diff --git a/meson.build b/meson.build index 4b494624..64481a1a 100644 --- a/meson.build +++ b/meson.build @@ -335,7 +335,7 @@ src_libfilter = [ 'src/filter-trackpoint-flat.c', ] libfilter = static_library('filter', src_libfilter, - dependencies : [dep_udev, dep_libwacom], + dependencies : [dep_udev, dep_libwacom, dep_libevdev], include_directories : includes_include) dep_libfilter = declare_dependency(link_with : libfilter) @@ -374,6 +374,7 @@ config_h.set10('EVENT_DEBUGGING', get_option('internal-event-debugging')) install_headers('src/libinput.h') src_libinput = src_libfilter + [ 'src/libinput.c', + 'src/libinput-plugin.c', 'src/libinput-private-config.c', 'src/evdev.c', 'src/evdev-debounce.c', diff --git a/src/evdev.c b/src/evdev.c index a6d44c38..c86eeeb6 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1120,19 +1120,25 @@ evdev_device_dispatch_one(struct evdev_device *device, } static inline void -evdev_device_dispatch_frame(struct evdev_device *device, +evdev_device_dispatch_frame(struct libinput *libinput, + struct evdev_device *device, struct evdev_frame *frame) { size_t nevents; struct evdev_event *events = evdev_frame_get_events(frame, &nevents); + libinput_plugin_system_notify_evdev_frame(&libinput->plugin_system, + &device->base, + frame); + for (size_t i = 0; i < nevents; i++) { evdev_device_dispatch_one(device, &events[i], evdev_frame_get_time(frame)); } } static int -evdev_sync_device(struct evdev_device *device) +evdev_sync_device(struct libinput *libinput, + struct evdev_device *device) { struct input_event ev; int rc; @@ -1149,7 +1155,7 @@ evdev_sync_device(struct evdev_device *device) evdev_frame_append_input_event(frame, &ev); } while (rc == LIBEVDEV_READ_STATUS_SYNC); - evdev_device_dispatch_frame(device, frame); + evdev_device_dispatch_frame(libinput, device, frame); return rc == -EAGAIN ? 0 : rc; } @@ -1211,10 +1217,10 @@ evdev_device_dispatch(void *data) evdev_log_bug_libinput(device, "event frame overflow, discarding events.\n"); } - evdev_device_dispatch_frame(device, frame); + evdev_device_dispatch_frame(libinput, device, frame); evdev_frame_reset(frame); - rc = evdev_sync_device(device); + rc = evdev_sync_device(libinput, device); if (rc == 0) rc = LIBEVDEV_READ_STATUS_SUCCESS; } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) { @@ -1228,7 +1234,7 @@ evdev_device_dispatch(void *data) "event frame overflow, discarding events.\n"); } if (ev.type == EV_SYN && ev.code == SYN_REPORT) { - evdev_device_dispatch_frame(device, frame); + evdev_device_dispatch_frame(libinput, device, frame); evdev_frame_reset(frame); } } else if (rc == -ENODEV) { @@ -1240,7 +1246,7 @@ evdev_device_dispatch(void *data) /* This should never happen, the kernel flushes only on SYN_REPORT */ if (evdev_frame_get_count(frame) > 1) { evdev_log_bug_kernel(device, "event frame missing SYN_REPORT, forcing frame.\n"); - evdev_device_dispatch_frame(device, frame); + evdev_device_dispatch_frame(libinput, device, frame); } if (rc != -EAGAIN && rc != -EINTR) { @@ -2538,17 +2544,22 @@ evdev_device_create(struct libinput_seat *seat, evdev_pre_configure_model_quirks(device); + libinput_plugin_system_notify_device_new(&libinput->plugin_system, + &device->base, + device->evdev, + device->udev_device); + device->dispatch = evdev_configure_device(device); if (device->dispatch == NULL || device->seat_caps == EVDEV_DEVICE_NO_CAPABILITIES) - goto err; + goto err_notify; device->source = libinput_add_fd(libinput, fd, evdev_device_dispatch, device); if (!device->source) - goto err; + goto err_notify; if (!evdev_set_device_group(device, udev_device)) - goto err; + goto err_notify; list_insert(seat->devices_list.prev, &device->base.link); @@ -2556,6 +2567,10 @@ evdev_device_create(struct libinput_seat *seat, return device; +err_notify: + libinput_plugin_system_notify_device_ignored(&libinput->plugin_system, + &device->base); + err: if (fd >= 0) { close_restricted(libinput, fd); diff --git a/src/libinput-plugin-private.h b/src/libinput-plugin-private.h new file mode 100644 index 00000000..32d45649 --- /dev/null +++ b/src/libinput-plugin-private.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2025 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "config.h" + +#include "libinput-plugin.h" + +void +libinput_plugin_run(struct libinput_plugin *plugin); + +void +libinput_plugin_notify_device_new(struct libinput_plugin *plugin, + struct libinput_device *device, + struct libevdev *evdev, + struct udev_device *udev_device); + +void +libinput_plugin_notify_device_added(struct libinput_plugin *plugin, + struct libinput_device *device); + +void +libinput_plugin_notify_device_ignored(struct libinput_plugin *plugin, + struct libinput_device *device); + +void +libinput_plugin_notify_device_removed(struct libinput_plugin *plugin, + struct libinput_device *device); + +void +libinput_plugin_notify_evdev_frame(struct libinput_plugin *plugin, + struct libinput_device *device, + struct evdev_frame *frame); diff --git a/src/libinput-plugin-system.h b/src/libinput-plugin-system.h new file mode 100644 index 00000000..b4b61d65 --- /dev/null +++ b/src/libinput-plugin-system.h @@ -0,0 +1,84 @@ +/* + * Copyright © 2025 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "config.h" + +#include +#include +#include + +#include "evdev-frame.h" +#include "util-list.h" + +#include "libinput.h" + +struct libinput; +struct libinput_plugin; + +struct libinput_plugin_system { + char **directories; /* NULL once loaded == true */ + + struct list plugins; + struct list removed_plugins; +}; + +void +libinput_plugin_system_init(struct libinput_plugin_system *system); + +void +libinput_plugin_system_destroy(struct libinput_plugin_system *system); + +void +libinput_plugin_system_run(struct libinput_plugin_system *system); + +void +libinput_plugin_system_register_plugin(struct libinput_plugin_system *system, + struct libinput_plugin *plugin); +void +libinput_plugin_system_unregister_plugin(struct libinput_plugin_system *system, + struct libinput_plugin *plugin); + +void +libinput_plugin_system_notify_device_new(struct libinput_plugin_system *system, + struct libinput_device *device, + struct libevdev *evdev, + struct udev_device *udev); + +void +libinput_plugin_system_notify_device_added(struct libinput_plugin_system *system, + struct libinput_device *device); + +void +libinput_plugin_system_notify_device_removed(struct libinput_plugin_system *system, + struct libinput_device *device); + +void +libinput_plugin_system_notify_device_ignored(struct libinput_plugin_system *system, + struct libinput_device *device); + +void +libinput_plugin_system_notify_evdev_frame(struct libinput_plugin_system *system, + struct libinput_device *device, + struct evdev_frame *frame); diff --git a/src/libinput-plugin.c b/src/libinput-plugin.c new file mode 100644 index 00000000..1dec4348 --- /dev/null +++ b/src/libinput-plugin.c @@ -0,0 +1,319 @@ +/* + * Copyright © 2025 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include + +#include "util-files.h" +#include "util-list.h" + +#include "libinput-plugin.h" +#include "libinput-plugin-private.h" +#include "libinput-plugin-system.h" +#include "libinput-util.h" +#include "libinput-private.h" + +struct libinput_plugin { + struct libinput *libinput; + char *name; + int refcount; + struct list link; + void *user_data; + + bool registered; + + const struct libinput_plugin_interface *interface; +}; + +LIBINPUT_ATTRIBUTE_PRINTF(3, 4) +void +plugin_log_msg(struct libinput_plugin *plugin, + enum libinput_log_priority priority, + const char *format, + ...) +{ + + if (!log_is_logged(plugin->libinput, priority)) + return; + + _autofree_ char *prefix = strdup_printf("Plugin:%-15s - ", plugin->name); + va_list args; + va_start(args, format); + _autofree_ char *message = strdup_vprintf(format, args); + va_end(args); + + log_msg(plugin->libinput, priority, "%s%s", prefix, message); +} + +struct libinput_plugin * +libinput_plugin_new(struct libinput *libinput, + const char *name, + const struct libinput_plugin_interface *interface, + void *user_data) +{ + struct libinput_plugin *plugin = zalloc(sizeof(*plugin)); + + plugin->registered = true; + plugin->libinput = libinput; + plugin->refcount = 1; + plugin->interface = interface; + plugin->user_data = user_data; + plugin->name = strdup(name); + + libinput_plugin_system_register_plugin(&libinput->plugin_system, plugin); + + return plugin; +} + +void +libinput_plugin_unregister(struct libinput_plugin *plugin) +{ + struct libinput *libinput = plugin->libinput; + if (!plugin->registered) + return; + + plugin->registered = false; + + libinput_plugin_system_unregister_plugin(&libinput->plugin_system, + plugin); +} + +struct libinput_plugin * +libinput_plugin_ref(struct libinput_plugin *plugin) +{ + assert(plugin->refcount > 0); + ++plugin->refcount; + return plugin; +} + +struct libinput_plugin * +libinput_plugin_unref(struct libinput_plugin *plugin) +{ + assert(plugin->refcount > 0); + if (--plugin->refcount == 0) { + list_remove(&plugin->link); + if (plugin->interface->destroy) + plugin->interface->destroy(plugin); + free(plugin->name); + free(plugin); + } + return NULL; +} + +void +libinput_plugin_set_user_data(struct libinput_plugin *plugin, + void *user_data) +{ + plugin->user_data = user_data; +} + +void * +libinput_plugin_get_user_data(struct libinput_plugin *plugin) +{ + return plugin->user_data; +} + +const char * +libinput_plugin_get_name(struct libinput_plugin *plugin) +{ + return plugin->name; +} + +struct libinput * +libinput_plugin_get_context(struct libinput_plugin *plugin) +{ + return plugin->libinput; +} + +void +libinput_plugin_run(struct libinput_plugin *plugin) +{ + if (plugin->interface->run) + plugin->interface->run(plugin); +} + +void +libinput_plugin_notify_device_new(struct libinput_plugin *plugin, + struct libinput_device *device, + struct libevdev *evdev, + struct udev_device *udev_device) +{ + if (plugin->interface->device_new) + plugin->interface->device_new(plugin, device, evdev, udev_device); +} + +void +libinput_plugin_notify_device_added(struct libinput_plugin *plugin, + struct libinput_device *device) +{ + if (plugin->interface->device_added) + plugin->interface->device_added(plugin, device); +} + +void +libinput_plugin_notify_device_ignored(struct libinput_plugin *plugin, + struct libinput_device *device) +{ + if (plugin->interface->device_ignored) + plugin->interface->device_ignored(plugin, device); +} + +void +libinput_plugin_notify_device_removed(struct libinput_plugin *plugin, + struct libinput_device *device) +{ + if (plugin->interface->device_removed) + plugin->interface->device_removed(plugin, device); +} + +void +libinput_plugin_notify_evdev_frame(struct libinput_plugin *plugin, + struct libinput_device *device, + struct evdev_frame *frame) +{ + if (plugin->interface->evdev_frame) + plugin->interface->evdev_frame(plugin, device, frame); +} + +void +libinput_plugin_system_run(struct libinput_plugin_system *system) +{ + struct libinput_plugin *plugin; + list_for_each_safe(plugin, + &system->plugins, + link) { + libinput_plugin_run(plugin); + } +} + +void +libinput_plugin_system_register_plugin(struct libinput_plugin_system *system, + struct libinput_plugin *plugin) +{ + libinput_plugin_ref(plugin); + list_append(&system->plugins, &plugin->link); +} + +void +libinput_plugin_system_unregister_plugin(struct libinput_plugin_system *system, + struct libinput_plugin *plugin) +{ + struct libinput_plugin *p; + list_for_each(p, &system->plugins, link) { + if (p == plugin) { + list_remove(&plugin->link); + list_append(&system->removed_plugins, &plugin->link); + return; + } + } +} + +static void +libinput_plugin_system_drop_unregistered_plugins(struct libinput_plugin_system *system) +{ + struct libinput_plugin *plugin; + list_for_each_safe(plugin, &system->removed_plugins, link) { + list_remove(&plugin->link); + list_init(&plugin->link); /* allow list_remove in unref */ + libinput_plugin_unref(plugin); + } +} + +void +libinput_plugin_system_init(struct libinput_plugin_system *system) +{ + list_init(&system->plugins); + list_init(&system->removed_plugins); +} + +void +libinput_plugin_system_destroy(struct libinput_plugin_system *system) +{ + struct libinput_plugin *plugin; + list_for_each_safe(plugin, &system->plugins, link) { + libinput_plugin_unregister(plugin); + } + + libinput_plugin_system_drop_unregistered_plugins(system); + + strv_free(system->directories); +} + +void +libinput_plugin_system_notify_device_new(struct libinput_plugin_system *system, + struct libinput_device *device, + struct libevdev *evdev, + struct udev_device *udev_device) +{ + struct libinput_plugin *plugin; + list_for_each_safe(plugin, &system->plugins, link) { + libinput_plugin_notify_device_new(plugin, device, evdev, udev_device); + } + libinput_plugin_system_drop_unregistered_plugins(system); +} + +void +libinput_plugin_system_notify_device_added(struct libinput_plugin_system *system, + struct libinput_device *device) +{ + struct libinput_plugin *plugin; + list_for_each_safe(plugin, &system->plugins, link) { + libinput_plugin_notify_device_added(plugin, device); + } + libinput_plugin_system_drop_unregistered_plugins(system); +} + +void +libinput_plugin_system_notify_device_removed(struct libinput_plugin_system *system, + struct libinput_device *device) +{ + struct libinput_plugin *plugin; + list_for_each_safe(plugin, &system->plugins, link) { + libinput_plugin_notify_device_removed(plugin, device); + } + libinput_plugin_system_drop_unregistered_plugins(system); +} + +void +libinput_plugin_system_notify_device_ignored(struct libinput_plugin_system *system, + struct libinput_device *device) +{ + struct libinput_plugin *plugin; + list_for_each_safe(plugin, &system->plugins, link) { + libinput_plugin_notify_device_ignored(plugin, device); + } + libinput_plugin_system_drop_unregistered_plugins(system); +} + +void +libinput_plugin_system_notify_evdev_frame(struct libinput_plugin_system *system, + struct libinput_device *device, + struct evdev_frame *frame) +{ + struct libinput_plugin *plugin; + list_for_each_safe(plugin, &system->plugins, link) { + libinput_plugin_notify_evdev_frame(plugin, device, frame); + } + libinput_plugin_system_drop_unregistered_plugins(system); +} diff --git a/src/libinput-plugin.h b/src/libinput-plugin.h new file mode 100644 index 00000000..930febf0 --- /dev/null +++ b/src/libinput-plugin.h @@ -0,0 +1,146 @@ +/* + * Copyright © 2025 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "config.h" + +#include +#include +#include + +/* Forward declarations instead of #includes to make + * this header self-contained (bindgen, etc.) */ +struct evdev_frame; +struct libinput; +struct libinput_device; +struct libinput_plugin; +enum libinput_log_priority; + +#define plugin_log_debug(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_DEBUG, __VA_ARGS__) +#define plugin_log_info(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_INFO, __VA_ARGS__) +#define plugin_log_error(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, __VA_ARGS__) +#define plugin_log_bug_kernel(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__) +#define plugin_log_bug_libinput(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, "libinput bug: " __VA_ARGS__) +#define plugin_log_bug_client(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__) +#define plugin_log_bug(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, "plugin bug: " __VA_ARGS__) + +void +plugin_log_msg(struct libinput_plugin *plugin, + enum libinput_log_priority priority, + const char *format, + ...); + +struct libinput_plugin_interface { + void (*run)(struct libinput_plugin *plugin); + /** + * Notification that the plugin is about to be destroyed. + * When this function is called, the plugin has already + * been unregistered. The plugin should free any + * resources allocated but not the struct libinput_plugin + * itself. + */ + void (*destroy)(struct libinput_plugin *plugin); + /** + * Notification about a newly added device that has **not** yet + * been added by libinput as struct libinput_device. + */ + void (*device_new)(struct libinput_plugin *plugin, + struct libinput_device *device, + struct libevdev *evdev, + struct udev_device *udev_device); + /** + * Notification that a device (previously announced with device_new) + * was ignored by libinput and was **never** added as struct + * libinput_device. + * + * If a device was added (device_added) then this callback will + * not be called for that device. + */ + void (*device_ignored)(struct libinput_plugin *plugin, + struct libinput_device *device); + /** + * Notification that a device was added to libinput. Called + * after the device_new callback if the device matches libinput's + * expectations. + */ + void (*device_added)(struct libinput_plugin *plugin, + struct libinput_device *device); + /** + * Notification that a previously added device was removed. + */ + void (*device_removed)(struct libinput_plugin *plugin, + struct libinput_device *device); + /** + * Notification that a device submitted a frame event. + */ + void (*evdev_frame)(struct libinput_plugin *plugin, + struct libinput_device *device, + struct evdev_frame *frame); +}; + +/** + * Returns a new plugin with the given interface and, optionally, + * the user data. The returned plugin has a refcount of at least 1 + * and must be unref'd by the caller. + * Should an error occur, the plugin must be unregistered by + * the caller: + * + * ``` + * struct libinput_plugin *plugin = libinput_plugin_new(libinput, ...); + * if (some_error_condition) { + * libinput_plugin_unregister(plugin); + * } + * libinput_plugin_unref(plugin); + * ``` + */ +struct libinput_plugin * +libinput_plugin_new(struct libinput *libinput, + const char *name, + const struct libinput_plugin_interface *interface, + void *user_data); + +const char * +libinput_plugin_get_name(struct libinput_plugin *plugin); + +struct libinput * +libinput_plugin_get_context(struct libinput_plugin *plugin); + +void +libinput_plugin_unregister(struct libinput_plugin *plugin); + +void +libinput_plugin_set_user_data(struct libinput_plugin *plugin, + void *user_data); +void * +libinput_plugin_get_user_data(struct libinput_plugin *plugin); + +struct libinput_plugin * +libinput_plugin_ref(struct libinput_plugin *plugin); + +struct libinput_plugin * +libinput_plugin_unref(struct libinput_plugin *plugin); + +#ifdef DEFINE_UNREF_CLEANUP_FUNC +DEFINE_UNREF_CLEANUP_FUNC(libinput_plugin); +#endif diff --git a/src/libinput-private.h b/src/libinput-private.h index 0a15f9ec..11c5440d 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -39,6 +39,7 @@ #include "libinput.h" #include "libinput-log.h" +#include "libinput-plugin-system.h" #include "libinput-private-config.h" #include "libinput-util.h" #include "libinput-version.h" @@ -221,6 +222,8 @@ struct libinput { bool quirks_initialized; struct quirks_context *quirks; + struct libinput_plugin_system plugin_system; + #if HAVE_LIBWACOM struct { WacomDeviceDatabase *db; diff --git a/src/libinput.c b/src/libinput.c index ca487954..75afc544 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1879,6 +1879,8 @@ libinput_init(struct libinput *libinput, list_init(&libinput->device_group_list); list_init(&libinput->tool_list); + libinput_plugin_system_init(&libinput->plugin_system); + if (libinput_timer_subsys_init(libinput) != 0) { free(libinput->events); close(libinput->epoll_fd); @@ -1977,6 +1979,8 @@ libinput_unref(struct libinput *libinput) free(libinput->events); + libinput_plugin_system_destroy(&libinput->plugin_system); + list_for_each_safe(seat, &libinput->seat_list, link) { list_for_each_safe(device, &seat->devices_list, @@ -2345,6 +2349,9 @@ post_device_event(struct libinput_device *device, void notify_added_device(struct libinput_device *device) { + struct libinput *libinput = device->seat->libinput; + libinput_plugin_system_notify_device_added(&libinput->plugin_system, device); + struct libinput_event_device_notify *added_device_event; added_device_event = zalloc(sizeof *added_device_event); @@ -2363,6 +2370,9 @@ notify_added_device(struct libinput_device *device) void notify_removed_device(struct libinput_device *device) { + struct libinput *libinput = device->seat->libinput; + libinput_plugin_system_notify_device_removed(&libinput->plugin_system, device); + struct libinput_event_device_notify *removed_device_event; removed_device_event = zalloc(sizeof *removed_device_event);