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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3420>
This commit is contained in:
Carlos Garnacho 2023-11-17 17:52:37 +01:00 committed by Robert Mader
parent b09374735b
commit c931ed0d81
3 changed files with 93 additions and 28 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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)
{