mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-29 06:51:10 +00:00
wayland: Separate selection buffers and other per-selection atom data
This has most notably impact in selection buffers, because those were shared across all selection atoms. This turned out wrong on 2 situations: - Because the selection atom was set at SelectionBuffer creation time, the GDK_SELECTION_NOTIFY events generated will have unexpected info if the buffer is attempted to be reused for another selection. - Anytime different selections imply different stored content for the same target. This is better separated into per-selection buffers, so it's not possible to get collisions if a same target is used across different selections. https://bugzilla.gnome.org/show_bug.cgi?id=768177
This commit is contained in:
parent
4b003a75aa
commit
0d30ad279f
@ -35,6 +35,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct _SelectionBuffer SelectionBuffer;
|
typedef struct _SelectionBuffer SelectionBuffer;
|
||||||
|
typedef struct _SelectionData SelectionData;
|
||||||
typedef struct _StoredSelection StoredSelection;
|
typedef struct _StoredSelection StoredSelection;
|
||||||
typedef struct _AsyncWriteData AsyncWriteData;
|
typedef struct _AsyncWriteData AsyncWriteData;
|
||||||
typedef struct _DataOfferData DataOfferData;
|
typedef struct _DataOfferData DataOfferData;
|
||||||
@ -80,22 +81,26 @@ struct _AsyncWriteData
|
|||||||
gsize index;
|
gsize index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _SelectionData
|
||||||
|
{
|
||||||
|
DataOfferData *offer;
|
||||||
|
GHashTable *buffers; /* Hashtable of target_atom->SelectionBuffer */
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ATOM_PRIMARY,
|
ATOM_PRIMARY,
|
||||||
ATOM_CLIPBOARD,
|
ATOM_CLIPBOARD,
|
||||||
ATOM_DND
|
ATOM_DND,
|
||||||
|
N_ATOMS
|
||||||
};
|
};
|
||||||
|
|
||||||
static GdkAtom atoms[3] = { 0 };
|
static GdkAtom atoms[N_ATOMS] = { 0 };
|
||||||
|
|
||||||
struct _GdkWaylandSelection
|
struct _GdkWaylandSelection
|
||||||
{
|
{
|
||||||
/* Destination-side data */
|
/* Destination-side data */
|
||||||
DataOfferData *dnd_offer;
|
SelectionData selections[N_ATOMS];
|
||||||
DataOfferData *clipboard_offer;
|
|
||||||
DataOfferData *primary_offer;
|
|
||||||
GHashTable *offers; /* Currently alive offers, Hashtable of wl_data_offer->DataOfferData */
|
GHashTable *offers; /* Currently alive offers, Hashtable of wl_data_offer->DataOfferData */
|
||||||
GHashTable *selection_buffers; /* Hashtable of target_atom->SelectionBuffer */
|
|
||||||
|
|
||||||
/* Source-side data */
|
/* Source-side data */
|
||||||
StoredSelection stored_selection;
|
StoredSelection stored_selection;
|
||||||
@ -307,6 +312,7 @@ GdkWaylandSelection *
|
|||||||
gdk_wayland_selection_new (void)
|
gdk_wayland_selection_new (void)
|
||||||
{
|
{
|
||||||
GdkWaylandSelection *selection;
|
GdkWaylandSelection *selection;
|
||||||
|
gint i;
|
||||||
|
|
||||||
/* init atoms */
|
/* init atoms */
|
||||||
atoms[ATOM_PRIMARY] = gdk_atom_intern_static_string ("PRIMARY");
|
atoms[ATOM_PRIMARY] = gdk_atom_intern_static_string ("PRIMARY");
|
||||||
@ -314,9 +320,13 @@ gdk_wayland_selection_new (void)
|
|||||||
atoms[ATOM_DND] = gdk_atom_intern_static_string ("GdkWaylandSelection");
|
atoms[ATOM_DND] = gdk_atom_intern_static_string ("GdkWaylandSelection");
|
||||||
|
|
||||||
selection = g_new0 (GdkWaylandSelection, 1);
|
selection = g_new0 (GdkWaylandSelection, 1);
|
||||||
selection->selection_buffers =
|
for (i = 0; i < G_N_ELEMENTS (selection->selections); i++)
|
||||||
g_hash_table_new_full (NULL, NULL, NULL,
|
{
|
||||||
(GDestroyNotify) selection_buffer_cancel_and_unref);
|
selection->selections[i].buffers =
|
||||||
|
g_hash_table_new_full (NULL, NULL, NULL,
|
||||||
|
(GDestroyNotify) selection_buffer_cancel_and_unref);
|
||||||
|
}
|
||||||
|
|
||||||
selection->offers =
|
selection->offers =
|
||||||
g_hash_table_new_full (NULL, NULL, NULL,
|
g_hash_table_new_full (NULL, NULL, NULL,
|
||||||
(GDestroyNotify) data_offer_data_free);
|
(GDestroyNotify) data_offer_data_free);
|
||||||
@ -328,7 +338,11 @@ gdk_wayland_selection_new (void)
|
|||||||
void
|
void
|
||||||
gdk_wayland_selection_free (GdkWaylandSelection *selection)
|
gdk_wayland_selection_free (GdkWaylandSelection *selection)
|
||||||
{
|
{
|
||||||
g_hash_table_destroy (selection->selection_buffers);
|
gint i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (selection->selections); i++)
|
||||||
|
g_hash_table_destroy (selection->selections[i].buffers);
|
||||||
|
|
||||||
g_array_unref (selection->source_targets);
|
g_array_unref (selection->source_targets);
|
||||||
|
|
||||||
g_hash_table_destroy (selection->offers);
|
g_hash_table_destroy (selection->offers);
|
||||||
@ -456,16 +470,16 @@ static const struct gtk_primary_selection_offer_listener primary_offer_listener
|
|||||||
primary_offer_offer,
|
primary_offer_offer,
|
||||||
};
|
};
|
||||||
|
|
||||||
DataOfferData *
|
SelectionData *
|
||||||
selection_lookup_offer_by_atom (GdkWaylandSelection *selection,
|
selection_lookup_offer_by_atom (GdkWaylandSelection *selection,
|
||||||
GdkAtom selection_atom)
|
GdkAtom selection_atom)
|
||||||
{
|
{
|
||||||
if (selection_atom == atoms[ATOM_PRIMARY])
|
if (selection_atom == atoms[ATOM_PRIMARY])
|
||||||
return selection->primary_offer;
|
return &selection->selections[ATOM_PRIMARY];
|
||||||
else if (selection_atom == atoms[ATOM_CLIPBOARD])
|
else if (selection_atom == atoms[ATOM_CLIPBOARD])
|
||||||
return selection->clipboard_offer;
|
return &selection->selections[ATOM_CLIPBOARD];
|
||||||
else if (selection_atom == atoms[ATOM_DND])
|
else if (selection_atom == atoms[ATOM_DND])
|
||||||
return selection->dnd_offer;
|
return &selection->selections[ATOM_DND];
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -517,6 +531,7 @@ gdk_wayland_selection_set_offer (GdkDisplay *display,
|
|||||||
{
|
{
|
||||||
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
|
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
|
||||||
struct wl_data_offer *prev_offer;
|
struct wl_data_offer *prev_offer;
|
||||||
|
SelectionData *selection_data;
|
||||||
DataOfferData *info;
|
DataOfferData *info;
|
||||||
|
|
||||||
info = g_hash_table_lookup (selection->offers, wl_offer);
|
info = g_hash_table_lookup (selection->offers, wl_offer);
|
||||||
@ -526,15 +541,14 @@ gdk_wayland_selection_set_offer (GdkDisplay *display,
|
|||||||
if (prev_offer)
|
if (prev_offer)
|
||||||
g_hash_table_remove (selection->offers, prev_offer);
|
g_hash_table_remove (selection->offers, prev_offer);
|
||||||
|
|
||||||
if (selection_atom == atoms[ATOM_PRIMARY])
|
selection_data = selection_lookup_offer_by_atom (selection, selection_atom);
|
||||||
selection->primary_offer = info;
|
|
||||||
else if (selection_atom == atoms[ATOM_CLIPBOARD])
|
|
||||||
selection->clipboard_offer = info;
|
|
||||||
else if (selection_atom == atoms[ATOM_DND])
|
|
||||||
selection->dnd_offer = info;
|
|
||||||
|
|
||||||
/* Clear all buffers */
|
if (selection_data)
|
||||||
g_hash_table_remove_all (selection->selection_buffers);
|
{
|
||||||
|
selection_data->offer = info;
|
||||||
|
/* Clear all buffers */
|
||||||
|
g_hash_table_remove_all (selection_data->buffers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gpointer
|
gpointer
|
||||||
@ -542,12 +556,12 @@ gdk_wayland_selection_get_offer (GdkDisplay *display,
|
|||||||
GdkAtom selection_atom)
|
GdkAtom selection_atom)
|
||||||
{
|
{
|
||||||
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
|
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
|
||||||
const DataOfferData *info;
|
const SelectionData *data;
|
||||||
|
|
||||||
info = selection_lookup_offer_by_atom (selection, selection_atom);
|
data = selection_lookup_offer_by_atom (selection, selection_atom);
|
||||||
|
|
||||||
if (info)
|
if (data && data->offer)
|
||||||
return info->offer_data;
|
return data->offer->offer_data;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -557,12 +571,12 @@ gdk_wayland_selection_get_targets (GdkDisplay *display,
|
|||||||
GdkAtom selection_atom)
|
GdkAtom selection_atom)
|
||||||
{
|
{
|
||||||
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
|
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
|
||||||
const DataOfferData *info;
|
const SelectionData *data;
|
||||||
|
|
||||||
info = selection_lookup_offer_by_atom (selection, selection_atom);
|
data = selection_lookup_offer_by_atom (selection, selection_atom);
|
||||||
|
|
||||||
if (info)
|
if (data && data->offer)
|
||||||
return info->targets;
|
return data->offer->targets;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -749,13 +763,17 @@ gdk_wayland_selection_lookup_requestor_buffer (GdkWindow *requestor)
|
|||||||
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
|
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
|
||||||
SelectionBuffer *buffer_data;
|
SelectionBuffer *buffer_data;
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
|
gint i;
|
||||||
|
|
||||||
g_hash_table_iter_init (&iter, selection->selection_buffers);
|
for (i = 0; i < G_N_ELEMENTS (selection->selections); i++)
|
||||||
|
|
||||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &buffer_data))
|
|
||||||
{
|
{
|
||||||
if (g_list_find (buffer_data->requestors, requestor))
|
g_hash_table_iter_init (&iter, selection->selections[i].buffers);
|
||||||
return buffer_data;
|
|
||||||
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &buffer_data))
|
||||||
|
{
|
||||||
|
if (g_list_find (buffer_data->requestors, requestor))
|
||||||
|
return buffer_data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1255,11 +1273,16 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
|
|||||||
guint32 time)
|
guint32 time)
|
||||||
{
|
{
|
||||||
GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
|
GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
|
||||||
|
const SelectionData *selection_data;
|
||||||
SelectionBuffer *buffer_data;
|
SelectionBuffer *buffer_data;
|
||||||
gpointer offer;
|
gpointer offer;
|
||||||
gchar *mimetype;
|
gchar *mimetype;
|
||||||
GList *target_list;
|
GList *target_list;
|
||||||
|
|
||||||
|
selection_data = selection_lookup_offer_by_atom (wayland_selection, selection);
|
||||||
|
if (!selection_data)
|
||||||
|
return;
|
||||||
|
|
||||||
offer = gdk_wayland_selection_get_offer (display, selection);
|
offer = gdk_wayland_selection_get_offer (display, selection);
|
||||||
target_list = gdk_wayland_selection_get_targets (display, selection);
|
target_list = gdk_wayland_selection_get_targets (display, selection);
|
||||||
|
|
||||||
@ -1285,8 +1308,7 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
|
|||||||
mimetype);
|
mimetype);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_data = g_hash_table_lookup (wayland_selection->selection_buffers,
|
buffer_data = g_hash_table_lookup (selection_data->buffers, target);
|
||||||
target);
|
|
||||||
|
|
||||||
if (buffer_data)
|
if (buffer_data)
|
||||||
selection_buffer_add_requestor (buffer_data, requestor);
|
selection_buffer_add_requestor (buffer_data, requestor);
|
||||||
@ -1333,7 +1355,7 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
|
|||||||
g_free (targets);
|
g_free (targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_hash_table_insert (wayland_selection->selection_buffers,
|
g_hash_table_insert (selection_data->buffers,
|
||||||
GDK_ATOM_TO_POINTER (target),
|
GDK_ATOM_TO_POINTER (target),
|
||||||
buffer_data);
|
buffer_data);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user