diff options
author | Florian Müllner <fmuellner@gnome.org> | 2021-07-19 00:01:24 +0200 |
---|---|---|
committer | Florian Müllner <fmuellner@gnome.org> | 2021-07-19 00:03:33 +0200 |
commit | 952865a86ebb08f97263cfdbfe38b7adc20e4560 (patch) | |
tree | 1f9347628656210b03ceee4fae83beb21491d1eb /src/wayland/meta-xwayland-dnd.c | |
parent | 7862f143937e43dca0513af3a24dabfb4d0db4fc (diff) | |
download | mutter-master.tar.gz |
Replace contents with redirect messagemaster
The default development branch is now `main`. This commit only exists
on `master` to point people towards that.
See https://gitlab.gnome.org/GNOME/glib/-/issues/2348 for details.
Diffstat (limited to 'src/wayland/meta-xwayland-dnd.c')
-rw-r--r-- | src/wayland/meta-xwayland-dnd.c | 991 |
1 files changed, 0 insertions, 991 deletions
diff --git a/src/wayland/meta-xwayland-dnd.c b/src/wayland/meta-xwayland-dnd.c deleted file mode 100644 index a3148ed95..000000000 --- a/src/wayland/meta-xwayland-dnd.c +++ /dev/null @@ -1,991 +0,0 @@ -/* - * Copyright © 2012 Intel Corporation - * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of the copyright holders not be used in - * advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. The copyright holders make - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF - * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* The file is loosely based on xwayland/selection.c from Weston */ - -#include "config.h" - -#include <fcntl.h> -#include <unistd.h> -#include <string.h> -#include <glib-unix.h> -#include <gio/gunixoutputstream.h> -#include <gio/gunixinputstream.h> -#include <gdk/gdkx.h> -#include <X11/Xatom.h> -#include <X11/extensions/Xfixes.h> - -#include "meta/meta-x11-errors.h" -#include "wayland/meta-wayland-data-device.h" -#include "wayland/meta-xwayland-private.h" -#include "wayland/meta-xwayland-dnd-private.h" -#include "wayland/meta-xwayland.h" -#include "x11/meta-x11-display-private.h" - -#define INCR_CHUNK_SIZE (128 * 1024) -#define XDND_VERSION 5 - -struct _MetaWaylandDataSourceXWayland -{ - MetaWaylandDataSource parent; - MetaXWaylandDnd *dnd; - gboolean has_utf8_string_atom; -}; - -struct _MetaXWaylandDnd -{ - Window owner; - Time client_message_timestamp; - MetaWaylandDataSource *source; /* owned by MetaWaylandDataDevice */ - MetaWaylandSurface *focus_surface; - Window dnd_window; /* Mutter-internal window, acts as peer on wayland drop sites */ - Window dnd_dest; /* X11 drag dest window */ - guint32 last_motion_time; -}; - -enum -{ - ATOM_DND_SELECTION, - ATOM_DND_AWARE, - ATOM_DND_STATUS, - ATOM_DND_POSITION, - ATOM_DND_ENTER, - ATOM_DND_LEAVE, - ATOM_DND_DROP, - ATOM_DND_FINISHED, - ATOM_DND_PROXY, - ATOM_DND_TYPE_LIST, - ATOM_DND_ACTION_MOVE, - ATOM_DND_ACTION_COPY, - ATOM_DND_ACTION_ASK, - ATOM_DND_ACTION_PRIVATE, - N_DND_ATOMS -}; - -/* Matches order in enum above */ -const gchar *atom_names[] = { - "XdndSelection", - "XdndAware", - "XdndStatus", - "XdndPosition", - "XdndEnter", - "XdndLeave", - "XdndDrop", - "XdndFinished", - "XdndProxy", - "XdndTypeList", - "XdndActionMove", - "XdndActionCopy", - "XdndActionAsk", - "XdndActionPrivate", - NULL -}; - -Atom xdnd_atoms[N_DND_ATOMS]; - -G_DEFINE_TYPE (MetaWaylandDataSourceXWayland, meta_wayland_data_source_xwayland, - META_TYPE_WAYLAND_DATA_SOURCE); - -/* XDND helpers */ -static Atom -action_to_atom (uint32_t action) -{ - if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) - return xdnd_atoms[ATOM_DND_ACTION_COPY]; - else if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) - return xdnd_atoms[ATOM_DND_ACTION_MOVE]; - else if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) - return xdnd_atoms[ATOM_DND_ACTION_ASK]; - else - return None; -} - -static enum wl_data_device_manager_dnd_action -atom_to_action (Atom atom) -{ - if (atom == xdnd_atoms[ATOM_DND_ACTION_COPY] || - atom == xdnd_atoms[ATOM_DND_ACTION_PRIVATE]) - return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; - else if (atom == xdnd_atoms[ATOM_DND_ACTION_MOVE]) - return WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; - else if (atom == xdnd_atoms[ATOM_DND_ACTION_ASK]) - return WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; - else - return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; -} - -static void -xdnd_send_enter (MetaXWaylandDnd *dnd, - Window dest) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaX11Display *x11_display = meta_get_display ()->x11_display; - Display *xdisplay = x11_display->xdisplay; - MetaWaylandDataSource *data_source; - XEvent xev = { 0 }; - gchar **p; - struct wl_array *source_mime_types; - - meta_x11_error_trap_push (x11_display); - - data_source = compositor->seat->data_device.dnd_data_source; - xev.xclient.type = ClientMessage; - xev.xclient.message_type = xdnd_atoms[ATOM_DND_ENTER]; - xev.xclient.format = 32; - xev.xclient.window = dest; - - xev.xclient.data.l[0] = x11_display->selection.xwindow; - xev.xclient.data.l[1] = XDND_VERSION << 24; /* version */ - xev.xclient.data.l[2] = xev.xclient.data.l[3] = xev.xclient.data.l[4] = 0; - - source_mime_types = meta_wayland_data_source_get_mime_types (data_source); - if (source_mime_types->size <= 3) - { - /* The mimetype atoms fit in this same message */ - gint i = 2; - - wl_array_for_each (p, source_mime_types) - { - xev.xclient.data.l[i++] = gdk_x11_get_xatom_by_name (*p); - } - } - else - { - /* We have more than 3 mimetypes, we must set up - * the mimetype list as a XdndTypeList property. - */ - g_autofree Atom *atomlist = NULL; - gint i = 0; - - xev.xclient.data.l[1] |= 1; - atomlist = g_new0 (Atom, source_mime_types->size); - - wl_array_for_each (p, source_mime_types) - { - atomlist[i++] = gdk_x11_get_xatom_by_name (*p); - } - - XChangeProperty (xdisplay, x11_display->selection.xwindow, - xdnd_atoms[ATOM_DND_TYPE_LIST], - XA_ATOM, 32, PropModeReplace, - (guchar *) atomlist, i); - } - - XSendEvent (xdisplay, dest, False, NoEventMask, &xev); - - if (meta_x11_error_trap_pop_with_return (x11_display) != Success) - g_critical ("Error sending XdndEnter"); -} - -static void -xdnd_send_leave (MetaXWaylandDnd *dnd, - Window dest) -{ - MetaX11Display *x11_display = meta_get_display ()->x11_display; - Display *xdisplay = x11_display->xdisplay; - XEvent xev = { 0 }; - - xev.xclient.type = ClientMessage; - xev.xclient.message_type = xdnd_atoms[ATOM_DND_LEAVE]; - xev.xclient.format = 32; - xev.xclient.window = dest; - xev.xclient.data.l[0] = x11_display->selection.xwindow; - - meta_x11_error_trap_push (x11_display); - XSendEvent (xdisplay, dest, False, NoEventMask, &xev); - meta_x11_error_trap_pop (x11_display); -} - -static void -xdnd_send_position (MetaXWaylandDnd *dnd, - Window dest, - uint32_t time, - int x, - int y) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaWaylandDataSource *source = compositor->seat->data_device.dnd_data_source; - MetaX11Display *x11_display = meta_get_display ()->x11_display; - Display *xdisplay = x11_display->xdisplay; - uint32_t action = 0, user_action, actions; - XEvent xev = { 0 }; - - user_action = meta_wayland_data_source_get_user_action (source); - meta_wayland_data_source_get_actions (source, &actions); - - if (user_action & actions) - action = user_action; - if (!action) - action = actions; - - xev.xclient.type = ClientMessage; - xev.xclient.message_type = xdnd_atoms[ATOM_DND_POSITION]; - xev.xclient.format = 32; - xev.xclient.window = dest; - - xev.xclient.data.l[0] = x11_display->selection.xwindow; - xev.xclient.data.l[1] = 0; - xev.xclient.data.l[2] = (x << 16) | y; - xev.xclient.data.l[3] = time; - xev.xclient.data.l[4] = action_to_atom (action); - - meta_x11_error_trap_push (x11_display); - XSendEvent (xdisplay, dest, False, NoEventMask, &xev); - - if (meta_x11_error_trap_pop_with_return (x11_display) != Success) - g_critical ("Error sending XdndPosition"); -} - -static void -xdnd_send_drop (MetaXWaylandDnd *dnd, - Window dest, - uint32_t time) -{ - MetaX11Display *x11_display = meta_get_display ()->x11_display; - Display *xdisplay = x11_display->xdisplay; - XEvent xev = { 0 }; - - xev.xclient.type = ClientMessage; - xev.xclient.message_type = xdnd_atoms[ATOM_DND_DROP]; - xev.xclient.format = 32; - xev.xclient.window = dest; - - xev.xclient.data.l[0] = x11_display->selection.xwindow; - xev.xclient.data.l[2] = time; - - meta_x11_error_trap_push (x11_display); - XSendEvent (xdisplay, dest, False, NoEventMask, &xev); - - if (meta_x11_error_trap_pop_with_return (x11_display) != Success) - g_critical ("Error sending XdndDrop"); -} - -static void -xdnd_send_finished (MetaXWaylandDnd *dnd, - Window dest, - gboolean accepted) -{ - MetaX11Display *x11_display = meta_get_display ()->x11_display; - Display *xdisplay = x11_display->xdisplay; - MetaWaylandDataSource *source = dnd->source; - uint32_t action = 0; - XEvent xev = { 0 }; - - xev.xclient.type = ClientMessage; - xev.xclient.message_type = xdnd_atoms[ATOM_DND_FINISHED]; - xev.xclient.format = 32; - xev.xclient.window = dest; - - xev.xclient.data.l[0] = dnd->dnd_window; - - if (accepted) - { - action = meta_wayland_data_source_get_current_action (source); - xev.xclient.data.l[1] = 1; /* Drop successful */ - xev.xclient.data.l[2] = action_to_atom (action); - } - - meta_x11_error_trap_push (x11_display); - XSendEvent (xdisplay, dest, False, NoEventMask, &xev); - - if (meta_x11_error_trap_pop_with_return (x11_display) != Success) - g_critical ("Error sending XdndFinished"); -} - -static void -xdnd_send_status (MetaXWaylandDnd *dnd, - Window dest, - uint32_t action) -{ - MetaX11Display *x11_display = meta_get_display ()->x11_display; - Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - XEvent xev = { 0 }; - - xev.xclient.type = ClientMessage; - xev.xclient.message_type = xdnd_atoms[ATOM_DND_STATUS]; - xev.xclient.format = 32; - xev.xclient.window = dest; - - xev.xclient.data.l[0] = dnd->dnd_window; - xev.xclient.data.l[1] = 1 << 1; /* Bit 2: dest wants XdndPosition messages */ - xev.xclient.data.l[4] = action_to_atom (action); - - if (xev.xclient.data.l[4]) - xev.xclient.data.l[1] |= 1 << 0; /* Bit 1: dest accepts the drop */ - - meta_x11_error_trap_push (x11_display); - XSendEvent (xdisplay, dest, False, NoEventMask, &xev); - - if (meta_x11_error_trap_pop_with_return (x11_display) != Success) - g_critical ("Error sending Xdndstatus"); -} - -static void -meta_xwayland_end_dnd_grab (MetaWaylandDataDevice *data_device, - gboolean success) -{ - Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaXWaylandManager *manager = &compositor->xwayland_manager; - MetaWaylandDragGrab *drag_grab = compositor->seat->data_device.current_grab; - MetaXWaylandDnd *dnd = manager->dnd; - - if (drag_grab) - { - if (!success && dnd->source) - meta_wayland_data_source_set_current_offer (dnd->source, NULL); - - meta_wayland_data_device_end_drag (data_device); - } - - XMoveResizeWindow (xdisplay, dnd->dnd_window, -1, -1, 1, 1); - XUnmapWindow (xdisplay, dnd->dnd_window); -} - -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 transfer DnD selection: %s", error->message); - g_error_free (error); - } - - g_output_stream_close (stream, NULL, NULL); - g_object_unref (stream); -} - -static void -meta_x11_source_send (MetaWaylandDataSource *source, - const gchar *mime_type, - gint fd) -{ - MetaDisplay *display = meta_get_display (); - GOutputStream *stream; - - stream = g_unix_output_stream_new (fd, TRUE); - meta_selection_transfer_async (meta_display_get_selection (display), - META_SELECTION_DND, - mime_type, - -1, - stream, - NULL, - (GAsyncReadyCallback) transfer_cb, - stream); -} - -static void -meta_x11_source_target (MetaWaylandDataSource *source, - const gchar *mime_type) -{ - MetaWaylandDataSourceXWayland *source_xwayland = - META_WAYLAND_DATA_SOURCE_XWAYLAND (source); - MetaXWaylandDnd *dnd = source_xwayland->dnd; - uint32_t action = 0; - - if (mime_type) - action = meta_wayland_data_source_get_current_action (source); - - xdnd_send_status (dnd, dnd->owner, action); -} - -static void -meta_x11_source_cancel (MetaWaylandDataSource *source) -{ - MetaWaylandDataSourceXWayland *source_xwayland = - META_WAYLAND_DATA_SOURCE_XWAYLAND (source); - MetaXWaylandDnd *dnd = source_xwayland->dnd; - - xdnd_send_finished (dnd, dnd->owner, FALSE); -} - -static void -meta_x11_source_action (MetaWaylandDataSource *source, - uint32_t action) -{ - MetaWaylandDataSourceXWayland *source_xwayland = - META_WAYLAND_DATA_SOURCE_XWAYLAND (source); - MetaXWaylandDnd *dnd = source_xwayland->dnd; - - if (!meta_wayland_data_source_has_target (source)) - action = 0; - - xdnd_send_status (dnd, dnd->owner, action); -} - -static void -meta_x11_source_drop_performed (MetaWaylandDataSource *source) -{ -} - -static void -meta_x11_source_drag_finished (MetaWaylandDataSource *source) -{ - MetaWaylandDataSourceXWayland *source_xwayland = - META_WAYLAND_DATA_SOURCE_XWAYLAND (source); - MetaXWaylandDnd *dnd = source_xwayland->dnd; - MetaX11Display *x11_display = meta_get_display ()->x11_display; - uint32_t action = meta_wayland_data_source_get_current_action (source); - - if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) - { - Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - - /* Request data deletion on the drag source */ - XConvertSelection (xdisplay, - xdnd_atoms[ATOM_DND_SELECTION], - gdk_x11_get_xatom_by_name ("DELETE"), - gdk_x11_get_xatom_by_name ("_META_SELECTION"), - x11_display->selection.xwindow, - META_CURRENT_TIME); - } - - xdnd_send_finished (dnd, dnd->owner, TRUE); -} - -static void -meta_wayland_data_source_xwayland_init (MetaWaylandDataSourceXWayland *source_xwayland) -{ -} - -static void -meta_wayland_data_source_xwayland_class_init (MetaWaylandDataSourceXWaylandClass *klass) -{ - MetaWaylandDataSourceClass *data_source_class = - META_WAYLAND_DATA_SOURCE_CLASS (klass); - - data_source_class->send = meta_x11_source_send; - data_source_class->target = meta_x11_source_target; - data_source_class->cancel = meta_x11_source_cancel; - data_source_class->action = meta_x11_source_action; - data_source_class->drop_performed = meta_x11_source_drop_performed; - data_source_class->drag_finished = meta_x11_source_drag_finished; -} - -static MetaWaylandDataSource * -meta_wayland_data_source_xwayland_new (MetaXWaylandDnd *dnd) -{ - MetaWaylandDataSourceXWayland *source_xwayland; - - source_xwayland = g_object_new (META_TYPE_WAYLAND_DATA_SOURCE_XWAYLAND, NULL); - source_xwayland->dnd = dnd; - - return META_WAYLAND_DATA_SOURCE (source_xwayland); -} - -static void -meta_x11_drag_dest_focus_in (MetaWaylandDataDevice *data_device, - MetaWaylandSurface *surface, - MetaWaylandDataOffer *offer) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - - dnd->dnd_dest = meta_wayland_surface_get_window (surface)->xwindow; - xdnd_send_enter (dnd, dnd->dnd_dest); -} - -static void -meta_x11_drag_dest_focus_out (MetaWaylandDataDevice *data_device, - MetaWaylandSurface *surface) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - - xdnd_send_leave (dnd, dnd->dnd_dest); - dnd->dnd_dest = None; -} - -static void -meta_x11_drag_dest_motion (MetaWaylandDataDevice *data_device, - MetaWaylandSurface *surface, - const ClutterEvent *event) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - guint32 time; - gfloat x, y; - - time = clutter_event_get_time (event); - clutter_event_get_coords (event, &x, &y); - xdnd_send_position (dnd, dnd->dnd_dest, time, x, y); -} - -static void -meta_x11_drag_dest_drop (MetaWaylandDataDevice *data_device, - MetaWaylandSurface *surface) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - - xdnd_send_drop (dnd, dnd->dnd_dest, - meta_display_get_current_time_roundtrip (meta_get_display ())); -} - -static void -meta_x11_drag_dest_update (MetaWaylandDataDevice *data_device, - MetaWaylandSurface *surface) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - MetaWaylandSeat *seat = compositor->seat; - graphene_point_t pos; - - clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), - seat->pointer->device, NULL, &pos, NULL); - xdnd_send_position (dnd, dnd->dnd_dest, - clutter_get_current_event_time (), - pos.x, pos.y); -} - -static const MetaWaylandDragDestFuncs meta_x11_drag_dest_funcs = { - meta_x11_drag_dest_focus_in, - meta_x11_drag_dest_focus_out, - meta_x11_drag_dest_motion, - meta_x11_drag_dest_drop, - meta_x11_drag_dest_update -}; - -const MetaWaylandDragDestFuncs * -meta_xwayland_selection_get_drag_dest_funcs (void) -{ - return &meta_x11_drag_dest_funcs; -} - -static gboolean -meta_xwayland_data_source_fetch_mimetype_list (MetaWaylandDataSource *source, - Window window, - Atom prop) -{ - MetaWaylandDataSourceXWayland *source_xwayland = - META_WAYLAND_DATA_SOURCE_XWAYLAND (source); - Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - gulong nitems_ret, bytes_after_ret, i; - Atom *atoms, type_ret, utf8_string; - int format_ret; - struct wl_array *source_mime_types; - - source_mime_types = meta_wayland_data_source_get_mime_types (source); - if (source_mime_types->size != 0) - return TRUE; - - utf8_string = gdk_x11_get_xatom_by_name ("UTF8_STRING"); - XGetWindowProperty (xdisplay, window, prop, - 0, /* offset */ - 0x1fffffff, /* length */ - False, /* delete */ - AnyPropertyType, - &type_ret, - &format_ret, - &nitems_ret, - &bytes_after_ret, - (guchar **) &atoms); - - if (nitems_ret == 0 || type_ret != XA_ATOM) - { - XFree (atoms); - return FALSE; - } - - for (i = 0; i < nitems_ret; i++) - { - const gchar *mime_type; - - if (atoms[i] == utf8_string) - { - meta_wayland_data_source_add_mime_type (source, - "text/plain;charset=utf-8"); - source_xwayland->has_utf8_string_atom = TRUE; - } - - mime_type = gdk_x11_get_xatom_name (atoms[i]); - meta_wayland_data_source_add_mime_type (source, mime_type); - } - - XFree (atoms); - - return TRUE; -} - -static MetaWaylandSurface * -pick_drop_surface (MetaWaylandCompositor *compositor, - const ClutterEvent *event) -{ - MetaDisplay *display = meta_get_display (); - MetaWindow *focus_window = NULL; - graphene_point_t pos; - - clutter_event_get_coords (event, &pos.x, &pos.y); - focus_window = meta_stack_get_default_focus_window_at_point (display->stack, - NULL, NULL, - pos.x, pos.y); - return focus_window ? focus_window->surface : NULL; -} - -static void -repick_drop_surface (MetaWaylandCompositor *compositor, - MetaWaylandDragGrab *drag_grab, - const ClutterEvent *event) -{ - Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - MetaWaylandSurface *focus = NULL; - MetaWindow *focus_window; - - focus = pick_drop_surface (compositor, event); - if (dnd->focus_surface == focus) - return; - - dnd->focus_surface = focus; - - if (focus) - focus_window = meta_wayland_surface_get_window (focus); - else - focus_window = NULL; - - if (focus_window && - focus_window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) - { - XMapRaised (xdisplay, dnd->dnd_window); - XMoveResizeWindow (xdisplay, dnd->dnd_window, - focus_window->rect.x, - focus_window->rect.y, - focus_window->rect.width, - focus_window->rect.height); - } - else - { - XMoveResizeWindow (xdisplay, dnd->dnd_window, -1, -1, 1, 1); - XUnmapWindow (xdisplay, dnd->dnd_window); - } -} - -static void -drag_xgrab_focus (MetaWaylandPointerGrab *grab, - MetaWaylandSurface *surface) -{ - /* Do not update the focus here. First, the surface may perfectly - * be the X11 source DnD icon window's, so we can only be fooled - * here. Second, delaying focus handling to XdndEnter/Leave - * makes us do the negotiation orderly on the X11 side. - */ -} - -static void -drag_xgrab_motion (MetaWaylandPointerGrab *grab, - const ClutterEvent *event) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - MetaWaylandSeat *seat = compositor->seat; - - repick_drop_surface (compositor, - (MetaWaylandDragGrab *) grab, - event); - - dnd->last_motion_time = clutter_event_get_time (event); - meta_wayland_pointer_send_motion (seat->pointer, event); -} - -static void -drag_xgrab_button (MetaWaylandPointerGrab *grab, - const ClutterEvent *event) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaWaylandSeat *seat = compositor->seat; - MetaWaylandDataSource *data_source; - - meta_wayland_pointer_send_button (seat->pointer, event); - data_source = compositor->seat->data_device.dnd_data_source; - - if (seat->pointer->button_count == 0 && - (!meta_wayland_drag_grab_get_focus ((MetaWaylandDragGrab *) grab) || - meta_wayland_data_source_get_current_action (data_source) == - WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE)) - meta_xwayland_end_dnd_grab (&seat->data_device, FALSE); -} - -static const MetaWaylandPointerGrabInterface drag_xgrab_interface = { - drag_xgrab_focus, - drag_xgrab_motion, - drag_xgrab_button, -}; - -static gboolean -meta_xwayland_dnd_handle_client_message (MetaWaylandCompositor *compositor, - XEvent *xevent) -{ - XClientMessageEvent *event = (XClientMessageEvent *) xevent; - MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - MetaWaylandSeat *seat = compositor->seat; - MetaX11Display *x11_display = meta_get_display ()->x11_display; - - /* Source side messages */ - if (event->window == x11_display->selection.xwindow) - { - MetaWaylandDataSource *data_source; - uint32_t action = 0; - - data_source = compositor->seat->data_device.dnd_data_source; - - if (!data_source) - return FALSE; - - if (event->message_type == xdnd_atoms[ATOM_DND_STATUS]) - { - /* The first bit in data.l[1] is set if the drag was accepted */ - meta_wayland_data_source_set_has_target (data_source, - (event->data.l[1] & 1) != 0); - - /* data.l[4] contains the action atom */ - if (event->data.l[4]) - action = atom_to_action ((Atom) event->data.l[4]); - - meta_wayland_data_source_set_current_action (data_source, action); - return TRUE; - } - else if (event->message_type == xdnd_atoms[ATOM_DND_FINISHED]) - { - /* Reject messages mid-grab */ - if (compositor->seat->data_device.current_grab) - return FALSE; - - meta_wayland_data_source_notify_finish (data_source); - return TRUE; - } - } - /* Dest side messages */ - else if (dnd->source && - compositor->seat->data_device.current_grab && - (Window) event->data.l[0] == dnd->owner) - { - MetaWaylandDragGrab *drag_grab = compositor->seat->data_device.current_grab; - MetaWaylandSurface *drag_focus = meta_wayland_drag_grab_get_focus (drag_grab); - - if (!drag_focus && - event->message_type != xdnd_atoms[ATOM_DND_ENTER]) - return FALSE; - - if (event->message_type == xdnd_atoms[ATOM_DND_ENTER]) - { - /* Bit 1 in data.l[1] determines whether there's 3 or less mimetype - * atoms (and are thus contained in this same message), or whether - * there's more than 3 and we need to check the XdndTypeList property - * for the full list. - */ - if (!(event->data.l[1] & 1)) - { - /* Mimetypes are contained in this message */ - const gchar *mimetype; - gint i; - struct wl_array *source_mime_types; - - /* We only need to fetch once */ - source_mime_types = - meta_wayland_data_source_get_mime_types (dnd->source); - if (source_mime_types->size == 0) - { - for (i = 2; i <= 4; i++) - { - if (event->data.l[i] == None) - break; - - mimetype = gdk_x11_get_xatom_name (event->data.l[i]); - meta_wayland_data_source_add_mime_type (dnd->source, - mimetype); - } - } - } - else - { - /* Fetch mimetypes from type list */ - meta_xwayland_data_source_fetch_mimetype_list (dnd->source, - event->data.l[0], - xdnd_atoms[ATOM_DND_TYPE_LIST]); - } - - meta_wayland_data_source_set_actions (dnd->source, - WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | - WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | - WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK); - meta_wayland_drag_grab_set_focus (drag_grab, dnd->focus_surface); - return TRUE; - } - else if (event->message_type == xdnd_atoms[ATOM_DND_POSITION]) - { - ClutterEvent *motion; - graphene_point_t pos; - uint32_t action = 0; - - dnd->client_message_timestamp = event->data.l[3]; - - motion = clutter_event_new (CLUTTER_MOTION); - clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), - seat->pointer->device, NULL, &pos, NULL); - clutter_event_set_coords (motion, pos.x, pos.y); - clutter_event_set_device (motion, seat->pointer->device); - clutter_event_set_source_device (motion, seat->pointer->device); - clutter_event_set_time (motion, dnd->last_motion_time); - - action = atom_to_action ((Atom) event->data.l[4]); - meta_wayland_data_source_set_user_action (dnd->source, action); - - meta_wayland_surface_drag_dest_motion (drag_focus, motion); - xdnd_send_status (dnd, (Window) event->data.l[0], - meta_wayland_data_source_get_current_action (dnd->source)); - - clutter_event_free (motion); - return TRUE; - } - else if (event->message_type == xdnd_atoms[ATOM_DND_LEAVE]) - { - meta_wayland_drag_grab_set_focus (drag_grab, NULL); - return TRUE; - } - else if (event->message_type == xdnd_atoms[ATOM_DND_DROP]) - { - dnd->client_message_timestamp = event->data.l[2]; - meta_wayland_surface_drag_dest_drop (drag_focus); - meta_xwayland_end_dnd_grab (&seat->data_device, TRUE); - return TRUE; - } - } - - return FALSE; -} - -static gboolean -meta_xwayland_dnd_handle_xfixes_selection_notify (MetaWaylandCompositor *compositor, - XEvent *xevent) -{ - XFixesSelectionNotifyEvent *event = (XFixesSelectionNotifyEvent *) xevent; - MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd; - MetaWaylandDataDevice *data_device = &compositor->seat->data_device; - MetaX11Display *x11_display = meta_get_display ()->x11_display; - MetaWaylandSurface *focus; - - if (event->selection != xdnd_atoms[ATOM_DND_SELECTION]) - return FALSE; - - dnd->owner = event->owner; - focus = compositor->seat->pointer->focus_surface; - - if (event->owner != None && event->owner != x11_display->selection.xwindow && - focus && meta_xwayland_is_xwayland_surface (focus)) - { - dnd->source = meta_wayland_data_source_xwayland_new (dnd); - meta_wayland_data_device_set_dnd_source (&compositor->seat->data_device, - dnd->source); - - meta_wayland_data_device_start_drag (data_device, - wl_resource_get_client (focus->resource), - &drag_xgrab_interface, - focus, dnd->source, - NULL); - } - else if (event->owner == None) - { - meta_xwayland_end_dnd_grab (data_device, FALSE); - g_clear_object (&dnd->source); - } - - return FALSE; -} - -gboolean -meta_xwayland_dnd_handle_event (XEvent *xevent) -{ - MetaWaylandCompositor *compositor; - - compositor = meta_wayland_compositor_get_default (); - - if (!compositor->xwayland_manager.dnd) - return FALSE; - - switch (xevent->type) - { - case ClientMessage: - return meta_xwayland_dnd_handle_client_message (compositor, xevent); - default: - { - MetaX11Display *x11_display = meta_get_display ()->x11_display; - - if (xevent->type - x11_display->xfixes_event_base == XFixesSelectionNotify) - return meta_xwayland_dnd_handle_xfixes_selection_notify (compositor, xevent); - - return FALSE; - } - } -} - -void -meta_xwayland_init_dnd (Display *xdisplay) -{ - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - MetaXWaylandManager *manager = &compositor->xwayland_manager; - MetaXWaylandDnd *dnd = manager->dnd; - XSetWindowAttributes attributes; - guint32 i, version = XDND_VERSION; - - g_assert (manager->dnd == NULL); - - manager->dnd = dnd = g_new0 (MetaXWaylandDnd, 1); - - for (i = 0; i < N_DND_ATOMS; i++) - xdnd_atoms[i] = gdk_x11_get_xatom_by_name (atom_names[i]); - - attributes.event_mask = PropertyChangeMask | SubstructureNotifyMask; - attributes.override_redirect = True; - - dnd->dnd_window = XCreateWindow (xdisplay, - gdk_x11_window_get_xid (gdk_get_default_root_window ()), - -1, -1, 1, 1, - 0, /* border width */ - 0, /* depth */ - InputOnly, /* class */ - CopyFromParent, /* visual */ - CWEventMask | CWOverrideRedirect, - &attributes); - XChangeProperty (xdisplay, dnd->dnd_window, - xdnd_atoms[ATOM_DND_AWARE], - XA_ATOM, 32, PropModeReplace, - (guchar*) &version, 1); -} - -void -meta_xwayland_shutdown_dnd (MetaXWaylandManager *manager, - Display *xdisplay) -{ - MetaXWaylandDnd *dnd = manager->dnd; - - g_assert (dnd != NULL); - - XDestroyWindow (xdisplay, dnd->dnd_window); - dnd->dnd_window = None; - - g_free (dnd); - manager->dnd = NULL; -} |