[mutter/wip/carlosg/clipboard-manager: 10/12] wayland: Integrate with MetaSelection



commit 5d9620278800324e870e2d190b1e99204f47d8cd
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Nov 22 15:56:24 2018 +0100

    wayland: Integrate with MetaSelection
    
    Make MetaWaylandDataDevice use MetaSelection and MetaSelectionSource to
    handle primary/clipboard/dnd.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/320

 src/wayland/meta-wayland-data-device.c | 383 +++++++++++++++++++++++++--------
 src/wayland/meta-wayland-data-device.h |   5 +
 2 files changed, 303 insertions(+), 85 deletions(-)
---
diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c
index 122604965..002d3df69 100644
--- a/src/wayland/meta-wayland-data-device.c
+++ b/src/wayland/meta-wayland-data-device.c
@@ -27,6 +27,7 @@
 #include "wayland/meta-wayland-data-device.h"
 #include "wayland/meta-wayland-data-device-private.h"
 
+#include <gio/gunixoutputstream.h>
 #include <glib-unix.h>
 #include <glib.h>
 #include <stdio.h>
@@ -35,6 +36,7 @@
 #include <unistd.h>
 
 #include "compositor/meta-dnd-actor-private.h"
+#include "wayland/meta-selection-source-wayland-private.h"
 #include "wayland/meta-wayland-dnd-surface.h"
 #include "wayland/meta-wayland-pointer.h"
 #include "wayland/meta-wayland-private.h"
@@ -101,6 +103,11 @@ meta_wayland_data_source_primary_new (struct wl_resource *resource);
 static void
 drag_grab_data_source_destroyed (gpointer data, GObject *where_the_object_was);
 
+static struct wl_resource * create_clipboard_source_offer (MetaWaylandDataDevice *data_device,
+                                                           struct wl_resource    *target);
+static struct wl_resource * create_primary_source_offer   (MetaWaylandDataDevice *data_device,
+                                                           struct wl_resource    *target);
+
 static void
 unbind_resource (struct wl_resource *resource)
 {
@@ -364,16 +371,60 @@ data_offer_accept (struct wl_client *client,
   offer->accepted = mime_type != NULL;
 }
 
+static void
+transfer_cb (MetaSelection *selection,
+             GAsyncResult  *res,
+             GOutputStream *stream)
+{
+  GError *error = NULL;
+
+  if (!meta_selection_transfer_finish (selection, res, &error))
+    {
+      g_warning ("Could not fetch selection data: %s\n", error->message);
+      g_error_free (error);
+    }
+
+  g_output_stream_close (stream, NULL, NULL);
+}
+
 static void
 data_offer_receive (struct wl_client *client, struct wl_resource *resource,
                     const char *mime_type, int32_t fd)
 {
   MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
+  MetaDisplay *display = meta_get_display ();
+  MetaSelectionType selection_type;
+  GList *mime_types;
+  gboolean found;
 
-  if (offer->source)
-    meta_wayland_data_source_send (offer->source, mime_type, fd);
+  if (offer->dnd_actions != 0)
+    selection_type = META_SELECTION_DND;
   else
-    close (fd);
+    selection_type = META_SELECTION_CLIPBOARD;
+
+  mime_types = meta_selection_get_mimetypes (meta_display_get_selection (display),
+                                             selection_type);
+  found = g_list_find_custom (mime_types, mime_type, (GCompareFunc) g_strcmp0) != NULL;
+  g_list_free_full (mime_types, g_free);
+
+  if (found)
+    {
+      GOutputStream *stream;
+
+      stream = g_unix_output_stream_new (fd, TRUE);
+      meta_selection_transfer_async (meta_display_get_selection (display),
+                                     selection_type,
+                                     mime_type,
+                                     -1,
+                                     stream,
+                                     NULL,
+                                     (GAsyncReadyCallback) transfer_cb,
+                                     stream);
+    }
+  else
+    {
+      close (fd);
+    }
 }
 
 static void
@@ -460,26 +511,31 @@ static void
 primary_offer_receive (struct wl_client *client, struct wl_resource *resource,
                        const char *mime_type, int32_t fd)
 {
-  MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
-  MetaWaylandDataSource *source = offer->source;
-  MetaWaylandSeat *seat;
-
-  if (!offer->source)
-    {
-      close (fd);
-      return;
-    }
+  MetaDisplay *display = meta_get_display ();
+  GOutputStream *stream;
+  GList *mime_types;
+  gboolean found;
 
-  seat = meta_wayland_data_source_get_seat (source);
+  mime_types = meta_selection_get_mimetypes (meta_display_get_selection (display),
+                                             META_SELECTION_CLIPBOARD);
+  found = g_list_find_custom (mime_types, mime_type, (GCompareFunc) g_strcmp0) != NULL;
+  g_list_free_full (mime_types, g_free);
 
-  if (wl_resource_get_client (offer->resource) !=
-      meta_wayland_keyboard_get_focus_client (seat->keyboard))
+  if (!found)
     {
       close (fd);
       return;
     }
 
-  meta_wayland_data_source_send (offer->source, mime_type, fd);
+  stream = g_unix_output_stream_new (fd, TRUE);
+  meta_selection_transfer_async (meta_display_get_selection (display),
+                                 META_SELECTION_PRIMARY,
+                                 mime_type,
+                                 -1,
+                                 stream,
+                                 NULL,
+                                 (GAsyncReadyCallback) transfer_cb,
+                                 stream);
 }
 
 static const struct gtk_primary_selection_offer_interface primary_offer_interface = {
@@ -583,35 +639,6 @@ meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
   return offer->resource;
 }
 
-static struct wl_resource *
-meta_wayland_data_source_send_primary_offer (MetaWaylandDataSource *source,
-                                            struct wl_resource    *target)
-{
-  MetaWaylandDataSourcePrivate *priv =
-    meta_wayland_data_source_get_instance_private (source);
-  MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer);
-  char **p;
-
-  offer->source = source;
-  g_object_add_weak_pointer (G_OBJECT (source), (gpointer *)&offer->source);
-  offer->resource = wl_resource_create (wl_resource_get_client (target),
-                                        &gtk_primary_selection_offer_interface,
-                                        wl_resource_get_version (target), 0);
-  wl_resource_set_implementation (offer->resource,
-                                  &primary_offer_interface,
-                                  offer,
-                                  destroy_primary_offer);
-
-  gtk_primary_selection_device_send_data_offer (target, offer->resource);
-
-  wl_array_for_each (p, &priv->mime_types)
-    gtk_primary_selection_offer_send_offer (offer->resource, *p);
-
-  meta_wayland_data_source_set_current_offer (source, offer);
-
-  return offer->resource;
-}
-
 static void
 data_source_offer (struct wl_client *client,
                    struct wl_resource *resource, const char *type)
