aboutsummaryrefslogtreecommitdiff
path: root/backend/libinput
diff options
context:
space:
mode:
Diffstat (limited to 'backend/libinput')
-rw-r--r--backend/libinput/backend.c204
-rw-r--r--backend/libinput/events.c294
-rw-r--r--backend/libinput/keyboard.c83
-rw-r--r--backend/libinput/pointer.c136
-rw-r--r--backend/libinput/switch.c55
-rw-r--r--backend/libinput/tablet_pad.c183
-rw-r--r--backend/libinput/tablet_tool.c371
-rw-r--r--backend/libinput/touch.c97
8 files changed, 1423 insertions, 0 deletions
diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c
new file mode 100644
index 00000000..8106af00
--- /dev/null
+++ b/backend/libinput/backend.c
@@ -0,0 +1,204 @@
+#include <assert.h>
+#include <libinput.h>
+#include <stdlib.h>
+#include <wlr/backend/interface.h>
+#include <wlr/backend/session.h>
+#include <wlr/util/log.h>
+#include "backend/libinput.h"
+#include "util/signal.h"
+
+static struct wlr_libinput_backend *get_libinput_backend_from_backend(
+ struct wlr_backend *wlr_backend) {
+ assert(wlr_backend_is_libinput(wlr_backend));
+ return (struct wlr_libinput_backend *)wlr_backend;
+}
+
+static int libinput_open_restricted(const char *path,
+ int flags, void *_backend) {
+ struct wlr_libinput_backend *backend = _backend;
+ return wlr_session_open_file(backend->session, path);
+}
+
+static void libinput_close_restricted(int fd, void *_backend) {
+ struct wlr_libinput_backend *backend = _backend;
+ wlr_session_close_file(backend->session, fd);
+}
+
+static const struct libinput_interface libinput_impl = {
+ .open_restricted = libinput_open_restricted,
+ .close_restricted = libinput_close_restricted
+};
+
+static int handle_libinput_readable(int fd, uint32_t mask, void *_backend) {
+ struct wlr_libinput_backend *backend = _backend;
+ if (libinput_dispatch(backend->libinput_context) != 0) {
+ wlr_log(WLR_ERROR, "Failed to dispatch libinput");
+ // TODO: some kind of abort?
+ return 0;
+ }
+ struct libinput_event *event;
+ while ((event = libinput_get_event(backend->libinput_context))) {
+ handle_libinput_event(backend, event);
+ libinput_event_destroy(event);
+ }
+ return 0;
+}
+
+static void log_libinput(struct libinput *libinput_context,
+ enum libinput_log_priority priority, const char *fmt, va_list args) {
+ _wlr_vlog(WLR_ERROR, fmt, args);
+}
+
+static bool backend_start(struct wlr_backend *wlr_backend) {
+ struct wlr_libinput_backend *backend =
+ get_libinput_backend_from_backend(wlr_backend);
+ wlr_log(WLR_DEBUG, "Initializing libinput");
+
+ backend->libinput_context = libinput_udev_create_context(&libinput_impl,
+ backend, backend->session->udev);
+ if (!backend->libinput_context) {
+ wlr_log(WLR_ERROR, "Failed to create libinput context");
+ return false;
+ }
+
+ if (libinput_udev_assign_seat(backend->libinput_context,
+ backend->session->seat) != 0) {
+ wlr_log(WLR_ERROR, "Failed to assign libinput seat");
+ return false;
+ }
+
+ // TODO: More sophisticated logging
+ libinput_log_set_handler(backend->libinput_context, log_libinput);
+ libinput_log_set_priority(backend->libinput_context, LIBINPUT_LOG_PRIORITY_ERROR);
+
+ int libinput_fd = libinput_get_fd(backend->libinput_context);
+ char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES");
+ if (no_devs) {
+ if (strcmp(no_devs, "1") != 0) {
+ no_devs = NULL;
+ }
+ }
+ if (!no_devs && backend->wlr_device_lists.length == 0) {
+ handle_libinput_readable(libinput_fd, WL_EVENT_READABLE, backend);
+ if (backend->wlr_device_lists.length == 0) {
+ wlr_log(WLR_ERROR, "libinput initialization failed, no input devices");
+ wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check");
+ return false;
+ }
+ }
+
+ struct wl_event_loop *event_loop =
+ wl_display_get_event_loop(backend->display);
+ if (backend->input_event) {
+ wl_event_source_remove(backend->input_event);
+ }
+ backend->input_event = wl_event_loop_add_fd(event_loop, libinput_fd,
+ WL_EVENT_READABLE, handle_libinput_readable, backend);
+ if (!backend->input_event) {
+ wlr_log(WLR_ERROR, "Failed to create input event on event loop");
+ return false;
+ }
+ wlr_log(WLR_DEBUG, "libinput successfully initialized");
+ return true;
+}
+
+static void backend_destroy(struct wlr_backend *wlr_backend) {
+ if (!wlr_backend) {
+ return;
+ }
+ struct wlr_libinput_backend *backend =
+ get_libinput_backend_from_backend(wlr_backend);
+
+ for (size_t i = 0; i < backend->wlr_device_lists.length; i++) {
+ struct wl_list *wlr_devices = backend->wlr_device_lists.items[i];
+ struct wlr_input_device *wlr_dev, *next;
+ wl_list_for_each_safe(wlr_dev, next, wlr_devices, link) {
+ wlr_input_device_destroy(wlr_dev);
+ }
+ free(wlr_devices);
+ }
+
+ wlr_signal_emit_safe(&wlr_backend->events.destroy, wlr_backend);
+
+ wl_list_remove(&backend->display_destroy.link);
+ wl_list_remove(&backend->session_signal.link);
+
+ wlr_list_finish(&backend->wlr_device_lists);
+ if (backend->input_event) {
+ wl_event_source_remove(backend->input_event);
+ }
+ libinput_unref(backend->libinput_context);
+ free(backend);
+}
+
+static const struct wlr_backend_impl backend_impl = {
+ .start = backend_start,
+ .destroy = backend_destroy,
+};
+
+bool wlr_backend_is_libinput(struct wlr_backend *b) {
+ return b->impl == &backend_impl;
+}
+
+static void session_signal(struct wl_listener *listener, void *data) {
+ struct wlr_libinput_backend *backend =
+ wl_container_of(listener, backend, session_signal);
+ struct wlr_session *session = data;
+
+ if (!backend->libinput_context) {
+ return;
+ }
+
+ if (session->active) {
+ libinput_resume(backend->libinput_context);
+ } else {
+ libinput_suspend(backend->libinput_context);
+ }
+}
+
+static void handle_display_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_libinput_backend *backend =
+ wl_container_of(listener, backend, display_destroy);
+ backend_destroy(&backend->backend);
+}
+
+struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,
+ struct wlr_session *session) {
+ struct wlr_libinput_backend *backend =
+ calloc(1, sizeof(struct wlr_libinput_backend));
+ if (!backend) {
+ wlr_log(WLR_ERROR, "Allocation failed: %s", strerror(errno));
+ return NULL;
+ }
+ wlr_backend_init(&backend->backend, &backend_impl);
+
+ if (!wlr_list_init(&backend->wlr_device_lists)) {
+ wlr_log(WLR_ERROR, "Allocation failed: %s", strerror(errno));
+ goto error_backend;
+ }
+
+ backend->session = session;
+ backend->display = display;
+
+ backend->session_signal.notify = session_signal;
+ wl_signal_add(&session->session_signal, &backend->session_signal);
+
+ backend->display_destroy.notify = handle_display_destroy;
+ wl_display_add_destroy_listener(display, &backend->display_destroy);
+
+ return &backend->backend;
+error_backend:
+ free(backend);
+ return NULL;
+}
+
+struct libinput_device *wlr_libinput_get_device_handle(
+ struct wlr_input_device *wlr_dev) {
+ struct wlr_libinput_input_device *dev =
+ (struct wlr_libinput_input_device *)wlr_dev;
+ return dev->handle;
+}
+
+uint32_t usec_to_msec(uint64_t usec) {
+ return (uint32_t)(usec / 1000);
+}
diff --git a/backend/libinput/events.c b/backend/libinput/events.c
new file mode 100644
index 00000000..a7a6c114
--- /dev/null
+++ b/backend/libinput/events.c
@@ -0,0 +1,294 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <libinput.h>
+#include <stdlib.h>
+#include <wayland-util.h>
+#include <wlr/backend/session.h>
+#include <wlr/interfaces/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "backend/libinput.h"
+#include "util/signal.h"
+
+struct wlr_libinput_input_device *get_libinput_device_from_device(
+ struct wlr_input_device *wlr_dev) {
+ assert(wlr_input_device_is_libinput(wlr_dev));
+ return (struct wlr_libinput_input_device *)wlr_dev;
+}
+
+struct wlr_input_device *get_appropriate_device(
+ enum wlr_input_device_type desired_type,
+ struct libinput_device *libinput_dev) {
+ struct wl_list *wlr_devices = libinput_device_get_user_data(libinput_dev);
+ if (!wlr_devices) {
+ return NULL;
+ }
+ struct wlr_input_device *dev;
+ wl_list_for_each(dev, wlr_devices, link) {
+ if (dev->type == desired_type) {
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+static void input_device_destroy(struct wlr_input_device *wlr_dev) {
+ struct wlr_libinput_input_device *dev =
+ get_libinput_device_from_device(wlr_dev);
+ libinput_device_unref(dev->handle);
+ wl_list_remove(&dev->wlr_input_device.link);
+ free(dev);
+}
+
+static const struct wlr_input_device_impl input_device_impl = {
+ .destroy = input_device_destroy,
+};
+
+static struct wlr_input_device *allocate_device(
+ struct wlr_libinput_backend *backend,
+ struct libinput_device *libinput_dev, struct wl_list *wlr_devices,
+ enum wlr_input_device_type type) {
+ int vendor = libinput_device_get_id_vendor(libinput_dev);
+ int product = libinput_device_get_id_product(libinput_dev);
+ const char *name = libinput_device_get_name(libinput_dev);
+ struct wlr_libinput_input_device *dev =
+ calloc(1, sizeof(struct wlr_libinput_input_device));
+ if (dev == NULL) {
+ return NULL;
+ }
+ struct wlr_input_device *wlr_dev = &dev->wlr_input_device;
+ libinput_device_get_size(libinput_dev,
+ &wlr_dev->width_mm, &wlr_dev->height_mm);
+ const char *output_name = libinput_device_get_output_name(libinput_dev);
+ if (output_name != NULL) {
+ wlr_dev->output_name = strdup(output_name);
+ }
+ wl_list_insert(wlr_devices, &wlr_dev->link);
+ dev->handle = libinput_dev;
+ libinput_device_ref(libinput_dev);
+ wlr_input_device_init(wlr_dev, type, &input_device_impl,
+ name, vendor, product);
+ return wlr_dev;
+}
+
+bool wlr_input_device_is_libinput(struct wlr_input_device *wlr_dev) {
+ return wlr_dev->impl == &input_device_impl;
+}
+
+static void handle_device_added(struct wlr_libinput_backend *backend,
+ struct libinput_device *libinput_dev) {
+ /*
+ * Note: the wlr API exposes only devices with a single capability, because
+ * that meshes better with how Wayland does things and is a bit simpler.
+ * However, libinput devices often have multiple capabilities - in such
+ * cases we have to create several devices.
+ */
+ int vendor = libinput_device_get_id_vendor(libinput_dev);
+ int product = libinput_device_get_id_product(libinput_dev);
+ const char *name = libinput_device_get_name(libinput_dev);
+ struct wl_list *wlr_devices = calloc(1, sizeof(struct wl_list));
+ if (!wlr_devices) {
+ wlr_log(WLR_ERROR, "Allocation failed");
+ return;
+ }
+ wl_list_init(wlr_devices);
+ wlr_log(WLR_DEBUG, "Added %s [%d:%d]", name, vendor, product);
+
+ if (libinput_device_has_capability(
+ libinput_dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) {
+ struct wlr_input_device *wlr_dev = allocate_device(backend,
+ libinput_dev, wlr_devices, WLR_INPUT_DEVICE_KEYBOARD);
+ if (!wlr_dev) {
+ goto fail;
+ }
+ wlr_dev->keyboard = create_libinput_keyboard(libinput_dev);
+ if (!wlr_dev->keyboard) {
+ free(wlr_dev);
+ goto fail;
+ }
+ wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
+ }
+ if (libinput_device_has_capability(
+ libinput_dev, LIBINPUT_DEVICE_CAP_POINTER)) {
+ struct wlr_input_device *wlr_dev = allocate_device(backend,
+ libinput_dev, wlr_devices, WLR_INPUT_DEVICE_POINTER);
+ if (!wlr_dev) {
+ goto fail;
+ }
+ wlr_dev->pointer = create_libinput_pointer(libinput_dev);
+ if (!wlr_dev->pointer) {
+ free(wlr_dev);
+ goto fail;
+ }
+ wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
+ }
+ if (libinput_device_has_capability(
+ libinput_dev, LIBINPUT_DEVICE_CAP_TOUCH)) {
+ struct wlr_input_device *wlr_dev = allocate_device(backend,
+ libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TOUCH);
+ if (!wlr_dev) {
+ goto fail;
+ }
+ wlr_dev->touch = create_libinput_touch(libinput_dev);
+ if (!wlr_dev->touch) {
+ free(wlr_dev);
+ goto fail;
+ }
+ wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
+ }
+ if (libinput_device_has_capability(libinput_dev,
+ LIBINPUT_DEVICE_CAP_TABLET_TOOL)) {
+ struct wlr_input_device *wlr_dev = allocate_device(backend,
+ libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TABLET_TOOL);
+ if (!wlr_dev) {
+ goto fail;
+ }
+ wlr_dev->tablet = create_libinput_tablet(libinput_dev);
+ if (!wlr_dev->tablet) {
+ free(wlr_dev);
+ goto fail;
+ }
+ wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
+ }
+ if (libinput_device_has_capability(
+ libinput_dev, LIBINPUT_DEVICE_CAP_TABLET_PAD)) {
+ struct wlr_input_device *wlr_dev = allocate_device(backend,
+ libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TABLET_PAD);
+ if (!wlr_dev) {
+ goto fail;
+ }
+ wlr_dev->tablet_pad = create_libinput_tablet_pad(libinput_dev);
+ if (!wlr_dev->tablet_pad) {
+ free(wlr_dev);
+ goto fail;
+ }
+ wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
+ }
+ if (libinput_device_has_capability(
+ libinput_dev, LIBINPUT_DEVICE_CAP_GESTURE)) {
+ // TODO
+ }
+ if (libinput_device_has_capability(
+ libinput_dev, LIBINPUT_DEVICE_CAP_SWITCH)) {
+ struct wlr_input_device *wlr_dev = allocate_device(backend,
+ libinput_dev, wlr_devices, WLR_INPUT_DEVICE_SWITCH);
+ if (!wlr_dev) {
+ goto fail;
+ }
+ wlr_dev->lid_switch = create_libinput_switch(libinput_dev);
+ if (!wlr_dev->lid_switch) {
+ free(wlr_dev);
+ goto fail;
+ }
+ wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
+ }
+
+ if (!wl_list_empty(wlr_devices)) {
+ libinput_device_set_user_data(libinput_dev, wlr_devices);
+ wlr_list_push(&backend->wlr_device_lists, wlr_devices);
+ } else {
+ free(wlr_devices);
+ }
+ return;
+
+fail:
+ wlr_log(WLR_ERROR, "Could not allocate new device");
+ struct wlr_input_device *dev, *tmp_dev;
+ wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) {
+ free(dev);
+ }
+ free(wlr_devices);
+}
+
+static void handle_device_removed(struct wlr_libinput_backend *backend,
+ struct libinput_device *libinput_dev) {
+ struct wl_list *wlr_devices = libinput_device_get_user_data(libinput_dev);
+ int vendor = libinput_device_get_id_vendor(libinput_dev);
+ int product = libinput_device_get_id_product(libinput_dev);
+ const char *name = libinput_device_get_name(libinput_dev);
+ wlr_log(WLR_DEBUG, "Removing %s [%d:%d]", name, vendor, product);
+ if (!wlr_devices) {
+ return;
+ }
+ struct wlr_input_device *dev, *tmp_dev;
+ wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) {
+ wlr_input_device_destroy(dev);
+ }
+ for (size_t i = 0; i < backend->wlr_device_lists.length; i++) {
+ if (backend->wlr_device_lists.items[i] == wlr_devices) {
+ wlr_list_del(&backend->wlr_device_lists, i);
+ break;
+ }
+ }
+ free(wlr_devices);
+}
+
+void handle_libinput_event(struct wlr_libinput_backend *backend,
+ struct libinput_event *event) {
+ struct libinput_device *libinput_dev = libinput_event_get_device(event);
+ enum libinput_event_type event_type = libinput_event_get_type(event);
+ switch (event_type) {
+ case LIBINPUT_EVENT_DEVICE_ADDED:
+ handle_device_added(backend, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_DEVICE_REMOVED:
+ handle_device_removed(backend, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_KEYBOARD_KEY:
+ handle_keyboard_key(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_POINTER_MOTION:
+ handle_pointer_motion(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+ handle_pointer_motion_abs(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_POINTER_BUTTON:
+ handle_pointer_button(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_POINTER_AXIS:
+ handle_pointer_axis(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TOUCH_DOWN:
+ handle_touch_down(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TOUCH_UP:
+ handle_touch_up(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TOUCH_MOTION:
+ handle_touch_motion(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TOUCH_CANCEL:
+ handle_touch_cancel(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TOUCH_FRAME:
+ // no-op (at least for now)
+ break;
+ case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
+ handle_tablet_tool_axis(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
+ handle_tablet_tool_proximity(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TABLET_TOOL_TIP:
+ handle_tablet_tool_tip(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
+ handle_tablet_tool_button(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
+ handle_tablet_pad_button(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TABLET_PAD_RING:
+ handle_tablet_pad_ring(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_TABLET_PAD_STRIP:
+ handle_tablet_pad_strip(event, libinput_dev);
+ break;
+ case LIBINPUT_EVENT_SWITCH_TOGGLE:
+ handle_switch_toggle(event, libinput_dev);
+ break;
+ default:
+ wlr_log(WLR_DEBUG, "Unknown libinput event %d", event_type);
+ break;
+ }
+}
diff --git a/backend/libinput/keyboard.c b/backend/libinput/keyboard.c
new file mode 100644
index 00000000..93605e77
--- /dev/null
+++ b/backend/libinput/keyboard.c
@@ -0,0 +1,83 @@
+#include <assert.h>
+#include <libinput.h>
+#include <stdlib.h>
+#include <wlr/backend/session.h>
+#include <wlr/interfaces/wlr_keyboard.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "backend/libinput.h"
+
+struct wlr_libinput_keyboard {
+ struct wlr_keyboard wlr_keyboard;
+ struct libinput_device *libinput_dev;
+};
+
+static const struct wlr_keyboard_impl impl;
+
+static struct wlr_libinput_keyboard *get_libinput_keyboard_from_keyboard(
+ struct wlr_keyboard *wlr_kb) {
+ assert(wlr_kb->impl == &impl);
+ return (struct wlr_libinput_keyboard *)wlr_kb;
+}
+
+static void keyboard_set_leds(struct wlr_keyboard *wlr_kb, uint32_t leds) {
+ struct wlr_libinput_keyboard *kb =
+ get_libinput_keyboard_from_keyboard(wlr_kb);
+ libinput_device_led_update(kb->libinput_dev, leds);
+}
+
+static void keyboard_destroy(struct wlr_keyboard *wlr_kb) {
+ struct wlr_libinput_keyboard *kb =
+ get_libinput_keyboard_from_keyboard(wlr_kb);
+ libinput_device_unref(kb->libinput_dev);
+ free(kb);
+}
+
+static const struct wlr_keyboard_impl impl = {
+ .destroy = keyboard_destroy,
+ .led_update = keyboard_set_leds
+};
+
+struct wlr_keyboard *create_libinput_keyboard(
+ struct libinput_device *libinput_dev) {
+ struct wlr_libinput_keyboard *kb =
+ calloc(1, sizeof(struct wlr_libinput_keyboard));
+ if (kb == NULL) {
+ return NULL;
+ }
+ kb->libinput_dev = libinput_dev;
+ libinput_device_ref(libinput_dev);
+ libinput_device_led_update(libinput_dev, 0);
+ struct wlr_keyboard *wlr_kb = &kb->wlr_keyboard;
+ wlr_keyboard_init(wlr_kb, &impl);
+ return wlr_kb;
+}
+
+void handle_keyboard_key(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_KEYBOARD, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG,
+ "Got a keyboard event for a device with no keyboards?");
+ return;
+ }
+ struct libinput_event_keyboard *kbevent =
+ libinput_event_get_keyboard_event(event);
+ struct wlr_event_keyboard_key wlr_event = { 0 };
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_keyboard_get_time_usec(kbevent));
+ wlr_event.keycode = libinput_event_keyboard_get_key(kbevent);
+ enum libinput_key_state state =
+ libinput_event_keyboard_get_key_state(kbevent);
+ switch (state) {
+ case LIBINPUT_KEY_STATE_RELEASED:
+ wlr_event.state = WLR_KEY_RELEASED;
+ break;
+ case LIBINPUT_KEY_STATE_PRESSED:
+ wlr_event.state = WLR_KEY_PRESSED;
+ break;
+ }
+ wlr_event.update_state = true;
+ wlr_keyboard_notify_key(wlr_dev->keyboard, &wlr_event);
+}
diff --git a/backend/libinput/pointer.c b/backend/libinput/pointer.c
new file mode 100644
index 00000000..fb85cddd
--- /dev/null
+++ b/backend/libinput/pointer.c
@@ -0,0 +1,136 @@
+#include <assert.h>
+#include <libinput.h>
+#include <stdlib.h>
+#include <wlr/backend/session.h>
+#include <wlr/interfaces/wlr_pointer.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "backend/libinput.h"
+#include "util/signal.h"
+
+struct wlr_pointer *create_libinput_pointer(
+ struct libinput_device *libinput_dev) {
+ assert(libinput_dev);
+ struct wlr_pointer *wlr_pointer = calloc(1, sizeof(struct wlr_pointer));
+ if (!wlr_pointer) {
+ wlr_log(WLR_ERROR, "Unable to allocate wlr_pointer");
+ return NULL;
+ }
+ wlr_pointer_init(wlr_pointer, NULL);
+ return wlr_pointer;
+}
+
+void handle_pointer_motion(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?");
+ return;
+ }
+ struct libinput_event_pointer *pevent =
+ libinput_event_get_pointer_event(event);
+ struct wlr_event_pointer_motion wlr_event = { 0 };
+ wlr_event.device = wlr_dev;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
+ wlr_event.delta_x = libinput_event_pointer_get_dx(pevent);
+ wlr_event.delta_y = libinput_event_pointer_get_dy(pevent);
+ wlr_signal_emit_safe(&wlr_dev->pointer->events.motion, &wlr_event);
+}
+
+void handle_pointer_motion_abs(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?");
+ return;
+ }
+ struct libinput_event_pointer *pevent =
+ libinput_event_get_pointer_event(event);
+ struct wlr_event_pointer_motion_absolute wlr_event = { 0 };
+ wlr_event.device = wlr_dev;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
+ wlr_event.x = libinput_event_pointer_get_absolute_x_transformed(pevent, 1);
+ wlr_event.y = libinput_event_pointer_get_absolute_y_transformed(pevent, 1);
+ wlr_signal_emit_safe(&wlr_dev->pointer->events.motion_absolute, &wlr_event);
+}
+
+void handle_pointer_button(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?");
+ return;
+ }
+ struct libinput_event_pointer *pevent =
+ libinput_event_get_pointer_event(event);
+ struct wlr_event_pointer_button wlr_event = { 0 };
+ wlr_event.device = wlr_dev;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
+ wlr_event.button = libinput_event_pointer_get_button(pevent);
+ switch (libinput_event_pointer_get_button_state(pevent)) {
+ case LIBINPUT_BUTTON_STATE_PRESSED:
+ wlr_event.state = WLR_BUTTON_PRESSED;
+ break;
+ case LIBINPUT_BUTTON_STATE_RELEASED:
+ wlr_event.state = WLR_BUTTON_RELEASED;
+ break;
+ }
+ wlr_signal_emit_safe(&wlr_dev->pointer->events.button, &wlr_event);
+}
+
+void handle_pointer_axis(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?");
+ return;
+ }
+ struct libinput_event_pointer *pevent =
+ libinput_event_get_pointer_event(event);
+ struct wlr_event_pointer_axis wlr_event = { 0 };
+ wlr_event.device = wlr_dev;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
+ switch (libinput_event_pointer_get_axis_source(pevent)) {
+ case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
+ wlr_event.source = WLR_AXIS_SOURCE_WHEEL;
+ break;
+ case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
+ wlr_event.source = WLR_AXIS_SOURCE_FINGER;
+ break;
+ case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
+ wlr_event.source = WLR_AXIS_SOURCE_CONTINUOUS;
+ break;
+ case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT:
+ wlr_event.source = WLR_AXIS_SOURCE_WHEEL_TILT;
+ break;
+ }
+ enum libinput_pointer_axis axies[] = {
+ LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
+ LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
+ };
+ for (size_t i = 0; i < sizeof(axies) / sizeof(axies[0]); ++i) {
+ if (libinput_event_pointer_has_axis(pevent, axies[i])) {
+ switch (axies[i]) {
+ case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL:
+ wlr_event.orientation = WLR_AXIS_ORIENTATION_VERTICAL;
+ break;
+ case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL:
+ wlr_event.orientation = WLR_AXIS_ORIENTATION_HORIZONTAL;
+ break;
+ }
+ wlr_event.delta =
+ libinput_event_pointer_get_axis_value(pevent, axies[i]);
+ wlr_event.delta_discrete =
+ libinput_event_pointer_get_axis_value_discrete(pevent, axies[i]);
+ wlr_signal_emit_safe(&wlr_dev->pointer->events.axis, &wlr_event);
+ }
+ }
+}
diff --git a/backend/libinput/switch.c b/backend/libinput/switch.c
new file mode 100644
index 00000000..393460b0
--- /dev/null
+++ b/backend/libinput/switch.c
@@ -0,0 +1,55 @@
+#include <assert.h>
+#include <libinput.h>
+#include <stdlib.h>
+#include <wlr/backend/session.h>
+#include <wlr/interfaces/wlr_switch.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "backend/libinput.h"
+#include "util/signal.h"
+
+struct wlr_switch *create_libinput_switch(
+ struct libinput_device *libinput_dev) {
+ assert(libinput_dev);
+ struct wlr_switch *wlr_switch = calloc(1, sizeof(struct wlr_switch));
+ if (!wlr_switch) {
+ wlr_log(WLR_ERROR, "Unable to allocate wlr_switch");
+ return NULL;
+ }
+ wlr_switch_init(wlr_switch, NULL);
+ wlr_log(WLR_DEBUG, "Created switch for device %s", libinput_device_get_name(libinput_dev));
+ return wlr_switch;
+}
+
+void handle_switch_toggle(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_SWITCH, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG, "Got a switch event for a device with no switch?");
+ return;
+ }
+ struct libinput_event_switch *sevent =
+ libinput_event_get_switch_event (event);
+ struct wlr_event_switch_toggle wlr_event = { 0 };
+ wlr_event.device = wlr_dev;
+ switch (libinput_event_switch_get_switch(sevent)) {
+ case LIBINPUT_SWITCH_LID:
+ wlr_event.switch_type = WLR_SWITCH_TYPE_LID;
+ break;
+ case LIBINPUT_SWITCH_TABLET_MODE:
+ wlr_event.switch_type = WLR_SWITCH_TYPE_TABLET_MODE;
+ break;
+ }
+ switch (libinput_event_switch_get_switch_state(sevent)) {
+ case LIBINPUT_SWITCH_STATE_OFF:
+ wlr_event.switch_state = WLR_SWITCH_STATE_OFF;
+ break;
+ case LIBINPUT_SWITCH_STATE_ON:
+ wlr_event.switch_state = WLR_SWITCH_STATE_ON;
+ break;
+ }
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_switch_get_time_usec(sevent));
+ wlr_signal_emit_safe(&wlr_dev->lid_switch->events.toggle, &wlr_event);
+}
diff --git a/backend/libinput/tablet_pad.c b/backend/libinput/tablet_pad.c
new file mode 100644
index 00000000..b053b9a0
--- /dev/null
+++ b/backend/libinput/tablet_pad.c
@@ -0,0 +1,183 @@
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
+#endif
+#include <assert.h>
+#include <string.h>
+#include <libinput.h>
+#include <stdlib.h>
+#include <wlr/backend/session.h>
+#include <wlr/interfaces/wlr_tablet_pad.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "backend/libinput.h"
+#include "util/signal.h"
+
+// FIXME: Decide on how to alloc/count here
+static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad,
+ struct libinput_device *device, unsigned int index) {
+ struct libinput_tablet_pad_mode_group *li_group =
+ libinput_device_tablet_pad_get_mode_group(device, index);
+ struct wlr_tablet_pad_group *group =
+ calloc(1, sizeof(struct wlr_tablet_pad_group));
+ if (!group) {
+ return;
+ }
+
+ for (size_t i = 0; i < pad->ring_count; ++i) {
+ if (libinput_tablet_pad_mode_group_has_ring(li_group, i)) {
+ ++group->ring_count;
+ }
+ }
+ group->rings = calloc(sizeof(unsigned int), group->ring_count);
+ size_t ring = 0;
+ for (size_t i = 0; i < pad->ring_count; ++i) {
+ if (libinput_tablet_pad_mode_group_has_ring(li_group, i)) {
+ group->rings[ring++] = i;
+ }
+ }
+
+ for (size_t i = 0; i < pad->strip_count; ++i) {
+ if (libinput_tablet_pad_mode_group_has_strip(li_group, i)) {
+ ++group->strip_count;
+ }
+ }
+ group->strips = calloc(sizeof(unsigned int), group->strip_count);
+ size_t strip = 0;
+ for (size_t i = 0; i < pad->strip_count; ++i) {
+ if (libinput_tablet_pad_mode_group_has_strip(li_group, i)) {
+ group->strips[strip++] = i;
+ }
+ }
+
+ for (size_t i = 0; i < pad->button_count; ++i) {
+ if (libinput_tablet_pad_mode_group_has_button(li_group, i)) {
+ ++group->button_count;
+ }
+ }
+ group->buttons = calloc(sizeof(unsigned int), group->button_count);
+ size_t button = 0;
+ for (size_t i = 0; i < pad->button_count; ++i) {
+ if (libinput_tablet_pad_mode_group_has_button(li_group, i)) {
+ group->buttons[button++] = i;
+ }
+ }
+
+ group->mode_count = libinput_tablet_pad_mode_group_get_num_modes(li_group);
+ wl_list_insert(&pad->groups, &group->link);
+}
+
+struct wlr_tablet_pad *create_libinput_tablet_pad(
+ struct libinput_device *libinput_dev) {
+ assert(libinput_dev);
+ struct wlr_tablet_pad *wlr_tablet_pad =
+ calloc(1, sizeof(struct wlr_tablet_pad));
+ if (!wlr_tablet_pad) {
+ wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_pad");
+ return NULL;
+ }
+
+ wlr_tablet_pad->button_count =
+ libinput_device_tablet_pad_get_num_buttons(libinput_dev);
+ wlr_tablet_pad->ring_count =
+ libinput_device_tablet_pad_get_num_rings(libinput_dev);
+ wlr_tablet_pad->strip_count =
+ libinput_device_tablet_pad_get_num_strips(libinput_dev);
+
+ wlr_list_init(&wlr_tablet_pad->paths);
+ struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
+ wlr_list_push(&wlr_tablet_pad->paths, strdup(udev_device_get_syspath(udev)));
+
+ wl_list_init(&wlr_tablet_pad->groups);
+ int groups = libinput_device_tablet_pad_get_num_mode_groups(libinput_dev);
+ for (int i = 0; i < groups; ++i) {
+ add_pad_group_from_libinput(wlr_tablet_pad, libinput_dev, i);
+ }
+
+ wlr_tablet_pad_init(wlr_tablet_pad, NULL);
+ return wlr_tablet_pad;
+}
+
+void handle_tablet_pad_button(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG,
+ "Got a tablet pad event for a device with no tablet pad?");
+ return;
+ }
+ struct libinput_event_tablet_pad *pevent =
+ libinput_event_get_tablet_pad_event(event);
+ struct wlr_event_tablet_pad_button wlr_event = { 0 };
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent));
+ wlr_event.button = libinput_event_tablet_pad_get_button_number(pevent);
+ wlr_event.mode = libinput_event_tablet_pad_get_mode(pevent);
+ wlr_event.group = libinput_tablet_pad_mode_group_get_index(
+ libinput_event_tablet_pad_get_mode_group(pevent));
+ switch (libinput_event_tablet_pad_get_button_state(pevent)) {
+ case LIBINPUT_BUTTON_STATE_PRESSED:
+ wlr_event.state = WLR_BUTTON_PRESSED;
+ break;
+ case LIBINPUT_BUTTON_STATE_RELEASED:
+ wlr_event.state = WLR_BUTTON_RELEASED;
+ break;
+ }
+ wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.button, &wlr_event);
+}
+
+void handle_tablet_pad_ring(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG,
+ "Got a tablet pad event for a device with no tablet pad?");
+ return;
+ }
+ struct libinput_event_tablet_pad *pevent =
+ libinput_event_get_tablet_pad_event(event);
+ struct wlr_event_tablet_pad_ring wlr_event = { 0 };
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent));
+ wlr_event.ring = libinput_event_tablet_pad_get_ring_number(pevent);
+ wlr_event.position = libinput_event_tablet_pad_get_ring_position(pevent);
+ wlr_event.mode = libinput_event_tablet_pad_get_mode(pevent);
+ switch (libinput_event_tablet_pad_get_ring_source(pevent)) {
+ case LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN:
+ wlr_event.source = WLR_TABLET_PAD_RING_SOURCE_UNKNOWN;
+ break;
+ case LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER:
+ wlr_event.source = WLR_TABLET_PAD_RING_SOURCE_FINGER;
+ break;
+ }
+ wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.ring, &wlr_event);
+}
+
+void handle_tablet_pad_strip(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG,
+ "Got a tablet pad event for a device with no tablet pad?");
+ return;
+ }
+ struct libinput_event_tablet_pad *pevent =
+ libinput_event_get_tablet_pad_event(event);
+ struct wlr_event_tablet_pad_strip wlr_event = { 0 };
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent));
+ wlr_event.strip = libinput_event_tablet_pad_get_strip_number(pevent);
+ wlr_event.position = libinput_event_tablet_pad_get_strip_position(pevent);
+ wlr_event.mode = libinput_event_tablet_pad_get_mode(pevent);
+ switch (libinput_event_tablet_pad_get_strip_source(pevent)) {
+ case LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN:
+ wlr_event.source = WLR_TABLET_PAD_STRIP_SOURCE_UNKNOWN;
+ break;
+ case LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER:
+ wlr_event.source = WLR_TABLET_PAD_STRIP_SOURCE_FINGER;
+ break;
+ }
+ wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.strip, &wlr_event);
+}
diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c
new file mode 100644
index 00000000..4e87b700
--- /dev/null
+++ b/backend/libinput/tablet_tool.c
@@ -0,0 +1,371 @@
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
+#endif
+#include <string.h>
+#include <assert.h>
+#include <libinput.h>
+#include <stdlib.h>
+#include <wayland-util.h>
+#include <wlr/backend/session.h>
+#include <wlr/interfaces/wlr_tablet_tool.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "backend/libinput.h"
+#include "util/signal.h"
+
+static struct wlr_tablet_impl tablet_impl;
+
+static bool tablet_is_libinput(struct wlr_tablet *tablet) {
+ return tablet->impl == &tablet_impl;
+}
+
+struct wlr_libinput_tablet_tool {
+ struct wlr_tablet_tool wlr_tool;
+
+ struct libinput_tablet_tool *libinput_tool;
+
+ bool unique;
+ // Refcount for destroy + release
+ size_t pad_refs;
+};
+
+// TODO: Maybe this should be a wlr_list? Do we keep it, or want to get rid of
+// it?
+struct tablet_tool_list_elem {
+ struct wl_list link;
+
+ struct wlr_libinput_tablet_tool *tool;
+};
+
+struct wlr_libinput_tablet {
+ struct wlr_tablet wlr_tablet;
+
+ struct wl_list tools; // tablet_tool_list_elem::link
+};
+
+static void destroy_tool(struct wlr_libinput_tablet_tool *tool) {
+ wlr_signal_emit_safe(&tool->wlr_tool.events.destroy, &tool->wlr_tool);
+ libinput_tablet_tool_ref(tool->libinput_tool);
+ libinput_tablet_tool_set_user_data(tool->libinput_tool, NULL);
+ free(tool);
+}
+
+
+static void destroy_tablet(struct wlr_tablet *wlr_tablet) {
+ assert(tablet_is_libinput(wlr_tablet));
+ struct wlr_libinput_tablet *tablet =
+ wl_container_of(wlr_tablet, tablet, wlr_tablet);
+
+ struct tablet_tool_list_elem *pos;
+ struct tablet_tool_list_elem *tmp;
+ wl_list_for_each_safe(pos, tmp, &tablet->tools, link) {
+ struct wlr_libinput_tablet_tool *tool = pos->tool;
+ wl_list_remove(&pos->link);
+ free(pos);
+
+ if (--tool->pad_refs == 0) {
+ destroy_tool(tool);
+ }
+ }
+
+ free(tablet);
+}
+
+static struct wlr_tablet_impl tablet_impl = {
+ .destroy = destroy_tablet,
+};
+
+struct wlr_tablet *create_libinput_tablet(
+ struct libinput_device *libinput_dev) {
+ assert(libinput_dev);
+ struct wlr_libinput_tablet *libinput_tablet =
+ calloc(1, sizeof(struct wlr_libinput_tablet));
+ if (!libinput_tablet) {
+ wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_tool");
+ return NULL;
+ }
+ struct wlr_tablet *wlr_tablet = &libinput_tablet->wlr_tablet;
+
+ wlr_list_init(&wlr_tablet->paths);
+ struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
+ wlr_list_push(&wlr_tablet->paths, strdup(udev_device_get_syspath(udev)));
+ wlr_tablet->name = strdup(libinput_device_get_name(libinput_dev));
+ wl_list_init(&libinput_tablet->tools);
+
+ wlr_tablet_init(wlr_tablet, &tablet_impl);
+ return wlr_tablet;
+}
+
+static enum wlr_tablet_tool_type wlr_type_from_libinput_type(
+ enum libinput_tablet_tool_type value) {
+ switch (value) {
+ case LIBINPUT_TABLET_TOOL_TYPE_PEN:
+ return WLR_TABLET_TOOL_TYPE_PEN;
+ case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
+ return WLR_TABLET_TOOL_TYPE_ERASER;
+ case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
+ return WLR_TABLET_TOOL_TYPE_BRUSH;
+ case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
+ return WLR_TABLET_TOOL_TYPE_PENCIL;
+ case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
+ return WLR_TABLET_TOOL_TYPE_AIRBRUSH;
+ case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
+ return WLR_TABLET_TOOL_TYPE_MOUSE;
+ case LIBINPUT_TABLET_TOOL_TYPE_LENS:
+ return WLR_TABLET_TOOL_TYPE_LENS;
+ }
+
+ assert(false && "UNREACHABLE");
+}
+
+static struct wlr_libinput_tablet_tool *get_wlr_tablet_tool(
+ struct libinput_tablet_tool *tool) {
+ struct wlr_libinput_tablet_tool *ret =
+ libinput_tablet_tool_get_user_data(tool);
+
+ if (ret) {
+ return ret;
+ }
+
+ ret = calloc(1, sizeof(struct wlr_libinput_tablet_tool));
+ if (!ret) {
+ return NULL;
+ }
+
+ ret->libinput_tool = libinput_tablet_tool_ref(tool);
+ ret->wlr_tool.pressure = libinput_tablet_tool_has_pressure(tool);
+ ret->wlr_tool.distance = libinput_tablet_tool_has_distance(tool);
+ ret->wlr_tool.tilt = libinput_tablet_tool_has_tilt(tool);
+ ret->wlr_tool.rotation = libinput_tablet_tool_has_rotation(tool);
+ ret->wlr_tool.slider = libinput_tablet_tool_has_slider(tool);
+ ret->wlr_tool.wheel = libinput_tablet_tool_has_wheel(tool);
+
+ ret->wlr_tool.hardware_serial = libinput_tablet_tool_get_serial(tool);
+ ret->wlr_tool.hardware_wacom = libinput_tablet_tool_get_tool_id(tool);
+ ret->wlr_tool.type = wlr_type_from_libinput_type(
+ libinput_tablet_tool_get_type(tool));
+
+ ret->unique = libinput_tablet_tool_is_unique(tool);
+
+ wl_signal_init(&ret->wlr_tool.events.destroy);
+
+ libinput_tablet_tool_set_user_data(tool, ret);
+ return ret;
+}
+
+static void ensure_tool_reference(struct wlr_libinput_tablet_tool *tool,
+ struct wlr_tablet *wlr_dev) {
+ assert(tablet_is_libinput(wlr_dev));
+ struct wlr_libinput_tablet *tablet =
+ wl_container_of(wlr_dev, tablet, wlr_tablet);
+
+ struct tablet_tool_list_elem *pos;
+ wl_list_for_each(pos, &tablet->tools, link) {
+ if (pos->tool == tool) { // We already have a ref
+ // XXX: We *could* optimize the tool to the front of
+ // the list here, since we will probably get the next
+ // couple of events from the same tool.
+ // BUT the list should always be rather short (probably
+ // single digit amount of tools) so it might be more
+ // work than it saves
+ return;
+ }
+ }
+
+ struct tablet_tool_list_elem *new =
+ calloc(1, sizeof(struct tablet_tool_list_elem));
+ if (!new) {
+ wlr_log(WLR_ERROR, "Failed to allocate memory for tracking tablet tool");
+ return;
+ }
+
+ new->tool = tool;
+ wl_list_insert(&tablet->tools, &new->link);
+ ++tool->pad_refs;
+}
+
+void handle_tablet_tool_axis(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG,
+ "Got a tablet tool event for a device with no tablet tools?");
+ return;
+ }
+ struct libinput_event_tablet_tool *tevent =
+ libinput_event_get_tablet_tool_event(event);
+ struct wlr_event_tablet_tool_axis wlr_event = { 0 };
+ struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool(
+ libinput_event_tablet_tool_get_tool(tevent));
+ ensure_tool_reference(tool, wlr_dev->tablet);
+
+ wlr_event.device = wlr_dev;
+ wlr_event.tool = &tool->wlr_tool;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent));
+ if (libinput_event_tablet_tool_x_has_changed(tevent)) {
+ wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_X;
+ wlr_event.x = libinput_event_tablet_tool_get_x_transformed(tevent, 1);
+ wlr_event.dx = libinput_event_tablet_tool_get_dx(tevent);
+ }
+ if (libinput_event_tablet_tool_y_has_changed(tevent)) {
+ wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_Y;
+ wlr_event.y = libinput_event_tablet_tool_get_y_transformed(tevent, 1);
+ wlr_event.dy = libinput_event_tablet_tool_get_dy(tevent);
+ }
+ if (libinput_event_tablet_tool_pressure_has_changed(tevent)) {
+ wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_PRESSURE;
+ wlr_event.pressure = libinput_event_tablet_tool_get_pressure(tevent);
+ }
+ if (libinput_event_tablet_tool_distance_has_changed(tevent)) {
+ wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_DISTANCE;
+ wlr_event.distance = libinput_event_tablet_tool_get_distance(tevent);
+ }
+ if (libinput_event_tablet_tool_tilt_x_has_changed(tevent)) {
+ wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_TILT_X;
+ wlr_event.tilt_x = libinput_event_tablet_tool_get_tilt_x(tevent);
+ }
+ if (libinput_event_tablet_tool_tilt_y_has_changed(tevent)) {
+ wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_TILT_Y;
+ wlr_event.tilt_y = libinput_event_tablet_tool_get_tilt_y(tevent);
+ }
+ if (libinput_event_tablet_tool_rotation_has_changed(tevent)) {
+ wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_ROTATION;
+ wlr_event.rotation = libinput_event_tablet_tool_get_rotation(tevent);
+ }
+ if (libinput_event_tablet_tool_slider_has_changed(tevent)) {
+ wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_SLIDER;
+ wlr_event.slider = libinput_event_tablet_tool_get_slider_position(tevent);
+ }
+ if (libinput_event_tablet_tool_wheel_has_changed(tevent)) {
+ wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_WHEEL;
+ wlr_event.wheel_delta = libinput_event_tablet_tool_get_wheel_delta(tevent);
+ }
+ wlr_signal_emit_safe(&wlr_dev->tablet->events.axis, &wlr_event);
+}
+
+void handle_tablet_tool_proximity(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG,
+ "Got a tablet tool event for a device with no tablet tools?");
+ return;
+ }
+ struct libinput_event_tablet_tool *tevent =
+ libinput_event_get_tablet_tool_event(event);
+ struct wlr_event_tablet_tool_proximity wlr_event = { 0 };
+ struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool(
+ libinput_event_tablet_tool_get_tool(tevent));
+ ensure_tool_reference(tool, wlr_dev->tablet);
+
+ wlr_event.tool = &tool->wlr_tool;
+ wlr_event.device = wlr_dev;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent));
+ switch (libinput_event_tablet_tool_get_proximity_state(tevent)) {
+ case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT:
+ wlr_event.state = WLR_TABLET_TOOL_PROXIMITY_OUT;
+ break;
+ case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN:
+ wlr_event.state = WLR_TABLET_TOOL_PROXIMITY_IN;
+ break;
+ }
+ wlr_signal_emit_safe(&wlr_dev->tablet->events.proximity, &wlr_event);
+
+ if (libinput_event_tablet_tool_get_proximity_state(tevent) ==
+ LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN) {
+ handle_tablet_tool_axis(event, libinput_dev);
+ }
+
+ // If the tool is not unique, libinput will not find it again after the
+ // proximity out, so we should destroy it
+ if (!tool->unique &&
+ libinput_event_tablet_tool_get_proximity_state(tevent) ==
+ LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) {
+ // The tool isn't unique, it can't be on multiple tablets
+ assert(tool->pad_refs == 1);
+ assert(tablet_is_libinput(wlr_dev->tablet));
+ struct wlr_libinput_tablet *tablet =
+ wl_container_of(wlr_dev->tablet, tablet, wlr_tablet);
+ struct tablet_tool_list_elem *pos;
+ struct tablet_tool_list_elem *tmp;
+
+ wl_list_for_each_safe(pos, tmp, &tablet->tools, link) {
+ if (pos->tool == tool) {
+ wl_list_remove(&pos->link);
+ free(pos);
+ break;
+ }
+ }
+
+ destroy_tool(tool);
+ }
+}
+
+void handle_tablet_tool_tip(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG,
+ "Got a tablet tool event for a device with no tablet tools?");
+ return;
+ }
+ handle_tablet_tool_axis(event, libinput_dev);
+ struct libinput_event_tablet_tool *tevent =
+ libinput_event_get_tablet_tool_event(event);
+ struct wlr_event_tablet_tool_tip wlr_event = { 0 };
+ struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool(
+ libinput_event_tablet_tool_get_tool(tevent));
+ ensure_tool_reference(tool, wlr_dev->tablet);
+
+ wlr_event.device = wlr_dev;
+ wlr_event.tool = &tool->wlr_tool;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent));
+ switch (libinput_event_tablet_tool_get_tip_state(tevent)) {
+ case LIBINPUT_TABLET_TOOL_TIP_UP:
+ wlr_event.state = WLR_TABLET_TOOL_TIP_UP;
+ break;
+ case LIBINPUT_TABLET_TOOL_TIP_DOWN:
+ wlr_event.state = WLR_TABLET_TOOL_TIP_DOWN;
+ break;
+ }
+ wlr_signal_emit_safe(&wlr_dev->tablet->events.tip, &wlr_event);
+}
+
+void handle_tablet_tool_button(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG,
+ "Got a tablet tool event for a device with no tablet tools?");
+ return;
+ }
+ handle_tablet_tool_axis(event, libinput_dev);
+ struct libinput_event_tablet_tool *tevent =
+ libinput_event_get_tablet_tool_event(event);
+ struct wlr_event_tablet_tool_button wlr_event = { 0 };
+ struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool(
+ libinput_event_tablet_tool_get_tool(tevent));
+ ensure_tool_reference(tool, wlr_dev->tablet);
+
+ wlr_event.device = wlr_dev;
+ wlr_event.tool = &tool->wlr_tool;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent));
+ wlr_event.button = libinput_event_tablet_tool_get_button(tevent);
+ switch (libinput_event_tablet_tool_get_button_state(tevent)) {
+ case LIBINPUT_BUTTON_STATE_RELEASED:
+ wlr_event.state = WLR_BUTTON_RELEASED;
+ break;
+ case LIBINPUT_BUTTON_STATE_PRESSED:
+ wlr_event.state = WLR_BUTTON_PRESSED;
+ break;
+ }
+ wlr_signal_emit_safe(&wlr_dev->tablet->events.button, &wlr_event);
+}
diff --git a/backend/libinput/touch.c b/backend/libinput/touch.c
new file mode 100644
index 00000000..cb9b0e36
--- /dev/null
+++ b/backend/libinput/touch.c
@@ -0,0 +1,97 @@
+#include <assert.h>
+#include <libinput.h>
+#include <stdlib.h>
+#include <wlr/backend/session.h>
+#include <wlr/interfaces/wlr_touch.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "backend/libinput.h"
+#include "util/signal.h"
+
+struct wlr_touch *create_libinput_touch(
+ struct libinput_device *libinput_dev) {
+ assert(libinput_dev);
+ struct wlr_touch *wlr_touch = calloc(1, sizeof(struct wlr_touch));
+ if (!wlr_touch) {
+ wlr_log(WLR_ERROR, "Unable to allocate wlr_touch");
+ return NULL;
+ }
+ wlr_touch_init(wlr_touch, NULL);
+ return wlr_touch;
+}
+
+void handle_touch_down(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
+ return;
+ }
+ struct libinput_event_touch *tevent =
+ libinput_event_get_touch_event(event);
+ struct wlr_event_touch_down wlr_event = { 0 };
+ wlr_event.device = wlr_dev;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_touch_get_time_usec(tevent));
+ wlr_event.touch_id = libinput_event_touch_get_slot(tevent);
+ wlr_event.x = libinput_event_touch_get_x_transformed(tevent, 1);
+ wlr_event.y = libinput_event_touch_get_y_transformed(tevent, 1);
+ wlr_signal_emit_safe(&wlr_dev->touch->events.down, &wlr_event);
+}
+
+void handle_touch_up(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
+ return;
+ }
+ struct libinput_event_touch *tevent =
+ libinput_event_get_touch_event(event);
+ struct wlr_event_touch_up wlr_event = { 0 };
+ wlr_event.device = wlr_dev;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_touch_get_time_usec(tevent));
+ wlr_event.touch_id = libinput_event_touch_get_slot(tevent);
+ wlr_signal_emit_safe(&wlr_dev->touch->events.up, &wlr_event);
+}
+
+void handle_touch_motion(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
+ return;
+ }
+ struct libinput_event_touch *tevent =
+ libinput_event_get_touch_event(event);
+ struct wlr_event_touch_motion wlr_event = { 0 };
+ wlr_event.device = wlr_dev;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_touch_get_time_usec(tevent));
+ wlr_event.touch_id = libinput_event_touch_get_slot(tevent);
+ wlr_event.x = libinput_event_touch_get_x_transformed(tevent, 1);
+ wlr_event.y = libinput_event_touch_get_y_transformed(tevent, 1);
+ wlr_signal_emit_safe(&wlr_dev->touch->events.motion, &wlr_event);
+}
+
+void handle_touch_cancel(struct libinput_event *event,
+ struct libinput_device *libinput_dev) {
+ struct wlr_input_device *wlr_dev =
+ get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
+ if (!wlr_dev) {
+ wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
+ return;
+ }
+ struct libinput_event_touch *tevent =
+ libinput_event_get_touch_event(event);
+ struct wlr_event_touch_cancel wlr_event = { 0 };
+ wlr_event.device = wlr_dev;
+ wlr_event.time_msec =
+ usec_to_msec(libinput_event_touch_get_time_usec(tevent));
+ wlr_event.touch_id = libinput_event_touch_get_slot(tevent);
+ wlr_signal_emit_safe(&wlr_dev->touch->events.cancel, &wlr_event);
+}