architecture.rst 12 KB

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