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