From 3c0cea92f26557103285a716ef7fd6ee5807b925 Mon Sep 17 00:00:00 2001 From: Jens Peters Date: Tue, 4 Jun 2024 20:21:12 +0200 Subject: [PATCH] input: support tablet-v2 pad notifications --- include/input/tablet-pad.h | 12 ++- src/input/tablet-pad.c | 147 ++++++++++++++++++++++++++++++++++--- src/input/tablet.c | 5 ++ src/seat.c | 1 + 4 files changed, 155 insertions(+), 10 deletions(-) diff --git a/include/input/tablet-pad.h b/include/input/tablet-pad.h index c17b2f7f..4f39239f 100644 --- a/include/input/tablet-pad.h +++ b/include/input/tablet-pad.h @@ -3,6 +3,7 @@ #define LABWC_TABLET_PAD_H #include +#include struct seat; struct wlr_device; @@ -19,15 +20,24 @@ struct wlr_input_device; #define LAB_BTN_PAD9 0x8 struct drawing_tablet_pad { + struct wlr_input_device *wlr_input_device; struct seat *seat; - struct wlr_tablet_pad *tablet; + struct wlr_tablet_pad *pad; + struct wlr_tablet_v2_tablet_pad *pad_v2; + struct drawing_tablet *tablet; + struct wlr_surface *current_surface; struct { + struct wl_listener current_surface_destroy; struct wl_listener button; + struct wl_listener ring; + struct wl_listener strip; struct wl_listener destroy; } handlers; struct wl_list link; /* seat.tablet_pads */ }; void tablet_pad_init(struct seat *seat, struct wlr_input_device *wlr_input_device); +void tablet_pad_attach_tablet(struct seat *seat); +void tablet_pad_enter_surface(struct seat *seat, struct wlr_surface *wlr_surface); #endif /* LABWC_TABLET_PAD_H */ diff --git a/src/input/tablet-pad.c b/src/input/tablet-pad.c index 2afa5e12..1729e356 100644 --- a/src/input/tablet-pad.c +++ b/src/input/tablet-pad.c @@ -1,27 +1,143 @@ // SPDX-License-Identifier: GPL-2.0-only #include #include +#include #include +#include #include #include "common/macros.h" #include "common/mem.h" #include "config/rcxml.h" #include "input/cursor.h" #include "input/tablet-pad.h" +#include "input/tablet.h" +#include "labwc.h" + +void +tablet_pad_attach_tablet(struct seat *seat) +{ + /* reset all tablet - pad links */ + struct drawing_tablet_pad *pad; + wl_list_for_each(pad, &seat->tablet_pads, link) { + pad->tablet = NULL; + } + + /* loop over all tablets and all pads and link by device group */ + struct drawing_tablet *tablet; + wl_list_for_each(tablet, &seat->tablets, link) { + struct libinput_device *tablet_device = + wlr_libinput_get_device_handle(tablet->wlr_input_device); + struct libinput_device_group *tablet_group = + libinput_device_get_device_group(tablet_device); + + wl_list_for_each(pad, &seat->tablet_pads, link) { + struct libinput_device *pad_device = + wlr_libinput_get_device_handle(pad->wlr_input_device); + struct libinput_device_group *pad_group = + libinput_device_get_device_group(pad_device); + + if (tablet_group == pad_group) { + wlr_log(WLR_DEBUG, "attach tablet to pad based on device group"); + pad->tablet = tablet; + } + } + } +} + +static void +handle_surface_destroy(struct wl_listener *listener, void *data) +{ + struct drawing_tablet_pad *pad = + wl_container_of(listener, pad, handlers.current_surface_destroy); + + pad->current_surface = NULL; + wl_list_remove(&pad->handlers.current_surface_destroy.link); +} + +void +tablet_pad_enter_surface(struct seat *seat, struct wlr_surface *surface) +{ + if (!surface) { + return; + } + + struct drawing_tablet_pad *pad; + wl_list_for_each(pad, &seat->tablet_pads, link) { + /* pad needs a linked tablet and both need tablet-v2 support */ + if (pad->tablet && pad->pad_v2 && pad->tablet->tablet_v2) { + if (pad->current_surface) { + wlr_tablet_v2_tablet_pad_notify_leave(pad->pad_v2, + pad->current_surface); + + /* remove previous surface destroy handler */ + wl_list_remove(&pad->handlers.current_surface_destroy.link); + } + + pad->current_surface = surface; + wlr_tablet_v2_tablet_pad_notify_enter(pad->pad_v2, + pad->tablet->tablet_v2, surface); + + /* signal surface destroy handler */ + wl_signal_add(&pad->current_surface->events.destroy, + &pad->handlers.current_surface_destroy); + pad->handlers.current_surface_destroy.notify = + handle_surface_destroy; + } + } +} static void handle_button(struct wl_listener *listener, void *data) { - struct drawing_tablet_pad *tablet_pad = - wl_container_of(listener, tablet_pad, handlers.button); + struct drawing_tablet_pad *pad = + wl_container_of(listener, pad, handlers.button); struct wlr_tablet_pad_button_event *ev = data; - uint32_t button = tablet_get_mapped_button(ev->button); - if (!button) { - return; + if (!rc.tablet.force_mouse_emulation + && pad->pad_v2 && pad->current_surface) { + wlr_tablet_v2_tablet_pad_notify_button(pad->pad_v2, ev->button, + ev->time_msec, + ev->state == WLR_BUTTON_PRESSED + ? ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED + : ZWP_TABLET_PAD_V2_BUTTON_STATE_RELEASED); + } else { + uint32_t button = tablet_get_mapped_button(ev->button); + if (button) { + cursor_emulate_button(pad->seat, button, ev->state, ev->time_msec); + } } +} - cursor_emulate_button(tablet_pad->seat, button, ev->state, ev->time_msec); +static void +handle_ring(struct wl_listener *listener, void *data) +{ + struct drawing_tablet_pad *pad = + wl_container_of(listener, pad, handlers.ring); + struct wlr_tablet_pad_ring_event *ev = data; + + if (!rc.tablet.force_mouse_emulation + && pad->pad_v2 && pad->current_surface) { + wlr_tablet_v2_tablet_pad_notify_ring(pad->pad_v2, + ev->ring, ev->position, + ev->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, + ev->time_msec); + } +} + +static void +handle_strip(struct wl_listener *listener, void *data) +{ + struct drawing_tablet_pad *pad = + wl_container_of(listener, pad, handlers.strip); + struct wlr_tablet_pad_strip_event *ev = data; + + if (!rc.tablet.force_mouse_emulation + && pad->pad_v2 && pad->current_surface) { + wlr_tablet_v2_tablet_pad_notify_strip(pad->pad_v2, + ev->strip, ev->position, + ev->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, + ev->time_msec); + } } static void @@ -30,8 +146,13 @@ handle_destroy(struct wl_listener *listener, void *data) struct drawing_tablet_pad *pad = wl_container_of(listener, pad, handlers.destroy); + if (pad->current_surface) { + wl_list_remove(&pad->handlers.current_surface_destroy.link); + } wl_list_remove(&pad->link); wl_list_remove(&pad->handlers.button.link); + wl_list_remove(&pad->handlers.ring.link); + wl_list_remove(&pad->handlers.strip.link); wl_list_remove(&pad->handlers.destroy.link); free(pad); } @@ -42,9 +163,17 @@ tablet_pad_init(struct seat *seat, struct wlr_input_device *wlr_device) wlr_log(WLR_DEBUG, "setting up tablet pad"); struct drawing_tablet_pad *pad = znew(*pad); pad->seat = seat; - pad->tablet = wlr_tablet_pad_from_input_device(wlr_device); - pad->tablet->data = pad; - CONNECT_SIGNAL(pad->tablet, &pad->handlers, button); + pad->wlr_input_device = wlr_device; + pad->pad = wlr_tablet_pad_from_input_device(wlr_device); + if (seat->server->tablet_manager) { + pad->pad_v2 = wlr_tablet_pad_create( + seat->server->tablet_manager, seat->seat, wlr_device); + } + pad->pad->data = pad; + CONNECT_SIGNAL(pad->pad, &pad->handlers, button); + CONNECT_SIGNAL(pad->pad, &pad->handlers, ring); + CONNECT_SIGNAL(pad->pad, &pad->handlers, strip); CONNECT_SIGNAL(wlr_device, &pad->handlers, destroy); wl_list_insert(&seat->tablet_pads, &pad->link); + tablet_pad_attach_tablet(pad->seat); } diff --git a/src/input/tablet.c b/src/input/tablet.c index 8ba1fda7..3d8caa61 100644 --- a/src/input/tablet.c +++ b/src/input/tablet.c @@ -14,6 +14,7 @@ #include "input/cursor.h" #include "input/tablet.h" #include "input/tablet-tool.h" +#include "input/tablet-pad.h" #include "labwc.h" #include "idle.h" #include "action.h" @@ -511,6 +512,8 @@ handle_destroy(struct wl_listener *listener, void *data) wl_container_of(listener, tablet, handlers.destroy); wl_list_remove(&tablet->link); + tablet_pad_attach_tablet(tablet->seat); + wl_list_remove(&tablet->handlers.tip.link); wl_list_remove(&tablet->handlers.button.link); wl_list_remove(&tablet->handlers.proximity.link); @@ -548,5 +551,7 @@ tablet_init(struct seat *seat, struct wlr_input_device *wlr_device) CONNECT_SIGNAL(tablet->tablet, &tablet->handlers, tip); CONNECT_SIGNAL(tablet->tablet, &tablet->handlers, button); CONNECT_SIGNAL(wlr_device, &tablet->handlers, destroy); + wl_list_insert(&seat->tablets, &tablet->link); + tablet_pad_attach_tablet(tablet->seat); } diff --git a/src/seat.c b/src/seat.c index edeaf819..ce1751c4 100644 --- a/src/seat.c +++ b/src/seat.c @@ -504,6 +504,7 @@ focus_change_notify(struct wl_listener *listener, void *data) } if (view) { view_set_activated(view, true); + tablet_pad_enter_surface(seat, surface); } server->active_view = view; }