[gtk+/wip/wayland-dnd-actions: 673/674] 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: 673/674] wayland: Implement DnD actions as per wl_data_device v3
- Date: Mon, 29 Jun 2015 16:44:31 +0000 (UTC)
commit 86c18a807acd3a9b5724017f7bf36f1b81f7060e
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 | 161 +++++++++++++++++++++++++++++++----
4 files changed, 181 insertions(+), 26 deletions(-)
---
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index a0a5d0c..dbe8bc7 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -350,7 +350,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 e96aeda..82e4265 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_set_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));
@@ -231,6 +253,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 b78f854..05e54c0 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 9da66cb..c81afc9 100644
--- a/gdk/wayland/gdkselection-wayland.c
+++ b/gdk/wayland/gdkselection-wayland.c
@@ -350,8 +350,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 *
@@ -406,7 +467,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);
}
@@ -569,6 +629,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);
@@ -715,18 +778,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);
}
@@ -748,7 +808,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",
@@ -760,8 +819,6 @@ data_source_send (void *data,
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)
@@ -779,13 +836,6 @@ data_source_send (void *data,
gdk_atom_intern (mime_type, FALSE),
fd))
gdk_wayland_selection_check_write (wayland_selection);
-
- if (context)
- {
- gdk_wayland_device_unset_grab (gdk_drag_context_get_device (context));
- _gdk_wayland_drag_context_emit_event (context, GDK_DROP_FINISHED,
- GDK_CURRENT_TIME);
- }
}
static void
@@ -814,10 +864,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_device_unset_grab (gdk_drag_context_get_device (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 *
@@ -1015,7 +1117,7 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
offer = gdk_wayland_selection_get_offer (display, selection);
target_list = gdk_wayland_selection_get_targets (display, selection);
- if (!offer)
+ if (!offer || target == gdk_atom_intern_static_string ("DELETE"))
{
GdkEvent *event;
@@ -1192,3 +1294,24 @@ gdk_wayland_selection_clear_targets (GdkDisplay *display,
g_array_set_size (wayland_selection->source_targets, 0);
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_set_actions (offer, all_actions, action);
+ return TRUE;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]