[mutter/wip/primary-selection: 21/21] WIP: Implement the primary selection protocol



commit e022dab1265493a37901dd5fd908ed7fb99a36ff
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Feb 3 18:39:58 2016 +0100

    WIP: Implement the primary selection protocol

 src/Makefile.am                                |    2 +
 src/wayland/meta-wayland-data-device-private.h |    6 +
 src/wayland/meta-wayland-data-device.c         |  282 +++++++++++++++++++++++-
 src/wayland/meta-wayland-data-device.h         |    5 +
 src/wayland/meta-xwayland-selection.c          |   16 ++-
 5 files changed, 301 insertions(+), 10 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 8dedc81..9e26738 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -45,6 +45,8 @@ mutter_built_sources = \
 
 if HAVE_WAYLAND
 mutter_built_sources += \
+       primary-selection-unstable-v1-protocol.c                        \
+       primary-selection-unstable-v1-server-protocol.h                 \
        pointer-gestures-unstable-v1-protocol.c                         \
        pointer-gestures-unstable-v1-server-protocol.h                  \
        gtk-shell-protocol.c                    \
diff --git a/src/wayland/meta-wayland-data-device-private.h b/src/wayland/meta-wayland-data-device-private.h
index 9f5377a..5e65130 100644
--- a/src/wayland/meta-wayland-data-device-private.h
+++ b/src/wayland/meta-wayland-data-device-private.h
@@ -31,4 +31,10 @@ G_DECLARE_FINAL_TYPE (MetaWaylandDataSourceWayland,
                       META, WAYLAND_DATA_SOURCE_WAYLAND,
                       MetaWaylandDataSource);
 
+#define META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY (meta_wayland_data_source_primary_get_type ())
+G_DECLARE_FINAL_TYPE (MetaWaylandDataSourcePrimary,
+                      meta_wayland_data_source_primary,
+                      META, WAYLAND_DATA_SOURCE_PRIMARY,
+                      MetaWaylandDataSourceWayland);
+
 #endif /* META_WAYLAND_DATA_DEVICE_PRIVATE_H */
diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c
index b0652a0..4aef2c8 100644
--- a/src/wayland/meta-wayland-data-device.c
+++ b/src/wayland/meta-wayland-data-device.c
@@ -37,6 +37,8 @@
 #include "meta-wayland-private.h"
 #include "meta-dnd-actor-private.h"
 
+#include "primary-selection-unstable-v1-server-protocol.h"
+
 #define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
                      WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
                      WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
@@ -70,13 +72,22 @@ typedef struct _MetaWaylandDataSourceWayland
   struct wl_resource *resource;
 } MetaWaylandDataSourceWayland;
 
+typedef struct _MetaWaylandDataSourcePrimary
+{
+  MetaWaylandDataSourceWayland parent;
+} MetaWaylandDataSourcePrimary;
+
 G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandDataSource, meta_wayland_data_source,
                             G_TYPE_OBJECT);
 G_DEFINE_TYPE (MetaWaylandDataSourceWayland, meta_wayland_data_source_wayland,
                META_TYPE_WAYLAND_DATA_SOURCE);
+G_DEFINE_TYPE (MetaWaylandDataSourcePrimary, meta_wayland_data_source_primary,
+               META_TYPE_WAYLAND_DATA_SOURCE_WAYLAND);
 
 static MetaWaylandDataSource *
 meta_wayland_data_source_wayland_new (struct wl_resource *resource);
+static MetaWaylandDataSource *
+meta_wayland_data_source_primary_new (struct wl_resource *resource);
 
 static void
 drag_grab_data_source_destroyed (gpointer data, GObject *where_the_object_was);
@@ -160,7 +171,8 @@ static void
 meta_wayland_data_source_target (MetaWaylandDataSource *source,
                                  const char *mime_type)
 {
-  META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target (source, mime_type);
+  if (META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target)
+    META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target (source, mime_type);
 }
 
 void
@@ -430,6 +442,11 @@ static const struct wl_data_offer_interface data_offer_interface = {
   data_offer_set_actions,
 };
 
+static const struct zwp_primary_selection_offer_v1_interface primary_offer_interface = {
+  data_offer_receive,
+  data_offer_destroy,
+};
+
 static void
 meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source)
 {
@@ -500,6 +517,35 @@ 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),
+                                        &zwp_primary_selection_offer_v1_interface,
+                                        wl_resource_get_version (target), 0);
+  wl_resource_set_implementation (offer->resource,
+                                  &primary_offer_interface,
+                                  offer,
+                                  destroy_data_offer);
+
+  zwp_primary_selection_device_v1_send_data_offer (target, offer->resource);
+
+  wl_array_for_each (p, &priv->mime_types)
+    zwp_primary_selection_offer_v1_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)
@@ -561,6 +607,11 @@ static struct wl_data_source_interface data_source_interface = {
   data_source_set_actions
 };
 
