diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c index 786420cc1..aa24a5560 100644 --- a/src/wayland/meta-wayland-data-device.c +++ b/src/wayland/meta-wayland-data-device.c @@ -131,9 +131,10 @@ create_and_send_dnd_offer (MetaWaylandDataSource *source, } struct _MetaWaylandDragGrab { - MetaWaylandPointerGrab generic; + MetaWaylandEventHandler *handler; - MetaWaylandKeyboardGrab keyboard_grab; + ClutterInputDevice *device; + ClutterEventSequence *sequence; MetaWaylandSeat *seat; struct wl_client *drag_client; @@ -327,13 +328,10 @@ meta_wayland_drag_grab_update_feedback_actor (MetaWaylandDragGrab *drag_grab, event); } -static void -drag_grab_focus (MetaWaylandPointerGrab *grab, - MetaWaylandSurface *surface) +MetaWaylandSeat * +meta_wayland_drag_grab_get_seat (MetaWaylandDragGrab *drag_grab) { - MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; - - meta_wayland_drag_grab_set_focus (drag_grab, surface); + return drag_grab->seat; } static void @@ -352,27 +350,6 @@ data_source_update_user_dnd_action (MetaWaylandDataSource *source, meta_wayland_data_source_set_user_action (source, user_dnd_action); } -static void -drag_grab_motion (MetaWaylandPointerGrab *grab, - const ClutterEvent *event) -{ - MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; - graphene_point_t point; - uint32_t time_ms; - - if (drag_grab->drag_focus) - { - clutter_event_get_coords (event, &point.x, &point.y); - time_ms = clutter_event_get_time (event); - meta_wayland_surface_drag_dest_motion (drag_grab->drag_focus, - point.x, point.y, time_ms); - } - - if (drag_grab->drag_surface) - meta_feedback_actor_update (META_FEEDBACK_ACTOR (drag_grab->feedback_actor), - event); -} - static void data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab) { @@ -401,17 +378,13 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab) drag_grab->seat->data_device.current_grab = NULL; - /* There might be other grabs created in result to DnD actions like popups - * on "ask" actions, we must not reset those, only our own. - */ - if (drag_grab->generic.pointer->grab == (MetaWaylandPointerGrab *) drag_grab) + if (drag_grab->handler) { - MetaWaylandCompositor *wayland_compositor = - meta_wayland_seat_get_compositor (data_device->seat); + MetaWaylandInput *input; - meta_wayland_pointer_end_grab (drag_grab->generic.pointer); - meta_wayland_keyboard_end_grab (drag_grab->keyboard_grab.keyboard); - meta_wayland_compositor_sync_focus (wayland_compositor); + input = meta_wayland_seat_get_input (data_device->seat); + meta_wayland_input_detach_event_handler (input, drag_grab->handler); + drag_grab->handler = NULL; } g_free (drag_grab); @@ -460,76 +433,140 @@ meta_wayland_data_source_fake_read (MetaWaylandDataSource *source, g_io_add_watch (channel, G_IO_HUP, on_fake_read_hup, source); } -static void -drag_grab_button (MetaWaylandPointerGrab *grab, - const ClutterEvent *event) +static MetaWaylandSurface * +drag_grab_get_focus_surface (MetaWaylandEventHandler *handler, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + gpointer user_data) { - MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; - MetaWaylandSeat *seat = drag_grab->seat; - ClutterEventType event_type = clutter_event_type (event); + MetaWaylandDragGrab *drag_grab = user_data; - if (drag_grab->generic.pointer->grab_button == - clutter_event_get_button (event) && - event_type == CLUTTER_BUTTON_RELEASE) - { - MetaWaylandDataSource *source = drag_grab->drag_data_source; - gboolean success; + if (device != drag_grab->device || + sequence != drag_grab->sequence) + return NULL; - if (drag_grab->drag_focus && source && - meta_wayland_data_source_has_target (source) && - meta_wayland_data_source_get_current_action (source)) - { - meta_wayland_surface_drag_dest_drop (drag_grab->drag_focus); - meta_wayland_data_source_notify_drop_performed (source); - - meta_wayland_data_source_update_in_ask (source); - success = TRUE; - } - else if (!drag_grab->drag_focus && source && - meta_wayland_data_source_has_target (source) && - meta_wayland_data_source_get_current_action (source) && - meta_wayland_data_source_has_mime_type (source, - ROOTWINDOW_DROP_MIME)) - { - /* Perform a fake read, that will lead to notify_finish() being called */ - meta_wayland_data_source_fake_read (source, ROOTWINDOW_DROP_MIME); - success = TRUE; - } - else - { - if (source) - meta_wayland_data_source_set_current_offer (source, NULL); - meta_wayland_data_device_set_dnd_source (&seat->data_device, NULL); - unset_selection_source (&seat->data_device, META_SELECTION_DND); - success = FALSE; - } - - /* Finish drag and let actor self-destruct */ - meta_dnd_actor_drag_finish (META_DND_ACTOR (drag_grab->feedback_actor), - success); - drag_grab->feedback_actor = NULL; - } - - if (seat->pointer->button_count == 0 && - event_type == CLUTTER_BUTTON_RELEASE) - data_device_end_drag_grab (drag_grab); + return meta_wayland_event_handler_chain_up_get_focus_surface (handler, + device, + sequence); } -static const MetaWaylandPointerGrabInterface drag_grab_interface = { - drag_grab_focus, - drag_grab_motion, - drag_grab_button, -}; +static void +drag_grab_focus (MetaWaylandEventHandler *handler, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + MetaWaylandSurface *surface, + gpointer user_data) +{ + MetaWaylandDragGrab *drag_grab = user_data; + + meta_wayland_event_handler_chain_up_focus (handler, device, sequence, NULL); + + if (device == drag_grab->device && + sequence == drag_grab->sequence) + meta_wayland_drag_grab_set_focus (drag_grab, surface); +} static gboolean -keyboard_drag_grab_key (MetaWaylandKeyboardGrab *grab, - const ClutterEvent *event) +drag_grab_motion (MetaWaylandEventHandler *handler, + const ClutterEvent *event, + gpointer user_data) { + MetaWaylandDragGrab *drag_grab = user_data; + graphene_point_t point; + uint32_t time_ms; + + if (drag_grab->device != clutter_event_get_device (event) || + drag_grab->sequence != clutter_event_get_event_sequence (event)) + return CLUTTER_EVENT_STOP; + + if (drag_grab->drag_focus) + { + clutter_event_get_coords (event, &point.x, &point.y); + time_ms = clutter_event_get_time (event); + meta_wayland_surface_drag_dest_motion (drag_grab->drag_focus, + point.x, point.y, time_ms); + } + + if (drag_grab->drag_surface) + { + meta_feedback_actor_update (META_FEEDBACK_ACTOR (drag_grab->feedback_actor), + event); + } + + return CLUTTER_EVENT_STOP; +} + +static gboolean +drag_grab_release (MetaWaylandEventHandler *handler, + const ClutterEvent *event, + gpointer user_data) +{ + MetaWaylandDragGrab *drag_grab = user_data; + MetaWaylandSeat *seat = drag_grab->seat; + MetaWaylandDataSource *source = drag_grab->drag_data_source; + gboolean success; + + if (drag_grab->device != clutter_event_get_device (event) || + drag_grab->sequence != clutter_event_get_event_sequence (event)) + return CLUTTER_EVENT_STOP; + + if (__builtin_popcount (clutter_event_get_state (event) & + (CLUTTER_BUTTON1_MASK | + CLUTTER_BUTTON2_MASK | + CLUTTER_BUTTON3_MASK | + CLUTTER_BUTTON4_MASK | + CLUTTER_BUTTON5_MASK)) > 1) + return CLUTTER_EVENT_STOP; + + if (drag_grab->drag_focus && source && + meta_wayland_data_source_has_target (source) && + meta_wayland_data_source_get_current_action (source)) + { + meta_wayland_surface_drag_dest_drop (drag_grab->drag_focus); + meta_wayland_data_source_notify_drop_performed (source); + + meta_wayland_data_source_update_in_ask (source); + success = TRUE; + } + else if (!drag_grab->drag_focus && source && + meta_wayland_data_source_has_target (source) && + meta_wayland_data_source_get_current_action (source) && + meta_wayland_data_source_has_mime_type (source, + ROOTWINDOW_DROP_MIME)) + { + /* Perform a fake read, that will lead to notify_finish() being called */ + meta_wayland_data_source_fake_read (source, ROOTWINDOW_DROP_MIME); + success = TRUE; + } + else + { + if (source) + meta_wayland_data_source_set_current_offer (source, NULL); + meta_wayland_data_device_set_dnd_source (&seat->data_device, NULL); + unset_selection_source (&seat->data_device, META_SELECTION_DND); + success = FALSE; + } + + /* Finish drag and let actor self-destruct */ + meta_dnd_actor_drag_finish (META_DND_ACTOR (drag_grab->feedback_actor), + success); + drag_grab->feedback_actor = NULL; + + data_device_end_drag_grab (drag_grab); + + return CLUTTER_EVENT_STOP; +} + +static gboolean +drag_grab_key (MetaWaylandEventHandler *handler, + const ClutterEvent *event, + gpointer user_data) +{ + MetaWaylandDragGrab *drag_grab = user_data; + ClutterModifierType modifiers; + if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_Escape) { - MetaWaylandDragGrab *drag_grab; - - drag_grab = wl_container_of (grab, drag_grab, keyboard_grab); meta_wayland_data_device_set_dnd_source (&drag_grab->seat->data_device, NULL); unset_selection_source (&drag_grab->seat->data_device, META_SELECTION_DND); @@ -539,38 +576,40 @@ keyboard_drag_grab_key (MetaWaylandKeyboardGrab *grab, FALSE); drag_grab->feedback_actor = NULL; data_device_end_drag_grab (drag_grab); - - return TRUE; } - - return FALSE; -} - -static void -keyboard_drag_grab_modifiers (MetaWaylandKeyboardGrab *grab, - ClutterModifierType modifiers) -{ - MetaWaylandDragGrab *drag_grab; - - drag_grab = wl_container_of (grab, drag_grab, keyboard_grab); - - /* The modifiers here just contain keyboard modifiers, mix it with the - * mouse button modifiers we got when starting the drag operation. - */ - modifiers |= drag_grab->buttons; - - if (drag_grab->drag_data_source) + else if (clutter_seat_query_state (clutter_input_device_get_seat (drag_grab->device), + drag_grab->device, + drag_grab->sequence, + NULL, + &modifiers) && + drag_grab->drag_data_source && + clutter_event_get_state (event) != modifiers) { data_source_update_user_dnd_action (drag_grab->drag_data_source, modifiers); if (drag_grab->drag_focus) meta_wayland_surface_drag_dest_update (drag_grab->drag_focus); } + + return CLUTTER_EVENT_STOP; } -static const MetaWaylandKeyboardGrabInterface keyboard_drag_grab_interface = { - keyboard_drag_grab_key, - keyboard_drag_grab_modifiers +static gboolean +drag_grab_discard_event (MetaWaylandEventHandler *handler, + const ClutterEvent *event, + gpointer user_data) +{ + return CLUTTER_EVENT_STOP; +} + +static const MetaWaylandEventInterface dnd_event_interface = { + drag_grab_get_focus_surface, + drag_grab_focus, + drag_grab_motion, + drag_grab_discard_event, /* press */ + drag_grab_release, + drag_grab_key, + drag_grab_discard_event, /* other */ }; static void @@ -612,30 +651,31 @@ destroy_data_device_icon (struct wl_listener *listener, } void -meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data_device, - struct wl_client *client, - const MetaWaylandPointerGrabInterface *funcs, - MetaWaylandSurface *surface, - MetaWaylandDataSource *source, - MetaWaylandSurface *icon_surface) +meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data_device, + struct wl_client *client, + const MetaWaylandEventInterface *event_iface, + MetaWaylandSurface *surface, + MetaWaylandDataSource *source, + MetaWaylandSurface *icon_surface, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t drag_start) { MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device); MetaWaylandDragGrab *drag_grab; graphene_point_t pos, surface_pos; ClutterModifierType modifiers; MetaSurfaceActor *surface_actor; + MetaWaylandInput *input; data_device->current_grab = drag_grab = g_new0 (MetaWaylandDragGrab, 1); - drag_grab->generic.interface = funcs; - drag_grab->generic.pointer = seat->pointer; - - drag_grab->keyboard_grab.interface = &keyboard_drag_grab_interface; - drag_grab->keyboard_grab.keyboard = seat->keyboard; - drag_grab->drag_client = client; drag_grab->seat = seat; + drag_grab->device = device; + drag_grab->sequence = sequence; + drag_grab->drag_origin = surface; drag_grab->drag_origin_listener.notify = destroy_data_device_origin; wl_resource_add_destroy_listener (surface->resource, @@ -644,16 +684,16 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data surface_actor = meta_wayland_surface_get_actor (surface); clutter_actor_transform_stage_point (CLUTTER_ACTOR (surface_actor), - seat->pointer->grab_x, - seat->pointer->grab_y, + drag_start.x, + drag_start.y, &surface_pos.x, &surface_pos.y); drag_grab->drag_start_x = surface_pos.x; drag_grab->drag_start_y = surface_pos.y; drag_grab->need_initial_focus = TRUE; - clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), - seat->pointer->device, NULL, NULL, &modifiers); + clutter_seat_query_state (clutter_input_device_get_seat (device), + device, sequence, &pos, &modifiers); drag_grab->buttons = modifiers & (CLUTTER_BUTTON1_MASK | CLUTTER_BUTTON2_MASK | CLUTTER_BUTTON3_MASK | CLUTTER_BUTTON4_MASK | CLUTTER_BUTTON5_MASK); @@ -687,14 +727,15 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data 0, 0); clutter_actor_add_child (drag_grab->feedback_actor, drag_surface_actor); - clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), - seat->pointer->device, NULL, &pos, NULL); meta_feedback_actor_set_position (META_FEEDBACK_ACTOR (drag_grab->feedback_actor), pos.x, pos.y); } - meta_wayland_pointer_start_grab (seat->pointer, - (MetaWaylandPointerGrab*) drag_grab); + input = meta_wayland_seat_get_input (seat); + drag_grab->handler = + meta_wayland_input_attach_event_handler (input, + event_iface, + drag_grab); meta_wayland_data_source_set_seat (source, seat); } @@ -718,6 +759,9 @@ data_device_start_drag (struct wl_client *client, MetaWaylandSurface *surface = NULL, *icon_surface = NULL; MetaWaylandDataSource *drag_source = NULL; MetaSelectionSource *selection_source; + ClutterInputDevice *device; + ClutterEventSequence *sequence; + float x, y; if (origin_resource) surface = wl_resource_get_user_data (origin_resource); @@ -725,16 +769,18 @@ data_device_start_drag (struct wl_client *client, if (!surface) return; - if (seat->pointer->button_count == 0 || - seat->pointer->grab_serial != serial || - !seat->pointer->focus_surface || - seat->pointer->focus_surface != surface) + if (!meta_wayland_seat_get_grab_info (seat, + surface, + serial, + TRUE, + &device, + &sequence, + &x, &y)) return; /* FIXME: Check that the data source type array isn't empty. */ - if (data_device->current_grab || - seat->pointer->grab != &seat->pointer->default_grab) + if (data_device->current_grab) return; if (icon_resource) @@ -758,14 +804,11 @@ data_device_start_drag (struct wl_client *client, selection_source); g_object_unref (selection_source); - meta_wayland_pointer_set_focus (seat->pointer, NULL); meta_wayland_data_device_start_drag (data_device, client, - &drag_grab_interface, - surface, drag_source, icon_surface); - - if (meta_wayland_seat_has_keyboard (seat)) - meta_wayland_keyboard_start_grab (seat->keyboard, - &seat->data_device.current_grab->keyboard_grab); + &dnd_event_interface, + surface, drag_source, icon_surface, + device, sequence, + GRAPHENE_POINT_INIT (x, y)); } static void @@ -788,7 +831,7 @@ meta_wayland_drag_dest_focus_in (MetaWaylandDataDevice *data_device, struct wl_client *client; struct wl_resource *resource; uint32_t source_actions; - wl_fixed_t sx, sy; + graphene_point_t pos; if (!grab->drag_focus_data_device) return; @@ -810,11 +853,19 @@ meta_wayland_drag_dest_focus_in (MetaWaylandDataDevice *data_device, wl_data_offer_send_source_actions (resource, source_actions); } - meta_wayland_pointer_get_relative_coordinates (grab->generic.pointer, - surface, &sx, &sy); + clutter_seat_query_state (clutter_input_device_get_seat (grab->device), + grab->device, + grab->sequence, + &pos, NULL); + meta_wayland_surface_get_relative_coordinates (surface, pos.x, pos.y, + &pos.x, &pos.y); + wl_data_device_send_enter (grab->drag_focus_data_device, wl_display_next_serial (display), - surface->resource, sx, sy, resource); + surface->resource, + wl_fixed_from_double (pos.x), + wl_fixed_from_double (pos.y), + resource); } static void @@ -839,17 +890,15 @@ meta_wayland_drag_dest_motion (MetaWaylandDataDevice *data_device, uint32_t time_ms) { MetaWaylandDragGrab *grab = data_device->current_grab; - wl_fixed_t sx, sy; if (!grab->drag_focus_data_device) return; - meta_wayland_pointer_get_relative_coordinates (grab->generic.pointer, - grab->drag_focus, - &sx, &sy); + meta_wayland_surface_get_relative_coordinates (surface, x, y, &x, &y); wl_data_device_send_motion (grab->drag_focus_data_device, time_ms, - sx, sy); + wl_fixed_from_double (x), + wl_fixed_from_double (y)); } static void diff --git a/src/wayland/meta-wayland-data-device.h b/src/wayland/meta-wayland-data-device.h index a6144d3eb..9a638509d 100644 --- a/src/wayland/meta-wayland-data-device.h +++ b/src/wayland/meta-wayland-data-device.h @@ -29,6 +29,7 @@ #include "meta/meta-selection-source.h" #include "wayland/meta-wayland-data-offer.h" #include "wayland/meta-wayland-data-source.h" +#include "wayland/meta-wayland-input.h" #include "wayland/meta-wayland-types.h" typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab; @@ -73,12 +74,15 @@ void meta_wayland_data_device_unset_dnd_selection (MetaWaylandDataDevice *da const MetaWaylandDragDestFuncs * meta_wayland_data_device_get_drag_dest_funcs (void); -void meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data_device, - struct wl_client *client, - const MetaWaylandPointerGrabInterface *funcs, - MetaWaylandSurface *surface, - MetaWaylandDataSource *source, - MetaWaylandSurface *icon_surface); +void meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data_device, + struct wl_client *client, + const MetaWaylandEventInterface *event_iface, + MetaWaylandSurface *surface, + MetaWaylandDataSource *source, + MetaWaylandSurface *icon_surface, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t drag_start); void meta_wayland_data_device_end_drag (MetaWaylandDataDevice *data_device); @@ -88,3 +92,5 @@ MetaWaylandSurface * meta_wayland_drag_grab_get_focus (MetaWaylandDragGrab *drag_grab); void meta_wayland_drag_grab_update_feedback_actor (MetaWaylandDragGrab *drag_grab, const ClutterEvent *event); + +MetaWaylandSeat * meta_wayland_drag_grab_get_seat (MetaWaylandDragGrab *drag_grab); diff --git a/src/wayland/meta-xwayland-dnd.c b/src/wayland/meta-xwayland-dnd.c index af4647eb0..ba2f9570a 100644 --- a/src/wayland/meta-xwayland-dnd.c +++ b/src/wayland/meta-xwayland-dnd.c @@ -820,55 +820,111 @@ repick_drop_surface (MetaWaylandCompositor *compositor, } } -static void -drag_xgrab_focus (MetaWaylandPointerGrab *grab, - MetaWaylandSurface *surface) +static MetaWaylandSurface * +drag_xgrab_get_focus_surface (MetaWaylandEventHandler *handler, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + gpointer user_data) { - /* Do not update the focus here. First, the surface may perfectly + ClutterSeat *clutter_seat; + + clutter_seat = clutter_input_device_get_seat (device); + if (sequence || + device != clutter_seat_get_pointer (clutter_seat)) + return NULL; + + return meta_wayland_event_handler_chain_up_get_focus_surface (handler, + device, + sequence); +} + +static void +drag_xgrab_focus (MetaWaylandEventHandler *handler, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + MetaWaylandSurface *surface, + gpointer user_data) +{ + meta_wayland_event_handler_chain_up_focus (handler, device, + sequence, surface); + + /* Do not update the DnD focus here. First, the surface may perfectly * be the X11 source DnD icon window's, so we can only be fooled * here. Second, delaying focus handling to XdndEnter/Leave * makes us do the negotiation orderly on the X11 side. */ } -static void -drag_xgrab_motion (MetaWaylandPointerGrab *grab, - const ClutterEvent *event) +static gboolean +drag_xgrab_motion (MetaWaylandEventHandler *handler, + const ClutterEvent *event, + gpointer user_data) { - MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (grab->pointer); + MetaWaylandDragGrab *drag_grab = user_data; + MetaWaylandSeat *seat = meta_wayland_drag_grab_get_seat (drag_grab); MetaWaylandCompositor *compositor = meta_wayland_seat_get_compositor (seat); MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - repick_drop_surface (compositor, - (MetaWaylandDragGrab *) grab, - event); + if (clutter_event_type (event) != CLUTTER_MOTION || + clutter_event_get_device_tool (event)) + return CLUTTER_EVENT_STOP; + + repick_drop_surface (compositor, drag_grab, event); dnd->last_motion_time = clutter_event_get_time (event); - meta_wayland_pointer_send_motion (seat->pointer, event); + + return CLUTTER_EVENT_PROPAGATE; } -static void -drag_xgrab_button (MetaWaylandPointerGrab *grab, - const ClutterEvent *event) +static gboolean +drag_xgrab_release (MetaWaylandEventHandler *handler, + const ClutterEvent *event, + gpointer user_data) { - MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (grab->pointer); + MetaWaylandDragGrab *drag_grab = user_data; + MetaWaylandSeat *seat = meta_wayland_drag_grab_get_seat (drag_grab); MetaWaylandCompositor *compositor = meta_wayland_seat_get_compositor (seat); MetaWaylandDataSource *data_source; - meta_wayland_pointer_send_button (seat->pointer, event); + if (clutter_event_type (event) != CLUTTER_BUTTON_RELEASE || + clutter_event_get_device_tool (event)) + return CLUTTER_EVENT_STOP; + data_source = compositor->seat->data_device.dnd_data_source; if (seat->pointer->button_count == 0 && - (!meta_wayland_drag_grab_get_focus ((MetaWaylandDragGrab *) grab) || + (!meta_wayland_drag_grab_get_focus (drag_grab) || meta_wayland_data_source_get_current_action (data_source) == WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE)) meta_xwayland_end_dnd_grab (&seat->data_device, FALSE); + + return CLUTTER_EVENT_PROPAGATE; } -static const MetaWaylandPointerGrabInterface drag_xgrab_interface = { +static gboolean +drag_xgrab_key (MetaWaylandEventHandler *handler, + const ClutterEvent *event, + gpointer user_data) +{ + return CLUTTER_EVENT_PROPAGATE; +} + +static gboolean +drag_xgrab_ignore_event (MetaWaylandEventHandler *handler, + const ClutterEvent *event, + gpointer user_data) +{ + return CLUTTER_EVENT_STOP; +} + +static const MetaWaylandEventInterface xdnd_event_interface = { + drag_xgrab_get_focus_surface, drag_xgrab_focus, drag_xgrab_motion, - drag_xgrab_button, + drag_xgrab_ignore_event, /* press */ + drag_xgrab_release, + drag_xgrab_key, + drag_xgrab_ignore_event, /* other */ }; static gboolean @@ -1016,7 +1072,8 @@ meta_xwayland_dnd_handle_xfixes_selection_notify (MetaWaylandCompositor *composi { XFixesSelectionNotifyEvent *event = (XFixesSelectionNotifyEvent *) xevent; MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - MetaWaylandDataDevice *data_device = &compositor->seat->data_device; + MetaWaylandSeat *seat = compositor->seat; + MetaWaylandDataDevice *data_device = &seat->data_device; MetaX11Display *x11_display = x11_display_from_dnd (dnd); MetaWaylandSurface *focus; @@ -1029,15 +1086,31 @@ meta_xwayland_dnd_handle_xfixes_selection_notify (MetaWaylandCompositor *composi if (event->owner != None && event->owner != x11_display->selection.xwindow && focus && meta_wayland_surface_is_xwayland (focus)) { + 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); - meta_wayland_data_device_start_drag (data_device, - wl_resource_get_client (focus->resource), - &drag_xgrab_interface, - focus, dnd->source, - NULL); + 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); + } } else if (event->owner == None) {