From ef69daacdfc0a73cb1b1716f13f0914ec045a250 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 3 Dec 2017 03:51:43 +0100 Subject: [PATCH] wayland: Implement taking over the clipboard The clipboard is now complete. That was fast. --- gdk/wayland/gdkclipboard-wayland.c | 135 +++++++++++++++++++++++++++-- gdk/wayland/gdkselection-wayland.c | 68 +-------------- 2 files changed, 133 insertions(+), 70 deletions(-) diff --git a/gdk/wayland/gdkclipboard-wayland.c b/gdk/wayland/gdkclipboard-wayland.c index 51d5ed2f67..30ada30f87 100644 --- a/gdk/wayland/gdkclipboard-wayland.c +++ b/gdk/wayland/gdkclipboard-wayland.c @@ -22,10 +22,12 @@ #include "gdkcontentformats.h" #include "gdkintl.h" +#include "gdkprivate-wayland.h" #include "gdk-private.h" #include #include +#include typedef struct _GdkWaylandClipboardClass GdkWaylandClipboardClass; @@ -35,6 +37,8 @@ struct _GdkWaylandClipboard struct wl_data_offer *offer; GdkContentFormats *offer_formats; + + struct wl_data_source *source; }; struct _GdkWaylandClipboardClass @@ -51,16 +55,116 @@ gdk_wayland_clipboard_discard_offer (GdkWaylandClipboard *cb) g_clear_pointer (&cb->offer, (GDestroyNotify) wl_data_offer_destroy); } +static void +gdk_wayland_clipboard_discard_source (GdkWaylandClipboard *cb) +{ + g_clear_pointer (&cb->source, (GDestroyNotify) wl_data_source_destroy); +} + static void gdk_wayland_clipboard_finalize (GObject *object) { GdkWaylandClipboard *cb = GDK_WAYLAND_CLIPBOARD (object); gdk_wayland_clipboard_discard_offer (cb); + gdk_wayland_clipboard_discard_source (cb); G_OBJECT_CLASS (gdk_wayland_clipboard_parent_class)->finalize (object); } +static void +gdk_wayland_clipboard_data_source_target (void *data, + struct wl_data_source *source, + const char *mime_type) +{ + GDK_NOTE (CLIPBOARD, g_printerr ("%p: Huh? data_source.target() events?\n", data)); +} + +static void +gdk_wayland_clipboard_write_done (GObject *clipboard, + GAsyncResult *result, + gpointer user_data) +{ + GError *error = NULL; + + if (!gdk_clipboard_write_finish (GDK_CLIPBOARD (clipboard), result, &error)) + { + GDK_NOTE(CLIPBOARD, g_printerr ("%p: failed to write stream: %s\n", clipboard, error->message)); + g_error_free (error); + } +} + +static void +gdk_wayland_clipboard_data_source_send (void *data, + struct wl_data_source *source, + const char *mime_type, + int32_t fd) +{ + GdkWaylandClipboard *cb = GDK_WAYLAND_CLIPBOARD (data); + GOutputStream *stream; + + GDK_NOTE (CLIPBOARD, g_printerr ("%p: data source send request for %s on fd %d\n", + source, mime_type, fd)); + + mime_type = gdk_intern_mime_type (mime_type); + stream = g_unix_output_stream_new (fd, TRUE); + + gdk_clipboard_write_async (GDK_CLIPBOARD (cb), + mime_type, + stream, + G_PRIORITY_DEFAULT, + NULL, + gdk_wayland_clipboard_write_done, + cb); + g_object_unref (stream); +} + +static void +gdk_wayland_clipboard_data_source_cancelled (void *data, + struct wl_data_source *source) +{ + GdkWaylandClipboard *cb = GDK_WAYLAND_CLIPBOARD (data); + + GDK_NOTE (CLIPBOARD, g_printerr ("%p: data source cancelled\n", data)); + + if (cb->source == source) + { + gdk_wayland_clipboard_discard_source (cb); + gdk_wayland_clipboard_claim_remote (cb, NULL, gdk_content_formats_new (NULL, 0)); + } +} + +static void +gdk_wayland_clipboard_data_source_dnd_drop_performed (void *data, + struct wl_data_source *source) +{ + GDK_NOTE (CLIPBOARD, g_printerr ("%p: Huh? data_source.dnd_drop_performed() events?\n", data)); +} + +static void +gdk_wayland_clipboard_data_source_dnd_finished (void *data, + struct wl_data_source *source) +{ + GDK_NOTE (CLIPBOARD, g_printerr ("%p: Huh? data_source.dnd_finished() events?\n", data)); +} + +static void +gdk_wayland_clipboard_data_source_action (void *data, + struct wl_data_source *source, + uint32_t action) +{ + GDK_NOTE (CLIPBOARD, g_printerr ("%p: Huh? data_source.action() events?\n", data)); +} + +static const struct wl_data_source_listener data_source_listener = { + gdk_wayland_clipboard_data_source_target, + gdk_wayland_clipboard_data_source_send, + gdk_wayland_clipboard_data_source_cancelled, + gdk_wayland_clipboard_data_source_dnd_drop_performed, + gdk_wayland_clipboard_data_source_dnd_finished, + gdk_wayland_clipboard_data_source_action, +}; + static gboolean gdk_wayland_clipboard_claim (GdkClipboard *clipboard, GdkContentFormats *formats, @@ -71,8 +175,25 @@ gdk_wayland_clipboard_claim (GdkClipboard *clipboard, if (local) { - /* not handled yet */ - cb->offer = NULL; + GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (gdk_clipboard_get_display (clipboard)); + GdkDevice *device; + const char * const *mime_types; + gsize i, n_mime_types; + + gdk_wayland_clipboard_discard_offer (cb); + gdk_wayland_clipboard_discard_source (cb); + + cb->source = wl_data_device_manager_create_data_source (wayland_display->data_device_manager); + wl_data_source_add_listener (cb->source, &data_source_listener, cb); + + mime_types = gdk_content_formats_get_mime_types (formats, &n_mime_types); + for (i = 0; i < n_mime_types; i++) + { + wl_data_source_offer (cb->source, mime_types[i]); + } + + device = gdk_seat_get_pointer (gdk_display_get_default_seat (GDK_DISPLAY (wayland_display))); + gdk_wayland_device_set_selection (device, cb->source); } return GDK_CLIPBOARD_CLASS (gdk_wayland_clipboard_parent_class)->claim (clipboard, formats, local, content); @@ -163,10 +284,6 @@ gdk_wayland_clipboard_class_init (GdkWaylandClipboardClass *class) object_class->finalize = gdk_wayland_clipboard_finalize; clipboard_class->claim = gdk_wayland_clipboard_claim; -#if 0 - clipboard_class->store_async = gdk_wayland_clipboard_store_async; - clipboard_class->store_finish = gdk_wayland_clipboard_store_finish; -#endif clipboard_class->read_async = gdk_wayland_clipboard_read_async; clipboard_class->read_finish = gdk_wayland_clipboard_read_finish; } @@ -195,6 +312,12 @@ gdk_wayland_clipboard_claim_remote (GdkWaylandClipboard *cb, { g_return_if_fail (GDK_IS_WAYLAND_CLIPBOARD (cb)); + if (cb->source) + { + GDK_NOTE (CLIPBOARD, g_printerr ("%p: Ignoring clipboard offer for self\n", cb)); + return; + } + gdk_wayland_clipboard_discard_offer (cb); GDK_NOTE (CLIPBOARD, char *s = gdk_content_formats_to_string (formats); diff --git a/gdk/wayland/gdkselection-wayland.c b/gdk/wayland/gdkselection-wayland.c index f2d76fc3c6..1a20148dca 100644 --- a/gdk/wayland/gdkselection-wayland.c +++ b/gdk/wayland/gdkselection-wayland.c @@ -83,7 +83,6 @@ struct _SelectionData enum { ATOM_PRIMARY, - ATOM_CLIPBOARD, ATOM_DND, N_ATOMS }; @@ -104,9 +103,6 @@ struct _GdkWaylandSelection struct gtk_primary_selection_source *primary_source; GdkWindow *primary_owner; - struct wl_data_source *clipboard_source; - GdkWindow *clipboard_owner; - struct wl_data_source *dnd_source; /* Owned by the GdkDragContext */ GdkWindow *dnd_owner; }; @@ -312,7 +308,6 @@ gdk_wayland_selection_new (void) /* 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"); selection = g_new0 (GdkWaylandSelection, 1); @@ -355,8 +350,6 @@ gdk_wayland_selection_free (GdkWaylandSelection *selection) if (selection->primary_source) gtk_primary_selection_source_destroy (selection->primary_source); - if (selection->clipboard_source) - wl_data_source_destroy (selection->clipboard_source); if (selection->dnd_source) wl_data_source_destroy (selection->dnd_source); @@ -489,8 +482,6 @@ selection_lookup_offer_by_atom (GdkWaylandSelection *selection, { if (selection_atom == atoms[ATOM_PRIMARY]) return &selection->selections[ATOM_PRIMARY]; - else if (selection_atom == atoms[ATOM_CLIPBOARD]) - return &selection->selections[ATOM_CLIPBOARD]; else if (selection_atom == atoms[ATOM_DND]) return &selection->selections[ATOM_DND]; else @@ -903,11 +894,6 @@ data_source_send (void *data, window = wayland_selection->dnd_owner; selection = atoms[ATOM_DND]; } - else if (source == wayland_selection->clipboard_source) - { - window = wayland_selection->clipboard_owner; - selection = atoms[ATOM_CLIPBOARD]; - } else { close (fd); @@ -940,8 +926,6 @@ data_source_cancelled (void *data, if (source == wayland_selection->dnd_source) atom = atoms[ATOM_DND]; - else if (source == wayland_selection->clipboard_source) - atom = atoms[ATOM_CLIPBOARD]; else return; @@ -1098,18 +1082,6 @@ gdk_wayland_selection_get_data_source (GdkWindow *owner, wayland_selection->primary_source = NULL; } } - else if (selection == atoms[ATOM_CLIPBOARD]) - { - if (wayland_selection->clipboard_source && - (!owner || owner == wayland_selection->clipboard_owner)) - return wayland_selection->clipboard_source; - - if (wayland_selection->clipboard_source) - { - wl_data_source_destroy (wayland_selection->clipboard_source); - wayland_selection->clipboard_source = NULL; - } - } else return NULL; @@ -1140,8 +1112,6 @@ gdk_wayland_selection_get_data_source (GdkWindow *owner, 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; } @@ -1152,21 +1122,7 @@ gdk_wayland_selection_unset_data_source (GdkDisplay *display, { GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display); - if (selection == atoms[ATOM_CLIPBOARD]) - { - GdkDevice *device; - - device = gdk_seat_get_pointer (gdk_display_get_default_seat (display)); - - gdk_wayland_device_set_selection (device, NULL); - - if (wayland_selection->clipboard_source) - { - wl_data_source_destroy (wayland_selection->clipboard_source); - wayland_selection->clipboard_source = NULL; - } - } - else if (selection == atoms[ATOM_PRIMARY]) + if (selection == atoms[ATOM_PRIMARY]) { GdkSeat *seat = gdk_display_get_default_seat (display); @@ -1190,9 +1146,7 @@ _gdk_wayland_display_get_selection_owner (GdkDisplay *display, { GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display); - if (selection == atoms[ATOM_CLIPBOARD]) - return wayland_selection->clipboard_owner; - else if (selection == atoms[ATOM_PRIMARY]) + if (selection == atoms[ATOM_PRIMARY]) return wayland_selection->primary_owner; else if (selection == atoms[ATOM_DND]) return wayland_selection->dnd_owner; @@ -1209,12 +1163,7 @@ _gdk_wayland_display_set_selection_owner (GdkDisplay *display, { GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display); - if (selection == atoms[ATOM_CLIPBOARD]) - { - wayland_selection->clipboard_owner = owner; - return TRUE; - } - else if (selection == atoms[ATOM_PRIMARY]) + if (selection == atoms[ATOM_PRIMARY]) { wayland_selection->primary_owner = owner; return TRUE; @@ -1553,16 +1502,7 @@ gdk_wayland_display_add_selection_targets (GdkDisplay *display, g_free (mimetype); } - if (selection == atoms[ATOM_CLIPBOARD]) - { - GdkDisplay *display; - GdkDevice *device; - - display = gdk_window_get_display (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]) + if (selection == atoms[ATOM_PRIMARY]) { GdkSeat *seat;