[gtk+/wip/wayland-dnd-actions: 20/23] wayland: Split handling of clipboard/DnD data offers
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/wayland-dnd-actions: 20/23] wayland: Split handling of clipboard/DnD data offers
- Date: Wed, 8 Apr 2015 13:43:20 +0000 (UTC)
commit 94795e1be8434ede272ccaaa12ffdaafeb666251
Author: Carlos Garnacho <carlosg gnome org>
Date: Tue Apr 7 16:40:57 2015 +0200
wayland: Split handling of clipboard/DnD data offers
We currently only hold the last offer received, which is wrong, as both
are independent and have different life cycles.
gdk/wayland/gdkdevice-wayland.c | 19 +++--
gdk/wayland/gdkdnd-wayland.c | 21 +++--
gdk/wayland/gdkprivate-wayland.h | 9 ++-
gdk/wayland/gdkselection-wayland.c | 162 ++++++++++++++++++++++++++----------
4 files changed, 150 insertions(+), 61 deletions(-)
---
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index 0708372..14ba5ea 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -592,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
@@ -607,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);
@@ -624,7 +624,8 @@ 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;
@@ -638,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
@@ -720,13 +721,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 = {
diff --git a/gdk/wayland/gdkdnd-wayland.c b/gdk/wayland/gdkdnd-wayland.c
index f558bb5..fd50c01 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;
@@ -196,8 +195,10 @@ 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);
+
+ display = gdk_device_get_display (gdk_drag_context_get_device (context));
+ wl_offer = gdk_wayland_selection_get_offer (display,
+ gdk_drag_get_selection (context));
if (!wl_offer)
return;
@@ -244,10 +245,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 +394,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
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index a8211fd..01038ba 100644
--- a/gdk/wayland/gdkprivate-wayland.h
+++ b/gdk/wayland/gdkprivate-wayland.h
@@ -237,10 +237,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,
diff --git a/gdk/wayland/gdkselection-wayland.c b/gdk/wayland/gdkselection-wayland.c
index 12a2d30..528724a 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,105 @@ 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 const struct wl_data_offer_listener data_offer_listener = {
data_offer_offer,
};
+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;
+
+ info = selection_lookup_offer_by_atom (selection, selection_atom);
- return selection->targets;
+ if (info)
+ return info->targets;
+
+ return NULL;
}
static void
@@ -551,6 +623,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 +633,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
@@ -655,8 +726,6 @@ data_source_send (void *data,
_gdk_wayland_drag_context_emit_event (context, GDK_DROP_FINISHED,
GDK_CURRENT_TIME);
}
-
- wayland_selection->source_requested_target = GDK_NONE;
}
static void
@@ -879,8 +948,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;
+
+ offer = gdk_wayland_selection_get_offer (display, selection);
+ targets = gdk_wayland_selection_get_targets (display, selection);
- if (!wayland_selection->offer)
+ if (!offer)
{
GdkEvent *event;
@@ -899,7 +973,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 +993,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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]