@@ -712,6 +739,34 @@ struct _MetaWaylandDragGrab {
   guint                   need_initial_focus : 1;
 };
 
+static void
+set_selection_source (MetaWaylandDataDevice *data_device,
+                      MetaSelectionType      selection_type,
+                      MetaSelectionSource   *selection_source)
+
+{
+  MetaDisplay *display = meta_get_display ();
+
+  meta_selection_set_owner (meta_display_get_selection (display),
+                            selection_type, selection_source);
+  g_set_object (&data_device->owners[selection_type], selection_source);
+}
+
+static void
+unset_selection_source (MetaWaylandDataDevice *data_device,
+                        MetaSelectionType      selection_type)
+{
+  MetaDisplay *display = meta_get_display ();
+
+  if (!data_device->owners[selection_type])
+    return;
+
+  meta_selection_unset_owner (meta_display_get_selection (display),
+                              selection_type,
+                              data_device->owners[selection_type]);
+  g_clear_object (&data_device->owners[selection_type]);
+}
+
 static void
 destroy_drag_focus (struct wl_listener *listener, void *data)
 {
@@ -1005,6 +1060,7 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
           meta_wayland_data_source_cancel (source);
           meta_wayland_data_source_set_current_offer (source, NULL);
           meta_wayland_data_device_set_dnd_source (&seat->data_device, NULL);
+          unset_selection_source (&seat->data_device, META_SELECTION_DND);
           success= FALSE;
         }
 
@@ -1066,6 +1122,7 @@ destroy_data_device_origin (struct wl_listener *listener, void *data)
 
   drag_grab->drag_origin = NULL;
   meta_wayland_data_device_set_dnd_source (&drag_grab->seat->data_device, NULL);
+  unset_selection_source (&drag_grab->seat->data_device, META_SELECTION_DND);
   data_device_end_drag_grab (drag_grab);
 }
 
@@ -1076,6 +1133,7 @@ drag_grab_data_source_destroyed (gpointer data, GObject *where_the_object_was)
 
   drag_grab->drag_data_source = NULL;
   meta_wayland_data_device_set_dnd_source (&drag_grab->seat->data_device, NULL);
+  unset_selection_source (&drag_grab->seat->data_device, META_SELECTION_DND);
   data_device_end_drag_grab (drag_grab);
 }
 
