wayland: Implement the (so far internal) primary selection protocol

Implement it using the internal copy of the protocol. Otherwise,
we just deal with it the same than clipboard selection, just mapping
it to the PRIMARY atom instead of the CLIPBOARD one.

https://bugzilla.gnome.org/show_bug.cgi?id=762561
This commit is contained in:
Carlos Garnacho
2016-02-04 17:33:51 +01:00
parent f9f5586714
commit ed3c87df7a
5 changed files with 315 additions and 60 deletions

View File

@ -96,7 +96,6 @@ struct _GdkWaylandSeat
GdkWindow *pointer_focus; GdkWindow *pointer_focus;
GdkWindow *keyboard_focus; GdkWindow *keyboard_focus;
GdkAtom pending_selection; GdkAtom pending_selection;
struct wl_data_device *data_device;
double surface_x, surface_y; double surface_x, surface_y;
uint32_t time; uint32_t time;
uint32_t enter_serial; uint32_t enter_serial;
@ -115,6 +114,8 @@ struct _GdkWaylandSeat
guint cursor_image_index; guint cursor_image_index;
guint cursor_image_delay; guint cursor_image_delay;
struct gtk_primary_selection_device *primary_data_device;
struct wl_data_device *data_device;
GdkDragContext *drop_context; GdkDragContext *drop_context;
struct wl_surface *pointer_surface; struct wl_surface *pointer_surface;
@ -926,6 +927,42 @@ static const struct wl_data_device_listener data_device_listener = {
data_device_selection data_device_selection
}; };
static void
primary_selection_data_offer (void *data,
struct gtk_primary_selection_device *gtk_primary_selection_device,
struct gtk_primary_selection_offer *gtk_primary_offer)
{
GdkWaylandDeviceData *device = (GdkWaylandDeviceData *) data;
GDK_NOTE (EVENTS,
g_message ("primary selection offer, device %p, data offer %p",
gtk_primary_selection_device, gtk_primary_offer));
gdk_wayland_selection_ensure_primary_offer (device->display, gtk_primary_offer);
}
static void
primary_selection_selection (void *data,
struct gtk_primary_selection_device *gtk_primary_selection_device,
struct gtk_primary_selection_offer *gtk_primary_offer)
{
GdkWaylandDeviceData *device = (GdkWaylandDeviceData *) data;
GdkAtom selection;
GDK_NOTE (EVENTS,
g_message ("primary selection selection, device %p, data offer %p",
gtk_primary_selection_device, gtk_primary_offer));
selection = gdk_atom_intern_static_string ("PRIMARY");
gdk_wayland_selection_set_offer (device->display, selection, gtk_primary_offer);
emit_selection_owner_change (device->keyboard_focus, selection);
}
static const struct gtk_primary_selection_device_listener primary_selection_device_listener = {
primary_selection_data_offer,
primary_selection_selection,
};
static GdkEvent * static GdkEvent *
create_scroll_event (GdkWaylandSeat *seat, create_scroll_event (GdkWaylandSeat *seat,
gboolean emulated) gboolean emulated)
@ -2883,6 +2920,12 @@ _gdk_wayland_device_manager_add_seat (GdkDeviceManager *device_manager,
wl_seat_add_listener (seat->wl_seat, &seat_listener, seat); wl_seat_add_listener (seat->wl_seat, &seat_listener, seat);
wl_seat_set_user_data (seat->wl_seat, seat); wl_seat_set_user_data (seat->wl_seat, seat);
seat->primary_data_device =
gtk_primary_selection_device_manager_get_device (display_wayland->primary_selection_manager,
seat->wl_seat);
gtk_primary_selection_device_add_listener (seat->primary_data_device,
&primary_selection_device_listener, seat);
seat->data_device = seat->data_device =
wl_data_device_manager_get_data_device (display_wayland->data_device_manager, wl_data_device_manager_get_data_device (display_wayland->data_device_manager,
seat->wl_seat); seat->wl_seat);
@ -3118,6 +3161,23 @@ gdk_wayland_device_set_selection (GdkDevice *gdk_device,
_gdk_wayland_display_get_serial (display_wayland)); _gdk_wayland_display_get_serial (display_wayland));
} }
void
gdk_wayland_seat_set_primary (GdkSeat *seat,
struct gtk_primary_selection_source *source)
{
GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
GdkWaylandDisplay *display_wayland;
guint32 serial;
if (source)
{
display_wayland = GDK_WAYLAND_DISPLAY (gdk_seat_get_display (seat));
serial = _gdk_wayland_display_get_serial (display_wayland);
gtk_primary_selection_device_set_selection (wayland_seat->primary_data_device,
source, serial);
}
}
struct wl_seat * struct wl_seat *
gdk_wayland_seat_get_wl_seat (GdkSeat *seat) gdk_wayland_seat_get_wl_seat (GdkSeat *seat)
{ {

View File

@ -335,6 +335,12 @@ gdk_registry_handle_global (void *data,
wl_registry_bind (display_wayland->wl_registry, wl_registry_bind (display_wayland->wl_registry,
id, &zwp_pointer_gestures_v1_interface, version); id, &zwp_pointer_gestures_v1_interface, version);
} }
else if (strcmp (interface, "gtk_primary_selection_device_manager") == 0)
{
display_wayland->primary_selection_manager =
wl_registry_bind(display_wayland->wl_registry, id,
&gtk_primary_selection_device_manager_interface, 1);
}
else else
handled = FALSE; handled = FALSE;

View File

@ -74,6 +74,7 @@ struct _GdkWaylandDisplay
struct wl_data_device_manager *data_device_manager; struct wl_data_device_manager *data_device_manager;
struct wl_subcompositor *subcompositor; struct wl_subcompositor *subcompositor;
struct zwp_pointer_gestures_v1 *pointer_gestures; struct zwp_pointer_gestures_v1 *pointer_gestures;
struct gtk_primary_selection_device_manager *primary_selection_manager;
GList *async_roundtrips; GList *async_roundtrips;

View File

@ -37,6 +37,7 @@
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include "gdkinternals.h" #include "gdkinternals.h"
#include "gtk-primary-selection-client-protocol.h"
#include "config.h" #include "config.h"
@ -190,6 +191,9 @@ struct wl_data_device * gdk_wayland_device_get_data_device (GdkDevice *gdk_devic
void gdk_wayland_device_set_selection (GdkDevice *gdk_device, void gdk_wayland_device_set_selection (GdkDevice *gdk_device,
struct wl_data_source *source); struct wl_data_source *source);
void gdk_wayland_seat_set_primary (GdkSeat *seat,
struct gtk_primary_selection_source *source);
GdkDragContext * gdk_wayland_device_get_drop_context (GdkDevice *gdk_device); GdkDragContext * gdk_wayland_device_get_drop_context (GdkDevice *gdk_device);
void gdk_wayland_device_unset_touch_grab (GdkDevice *device, void gdk_wayland_device_unset_touch_grab (GdkDevice *device,
@ -242,11 +246,14 @@ void gdk_wayland_selection_free (GdkWaylandSelection *selection);
void gdk_wayland_selection_ensure_offer (GdkDisplay *display, void gdk_wayland_selection_ensure_offer (GdkDisplay *display,
struct wl_data_offer *wl_offer); struct wl_data_offer *wl_offer);
void gdk_wayland_selection_ensure_primary_offer (GdkDisplay *display,
struct gtk_primary_selection_offer *wp_offer);
void gdk_wayland_selection_set_offer (GdkDisplay *display, void gdk_wayland_selection_set_offer (GdkDisplay *display,
GdkAtom selection, GdkAtom selection,
struct wl_data_offer *wl_offer); gpointer offer);
struct wl_data_offer * gdk_wayland_selection_get_offer (GdkDisplay *display, gpointer gdk_wayland_selection_get_offer (GdkDisplay *display,
GdkAtom selection); GdkAtom selection);
GList * gdk_wayland_selection_get_targets (GdkDisplay *display, GList * gdk_wayland_selection_get_targets (GdkDisplay *display,
GdkAtom selection); GdkAtom selection);

View File

@ -67,7 +67,8 @@ struct _DataSourceData
struct _DataOfferData struct _DataOfferData
{ {
struct wl_data_offer *offer; GDestroyNotify destroy_notify;
gpointer offer_data;
GList *targets; /* List of GdkAtom */ GList *targets; /* List of GdkAtom */
}; };
@ -79,17 +80,19 @@ struct _AsyncWriteData
}; };
enum { enum {
ATOM_PRIMARY,
ATOM_CLIPBOARD, ATOM_CLIPBOARD,
ATOM_DND ATOM_DND
}; };
static GdkAtom atoms[2] = { 0 }; static GdkAtom atoms[3] = { 0 };
struct _GdkWaylandSelection struct _GdkWaylandSelection
{ {
/* Destination-side data */ /* Destination-side data */
DataOfferData *dnd_offer; DataOfferData *dnd_offer;
DataOfferData *clipboard_offer; 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 */ GHashTable *selection_buffers; /* Hashtable of target_atom->SelectionBuffer */
@ -98,6 +101,9 @@ struct _GdkWaylandSelection
GArray *source_targets; GArray *source_targets;
GdkAtom requested_target; GdkAtom requested_target;
struct gtk_primary_selection_source *primary_source;
GdkWindow *primary_owner;
struct wl_data_source *clipboard_source; struct wl_data_source *clipboard_source;
GdkWindow *clipboard_owner; GdkWindow *clipboard_owner;
@ -268,12 +274,14 @@ selection_buffer_read (SelectionBuffer *buffer)
} }
static DataOfferData * static DataOfferData *
data_offer_data_new (struct wl_data_offer *offer) data_offer_data_new (gpointer offer,
GDestroyNotify destroy_notify)
{ {
DataOfferData *info; DataOfferData *info;
info = g_slice_new0 (DataOfferData); info = g_slice_new0 (DataOfferData);
info->offer = offer; info->offer_data = offer;
info->destroy_notify = destroy_notify;
return info; return info;
} }
@ -281,7 +289,7 @@ data_offer_data_new (struct wl_data_offer *offer)
static void static void
data_offer_data_free (DataOfferData *info) data_offer_data_free (DataOfferData *info)
{ {
wl_data_offer_destroy (info->offer); info->destroy_notify (info->offer_data);
g_list_free (info->targets); g_list_free (info->targets);
g_slice_free (DataOfferData, info); g_slice_free (DataOfferData, info);
} }
@ -292,6 +300,7 @@ gdk_wayland_selection_new (void)
GdkWaylandSelection *selection; GdkWaylandSelection *selection;
/* init atoms */ /* init atoms */
atoms[ATOM_PRIMARY] = gdk_atom_intern_static_string ("PRIMARY");
atoms[ATOM_CLIPBOARD] = gdk_atom_intern_static_string ("CLIPBOARD"); atoms[ATOM_CLIPBOARD] = gdk_atom_intern_static_string ("CLIPBOARD");
atoms[ATOM_DND] = gdk_atom_intern_static_string ("GdkWaylandSelection"); atoms[ATOM_DND] = gdk_atom_intern_static_string ("GdkWaylandSelection");
@ -325,6 +334,8 @@ gdk_wayland_selection_free (GdkWaylandSelection *selection)
if (selection->stored_selection.fd > 0) if (selection->stored_selection.fd > 0)
close (selection->stored_selection.fd); close (selection->stored_selection.fd);
if (selection->primary_source)
gtk_primary_selection_source_destroy (selection->primary_source);
if (selection->clipboard_source) if (selection->clipboard_source)
wl_data_source_destroy (selection->clipboard_source); wl_data_source_destroy (selection->clipboard_source);
if (selection->dnd_source) if (selection->dnd_source)
@ -415,11 +426,34 @@ static const struct wl_data_offer_listener data_offer_listener = {
data_offer_action data_offer_action
}; };
static void
primary_offer_offer (void *data,
struct gtk_primary_selection_offer *gtk_offer,
const char *type)
{
GdkWaylandSelection *selection = data;
DataOfferData *info;
GdkAtom atom = gdk_atom_intern (type, FALSE);
info = g_hash_table_lookup (selection->offers, gtk_offer);
if (!info || g_list_find (info->targets, atom))
return;
info->targets = g_list_prepend (info->targets, atom);
}
static const struct gtk_primary_selection_offer_listener primary_offer_listener = {
primary_offer_offer,
};
DataOfferData * DataOfferData *
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_CLIPBOARD]) if (selection_atom == atoms[ATOM_PRIMARY])
return selection->primary_offer;
else if (selection_atom == atoms[ATOM_CLIPBOARD])
return selection->clipboard_offer; return selection->clipboard_offer;
else if (selection_atom == atoms[ATOM_DND]) else if (selection_atom == atoms[ATOM_DND])
return selection->dnd_offer; return selection->dnd_offer;
@ -438,7 +472,8 @@ gdk_wayland_selection_ensure_offer (GdkDisplay *display,
if (!info) if (!info)
{ {
info = data_offer_data_new (wl_offer); info = data_offer_data_new (wl_offer,
(GDestroyNotify) wl_data_offer_destroy);
g_hash_table_insert (selection->offers, wl_offer, info); g_hash_table_insert (selection->offers, wl_offer, info);
wl_data_offer_add_listener (wl_offer, wl_data_offer_add_listener (wl_offer,
&data_offer_listener, &data_offer_listener,
@ -447,9 +482,29 @@ gdk_wayland_selection_ensure_offer (GdkDisplay *display,
} }
void void
gdk_wayland_selection_set_offer (GdkDisplay *display, gdk_wayland_selection_ensure_primary_offer (GdkDisplay *display,
GdkAtom selection_atom, struct gtk_primary_selection_offer *gtk_offer)
struct wl_data_offer *wl_offer) {
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
DataOfferData *info;
info = g_hash_table_lookup (selection->offers, gtk_offer);
if (!info)
{
info = data_offer_data_new (gtk_offer,
(GDestroyNotify) gtk_primary_selection_offer_destroy);
g_hash_table_insert (selection->offers, gtk_offer, info);
gtk_primary_selection_offer_add_listener (gtk_offer,
&primary_offer_listener,
selection);
}
}
void
gdk_wayland_selection_set_offer (GdkDisplay *display,
GdkAtom selection_atom,
gpointer wl_offer)
{ {
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;
@ -462,7 +517,9 @@ 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_CLIPBOARD]) if (selection_atom == atoms[ATOM_PRIMARY])
selection->primary_offer = info;
else if (selection_atom == atoms[ATOM_CLIPBOARD])
selection->clipboard_offer = info; selection->clipboard_offer = info;
else if (selection_atom == atoms[ATOM_DND]) else if (selection_atom == atoms[ATOM_DND])
selection->dnd_offer = info; selection->dnd_offer = info;
@ -471,7 +528,7 @@ gdk_wayland_selection_set_offer (GdkDisplay *display,
g_hash_table_remove_all (selection->selection_buffers); g_hash_table_remove_all (selection->selection_buffers);
} }
struct wl_data_offer * gpointer
gdk_wayland_selection_get_offer (GdkDisplay *display, gdk_wayland_selection_get_offer (GdkDisplay *display,
GdkAtom selection_atom) GdkAtom selection_atom)
{ {
@ -481,7 +538,7 @@ gdk_wayland_selection_get_offer (GdkDisplay *display,
info = selection_lookup_offer_by_atom (selection, selection_atom); info = selection_lookup_offer_by_atom (selection, selection_atom);
if (info) if (info)
return info->offer; return info->offer_data;
return NULL; return NULL;
} }
@ -718,18 +775,10 @@ gdk_wayland_selection_source_handles_target (GdkWaylandSelection *wayland_select
static gboolean static gboolean
gdk_wayland_selection_request_target (GdkWaylandSelection *wayland_selection, gdk_wayland_selection_request_target (GdkWaylandSelection *wayland_selection,
GdkWindow *window, GdkWindow *window,
GdkAtom selection,
GdkAtom target, GdkAtom target,
gint fd) gint fd)
{ {
GdkAtom selection;
if (wayland_selection->clipboard_owner == window)
selection = atoms[ATOM_CLIPBOARD];
else if (wayland_selection->dnd_owner == window)
selection = atoms[ATOM_DND];
else
return FALSE;
if (wayland_selection->stored_selection.fd == fd && if (wayland_selection->stored_selection.fd == fd &&
wayland_selection->requested_target == target) wayland_selection->requested_target == target)
return FALSE; return FALSE;
@ -766,6 +815,7 @@ data_source_target (void *data,
{ {
GdkWaylandSelection *wayland_selection = data; GdkWaylandSelection *wayland_selection = data;
GdkWindow *window = NULL; GdkWindow *window = NULL;
GdkAtom selection;
g_debug (G_STRLOC ": %s source = %p, mime_type = %s", g_debug (G_STRLOC ": %s source = %p, mime_type = %s",
G_STRFUNC, source, mime_type); G_STRFUNC, source, mime_type);
@ -774,14 +824,21 @@ data_source_target (void *data,
return; return;
if (source == wayland_selection->dnd_source) if (source == wayland_selection->dnd_source)
window = wayland_selection->dnd_owner; {
selection = atoms[ATOM_DND];
window = wayland_selection->dnd_owner;
}
else if (source == wayland_selection->clipboard_source) else if (source == wayland_selection->clipboard_source)
window = wayland_selection->clipboard_owner; {
selection = atoms[ATOM_CLIPBOARD];
window = wayland_selection->clipboard_owner;
}
if (!window) if (!window)
return; return;
gdk_wayland_selection_request_target (wayland_selection, window, gdk_wayland_selection_request_target (wayland_selection, window,
selection,
gdk_atom_intern (mime_type, FALSE), gdk_atom_intern (mime_type, FALSE),
-1); -1);
} }
@ -794,6 +851,7 @@ data_source_send (void *data,
{ {
GdkWaylandSelection *wayland_selection = data; GdkWaylandSelection *wayland_selection = data;
GdkWindow *window; GdkWindow *window;
GdkAtom selection;
g_debug (G_STRLOC ": %s source = %p, mime_type = %s, fd = %d", g_debug (G_STRLOC ": %s source = %p, mime_type = %s, fd = %d",
G_STRFUNC, source, mime_type, fd); G_STRFUNC, source, mime_type, fd);
@ -805,9 +863,15 @@ data_source_send (void *data,
} }
if (source == wayland_selection->dnd_source) if (source == wayland_selection->dnd_source)
window = wayland_selection->dnd_owner; {
window = wayland_selection->dnd_owner;
selection = atoms[ATOM_DND];
}
else if (source == wayland_selection->clipboard_source) else if (source == wayland_selection->clipboard_source)
window = wayland_selection->clipboard_owner; {
window = wayland_selection->clipboard_owner;
selection = atoms[ATOM_CLIPBOARD];
}
else else
{ {
close (fd); close (fd);
@ -818,6 +882,7 @@ data_source_send (void *data,
return; return;
if (!gdk_wayland_selection_request_target (wayland_selection, window, if (!gdk_wayland_selection_request_target (wayland_selection, window,
selection,
gdk_atom_intern (mime_type, FALSE), gdk_atom_intern (mime_type, FALSE),
fd)) fd))
gdk_wayland_selection_check_write (wayland_selection); gdk_wayland_selection_check_write (wayland_selection);
@ -919,15 +984,61 @@ static const struct wl_data_source_listener data_source_listener = {
data_source_action, data_source_action,
}; };
static void
primary_source_send (void *data,
struct gtk_primary_selection_source *source,
const char *mime_type,
int32_t fd)
{
GdkWaylandSelection *wayland_selection = data;
g_debug (G_STRLOC ": %s source = %p, mime_type = %s, fd = %d",
G_STRFUNC, source, mime_type, fd);
if (!mime_type || !wayland_selection->primary_owner)
{
close (fd);
return;
}
if (!gdk_wayland_selection_request_target (wayland_selection,
wayland_selection->primary_owner,
atoms[ATOM_PRIMARY],
gdk_atom_intern (mime_type, FALSE),
fd))
gdk_wayland_selection_check_write (wayland_selection);
}
static void
primary_source_cancelled (void *data,
struct gtk_primary_selection_source *source)
{
GdkDisplay *display;
GdkAtom atom;
g_debug (G_STRLOC ": %s source = %p",
G_STRFUNC, source);
display = gdk_display_get_default ();
atom = atoms[ATOM_PRIMARY];
gdk_selection_owner_set (NULL, atom, GDK_CURRENT_TIME, TRUE);
gdk_wayland_selection_unset_data_source (display, atom);
}
static const struct gtk_primary_selection_source_listener primary_source_listener = {
primary_source_send,
primary_source_cancelled,
};
struct wl_data_source * struct wl_data_source *
gdk_wayland_selection_get_data_source (GdkWindow *owner, gdk_wayland_selection_get_data_source (GdkWindow *owner,
GdkAtom selection) GdkAtom selection)
{ {
GdkDisplay *display = gdk_window_get_display (owner); GdkDisplay *display = gdk_window_get_display (owner);
GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display); GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
struct wl_data_source *source = NULL; gpointer source = NULL;
GdkWaylandDisplay *display_wayland; GdkWaylandDisplay *display_wayland;
gboolean is_clipboard = FALSE;
if (selection == atoms[ATOM_DND]) if (selection == atoms[ATOM_DND])
{ {
@ -935,6 +1046,18 @@ gdk_wayland_selection_get_data_source (GdkWindow *owner,
(!owner || owner == wayland_selection->dnd_owner)) (!owner || owner == wayland_selection->dnd_owner))
return wayland_selection->dnd_source; return wayland_selection->dnd_source;
} }
else if (selection == atoms[ATOM_PRIMARY])
{
if (wayland_selection->primary_source &&
(!owner || owner == wayland_selection->primary_owner))
return (gpointer) wayland_selection->primary_source;
if (wayland_selection->primary_source)
{
gtk_primary_selection_source_destroy (wayland_selection->primary_source);
wayland_selection->primary_source = NULL;
}
}
else if (selection == atoms[ATOM_CLIPBOARD]) else if (selection == atoms[ATOM_CLIPBOARD])
{ {
if (wayland_selection->clipboard_source && if (wayland_selection->clipboard_source &&
@ -946,8 +1069,6 @@ gdk_wayland_selection_get_data_source (GdkWindow *owner,
wl_data_source_destroy (wayland_selection->clipboard_source); wl_data_source_destroy (wayland_selection->clipboard_source);
wayland_selection->clipboard_source = NULL; wayland_selection->clipboard_source = NULL;
} }
is_clipboard = TRUE;
} }
else else
return NULL; return NULL;
@ -957,15 +1078,27 @@ gdk_wayland_selection_get_data_source (GdkWindow *owner,
display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (owner)); display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (owner));
source = wl_data_device_manager_create_data_source (display_wayland->data_device_manager); if (selection == atoms[ATOM_PRIMARY])
wl_data_source_add_listener (source, {
&data_source_listener, source = gtk_primary_selection_device_manager_create_source (display_wayland->primary_selection_manager);
wayland_selection); gtk_primary_selection_source_add_listener (source,
&primary_source_listener,
if (is_clipboard) wayland_selection);
wayland_selection->clipboard_source = source; }
else else
{
source = wl_data_device_manager_create_data_source (display_wayland->data_device_manager);
wl_data_source_add_listener (source,
&data_source_listener,
wayland_selection);
}
if (selection == atoms[ATOM_DND])
wayland_selection->dnd_source = source; wayland_selection->dnd_source = source;
else if (selection == atoms[ATOM_PRIMARY])
wayland_selection->primary_source = source;
else if (selection == atoms[ATOM_CLIPBOARD])
wayland_selection->clipboard_source = source;
return source; return source;
} }
@ -990,6 +1123,18 @@ gdk_wayland_selection_unset_data_source (GdkDisplay *display,
wayland_selection->clipboard_source = NULL; wayland_selection->clipboard_source = NULL;
} }
} }
else if (selection == atoms[ATOM_PRIMARY])
{
GdkSeat *seat = gdk_display_get_default_seat (display);
gdk_wayland_seat_set_primary (seat, NULL);
if (wayland_selection->primary_source)
{
gtk_primary_selection_source_destroy (wayland_selection->primary_source);
wayland_selection->primary_source = NULL;
}
}
else if (selection == atoms[ATOM_DND]) else if (selection == atoms[ATOM_DND])
{ {
wayland_selection->dnd_source = NULL; wayland_selection->dnd_source = NULL;
@ -1004,6 +1149,8 @@ _gdk_wayland_display_get_selection_owner (GdkDisplay *display,
if (selection == atoms[ATOM_CLIPBOARD]) if (selection == atoms[ATOM_CLIPBOARD])
return wayland_selection->clipboard_owner; return wayland_selection->clipboard_owner;
else if (selection == atoms[ATOM_PRIMARY])
return wayland_selection->primary_owner;
else if (selection == atoms[ATOM_DND]) else if (selection == atoms[ATOM_DND])
return wayland_selection->dnd_owner; return wayland_selection->dnd_owner;
@ -1024,6 +1171,11 @@ _gdk_wayland_display_set_selection_owner (GdkDisplay *display,
wayland_selection->clipboard_owner = owner; wayland_selection->clipboard_owner = owner;
return TRUE; return TRUE;
} }
else if (selection == atoms[ATOM_PRIMARY])
{
wayland_selection->primary_owner = owner;
return TRUE;
}
else if (selection == atoms[ATOM_DND]) else if (selection == atoms[ATOM_DND])
{ {
wayland_selection->dnd_owner = owner; wayland_selection->dnd_owner = owner;
@ -1088,6 +1240,26 @@ _gdk_wayland_display_get_selection_property (GdkDisplay *display,
return len; return len;
} }
static void
emit_empty_selection_notify (GdkWindow *requestor,
GdkAtom selection,
GdkAtom target)
{
GdkEvent *event;
event = gdk_event_new (GDK_SELECTION_NOTIFY);
event->selection.window = g_object_ref (requestor);
event->selection.send_event = FALSE;
event->selection.selection = selection;
event->selection.target = target;
event->selection.property = GDK_NONE;
event->selection.time = GDK_CURRENT_TIME;
event->selection.requestor = g_object_ref (requestor);
gdk_event_put (event);
gdk_event_free (event);
}
void void
_gdk_wayland_display_convert_selection (GdkDisplay *display, _gdk_wayland_display_convert_selection (GdkDisplay *display,
GdkWindow *requestor, GdkWindow *requestor,
@ -1097,7 +1269,7 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
{ {
GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display); GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
SelectionBuffer *buffer_data; SelectionBuffer *buffer_data;
struct wl_data_offer *offer; gpointer offer;
gchar *mimetype; gchar *mimetype;
GList *target_list; GList *target_list;
@ -1106,28 +1278,25 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
if (!offer || target == gdk_atom_intern_static_string ("DELETE")) if (!offer || target == gdk_atom_intern_static_string ("DELETE"))
{ {
GdkEvent *event; emit_empty_selection_notify (requestor, selection, target);
event = gdk_event_new (GDK_SELECTION_NOTIFY);
event->selection.window = g_object_ref (requestor);
event->selection.send_event = FALSE;
event->selection.selection = selection;
event->selection.target = target;
event->selection.property = GDK_NONE;
event->selection.time = GDK_CURRENT_TIME;
event->selection.requestor = g_object_ref (requestor);
gdk_event_put (event);
gdk_event_free (event);
return; return;
} }
mimetype = gdk_atom_name (target); mimetype = gdk_atom_name (target);
if (target != gdk_atom_intern_static_string ("TARGETS")) if (target != gdk_atom_intern_static_string ("TARGETS"))
wl_data_offer_accept (offer, {
_gdk_wayland_display_get_serial (GDK_WAYLAND_DISPLAY (display)), if (!g_list_find (target_list, GDK_ATOM_TO_POINTER (target)))
mimetype); {
emit_empty_selection_notify (requestor, selection, target);
return;
}
if (selection != atoms[ATOM_PRIMARY])
wl_data_offer_accept (offer,
_gdk_wayland_display_get_serial (GDK_WAYLAND_DISPLAY (display)),
mimetype);
}
buffer_data = g_hash_table_lookup (wayland_selection->selection_buffers, buffer_data = g_hash_table_lookup (wayland_selection->selection_buffers,
target); target);
@ -1154,7 +1323,12 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
else else
{ {
g_unix_open_pipe (pipe_fd, FD_CLOEXEC, NULL); g_unix_open_pipe (pipe_fd, FD_CLOEXEC, NULL);
wl_data_offer_receive (offer, mimetype, pipe_fd[1]);
if (selection == atoms[ATOM_PRIMARY])
gtk_primary_selection_offer_receive (offer, mimetype, pipe_fd[1]);
else
wl_data_offer_receive (offer, mimetype, pipe_fd[1]);
stream = g_unix_input_stream_new (pipe_fd[0], TRUE); stream = g_unix_input_stream_new (pipe_fd[0], TRUE);
close (pipe_fd[1]); close (pipe_fd[1]);
} }
@ -1239,7 +1413,7 @@ gdk_wayland_selection_add_targets (GdkWindow *window,
{ {
GdkDisplay *display = gdk_window_get_display (window); GdkDisplay *display = gdk_window_get_display (window);
GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display); GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
struct wl_data_source *data_source; gpointer data_source;
guint i; guint i;
g_return_if_fail (GDK_IS_WINDOW (window)); g_return_if_fail (GDK_IS_WINDOW (window));
@ -1268,6 +1442,13 @@ gdk_wayland_selection_add_targets (GdkWindow *window,
device = gdk_seat_get_pointer (gdk_display_get_default_seat (display)); device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
gdk_wayland_device_set_selection (device, data_source); gdk_wayland_device_set_selection (device, data_source);
} }
else if (selection == atoms[ATOM_PRIMARY])
{
GdkSeat *seat;
seat = gdk_display_get_default_seat (display);
gdk_wayland_seat_set_primary (seat, data_source);
}
} }
void void