summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2016-03-09 16:53:26 +0100
committerCarlos Garnacho <carlosg@gnome.org>2016-03-11 14:47:02 +0100
commit3d67bfda14e8fb52f882dc257b7020bfedd4a7fb (patch)
treef8f102e6f9b9a2f32632840dfc5e6264e2d2a684 /src
parent51e4491a9f3966958a9fe2367936ffa0d00c21d9 (diff)
downloadmutter-3d67bfda14e8fb52f882dc257b7020bfedd4a7fb.tar.gz
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
Diffstat (limited to 'src')
-rw-r--r--src/wayland/meta-wayland-data-device.c83
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 28b870e6a..c7b324f65 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);