+static struct zwp_primary_selection_source_v1_interface primary_source_interface = {
+  data_source_offer,
+  data_source_destroy,
+};
+
 struct _MetaWaylandDragGrab {
   MetaWaylandPointerGrab  generic;
 
@@ -1109,6 +1160,43 @@ meta_wayland_data_source_wayland_class_init (MetaWaylandDataSourceWaylandClass *
 }
 
 static void
+meta_wayland_data_source_primary_send (MetaWaylandDataSource *source,
+                                       const gchar           *mime_type,
+                                       gint                   fd)
+{
+  MetaWaylandDataSourceWayland *source_wayland;
+
+  source_wayland = (MetaWaylandDataSourceWayland *) source;
+  zwp_primary_selection_source_v1_send_send (source_wayland->resource,
+                                             mime_type, fd);
+}
+
+static void
+meta_wayland_data_source_primary_cancel (MetaWaylandDataSource *source)
+{
+  MetaWaylandDataSourceWayland *source_wayland;
+
+  source_wayland = (MetaWaylandDataSourceWayland *) source;
+  zwp_primary_selection_source_v1_send_cancelled (source_wayland->resource);
+}
+
+static void
+meta_wayland_data_source_primary_init (MetaWaylandDataSourcePrimary *source_primary)
+{
+}
+
+static void
+meta_wayland_data_source_primary_class_init (MetaWaylandDataSourcePrimaryClass *klass)
+{
+  MetaWaylandDataSourceClass *data_source_class =
+    META_WAYLAND_DATA_SOURCE_CLASS (klass);
+
+  data_source_class->send = meta_wayland_data_source_primary_send;
+  data_source_class->cancel = meta_wayland_data_source_primary_cancel;
+  data_source_class->target = NULL;
+}
+
+static void
 meta_wayland_data_source_finalize (GObject *object)
 {
   MetaWaylandDataSource *source = META_WAYLAND_DATA_SOURCE (object);
@@ -1352,6 +1440,92 @@ static const struct wl_data_device_interface data_device_interface = {
 };
 
 static void
+primary_source_destroyed (gpointer  data,
+                          GObject  *object_was_here)
+{
+  MetaWaylandDataDevice *data_device = data;
+  MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
+  struct wl_client *focus_client = NULL;
+
+  data_device->primary_data_source = NULL;
+
+  focus_client = meta_wayland_keyboard_get_focus_client (&seat->keyboard);
+  if (focus_client)
+    {
+      struct wl_resource *data_device_resource;
+
+      data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
+      if (data_device_resource)
+        zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
+    }
+}
+
+void
+meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
+                                      MetaWaylandDataSource *source)
+{
+  MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
+  struct wl_resource *data_device_resource, *offer;
+  struct wl_client *focus_client;
+
+  if (data_device->primary_data_source)
+    {
+      meta_wayland_data_source_cancel (data_device->primary_data_source);
+      g_object_weak_unref (G_OBJECT (data_device->primary_data_source),
+                           primary_source_destroyed,
+                           data_device);
+      data_device->primary_data_source = NULL;
+    }
+
+  data_device->primary_data_source = source;
+
+  focus_client = meta_wayland_keyboard_get_focus_client (&seat->keyboard);
+  if (focus_client)
+    {
+      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);
+              zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
+            }
+          else
+            {
+              zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
+            }
+        }
+    }
+
+  if (source)
+    {
+      g_object_weak_ref (G_OBJECT (source),
+                         primary_source_destroyed,
+                         data_device);
+    }
+
+  wl_signal_emit (&data_device->primary_ownership_signal, source);
+}
+
+static void
+primary_device_set_selection (struct wl_client   *client,
+                              struct wl_resource *resource,
+                              struct wl_resource *source_resource)
+{
+  MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
+  MetaWaylandDataSource *source;
+
+  source = wl_resource_get_user_data (source_resource);
+  meta_wayland_data_device_set_primary (data_device, source);
+}
+
+static const struct zwp_primary_selection_device_v1_interface primary_device_interface = {
+  primary_device_set_selection,
+  data_device_release,
+};
+
+static void
 destroy_data_source (struct wl_resource *resource)
 {
   MetaWaylandDataSourceWayland *source = wl_resource_get_user_data (resource);
@@ -1390,6 +1564,48 @@ static const struct wl_data_device_manager_interface manager_interface = {
 };
 
 static void
+primary_device_manager_create_source (struct wl_client   *client,
+                                      struct wl_resource *manager_resource,
+                                      guint32             id)
+{
+  struct wl_resource *source_resource;
+
+  source_resource =
+    wl_resource_create (client, &zwp_primary_selection_source_v1_interface,
+                        wl_resource_get_version (manager_resource),
+                        id);
+  meta_wayland_data_source_primary_new (source_resource);
+}
+
+static void
+primary_device_manager_get_device (struct wl_client   *client,
+                                   struct wl_resource *manager_resource,
+                                   guint32             id,
+                                   struct wl_resource *seat_resource)
+{
+  MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
+  struct wl_resource *cr;
+
+  cr = wl_resource_create (client, &zwp_primary_selection_device_v1_interface,
+                           wl_resource_get_version (manager_resource), id);
+  wl_resource_set_implementation (cr, &primary_device_interface,
+                                  &seat->data_device, unbind_resource);
+  wl_list_insert (&seat->data_device.primary_resource_list, wl_resource_get_link (cr));
+}
+
+static void
+primary_device_manager_destroy (struct wl_client *client,
+                                struct wl_resource *manager_resource)
+{
+}
+
+static const struct zwp_primary_selection_device_manager_v1_interface primary_manager_interface = {
+  primary_device_manager_create_source,
+  primary_device_manager_get_device,
+  primary_device_manager_destroy
+};
+
+static void
 bind_manager (struct wl_client *client,
               void *data, guint32 version, guint32 id)
 {
@@ -1398,6 +1614,19 @@ bind_manager (struct wl_client *client,
   wl_resource_set_implementation (resource, &manager_interface, NULL, NULL);
 }
 
+static void
+bind_primary_manager (struct wl_client *client,
+                      void             *data,
+                      uint32_t          version,
+                      uint32_t          id)
+{
+  struct wl_resource *resource;
+
+  resource = wl_resource_create (client, &zwp_primary_selection_device_manager_v1_interface,
+                                 version, id);
+  wl_resource_set_implementation (resource, &primary_manager_interface, NULL, NULL);
+}
+
 void
 meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor)
 {
@@ -1406,13 +1635,20 @@ meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor)
                        META_WL_DATA_DEVICE_MANAGER_VERSION,
                        NULL, bind_manager) == NULL)
     g_error ("Could not create data_device");