@@ -1091,6 +1149,18 @@ destroy_data_device_icon (struct wl_listener *listener, void *data)
     clutter_actor_remove_all_children (drag_grab->feedback_actor);
 }
 
+static GList *
+copy_string_array_to_list (struct wl_array *array)
+{
+  GList *l = NULL;
+  char **p;
+
+  wl_array_for_each (p, array)
+    l = g_list_prepend (l, g_strdup (*p));
+
+  return l;
+}
+
 void
 meta_wayland_data_device_start_drag (MetaWaylandDataDevice                 *data_device,
                                      struct wl_client                      *client,
@@ -1189,6 +1259,8 @@ data_device_start_drag (struct wl_client *client,
   MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
   MetaWaylandSurface *surface = NULL, *icon_surface = NULL;
   MetaWaylandDataSource *drag_source = NULL;
+  MetaSelectionSource *selection_source;
+  GList *mimetypes;
 
   if (origin_resource)
     surface = wl_resource_get_user_data (origin_resource);
@@ -1224,6 +1296,15 @@ data_device_start_drag (struct wl_client *client,
       return;
     }
 
+  mimetypes = copy_string_array_to_list (meta_wayland_data_source_get_mime_types (drag_source));
+  selection_source = meta_selection_source_wayland_new (source_resource,
+                                                        mimetypes,
+                                                        wl_data_source_send_send,
+                                                        wl_data_source_send_cancelled);
+  g_list_free_full (mimetypes, g_free);
+  set_selection_source (data_device, META_SELECTION_DND,
+                        selection_source);
+
   meta_wayland_pointer_set_focus (seat->pointer, NULL);
   meta_wayland_data_device_start_drag (data_device, client,
                                        &drag_grab_interface,
@@ -1256,6 +1337,7 @@ selection_data_source_destroyed (gpointer data, GObject *object_was_here)
     }
 
   wl_signal_emit (&data_device->selection_ownership_signal, NULL);
+  unset_selection_source (data_device, META_SELECTION_CLIPBOARD);
 }
 
 static void
@@ -1315,6 +1397,8 @@ meta_wayland_source_drop_performed (MetaWaylandDataSource *source)
 static void
 meta_wayland_source_drag_finished (MetaWaylandDataSource *source)
 {
+  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+  MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
   MetaWaylandDataSourceWayland *source_wayland =
     META_WAYLAND_DATA_SOURCE_WAYLAND (source);
   enum wl_data_device_manager_dnd_action action;
@@ -1328,6 +1412,8 @@ meta_wayland_source_drag_finished (MetaWaylandDataSource *source)
   if (wl_resource_get_version (source_wayland->resource) >=
       WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
     wl_data_source_send_dnd_finished (source_wayland->resource);
+
+  unset_selection_source (data_device, META_SELECTION_DND);
 }
 
 static void
@@ -1579,24 +1665,36 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
       data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
       if (data_device_resource)
         {
-          if (data_device->selection_data_source)
-            {
-              offer = meta_wayland_data_source_send_offer (data_device->selection_data_source, 
data_device_resource);
-              wl_data_device_send_selection (data_device_resource, offer);
-            }
-          else
-            {
-              wl_data_device_send_selection (data_device_resource, NULL);
-            }
+          offer = create_clipboard_source_offer (data_device, data_device_resource);
+          wl_data_device_send_selection (data_device_resource, offer);
         }
     }
 
   if (source)
     {
+      MetaWaylandDataSourceWayland *source_wayland =
+        META_WAYLAND_DATA_SOURCE_WAYLAND (source);
+      MetaSelectionSource *selection_source;
+      GList *mimetypes;
+
       meta_wayland_data_source_set_seat (source, seat);
       g_object_weak_ref (G_OBJECT (source),
                          selection_data_source_destroyed,
                          data_device);
+
+      mimetypes = copy_string_array_to_list (meta_wayland_data_source_get_mime_types (source));
+      selection_source = meta_selection_source_wayland_new (source_wayland->resource,
+                                                            mimetypes,
+                                                            wl_data_source_send_send,
+                                                            wl_data_source_send_cancelled);
+      g_list_free_full (mimetypes, g_free);
+
+      set_selection_source (data_device, META_SELECTION_CLIPBOARD,
+                            selection_source);
+    }
+  else
+    {
+      unset_selection_source (data_device, META_SELECTION_CLIPBOARD);
     }
 
   wl_signal_emit (&data_device->selection_ownership_signal, source);
@@ -1661,6 +1759,7 @@ primary_source_destroyed (gpointer  data,
     }
 
   wl_signal_emit (&data_device->primary_ownership_signal, NULL);
+  unset_selection_source (data_device, META_SELECTION_PRIMARY);
 }
 
 void
