diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2016-02-04 17:33:51 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2016-02-20 01:37:16 +0100 |
commit | 91f859b8dae190891fd367298055462862264fe0 (patch) | |
tree | c312d23f9bf1c8d0da442851e767fa9788978684 | |
parent | ebb175021e0e26374e4d1ab3c6d8429a1353a77d (diff) | |
download | gtk+-wip/wayland-primary-selection.tar.gz |
WIP: Implement primary selection protocolwip/wayland-primary-selection
-rw-r--r-- | gdk/wayland/Makefile.am | 2 | ||||
-rw-r--r-- | gdk/wayland/gdkdevice-wayland.c | 68 | ||||
-rw-r--r-- | gdk/wayland/gdkdisplay-wayland.c | 6 | ||||
-rw-r--r-- | gdk/wayland/gdkdisplay-wayland.h | 1 | ||||
-rw-r--r-- | gdk/wayland/gdkprivate-wayland.h | 17 | ||||
-rw-r--r-- | gdk/wayland/gdkselection-wayland.c | 320 | ||||
-rw-r--r-- | gdk/wayland/gdkwindow-wayland.c | 13 |
7 files changed, 348 insertions, 79 deletions
diff --git a/gdk/wayland/Makefile.am b/gdk/wayland/Makefile.am index a56c407c09..d155db292b 100644 --- a/gdk/wayland/Makefile.am +++ b/gdk/wayland/Makefile.am @@ -24,6 +24,8 @@ BUILT_SOURCES = \ pointer-gestures-unstable-v1-protocol.c \ xdg-shell-unstable-v5-client-protocol.h \ xdg-shell-unstable-v5-protocol.c \ + primary-selection-unstable-v1-client-protocol.h \ + primary-selection-unstable-v1-protocol.c \ gtk-shell-client-protocol.h \ gtk-shell-protocol.c diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index b8f92fef68..34e5759eea 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -96,7 +96,6 @@ struct _GdkWaylandSeat GdkWindow *pointer_focus; GdkWindow *keyboard_focus; GdkAtom pending_selection; - struct wl_data_device *data_device; double surface_x, surface_y; uint32_t time; uint32_t enter_serial; @@ -115,6 +114,8 @@ struct _GdkWaylandSeat guint cursor_image_index; guint cursor_image_delay; + struct zwp_primary_selection_device_v1 *primary_data_device; + struct wl_data_device *data_device; GdkDragContext *drop_context; struct wl_surface *pointer_surface; @@ -926,6 +927,42 @@ static const struct wl_data_device_listener data_device_listener = { data_device_selection }; +static void +primary_selection_data_offer (void *data, + struct zwp_primary_selection_device_v1 *wp_primary_selection_device, + struct zwp_primary_selection_offer_v1 *wp_primary_offer) +{ + GdkWaylandDeviceData *device = (GdkWaylandDeviceData *) data; + + GDK_NOTE (EVENTS, + g_message ("primary selection offer, device %p, data offer %p", + wp_primary_selection_device, wp_primary_offer)); + + gdk_wayland_selection_ensure_primary_offer (device->display, wp_primary_offer); +} + +static void +primary_selection_selection (void *data, + struct zwp_primary_selection_device_v1 *wp_primary_selection_device, + struct zwp_primary_selection_offer_v1 *wp_primary_offer) +{ + GdkWaylandDeviceData *device = (GdkWaylandDeviceData *) data; + GdkAtom selection; + + GDK_NOTE (EVENTS, + g_message ("primary selection selection, device %p, data offer %p", + wp_primary_selection_device, wp_primary_offer)); + + selection = gdk_atom_intern_static_string ("PRIMARY"); + gdk_wayland_selection_set_offer (device->display, selection, wp_primary_offer); + emit_selection_owner_change (device->keyboard_focus, selection); +} + +static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = { + primary_selection_data_offer, + primary_selection_selection, +}; + static GdkEvent * create_scroll_event (GdkWaylandSeat *seat, 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_set_user_data (seat->wl_seat, seat); + seat->primary_data_device = + zwp_primary_selection_device_manager_v1_get_device (display_wayland->primary_selection_manager, + seat->wl_seat); + zwp_primary_selection_device_v1_add_listener (seat->primary_data_device, + &primary_selection_device_listener, seat); + seat->data_device = wl_data_device_manager_get_data_device (display_wayland->data_device_manager, seat->wl_seat); @@ -3021,20 +3064,22 @@ _gdk_wayland_device_get_implicit_grab_serial (GdkWaylandDevice *device, } uint32_t -_gdk_wayland_device_get_last_implicit_grab_serial (GdkWaylandDevice *device, - GdkEventSequence **sequence) +_gdk_wayland_seat_get_last_implicit_grab_serial (GdkSeat *seat, + GdkEventSequence **sequence) { + GdkWaylandSeat *wayland_seat; GdkWaylandTouchData *touch; GHashTableIter iter; uint32_t serial = 0; - g_hash_table_iter_init (&iter, device->device->touches); + wayland_seat = GDK_WAYLAND_SEAT (seat); + g_hash_table_iter_init (&iter, wayland_seat->touches); if (sequence) *sequence = NULL; - if (device->device->button_press_serial > serial) - serial = device->device->button_press_serial; + if (wayland_seat->button_press_serial > serial) + serial = wayland_seat->button_press_serial; while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch)) { @@ -3116,6 +3161,17 @@ gdk_wayland_device_set_selection (GdkDevice *gdk_device, _gdk_wayland_display_get_serial (display_wayland)); } +void +gdk_wayland_seat_set_primary (GdkSeat *seat, + struct zwp_primary_selection_source_v1 *source) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + + if (source) + zwp_primary_selection_device_v1_set_selection (wayland_seat->primary_data_device, + source); +} + struct wl_seat * gdk_wayland_seat_get_wl_seat (GdkSeat *seat) { diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index d708385b61..dc2d879d72 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -335,6 +335,12 @@ gdk_registry_handle_global (void *data, wl_registry_bind (display_wayland->wl_registry, id, &zwp_pointer_gestures_v1_interface, version); } + else if (strcmp (interface, "zwp_primary_selection_device_manager_v1") == 0) + { + display_wayland->primary_selection_manager = + wl_registry_bind(display_wayland->wl_registry, id, + &zwp_primary_selection_device_manager_v1_interface, 1); + } else handled = FALSE; diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index 74b970fff9..c5eabfff42 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -74,6 +74,7 @@ struct _GdkWaylandDisplay struct wl_data_device_manager *data_device_manager; struct wl_subcompositor *subcompositor; struct zwp_pointer_gestures_v1 *pointer_gestures; + struct zwp_primary_selection_device_manager_v1 *primary_selection_manager; GList *async_roundtrips; diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h index 549851c82c..41a709a0b8 100644 --- a/gdk/wayland/gdkprivate-wayland.h +++ b/gdk/wayland/gdkprivate-wayland.h @@ -37,6 +37,7 @@ #include <xkbcommon/xkbcommon.h> #include "gdkinternals.h" +#include "primary-selection-unstable-v1-client-protocol.h" #include "config.h" @@ -184,12 +185,15 @@ void _gdk_wayland_device_manager_remove_seat (GdkDeviceManager *dev GdkKeymap *_gdk_wayland_device_get_keymap (GdkDevice *device); uint32_t _gdk_wayland_device_get_implicit_grab_serial(GdkWaylandDevice *device, const GdkEvent *event); -uint32_t _gdk_wayland_device_get_last_implicit_grab_serial (GdkWaylandDevice *device, - GdkEventSequence **seqence); +uint32_t _gdk_wayland_seat_get_last_implicit_grab_serial (GdkSeat *seat, + GdkEventSequence **seqence); 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); +void gdk_wayland_seat_set_primary (GdkSeat *seat, + struct zwp_primary_selection_source_v1 *source); + GdkDragContext * gdk_wayland_device_get_drop_context (GdkDevice *gdk_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, struct wl_data_offer *wl_offer); +void gdk_wayland_selection_ensure_primary_offer (GdkDisplay *display, + struct zwp_primary_selection_offer_v1 *wp_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, - GdkAtom selection); + gpointer offer); +gpointer gdk_wayland_selection_get_offer (GdkDisplay *display, + GdkAtom selection); GList * gdk_wayland_selection_get_targets (GdkDisplay *display, GdkAtom selection); diff --git a/gdk/wayland/gdkselection-wayland.c b/gdk/wayland/gdkselection-wayland.c index 5ed13aefb8..d2fa9470fc 100644 --- a/gdk/wayland/gdkselection-wayland.c +++ b/gdk/wayland/gdkselection-wayland.c @@ -33,6 +33,8 @@ #include <string.h> +#define READ_BUFFER_SIZE 1000 + typedef struct _SelectionBuffer SelectionBuffer; typedef struct _StoredSelection StoredSelection; typedef struct _AsyncWriteData AsyncWriteData; @@ -67,7 +69,8 @@ struct _DataSourceData struct _DataOfferData { - struct wl_data_offer *offer; + GDestroyNotify destroy_notify; + gpointer offer; GList *targets; /* List of GdkAtom */ }; @@ -79,17 +82,19 @@ struct _AsyncWriteData }; enum { + ATOM_PRIMARY, ATOM_CLIPBOARD, ATOM_DND }; -static GdkAtom atoms[2] = { 0 }; +static GdkAtom atoms[3] = { 0 }; struct _GdkWaylandSelection { /* Destination-side data */ DataOfferData *dnd_offer; DataOfferData *clipboard_offer; + DataOfferData *primary_offer; GHashTable *offers; /* Currently alive offers, Hashtable of wl_data_offer->DataOfferData */ GHashTable *selection_buffers; /* Hashtable of target_atom->SelectionBuffer */ @@ -98,6 +103,9 @@ struct _GdkWaylandSelection GArray *source_targets; GdkAtom requested_target; + struct zwp_primary_selection_source_v1 *primary_source; + GdkWindow *primary_owner; + struct wl_data_source *clipboard_source; GdkWindow *clipboard_owner; @@ -224,19 +232,23 @@ selection_buffer_read_cb (GObject *object, gpointer user_data) { SelectionBuffer *buffer = user_data; + gboolean finished = TRUE; GError *error = NULL; GBytes *bytes; bytes = g_input_stream_read_bytes_finish (buffer->stream, result, &error); - if (bytes && g_bytes_get_size (bytes) > 0) + if (bytes) { + finished = g_bytes_get_size (bytes) < READ_BUFFER_SIZE; selection_buffer_append_data (buffer, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes)); - selection_buffer_read (buffer); g_bytes_unref (bytes); } + + if (!finished) + selection_buffer_read (buffer); else { if (error) @@ -250,9 +262,6 @@ selection_buffer_read_cb (GObject *object, g_input_stream_close (buffer->stream, NULL, NULL); g_clear_object (&buffer->stream); g_clear_object (&buffer->cancellable); - - if (bytes) - g_bytes_unref (bytes); } selection_buffer_unref (buffer); @@ -262,18 +271,20 @@ static void selection_buffer_read (SelectionBuffer *buffer) { selection_buffer_ref (buffer); - g_input_stream_read_bytes_async (buffer->stream, 1000, G_PRIORITY_DEFAULT, + g_input_stream_read_bytes_async (buffer->stream, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, buffer->cancellable, selection_buffer_read_cb, buffer); } static DataOfferData * -data_offer_data_new (struct wl_data_offer *offer) +data_offer_data_new (gpointer offer, + GDestroyNotify destroy_notify) { DataOfferData *info; info = g_slice_new0 (DataOfferData); info->offer = offer; + info->destroy_notify = destroy_notify; return info; } @@ -281,7 +292,7 @@ data_offer_data_new (struct wl_data_offer *offer) static void data_offer_data_free (DataOfferData *info) { - wl_data_offer_destroy (info->offer); + info->destroy_notify (info->offer); g_list_free (info->targets); g_slice_free (DataOfferData, info); } @@ -292,6 +303,7 @@ gdk_wayland_selection_new (void) GdkWaylandSelection *selection; /* init atoms */ + atoms[ATOM_PRIMARY] = gdk_atom_intern_static_string ("PRIMARY"); atoms[ATOM_CLIPBOARD] = gdk_atom_intern_static_string ("CLIPBOARD"); atoms[ATOM_DND] = gdk_atom_intern_static_string ("GdkWaylandSelection"); @@ -325,6 +337,8 @@ gdk_wayland_selection_free (GdkWaylandSelection *selection) if (selection->stored_selection.fd > 0) close (selection->stored_selection.fd); + if (selection->primary_source) + zwp_primary_selection_source_v1_destroy (selection->primary_source); if (selection->clipboard_source) wl_data_source_destroy (selection->clipboard_source); if (selection->dnd_source) @@ -415,11 +429,34 @@ static const struct wl_data_offer_listener data_offer_listener = { data_offer_action }; +static void +primary_offer_offer (void *data, + struct zwp_primary_selection_offer_v1 *wp_offer, + const char *type) +{ + GdkWaylandSelection *selection = data; + DataOfferData *info; + GdkAtom atom = gdk_atom_intern (type, FALSE); + + info = g_hash_table_lookup (selection->offers, wp_offer); + + if (!info || g_list_find (info->targets, atom)) + return; + + info->targets = g_list_prepend (info->targets, atom); +} + +static const struct zwp_primary_selection_offer_v1_listener primary_offer_listener = { + primary_offer_offer, +}; + DataOfferData * selection_lookup_offer_by_atom (GdkWaylandSelection *selection, 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; else if (selection_atom == atoms[ATOM_DND]) return selection->dnd_offer; @@ -438,7 +475,8 @@ gdk_wayland_selection_ensure_offer (GdkDisplay *display, 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); wl_data_offer_add_listener (wl_offer, &data_offer_listener, @@ -447,9 +485,29 @@ gdk_wayland_selection_ensure_offer (GdkDisplay *display, } void -gdk_wayland_selection_set_offer (GdkDisplay *display, - GdkAtom selection_atom, - struct wl_data_offer *wl_offer) +gdk_wayland_selection_ensure_primary_offer (GdkDisplay *display, + struct zwp_primary_selection_offer_v1 *wp_offer) +{ + GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display); + DataOfferData *info; + + info = g_hash_table_lookup (selection->offers, wp_offer); + + if (!info) + { + info = data_offer_data_new (wp_offer, + (GDestroyNotify) zwp_primary_selection_offer_v1_destroy); + g_hash_table_insert (selection->offers, wp_offer, info); + zwp_primary_selection_offer_v1_add_listener (wp_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); struct wl_data_offer *prev_offer; @@ -462,7 +520,9 @@ gdk_wayland_selection_set_offer (GdkDisplay *display, if (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; else if (selection_atom == atoms[ATOM_DND]) selection->dnd_offer = info; @@ -471,7 +531,7 @@ gdk_wayland_selection_set_offer (GdkDisplay *display, g_hash_table_remove_all (selection->selection_buffers); } -struct wl_data_offer * +gpointer gdk_wayland_selection_get_offer (GdkDisplay *display, GdkAtom selection_atom) { @@ -718,18 +778,10 @@ gdk_wayland_selection_source_handles_target (GdkWaylandSelection *wayland_select static gboolean gdk_wayland_selection_request_target (GdkWaylandSelection *wayland_selection, GdkWindow *window, + GdkAtom selection, GdkAtom target, 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 && wayland_selection->requested_target == target) return FALSE; @@ -766,6 +818,7 @@ data_source_target (void *data, { GdkWaylandSelection *wayland_selection = data; GdkWindow *window = NULL; + GdkAtom selection; g_debug (G_STRLOC ": %s source = %p, mime_type = %s", G_STRFUNC, source, mime_type); @@ -774,14 +827,21 @@ data_source_target (void *data, return; 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) - window = wayland_selection->clipboard_owner; + { + selection = atoms[ATOM_CLIPBOARD]; + window = wayland_selection->clipboard_owner; + } if (!window) return; gdk_wayland_selection_request_target (wayland_selection, window, + selection, gdk_atom_intern (mime_type, FALSE), -1); } @@ -794,6 +854,7 @@ data_source_send (void *data, { GdkWaylandSelection *wayland_selection = data; GdkWindow *window; + GdkAtom selection; g_debug (G_STRLOC ": %s source = %p, mime_type = %s, fd = %d", G_STRFUNC, source, mime_type, fd); @@ -805,9 +866,20 @@ data_source_send (void *data, } 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) - window = wayland_selection->clipboard_owner; + { + window = wayland_selection->clipboard_owner; + selection = atoms[ATOM_CLIPBOARD]; + } + else if (source == (gpointer) wayland_selection->primary_source) + { + window = wayland_selection->primary_owner; + selection = atoms[ATOM_PRIMARY]; + } else { close (fd); @@ -818,6 +890,7 @@ data_source_send (void *data, return; if (!gdk_wayland_selection_request_target (wayland_selection, window, + selection, gdk_atom_intern (mime_type, FALSE), fd)) gdk_wayland_selection_check_write (wayland_selection); @@ -839,6 +912,8 @@ data_source_cancelled (void *data, if (source == wayland_selection->dnd_source) atom = atoms[ATOM_DND]; + else if (source == (gpointer) wayland_selection->primary_source) + atom = atoms[ATOM_PRIMARY]; else if (source == wayland_selection->clipboard_source) atom = atoms[ATOM_CLIPBOARD]; else @@ -919,15 +994,61 @@ static const struct wl_data_source_listener data_source_listener = { data_source_action, }; +static void +primary_source_send (void *data, + struct zwp_primary_selection_source_v1 *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 zwp_primary_selection_source_v1 *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 zwp_primary_selection_source_v1_listener primary_source_listener = { + primary_source_send, + primary_source_cancelled, +}; + struct wl_data_source * gdk_wayland_selection_get_data_source (GdkWindow *owner, GdkAtom selection) { GdkDisplay *display = gdk_window_get_display (owner); GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display); - struct wl_data_source *source = NULL; + gpointer source = NULL; GdkWaylandDisplay *display_wayland; - gboolean is_clipboard = FALSE; if (selection == atoms[ATOM_DND]) { @@ -935,6 +1056,18 @@ gdk_wayland_selection_get_data_source (GdkWindow *owner, (!owner || owner == wayland_selection->dnd_owner)) 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) + { + zwp_primary_selection_source_v1_destroy (wayland_selection->primary_source); + wayland_selection->primary_source = NULL; + } + } else if (selection == atoms[ATOM_CLIPBOARD]) { if (wayland_selection->clipboard_source && @@ -946,8 +1079,6 @@ gdk_wayland_selection_get_data_source (GdkWindow *owner, wl_data_source_destroy (wayland_selection->clipboard_source); wayland_selection->clipboard_source = NULL; } - - is_clipboard = TRUE; } else return NULL; @@ -957,15 +1088,27 @@ gdk_wayland_selection_get_data_source (GdkWindow *owner, display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (owner)); - 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 (is_clipboard) - wayland_selection->clipboard_source = source; + if (selection == atoms[ATOM_PRIMARY]) + { + source = zwp_primary_selection_device_manager_v1_create_source (display_wayland->primary_selection_manager); + zwp_primary_selection_source_v1_add_listener (source, + &primary_source_listener, + wayland_selection); + } 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; + else if (selection == atoms[ATOM_PRIMARY]) + wayland_selection->primary_source = source; + else if (selection == atoms[ATOM_CLIPBOARD]) + wayland_selection->clipboard_source = source; return source; } @@ -990,6 +1133,18 @@ gdk_wayland_selection_unset_data_source (GdkDisplay *display, 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) + { + zwp_primary_selection_source_v1_destroy (wayland_selection->primary_source); + wayland_selection->primary_source = NULL; + } + } else if (selection == atoms[ATOM_DND]) { wayland_selection->dnd_source = NULL; @@ -1004,6 +1159,8 @@ _gdk_wayland_display_get_selection_owner (GdkDisplay *display, if (selection == atoms[ATOM_CLIPBOARD]) return wayland_selection->clipboard_owner; + else if (selection == atoms[ATOM_PRIMARY]) + return wayland_selection->primary_owner; else if (selection == atoms[ATOM_DND]) return wayland_selection->dnd_owner; @@ -1024,6 +1181,11 @@ _gdk_wayland_display_set_selection_owner (GdkDisplay *display, wayland_selection->clipboard_owner = owner; return TRUE; } + else if (selection == atoms[ATOM_PRIMARY]) + { + wayland_selection->primary_owner = owner; + return TRUE; + } else if (selection == atoms[ATOM_DND]) { wayland_selection->dnd_owner = owner; @@ -1088,6 +1250,26 @@ _gdk_wayland_display_get_selection_property (GdkDisplay *display, 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 _gdk_wayland_display_convert_selection (GdkDisplay *display, GdkWindow *requestor, @@ -1097,7 +1279,7 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display, { GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display); SelectionBuffer *buffer_data; - struct wl_data_offer *offer; + gpointer offer; gchar *mimetype; GList *target_list; @@ -1106,28 +1288,25 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display, if (!offer || target == gdk_atom_intern_static_string ("DELETE")) { - 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); + emit_empty_selection_notify (requestor, selection, target); return; } mimetype = gdk_atom_name (target); if (target != gdk_atom_intern_static_string ("TARGETS")) - wl_data_offer_accept (offer, - _gdk_wayland_display_get_serial (GDK_WAYLAND_DISPLAY (display)), - mimetype); + { + if (!g_list_find (target_list, GDK_ATOM_TO_POINTER (target))) + { + 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, target); @@ -1154,7 +1333,21 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display, else { g_unix_open_pipe (pipe_fd, FD_CLOEXEC, NULL); - wl_data_offer_receive (offer, mimetype, pipe_fd[1]); + + if (selection == atoms[ATOM_PRIMARY]) + { + uint32_t serial; + GdkSeat *seat; + + seat = gdk_display_get_default_seat (GDK_DISPLAY (display)); + serial = _gdk_wayland_seat_get_last_implicit_grab_serial (seat, + NULL); + zwp_primary_selection_offer_v1_receive (offer, mimetype, + pipe_fd[1], serial); + } + else + wl_data_offer_receive (offer, mimetype, pipe_fd[1]); + stream = g_unix_input_stream_new (pipe_fd[0], TRUE); close (pipe_fd[1]); } @@ -1239,7 +1432,7 @@ gdk_wayland_selection_add_targets (GdkWindow *window, { GdkDisplay *display = gdk_window_get_display (window); GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display); - struct wl_data_source *data_source; + gpointer data_source; guint i; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -1268,6 +1461,13 @@ gdk_wayland_selection_add_targets (GdkWindow *window, device = gdk_seat_get_pointer (gdk_display_get_default_seat (display)); 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 diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c index 87bdc934ae..98688b93d2 100644 --- a/gdk/wayland/gdkwindow-wayland.c +++ b/gdk/wayland/gdkwindow-wayland.c @@ -1316,7 +1316,6 @@ gdk_wayland_window_create_xdg_popup (GdkWindow *window, GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window)); GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); GdkWindowImplWayland *parent_impl = GDK_WINDOW_IMPL_WAYLAND (parent->impl); - GdkWaylandDevice *device; GdkSeat *gdk_seat; int x, y; int parent_x, parent_y; @@ -1328,8 +1327,6 @@ gdk_wayland_window_create_xdg_popup (GdkWindow *window, return; gdk_seat = gdk_display_get_default_seat (GDK_DISPLAY (display)); - device = GDK_WAYLAND_DEVICE (gdk_seat_get_pointer (gdk_seat)); - gdk_wayland_window_get_fake_root_coords (parent, &parent_x, &parent_y); x = window->x - parent_x; @@ -1339,7 +1336,7 @@ gdk_wayland_window_create_xdg_popup (GdkWindow *window, impl->display_server.wl_surface, parent_impl->display_server.wl_surface, seat, - _gdk_wayland_device_get_last_implicit_grab_serial (device, NULL), + _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_seat, NULL), x, y); xdg_popup_add_listener (impl->display_server.xdg_popup, &xdg_popup_listener, window); @@ -2455,8 +2452,8 @@ gdk_wayland_window_begin_resize_drag (GdkWindow *window, if (!impl->display_server.xdg_surface) return; - serial = _gdk_wayland_device_get_last_implicit_grab_serial (GDK_WAYLAND_DEVICE (device), - &sequence); + serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device), + &sequence); xdg_surface_resize (impl->display_server.xdg_surface, gdk_wayland_device_get_wl_seat (device), @@ -2492,8 +2489,8 @@ gdk_wayland_window_begin_move_drag (GdkWindow *window, if (!impl->display_server.xdg_surface) return; - serial = _gdk_wayland_device_get_last_implicit_grab_serial (GDK_WAYLAND_DEVICE (device), - &sequence); + serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device), + &sequence); xdg_surface_move (impl->display_server.xdg_surface, gdk_wayland_device_get_wl_seat (device), serial); |