From c931ed0d817c4bd0ab03f10b1ba8af301579a7d2 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 17 Nov 2023 17:52:37 +0100 Subject: [PATCH] wayland: Allow XDnD with other devices than the pointer While every kind of input is seen as coming from the Virtual Core Pointer in the X11 case, we can largely abstract away from that fact, and lock XDnD pointer input to the most plausible source (e.g. a device with a pressed button), instead of only working with pointer input. Part-of: --- src/wayland/meta-wayland-data-device.c | 10 +++ src/wayland/meta-wayland-data-device.h | 3 + src/wayland/meta-xwayland-dnd.c | 108 ++++++++++++++++++------- 3 files changed, 93 insertions(+), 28 deletions(-) diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c index aa24a5560..6c2f6628e 100644 --- a/src/wayland/meta-wayland-data-device.c +++ b/src/wayland/meta-wayland-data-device.c @@ -334,6 +334,16 @@ meta_wayland_drag_grab_get_seat (MetaWaylandDragGrab *drag_grab) return drag_grab->seat; } +ClutterInputDevice * +meta_wayland_drag_grab_get_device (MetaWaylandDragGrab *drag_grab, + ClutterEventSequence **sequence) +{ + if (sequence) + *sequence = drag_grab->sequence; + + return drag_grab->device; +} + static void data_source_update_user_dnd_action (MetaWaylandDataSource *source, ClutterModifierType modifiers) diff --git a/src/wayland/meta-wayland-data-device.h b/src/wayland/meta-wayland-data-device.h index 9a638509d..a67d37990 100644 --- a/src/wayland/meta-wayland-data-device.h +++ b/src/wayland/meta-wayland-data-device.h @@ -94,3 +94,6 @@ void meta_wayland_drag_grab_update_feedback_actor (MetaWaylandDragGrab *drag const ClutterEvent *event); MetaWaylandSeat * meta_wayland_drag_grab_get_seat (MetaWaylandDragGrab *drag_grab); + +ClutterInputDevice * meta_wayland_drag_grab_get_device (MetaWaylandDragGrab *drag_grab, + ClutterEventSequence **sequence); diff --git a/src/wayland/meta-xwayland-dnd.c b/src/wayland/meta-xwayland-dnd.c index ba2f9570a..4659cf194 100644 --- a/src/wayland/meta-xwayland-dnd.c +++ b/src/wayland/meta-xwayland-dnd.c @@ -67,6 +67,17 @@ struct _MetaXWaylandDnd int current_dnd_window; }; +typedef struct _DndCandidateDevice DndCandidateDevice; + +struct _DndCandidateDevice +{ + MetaWaylandSeat *seat; + ClutterInputDevice *device; + ClutterEventSequence *sequence; + MetaWaylandSurface *focus; + graphene_point_t pos; +}; + enum { ATOM_DND_SELECTION, @@ -669,10 +680,15 @@ meta_x11_drag_dest_update (MetaWaylandDataDevice *data_device, MetaWaylandSeat *seat = meta_wayland_data_device_get_seat (data_device); MetaWaylandCompositor *compositor = meta_wayland_seat_get_compositor (seat); MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; + MetaWaylandDragGrab *drag_grab = compositor->seat->data_device.current_grab; + ClutterInputDevice *device; + ClutterEventSequence *sequence; graphene_point_t pos; - clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), - seat->pointer->device, NULL, &pos, NULL); + device = meta_wayland_drag_grab_get_device (drag_grab, &sequence); + + clutter_seat_query_state (clutter_input_device_get_seat (device), + device, sequence, &pos, NULL); xdnd_send_position (dnd, dnd->dnd_dest, clutter_get_current_event_time (), pos.x, pos.y); @@ -892,7 +908,12 @@ drag_xgrab_release (MetaWaylandEventHandler *handler, data_source = compositor->seat->data_device.dnd_data_source; - if (seat->pointer->button_count == 0 && + if (__builtin_popcount (clutter_event_get_state (event) & + (CLUTTER_BUTTON1_MASK | + CLUTTER_BUTTON2_MASK | + CLUTTER_BUTTON3_MASK | + CLUTTER_BUTTON4_MASK | + CLUTTER_BUTTON5_MASK)) <= 1 && (!meta_wayland_drag_grab_get_focus (drag_grab) || meta_wayland_data_source_get_current_action (data_source) == WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE)) @@ -1031,13 +1052,17 @@ meta_xwayland_dnd_handle_client_message (MetaWaylandCompositor *compositor, } else if (event->message_type == xdnd_atoms[ATOM_DND_POSITION]) { + ClutterInputDevice *device; + ClutterEventSequence *sequence; graphene_point_t pos; uint32_t action = 0; dnd->client_message_timestamp = event->data.l[3]; - clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), - seat->pointer->device, NULL, &pos, NULL); + device = meta_wayland_drag_grab_get_device (drag_grab, &sequence); + + clutter_seat_query_state (clutter_input_device_get_seat (device), + device, sequence, &pos, NULL); action = atom_to_action ((Atom) event->data.l[4]); meta_wayland_data_source_set_user_action (dnd->source, action); @@ -1066,6 +1091,42 @@ meta_xwayland_dnd_handle_client_message (MetaWaylandCompositor *compositor, return FALSE; } +static gboolean +find_dnd_candidate_device (ClutterStage *stage, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + gpointer user_data) +{ + DndCandidateDevice *candidate = user_data; + graphene_point_t pos; + ClutterModifierType modifiers; + MetaWaylandSurface *focus; + + clutter_seat_query_state (clutter_input_device_get_seat (device), + device, sequence, &pos, &modifiers); + + if (!sequence) + { + if (modifiers & + (CLUTTER_BUTTON1_MASK | CLUTTER_BUTTON2_MASK | + CLUTTER_BUTTON3_MASK | CLUTTER_BUTTON4_MASK | + CLUTTER_BUTTON5_MASK)) + return TRUE; + } + + focus = meta_wayland_seat_get_current_surface (candidate->seat, + device, sequence); + if (!focus || !meta_wayland_surface_is_xwayland (focus)) + return TRUE; + + candidate->device = device; + candidate->sequence = sequence; + candidate->pos = pos; + candidate->focus = focus; + + return FALSE; +} + static gboolean meta_xwayland_dnd_handle_xfixes_selection_notify (MetaWaylandCompositor *compositor, XEvent *xevent) @@ -1075,42 +1136,33 @@ meta_xwayland_dnd_handle_xfixes_selection_notify (MetaWaylandCompositor *composi MetaWaylandSeat *seat = compositor->seat; MetaWaylandDataDevice *data_device = &seat->data_device; MetaX11Display *x11_display = x11_display_from_dnd (dnd); - MetaWaylandSurface *focus; + MetaContext *context = meta_wayland_compositor_get_context (compositor); + MetaBackend *backend = meta_context_get_backend (context); + ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); + DndCandidateDevice candidate = { seat, }; if (event->selection != xdnd_atoms[ATOM_DND_SELECTION]) return FALSE; dnd->owner = event->owner; - focus = compositor->seat->pointer->focus_surface; if (event->owner != None && event->owner != x11_display->selection.xwindow && - focus && meta_wayland_surface_is_xwayland (focus)) + !clutter_stage_pointing_input_foreach (stage, find_dnd_candidate_device, + &candidate)) { - graphene_point_t pos; - ClutterModifierType modifiers; dnd->source = meta_wayland_data_source_xwayland_new (dnd, compositor); meta_wayland_data_device_set_dnd_source (&compositor->seat->data_device, dnd->source); - clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), - seat->pointer->device, NULL, &pos, &modifiers); - - if (modifiers & - (CLUTTER_BUTTON1_MASK | - CLUTTER_BUTTON2_MASK | - CLUTTER_BUTTON3_MASK | - CLUTTER_BUTTON4_MASK | - CLUTTER_BUTTON5_MASK)) - { - meta_wayland_data_device_start_drag (data_device, - wl_resource_get_client (focus->resource), - &xdnd_event_interface, - focus, dnd->source, - NULL, - seat->pointer->device, NULL, - pos); - } + meta_wayland_data_device_start_drag (data_device, + wl_resource_get_client (candidate.focus->resource), + &xdnd_event_interface, + candidate.focus, dnd->source, + NULL, + candidate.device, + candidate.sequence, + candidate.pos); } else if (event->owner == None) {