@@ -1704,25 +1803,34 @@ meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
       data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
       if (data_device_resource)
         {
-          if (data_device->primary_data_source)
-            {
-              offer = meta_wayland_data_source_send_primary_offer (data_device->primary_data_source,
-                                                                   data_device_resource);
-              gtk_primary_selection_device_send_selection (data_device_resource, offer);
-            }
-          else
-            {
-              gtk_primary_selection_device_send_selection (data_device_resource, NULL);
-            }
+          offer = create_primary_source_offer (data_device, data_device_resource);
+          gtk_primary_selection_device_send_selection (data_device_resource, offer);
         }
     }
 
   if (source)
     {
+      MetaSelectionSource *selection_source;
+      GList *mimetypes;
+
       meta_wayland_data_source_set_seat (source, seat);
       g_object_weak_ref (G_OBJECT (source),
                          primary_source_destroyed,
                          data_device);
+
+      mimetypes = copy_string_array_to_list (meta_wayland_data_source_get_mime_types (source));
+      selection_source = meta_selection_source_wayland_new (META_WAYLAND_DATA_SOURCE_PRIMARY 
(source)->resource,
+                                                            mimetypes,
+                                                            gtk_primary_selection_source_send_send,
+                                                            gtk_primary_selection_source_send_cancelled);
+      g_list_free_full (mimetypes, g_free);
+
+      set_selection_source (data_device, META_SELECTION_PRIMARY,
+                            selection_source);
+    }
+  else
+    {
+      unset_selection_source (data_device, META_SELECTION_PRIMARY);
     }
 
   wl_signal_emit (&data_device->primary_ownership_signal, source);
@@ -1767,6 +1875,56 @@ create_data_source (struct wl_client *client,
   meta_wayland_data_source_wayland_new (source_resource);
 }
 
