diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2016-03-09 16:53:26 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2016-03-11 14:47:02 +0100 |
commit | 3d67bfda14e8fb52f882dc257b7020bfedd4a7fb (patch) | |
tree | f8f102e6f9b9a2f32632840dfc5e6264e2d2a684 /src | |
parent | 51e4491a9f3966958a9fe2367936ffa0d00c21d9 (diff) | |
download | mutter-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.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 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); |