diff --git a/doc/user/dot/plugin-stack.gv b/doc/user/dot/plugin-stack.gv
new file mode 100644
index 00000000..1805c741
--- /dev/null
+++ b/doc/user/dot/plugin-stack.gv
@@ -0,0 +1,31 @@
+digraph stack
+{
+ compound=true;
+ rankdir="LR";
+ node [
+ shape="box";
+ ]
+
+ subgraph cluster_2 {
+ label="Kernel";
+ event0 [label="/dev/input/event0"]
+ }
+
+ subgraph cluster_1 {
+ label="libinput";
+ subgraph cluster_0 {
+ label="Plugin pipeline";
+ p1 [label="00-foo.lua"];
+ p2 [label="10-bar.lua"];
+ }
+ libinput [label="libinput core"];
+ }
+
+
+ compositor [label="Compositor"];
+
+ event0 -> p1;
+ p1 -> p2;
+ p2 -> libinput;
+ libinput -> compositor [ltail=cluster_1 label="libinput API"];
+}
diff --git a/doc/user/lua-plugins.rst b/doc/user/lua-plugins.rst
index 0b3e4e7d..dcd254a4 100644
--- a/doc/user/lua-plugins.rst
+++ b/doc/user/lua-plugins.rst
@@ -10,15 +10,24 @@ device and/or modify the event stream seen by this device before it is passed
to libinput.
Plugins are implemented in `Lua `_ (version 5.1)
-and are typically loaded from ``/usr/lib{64}/libinput/plugins`` and
-``/etc/libinput/plugins``. Plugins are loaded in alphabetical order and where
+and are typically loaded from the following paths:
+
+- ``/etc/libinput/plugins/*.lua``, and
+- ``/usr/lib{64}/libinput/plugins/*.lua``
+
+Plugins are loaded in alphabetical order and where
multiple plugins share the same file name, the one in the highest precedence
directory is used. Plugins in ``/etc`` take precedence over
plugins in ``/usr``.
+.. note:: Plugins lookup paths and their order are decided by the compositor.
+ Some compositors may support more/fewer/other lookup paths than the
+ above defaults.
+
Plugins are run sequentially in ascending sort-order (i.e. ``00-foo.lua`` runs
before ``10-bar.lua``) and each plugin sees the state left by any previous
-plugins.
+plugins. For example if ``00-foo.lua`` changes all left button events to right
+button events, ``10-bar.lua`` only ever sees right button events.
See the `Lua Reference manual `_ for
details on the Lua language.
@@ -45,8 +54,8 @@ The Lua API available to plugins is limited to the following calls::
It is not possible to e.g. use the ``io`` module from a script.
-To use methods on instantiated objects, the method call syntax must be used.
-For example:
+To use methods on instantiated objects, the ``object:method`` method call
+syntax must be used. For example:
.. code-block:: lua
@@ -88,14 +97,19 @@ Lua Plugin API
--------------------------------------------------------------------------------
Lua plugins sit effectively below libinput and the API is not a
-representation of the libinput API. The API revolves around two types:
-``libinput`` and ``EvdevDevice``. The former is used to register a
-plugin from a script, the latter represents one device that is present
-in the system (but may not have yet been added by libinput).
+representation of the libinput API. Plugins modify the evdev event stream
+received from the kernel.
+
+.. graphviz:: plugin-stack.gv
+
+The API revolves around two types: ``libinput`` and ``EvdevDevice``. The
+``libinput`` type is used to register a plugin from a script, the
+``EvdevDevice`` represents one device that is present in the system (but may
+not have yet been added by libinput).
Typically a script does the following steps:
-- register with libinput via ``libinput:register(version)``
+- register with libinput via ``libinput:register({versions})``
- connect to the ``"new-evdev-device"`` event
- receive an ``EvdevDevice`` object in the ``"new-evdev-device"`` callback
@@ -142,14 +156,17 @@ evdev types and codes. They are used by libinput internally and are a 32-bit
combination of ``type << 16 | code``. Each usage carries the type and code and
is thus simpler to pass around and less prone to type confusion.
-For the case where the :ref:`evdev global ` does not
-provide a named constant the value can be crafted manually:
+The :ref:`evdev global ` attempts to provide all
+available usages but for the niche cases where it does not provide a named constant
+the value can be crafted manually:
.. code-block:: lua
- type = 0x3 -- EV_REL
- code = 0x1 -- REL_Y
- usage = (type << 16) | code
+ evdev_type = 0x3 -- EV_REL
+ evdev_code = 0x1 -- REL_Y
+ evdev_usage = (evdev_type << 16) | evdev_code
+
+ assert(usage == evdev.REL_Y)
.. _plugins_api_evdev_global:
@@ -173,8 +190,8 @@ effectively in the form:
This global is provided for convenience to improve readability in the code.
-Note that the name uses the event code name only but the value is an
-:ref:`Evdev Usage ` (type and code).
+Note that the name uses the event code name only (e.g. ``evdev.ABS_Y``) but the
+value is an :ref:`Evdev Usage ` (type and code).
See the ``linux/input-event-codes.h`` header file provided by your kernel
for a list of all evdev types and codes.
@@ -204,10 +221,10 @@ In our API a frame is exposed as a nested table with the following structure:
{ usage = evdev.BTN_LEFT, value = 1 },
}
frame2 = {
- { sage = evdev.ABS_Y, value = 457 },
+ { usage = evdev.ABS_Y, value = 457 },
}
frame3 = {
- { sage = evdev.ABS_X, value = 124 },
+ { usage = evdev.ABS_X, value = 124 },
{ usage = evdev.BTN_LEFT, value = 0 },
}
@@ -259,7 +276,7 @@ location as other libinput log messages and are not discarded.
The ``libinput`` global object
................................................................................
-The core of our plugin's API is the ``libinput`` global object. A script must
+The core of our plugin API is the ``libinput`` global object. A script must
immediately ``register()`` to be active, otherwise it is unloaded immediately.
All libinput-specific APIs can be accessed through the ``libinput`` object.
@@ -279,7 +296,8 @@ All libinput-specific APIs can be accessed through the ``libinput`` object.
This function must be the first function called.
If the plugin calls any other functions before ``register()``, those functions
- return ``nil``, 0, an empty table, etc.
+ return the default zero value for the return type (``nil``, ``0``, an empty
+ table, etc.).
If the plugin does not call ``register()`` it will be removed immediately.
Once registered, any connected callbacks will be invoked whenever libinput
@@ -290,8 +308,8 @@ All libinput-specific APIs can be accessed through the ``libinput`` object.
.. function:: libinput:unregister()
Unregister this plugin. This removes the plugin from libinput and releases
- any resources. This call must be the last call in your plugin, it is
- effectively equivalent to Lua's
+ any resources associated with this plugin. This call must be the last call
+ in your plugin, it is effectively equivalent to Lua's
`os.exit() `_.
.. function:: libinput:now()
@@ -305,7 +323,7 @@ All libinput-specific APIs can be accessed through the ``libinput`` object.
.. function:: libinput:version()
Returns the agreed-on version of the plugin, see ``libinput:register()``.
- If called before ``libinput:register()`` this function returns 0.
+ If called before ``libinput:register()`` this function returns ``0``.
.. function:: libinput:connect(name, function)
@@ -327,7 +345,7 @@ All libinput-specific APIs can be accessed through the ``libinput`` object.
.. code-block:: lua
- libinput:connect("timer-expired", function (plugin, now) ... end)
+ libinput:connect("timer-expired", function (now) ... end)
The ``now`` argument is the current time in microseconds in
``CLOCK_MONOTONIC`` (see ``libinput.now()``).
@@ -382,6 +400,12 @@ The ``EvdevDevice`` type represents a device available in the system
but not (yet) added by libinput. This device may be used to modify
a device's capabilities before the device is processed by libinput.
+A plugin should always ``connect()`` to the ``"device-removed"`` callback
+to be notified when a device is removed. If the plugin keeps a reference
+to this device but the device is discarded by libinput, the device's query
+methods will return zero values (e.g. ``nil``, ``0``, an empty table) and
+methods will be noops.
+
.. function:: EvdevDevice:info()
A table containing static information about the device, e.g.
@@ -403,13 +427,16 @@ a device's capabilities before the device is processed by libinput.
- ``vid``: The 16-bit vendor ID of the device
- ``pid``: The 16-bit product ID of the device
+ If the device has since been discarded by libinput, this function returns an
+ empty table.
+
.. function:: EvdevDevice:name()
The device name as set by the kernel
.. function:: EvdevDevice:usages()
- Returns a nested table of all usages that are currently enabled for this
+ Returns a table of all usages that are currently enabled for this
device. Any type that exists on the device has a table assigned and in this
table any code that exists on the device is a boolean true.
For example:
@@ -480,7 +507,11 @@ a device's capabilities before the device is processed by libinput.
Enable the given :ref:`evdev usage ` for this device.
Use :ref:`plugins_api_evdev_global` for better readability,
e.g. ``device:enable_evdev_usage(evdev.REL_X)``.
- This function must not be used for ``ABS_*`` events, use ``set_absinfo()`` instead.
+ This function must not be used for ``ABS_*`` events, use ``set_absinfo()``
+ instead.
+
+ Once a usage is enabled, events for that usage may be added to a device's
+ frame.
If the device has since been discarded by libinput, this function does nothing.
@@ -490,17 +521,20 @@ a device's capabilities before the device is processed by libinput.
Use :ref:`plugins_api_evdev_global` for better readability,
e.g. ``device:disable_evdev_usage(evdev.REL_X)``.
+ Once a usage is disabled, events for that usage are discarded from any
+ device frame.
+
If the device has since been discarded by libinput, this function does nothing.
.. function:: EvdevDevice:set_absinfo(usage, absinfo)
Set the absolute axis information for the given :ref:`evdev usage `
- if it does not yet exist on the device. The ``absinfo`` argument is a table
+ and enable it if it does not yet exist on the device. The ``absinfo`` argument is a table
containing zero or more of the following keys: ``min``, ``max``, ``fuzz``,
``flat``, ``resolution``. Any missing key defaults the corresponding
- value from the device if the device already has this event code or zero otherwise.
- In other words the following code is enough to change the resolution but leave
- everything else as-is:
+ value from the device if the device already has this event usage or zero otherwise.
+ For example, the following code changes the resolution but leaves everything
+ else as-is:
.. code-block:: lua
@@ -591,12 +625,11 @@ a device's capabilities before the device is processed by libinput.
.. function:: EvdevDevice:prepend_frame(frame)
Prepend an :ref:`evdev frame ` for this device
- **before** the current frame (if any). This function can only be called from
- within a device's ``frame()`` handler or from within the plugin's timer
- callback function.
+ **before** the current frame (if any). The **next** plugin will see the
+ prepended frame first followed by the current frame.
- Assuming three plugins P1, P2 and P3, if P2 injects a frame the frame is
- seen only by P3.
+ This function can only be called from within a device's ``frame()`` handler
+ or from within the plugin's timer callback function.
For example, to change a single event into a drag, prepend a button
down and append a button up before each event:
@@ -610,11 +643,10 @@ a device's capabilities before the device is processed by libinput.
device:append_frame({
{ usage = evdev.BTN_LEFT, value = 0}
})
- return nil -- return the frame unmodified
+ return nil -- return the current frame unmodified
- -- this results in the event sequence
+ -- The next plugin sees the event sequence:
-- button down, frame, button up
- -- to be passed to the next plugin
end
If called from within the plugin's timer there is no current frame and this
@@ -644,9 +676,9 @@ a device's capabilities before the device is processed by libinput.
Version 1 of the plugin API supports the following features:
- - ``button-debouncing``: see :ref:`button_debouncing`
- - ``touchpad-hysteresis``: see :ref:`touchpad_jitter`
- - ``touchpad-jump-detection``: see :ref:`touchpad_jumping_cursor`
- - ``touchpad-palm-detection``: see :ref:`palm_detection`
- - ``wheel-debouncing``: some high-resolution mouse wheel movements inside libinput
+ - ``"button-debouncing"``: see :ref:`button_debouncing`
+ - ``"touchpad-hysteresis"``: see :ref:`touchpad_jitter`
+ - ``"touchpad-jump-detection"``: see :ref:`touchpad_jumping_cursor`
+ - ``"touchpad-palm-detection"``: see :ref:`palm_detection`
+ - ``"wheel-debouncing"``: some high-resolution mouse wheel movements inside libinput
are delayed and/or modified
diff --git a/doc/user/meson.build b/doc/user/meson.build
index 9ca63186..397392dc 100644
--- a/doc/user/meson.build
+++ b/doc/user/meson.build
@@ -100,6 +100,7 @@ src_rst = files(
'dot/libinput-stack-gnome.gv',
'dot/evemu.gv',
'dot/libinput-record.gv',
+ 'dot/plugin-stack.gv',
# svgs
'svg/button-debouncing-wave-diagram.svg',
'svg/button-scrolling.svg',