plugin: add evdev usage masks for plugins

This adds the ability for a plugin to announce the evdev usages it may
possibly care about. Only event frames that contain one or more of those
usages will be passed to the plugin. Ideally this is an optimization
over calling every plugin for every frame but that largely also depends
on what exactly the plugin does with each frame.

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1271>
This commit is contained in:
Peter Hutterer 2025-07-14 15:34:44 +10:00
parent f04b276ac1
commit 3a86b6ea58
2 changed files with 55 additions and 1 deletions

View file

@ -62,6 +62,8 @@ struct libinput_plugin {
struct list *after; struct list *after;
struct list *before; struct list *before;
} event_queue; } event_queue;
struct evdev_mask *mask;
}; };
struct libinput_plugin_timer { struct libinput_plugin_timer {
@ -153,6 +155,7 @@ libinput_plugin_unref(struct libinput_plugin *plugin)
if (plugin->interface->destroy) if (plugin->interface->destroy)
plugin->interface->destroy(plugin); plugin->interface->destroy(plugin);
free(plugin->name); free(plugin->name);
evdev_mask_destroy(plugin->mask);
free(plugin); free(plugin);
} }
return NULL; return NULL;
@ -194,6 +197,16 @@ libinput_plugin_enable_device_event_frame(struct libinput_plugin *plugin,
} }
} }
void
libinput_plugin_enable_evdev_usage(struct libinput_plugin *plugin,
enum evdev_usage usage)
{
if (!plugin->mask)
plugin->mask = evdev_mask_new();
evdev_mask_set_usage(plugin->mask, evdev_usage_from(usage));
}
struct plugin_queued_event { struct plugin_queued_event {
struct list link; struct list link;
struct evdev_frame *frame; /* owns a ref */ struct evdev_frame *frame; /* owns a ref */
@ -555,6 +568,27 @@ print_frame(struct libinput *libinput, struct evdev_frame *frame, const char *pr
} }
} }
static bool
plugin_has_mask(struct libinput_plugin *plugin, struct evdev_frame *frame)
{
/* A plugin without a mask wants all events */
if (plugin->mask == NULL)
return true;
size_t nevents;
struct evdev_event *events = evdev_frame_get_events(frame, &nevents);
/* nevents - 1 because we don't check the SYN_REPORT */
for (size_t i = 0; i < nevents - 1; i++) {
struct evdev_event *e = &events[i];
if (evdev_mask_is_set(plugin->mask, e->usage))
return true;
}
return false;
}
static void static void
plugin_system_notify_evdev_frame(struct libinput_plugin_system *system, plugin_system_notify_evdev_frame(struct libinput_plugin_system *system,
struct libinput_device *device, struct libinput_device *device,
@ -606,11 +640,13 @@ plugin_system_notify_evdev_frame(struct libinput_plugin_system *system,
evdev_frame_set_time(event->frame, frame_time); evdev_frame_set_time(event->frame, frame_time);
if (!bitmask_bit_is_set(device->plugin_frame_callbacks, if (!bitmask_bit_is_set(device->plugin_frame_callbacks,
plugin->index)) { plugin->index) ||
!plugin_has_mask(plugin, event->frame)) {
list_remove(&event->link); list_remove(&event->link);
list_append(&next_events, &event->link); list_append(&next_events, &event->link);
continue; continue;
} }
#ifdef EVENT_DEBUGGING #ifdef EVENT_DEBUGGING
_autofree_ char *prefix = strdup_printf( _autofree_ char *prefix = strdup_printf(
"%7s: plugin %-15s - ", "%7s: plugin %-15s - ",

View file

@ -33,6 +33,7 @@
/* Forward declarations instead of #includes to make /* Forward declarations instead of #includes to make
* this header self-contained (bindgen, etc.) */ * this header self-contained (bindgen, etc.) */
struct evdev_frame; struct evdev_frame;
enum evdev_usage;
struct libinput; struct libinput;
struct libinput_device; struct libinput_device;
struct libinput_tablet_tool; struct libinput_tablet_tool;
@ -158,6 +159,23 @@ libinput_plugin_enable_device_event_frame(struct libinput_plugin *plugin,
struct libinput_device *device, struct libinput_device *device,
bool enable); bool enable);
/**
* Mask this plugin's evdev_frame function to be called only
* if the frame **contains** the given evdev usage. Plugins
* that e.g. only care about button events should use this function
* to avoid being called for every motion event.
*
* By default the mask includes all events. Calling this function
* changes the behavior to *only* include frames with the usages.
*
* Note that the frame passed to evdev_frame function contains all
* events of that frame (i.e. including events that are not specified
* by this mask).
*/
void
libinput_plugin_enable_evdev_usage(struct libinput_plugin *plugin,
enum evdev_usage usage);
/** /**
* Inject a new event frame from the given plugin. This * Inject a new event frame from the given plugin. This
* frame is treated as if it was just sent by the kernel's * frame is treated as if it was just sent by the kernel's