+
+  if (wl_global_create (compositor->wayland_display,
+                       &zwp_primary_selection_device_manager_v1_interface,
+                       1, NULL, bind_primary_manager) == NULL)
+    g_error ("Could not create data_device");
 }
 
 void
 meta_wayland_data_device_init (MetaWaylandDataDevice *data_device)
 {
   wl_list_init (&data_device->resource_list);
+  wl_list_init (&data_device->primary_resource_list);
   wl_signal_init (&data_device->selection_ownership_signal);
+  wl_signal_init (&data_device->primary_ownership_signal);
   wl_signal_init (&data_device->dnd_ownership_signal);
 }
 
@@ -1435,17 +1671,32 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
     return;
 
   data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
-  if (!data_device_resource)
-    return;
+  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);
+    }
 
-  source = data_device->selection_data_source;
-  if (source)
+  data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
+  if (data_device_resource)
     {
-      offer = meta_wayland_data_source_send_offer (source, data_device_resource);
-      wl_data_device_send_selection (data_device_resource, offer);
+      source = data_device->primary_data_source;
+      if (source)
+        {
+          offer = meta_wayland_data_source_send_primary_offer (source, data_device_resource);
+          zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
+        }
+      else
+        {
+          zwp_primary_selection_device_v1_send_selection (data_device_resource, NULL);
+        }
     }
-  else
-    wl_data_device_send_selection (data_device_resource, NULL);
 }
 
 gboolean
@@ -1486,6 +1737,19 @@ meta_wayland_data_source_wayland_new (struct wl_resource *resource)
   return META_WAYLAND_DATA_SOURCE (source_wayland);
 }
 
+static MetaWaylandDataSource *
+meta_wayland_data_source_primary_new (struct wl_resource *resource)
+{
+  MetaWaylandDataSourceWayland *source_wayland =
+   g_object_new (META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY, NULL);
+
+  source_wayland->resource = resource;
+  wl_resource_set_implementation (resource, &primary_source_interface,
+                                  source_wayland, destroy_data_source);
+
+  return META_WAYLAND_DATA_SOURCE (source_wayland);
+}
+
 gboolean
 meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
                                         const gchar           *mime_type)