+static void
+owner_changed_cb (MetaSelection         *selection,
+                  MetaSelectionType      selection_type,
+                  MetaSelectionSource   *owner,
+                  MetaWaylandDataDevice *data_device)
+{
+  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+  MetaWaylandSeat *seat = compositor->seat;
+  struct wl_resource *offer = NULL, *data_device_resource;
+  struct wl_client *focus_client;
+
+  focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
+  if (!focus_client)
+    return;
+
+  if (selection_type == META_SELECTION_PRIMARY)
+    {
+      data_device_resource =
+        wl_resource_find_for_client (&data_device->primary_resource_list,
+                                     focus_client);
+      if (data_device_resource)
+        {
+          if (owner)
+            {
+              offer = create_primary_source_offer (data_device,
+                                                   data_device_resource);
+            }
+
+          gtk_primary_selection_device_send_selection (data_device_resource,
+                                                       offer);
+        }
+    }
+  else if (selection_type == META_SELECTION_CLIPBOARD)
+    {
+      data_device_resource =
+        wl_resource_find_for_client (&data_device->resource_list, focus_client);
+
+      if (data_device_resource)
+        {
+          if (owner)
+            {
+              offer = create_clipboard_source_offer (data_device,
+                                                     data_device_resource);
+            }
+
+          wl_data_device_send_selection (data_device_resource, offer);
+        }
+    }
+}
+
 static void
 get_data_device (struct wl_client *client,
                  struct wl_resource *manager_resource,
@@ -1778,6 +1936,14 @@ get_data_device (struct wl_client *client,
   cr = wl_resource_create (client, &wl_data_device_interface, wl_resource_get_version (manager_resource), 
id);
   wl_resource_set_implementation (cr, &data_device_interface, &seat->data_device, unbind_resource);
   wl_list_insert (&seat->data_device.resource_list, wl_resource_get_link (cr));
+
+  if (seat->data_device.selection_owner_signal_id == 0)
+    {
+      seat->data_device.selection_owner_signal_id =
+        g_signal_connect (meta_display_get_selection (meta_get_display ()),
+                          "owner-changed",
+                          G_CALLBACK (owner_changed_cb), &seat->data_device);
+    }
 }
 
 static const struct wl_data_device_manager_interface manager_interface = {
@@ -1877,13 +2043,76 @@ meta_wayland_data_device_init (MetaWaylandDataDevice *data_device)
   wl_signal_init (&data_device->dnd_ownership_signal);
 }
 
+static struct wl_resource *
+create_clipboard_source_offer (MetaWaylandDataDevice *data_device,
+                               struct wl_resource    *target)
+{
+  MetaWaylandDataOffer *offer;
+  MetaDisplay *display = meta_get_display ();
+  GList *mimetypes, *l;
+
+  mimetypes = meta_selection_get_mimetypes (meta_display_get_selection (display),
+                                            META_SELECTION_CLIPBOARD);
+  if (!mimetypes)
+    return NULL;
+
+  offer = g_slice_new0 (MetaWaylandDataOffer);
+  offer->resource = wl_resource_create (wl_resource_get_client (target),
+                                        &wl_data_offer_interface,
+                                        wl_resource_get_version (target), 0);
+  wl_resource_set_implementation (offer->resource,
+                                  &data_offer_interface,
+                                  offer,
+                                  destroy_data_offer);
+
+  wl_data_device_send_data_offer (target, offer->resource);
+
+  for (l = mimetypes; l; l = l->next)
+    wl_data_offer_send_offer (offer->resource, l->data);
+
+  g_list_free_full (mimetypes, g_free);
+
+  return offer->resource;
+}
+
+static struct wl_resource *
+create_primary_source_offer (MetaWaylandDataDevice *data_device,
+                             struct wl_resource    *target)
+{
+  MetaWaylandDataOffer *offer;
+  MetaDisplay *display = meta_get_display ();
+  GList *mimetypes, *l;
+
+  mimetypes = meta_selection_get_mimetypes (meta_display_get_selection (display),
+                                            META_SELECTION_PRIMARY);
+  if (!mimetypes)
+    return NULL;
+
+  offer = g_slice_new0 (MetaWaylandDataOffer);
+  offer->resource = wl_resource_create (wl_resource_get_client (target),
+                                        &gtk_primary_selection_offer_interface,
+                                        wl_resource_get_version (target), 0);
+  wl_resource_set_implementation (offer->resource,
+                                  &primary_offer_interface,
+                                  offer,
+                                  destroy_primary_offer);
+
+  gtk_primary_selection_device_send_data_offer (target, offer->resource);
+
+  for (l = mimetypes; l; l = l->next)
+    gtk_primary_selection_offer_send_offer (offer->resource, l->data);
+
+  g_list_free_full (mimetypes, g_free);
+
+  return offer->resource;
+}
+
 void
 meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
 {
   MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
   struct wl_client *focus_client;
   struct wl_resource *data_device_resource, *offer;
-  MetaWaylandDataSource *source;
 
   focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
 
@@ -1898,31 +2127,15 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
   data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
   if (data_device_resource)
     {
-      source = data_device->selection_data_source;
-      if (source)
-        {
-          offer = meta_wayland_data_source_send_offer (source, data_device_resource);
-          wl_data_device_send_selection (data_device_resource, offer);
-        }
-      else
-        {
-          wl_data_device_send_selection (data_device_resource, NULL);
-        }
+      offer = create_clipboard_source_offer (data_device, data_device_resource);
+      wl_data_device_send_selection (data_device_resource, offer);
     }
 
   data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
   if (data_device_resource)
     {
-      source = data_device->primary_data_source;
-      if (source)
-        {
-          offer = meta_wayland_data_source_send_primary_offer (source, data_device_resource);
-          gtk_primary_selection_device_send_selection (data_device_resource, offer);
-        }
-      else
-        {
-          gtk_primary_selection_device_send_selection (data_device_resource, NULL);
-        }
+      offer = create_primary_source_offer (data_device, data_device_resource);
+      gtk_primary_selection_device_send_selection (data_device_resource, offer);
     }
 }
 
diff --git a/src/wayland/meta-wayland-data-device.h b/src/wayland/meta-wayland-data-device.h
index c63c65033..58b72ecf1 100644
--- a/src/wayland/meta-wayland-data-device.h
+++ b/src/wayland/meta-wayland-data-device.h
@@ -27,6 +27,7 @@
 #include <wayland-server.h>
 
 #include "clutter/clutter.h"
+#include "core/meta-selection-source.h"
 #include "wayland/meta-wayland-types.h"
 
 typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab;
@@ -69,6 +70,10 @@ struct _MetaWaylandDataDevice
   struct wl_signal selection_ownership_signal;
   struct wl_signal dnd_ownership_signal;
   struct wl_signal primary_ownership_signal;
+
+  guint selection_owner_signal_id;
+
+  MetaSelectionSource *owners[META_N_SELECTION_TYPES];
 };
 
 void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);


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