[mutter/gnome-40] wayland/xdnd: Use multiple DnD X11 peers



commit 232e3c20b5f26621f8d1ae5cf7ea2f7e042ceda5
Author: Olivier Fourdan <ofourdan redhat com>
Date:   Mon Feb 21 16:25:25 2022 +0100

    wayland/xdnd: Use multiple DnD X11 peers
    
    When a drag and drop occurs from an X11 client to a Wayland native
    client, mutter uses an internal X11 window as a peer for the DnD  drop
    site.
    
    That internal X11 window is moved and resized to match the Wayland
    native windows as the drag destination moves.
    
    When moving from one Wayland native window to another Wayland native
    window, the same X11 window is used, and as a result no DND enter/leave
    events is emitted.
    
    In that case, the drop may occur on the wrong Wayland native window,
    because no new XdndEnter/XdndLeave event were emitted.
    
    To avoid that issue, use a pair of X11 windows instead of just one and
    alternate between the two when repicking a new drop surface, so that
    moving from a Wayland surface to another will always generate the
    expected enter/leave events that we rely on.
    
    Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2136
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2305>
    (cherry picked from commit fe41e69eea9627f80cf793ec58c65cf3ca79a1a6)

 src/wayland/meta-xwayland-dnd.c | 129 ++++++++++++++++++++++++++++++----------
 1 file changed, 99 insertions(+), 30 deletions(-)
---
diff --git a/src/wayland/meta-xwayland-dnd.c b/src/wayland/meta-xwayland-dnd.c
index de61ccf73f..fc0b0c297f 100644
--- a/src/wayland/meta-xwayland-dnd.c
+++ b/src/wayland/meta-xwayland-dnd.c
@@ -57,9 +57,10 @@ struct _MetaXWaylandDnd
   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_window[2]; /* Mutter-internal windows, act as peer on wayland drop sites */
   Window dnd_dest; /* X11 drag dest window */
   guint32 last_motion_time;
+  int current_dnd_window;
 };
 
 enum
@@ -133,6 +134,86 @@ atom_to_action (Atom atom)
     return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
 }
 
+static Window
+current_dnd_window (MetaXWaylandDnd *dnd)
+{
+  return dnd->dnd_window[dnd->current_dnd_window];
+}
+
+static Window
+next_dnd_window (MetaXWaylandDnd *dnd)
+{
+  dnd->current_dnd_window =
+    (dnd->current_dnd_window + 1) % G_N_ELEMENTS (dnd->dnd_window);
+
+  return current_dnd_window (dnd);
+}
+
+static void
+create_dnd_windows (MetaXWaylandDnd *dnd,
+                    Display         *xdisplay)
+{
+  XSetWindowAttributes attributes;
+  guint32 version = XDND_VERSION;
+  int i;
+
+  attributes.event_mask = PropertyChangeMask | SubstructureNotifyMask;
+  attributes.override_redirect = True;
+
+  for (i = 0; i < G_N_ELEMENTS (dnd->dnd_window); i++)
+    {
+      dnd->dnd_window[i] =
+        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[i],
+                       xdnd_atoms[ATOM_DND_AWARE],
+                       XA_ATOM, 32, PropModeReplace,
+                       (guchar*) &version, 1);
+    }
+}
+
+static void
+destroy_dnd_windows (MetaXWaylandDnd *dnd,
+                     Display         *xdisplay)
+{
+  int i;
+
+  for (i = 0; i < G_N_ELEMENTS (dnd->dnd_window); i++)
+    {
+      XDestroyWindow (xdisplay, dnd->dnd_window[i]);
+      dnd->dnd_window[i] = None;
+    }
+}
+
+static void
+hide_dnd_window (MetaXWaylandDnd *dnd,
+                 Display         *xdisplay,
+                 int              index)
+{
+  g_assert (index < G_N_ELEMENTS (dnd->dnd_window));
+
+  XMoveResizeWindow (xdisplay, dnd->dnd_window[index], -1, -1, 1, 1);
+  XUnmapWindow (xdisplay, dnd->dnd_window[index]);
+}
+
+static void
+hide_all_dnd_windows (MetaXWaylandDnd *dnd,
+                      Display         *xdisplay)
+{
+  int i;
+
+  for (i = 0; i < G_N_ELEMENTS (dnd->dnd_window); i++)
+    hide_dnd_window (dnd, xdisplay, i);
+}
+
 static void
 xdnd_send_enter (MetaXWaylandDnd *dnd,
                  Window           dest)
