• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _architecture:
2
3==============================================================================
4libinput's internal architecture
5==============================================================================
6
7This page provides an outline of libinput's internal architecture. The goal
8here is to get the high-level picture across and point out the components
9and their interplay to new developers.
10
11The public facing API is in ``libinput.c``, this file is thus the entry point
12for almost all API calls. General device handling is in ``evdev.c`` with the
13device-type-specific implementations in ``evdev-<type>.c``. It is not
14necessary to understand all of libinput to contribute a patch.
15
16:ref:`architecture-contexts` is the only user-visible implementation detail,
17everything else is purely internal implementation and may change when
18required.
19
20.. _architecture-contexts:
21
22------------------------------------------------------------------------------
23The udev and path contexts
24------------------------------------------------------------------------------
25
26The first building block is the "context" which can be one of
27two types, "path" and "udev". See **libinput_path_create_context()** and
28**libinput_udev_create_context()**. The path/udev specific bits are in
29``path-seat.c`` and ``udev-seat.c``. This includes the functions that add new
30devices to a context.
31
32
33.. graphviz::
34
35
36    digraph context
37    {
38      compound=true;
39      rankdir="LR";
40      node [
41        shape="box";
42      ]
43
44      libudev [label="libudev 'add' event"]
45      udev [label="**libinput_udev_create_context()**"];
46      udev_backend [label="udev-specific backend"];
47      context [label="libinput context"]
48      udev -> udev_backend;
49      libudev -> udev_backend;
50      udev_backend -> context;
51    }
52
53
54The udev context provides automatic device hotplugging as udev's "add"
55events are handled directly by libinput. The path context requires that the
56caller adds devices.
57
58
59.. graphviz::
60
61
62    digraph context
63    {
64      compound=true;
65      rankdir="LR";
66      node [
67        shape="box";
68      ]
69
70      path [label="**libinput_path_create_context()**"];
71      path_backend [label="path-specific backend"];
72      xdriver [label="**libinput_path_add_device()**"]
73      context [label="libinput context"]
74      path -> path_backend;
75      xdriver -> path_backend;
76      path_backend -> context;
77    }
78
79
80As a general rule: all Wayland compositors use a udev context, the X.org
81stack uses a path context.
82
83Which context was initialized only matters for creating/destroying a context
84and adding devices. The device handling itself is the same for both types of
85context.
86
87.. _architecture-device:
88
89------------------------------------------------------------------------------
90Device initialization
91------------------------------------------------------------------------------
92
93libinput only supports evdev devices, all the device initialization is done
94in ``evdev.c``. Much of the libinput public API is also a thin wrapper around
95the matching implementation in the evdev device.
96
97There is a 1:1 mapping between libinput devices and ``/dev/input/eventX``
98device nodes.
99
100
101
102.. graphviz::
103
104
105    digraph context
106    {
107      compound=true;
108      rankdir="LR";
109      node [
110        shape="box";
111      ]
112
113      devnode [label="/dev/input/event0"]
114
115      libudev [label="libudev 'add' event"]
116      xdriver [label="**libinput_path_add_device()**"]
117      context [label="libinput context"]
118
119      evdev [label="evdev_device_create()"]
120
121      devnode -> xdriver;
122      devnode -> libudev;
123      xdriver -> context;
124      libudev -> context;
125
126      context->evdev;
127
128    }
129
130
131Entry point for all devices is ``evdev_device_create()``, this function
132decides to create a ``struct evdev_device`` for the given device node.
133Based on the udev tags (e.g. ``ID_INPUT_TOUCHPAD``), a
134:ref:`architecture-dispatch` is initialized. All event handling is then in this
135dispatch.
136
137Rejection of devices and the application of quirks is generally handled in
138``evdev.c`` as well. Common functionality shared across multiple device types
139(like button-scrolling) is also handled here.
140
141.. _architecture-dispatch:
142
143------------------------------------------------------------------------------
144Device-type specific event dispatch
145------------------------------------------------------------------------------
146
147Depending on the device type, ``evdev_configure_device`` creates the matching
148``struct evdev_dispatch``. This dispatch interface contains the function
149pointers to handle events. Four such dispatch methods are currently
150implemented: touchpad, tablet, tablet pad, and the fallback dispatch which
151handles mice, keyboards and touchscreens.
152
153
154.. graphviz::
155
156
157    digraph context
158    {
159      compound=true;
160      rankdir="LR";
161      node [
162        shape="box";
163      ]
164
165      evdev [label="evdev_device_create()"]
166
167      fallback [label="evdev-fallback.c"]
168      touchpad [label="evdev-mt-touchpad.c"]
169      tablet [label="evdev-tablet.c"]
170      pad [label="evdev-tablet-pad.c"]
171
172      evdev -> fallback;
173      evdev -> touchpad;
174      evdev -> tablet;
175      evdev -> pad;
176
177    }
178
179
180While ``evdev.c`` pulls the event out of libevdev, the actual handling of the
181events is performed within the dispatch method.
182
183
184.. graphviz::
185
186
187    digraph context
188    {
189      compound=true;
190      rankdir="LR";
191      node [
192        shape="box";
193      ]
194
195      evdev [label="evdev_device_dispatch()"]
196
197      fallback [label="fallback_interface_process()"];
198      touchpad [label="tp_interface_process()"]
199      tablet [label="tablet_process()"]
200      pad [label="pad_process()"]
201
202      evdev -> fallback;
203      evdev -> touchpad;
204      evdev -> tablet;
205      evdev -> pad;
206    }
207
208
209The dispatch methods then look at the ``struct input_event`` and proceed to
210update the state. Note: the serialized nature of the kernel evdev protocol
211requires that the device updates the state with each event but to delay
212processing until the ``SYN_REPORT`` event is received.
213
214.. _architecture-configuration:
215
216------------------------------------------------------------------------------
217Device configuration
218------------------------------------------------------------------------------
219
220All device-specific configuration is handled through ``struct
221libinput_device_config_FOO`` instances. These are set up during device init
222and provide the function pointers for the ``get``, ``set``, ``get_default``
223triplet of configuration queries (or more, where applicable).
224
225For example, the ``struct tablet_dispatch`` for tablet devices has a
226``struct libinput_device_config_accel``. This struct is set up with the
227required function pointers to change the profiles.
228
229
230.. graphviz::
231
232
233    digraph context
234    {
235      compound=true;
236      rankdir="LR";
237      node [
238        shape="box";
239      ]
240
241      tablet [label="struct tablet_dispatch"]
242      config [label="struct libinput_device_config_accel"];
243      tablet_config [label="tablet_accel_config_set_profile()"];
244      tablet->config;
245      config->tablet_config;
246    }
247
248
249When the matching ``**libinput_device_config_set_FOO()**`` is called, this goes
250through to the config struct and invokes the function there. Thus, it is
251possible to have different configuration functions for a mouse vs a
252touchpad, even though the interface is the same.
253
254
255.. graphviz::
256
257
258    digraph context
259    {
260      compound=true;
261      rankdir="LR";
262      node [
263        shape="box";
264      ]
265
266      libinput [label="**libinput_device_config_accel_set_profile()**"];
267      tablet_config [label="tablet_accel_config_set_profile()"];
268      libinput->tablet_config;
269    }
270
271
272.. _architecture-filter:
273
274------------------------------------------------------------------------------
275Pointer acceleration filters
276------------------------------------------------------------------------------
277
278All pointer acceleration is handled in the ``filter.c`` file and its
279associated files.
280
281The ``struct motion_filter`` is initialized during device init, whenever
282deltas are available they are passed to ``filter_dispatch()``. This function
283returns a set of :ref:`normalized coordinates <motion_normalization_customization>`.
284
285All actual acceleration is handled within the filter, the device itself has
286no further knowledge. Thus it is possible to have different acceleration
287filters for the same device types (e.g. the Lenovo X230 touchpad has a
288custom filter).
289
290
291.. graphviz::
292
293
294    digraph context
295    {
296      compound=true;
297      rankdir="LR";
298      node [
299        shape="box";
300      ]
301
302      fallback [label="fallback deltas"];
303      touchpad [label="touchpad deltas"];
304      tablet [label="tablet deltas"];
305
306      filter [label="filter_dispatch"];
307
308      fallback->filter;
309      touchpad->filter;
310      tablet->filter;
311
312      flat [label="accelerator_interface_flat()"];
313      x230 [label="accelerator_filter_x230()"];
314      pen [label="tablet_accelerator_filter_flat_pen()"];
315
316      filter->flat;
317      filter->x230;
318      filter->pen;
319
320    }
321
322
323Most filters convert the deltas (incl. timestamps) to a motion speed and
324then apply a so-called profile function. This function returns a factor that
325is then applied to the current delta, converting it into an accelerated
326delta. See :ref:`pointer-acceleration` for more details.
327the current
328