diff --git a/src/wayland/meta-wayland-data-device.h b/src/wayland/meta-wayland-data-device.h
index cdb4f05..d779502 100644
--- a/src/wayland/meta-wayland-data-device.h
+++ b/src/wayland/meta-wayland-data-device.h
@@ -57,13 +57,16 @@ struct _MetaWaylandDataDevice
   uint32_t selection_serial;
   MetaWaylandDataSource *selection_data_source;
   MetaWaylandDataSource *dnd_data_source;
+  MetaWaylandDataSource *primary_data_source;
   struct wl_listener selection_data_source_listener;
   struct wl_list resource_list;
+  struct wl_list primary_resource_list;
   MetaWaylandDragGrab *current_grab;
   struct wl_client *focus_client;
 
   struct wl_signal selection_ownership_signal;
   struct wl_signal dnd_ownership_signal;
+  struct wl_signal primary_ownership_signal;
 };
 
 void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);
@@ -80,6 +83,8 @@ void meta_wayland_data_device_set_dnd_source     (MetaWaylandDataDevice *data_de
 void meta_wayland_data_device_set_selection      (MetaWaylandDataDevice *data_device,
                                                   MetaWaylandDataSource *source,
                                                   guint32 serial);
+void meta_wayland_data_device_set_primary        (MetaWaylandDataDevice *data_device,
+                                                  MetaWaylandDataSource *source);
 
 gboolean meta_wayland_data_source_add_mime_type  (MetaWaylandDataSource *source,
                                                   const gchar           *mime_type);
diff --git a/src/wayland/meta-xwayland-selection.c b/src/wayland/meta-xwayland-selection.c
index 5d3405a..cbafbef 100644
--- a/src/wayland/meta-xwayland-selection.c
+++ b/src/wayland/meta-xwayland-selection.c
@@ -91,6 +91,7 @@ struct _MetaWaylandDataSourceXWayland
 
 struct _MetaXWaylandSelection {
   MetaSelectionBridge clipboard;
+  MetaSelectionBridge primary;
   MetaDndBridge dnd;
 };
 
@@ -396,6 +397,8 @@ atom_to_selection_bridge (MetaWaylandCompositor *compositor,
 
   if (selection_atom == selection_data->clipboard.selection_atom)
     return &selection_data->clipboard;
+  else if (selection_atom == selection_data->primary.selection_atom)
+    return &selection_data->primary;
   else if (selection_atom == selection_data->dnd.selection.selection_atom)
     return &selection_data->dnd.selection;
   else
@@ -530,6 +533,8 @@ data_device_get_active_source_for_atom (MetaWaylandDataDevice *data_device,
 {
   if (selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
     return data_device->selection_data_source;
+  else if (selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
+    return data_device->primary_data_source;
   else if (selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
     return data_device->dnd_data_source;
   else
@@ -1058,6 +1063,10 @@ meta_xwayland_selection_get_x11_targets (MetaWaylandCompositor *compositor,
           meta_wayland_data_device_set_selection (&compositor->seat->data_device, data_source,
                                                   wl_display_next_serial (compositor->wayland_display));
         }
+      else if (selection->selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
+        {
+          meta_wayland_data_device_set_primary (&compositor->seat->data_device, data_source);
+        }
     }
   else
     g_object_unref (data_source);
@@ -1529,7 +1538,8 @@ meta_xwayland_selection_handle_xfixes_selection_notify (MetaWaylandCompositor *c
   if (!selection)
     return FALSE;
 
-  if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD"))
+  if (selection->selection_atom == gdk_x11_get_xatom_by_name ("CLIPBOARD") ||
+      selection->selection_atom == gdk_x11_get_xatom_by_name ("PRIMARY"))
     {
       if (event->owner == None)
         {
@@ -1712,6 +1722,9 @@ meta_xwayland_init_selection (void)
   init_selection_bridge (&manager->selection_data->clipboard,
                          gdk_x11_get_xatom_by_name ("CLIPBOARD"),
                          &compositor->seat->data_device.selection_ownership_signal);
+  init_selection_bridge (&manager->selection_data->primary,
+                         gdk_x11_get_xatom_by_name ("PRIMARY"),
+                         &compositor->seat->data_device.primary_ownership_signal);
   init_selection_bridge (&manager->selection_data->dnd.selection,
                          xdnd_atoms[ATOM_DND_SELECTION],
                          &compositor->seat->data_device.dnd_ownership_signal);
@@ -1730,6 +1743,7 @@ meta_xwayland_shutdown_selection (void)
 
   meta_xwayland_shutdown_dnd (manager);
   shutdown_selection_bridge (&selection->clipboard);
+  shutdown_selection_bridge (&selection->primary);
   shutdown_selection_bridge (&selection->dnd.selection);
 
   g_slice_free (MetaXWaylandSelection, selection);


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