Patch-Source: https://gitlab.gnome.org/GNOME/gtk/-/commit/7141305972a73559c97730e17d38a0a7440f3599 https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6095 -- From 6070f1092258e053ecdbe2dbf6148d2dd9d8b326 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Tue, 13 Jun 2023 22:11:15 +0200 Subject: [PATCH 1/3] gdk/wayland: Create pad devices on enter We were creating the pad device on wp_tablet_pad.done, but at that time we do not know what tablet it is associated with, thus we cannot get appropriate vid/pid/name properties for it. To get that, we need to wait for the pad to enter a surface, at that time we do know what tablet it is associated with, so we can get better information about the device. There are pads that may plausibly "change" tablet between one .enter event and the next (e.g. Wacom Express Key Remote), but this situation is highly unlikely. The pad devices created are thus persistent until that situation happens. --- gdk/wayland/gdkdevice-wayland.c | 86 ++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 9dc86a32578..7e7beac9d1e 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -2921,13 +2921,17 @@ _gdk_wayland_seat_remove_tablet_pad (GdkWaylandSeat *seat, seat->tablet_pads = g_list_remove (seat->tablet_pads, pad); - device_manager->devices = - g_list_remove (device_manager->devices, pad->device); - g_signal_emit_by_name (device_manager, "device-removed", pad->device); + if (pad->device) + { + device_manager->devices = + g_list_remove (device_manager->devices, pad->device); + g_signal_emit_by_name (device_manager, "device-removed", pad->device); - _gdk_device_set_associated_device (pad->device, NULL); + _gdk_device_set_associated_device (pad->device, NULL); + + g_object_unref (pad->device); + } - g_object_unref (pad->device); g_free (pad); } @@ -4439,27 +4443,8 @@ static void tablet_pad_handle_done (void *data, struct zwp_tablet_pad_v2 *wp_tablet_pad) { - GdkWaylandTabletPadData *pad = data; - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat); - GdkWaylandDeviceManager *device_manager = - GDK_WAYLAND_DEVICE_MANAGER (seat->device_manager); - GDK_NOTE (EVENTS, g_message ("tablet pad handle done, pad = %p", wp_tablet_pad)); - - pad->device = - g_object_new (GDK_TYPE_WAYLAND_DEVICE_PAD, - "name", "Pad device", - "type", GDK_DEVICE_TYPE_SLAVE, - "input-source", GDK_SOURCE_TABLET_PAD, - "input-mode", GDK_MODE_SCREEN, - "display", gdk_seat_get_display (pad->seat), - "device-manager", device_manager, - "seat", seat, - NULL); - - _gdk_device_set_associated_device (pad->device, seat->master_keyboard); - g_signal_emit_by_name (device_manager, "device-added", pad->device); } static void @@ -4506,14 +4491,60 @@ tablet_pad_handle_enter (void *data, { GdkWaylandTabletPadData *pad = data; GdkWaylandTabletData *tablet = zwp_tablet_v2_get_user_data (wp_tablet); + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat); + GdkWaylandDeviceManager *device_manager = + GDK_WAYLAND_DEVICE_MANAGER (seat->device_manager); GDK_NOTE (EVENTS, g_message ("tablet pad handle enter, pad = %p, tablet = %p surface = %p", wp_tablet_pad, wp_tablet, surface)); + if (pad->device && pad->current_tablet != tablet) + { + device_manager->devices = + g_list_remove (device_manager->devices, pad->device); + g_signal_emit_by_name (device_manager, "device-removed", pad->device); + _gdk_device_set_associated_device (pad->device, NULL); + g_clear_object (&pad->device); + } + /* Relate pad and tablet */ - tablet->pads = g_list_prepend (tablet->pads, pad); + tablet->pads = g_list_append (tablet->pads, pad); pad->current_tablet = tablet; + + if (!pad->device) + { + GdkWaylandTabletPadData *pad = data; + gchar *name, *vid, *pid; + + name = g_strdup_printf ("%s Pad %d", + tablet->name, + g_list_index (tablet->pads, pad) + 1); + vid = g_strdup_printf ("%.4x", tablet->vid); + pid = g_strdup_printf ("%.4x", tablet->pid); + + pad->device = + g_object_new (GDK_TYPE_WAYLAND_DEVICE_PAD, + "name", name, + "vendor-id", vid, + "product-id", pid, + "type", GDK_DEVICE_TYPE_SLAVE, + "input-source", GDK_SOURCE_TABLET_PAD, + "input-mode", GDK_MODE_SCREEN, + "display", gdk_seat_get_display (pad->seat), + "device-manager", device_manager, + "seat", seat, + NULL); + + _gdk_device_set_associated_device (pad->device, seat->master_keyboard); + device_manager->devices = + g_list_prepend (device_manager->devices, pad->device); + g_signal_emit_by_name (device_manager, "device-added", pad->device); + + g_free (name); + g_free (vid); + g_free (pid); + } } static void @@ -4529,10 +4560,7 @@ tablet_pad_handle_leave (void *data, wp_tablet_pad, surface)); if (pad->current_tablet) - { - pad->current_tablet->pads = g_list_remove (pad->current_tablet->pads, pad); - pad->current_tablet = NULL; - } + pad->current_tablet->pads = g_list_remove (pad->current_tablet->pads, pad); } static void -- GitLab From 81029b824b39122704a9bd615dc7b03886516843 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Tue, 13 Jun 2023 22:52:48 +0200 Subject: [PATCH 2/3] gdk/wayland: Ensure device-added/removed emission in GdkSeat We've used to emit these in the GdkDeviceManager, but missed to do this signal emission at the GdkSeat object level. In order to avoid the double emission, trigger one from the other. --- gdk/wayland/gdkdevice-wayland.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 7e7beac9d1e..dd7db81cf1b 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -5181,6 +5181,22 @@ init_pointer_data (GdkWaylandPointerData *pointer_data, master); } +static void +device_manager_device_added (GdkDeviceManager *device_manager, + GdkDevice *device, + GdkSeat *seat) +{ + g_signal_emit_by_name (seat, "device-added", device); +} + +static void +device_manager_device_removed (GdkDeviceManager *device_manager, + GdkDevice *device, + GdkSeat *seat) +{ + g_signal_emit_by_name (seat, "device-removed", device); +} + void _gdk_wayland_device_manager_add_seat (GdkDeviceManager *device_manager, guint32 id, @@ -5249,6 +5265,11 @@ _gdk_wayland_device_manager_add_seat (GdkDeviceManager *device_manager, seat); } + g_signal_connect (seat->device_manager, "device-added", + G_CALLBACK (device_manager_device_added), seat); + g_signal_connect (seat->device_manager, "device-removed", + G_CALLBACK (device_manager_device_removed), seat); + gdk_display_add_seat (display, GDK_SEAT (seat)); } @@ -5268,6 +5289,12 @@ _gdk_wayland_device_manager_remove_seat (GdkDeviceManager *manager, if (seat->id != id) continue; + g_signal_handlers_disconnect_by_func (manager, + device_manager_device_added, + seat); + g_signal_handlers_disconnect_by_func (manager, + device_manager_device_removed, + seat); gdk_display_remove_seat (display, GDK_SEAT (seat)); break; } -- GitLab From a9d7198d63d14e049c399914f11ddd37fc034f3a Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Tue, 13 Jun 2023 22:54:23 +0200 Subject: [PATCH 3/3] gdk/wayland: Return pad devices querying for all devices These devices unfortunately didn't ever get a capability flag in 3.24 (fixed in GTK4). We are very far off into maintenance grounds that it is not ideal to add new flag values, but we could however return these devices if GDK_SEAT_CAPABILITY_ALL is being asked. Do that, so it is possible to deal with pad devices, even if it's not possible to query them specifically. --- gdk/wayland/gdkdevice-wayland.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index dd7db81cf1b..a1e4771a74e 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -5141,6 +5141,21 @@ gdk_wayland_seat_get_slaves (GdkSeat *seat, } } + /* There is no specific capability for pads, return + * them anyways if all devices are requested + */ + if (capabilities == GDK_SEAT_CAPABILITY_ALL) + { + GList *l; + + for (l = wayland_seat->tablet_pads; l; l = l->next) + { + GdkWaylandTabletPadData *pad = l->data; + + slaves = g_list_prepend (slaves, pad->device); + } + } + return slaves; } -- GitLab