From ce698b9a8720e20e0b4851c8319d280f4b01955b Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 26 Mar 2025 11:28:03 +0100 Subject: [PATCH] wayland: Take over cursor feedback during DnD The original strategy to let the drag source client be in charge of pointer cursor feedback during DnD has gotten way too complex, with tablets and tools, toplevel drags, and now the cursor shape protocol. Instead, let the compositor be in charge of pointer cursor feedback during DnD operation, it will know right away the cursor renderer to update, and the appropriate feedback through the current DnD action. Part-of: --- src/wayland/meta-wayland-data-device.c | 80 ++++++++++++++++++++++++-- src/wayland/meta-wayland-pointer.c | 8 +-- 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c index 07a6594c5..c058588b0 100644 --- a/src/wayland/meta-wayland-data-device.c +++ b/src/wayland/meta-wayland-data-device.c @@ -218,21 +218,88 @@ on_drag_focus_destroyed (MetaWaylandSurface *surface, grab->drag_focus = NULL; } +static void +meta_wayland_drag_grab_set_cursor (MetaWaylandDragGrab *drag_grab, + MetaCursor cursor) +{ + MetaWaylandCompositor *compositor = + meta_wayland_seat_get_compositor (drag_grab->seat); + MetaContext *context = meta_wayland_compositor_get_context (compositor); + MetaBackend *backend = meta_context_get_backend (context); + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); + g_autoptr (MetaCursorSprite) cursor_sprite = NULL; + MetaCursorRenderer *cursor_renderer; + + cursor_sprite = + META_CURSOR_SPRITE (meta_cursor_sprite_xcursor_new (cursor, cursor_tracker)); + cursor_renderer = + meta_backend_get_cursor_renderer_for_device (backend, drag_grab->device); + + if (cursor_renderer && cursor_sprite) + meta_cursor_renderer_set_cursor (cursor_renderer, cursor_sprite); +} + +static void +meta_wayland_drag_grab_update_cursor (MetaWaylandDragGrab *drag_grab) +{ + enum wl_data_device_manager_dnd_action action = + meta_wayland_data_source_get_current_action (drag_grab->drag_data_source); + MetaCursor cursor = META_CURSOR_DEFAULT; + + switch (action) + { + case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: + cursor = META_CURSOR_NOT_ALLOWED; + break; + case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE: + cursor = META_CURSOR_MOVE; + break; + case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: + cursor = META_CURSOR_COPY; + break; + case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK: + cursor = META_CURSOR_DND_ASK; + break; + default: + break; + } + + meta_wayland_drag_grab_set_cursor (drag_grab, cursor); +} + +static void +on_data_source_action_changed (MetaWaylandDataSource *source, + MetaWaylandDragGrab *drag_grab) +{ + meta_wayland_drag_grab_update_cursor (drag_grab); +} + static void meta_wayland_drag_grab_set_source (MetaWaylandDragGrab *drag_grab, MetaWaylandDataSource *source) { if (drag_grab->drag_data_source) - g_object_weak_unref (G_OBJECT (drag_grab->drag_data_source), - drag_grab_data_source_destroyed, - drag_grab); + { + g_signal_handlers_disconnect_by_func (drag_grab->drag_data_source, + on_data_source_action_changed, + drag_grab); + g_object_weak_unref (G_OBJECT (drag_grab->drag_data_source), + drag_grab_data_source_destroyed, + drag_grab); + } drag_grab->drag_data_source = source; if (source) - g_object_weak_ref (G_OBJECT (source), - drag_grab_data_source_destroyed, - drag_grab); + { + g_signal_connect (drag_grab->drag_data_source, "action-changed", + G_CALLBACK (on_data_source_action_changed), + drag_grab); + g_object_weak_ref (G_OBJECT (source), + drag_grab_data_source_destroyed, + drag_grab); + } } static void @@ -411,6 +478,7 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab) drag_grab->handler = NULL; } + meta_wayland_drag_grab_set_cursor (drag_grab, META_CURSOR_DEFAULT); meta_dnd_wayland_handle_end_modal (compositor); g_free (drag_grab); diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index a0d9acf5d..1649fc835 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -1141,15 +1141,9 @@ meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer) { MetaBackend *backend = backend_from_pointer (pointer); MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); - MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer); - MetaWaylandDragGrab *drag_grab; MetaWaylandSurface *surface; - drag_grab = meta_wayland_data_device_get_current_grab (&seat->data_device); - if (drag_grab) - surface = meta_wayland_drag_grab_get_origin (drag_grab); - else - surface = pointer->focus_surface; + surface = pointer->focus_surface; if (surface) {