[gtk+] wayland: Implement taking over the clipboard



commit ef69daacdfc0a73cb1b1716f13f0914ec045a250
Author: Benjamin Otte <otte redhat com>
Date:   Sun Dec 3 03:51:43 2017 +0100

    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 51d5ed2..30ada30 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 <glib-unix.h>
 #include <gio/gunixinputstream.h>
+#include <gio/gunixoutputstream.h>
 
 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
@@ -52,15 +56,115 @@ gdk_wayland_clipboard_discard_offer (GdkWaylandClipboard *cb)
 }
 
 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 f2d76fc..1a20148 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;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]