[gtk+/wip/wayland-dnd-actions] WIP: Wayland DnD actions
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/wayland-dnd-actions] WIP: Wayland DnD actions
- Date: Fri, 3 Apr 2015 18:02:28 +0000 (UTC)
commit 061a3dcde287dda2ea28038d71e97bc34230e72c
Author: Carlos Garnacho <carlosg gnome org>
Date: Wed Feb 18 13:27:54 2015 +0100
WIP: Wayland DnD actions
gdk/wayland/gdkdevice-wayland.c | 64 ++++++-
gdk/wayland/gdkdisplay-wayland.c | 2 +-
gdk/wayland/gdkdnd-wayland.c | 62 ++++++--
gdk/wayland/gdkprivate-wayland.h | 16 ++-
gdk/wayland/gdkselection-wayland.c | 325 +++++++++++++++++++++++++++++-------
5 files changed, 380 insertions(+), 89 deletions(-)
---
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index a22351b..34495c7 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -95,6 +95,9 @@ struct _GdkWaylandDeviceData
struct wl_surface *pointer_surface;
guint current_output_scale;
GSList *pointer_surface_outputs;
+
+ /* Source/dest for non-local dnd */
+ GdkWindow *foreign_dnd_window;
};
struct _GdkWaylandDevice
@@ -589,8 +592,7 @@ data_device_data_offer (void *data,
g_message ("data device data offer, data device %p, offer %p",
data_device, offer));
- gdk_wayland_selection_set_offer (device->display, offer);
- emit_selection_owner_change_forall (gdk_atom_intern_static_string ("GdkWaylandSelection"));
+ gdk_wayland_selection_ensure_offer (device->display, offer);
}
static void
@@ -604,6 +606,7 @@ data_device_enter (void *data,
{
GdkWaylandDeviceData *device = (GdkWaylandDeviceData *)data;
GdkWindow *dest_window, *dnd_owner;
+ GdkAtom selection;
dest_window = wl_surface_get_user_data (surface);
@@ -621,10 +624,13 @@ data_device_enter (void *data,
gdk_wayland_drop_context_update_targets (device->drop_context);
- dnd_owner = gdk_selection_owner_get_for_display (device->display, gdk_drag_get_selection
(device->drop_context));
+ selection = gdk_drag_get_selection (device->drop_context);
+ dnd_owner = gdk_selection_owner_get_for_display (device->display, selection);
+
+ if (!dnd_owner)
+ dnd_owner = device->foreign_dnd_window;
- if (dnd_owner)
- _gdk_wayland_drag_context_set_source_window (device->drop_context, dnd_owner);
+ _gdk_wayland_drag_context_set_source_window (device->drop_context, dnd_owner);
_gdk_wayland_drag_context_set_dest_window (device->drop_context,
dest_window, serial);
@@ -633,9 +639,9 @@ data_device_enter (void *data,
wl_fixed_to_double (y));
_gdk_wayland_drag_context_emit_event (device->drop_context, GDK_DRAG_ENTER,
GDK_CURRENT_TIME);
- gdk_wayland_selection_set_offer (device->display, offer);
- emit_selection_owner_change (dest_window,
- gdk_atom_intern_static_string ("GdkWaylandSelection"));
+
+ gdk_wayland_selection_set_offer (device->display, selection, offer);
+ emit_selection_owner_change_forall (selection);
}
static void
@@ -695,6 +701,9 @@ data_device_drop (void *data,
GDK_NOTE (EVENTS,
g_message ("data device drop, data device %p", data_device));
+ if (!gdk_drag_context_get_dest_window (device->drop_context))
+ return;
+
local_dnd_owner = gdk_selection_owner_get_for_display (device->display, gdk_drag_get_selection
(device->drop_context));
if (local_dnd_owner)
@@ -715,13 +724,15 @@ data_device_selection (void *data,
struct wl_data_offer *offer)
{
GdkWaylandDeviceData *device = (GdkWaylandDeviceData *) data;
+ GdkAtom selection;
GDK_NOTE (EVENTS,
g_message ("data device selection, data device %p, data offer %p",
wl_data_device, offer));
- gdk_wayland_selection_set_offer (device->display, offer);
- emit_selection_owner_change_forall (gdk_atom_intern_static_string ("CLIPBOARD"));
+ selection = gdk_atom_intern_static_string ("CLIPBOARD");
+ gdk_wayland_selection_set_offer (device->display, selection, offer);
+ emit_selection_owner_change_forall (selection);
}
static const struct wl_data_device_listener data_device_listener = {
@@ -1838,6 +1849,26 @@ static const struct wl_surface_listener pointer_surface_listener = {
pointer_surface_leave
};
+static GdkWindow *
+create_foreign_dnd_window (GdkDisplay *display)
+{
+ GdkWindowAttr attrs;
+ GdkScreen *screen;
+ guint mask;
+
+ screen = gdk_display_get_default_screen (display);
+
+ attrs.x = attrs.y = 0;
+ attrs.width = attrs.height = 1;
+ attrs.wclass = GDK_INPUT_OUTPUT;
+ attrs.window_type = GDK_WINDOW_TEMP;
+ attrs.visual = gdk_screen_get_system_visual (screen);
+
+ mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+
+ return gdk_window_new (gdk_screen_get_root_window (screen), &attrs, mask);
+}
+
void
_gdk_wayland_device_manager_add_seat (GdkDeviceManager *device_manager,
guint32 id,
@@ -1857,6 +1888,7 @@ _gdk_wayland_device_manager_add_seat (GdkDeviceManager *device_manager,
device->device_manager = device_manager;
device->touches = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) g_free);
+ device->foreign_dnd_window = create_foreign_dnd_window (display);
device->wl_seat = wl_seat;
wl_seat_add_listener (device->wl_seat, &seat_listener, device);
@@ -1898,6 +1930,7 @@ _gdk_wayland_device_manager_remove_seat (GdkDeviceManager *manager,
/* FIXME: destroy data_device */
g_clear_object (&device->keyboard_settings);
g_hash_table_destroy (device->touches);
+ gdk_window_destroy (device->foreign_dnd_window);
g_free (device);
break;
@@ -2072,3 +2105,14 @@ gdk_wayland_device_set_selection (GdkDevice *gdk_device,
wl_data_device_set_selection (device->data_device, source,
_gdk_wayland_display_get_serial (display_wayland));
}
+
+GdkDragContext *
+gdk_wayland_device_get_drop_context (GdkDevice *gdk_device)
+{
+ GdkWaylandDeviceData *device;
+
+ g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device));
+ device = GDK_WAYLAND_DEVICE (gdk_device)->device;
+
+ return device->drop_context;
+}
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 1b26e5b..4aeb526 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 f558bb5..30a7df2 100644
--- a/gdk/wayland/gdkdnd-wayland.c
+++ b/gdk/wayland/gdkdnd-wayland.c
@@ -43,7 +43,6 @@ struct _GdkWaylandDragContext
GdkWindow *dnd_window;
struct wl_surface *dnd_surface;
struct wl_data_source *data_source;
- struct wl_data_offer *offer;
uint32_t serial;
gdouble x;
gdouble y;
@@ -144,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
@@ -168,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,8 +214,13 @@ gdk_wayland_drop_context_set_status (GdkDragContext *context,
struct wl_data_offer *wl_offer;
context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context);
- display = gdk_window_get_display (context->source_window);
- wl_offer = gdk_wayland_selection_get_offer (display);
+
+ if (!context->dest_window)
+ return;
+
+ display = gdk_window_get_display (context->dest_window);
+ wl_offer = gdk_wayland_selection_get_offer (display,
+ gdk_drag_get_selection (context));
if (!wl_offer)
return;
@@ -228,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);
}
@@ -244,10 +275,15 @@ gdk_wayland_drag_context_drop_finish (GdkDragContext *context,
gboolean success,
guint32 time)
{
- GdkDisplay *display = gdk_window_get_display (context->source_window);
+ GdkDisplay *display = gdk_device_get_display (gdk_drag_context_get_device (context));
+ GdkAtom selection;
- if (gdk_selection_owner_get_for_display (display, gdk_drag_get_selection (context)))
- gdk_wayland_selection_unset_data_source (display, gdk_drag_get_selection (context));
+ selection = gdk_drag_get_selection (context);
+
+ if (gdk_selection_owner_get_for_display (display, selection))
+ gdk_wayland_selection_unset_data_source (display, selection);
+
+ gdk_wayland_selection_set_offer (display, selection, NULL);
}
static gboolean
@@ -388,7 +424,8 @@ gdk_wayland_drop_context_update_targets (GdkDragContext *context)
device = gdk_drag_context_get_device (context);
display = gdk_device_get_display (device);
g_list_free (context->targets);
- context->targets = g_list_copy (gdk_wayland_selection_get_targets (display));
+ context->targets = g_list_copy (gdk_wayland_selection_get_targets (display,
+ gdk_drag_get_selection (context)));
}
void
@@ -418,6 +455,9 @@ _gdk_wayland_drag_context_set_dest_window (GdkDragContext *context,
GdkWindow *dest_window,
uint32_t serial)
{
+ if (context->dest_window)
+ g_object_unref (context->dest_window);
+
context->dest_window = dest_window ? g_object_ref (dest_window) : NULL;
GDK_WAYLAND_DRAG_CONTEXT (context)->serial = serial;
gdk_wayland_drop_context_update_targets (context);
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index a8211fd..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);
@@ -186,6 +186,7 @@ uint32_t _gdk_wayland_device_get_last_implicit_grab_serial (GdkWaylandDevice *d
struct wl_data_device * gdk_wayland_device_get_data_device (GdkDevice *gdk_device);
void gdk_wayland_device_set_selection (GdkDevice *gdk_device,
struct wl_data_source *source);
+GdkDragContext * gdk_wayland_device_get_drop_context (GdkDevice *gdk_device);
void gdk_wayland_device_unset_touch_grab (GdkDevice *device,
GdkEventSequence *sequence);
@@ -237,10 +238,15 @@ GdkWaylandSelection * gdk_wayland_display_get_selection (GdkDisplay *display);
GdkWaylandSelection * gdk_wayland_selection_new (void);
void gdk_wayland_selection_free (GdkWaylandSelection *selection);
+void gdk_wayland_selection_ensure_offer (GdkDisplay *display,
+ struct wl_data_offer *wl_offer);
void gdk_wayland_selection_set_offer (GdkDisplay *display,
+ GdkAtom selection,
struct wl_data_offer *wl_offer);
-struct wl_data_offer * gdk_wayland_selection_get_offer (GdkDisplay *display);
-GList * gdk_wayland_selection_get_targets (GdkDisplay *display);
+struct wl_data_offer * gdk_wayland_selection_get_offer (GdkDisplay *display,
+ GdkAtom selection);
+GList * gdk_wayland_selection_get_targets (GdkDisplay *display,
+ GdkAtom selection);
void gdk_wayland_selection_store (GdkWindow *window,
GdkAtom type,
@@ -250,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 12a2d30..f7cd7ea 100644
--- a/gdk/wayland/gdkselection-wayland.c
+++ b/gdk/wayland/gdkselection-wayland.c
@@ -36,6 +36,7 @@
typedef struct _SelectionBuffer SelectionBuffer;
typedef struct _StoredSelection StoredSelection;
typedef struct _AsyncWriteData AsyncWriteData;
+typedef struct _DataOfferData DataOfferData;
struct _SelectionBuffer
{
@@ -64,6 +65,13 @@ struct _DataSourceData
GdkAtom selection;
};
+struct _DataOfferData
+{
+ struct wl_data_offer *offer;
+ GList *targets; /* List of GdkAtom */
+ GdkAtom requested_target;
+};
+
struct _AsyncWriteData
{
GOutputStream *stream;
@@ -81,11 +89,10 @@ static GdkAtom atoms[2] = { 0 };
struct _GdkWaylandSelection
{
/* Destination-side data */
- struct wl_data_offer *offer;
- GdkAtom source_requested_target;
-
+ DataOfferData *dnd_offer;
+ DataOfferData *clipboard_offer;
+ GHashTable *offers; /* Currently alive offers, Hashtable of wl_data_offer->DataOfferData */
GHashTable *selection_buffers; /* Hashtable of target_atom->SelectionBuffer */
- GList *targets; /* List of GdkAtom */
/* Source-side data */
StoredSelection stored_selection;
@@ -259,6 +266,25 @@ selection_buffer_read (SelectionBuffer *buffer)
buffer);
}
+static DataOfferData *
+data_offer_data_new (struct wl_data_offer *offer)
+{
+ DataOfferData *info;
+
+ info = g_slice_new0 (DataOfferData);
+ info->offer = offer;
+
+ return info;
+}
+
+static void
+data_offer_data_free (DataOfferData *info)
+{
+ wl_data_offer_destroy (info->offer);
+ g_list_free (info->targets);
+ g_slice_free (DataOfferData, info);
+}
+
GdkWaylandSelection *
gdk_wayland_selection_new (void)
{
@@ -270,8 +296,11 @@ gdk_wayland_selection_new (void)
selection = g_new0 (GdkWaylandSelection, 1);
selection->selection_buffers =
- g_hash_table_new_full (NULL, NULL, NULL,
- (GDestroyNotify) selection_buffer_cancel_and_unref);
+ g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) selection_buffer_cancel_and_unref);
+ selection->offers =
+ g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) data_offer_data_free);
return selection;
}
@@ -279,10 +308,7 @@ void
gdk_wayland_selection_free (GdkWaylandSelection *selection)
{
g_hash_table_destroy (selection->selection_buffers);
-
- if (selection->targets)
- g_list_free (selection->targets);
-
+ g_hash_table_destroy (selection->offers);
g_free (selection->stored_selection.data);
if (selection->stored_selection.cancellable)
@@ -294,8 +320,6 @@ gdk_wayland_selection_free (GdkWaylandSelection *selection)
if (selection->stored_selection.fd > 0)
close (selection->stored_selection.fd);
- if (selection->offer)
- wl_data_offer_destroy (selection->offer);
if (selection->clipboard_source)
wl_data_source_destroy (selection->clipboard_source);
if (selection->dnd_source)
@@ -310,57 +334,165 @@ data_offer_offer (void *data,
const char *type)
{
GdkWaylandSelection *selection = data;
+ DataOfferData *info;
GdkAtom atom = gdk_atom_intern (type, FALSE);
- if (g_list_find (selection->targets, atom))
+ info = g_hash_table_lookup (selection->offers, wl_data_offer);
+
+ if (!info || g_list_find (info->targets, atom))
return;
- selection->targets = g_list_prepend (selection->targets, atom);
+ 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 *
+selection_lookup_offer_by_atom (GdkWaylandSelection *selection,
+ GdkAtom selection_atom)
+{
+ if (selection_atom == atoms[ATOM_CLIPBOARD])
+ return selection->clipboard_offer;
+ else if (selection_atom == atoms[ATOM_DND])
+ return selection->dnd_offer;
+ else
+ return NULL;
+}
+
+void
+gdk_wayland_selection_ensure_offer (GdkDisplay *display,
+ struct wl_data_offer *wl_offer)
+{
+ GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
+ DataOfferData *info;
+
+ info = g_hash_table_lookup (selection->offers, wl_offer);
+
+ if (!info)
+ {
+ info = data_offer_data_new (wl_offer);
+ g_hash_table_insert (selection->offers, wl_offer, info);
+ wl_data_offer_add_listener (wl_offer,
+ &data_offer_listener,
+ selection);
+ }
+}
+
void
gdk_wayland_selection_set_offer (GdkDisplay *display,
+ GdkAtom selection_atom,
struct wl_data_offer *wl_offer)
{
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
+ struct wl_data_offer *prev_offer;
+ DataOfferData *info;
- if (selection->offer == wl_offer)
- return;
+ info = g_hash_table_lookup (selection->offers, wl_offer);
- if (selection->offer)
- wl_data_offer_destroy (selection->offer);
+ prev_offer = gdk_wayland_selection_get_offer (display, selection_atom);
- selection->offer = wl_offer;
+ if (prev_offer)
+ g_hash_table_remove (selection->offers, prev_offer);
- if (wl_offer)
- wl_data_offer_add_listener (wl_offer,
- &data_offer_listener,
- selection);
+ if (selection_atom == atoms[ATOM_CLIPBOARD])
+ selection->clipboard_offer = info;
+ else if (selection_atom == atoms[ATOM_DND])
+ selection->dnd_offer = info;
- /* Clear all buffers */
g_hash_table_remove_all (selection->selection_buffers);
- g_list_free (selection->targets);
- selection->targets = NULL;
}
struct wl_data_offer *
-gdk_wayland_selection_get_offer (GdkDisplay *display)
+gdk_wayland_selection_get_offer (GdkDisplay *display,
+ GdkAtom selection_atom)
{
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
+ const DataOfferData *info;
+
+ info = selection_lookup_offer_by_atom (selection, selection_atom);
- return selection->offer;
+ if (info)
+ return info->offer;
+
+ return NULL;
}
GList *
-gdk_wayland_selection_get_targets (GdkDisplay *display)
+gdk_wayland_selection_get_targets (GdkDisplay *display,
+ GdkAtom selection_atom)
{
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
+ const DataOfferData *info;
- return selection->targets;
+ info = selection_lookup_offer_by_atom (selection, selection_atom);
+
+ if (info)
+ return info->targets;
+
+ return NULL;
}
static void
@@ -399,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);
}
@@ -461,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;
@@ -483,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);
@@ -551,6 +688,7 @@ gdk_wayland_selection_request_target (GdkWaylandSelection *wayland_selection,
GdkAtom target,
gint fd)
{
+ DataOfferData *offer;
GdkAtom selection;
if (wayland_selection->clipboard_owner == window)
@@ -560,21 +698,19 @@ gdk_wayland_selection_request_target (GdkWaylandSelection *wayland_selection,
else
return FALSE;
+ offer = selection_lookup_offer_by_atom (wayland_selection, selection);
+
if (wayland_selection->stored_selection.fd == fd &&
- wayland_selection->source_requested_target == target)
+ offer->requested_target == target)
return FALSE;
wayland_selection->stored_selection.fd = fd;
-
- wayland_selection->source_requested_target = target;
+ offer->requested_target = target;
if (window && target != GDK_NONE)
- {
- gdk_wayland_selection_emit_request (window, selection, target);
- return TRUE;
- }
+ gdk_wayland_selection_emit_request (window, selection, target);
- return FALSE;
+ return TRUE;
}
static void
@@ -594,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);
}
@@ -626,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",
@@ -635,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)
@@ -648,15 +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);
- }
-
- wayland_selection->source_requested_target = GDK_NONE;
}
static void
@@ -685,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 *
@@ -879,8 +1052,13 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
{
GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
SelectionBuffer *buffer_data;
+ struct wl_data_offer *offer;
+ GList *targets;
- if (!wayland_selection->offer)
+ offer = gdk_wayland_selection_get_offer (display, selection);
+ targets = gdk_wayland_selection_get_targets (display, selection);
+
+ if (!offer || target == gdk_atom_intern_static_string ("DELETE"))
{
GdkEvent *event;
@@ -899,7 +1077,7 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
}
if (target != gdk_atom_intern_static_string ("TARGETS"))
- wl_data_offer_accept (wayland_selection->offer,
+ wl_data_offer_accept (offer,
_gdk_wayland_display_get_serial (GDK_WAYLAND_DISPLAY (display)),
gdk_atom_name (target));
@@ -919,16 +1097,16 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
gint i = 0;
GList *l;
- natoms = g_list_length (wayland_selection->targets);
+ natoms = g_list_length (targets);
atoms = g_new0 (GdkAtom, natoms);
- for (l = wayland_selection->targets; l; l = l->next)
+ for (l = targets; l; l = l->next)
atoms[i++] = l->data;
}
else
{
g_unix_open_pipe (pipe_fd, FD_CLOEXEC, NULL);
- wl_data_offer_receive (wayland_selection->offer,
+ wl_data_offer_receive (offer,
gdk_atom_name (target),
pipe_fd[1]);
stream = g_unix_input_stream_new (pipe_fd[0], TRUE);
@@ -1043,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]