xwayland: Implement X11-to-wayland DnD
When DnD is started from an X11 client, mutter now sets up an special grab that 1) Ensures the drag source keeps receiving events, and 2) Moves an internal X Window over wayland clients as soon as the pointer enters over these. That window will act as the X-side peer for the currently focused wayland client, and will transform XdndEnter/Position/Leave/Drop messages into wayland actions. If DnD happens between X11 clients, the window will be moved away and unmapped, to let these operate as usual. https://bugzilla.gnome.org/show_bug.cgi?id=738312
This commit is contained in:
parent
ccb7833e99
commit
4a968c3b4e
@ -190,11 +190,10 @@ destroy_drag_focus (struct wl_listener *listener, void *data)
|
||||
grab->drag_focus_data_device = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_grab_focus (MetaWaylandPointerGrab *grab,
|
||||
MetaWaylandSurface *surface)
|
||||
void
|
||||
meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
|
||||
MetaWaylandSeat *seat = drag_grab->seat;
|
||||
struct wl_client *client;
|
||||
struct wl_resource *data_device_resource, *offer = NULL;
|
||||
@ -230,6 +229,21 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
|
||||
offer ? wl_resource_get_user_data (offer) : NULL);
|
||||
}
|
||||
|
||||
MetaWaylandSurface *
|
||||
meta_wayland_drag_grab_get_focus (MetaWaylandDragGrab *drag_grab)
|
||||
{
|
||||
return drag_grab->drag_focus;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_grab_focus (MetaWaylandPointerGrab *grab,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
|
||||
|
||||
meta_wayland_drag_grab_set_focus (drag_grab, surface);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_grab_motion (MetaWaylandPointerGrab *grab,
|
||||
const ClutterEvent *event)
|
||||
@ -247,7 +261,7 @@ drag_grab_motion (MetaWaylandPointerGrab *grab,
|
||||
static void
|
||||
data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
|
||||
{
|
||||
drag_grab_focus (&drag_grab->generic, NULL);
|
||||
meta_wayland_drag_grab_set_focus (drag_grab, NULL);
|
||||
|
||||
if (drag_grab->drag_origin)
|
||||
{
|
||||
@ -261,7 +275,8 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
|
||||
wl_list_remove (&drag_grab->drag_icon_listener.link);
|
||||
}
|
||||
|
||||
if (drag_grab->drag_data_source)
|
||||
if (drag_grab->drag_data_source &&
|
||||
drag_grab->drag_data_source->resource)
|
||||
wl_list_remove (&drag_grab->drag_data_source_listener.link);
|
||||
|
||||
if (drag_grab->feedback_actor)
|
||||
@ -347,6 +362,82 @@ destroy_data_device_icon (struct wl_listener *listener, void *data)
|
||||
clutter_actor_remove_all_children (drag_grab->feedback_actor);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data_device,
|
||||
struct wl_client *client,
|
||||
const MetaWaylandPointerGrabInterface *funcs,
|
||||
MetaWaylandSurface *surface,
|
||||
MetaWaylandDataSource *source,
|
||||
MetaWaylandSurface *icon_surface)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
|
||||
MetaWaylandDragGrab *drag_grab;
|
||||
ClutterPoint pos, stage_pos;
|
||||
|
||||
data_device->current_grab = drag_grab = g_slice_new0 (MetaWaylandDragGrab);
|
||||
|
||||
drag_grab->generic.interface = funcs;
|
||||
drag_grab->generic.pointer = &seat->pointer;
|
||||
|
||||
drag_grab->drag_client = client;
|
||||
drag_grab->seat = seat;
|
||||
|
||||
drag_grab->drag_origin = surface;
|
||||
drag_grab->drag_origin_listener.notify = destroy_data_device_origin;
|
||||
wl_resource_add_destroy_listener (surface->resource,
|
||||
&drag_grab->drag_origin_listener);
|
||||
|
||||
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
|
||||
clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
|
||||
pos.x, pos.y, &stage_pos.x, &stage_pos.y);
|
||||
drag_grab->drag_start_x = stage_pos.x;
|
||||
drag_grab->drag_start_y = stage_pos.y;
|
||||
|
||||
if (source)
|
||||
{
|
||||
if (source->resource)
|
||||
{
|
||||
drag_grab->drag_data_source_listener.notify = destroy_data_device_source;
|
||||
wl_resource_add_destroy_listener (source->resource,
|
||||
&drag_grab->drag_data_source_listener);
|
||||
}
|
||||
|
||||
drag_grab->drag_data_source = source;
|
||||
meta_wayland_data_device_set_dnd_source (data_device,
|
||||
drag_grab->drag_data_source);
|
||||
}
|
||||
|
||||
if (icon_surface)
|
||||
{
|
||||
drag_grab->drag_surface = icon_surface;
|
||||
|
||||
drag_grab->drag_icon_listener.notify = destroy_data_device_icon;
|
||||
wl_resource_add_destroy_listener (icon_surface->resource,
|
||||
&drag_grab->drag_icon_listener);
|
||||
|
||||
drag_grab->feedback_actor = meta_dnd_actor_new (CLUTTER_ACTOR (drag_grab->drag_origin->surface_actor),
|
||||
drag_grab->drag_start_x,
|
||||
drag_grab->drag_start_y);
|
||||
meta_feedback_actor_set_anchor (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
|
||||
-drag_grab->drag_surface->offset_x,
|
||||
-drag_grab->drag_surface->offset_y);
|
||||
clutter_actor_add_child (drag_grab->feedback_actor,
|
||||
CLUTTER_ACTOR (drag_grab->drag_surface->surface_actor));
|
||||
|
||||
meta_feedback_actor_set_position (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
|
||||
pos.x, pos.y);
|
||||
}
|
||||
|
||||
meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*) drag_grab);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_data_device_end_drag (MetaWaylandDataDevice *data_device)
|
||||
{
|
||||
if (data_device->current_grab)
|
||||
data_device_end_drag_grab (data_device->current_grab);
|
||||
}
|
||||
|
||||
static void
|
||||
data_device_start_drag (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
@ -356,9 +447,8 @@ data_device_start_drag (struct wl_client *client,
|
||||
{
|
||||
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
|
||||
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
|
||||
MetaWaylandSurface *surface = NULL;
|
||||
MetaWaylandDragGrab *drag_grab;
|
||||
ClutterPoint pos;
|
||||
MetaWaylandSurface *surface = NULL, *icon_surface = NULL;
|
||||
MetaWaylandDataSource *drag_source = NULL;
|
||||
|
||||
if (origin_resource)
|
||||
surface = wl_resource_get_user_data (origin_resource);
|
||||
@ -378,66 +468,22 @@ data_device_start_drag (struct wl_client *client,
|
||||
seat->pointer.grab != &seat->pointer.default_grab)
|
||||
return;
|
||||
|
||||
if (icon_resource)
|
||||
icon_surface = wl_resource_get_user_data (icon_resource);
|
||||
if (source_resource)
|
||||
drag_source = wl_resource_get_user_data (source_resource);
|
||||
|
||||
if (icon_resource &&
|
||||
meta_wayland_surface_set_role (wl_resource_get_user_data (icon_resource),
|
||||
meta_wayland_surface_set_role (icon_surface,
|
||||
META_WAYLAND_SURFACE_ROLE_DND,
|
||||
resource,
|
||||
WL_DATA_DEVICE_ERROR_ROLE) != 0)
|
||||
return;
|
||||
|
||||
data_device->current_grab = drag_grab = g_slice_new0 (MetaWaylandDragGrab);
|
||||
|
||||
drag_grab->generic.interface = &drag_grab_interface;
|
||||
drag_grab->generic.pointer = &seat->pointer;
|
||||
|
||||
drag_grab->drag_client = client;
|
||||
drag_grab->seat = seat;
|
||||
|
||||
drag_grab->drag_origin = surface;
|
||||
drag_grab->drag_origin_listener.notify = destroy_data_device_origin;
|
||||
wl_resource_add_destroy_listener (origin_resource,
|
||||
&drag_grab->drag_origin_listener);
|
||||
|
||||
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
|
||||
clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
|
||||
pos.x, pos.y, &pos.x, &pos.y);
|
||||
drag_grab->drag_start_x = pos.x;
|
||||
drag_grab->drag_start_y = pos.y;
|
||||
|
||||
if (source_resource)
|
||||
{
|
||||
drag_grab->drag_data_source = wl_resource_get_user_data (source_resource);
|
||||
drag_grab->drag_data_source_listener.notify = destroy_data_device_source;
|
||||
wl_resource_add_destroy_listener (source_resource,
|
||||
&drag_grab->drag_data_source_listener);
|
||||
|
||||
meta_wayland_data_device_set_dnd_source (data_device,
|
||||
drag_grab->drag_data_source);
|
||||
}
|
||||
|
||||
if (icon_resource)
|
||||
{
|
||||
drag_grab->drag_surface = wl_resource_get_user_data (icon_resource);
|
||||
drag_grab->drag_icon_listener.notify = destroy_data_device_icon;
|
||||
wl_resource_add_destroy_listener (icon_resource,
|
||||
&drag_grab->drag_icon_listener);
|
||||
|
||||
drag_grab->feedback_actor = meta_dnd_actor_new (CLUTTER_ACTOR (drag_grab->drag_origin->surface_actor),
|
||||
drag_grab->drag_start_x,
|
||||
drag_grab->drag_start_y);
|
||||
meta_feedback_actor_set_anchor (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
|
||||
-drag_grab->drag_surface->offset_x,
|
||||
-drag_grab->drag_surface->offset_y);
|
||||
clutter_actor_add_child (drag_grab->feedback_actor,
|
||||
CLUTTER_ACTOR (drag_grab->drag_surface->surface_actor));
|
||||
|
||||
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
|
||||
meta_feedback_actor_set_position (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
|
||||
pos.x, pos.y);
|
||||
}
|
||||
|
||||
meta_wayland_pointer_set_focus (&seat->pointer, NULL);
|
||||
meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*)drag_grab);
|
||||
meta_wayland_data_device_start_drag (data_device, client,
|
||||
&drag_grab_interface,
|
||||
surface, drag_source, icon_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -96,4 +96,18 @@ void meta_wayland_data_source_send (MetaWaylandDataSource *source,
|
||||
const MetaWaylandDragDestFuncs *
|
||||
meta_wayland_data_device_get_drag_dest_funcs (void);
|
||||
|
||||
void meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data_device,
|
||||
struct wl_client *client,
|
||||
const MetaWaylandPointerGrabInterface *funcs,
|
||||
MetaWaylandSurface *surface,
|
||||
MetaWaylandDataSource *source,
|
||||
MetaWaylandSurface *icon_surface);
|
||||
|
||||
void meta_wayland_data_device_end_drag (MetaWaylandDataDevice *data_device);
|
||||
|
||||
void meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
|
||||
MetaWaylandSurface *surface);
|
||||
MetaWaylandSurface *
|
||||
meta_wayland_drag_grab_get_focus (MetaWaylandDragGrab *drag_grab);
|
||||
|
||||
#endif /* META_WAYLAND_DATA_DEVICE_H */
|
||||
|
@ -64,7 +64,7 @@ typedef struct {
|
||||
Window window;
|
||||
Window owner;
|
||||
Time timestamp;
|
||||
const MetaWaylandDataSource *source;
|
||||
MetaWaylandDataSource *source; /* owned by MetaWaylandDataDevice */
|
||||
WaylandSelectionData *wayland_selection;
|
||||
X11SelectionData *x11_selection;
|
||||
|
||||
@ -73,7 +73,10 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
MetaSelectionBridge selection;
|
||||
Window dnd_dest;
|
||||
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;
|
||||
} MetaDndBridge;
|
||||
|
||||
struct _MetaXWaylandSelection {
|
||||
@ -239,12 +242,93 @@ xdnd_send_drop (MetaXWaylandSelection *selection_data,
|
||||
}
|
||||
|
||||
static void
|
||||
meta_xwayland_init_dnd (void)
|
||||
xdnd_send_finished (MetaXWaylandSelection *selection_data,
|
||||
Window dest,
|
||||
gboolean accepted)
|
||||
{
|
||||
guint i;
|
||||
MetaDndBridge *selection = &selection_data->dnd;
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
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] = selection->dnd_window;
|
||||
|
||||
if (accepted)
|
||||
{
|
||||
xev.xclient.data.l[1] = 1; /* Drop successful */
|
||||
xev.xclient.data.l[2] = xdnd_atoms[ATOM_DND_ACTION_COPY];
|
||||
}
|
||||
|
||||
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
|
||||
}
|
||||
|
||||
static void
|
||||
xdnd_send_status (MetaXWaylandSelection *selection_data,
|
||||
Window dest,
|
||||
gboolean accepted)
|
||||
{
|
||||
MetaDndBridge *selection = &selection_data->dnd;
|
||||
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] = selection->dnd_window;
|
||||
xev.xclient.data.l[1] = 1 << 1; /* Bit 2: dest wants XdndPosition messages */
|
||||
|
||||
if (accepted)
|
||||
{
|
||||
xev.xclient.data.l[1] |= 1 << 0; /* Bit 1: dest accepts the drop */
|
||||
xev.xclient.data.l[4] = xdnd_atoms[ATOM_DND_ACTION_COPY];
|
||||
}
|
||||
|
||||
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_xwayland_init_dnd (MetaXWaylandManager *manager)
|
||||
{
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
MetaDndBridge *dnd = &manager->selection_data->dnd;
|
||||
XSetWindowAttributes attributes;
|
||||
guint32 i, version = XDND_VERSION;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_xwayland_shutdown_dnd (MetaXWaylandManager *manager)
|
||||
{
|
||||
MetaDndBridge *dnd = &manager->selection_data->dnd;
|
||||
|
||||
XDestroyWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
|
||||
dnd->dnd_window);
|
||||
dnd->dnd_window = None;
|
||||
}
|
||||
|
||||
/* X11/Wayland data bridges */
|
||||
@ -289,6 +373,21 @@ x11_selection_data_free (X11SelectionData *data)
|
||||
g_slice_free (X11SelectionData, data);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_selection_data_finish (MetaSelectionBridge *selection,
|
||||
gboolean success)
|
||||
{
|
||||
if (!selection->x11_selection)
|
||||
return;
|
||||
|
||||
if (selection == &selection->x11_selection->selection_data->dnd.selection)
|
||||
xdnd_send_finished (selection->x11_selection->selection_data,
|
||||
selection->owner, success);
|
||||
|
||||
g_clear_pointer (&selection->x11_selection,
|
||||
(GDestroyNotify) x11_selection_data_free);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_data_write_cb (GObject *object,
|
||||
GAsyncResult *res,
|
||||
@ -317,10 +416,7 @@ x11_data_write_cb (GObject *object,
|
||||
}
|
||||
|
||||
if (!data->incr)
|
||||
{
|
||||
g_clear_pointer (&selection->x11_selection,
|
||||
(GDestroyNotify) x11_selection_data_free);
|
||||
}
|
||||
x11_selection_data_finish (selection, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -577,8 +673,7 @@ meta_xwayland_selection_get_incr_chunk (MetaWaylandCompositor *compositor,
|
||||
else
|
||||
{
|
||||
/* Transfer has completed */
|
||||
g_clear_pointer (&selection->x11_selection,
|
||||
(GDestroyNotify) x11_selection_data_free);
|
||||
x11_selection_data_finish (selection, TRUE);
|
||||
}
|
||||
|
||||
XFree (prop_ret);
|
||||
@ -599,8 +694,8 @@ meta_x11_source_send (MetaWaylandDataSource *source,
|
||||
else
|
||||
type_atom = gdk_x11_get_xatom_by_name (mime_type);
|
||||
|
||||
g_clear_pointer (&selection->x11_selection,
|
||||
(GDestroyNotify) x11_selection_data_free);
|
||||
/* Ensure we close previous transactions */
|
||||
x11_selection_data_finish (selection, FALSE);
|
||||
|
||||
/* Takes ownership of fd */
|
||||
selection->x11_selection =
|
||||
@ -619,6 +714,14 @@ static void
|
||||
meta_x11_source_target (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type)
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
MetaSelectionBridge *selection = source->user_data;
|
||||
|
||||
if (selection->selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
|
||||
{
|
||||
xdnd_send_status (compositor->xwayland_manager.selection_data,
|
||||
selection->owner, mime_type != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -709,6 +812,9 @@ meta_xwayland_data_source_fetch_mimetype_list (MetaWaylandDataSource *source,
|
||||
Atom *atoms, type_ret, utf8_string;
|
||||
int format_ret;
|
||||
|
||||
if (source->mime_types.size != 0)
|
||||
return TRUE;
|
||||
|
||||
utf8_string = gdk_x11_get_xatom_by_name ("UTF8_STRING");
|
||||
XGetWindowProperty (xdisplay, window, prop,
|
||||
0, /* offset */
|
||||
@ -994,15 +1100,106 @@ meta_xwayland_selection_handle_selection_request (MetaWaylandCompositor *composi
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static MetaWaylandSurface *
|
||||
pick_drop_surface (MetaWaylandCompositor *compositor,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
MetaWindow *focus_window = NULL;
|
||||
ClutterPoint pos;
|
||||
|
||||
clutter_event_get_coords (event, &pos.x, &pos.y);
|
||||
focus_window = meta_stack_get_default_focus_window_at_point (display->screen->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 ());
|
||||
MetaDndBridge *dnd = &compositor->xwayland_manager.selection_data->dnd;
|
||||
MetaWaylandSurface *focus = NULL;
|
||||
|
||||
focus = pick_drop_surface (compositor, event);
|
||||
dnd->focus_surface = focus;
|
||||
|
||||
if (meta_wayland_drag_grab_get_focus (drag_grab) == focus)
|
||||
return;
|
||||
|
||||
if (focus &&
|
||||
focus->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
{
|
||||
XMapWindow (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 ();
|
||||
MetaDndBridge *dnd = &compositor->xwayland_manager.selection_data->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;
|
||||
|
||||
meta_wayland_pointer_send_button (&seat->pointer, event);
|
||||
}
|
||||
|
||||
static const MetaWaylandPointerGrabInterface drag_xgrab_interface = {
|
||||
drag_xgrab_focus,
|
||||
drag_xgrab_motion,
|
||||
drag_xgrab_button,
|
||||
};
|
||||
|
||||
static gboolean
|
||||
meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor,
|
||||
XEvent *xevent)
|
||||
{
|
||||
XClientMessageEvent *event = (XClientMessageEvent *) xevent;
|
||||
MetaSelectionBridge *selection = &compositor->xwayland_manager.selection_data->dnd.selection;
|
||||
MetaDndBridge *dnd = &compositor->xwayland_manager.selection_data->dnd;
|
||||
MetaWaylandSeat *seat = compositor->seat;
|
||||
|
||||
/* Source side messages */
|
||||
if (event->window == selection->window)
|
||||
if (event->window == dnd->selection.window)
|
||||
{
|
||||
MetaWaylandDataSource *data_source;
|
||||
|
||||
@ -1029,6 +1226,83 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
/* Dest side messages */
|
||||
else if (dnd->selection.source &&
|
||||
compositor->seat->data_device.current_grab &&
|
||||
(Window) event->data.l[0] == dnd->selection.owner)
|
||||
{
|
||||
MetaWaylandDragGrab *drag_grab = compositor->seat->data_device.current_grab;
|
||||
MetaWaylandSurface *drag_focus = meta_wayland_drag_grab_get_focus (drag_grab);
|
||||
|
||||
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;
|
||||
|
||||
/* We only need to fetch once */
|
||||
if (dnd->selection.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->selection.source,
|
||||
mimetype);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fetch mimetypes from type list */
|
||||
meta_xwayland_data_source_fetch_mimetype_list (dnd->selection.source,
|
||||
event->data.l[0],
|
||||
xdnd_atoms[ATOM_DND_TYPE_LIST]);
|
||||
}
|
||||
|
||||
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;
|
||||
ClutterPoint pos;
|
||||
|
||||
motion = clutter_event_new (CLUTTER_MOTION);
|
||||
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
|
||||
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);
|
||||
|
||||
meta_wayland_surface_drag_dest_motion (drag_focus, motion);
|
||||
xdnd_send_status (compositor->xwayland_manager.selection_data,
|
||||
(Window) event->data.l[0],
|
||||
dnd->selection.source->has_target);
|
||||
|
||||
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])
|
||||
{
|
||||
meta_wayland_surface_drag_dest_drop (drag_focus);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -1083,6 +1357,35 @@ meta_xwayland_selection_handle_xfixes_selection_notify (MetaWaylandCompositor *c
|
||||
XFlush (xdisplay);
|
||||
}
|
||||
}
|
||||
else if (selection->selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
|
||||
{
|
||||
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
|
||||
MetaXWaylandSelection *selection_data = compositor->xwayland_manager.selection_data;
|
||||
|
||||
selection->owner = event->owner;
|
||||
|
||||
if (event->owner != None && event->owner != selection->window)
|
||||
{
|
||||
MetaWaylandSurface *focus;
|
||||
|
||||
focus = compositor->seat->pointer.focus_surface;
|
||||
selection->source = meta_wayland_data_source_new (&meta_x11_source_funcs,
|
||||
NULL, selection);
|
||||
meta_wayland_data_device_set_dnd_source (&compositor->seat->data_device,
|
||||
selection->source);
|
||||
|
||||
meta_wayland_data_device_start_drag (data_device,
|
||||
wl_resource_get_client (focus->resource),
|
||||
&drag_xgrab_interface,
|
||||
focus, selection->source,
|
||||
NULL);
|
||||
}
|
||||
else if (event->owner == None)
|
||||
{
|
||||
meta_wayland_data_device_end_drag (data_device);
|
||||
XUnmapWindow (xdisplay, selection_data->dnd.dnd_window);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -1199,7 +1502,7 @@ meta_xwayland_init_selection (void)
|
||||
|
||||
manager->selection_data = g_slice_new0 (MetaXWaylandSelection);
|
||||
|
||||
meta_xwayland_init_dnd ();
|
||||
meta_xwayland_init_dnd (manager);
|
||||
init_selection_bridge (&manager->selection_data->clipboard,
|
||||
gdk_x11_get_xatom_by_name ("CLIPBOARD"),
|
||||
&compositor->seat->data_device.selection_ownership_signal);
|
||||
@ -1223,6 +1526,7 @@ meta_xwayland_shutdown_selection (void)
|
||||
wl_display_next_serial (compositor->wayland_display));
|
||||
}
|
||||
|
||||
meta_xwayland_shutdown_dnd (manager);
|
||||
shutdown_selection_bridge (&selection->clipboard);
|
||||
shutdown_selection_bridge (&selection->dnd.selection);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user