[mutter/wip/dnd-actions: 101/101] wayland: Implement DnD actions as per wl_data_device v3 changes
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/dnd-actions: 101/101] wayland: Implement DnD actions as per wl_data_device v3 changes
- Date: Mon, 29 Jun 2015 16:44:00 +0000 (UTC)
commit cd986f29c6e6302ac216d9b9631b954cc47dd3fb
Author: Carlos Garnacho <carlosg gnome org>
Date: Tue Apr 7 16:05:46 2015 +0200
wayland: Implement DnD actions as per wl_data_device v3 changes
We now additionally send:
- wl_data_offer.source_actions
- wl_data_source.action
- wl_data_offer.action
- wl_data_source.drop_performed
- wl_data_source.drag_finished
The protocol changes allow for compositors to implement different policies
when chosing the action, mutter uses this to reimplement the same behavior
that GTK+ traditionally had:
- Alt/Control/Shift modifiers change the chosen action to
ask/copy/move respectively
- Drags with middle button start out as "ask" by default
As mutter now also grabs the keyboard and unsets the window focus for these
purposes, the window focus is restored after the drag operation has
finished.
src/wayland/meta-wayland-data-device.c | 229 +++++++++++++++++++++++++++++++-
src/wayland/meta-wayland-data-device.h | 15 ++
src/wayland/meta-wayland-versions.h | 2 +-
src/wayland/meta-xwayland-selection.c | 139 +++++++++++++++++--
4 files changed, 365 insertions(+), 20 deletions(-)
---
diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c
index 5e5d0be..a4b28a5 100644
--- a/src/wayland/meta-wayland-data-device.c
+++ b/src/wayland/meta-wayland-data-device.c
@@ -41,6 +41,8 @@ struct _MetaWaylandDataOffer
struct wl_resource *resource;
MetaWaylandDataSource *source;
struct wl_listener source_destroy_listener;
+ uint32_t dnd_actions;
+ uint32_t preferred_dnd_action;
};
static void
@@ -49,6 +51,57 @@ unbind_resource (struct wl_resource *resource)
wl_list_remove (wl_resource_get_link (resource));
}
+static uint32_t
+data_offer_choose_action (MetaWaylandDataOffer *offer)
+{
+ MetaWaylandDataSource *source = offer->source;
+ uint32_t available_actions;
+
+ available_actions = source->dnd_actions & offer->dnd_actions;
+
+ if (!available_actions)
+ return 0;
+
+ /* If the user is forcing an action, go for it */
+ if ((source->user_dnd_action & available_actions) != 0)
+ return source->user_dnd_action;
+
+ /* If the dest side has a preferred DnD action, use it */
+ if ((offer->preferred_dnd_action & available_actions) != 0)
+ return offer->preferred_dnd_action;
+
+ /* Use the first found action, in bit order */
+ return 1 << (ffs (available_actions) - 1);
+}
+
+void
+meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
+ uint32_t action)
+{
+ if (source->current_dnd_action == action)
+ return;
+
+ source->current_dnd_action = action;
+ source->funcs.action (source, action);
+}
+
+static void
+data_offer_update_action (MetaWaylandDataOffer *offer)
+{
+ uint32_t action;
+
+ if (!offer->source)
+ return;
+
+ action = data_offer_choose_action (offer);
+
+ if (offer->source->current_dnd_action == action)
+ return;
+
+ meta_wayland_data_source_set_current_action (offer->source, action);
+ wl_data_offer_send_action (offer->resource, action);
+}
+
static void
data_offer_accept (struct wl_client *client,
struct wl_resource *resource,
@@ -86,20 +139,54 @@ data_offer_destroy (struct wl_client *client, struct wl_resource *resource)
wl_resource_destroy (resource);
}
+static void
+data_offer_set_actions (struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t dnd_actions,
+ uint32_t preferred_action)
+{
+ MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
+
+ if (offer->dnd_actions == dnd_actions &&
+ offer->preferred_dnd_action == preferred_action)
+ return;
+
+ offer->dnd_actions = dnd_actions;
+ offer->preferred_dnd_action = preferred_action;
+
+ data_offer_update_action (offer);
+}
+
static const struct wl_data_offer_interface data_offer_interface = {
data_offer_accept,
data_offer_receive,
data_offer_destroy,
+ data_offer_set_actions
};
+void
+meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source)
+{
+ source->funcs.drag_finished (source);
+}
+
static void
destroy_data_offer (struct wl_resource *resource)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
- if (offer->source && offer->source->resource)
- wl_list_remove (&offer->source_destroy_listener.link);
+ if (offer->source)
+ {
+ if (offer == offer->source->offer)
+ meta_wayland_data_source_notify_finish (offer->source);
+
+ if (offer->source->resource)
+ wl_list_remove (&offer->source_destroy_listener.link);
+ offer->source = NULL;
+ }
+
+ meta_display_sync_wayland_input_focus (meta_get_display ());
g_slice_free (MetaWaylandDataOffer, offer);
}
@@ -134,6 +221,9 @@ meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
wl_array_for_each (p, &source->mime_types)
wl_data_offer_send_offer (offer->resource, *p);
+ data_offer_update_action (offer);
+ source->offer = offer;
+
return offer->resource;
}
@@ -153,14 +243,44 @@ data_source_destroy (struct wl_client *client, struct wl_resource *resource)
wl_resource_destroy (resource);
}
+void
+meta_wayland_data_source_update_actions (MetaWaylandDataSource *source,
+ uint32_t dnd_actions)
+{
+ if (source->dnd_actions == dnd_actions)
+ return;
+
+ source->dnd_actions = dnd_actions;
+
+ if (source->offer)
+ {
+ wl_data_offer_send_source_actions (source->offer->resource,
+ source->dnd_actions);
+ data_offer_update_action (source->offer);
+ }
+}
+
+static void
+data_source_set_actions (struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t dnd_actions)
+{
+ MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
+
+ meta_wayland_data_source_update_actions (source, dnd_actions);
+}
+
static struct wl_data_source_interface data_source_interface = {
data_source_offer,
- data_source_destroy
+ data_source_destroy,
+ data_source_set_actions
};
struct _MetaWaylandDragGrab {
MetaWaylandPointerGrab generic;
+ MetaWaylandKeyboardGrab keyboard_grab;
+
MetaWaylandSeat *seat;
struct wl_client *drag_client;
@@ -180,6 +300,7 @@ struct _MetaWaylandDragGrab {
struct wl_listener drag_origin_listener;
int drag_start_x, drag_start_y;
+ ClutterModifierType buttons;
};
static void
@@ -188,6 +309,7 @@ destroy_drag_focus (struct wl_listener *listener, void *data)
MetaWaylandDragGrab *grab = wl_container_of (listener, grab, drag_focus_listener);
grab->drag_focus_data_device = NULL;
+ grab->drag_focus = NULL;
}
void
@@ -217,6 +339,7 @@ meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
client = wl_resource_get_client (surface->resource);
data_device_resource = wl_resource_find_for_client (&seat->data_device.resource_list, client);
+ drag_grab->drag_data_source->offer = NULL;
if (drag_grab->drag_data_source && data_device_resource)
offer = meta_wayland_data_source_send_offer (drag_grab->drag_data_source,
@@ -245,6 +368,28 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
}
static void
+data_source_update_user_dnd_action (MetaWaylandDataSource *source,
+ ClutterModifierType modifiers)
+{
+ uint32_t user_dnd_action = 0;
+
+ if (modifiers & CLUTTER_SHIFT_MASK)
+ user_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+ else if (modifiers & CLUTTER_CONTROL_MASK)
+ user_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ else if (modifiers & (CLUTTER_MOD1_MASK | CLUTTER_BUTTON2_MASK))
+ user_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+
+ if (source->user_dnd_action == user_dnd_action)
+ return;
+
+ source->user_dnd_action = user_dnd_action;
+
+ if (source->offer)
+ data_offer_update_action (source->offer);
+}
+
+static void
drag_grab_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
@@ -288,6 +433,7 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
drag_grab->seat->data_device.current_grab = NULL;
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
+ meta_wayland_keyboard_end_grab (drag_grab->keyboard_grab.keyboard);
g_slice_free (MetaWaylandDragGrab, drag_grab);
}
@@ -302,13 +448,21 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
if (drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
event_type == CLUTTER_BUTTON_RELEASE)
{
+ MetaWaylandDataSource *data_source = drag_grab->drag_data_source;
gboolean success = FALSE;
- if (drag_grab->drag_data_source->has_target)
+ if (drag_grab->drag_focus &&
+ data_source->has_target &&
+ data_source->current_dnd_action)
{
meta_wayland_surface_drag_dest_drop (drag_grab->drag_focus);
+ data_source->funcs.drop_performed (data_source);
success = TRUE;
}
+ else
+ {
+ data_source->funcs.cancel (data_source);
+ }
/* Finish drag and let actor self-destruct */
meta_dnd_actor_drag_finish (META_DND_ACTOR (drag_grab->feedback_actor),
@@ -327,6 +481,35 @@ static const MetaWaylandPointerGrabInterface drag_grab_interface = {
drag_grab_button,
};
+static gboolean
+keyboard_drag_grab_key (MetaWaylandKeyboardGrab *grab,
+ const ClutterEvent *event)
+{
+ 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)
+ data_source_update_user_dnd_action (drag_grab->drag_data_source, modifiers);
+}
+
+static const MetaWaylandKeyboardGrabInterface keyboard_drag_grab_interface = {
+ keyboard_drag_grab_key,
+ keyboard_drag_grab_modifiers
+};
+
static void
destroy_data_device_origin (struct wl_listener *listener, void *data)
{
@@ -373,12 +556,16 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
MetaWaylandDragGrab *drag_grab;
ClutterPoint pos, stage_pos;
+ ClutterModifierType modifiers;
data_device->current_grab = drag_grab = g_slice_new0 (MetaWaylandDragGrab);
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;
@@ -393,6 +580,11 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data
drag_grab->drag_start_x = stage_pos.x;
drag_grab->drag_start_y = stage_pos.y;
+ modifiers = clutter_input_device_get_modifier_state (seat->pointer.device);
+ drag_grab->buttons = modifiers &
+ (CLUTTER_BUTTON1_MASK | CLUTTER_BUTTON2_MASK | CLUTTER_BUTTON3_MASK |
+ CLUTTER_BUTTON4_MASK | CLUTTER_BUTTON5_MASK);
+
if (source)
{
if (source->resource)
@@ -405,6 +597,7 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data
drag_grab->drag_data_source = source;
meta_wayland_data_device_set_dnd_source (data_device,
drag_grab->drag_data_source);
+ data_source_update_user_dnd_action (drag_grab->drag_data_source, modifiers);
}
if (icon_surface)
@@ -484,6 +677,10 @@ data_device_start_drag (struct wl_client *client,
meta_wayland_data_device_start_drag (data_device, client,
&drag_grab_interface,
surface, drag_source, icon_surface);
+
+ meta_wayland_keyboard_set_focus (&seat->keyboard, NULL);
+ meta_wayland_keyboard_start_grab (&seat->keyboard,
+ &seat->data_device.current_grab->keyboard_grab);
}
static void
@@ -527,10 +724,32 @@ meta_wayland_source_cancel (MetaWaylandDataSource *source)
wl_data_source_send_cancelled (source->resource);
}
+static void
+meta_wayland_source_action (MetaWaylandDataSource *source,
+ uint32_t action)
+{
+ wl_data_source_send_action (source->resource, action);
+}
+
+static void
+meta_wayland_source_drop_performed (MetaWaylandDataSource *source)
+{
+ wl_data_source_send_drop_performed (source->resource);
+}
+
+static void
+meta_wayland_source_drag_finished (MetaWaylandDataSource *source)
+{
+ wl_data_source_send_drag_finished (source->resource);
+}
+
static const MetaWaylandDataSourceFuncs meta_wayland_source_funcs = {
meta_wayland_source_send,
meta_wayland_source_target,
- meta_wayland_source_cancel
+ meta_wayland_source_cancel,
+ meta_wayland_source_action,
+ meta_wayland_source_drop_performed,
+ meta_wayland_source_drag_finished
};
static void
diff --git a/src/wayland/meta-wayland-data-device.h b/src/wayland/meta-wayland-data-device.h
index 5c8793b..851748b 100644
--- a/src/wayland/meta-wayland-data-device.h
+++ b/src/wayland/meta-wayland-data-device.h
@@ -51,15 +51,24 @@ struct _MetaWaylandDataSourceFuncs
void (* target) (MetaWaylandDataSource *source,
const gchar *mime_type);
void (* cancel) (MetaWaylandDataSource *source);
+
+ void (* action) (MetaWaylandDataSource *source,
+ uint32_t action);
+ void (* drop_performed) (MetaWaylandDataSource *source);
+ void (* drag_finished) (MetaWaylandDataSource *source);
};
struct _MetaWaylandDataSource
{
MetaWaylandDataSourceFuncs funcs;
+ MetaWaylandDataOffer *offer;
struct wl_resource *resource;
struct wl_array mime_types;
gpointer user_data;
gboolean has_target;
+ uint32_t dnd_actions;
+ uint32_t user_dnd_action;
+ uint32_t current_dnd_action;
};
void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);
@@ -92,6 +101,12 @@ gboolean meta_wayland_data_source_has_mime_type (const MetaWaylandDataSource *s
void meta_wayland_data_source_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd);
+void meta_wayland_data_source_update_actions (MetaWaylandDataSource *source,
+ uint32_t dnd_actions);
+void meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source);
+
+void meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
+ uint32_t action);
const MetaWaylandDragDestFuncs *
meta_wayland_data_device_get_drag_dest_funcs (void);
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index 08ceaca..4a14eea 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -36,7 +36,7 @@
/* Global/master objects (version exported by wl_registry and negotiated through bind) */
#define META_WL_COMPOSITOR_VERSION 3
-#define META_WL_DATA_DEVICE_MANAGER_VERSION 2
+#define META_WL_DATA_DEVICE_MANAGER_VERSION 3
#define META_XDG_SHELL_VERSION 1
#define META_WL_SHELL_VERSION 1
#define META_WL_SEAT_VERSION 4
diff --git a/src/wayland/meta-xwayland-selection.c b/src/wayland/meta-xwayland-selection.c
index f0a136f..8d05d1f 100644
--- a/src/wayland/meta-xwayland-selection.c
+++ b/src/wayland/meta-xwayland-selection.c
@@ -122,6 +122,19 @@ const gchar *atom_names[] = {
Atom xdnd_atoms[N_DND_ATOMS];
/* XDND helpers */
+static Atom
+action_to_atom (uint32_t action)
+{
+ if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
+ return xdnd_atoms[ATOM_DND_ACTION_COPY];
+ else if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
+ return xdnd_atoms[ATOM_DND_ACTION_MOVE];
+ else if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
+ return xdnd_atoms[ATOM_DND_ACTION_ASK];
+ else
+ return None;
+}
+
static void
xdnd_send_enter (MetaXWaylandSelection *selection_data,
Window dest)
@@ -203,10 +216,18 @@ xdnd_send_position (MetaXWaylandSelection *selection_data,
int x,
int y)
{
+ MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaSelectionBridge *selection = &selection_data->dnd.selection;
+ MetaWaylandDataSource *source = compositor->seat->data_device.dnd_data_source;
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ uint32_t action = 0;
XEvent xev = { 0 };
+ if (source->user_dnd_action)
+ action = source->user_dnd_action;
+ else
+ action = source->dnd_actions;
+
xev.xclient.type = ClientMessage;
xev.xclient.message_type = xdnd_atoms[ATOM_DND_POSITION];
xev.xclient.format = 32;
@@ -216,7 +237,7 @@ xdnd_send_position (MetaXWaylandSelection *selection_data,
xev.xclient.data.l[1] = 0;
xev.xclient.data.l[2] = (x << 16) | y;
xev.xclient.data.l[3] = time;
- xev.xclient.data.l[4] = xdnd_atoms[ATOM_DND_ACTION_COPY];
+ xev.xclient.data.l[4] = action_to_atom (action);
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
}
@@ -248,6 +269,7 @@ xdnd_send_finished (MetaXWaylandSelection *selection_data,
{
MetaDndBridge *selection = &selection_data->dnd;
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ MetaWaylandDataSource *source = selection_data->dnd.selection.source;
XEvent xev = { 0 };
xev.xclient.type = ClientMessage;
@@ -260,7 +282,7 @@ xdnd_send_finished (MetaXWaylandSelection *selection_data,
if (accepted)
{
xev.xclient.data.l[1] = 1; /* Drop successful */
- xev.xclient.data.l[2] = xdnd_atoms[ATOM_DND_ACTION_COPY];
+ xev.xclient.data.l[2] = action_to_atom (source->current_dnd_action);
}
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
@@ -269,7 +291,7 @@ xdnd_send_finished (MetaXWaylandSelection *selection_data,
static void
xdnd_send_status (MetaXWaylandSelection *selection_data,
Window dest,
- gboolean accepted)
+ uint32_t action)
{
MetaDndBridge *selection = &selection_data->dnd;
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
@@ -282,12 +304,10 @@ xdnd_send_status (MetaXWaylandSelection *selection_data,
xev.xclient.data.l[0] = selection->dnd_window;
xev.xclient.data.l[1] = 1 << 1; /* Bit 2: dest wants XdndPosition messages */
+ xev.xclient.data.l[4] = action_to_atom (action);
- if (accepted)
- {
- xev.xclient.data.l[1] |= 1 << 0; /* Bit 1: dest accepts the drop */
- xev.xclient.data.l[4] = xdnd_atoms[ATOM_DND_ACTION_COPY];
- }
+ if (xev.xclient.data.l[4])
+ xev.xclient.data.l[1] |= 1 << 0; /* Bit 1: dest accepts the drop */
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
}
@@ -389,6 +409,12 @@ x11_selection_data_finish (MetaSelectionBridge *selection,
}
static void
+x11_selection_data_close (X11SelectionData *data)
+{
+ g_output_stream_close (data->stream, data->cancellable, NULL);
+}
+
+static void
x11_data_write_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
@@ -416,7 +442,10 @@ x11_data_write_cb (GObject *object,
}
if (!data->incr)
- x11_selection_data_finish (selection, TRUE);
+ {
+ x11_selection_data_close (selection->x11_selection);
+ x11_selection_data_finish (selection, TRUE);
+ }
}
static void
@@ -673,6 +702,7 @@ meta_xwayland_selection_get_incr_chunk (MetaWaylandCompositor *compositor,
else
{
/* Transfer has completed */
+ x11_selection_data_close (selection->x11_selection);
x11_selection_data_finish (selection, TRUE);
}
@@ -716,11 +746,15 @@ meta_x11_source_target (MetaWaylandDataSource *source,
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaSelectionBridge *selection = source->user_data;
+ uint32_t action = 0;
if (selection->selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
{
+ if (mime_type)
+ action = source->current_dnd_action;
+
xdnd_send_status (compositor->xwayland_manager.selection_data,
- selection->owner, mime_type != NULL);
+ selection->owner, action);
}
}
@@ -729,14 +763,64 @@ meta_x11_source_cancel (MetaWaylandDataSource *source)
{
MetaSelectionBridge *selection = source->user_data;
+ xdnd_send_finished (selection->x11_selection->selection_data,
+ selection->owner, FALSE);
g_clear_pointer (&selection->x11_selection,
(GDestroyNotify) x11_selection_data_free);
}
+static void
+meta_x11_source_action (MetaWaylandDataSource *source,
+ uint32_t action)
+{
+ MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+ MetaSelectionBridge *selection = source->user_data;
+
+ if (selection->selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
+ {
+ if (!source->has_target)
+ action = 0;
+
+ xdnd_send_status (compositor->xwayland_manager.selection_data,
+ selection->owner, action);
+ }
+}
+
+static void
+meta_x11_source_drop_performed (MetaWaylandDataSource *source)
+{
+}
+
+static void
+meta_x11_source_drag_finished (MetaWaylandDataSource *source)
+{
+ MetaSelectionBridge *selection = source->user_data;
+
+ if (source->current_dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
+ {
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ MetaSelectionBridge *selection = source->user_data;
+
+ /* Request data deletion on the drag source */
+ XConvertSelection (xdisplay,
+ selection->selection_atom,
+ gdk_x11_get_xatom_by_name ("DELETE"),
+ gdk_x11_get_xatom_by_name ("_META_SELECTION"),
+ selection->window,
+ CurrentTime);
+ }
+
+ xdnd_send_finished (selection->x11_selection->selection_data,
+ selection->owner, TRUE);
+}
+
static const MetaWaylandDataSourceFuncs meta_x11_source_funcs = {
meta_x11_source_send,
meta_x11_source_target,
- meta_x11_source_cancel
+ meta_x11_source_cancel,
+ meta_x11_source_action,
+ meta_x11_source_drop_performed,
+ meta_x11_source_drag_finished
};
static void
@@ -1080,6 +1164,10 @@ meta_xwayland_selection_handle_selection_request (MetaWaylandCompositor *composi
selection->timestamp);
reply_selection_request (event, TRUE);
}
+ else if (data_source && event->target == gdk_x11_get_xatom_by_name ("DELETE"))
+ {
+ meta_wayland_data_source_notify_finish (data_source);
+ }
else
{
if (data_source &&
@@ -1202,6 +1290,7 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
if (event->window == dnd->selection.window)
{
MetaWaylandDataSource *data_source;
+ uint32_t action = 0;
data_source = compositor->seat->data_device.dnd_data_source;
@@ -1213,6 +1302,18 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
/* The first bit in data.l[1] is set if the drag was accepted */
data_source->has_target = (event->data.l[1] & 1) != 0;
+ /* data.l[4] contains the action atom */
+ if (event->data.l[4])
+ {
+ if (((Atom) event->data.l[4]) == xdnd_atoms[ATOM_DND_ACTION_COPY])
+ action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ else if (((Atom) event->data.l[4]) == xdnd_atoms[ATOM_DND_ACTION_MOVE])
+ action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+ else if (((Atom) event->data.l[4]) == xdnd_atoms[ATOM_DND_ACTION_ASK])
+ action = WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+ }
+
+ meta_wayland_data_source_set_current_action (data_source, action);
return TRUE;
}
else if (event->message_type == xdnd_atoms[ATOM_DND_FINISHED])
@@ -1221,8 +1322,7 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
if (compositor->seat->data_device.current_grab)
return FALSE;
- meta_wayland_data_device_set_dnd_source (&compositor->seat->data_device,
- NULL);
+ meta_wayland_data_source_notify_finish (data_source);
return TRUE;
}
}
@@ -1276,6 +1376,7 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
{
ClutterEvent *motion;
ClutterPoint pos;
+ uint32_t action = 0;
motion = clutter_event_new (CLUTTER_MOTION);
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
@@ -1284,10 +1385,20 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
clutter_event_set_source_device (motion, seat->pointer.device);
clutter_event_set_time (motion, dnd->last_motion_time);
+ if ((Atom) event->data.l[4] == xdnd_atoms[ATOM_DND_ACTION_COPY])
+ action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ else if ((Atom) event->data.l[4] == xdnd_atoms[ATOM_DND_ACTION_MOVE])
+ action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+ else if ((Atom) event->data.l[4] == xdnd_atoms[ATOM_DND_ACTION_ASK])
+ action = WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+
+ meta_wayland_data_source_update_actions (dnd->selection.source,
+ action);
+
meta_wayland_surface_drag_dest_motion (drag_focus, motion);
xdnd_send_status (compositor->xwayland_manager.selection_data,
(Window) event->data.l[0],
- dnd->selection.source->has_target);
+ dnd->selection.source->current_dnd_action);
clutter_event_free (motion);
return TRUE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]