[gtk+/wip/wayland-dnd-actions: 23/23] wayland: Implement DnD actions as per wl_data_device v3
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/wayland-dnd-actions: 23/23] wayland: Implement DnD actions as per wl_data_device v3
- Date: Wed, 8 Apr 2015 13:43:35 +0000 (UTC)
commit dad02763599b32fbfa4a330601c25ecdac50b34e
Author: Carlos Garnacho <carlosg gnome org>
Date: Tue Apr 7 17:01:03 2015 +0200
wayland: Implement DnD actions as per wl_data_device v3
Instead of faking drag status all around, communicate these to the
compositor (and other peer), and trigger the right events on both sides:
- Changes in the selected action trigger GDK_DRAG_STATUS events on the
drag source, which trigger grab (and grab cursor) updates.
- In the case of move actions, the "DELETE" target request is completely
emulated on the source side as well, that target will be filtered out
from the offered mimetypes list as well.
gdk/wayland/gdkdisplay-wayland.c | 2 +-
gdk/wayland/gdkdnd-wayland.c | 38 ++++++++-
gdk/wayland/gdkprivate-wayland.h | 6 +-
gdk/wayland/gdkselection-wayland.c | 165 +++++++++++++++++++++++++++++++-----
4 files changed, 184 insertions(+), 27 deletions(-)
---
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 6d9a50e..e726842 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -202,7 +202,7 @@ gdk_registry_handle_global (void *data,
else if (strcmp (interface, "wl_data_device_manager") == 0)
{
display_wayland->data_device_manager =
- wl_registry_bind (display_wayland->wl_registry, id, &wl_data_device_manager_interface, 1);
+ wl_registry_bind (display_wayland->wl_registry, id, &wl_data_device_manager_interface, 3);
}
else if (strcmp (interface, "wl_subcompositor") == 0)
{
diff --git a/gdk/wayland/gdkdnd-wayland.c b/gdk/wayland/gdkdnd-wayland.c
index dd8a4c4..1b1a643 100644
--- a/gdk/wayland/gdkdnd-wayland.c
+++ b/gdk/wayland/gdkdnd-wayland.c
@@ -143,11 +143,30 @@ gdk_wayland_drag_context_find_window (GdkDragContext *context,
return NULL;
}
+static inline uint32_t
+gdk_to_wl_actions (GdkDragAction action)
+{
+ uint32_t dnd_actions = 0;
+
+ if (action & (GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_PRIVATE))
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ if (action & GDK_ACTION_MOVE)
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+ if (action & GDK_ACTION_ASK)
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+
+ return dnd_actions;
+}
+
void
-gdk_wayland_drag_context_set_action (GdkDragContext *context,
- GdkDragAction action)
+gdk_wayland_drag_context_set_actions (GdkDragContext *context,
+ GdkDragAction actions)
{
- context->suggested_action = context->action = action;
+ GdkWaylandDragContext *wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
+
+ context->actions = actions;
+ wl_data_source_notify_actions (wayland_context->data_source,
+ gdk_to_wl_actions (actions));
}
static gboolean
@@ -167,7 +186,7 @@ gdk_wayland_drag_context_drag_motion (GdkDragContext *context,
_gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS, time);
}
- gdk_wayland_drag_context_set_action (context, suggested_action);
+ gdk_wayland_drag_context_set_actions (context, possible_actions);
return context->dest_window != NULL;
}
@@ -196,6 +215,9 @@ gdk_wayland_drop_context_set_status (GdkDragContext *context,
context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context);
+ if (!context->dest_window)
+ return;
+
display = gdk_device_get_display (gdk_drag_context_get_device (context));
wl_offer = gdk_wayland_selection_get_offer (display,
gdk_drag_get_selection (context));
@@ -229,6 +251,14 @@ gdk_wayland_drag_context_drag_status (GdkDragContext *context,
GdkDragAction action,
guint32 time_)
{
+ GdkDisplay *display;
+ uint32_t dnd_actions;
+
+ display = gdk_device_get_display (gdk_drag_context_get_device (context));
+
+ dnd_actions = gdk_to_wl_actions (action);
+ gdk_wayland_selection_set_current_offer_actions (display, dnd_actions);
+
gdk_wayland_drop_context_set_status (context, action != 0);
}
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index a42eae6..6931e24 100644
--- a/gdk/wayland/gdkprivate-wayland.h
+++ b/gdk/wayland/gdkprivate-wayland.h
@@ -118,8 +118,8 @@ void _gdk_wayland_drag_context_set_coords (GdkDragContext *context,
gdouble x,
gdouble y);
-void gdk_wayland_drag_context_set_action (GdkDragContext *context,
- GdkDragAction action);
+void gdk_wayland_drag_context_set_actions (GdkDragContext *context,
+ GdkDragAction actions);
GdkDragContext * gdk_wayland_drag_context_lookup_by_data_source (struct wl_data_source *source);
GdkDragContext * gdk_wayland_drag_context_lookup_by_source_window (GdkWindow *window);
@@ -256,6 +256,8 @@ void gdk_wayland_selection_store (GdkWindow *window,
struct wl_data_source * gdk_wayland_selection_get_data_source (GdkWindow *owner,
GdkAtom selection);
void gdk_wayland_selection_unset_data_source (GdkDisplay *display, GdkAtom selection);
+gboolean gdk_wayland_selection_set_current_offer_actions (GdkDisplay *display,
+ uint32_t actions);
EGLSurface gdk_wayland_window_get_egl_surface (GdkWindow *window,
EGLConfig config);
diff --git a/gdk/wayland/gdkselection-wayland.c b/gdk/wayland/gdkselection-wayland.c
index 528724a..f7cd7ea 100644
--- a/gdk/wayland/gdkselection-wayland.c
+++ b/gdk/wayland/gdkselection-wayland.c
@@ -345,8 +345,69 @@ data_offer_offer (void *data,
info->targets = g_list_prepend (info->targets, atom);
}
+static inline GdkDragAction
+_wl_to_gdk_actions (uint32_t dnd_actions)
+{
+ GdkDragAction actions = 0;
+
+ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
+ actions |= GDK_ACTION_COPY;
+ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
+ actions |= GDK_ACTION_MOVE;
+ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
+ actions |= GDK_ACTION_ASK;
+
+ return actions;
+}
+
+static void
+data_offer_source_actions (void *data,
+ struct wl_data_offer *wl_data_offer,
+ uint32_t source_actions)
+{
+ GdkDeviceManager *device_manager;
+ GdkDragContext *drop_context;
+ GdkDisplay *display;
+ GdkDevice *device;
+
+ display = gdk_display_get_default ();
+ device_manager = gdk_display_get_device_manager (display);
+ device = gdk_device_manager_get_client_pointer (device_manager);
+ drop_context = gdk_wayland_device_get_drop_context (device);
+
+ drop_context->actions = _wl_to_gdk_actions (source_actions);
+
+ if (gdk_drag_context_get_dest_window (drop_context))
+ _gdk_wayland_drag_context_emit_event (drop_context, GDK_DRAG_MOTION,
+ GDK_CURRENT_TIME);
+}
+
+static void
+data_offer_action (void *data,
+ struct wl_data_offer *wl_data_offer,
+ uint32_t action)
+{
+ GdkDeviceManager *device_manager;
+ GdkDragContext *drop_context;
+ GdkDisplay *display;
+ GdkDevice *device;
+
+ display = gdk_display_get_default ();
+ device_manager = gdk_display_get_device_manager (display);
+ device = gdk_device_manager_get_client_pointer (device_manager);
+ drop_context = gdk_wayland_device_get_drop_context (device);
+
+ drop_context->action = _wl_to_gdk_actions (action);
+
+ if (gdk_drag_context_get_dest_window (drop_context))
+ _gdk_wayland_drag_context_emit_event (drop_context, GDK_DRAG_MOTION,
+ GDK_CURRENT_TIME);
+}
+
static const struct wl_data_offer_listener data_offer_listener = {
data_offer_offer,
+ data_offer_source_actions,
+ data_offer_action
};
DataOfferData *
@@ -401,7 +462,6 @@ gdk_wayland_selection_set_offer (GdkDisplay *display,
else if (selection_atom == atoms[ATOM_DND])
selection->dnd_offer = info;
- /* Clear all buffers */
g_hash_table_remove_all (selection->selection_buffers);
}
@@ -471,6 +531,8 @@ async_write_data_new (GdkWaylandSelection *selection)
static void
async_write_data_free (AsyncWriteData *write_data)
{
+ close (write_data->selection->stored_selection.fd);
+ write_data->selection->stored_selection.fd = -1;
g_object_unref (write_data->stream);
g_slice_free (AsyncWriteData, write_data);
}
@@ -533,7 +595,7 @@ gdk_wayland_selection_check_write (GdkWaylandSelection *selection)
{
AsyncWriteData *write_data;
- if (selection->stored_selection.fd < 0 ||
+ if (selection->stored_selection.fd <= 0 ||
selection->stored_selection.data_len == 0)
return FALSE;
@@ -555,6 +617,9 @@ gdk_wayland_selection_store (GdkWindow *window,
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
GArray *array;
+ if (type == gdk_atom_intern_static_string ("NULL"))
+ return;
+
array = g_array_new (TRUE, FALSE, sizeof (guchar));
g_array_append_vals (array, data, len);
@@ -665,18 +730,15 @@ data_source_target (void *data,
if (!mime_type)
{
if (context)
- {
- gdk_wayland_drag_context_set_action (context, 0);
- _gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS,
- GDK_CURRENT_TIME);
- }
+ _gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS,
+ GDK_CURRENT_TIME);
+
return;
}
if (source == wayland_selection->dnd_source)
{
window = wayland_selection->dnd_owner;
- gdk_wayland_drag_context_set_action (context, GDK_ACTION_COPY);
_gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS,
GDK_CURRENT_TIME);
}
@@ -697,7 +759,6 @@ data_source_send (void *data,
int32_t fd)
{
GdkWaylandSelection *wayland_selection = data;
- GdkDragContext *context;
GdkWindow *window;
g_debug (G_STRLOC ": %s source = %p, mime_type = %s, fd = %d",
@@ -706,8 +767,6 @@ data_source_send (void *data,
if (!mime_type)
return;
- context = gdk_wayland_drag_context_lookup_by_data_source (source);
-
if (source == wayland_selection->dnd_source)
window = wayland_selection->dnd_owner;
else if (source == wayland_selection->clipboard_source)
@@ -719,13 +778,6 @@ data_source_send (void *data,
gdk_atom_intern (mime_type, FALSE),
fd))
gdk_wayland_selection_check_write (wayland_selection);
-
- if (context)
- {
- gdk_wayland_drag_context_undo_grab (context);
- _gdk_wayland_drag_context_emit_event (context, GDK_DROP_FINISHED,
- GDK_CURRENT_TIME);
- }
}
static void
@@ -754,10 +806,62 @@ data_source_cancelled (void *data,
gdk_wayland_selection_unset_data_source (display, atoms[ATOM_CLIPBOARD]);
}
+static void
+data_source_action (void *data,
+ struct wl_data_source *source,
+ uint32_t action)
+{
+ GdkDragContext *context;
+
+ g_debug (G_STRLOC ": %s source = %p action=%x",
+ G_STRFUNC, source, action);
+
+ context = gdk_wayland_drag_context_lookup_by_data_source (source);
+
+ if (context)
+ {
+ context->action = _wl_to_gdk_actions (action);
+ _gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS,
+ GDK_CURRENT_TIME);
+ }
+}
+
+static void
+data_source_drop_performed (void *data,
+ struct wl_data_source *source)
+{
+}
+
+static void
+data_source_drag_finished (void *data,
+ struct wl_data_source *source)
+{
+ GdkDragContext *context;
+
+ context = gdk_wayland_drag_context_lookup_by_data_source (source);
+
+ if (!context)
+ return;
+
+ if (context->action == GDK_ACTION_MOVE)
+ {
+ gdk_wayland_selection_emit_request (context->source_window,
+ atoms[ATOM_DND],
+ gdk_atom_intern_static_string ("DELETE"));
+ }
+
+ gdk_wayland_drag_context_undo_grab (context);
+ _gdk_wayland_drag_context_emit_event (context, GDK_DROP_FINISHED,
+ GDK_CURRENT_TIME);
+}
+
static const struct wl_data_source_listener data_source_listener = {
data_source_target,
data_source_send,
- data_source_cancelled
+ data_source_cancelled,
+ data_source_action,
+ data_source_drop_performed,
+ data_source_drag_finished
};
struct wl_data_source *
@@ -954,7 +1058,7 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
offer = gdk_wayland_selection_get_offer (display, selection);
targets = gdk_wayland_selection_get_targets (display, selection);
- if (!offer)
+ if (!offer || target == gdk_atom_intern_static_string ("DELETE"))
{
GdkEvent *event;
@@ -1117,3 +1221,24 @@ gdk_wayland_selection_clear_targets (GdkDisplay *display,
{
gdk_wayland_selection_unset_data_source (display, selection);
}
+
+gboolean
+gdk_wayland_selection_set_current_offer_actions (GdkDisplay *display,
+ uint32_t action)
+{
+ struct wl_data_offer *offer;
+ uint32_t all_actions = 0;
+
+ offer = gdk_wayland_selection_get_offer (display, atoms[ATOM_DND]);
+
+ if (!offer)
+ return FALSE;
+
+ if (action != 0)
+ all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+
+ wl_data_offer_notify_actions (offer, all_actions, action);
+ return TRUE;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]