@@ -295,7 +376,7 @@ xdnd_send_finished (MetaXWaylandDnd *dnd,
   xev.xclient.format = 32;
   xev.xclient.window = dest;
 
-  xev.xclient.data.l[0] = dnd->dnd_window;
+  xev.xclient.data.l[0] = current_dnd_window (dnd);
 
   if (accepted)
     {
@@ -325,7 +406,7 @@ xdnd_send_status (MetaXWaylandDnd *dnd,
   xev.xclient.format = 32;
   xev.xclient.window = dest;
 
-  xev.xclient.data.l[0] = dnd->dnd_window;
+  xev.xclient.data.l[0] = current_dnd_window (dnd);
   xev.xclient.data.l[1] = 1 << 1; /* Bit 2: dest wants XdndPosition messages */
   xev.xclient.data.l[4] = action_to_atom (action);
 
@@ -357,8 +438,7 @@ meta_xwayland_end_dnd_grab (MetaWaylandDataDevice *data_device,
       meta_wayland_data_device_end_drag (data_device);
     }
 
-  XMoveResizeWindow (xdisplay, dnd->dnd_window, -1, -1, 1, 1);
-  XUnmapWindow (xdisplay, dnd->dnd_window);
+  hide_all_dnd_windows (dnd, xdisplay);
 }
 
 static void
@@ -650,7 +730,8 @@ repick_drop_surface (MetaWaylandCompositor *compositor,
                      MetaWaylandDragGrab   *drag_grab,
                      const ClutterEvent    *event)
 {
-  Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+  MetaX11Display *x11_display = meta_get_display ()->x11_display;
+  Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
   MetaXWaylandDnd *dnd = compositor->xwayland_manager.dnd;
   MetaWaylandSurface *focus = NULL;
   MetaWindow *focus_window;
@@ -669,8 +750,13 @@ repick_drop_surface (MetaWaylandCompositor *compositor,
   if (focus_window &&
       focus_window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
     {
-      XMapRaised (xdisplay, dnd->dnd_window);
-      XMoveResizeWindow (xdisplay, dnd->dnd_window,
+      Window dnd_window;
+
+      hide_dnd_window (dnd, xdisplay, dnd->current_dnd_window);
+      dnd_window = next_dnd_window (dnd);
+
+      XMapRaised (xdisplay, dnd_window);
+      XMoveResizeWindow (xdisplay, dnd_window,
                          focus_window->rect.x,
                          focus_window->rect.y,
                          focus_window->rect.width,
@@ -678,8 +764,7 @@ repick_drop_surface (MetaWaylandCompositor *compositor,
     }
   else
     {
-      XMoveResizeWindow (xdisplay, dnd->dnd_window, -1, -1, 1, 1);
-      XUnmapWindow (xdisplay, dnd->dnd_window);
+      hide_all_dnd_windows (dnd, xdisplay);
     }
 }
 
@@ -947,8 +1032,7 @@ 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;
+  guint32 i;
 
   g_assert (manager->dnd == NULL);
 
@@ -957,22 +1041,8 @@ meta_xwayland_init_dnd (Display *xdisplay)
   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);
+  create_dnd_windows (dnd, xdisplay);
+  dnd->current_dnd_window = 0;
 }
 
 void
@@ -984,8 +1054,7 @@ meta_xwayland_shutdown_dnd (Display *xdisplay)
 
   g_assert (dnd != NULL);
 
-  XDestroyWindow (xdisplay, dnd->dnd_window);
-  dnd->dnd_window = None;
+  destroy_dnd_windows (dnd, xdisplay);
 
   g_free (dnd);
   manager->dnd = NULL;


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