[mutter] wayland: Implement support for the x-rootwindow-drop target



commit 3d67bfda14e8fb52f882dc257b7020bfedd4a7fb
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Mar 9 16:53:26 2016 +0100

    wayland: Implement support for the x-rootwindow-drop target
    
    This target is set whenever DnD moves towards an area between surfaces.
    Although no offer is set and data is actually not read, drag sources
    offering this mimetype will be able to behave just like they used to
    do in X11.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=762104

 src/wayland/meta-wayland-data-device.c |   83 ++++++++++++++++++++++++++++++++
 1 files changed, 83 insertions(+), 0 deletions(-)
---
diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c
index 28b870e..c7b324f 100644
--- a/src/wayland/meta-wayland-data-device.c
+++ b/src/wayland/meta-wayland-data-device.c
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <glib.h>
+#include <glib-unix.h>
 
 #include "meta-wayland-data-device.h"
 #include "meta-wayland-data-device-private.h"
@@ -39,6 +40,8 @@
 
 #include "gtk-primary-selection-server-protocol.h"
 
+#define ROOTWINDOW_DROP_MIME "application/x-rootwindow-drop"
+
 #define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
                      WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
                      WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
@@ -726,6 +729,30 @@ meta_wayland_drag_grab_set_source (MetaWaylandDragGrab   *drag_grab,
                        drag_grab);
 }
 
+static void
+meta_wayland_drag_source_fake_acceptance (MetaWaylandDataSource *source,
+                                          const gchar           *mimetype)
+{
+  uint32_t actions, user_action, action = 0;
+
+  actions = meta_wayland_data_source_get_actions (source);
+  user_action = meta_wayland_data_source_get_user_action (source);
+
+  /* Pick a suitable action */
+  if ((user_action & actions) != 0)
+    action = user_action;
+  else if (actions != 0)
+    action = 1 << (ffs (actions) - 1);
+
+  /* Bail out if there is none, source didn't cooperate */
+  if (action == 0)
+    return;
+
+  meta_wayland_data_source_target (source, mimetype);
+  meta_wayland_data_source_set_current_action (source, action);
+  meta_wayland_data_source_set_has_target (source, TRUE);
+}
+
 void
 meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
                                   MetaWaylandSurface  *surface)
@@ -750,6 +777,12 @@ meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
   if (source)
     meta_wayland_data_source_set_current_offer (source, NULL);
 
+  if (!surface && source &&
+      meta_wayland_data_source_has_mime_type (source, ROOTWINDOW_DROP_MIME))
+    meta_wayland_drag_source_fake_acceptance (source, ROOTWINDOW_DROP_MIME);
+  else if (source)
+    meta_wayland_data_source_target (source, NULL);
+
   if (!surface)
     return;
 
@@ -855,6 +888,47 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
   g_slice_free (MetaWaylandDragGrab, drag_grab);
 }
 
+static gboolean
+on_fake_read_hup (GIOChannel   *channel,
+                  GIOCondition  condition,
+                  gpointer      data)
+{
+  MetaWaylandDataSource *source = data;
+
+  meta_wayland_data_source_notify_finish (source);
+  g_io_channel_shutdown (channel, FALSE, NULL);
+  g_io_channel_unref (channel);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+meta_wayland_data_source_fake_read (MetaWaylandDataSource *source,
+                                    const gchar           *mimetype)
+{
+  GIOChannel *channel;
+  int p[2];
+
+  if (!g_unix_open_pipe (p, FD_CLOEXEC, NULL))
+    {
+      meta_wayland_data_source_notify_finish (source);
+      return;
+    }
+
+  if (!g_unix_set_fd_nonblocking (p[0], TRUE, NULL) ||
+      !g_unix_set_fd_nonblocking (p[1], TRUE, NULL))
+    {
+      meta_wayland_data_source_notify_finish (source);
+      close (p[0]);
+      close (p[1]);
+      return;
+    }
+
+  meta_wayland_data_source_send (source, mimetype, p[1]);
+  channel = g_io_channel_unix_new (p[0]);
+  g_io_add_watch (channel, G_IO_HUP, on_fake_read_hup, source);
+}
+
 static void
 drag_grab_button (MetaWaylandPointerGrab *grab,
                  const ClutterEvent     *event)
@@ -883,6 +957,15 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
           meta_wayland_source_update_in_ask (source);
           success = TRUE;
         }
+      else if (!drag_grab->drag_focus && source &&
+               meta_wayland_data_source_has_target (source) &&
+               meta_wayland_data_source_get_current_action (source) &&
+               meta_wayland_data_source_has_mime_type (source, ROOTWINDOW_DROP_MIME))
+        {
+          /* Perform a fake read, that will lead to notify_finish() being called */
+          meta_wayland_data_source_fake_read (source, ROOTWINDOW_DROP_MIME);
+          success = TRUE;
+        }
       else
         {
           meta_wayland_data_source_cancel (source);


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