xserver: Branch 'master' - 12 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Apr 10 08:59:38 UTC 2024


 hw/xwayland/xwayland-dmabuf.c         |    4 
 hw/xwayland/xwayland-glamor-gbm.c     |    5 
 hw/xwayland/xwayland-glamor.c         |    9 
 hw/xwayland/xwayland-glamor.h         |    2 
 hw/xwayland/xwayland-input.c          |   35 +--
 hw/xwayland/xwayland-input.h          |    4 
 hw/xwayland/xwayland-present.c        |   89 ++++++-
 hw/xwayland/xwayland-present.h        |    6 
 hw/xwayland/xwayland-screen.c         |   19 -
 hw/xwayland/xwayland-screen.h         |    6 
 hw/xwayland/xwayland-window-buffers.c |   17 -
 hw/xwayland/xwayland-window.c         |  381 ++++++++++++++++++++++++++--------
 hw/xwayland/xwayland-window.h         |   33 ++
 13 files changed, 466 insertions(+), 144 deletions(-)

New commits:
commit c7d56b0e294f572c0685a572077b5bfdfbf33b49
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Thu Feb 15 18:34:13 2024 +0100

    xwayland/present: Redirect surface window as needed for page flips
    
    It's needed when the surface window is a depth 24 descendant of a depth
    32 toplevel window.
    
    xwl_source_validate ensures the toplevel window pixmap has valid
    contents when a client reads from it, or when the window hierarchy /
    geometry changes. It's never called in the normal fullscreen application
    case, so there's no GPU copy overhead with that.
    
    v2:
    * Don't try to redirect a depth 32 descendant of different-depth
      ancestors, the alpha channel wouldn't be handled correctly.
      (Olivier Fourdan)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index f03366437..ab56fe551 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -46,6 +46,7 @@
 #include "xwayland-dmabuf.h"
 #include "xwayland-glamor.h"
 #include "xwayland-glamor-gbm.h"
+#include "xwayland-present.h"
 #include "xwayland-screen.h"
 #include "xwayland-window.h"
 #include "xwayland-window-buffers.h"
@@ -96,8 +97,12 @@ xwl_glamor_check_flip(WindowPtr present_window, PixmapPtr pixmap)
     ScreenPtr screen = pixmap->drawable.pScreen;
     PixmapPtr backing_pixmap = screen->GetWindowPixmap(present_window);
 
-    if (pixmap->drawable.depth != backing_pixmap->drawable.depth)
-        return FALSE;
+    if (pixmap->drawable.depth != backing_pixmap->drawable.depth) {
+        if (pixmap->drawable.depth == 32)
+            return FALSE;
+
+        return xwl_present_maybe_redirect_window(present_window, pixmap);
+    }
 
     return TRUE;
 }
commit 4495c696b5dfa78a4ba80b76888f85532386d1b8
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Tue Jan 9 17:35:21 2024 +0100

    xwayland/present: Check window & source pixmap depth match last
    
    Preparation for next commit, no functional change intended.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index ff0a560db..43f053dfb 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -773,16 +773,6 @@ xwl_present_check_flip(RRCrtcPtr crtc,
     if (!RegionEqual(&present_window->clipList, &present_window->winSize))
         return FALSE;
 
-#ifdef XWL_HAS_GLAMOR
-    if (xwl_window->xwl_screen->glamor &&
-        !xwl_glamor_check_flip(present_window, pixmap))
-        return FALSE;
-
-    if (!xwl_glamor_supports_implicit_sync(xwl_window->xwl_screen) &&
-        !xwl_window->xwl_screen->explicit_sync)
-        return FALSE;
-#endif /* XWL_HAS_GLAMOR */
-
     /* Can't flip if the window pixmap doesn't match the xwl_window parent
      * window's, e.g. because a client redirected this window or one of its
      * parents.
@@ -798,6 +788,16 @@ xwl_present_check_flip(RRCrtcPtr crtc,
     if (!RegionEqual(&xwl_window->toplevel->winSize, &present_window->winSize))
         return FALSE;
 
+#ifdef XWL_HAS_GLAMOR
+    if (!xwl_glamor_supports_implicit_sync(xwl_window->xwl_screen) &&
+        !xwl_window->xwl_screen->explicit_sync)
+        return FALSE;
+
+    if (xwl_window->xwl_screen->glamor &&
+        !xwl_glamor_check_flip(present_window, pixmap))
+        return FALSE;
+#endif /* XWL_HAS_GLAMOR */
+
     return TRUE;
 }
 
commit aa05f38f3deb55b63759571a9c600ef8f71b489c
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Wed Jan 10 14:55:57 2024 +0100

    xwayland: Add SourceValidate hook
    
    A later commit will use it to ensure the toplevel window pixmap has
    valid contents.
    
    It's hooked up only while any xwl_window->surface_window_damage points
    to a non-empty region. So far it's always NULL, so no functional change
    intended.
    
    v2:
    * Fix trailing whitespace. (Olivier Fourdan)
    v3:
    * Use toplevel local variable more in xwl_window_update_surface_window.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index 5b30c210b..757417ef6 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -81,6 +81,7 @@ struct xwl_screen {
     ChangeWindowAttributesProcPtr ChangeWindowAttributes;
     ReparentWindowProcPtr ReparentWindow;
     MoveWindowProcPtr MoveWindow;
+    SourceValidateProcPtr SourceValidate;
 
     int (*GrabServer) (ClientPtr client);
     int (*UngrabServer) (ClientPtr client);
@@ -91,6 +92,8 @@ struct xwl_screen {
     struct xorg_list window_list;
     Bool ignore_damage;
 
+    int need_source_validate;
+
     int wayland_fd;
     struct wl_display *display;
     struct wl_registry *registry;
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index fe2983a25..c0938b9e4 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -189,6 +189,107 @@ xwl_window_update_property(struct xwl_window *xwl_window,
     }
 }
 
+static void
+need_source_validate_dec(struct xwl_screen *xwl_screen)
+{
+    xwl_screen->need_source_validate--;
+
+    if (!xwl_screen->need_source_validate)
+        xwl_screen->screen->SourceValidate = xwl_screen->SourceValidate;
+}
+
+static void
+xwl_source_validate(DrawablePtr drawable, int x, int y, int width, int height,
+                    unsigned int sub_window_mode)
+{
+    struct xwl_window *xwl_window;
+    WindowPtr window, iterator;
+    RegionRec region;
+    BoxRec box;
+
+    if (sub_window_mode != IncludeInferiors ||
+        drawable->type != DRAWABLE_WINDOW)
+        return;
+
+    window = (WindowPtr)drawable;
+    xwl_window = xwl_window_from_window(window);
+    if (!xwl_window || !xwl_window->surface_window_damage ||
+        !RegionNotEmpty(xwl_window->surface_window_damage))
+        return;
+
+    for (iterator = xwl_window->toplevel;
+         ;
+         iterator = iterator->firstChild) {
+        if (iterator == xwl_window->surface_window)
+            return;
+
+        if (iterator == window)
+            break;
+    }
+
+    box.x1 = x;
+    box.y1 = y;
+    box.x2 = x + width;
+    box.y2 = y + height;
+    RegionInit(&region, &box, 1);
+    RegionIntersect(&region, &region, xwl_window->surface_window_damage);
+
+    if (RegionNotEmpty(&region)) {
+        ScreenPtr screen = drawable->pScreen;
+        PixmapPtr dst_pix, src_pix;
+        BoxPtr pbox;
+        GCPtr pGC;
+        int nbox;
+
+        dst_pix = screen->GetWindowPixmap(window);
+        pGC = GetScratchGC(dst_pix->drawable.depth, screen);
+        if (!pGC)
+            FatalError("GetScratchGC failed for depth %d", dst_pix->drawable.depth);
+        ValidateGC(&dst_pix->drawable, pGC);
+
+        src_pix = screen->GetWindowPixmap(xwl_window->surface_window);
+
+        RegionSubtract(xwl_window->surface_window_damage,
+                       xwl_window->surface_window_damage,
+                       &region);
+
+        if (!RegionNotEmpty(xwl_window->surface_window_damage))
+            need_source_validate_dec(xwl_window->xwl_screen);
+
+#if defined(COMPOSITE)
+        if (dst_pix->screen_x || dst_pix->screen_y)
+            RegionTranslate(&region, -dst_pix->screen_x, -dst_pix->screen_y);
+#endif
+
+        pbox = RegionRects(&region);
+        nbox = RegionNumRects(&region);
+        while (nbox--) {
+            (void) (*pGC->ops->CopyArea) (&src_pix->drawable,
+                                          &dst_pix->drawable,
+                                          pGC,
+                                          pbox->x1, pbox->y1,
+                                          pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
+                                          pbox->x1, pbox->y1);
+        }
+        FreeScratchGC(pGC);
+    }
+
+    RegionUninit(&region);
+}
+
+static void
+need_source_validate_inc(struct xwl_screen *xwl_screen)
+{
+    if (!xwl_screen->need_source_validate) {
+        ScreenPtr screen = xwl_screen->screen;
+
+        xwl_screen->SourceValidate = screen->SourceValidate;
+        screen->SourceValidate = xwl_source_validate;
+    }
+
+    xwl_screen->need_source_validate++;
+}
+
 static void
 damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
 {
@@ -196,6 +297,16 @@ damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     PixmapPtr window_pixmap;
 
+    if (xwl_window->surface_window_damage &&
+        RegionNotEmpty(pRegion)) {
+        if (!RegionNotEmpty(xwl_window->surface_window_damage))
+            need_source_validate_inc(xwl_screen);
+
+        RegionUnion(xwl_window->surface_window_damage,
+                    xwl_window->surface_window_damage,
+                    DamageRegion(pDamage));
+    }
+
     if (xwl_screen->ignore_damage)
         return;
 
@@ -1259,6 +1370,25 @@ xwl_window_update_surface_window(struct xwl_window *xwl_window)
     if (xwl_window->surface_window == surface_window)
         return;
 
+    if (xwl_window->surface_window_damage) {
+        if (xwl_present_maybe_unredirect_window(xwl_window->surface_window) &&
+            screen->SourceValidate == xwl_source_validate) {
+            WindowPtr toplevel = xwl_window->toplevel;
+
+            xwl_source_validate(&toplevel->drawable,
+                                toplevel->drawable.x, toplevel->drawable.y,
+                                toplevel->drawable.width,
+                                toplevel->drawable.height,
+                                IncludeInferiors);
+        }
+
+        if (RegionNotEmpty(xwl_window->surface_window_damage))
+            need_source_validate_dec(xwl_window->xwl_screen);
+
+        RegionDestroy(xwl_window->surface_window_damage);
+        xwl_window->surface_window_damage = NULL;
+    }
+
     window_damage = window_get_damage(xwl_window->surface_window);
     if (window_damage) {
         RegionInit(&damage_region, NullBox, 1);
@@ -1666,6 +1796,12 @@ xwl_config_notify(WindowPtr window,
     xwl_window = xwl_window_from_window(window);
 
     size_changed = width != window->drawable.width || height != window->drawable.height;
+    if (size_changed && xwl_window && xwl_window->toplevel == window &&
+        screen->SourceValidate == xwl_source_validate) {
+        xwl_source_validate(&window->drawable, window->drawable.x, window->drawable.y,
+                            window->drawable.width, window->drawable.height,
+                            IncludeInferiors);
+    }
 
     screen->ConfigNotify = xwl_screen->ConfigNotify;
     ret = screen->ConfigNotify(window, x, y, width, height, bw, sib);
commit fca63f8fb8e09d6c76f94e5682e9dc7d32495b87
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Thu Feb 15 18:27:27 2024 +0100

    xwayland/present: Add xwl_present_maybe_(un)redirect_window
    
    A later commit will use these to (un)redirect the surface window on
    demand.
    
    Not used yet, so no functional change intended.
    
    v2:
    * Use "surface_window_damage" instead of "surf_win_damage".
      (Olivier Fourdan)
    * Slightly simplify logic in xwl_unrealize_window.
    v3:
    * Add comment in xwl_present_maybe_unredirect_window explaining why we
      use a timer. (Olivier Fourdan)
    v4:
    * Rename unredir_timer field to unredirect_timer.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 9def82fcd..ff0a560db 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -25,6 +25,7 @@
 
 #include <xwayland-config.h>
 
+#include <compint.h>
 #ifdef XWL_HAS_GLAMOR
 #include <glamor.h>
 #endif
@@ -484,6 +485,7 @@ xwl_present_cleanup(WindowPtr window)
 
     /* Clear timer */
     xwl_present_free_timer(xwl_present_window);
+    TimerFree(xwl_present_window->unredirect_timer);
 
     /* Remove from privates so we don't try to access it later */
     dixSetPrivate(&window->devPrivates,
@@ -1263,6 +1265,67 @@ xwl_present_unrealize_window(struct xwl_present_window *xwl_present_window)
     xwl_present_reset_timer(xwl_present_window);
 }
 
+Bool
+xwl_present_maybe_redirect_window(WindowPtr window, PixmapPtr pixmap)
+{
+    struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window);
+    struct xwl_window *xwl_window = xwl_window_from_window(window);
+
+    if (xwl_present_window->redirect_failed)
+        return FALSE;
+
+    if (compRedirectWindow(serverClient, window, CompositeRedirectManual) != Success) {
+        xwl_present_window->redirect_failed = TRUE;
+        return FALSE;
+    }
+
+    xwl_window_update_surface_window(xwl_window);
+    if (xwl_window->surface_window != window) {
+        compUnredirectWindow(serverClient, window, CompositeRedirectManual);
+        xwl_present_window->redirect_failed = TRUE;
+        return FALSE;
+    }
+
+    if (!xwl_window->surface_window_damage)
+        xwl_window->surface_window_damage = RegionCreate(NullBox, 1);
+
+    xwl_present_window->redirected = TRUE;
+    return TRUE;
+}
+
+static CARD32
+unredirect_window(OsTimerPtr timer, CARD32 time, void *arg)
+{
+    WindowPtr window = arg;
+    struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window);
+
+    compUnredirectWindow(serverClient, window, CompositeRedirectManual);
+    xwl_present_window->redirected = FALSE;
+
+    xwl_present_window->unredirect_timer = NULL;
+    return 0;
+}
+
+Bool
+xwl_present_maybe_unredirect_window(WindowPtr window)
+{
+    struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window);
+
+    if (!xwl_present_window || !xwl_present_window->redirected)
+        return FALSE;
+
+    /* This function may get called from composite layer code, in which case
+     * calling compUnredirectWindow would blow up. To avoid this, set up a timer
+     * which will call it "as soon as possible".
+     */
+    if (!xwl_present_window->unredirect_timer) {
+        xwl_present_window->unredirect_timer =
+            TimerSet(NULL, 0, 1, unredirect_window, window);
+    }
+
+    return TRUE;
+}
+
 Bool
 xwl_present_init(ScreenPtr screen)
 {
diff --git a/hw/xwayland/xwayland-present.h b/hw/xwayland/xwayland-present.h
index c0efaa6bf..808e54182 100644
--- a/hw/xwayland/xwayland-present.h
+++ b/hw/xwayland/xwayland-present.h
@@ -54,6 +54,10 @@ struct xwl_present_window {
 
     present_vblank_ptr flip_active;
     uint64_t blocking_event;
+
+    OsTimerPtr unredirect_timer;
+    Bool redirected;
+    Bool redirect_failed;
 };
 
 struct xwl_present_event {
@@ -77,5 +81,7 @@ void xwl_present_frame_callback(struct xwl_present_window *xwl_present_window);
 Bool xwl_present_init(ScreenPtr screen);
 void xwl_present_cleanup(WindowPtr window);
 void xwl_present_unrealize_window(struct xwl_present_window *xwl_present_window);
+Bool xwl_present_maybe_redirect_window(WindowPtr window, PixmapPtr pixmap);
+Bool xwl_present_maybe_unredirect_window(WindowPtr window);
 
 #endif /* XWAYLAND_PRESENT_H */
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 93b689525..fe2983a25 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -1221,7 +1221,7 @@ err_surf:
     return FALSE;
 }
 
-static void
+void
 xwl_window_update_surface_window(struct xwl_window *xwl_window)
 {
     WindowPtr surface_window = xwl_window->toplevel;
@@ -1512,14 +1512,15 @@ xwl_unrealize_window(WindowPtr window)
 
     xwl_screen = xwl_screen_get(screen);
 
-    compUnredirectWindow(serverClient, window, CompositeRedirectManual);
+    xwl_window = xwl_window_get(window);
+    if (xwl_window)
+        compUnredirectWindow(serverClient, window, CompositeRedirectManual);
 
     screen->UnrealizeWindow = xwl_screen->UnrealizeWindow;
     ret = (*screen->UnrealizeWindow) (window);
     xwl_screen->UnrealizeWindow = screen->UnrealizeWindow;
     screen->UnrealizeWindow = xwl_unrealize_window;
 
-    xwl_window = xwl_window_get(window);
     if (!xwl_window)
         return ret;
 
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 8823b03ea..836f654a3 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -82,6 +82,7 @@ struct xwl_window {
      * can also be used for the X dimensions of the Wayland surface though.
      */
     WindowPtr surface_window;
+    RegionPtr surface_window_damage;
 
     struct xorg_list link_damage;
     struct xorg_list link_window;
@@ -121,6 +122,7 @@ void xwl_window_rootful_update_title(struct xwl_window *xwl_window);
 void xwl_window_rootful_update_fullscreen(struct xwl_window *xwl_window,
                                           struct xwl_output *xwl_output);
 void xwl_window_set_window_pixmap(WindowPtr window, PixmapPtr pixmap);
+void xwl_window_update_surface_window(struct xwl_window *xwl_window);
 
 void xwl_window_leave_output(struct xwl_window *xwl_window,
                              struct xwl_output *xwl_output);
commit fa7b1c20c4104dd134e502f85c9918216548c8c7
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Thu Feb 15 18:08:16 2024 +0100

    xwayland: Use ConfigNotify screen hook instead of ResizeWindow
    
    Preparation for later commits, no functional change intended.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index 135ae7b74..284189912 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -1113,8 +1113,8 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     xwl_screen->ClipNotify = pScreen->ClipNotify;
     pScreen->ClipNotify = xwl_clip_notify;
 
-    xwl_screen->ResizeWindow = pScreen->ResizeWindow;
-    pScreen->ResizeWindow = xwl_resize_window;
+    xwl_screen->ConfigNotify = pScreen->ConfigNotify;
+    pScreen->ConfigNotify = xwl_config_notify;
 
     xwl_screen->MoveWindow = pScreen->MoveWindow;
     pScreen->MoveWindow = xwl_move_window;
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index 9653d82c9..5b30c210b 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -71,6 +71,7 @@ struct xwl_screen {
     ClipNotifyProcPtr ClipNotify;
     CreateScreenResourcesProcPtr CreateScreenResources;
     CloseScreenProcPtr CloseScreen;
+    ConfigNotifyProcPtr ConfigNotify;
     CreateWindowProcPtr CreateWindow;
     RealizeWindowProcPtr RealizeWindow;
     UnrealizeWindowProcPtr UnrealizeWindow;
@@ -79,7 +80,6 @@ struct xwl_screen {
     SetWindowPixmapProcPtr SetWindowPixmap;
     ChangeWindowAttributesProcPtr ChangeWindowAttributes;
     ReparentWindowProcPtr ReparentWindow;
-    ResizeWindowProcPtr ResizeWindow;
     MoveWindowProcPtr MoveWindow;
 
     int (*GrabServer) (ClientPtr client);
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 11a6b3adc..93b689525 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -1649,25 +1649,29 @@ xwl_clip_notify(WindowPtr window, int dx, int dy)
         xwl_window_update_surface_window(xwl_window);
 }
 
-void
-xwl_resize_window(WindowPtr window,
+int
+xwl_config_notify(WindowPtr window,
                   int x, int y,
-                  unsigned int width, unsigned int height,
+                  int width, int height, int bw,
                   WindowPtr sib)
 {
     ScreenPtr screen = window->drawable.pScreen;
     struct xwl_screen *xwl_screen;
     struct xwl_window *xwl_window;
+    Bool size_changed;
+    int ret;
 
     xwl_screen = xwl_screen_get(screen);
     xwl_window = xwl_window_from_window(window);
 
-    screen->ResizeWindow = xwl_screen->ResizeWindow;
-    (*screen->ResizeWindow) (window, x, y, width, height, sib);
-    xwl_screen->ResizeWindow = screen->ResizeWindow;
-    screen->ResizeWindow = xwl_resize_window;
+    size_changed = width != window->drawable.width || height != window->drawable.height;
 
-    if (xwl_window) {
+    screen->ConfigNotify = xwl_screen->ConfigNotify;
+    ret = screen->ConfigNotify(window, x, y, width, height, bw, sib);
+    xwl_screen->ConfigNotify = screen->ConfigNotify;
+    screen->ConfigNotify = xwl_config_notify;
+
+    if (size_changed && xwl_window) {
         if (xwl_window_get(window) || xwl_window_is_toplevel(window))
             xwl_window_check_resolution_change_emulation(xwl_window);
         if (window == screen->root) {
@@ -1682,6 +1686,8 @@ xwl_resize_window(WindowPtr window,
             xwl_window_check_fractional_scale_viewport(xwl_window, width, height);
         }
     }
+
+    return ret;
 }
 
 void
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index fefb4969c..8823b03ea 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -129,10 +129,10 @@ Bool xwl_realize_window(WindowPtr window);
 Bool xwl_unrealize_window(WindowPtr window);
 Bool xwl_change_window_attributes(WindowPtr window, unsigned long mask);
 void xwl_clip_notify(WindowPtr window, int dx, int dy);
-void xwl_resize_window(WindowPtr window,
-                       int x, int y,
-                       unsigned int width, unsigned int height,
-                       WindowPtr sib);
+int xwl_config_notify(WindowPtr window,
+                      int x, int y,
+                      int width, int height, int bw,
+                      WindowPtr sib);
 void xwl_move_window(WindowPtr window,
                      int x, int y,
                      WindowPtr next_sib,
commit 3a0fc2684a037591725585c50760fda6e3c3c765
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Fri Dec 22 19:00:42 2023 +0100

    xwayland: Add xwl_window::surface_window
    
    It may track a non-toplevel window which fully covers the area of the
    window pixmap / Wayland surface. It is now used instead of
    xwl_window::toplevel for updating the Wayland surface contents.
    
    The surface_window can now hit the Present page flip path while it's
    automatically redirected.
    
    v2:
    * Use "surface_window" instead of "surf_win". (Olivier Fourdan)
    * Add comment describing surface_window, and describe what
      surface_window/toplevel are useful for respectively. (Olivier Fourdan)
    * Use surface_window in xwl_realize_window.
    v3:
    * Backtrack up to the closest opaque ancestor in
      xwl_window_update_surface_window. (Olivier Fourdan)
    v4:
    * Clean up logic for determining the surface window in
      xwl_window_update_surface_window, and document it better.
    * Handle window_get_damage(xwl_window->surface_window) returning NULL
      in xwl_window_update_surface_window.
    * Call xwl_window_update_surface_window after xwl_window_buffers_init
      in ensure_surface_for_window, since the former may call
      xwl_window_buffers_dispose.
    * Rename surf/win_pix to surface/window_pixmap in
      xwl_window_update_surface_window.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-dmabuf.c b/hw/xwayland/xwayland-dmabuf.c
index 97c501273..8119e1ddb 100644
--- a/hw/xwayland/xwayland-dmabuf.c
+++ b/hw/xwayland/xwayland-dmabuf.c
@@ -735,7 +735,7 @@ xwl_window_dmabuf_feedback_done(void *data,
                                 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
 {
     struct xwl_window *xwl_window = data;
-    uint32_t format = wl_drm_format_for_depth(xwl_window->toplevel->drawable.depth);
+    uint32_t format = wl_drm_format_for_depth(xwl_window->surface_window->drawable.depth);
 
     xwl_dmabuf_feedback_done(&xwl_window->feedback, dmabuf_feedback);
 
@@ -743,7 +743,7 @@ xwl_window_dmabuf_feedback_done(void *data,
         xwl_feedback_is_modifier_supported(&xwl_window->feedback, format,
                                            DRM_FORMAT_MOD_INVALID, TRUE);
     DebugF("XWAYLAND: Window 0x%x can%s get implicit scanout support\n",
-            xwl_window->toplevel->drawable.id,
+            xwl_window->surface_window->drawable.id,
             xwl_window->has_implicit_scanout_support ? "" : "not");
 
     /* If the linux-dmabuf v4 per-surface feedback changed, make sure the
diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c
index 1198ca16b..745a9ed38 100644
--- a/hw/xwayland/xwayland-glamor-gbm.c
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -412,7 +412,7 @@ PixmapPtr
 xwl_glamor_create_pixmap_for_window(struct xwl_window *xwl_window)
 {
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
-    WindowPtr window = xwl_window->toplevel;
+    WindowPtr window = xwl_window->surface_window;
     unsigned border_width = 2 * window->borderWidth;
 
     if (!xwl_screen->glamor)
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 1ac099da9..9def82fcd 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -785,7 +785,7 @@ xwl_present_check_flip(RRCrtcPtr crtc,
      * window's, e.g. because a client redirected this window or one of its
      * parents.
      */
-    if (screen->GetWindowPixmap(xwl_window->toplevel) != screen->GetWindowPixmap(present_window))
+    if (screen->GetWindowPixmap(xwl_window->surface_window) != screen->GetWindowPixmap(present_window))
         return FALSE;
 
     /*
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index 701425c08..135ae7b74 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -1110,6 +1110,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     xwl_screen->ChangeWindowAttributes = pScreen->ChangeWindowAttributes;
     pScreen->ChangeWindowAttributes = xwl_change_window_attributes;
 
+    xwl_screen->ClipNotify = pScreen->ClipNotify;
+    pScreen->ClipNotify = xwl_clip_notify;
+
     xwl_screen->ResizeWindow = pScreen->ResizeWindow;
     pScreen->ResizeWindow = xwl_resize_window;
 
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index 2b3bdb29e..9653d82c9 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -68,6 +68,7 @@ struct xwl_screen {
     int nokeymap;
     int hidpi;
 
+    ClipNotifyProcPtr ClipNotify;
     CreateScreenResourcesProcPtr CreateScreenResources;
     CloseScreenProcPtr CloseScreen;
     CreateWindowProcPtr CreateWindow;
diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c
index bdae04945..2e8b0859c 100644
--- a/hw/xwayland/xwayland-window-buffers.c
+++ b/hw/xwayland/xwayland-window-buffers.c
@@ -339,7 +339,7 @@ xwl_window_allocate_pixmap(struct xwl_window *xwl_window)
         return window_pixmap;
 #endif /* XWL_HAS_GLAMOR */
 
-    window_pixmap = screen->GetWindowPixmap(xwl_window->toplevel);
+    window_pixmap = screen->GetWindowPixmap(xwl_window->surface_window);
     return screen->CreatePixmap(screen,
                                 window_pixmap->drawable.width,
                                 window_pixmap->drawable.height,
@@ -358,7 +358,7 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window)
     if (!new_window_pixmap)
         return;
 
-    window = xwl_window->toplevel;
+    window = xwl_window->surface_window;
     screen = window->drawable.pScreen;
     window_pixmap = screen->GetWindowPixmap(window);
     copy_pixmap_area(window_pixmap,
@@ -366,7 +366,7 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window)
                      0, 0,
                      window_pixmap->drawable.width,
                      window_pixmap->drawable.height);
-    xwl_window_set_pixmap(xwl_window->toplevel, new_window_pixmap);
+    xwl_window_set_pixmap(xwl_window->surface_window, new_window_pixmap);
     screen->DestroyPixmap(window_pixmap);
 }
 
@@ -414,11 +414,12 @@ PixmapPtr
 xwl_window_swap_pixmap(struct xwl_window *xwl_window)
 {
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    WindowPtr surface_window = xwl_window->surface_window;
     struct xwl_window_buffer *xwl_window_buffer;
     PixmapPtr window_pixmap;
     Bool implicit_sync = TRUE;
 
-    window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->toplevel);
+    window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (surface_window);
 
     xwl_window_buffer_add_damage_region(xwl_window);
 
@@ -441,8 +442,8 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window)
         while (nBox--) {
             copy_pixmap_area(window_pixmap,
                              xwl_window_buffer->pixmap,
-                             pBox->x1 + xwl_window->toplevel->borderWidth,
-                             pBox->y1 + xwl_window->toplevel->borderWidth,
+                             pBox->x1 + surface_window->borderWidth,
+                             pBox->y1 + surface_window->borderWidth,
                              pBox->x2 - pBox->x1,
                              pBox->y2 - pBox->y1);
 
@@ -451,7 +452,7 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window)
 
         RegionEmpty(xwl_window_buffer->damage_region);
         xorg_list_del(&xwl_window_buffer->link_buffer);
-        xwl_window_set_pixmap(xwl_window->toplevel, xwl_window_buffer->pixmap);
+        xwl_window_set_pixmap(surface_window, xwl_window_buffer->pixmap);
 
         /* Can't re-use client pixmap as a window buffer */
         if (xwl_is_client_pixmap(window_pixmap)) {
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index e85827b82..11a6b3adc 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -87,7 +87,7 @@ window_get_damage(WindowPtr window)
 RegionPtr
 xwl_window_get_damage_region(struct xwl_window *xwl_window)
 {
-    return DamageRegion(window_get_damage(xwl_window->toplevel));
+    return DamageRegion(window_get_damage(xwl_window->surface_window));
 }
 
 struct xwl_window *
@@ -135,7 +135,7 @@ xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow,
     DebugF("XWAYLAND: win %d allow_commits = %d (%s)\n",
            xwl_window->toplevel->drawable.id, allow, debug_msg);
 
-    damage = window_get_damage(xwl_window->toplevel);
+    damage = window_get_damage(xwl_window->surface_window);
     if (allow &&
         xorg_list_is_empty(&xwl_window->link_damage) &&
         damage &&
@@ -202,7 +202,7 @@ damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
     if (xorg_list_is_empty(&xwl_window->link_damage))
         xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list);
 
-    window_pixmap = xwl_screen->screen->GetWindowPixmap(xwl_window->toplevel);
+    window_pixmap = xwl_screen->screen->GetWindowPixmap(xwl_window->surface_window);
     if (xwl_is_client_pixmap(window_pixmap))
         xwl_screen->screen->DestroyPixmap(xwl_window_swap_pixmap(xwl_window));
 }
@@ -215,18 +215,18 @@ damage_destroy(DamagePtr pDamage, void *data)
 static Bool
 register_damage(struct xwl_window *xwl_window)
 {
-    WindowPtr toplevel = xwl_window->toplevel;
+    WindowPtr surface_window = xwl_window->surface_window;
     DamagePtr damage;
 
     damage = DamageCreate(damage_report, damage_destroy, DamageReportNonEmpty,
-                          FALSE, toplevel->drawable.pScreen, xwl_window);
+                          FALSE, surface_window->drawable.pScreen, xwl_window);
     if (damage == NULL) {
         ErrorF("Failed creating damage\n");
         return FALSE;
     }
 
-    DamageRegister(&toplevel->drawable, damage);
-    dixSetPrivate(&toplevel->devPrivates, &xwl_damage_private_key, damage);
+    DamageRegister(&surface_window->drawable, damage);
+    dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, damage);
 
     return TRUE;
 }
@@ -234,17 +234,17 @@ register_damage(struct xwl_window *xwl_window)
 static void
 unregister_damage(struct xwl_window *xwl_window)
 {
-    WindowPtr toplevel = xwl_window->toplevel;
+    WindowPtr surface_window = xwl_window->surface_window;
     DamagePtr damage;
 
-    damage = dixLookupPrivate(&toplevel->devPrivates, &xwl_damage_private_key);
+    damage = dixLookupPrivate(&surface_window->devPrivates, &xwl_damage_private_key);
     if (!damage)
         return;
 
     DamageUnregister(damage);
     DamageDestroy(damage);
 
-    dixSetPrivate(&toplevel->devPrivates, &xwl_damage_private_key, NULL);
+    dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, NULL);
 }
 
 static Bool
@@ -540,15 +540,15 @@ xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window)
 Bool
 xwl_window_is_toplevel(WindowPtr window)
 {
-    if (window_is_wm_window(window))
+    if (!window->parent || window_is_wm_window(window))
         return FALSE;
 
     /* CSD and override-redirect toplevel windows */
-    if (window_get_damage(window))
+    if (!window->parent->parent)
         return TRUE;
 
     /* Normal toplevel client windows, reparented to a window-manager window */
-    return window->parent && window_is_wm_window(window->parent);
+    return window_is_wm_window(window->parent);
 }
 
 static void
@@ -1221,6 +1221,65 @@ err_surf:
     return FALSE;
 }
 
+static void
+xwl_window_update_surface_window(struct xwl_window *xwl_window)
+{
+    WindowPtr surface_window = xwl_window->toplevel;
+    ScreenPtr screen = surface_window->drawable.pScreen;
+    PixmapPtr surface_pixmap;
+    DamagePtr window_damage;
+    RegionRec damage_region;
+    WindowPtr window;
+
+    surface_pixmap = screen->GetWindowPixmap(surface_window);
+
+    for (window = surface_window->firstChild; window; window = window->firstChild) {
+        PixmapPtr window_pixmap;
+
+        if (!RegionEqual(&window->winSize, &surface_window->winSize))
+            break;
+
+        /* The surface window must be top-level for its window pixmap */
+        window_pixmap = screen->GetWindowPixmap(window);
+        if (window_pixmap == surface_pixmap)
+            continue;
+
+        surface_pixmap = window_pixmap;
+
+        /* A descendant with alpha channel cannot be the surface window, since
+         * any non-opaque areas need to take the contents of ancestors into
+         * account.
+         */
+        if (window->drawable.depth == 32)
+            continue;
+
+        surface_window = window;
+    }
+
+    if (xwl_window->surface_window == surface_window)
+        return;
+
+    window_damage = window_get_damage(xwl_window->surface_window);
+    if (window_damage) {
+        RegionInit(&damage_region, NullBox, 1);
+        RegionCopy(&damage_region, DamageRegion(window_damage));
+        unregister_damage(xwl_window);
+    }
+
+    if (surface_window->drawable.depth != xwl_window->surface_window->drawable.depth)
+        xwl_window_buffers_dispose(xwl_window);
+
+    xwl_window->surface_window = surface_window;
+    register_damage(xwl_window);
+
+    if (window_damage) {
+        RegionPtr new_region = DamageRegion(window_get_damage(surface_window));
+
+        RegionUnion(new_region, new_region, &damage_region);
+        RegionUninit(&damage_region);
+    }
+}
+
 static struct xwl_window *
 ensure_surface_for_window(WindowPtr window)
 {
@@ -1250,6 +1309,7 @@ ensure_surface_for_window(WindowPtr window)
 
     xwl_window->xwl_screen = xwl_screen;
     xwl_window->toplevel = window;
+    xwl_window->surface_window = window;
     xwl_window->fractional_scale_numerator = FRACTIONAL_SCALE_DENOMINATOR;
     xwl_window->viewport_scale_x = 1.0;
     xwl_window->viewport_scale_y = 1.0;
@@ -1290,6 +1350,8 @@ ensure_surface_for_window(WindowPtr window)
 
     xwl_window_buffers_init(xwl_window);
 
+    xwl_window_update_surface_window(xwl_window);
+
     xwl_window_init_allow_commits(xwl_window);
 
     /* When a new window-manager window is realized, then the randr emulation
@@ -1360,7 +1422,7 @@ xwl_realize_window(WindowPtr window)
     if (!xwl_window)
         return FALSE;
 
-    if (window == xwl_window->toplevel &&
+    if (window == xwl_window->surface_window &&
         !window_get_damage(window))
         return register_damage(xwl_window);
 
@@ -1571,6 +1633,22 @@ xwl_change_window_attributes(WindowPtr window, unsigned long mask)
     return ret;
 }
 
+void
+xwl_clip_notify(WindowPtr window, int dx, int dy)
+{
+    ScreenPtr screen = window->drawable.pScreen;
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_window *xwl_window = xwl_window_from_window(window);
+
+    screen->ClipNotify = xwl_screen->ClipNotify;
+    (*screen->ClipNotify) (window, dx, dy);
+    xwl_screen->ClipNotify = screen->ClipNotify;
+    screen->ClipNotify = xwl_clip_notify;
+
+    if (xwl_window)
+        xwl_window_update_surface_window(xwl_window);
+}
+
 void
 xwl_resize_window(WindowPtr window,
                   int x, int y,
@@ -1696,6 +1774,7 @@ static Bool
 xwl_window_attach_buffer(struct xwl_window *xwl_window)
 {
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    WindowPtr surface_window = xwl_window->surface_window;
     RegionPtr region;
     BoxPtr box;
     struct wl_buffer *buffer;
@@ -1720,15 +1799,15 @@ xwl_window_attach_buffer(struct xwl_window *xwl_window)
     if (RegionNumRects(region) > 256) {
         box = RegionExtents(region);
         xwl_surface_damage(xwl_screen, xwl_window->surface,
-                           box->x1 + xwl_window->toplevel->borderWidth,
-                           box->y1 + xwl_window->toplevel->borderWidth,
+                           box->x1 + surface_window->borderWidth,
+                           box->y1 + surface_window->borderWidth,
                            box->x2 - box->x1, box->y2 - box->y1);
     } else {
         box = RegionRects(region);
         for (i = 0; i < RegionNumRects(region); i++, box++) {
             xwl_surface_damage(xwl_screen, xwl_window->surface,
-                               box->x1 + xwl_window->toplevel->borderWidth,
-                               box->y1 + xwl_window->toplevel->borderWidth,
+                               box->x1 + surface_window->borderWidth,
+                               box->y1 + surface_window->borderWidth,
                                box->x2 - box->x1, box->y2 - box->y1);
         }
     }
@@ -1745,7 +1824,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
         return;
 
     xwl_window_create_frame_callback(xwl_window);
-    DamageEmpty(window_get_damage(xwl_window->toplevel));
+    DamageEmpty(window_get_damage(xwl_window->surface_window));
 }
 
 Bool
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 7c75f9b80..fefb4969c 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -66,9 +66,23 @@ struct xwl_window {
     /* Top-level window for the Wayland surface:
      * - With rootful, the root window itself
      * - With rootless, a direct child of the root window
+     * Mainly useful when the top-level window is needed, can also be used for
+     * the X dimensions of the Wayland surface though.
      */
     WindowPtr toplevel;
 
+    /* The window associated with the Wayland surface:
+     * - If the top-level window has descendants which:
+     *   - Cover it completely
+     *   - Have no alpha channel
+     *   - Use a different window pixmap than their parent for storage
+     *   then the surface window is the lowest-level such descendant.
+     * - Otherwise it's the top-level window itself.
+     * Mainly useful for code dealing with (buffers for) the Wayland surface,
+     * can also be used for the X dimensions of the Wayland surface though.
+     */
+    WindowPtr surface_window;
+
     struct xorg_list link_damage;
     struct xorg_list link_window;
     struct wl_callback *frame_callback;
@@ -114,6 +128,7 @@ int xwl_window_get_max_output_scale(struct xwl_window *xwl_window);
 Bool xwl_realize_window(WindowPtr window);
 Bool xwl_unrealize_window(WindowPtr window);
 Bool xwl_change_window_attributes(WindowPtr window, unsigned long mask);
+void xwl_clip_notify(WindowPtr window, int dx, int dy);
 void xwl_resize_window(WindowPtr window,
                        int x, int y,
                        unsigned int width, unsigned int height,
commit db248682b3ff8a39eb29469589e35ecddf008c36
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Tue Apr 9 18:04:07 2024 +0200

    xwayland: Pass xwl_window to xwl_glamor_dri3_syncobj_passthrough
    
    Preparation for later changes, no functional change intended.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c
index b5b0c2a1c..1198ca16b 100644
--- a/hw/xwayland/xwayland-glamor-gbm.c
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -972,13 +972,12 @@ struct xwl_dri3_syncobj
 };
 
 void
-xwl_glamor_dri3_syncobj_passthrough(WindowPtr window,
+xwl_glamor_dri3_syncobj_passthrough(struct xwl_window *xwl_window,
                                     struct dri3_syncobj *acquire_syncobj,
                                     struct dri3_syncobj *release_syncobj,
                                     uint64_t acquire_point,
                                     uint64_t release_point)
 {
-    struct xwl_window *xwl_window = xwl_window_from_window(window);
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     struct xwl_dri3_syncobj *xwl_acquire_syncobj = (struct xwl_dri3_syncobj *)acquire_syncobj;
     struct xwl_dri3_syncobj *xwl_release_syncobj = (struct xwl_dri3_syncobj *)release_syncobj;
diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h
index bbf930437..ef312a857 100644
--- a/hw/xwayland/xwayland-glamor.h
+++ b/hw/xwayland/xwayland-glamor.h
@@ -67,7 +67,7 @@ Bool xwl_glamor_supports_syncobjs(struct xwl_screen *xwl_screen);
 int xwl_glamor_get_fence(struct xwl_screen *screen);
 void xwl_glamor_wait_fence(struct xwl_screen *xwl_screen, int fence);
 struct dri3_syncobj *xwl_glamor_dri3_syncobj_create(struct xwl_screen *xwl_screen);
-void xwl_glamor_dri3_syncobj_passthrough(WindowPtr window,
+void xwl_glamor_dri3_syncobj_passthrough(struct xwl_window *xwl_window,
                                          struct dri3_syncobj *acquire_syncobj,
                                          struct dri3_syncobj *release_syncobj,
                                          uint64_t acquire_point,
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 2153ce6fb..1ac099da9 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -882,7 +882,7 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage)
 #ifdef XWL_HAS_GLAMOR
     if (vblank->acquire_syncobj && vblank->release_syncobj) {
         if (xwl_window->xwl_screen->explicit_sync) {
-            xwl_glamor_dri3_syncobj_passthrough(present_window,
+            xwl_glamor_dri3_syncobj_passthrough(xwl_window,
                                                 vblank->acquire_syncobj,
                                                 vblank->release_syncobj,
                                                 vblank->acquire_point,
diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c
index f66f36169..bdae04945 100644
--- a/hw/xwayland/xwayland-window-buffers.c
+++ b/hw/xwayland/xwayland-window-buffers.c
@@ -393,7 +393,7 @@ xwl_window_buffers_set_syncpts(struct xwl_window_buffer *xwl_window_buffer)
     else
         goto fail;
 
-    xwl_glamor_dri3_syncobj_passthrough(xwl_window->toplevel,
+    xwl_glamor_dri3_syncobj_passthrough(xwl_window,
                                         xwl_window_buffer->syncobj,
                                         xwl_window_buffer->syncobj,
                                         acquire_point,
commit d3448f7aad076fb248014cbd59e2c7bb9dd990d3
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Thu Feb 8 18:18:06 2024 +0100

    xwayland: Use xwl_window for damage closure
    
    Preparation for later commits, no functional change intended.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index d4e8e81e2..e85827b82 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -192,15 +192,10 @@ xwl_window_update_property(struct xwl_window *xwl_window,
 static void
 damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
 {
-    WindowPtr window = data;
-    struct xwl_window *xwl_window = xwl_window_get(window);
-    struct xwl_screen *xwl_screen;
+    struct xwl_window *xwl_window = data;
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     PixmapPtr window_pixmap;
 
-    if (!xwl_window)
-        return;
-
-    xwl_screen = xwl_window->xwl_screen;
     if (xwl_screen->ignore_damage)
         return;
 
@@ -218,37 +213,38 @@ damage_destroy(DamagePtr pDamage, void *data)
 }
 
 static Bool
-register_damage(WindowPtr window)
+register_damage(struct xwl_window *xwl_window)
 {
+    WindowPtr toplevel = xwl_window->toplevel;
     DamagePtr damage;
 
     damage = DamageCreate(damage_report, damage_destroy, DamageReportNonEmpty,
-                          FALSE, window->drawable.pScreen, window);
+                          FALSE, toplevel->drawable.pScreen, xwl_window);
     if (damage == NULL) {
         ErrorF("Failed creating damage\n");
         return FALSE;
     }
 
-    DamageRegister(&window->drawable, damage);
-
-    dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, damage);
+    DamageRegister(&toplevel->drawable, damage);
+    dixSetPrivate(&toplevel->devPrivates, &xwl_damage_private_key, damage);
 
     return TRUE;
 }
 
 static void
-unregister_damage(WindowPtr window)
+unregister_damage(struct xwl_window *xwl_window)
 {
+    WindowPtr toplevel = xwl_window->toplevel;
     DamagePtr damage;
 
-    damage = dixLookupPrivate(&window->devPrivates, &xwl_damage_private_key);
+    damage = dixLookupPrivate(&toplevel->devPrivates, &xwl_damage_private_key);
     if (!damage)
         return;
 
     DamageUnregister(damage);
     DamageDestroy(damage);
 
-    dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, NULL);
+    dixSetPrivate(&toplevel->devPrivates, &xwl_damage_private_key, NULL);
 }
 
 static Bool
@@ -1366,7 +1362,7 @@ xwl_realize_window(WindowPtr window)
 
     if (window == xwl_window->toplevel &&
         !window_get_damage(window))
-        return register_damage(window);
+        return register_damage(xwl_window);
 
     return TRUE;
 }
@@ -1503,7 +1499,7 @@ xwl_unrealize_window(WindowPtr window)
     release_wl_surface_for_window(xwl_window);
     xorg_list_del(&xwl_window->link_damage);
     xorg_list_del(&xwl_window->link_window);
-    unregister_damage(window);
+    unregister_damage(xwl_window);
 
     xwl_window_buffers_dispose(xwl_window);
 
commit 07f603262700bfe2abcc28f6d7a8e38457d211cc
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Thu Feb 8 18:41:25 2024 +0100

    xwayland: Call register_damage depending on ensure_surface_for_window
    
    Preparation for next commit.
    
    This might change behaviour for non-InputOutput top-level windows.
    ensure_surface_for_window getting called and returning non-NULL for
    those would seem like a pre-existing bug though.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index fdd4b287a..d4e8e81e2 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -1360,18 +1360,14 @@ xwl_realize_window(WindowPtr window)
         }
     }
 
-    if (xwl_screen->rootless ?
-        (window->drawable.class == InputOutput &&
-         window->parent == window->drawable.pScreen->root) :
-        !window->parent) {
-        if (!register_damage(window))
-            return FALSE;
-    }
-
     xwl_window = ensure_surface_for_window(window);
     if (!xwl_window)
         return FALSE;
 
+    if (window == xwl_window->toplevel &&
+        !window_get_damage(window))
+        return register_damage(window);
+
     return TRUE;
 }
 
commit a562d01a184b2619adcf62b2283c8db04f2978a2
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Thu Feb 8 18:41:25 2024 +0100

    xwayland: Return struct xwl_window * from ensure_surface_for_window
    
    Preparation for later commits, no functional change intended.
    
    v2:
    * Leave register_damage call unchanged in this commit. (Olivier Fourdan)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 51ea27243..fdd4b287a 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -1225,7 +1225,7 @@ err_surf:
     return FALSE;
 }
 
-static Bool
+static struct xwl_window *
 ensure_surface_for_window(WindowPtr window)
 {
     ScreenPtr screen = window->drawable.pScreen;
@@ -1233,23 +1233,24 @@ ensure_surface_for_window(WindowPtr window)
     struct xwl_window *xwl_window;
     WindowPtr toplevel;
 
-    if (xwl_window_from_window(window))
-        return TRUE;
+    xwl_window = xwl_window_from_window(window);
+    if (xwl_window)
+        return xwl_window;
 
     xwl_screen = xwl_screen_get(screen);
 
     if (xwl_screen->rootless) {
         if (window->redirectDraw != RedirectDrawManual)
-            return TRUE;
+            return NULL;
     }
     else {
         if (window->parent)
-            return TRUE;
+            return NULL;
     }
 
     xwl_window = calloc(1, sizeof *xwl_window);
     if (xwl_window == NULL)
-        return FALSE;
+        return NULL;
 
     xwl_window->xwl_screen = xwl_screen;
     xwl_window->toplevel = window;
@@ -1312,11 +1313,11 @@ ensure_surface_for_window(WindowPtr window)
             xwl_screen->tearing_control_manager, xwl_window->surface);
     }
 
-    return TRUE;
+    return xwl_window;
 
 err:
     free(xwl_window);
-    return FALSE;
+    return NULL;
 }
 
 Bool
@@ -1325,6 +1326,7 @@ xwl_realize_window(WindowPtr window)
     ScreenPtr screen = window->drawable.pScreen;
     CompScreenPtr comp_screen = GetCompScreen(screen);
     struct xwl_screen *xwl_screen;
+    struct xwl_window *xwl_window;
     Bool ret;
 
     xwl_screen = xwl_screen_get(screen);
@@ -1366,7 +1368,11 @@ xwl_realize_window(WindowPtr window)
             return FALSE;
     }
 
-    return ensure_surface_for_window(window);
+    xwl_window = ensure_surface_for_window(window);
+    if (!xwl_window)
+        return FALSE;
+
+    return TRUE;
 }
 
 static void
@@ -1539,15 +1545,14 @@ xwl_window_set_window_pixmap(WindowPtr window,
     if (!RegionNotEmpty(&window->winSize))
         return;
 
-    ensure_surface_for_window(window);
+    xwl_window = ensure_surface_for_window(window);
 
-    if (old_pixmap->drawable.width == pixmap->drawable.width &&
-        old_pixmap->drawable.height == pixmap->drawable.height)
+    if (!xwl_window ||
+        (old_pixmap->drawable.width == pixmap->drawable.width &&
+         old_pixmap->drawable.height == pixmap->drawable.height))
        return;
 
-    xwl_window = xwl_window_get(window);
-    if (xwl_window)
-        xwl_window_buffers_dispose(xwl_window);
+    xwl_window_buffers_dispose(xwl_window);
 }
 
 Bool
commit 972d5af53785eea924aaddf91b1b2d479cbb4add
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Fri Dec 22 16:54:40 2023 +0100

    xwayland: Rename xwl_window::window to ::toplevel
    
    It's always the toplevel window, i.e. either the root window or a child
    of it.
    
    Preparation for later commits, no functional change.
    
    v2: (Olivier Fourdan)
    * Fix debug build.
    * Add comment describing ::toplevel.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-dmabuf.c b/hw/xwayland/xwayland-dmabuf.c
index 4897c2708..97c501273 100644
--- a/hw/xwayland/xwayland-dmabuf.c
+++ b/hw/xwayland/xwayland-dmabuf.c
@@ -735,7 +735,7 @@ xwl_window_dmabuf_feedback_done(void *data,
                                 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
 {
     struct xwl_window *xwl_window = data;
-    uint32_t format = wl_drm_format_for_depth(xwl_window->window->drawable.depth);
+    uint32_t format = wl_drm_format_for_depth(xwl_window->toplevel->drawable.depth);
 
     xwl_dmabuf_feedback_done(&xwl_window->feedback, dmabuf_feedback);
 
@@ -743,7 +743,7 @@ xwl_window_dmabuf_feedback_done(void *data,
         xwl_feedback_is_modifier_supported(&xwl_window->feedback, format,
                                            DRM_FORMAT_MOD_INVALID, TRUE);
     DebugF("XWAYLAND: Window 0x%x can%s get implicit scanout support\n",
-            xwl_window->window->drawable.id,
+            xwl_window->toplevel->drawable.id,
             xwl_window->has_implicit_scanout_support ? "" : "not");
 
     /* If the linux-dmabuf v4 per-surface feedback changed, make sure the
diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c
index 5bfbb3262..b5b0c2a1c 100644
--- a/hw/xwayland/xwayland-glamor-gbm.c
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -412,7 +412,7 @@ PixmapPtr
 xwl_glamor_create_pixmap_for_window(struct xwl_window *xwl_window)
 {
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
-    WindowPtr window = xwl_window->window;
+    WindowPtr window = xwl_window->toplevel;
     unsigned border_width = 2 * window->borderWidth;
 
     if (!xwl_screen->glamor)
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 3b3337869..7447de102 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -543,8 +543,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
     xwl_seat->pointer_enter_serial = serial;
 
     xwl_seat->focus_window = wl_surface_get_user_data(surface);
-    dx = xwl_seat->focus_window->window->drawable.x;
-    dy = xwl_seat->focus_window->window->drawable.y;
+    dx = xwl_seat->focus_window->toplevel->drawable.x;
+    dy = xwl_seat->focus_window->toplevel->drawable.y;
 
     /* We just entered a new xwindow, forget about the old last xwindow */
     xwl_seat->last_focus_window = NULL;
@@ -660,8 +660,8 @@ dispatch_absolute_motion(struct xwl_seat *xwl_seat)
     int flags;
     int event_x = wl_fixed_to_int(xwl_seat->pending_pointer_event.x);
     int event_y = wl_fixed_to_int(xwl_seat->pending_pointer_event.y);
-    int drawable_x = xwl_seat->focus_window->window->drawable.x;
-    int drawable_y = xwl_seat->focus_window->window->drawable.y;
+    int drawable_x = xwl_seat->focus_window->toplevel->drawable.x;
+    int drawable_y = xwl_seat->focus_window->toplevel->drawable.y;
     int x;
     int y;
 
@@ -1411,8 +1411,8 @@ xwl_touch_send_event(struct xwl_touch *xwl_touch,
     double dx, dy, x, y;
     ValuatorMask mask;
 
-    dx = xwl_touch->window->window->drawable.x;
-    dy = xwl_touch->window->window->drawable.y;
+    dx = xwl_touch->window->toplevel->drawable.x;
+    dy = xwl_touch->window->toplevel->drawable.y;
 
     x = (dx + xwl_touch->x) * 0xFFFF / xwl_screen_get_width(xwl_seat->xwl_screen);
     y = (dy + xwl_touch->y) * 0xFFFF / xwl_screen_get_height(xwl_seat->xwl_screen);
@@ -2202,8 +2202,8 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
     sx *= xwl_seat->tablet_focus_window->viewport_scale_x;
     sy *= xwl_seat->tablet_focus_window->viewport_scale_y;
 
-    dx = xwl_seat->tablet_focus_window->window->drawable.x;
-    dy = xwl_seat->tablet_focus_window->window->drawable.y;
+    dx = xwl_seat->tablet_focus_window->toplevel->drawable.x;
+    dy = xwl_seat->tablet_focus_window->toplevel->drawable.y;
 
     xwl_tablet_tool->x = (double) dx + sx;
     xwl_tablet_tool->y = (double) dy + sy;
@@ -3193,8 +3193,8 @@ sprite_check_lost_focus(SpritePtr sprite, WindowPtr window)
 
     if (xwl_seat->focus_window == NULL &&
         xwl_seat->last_focus_window != NULL &&
-        (xwl_seat->last_focus_window->window == window ||
-         IsParent(xwl_seat->last_focus_window->window, window)))
+        (xwl_seat->last_focus_window->toplevel == window ||
+         IsParent(xwl_seat->last_focus_window->toplevel, window)))
         return TRUE;
 
     return FALSE;
@@ -3257,7 +3257,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
     if (!warp_emulator->xwl_seat->focus_window)
         return;
 
-    window = warp_emulator->xwl_seat->focus_window->window;
+    window = warp_emulator->xwl_seat->focus_window->toplevel;
     if (x >= window->drawable.x ||
         y >= window->drawable.y ||
         x < (window->drawable.x + window->drawable.width) ||
@@ -3326,7 +3326,7 @@ xwl_pointer_warp_emulator_maybe_lock(struct xwl_pointer_warp_emulator *warp_emul
     if (pointer_grab &&
         !pointer_grab->ownerEvents &&
         sprite &&
-        XYToWindow(sprite, x, y) != xwl_seat->focus_window->window)
+        XYToWindow(sprite, x, y) != xwl_seat->focus_window->toplevel)
         return;
 
     xwl_pointer_warp_emulator_lock(warp_emulator);
@@ -3364,7 +3364,7 @@ xwl_pointer_warp_emulator_handle_motion(struct xwl_pointer_warp_emulator *warp_e
     QueuePointerEvents(xwl_seat->relative_pointer, MotionNotify, 0,
                        POINTER_RELATIVE, &mask);
 
-    window = xwl_seat->focus_window->window;
+    window = xwl_seat->focus_window->toplevel;
     miPointerGetPosition(xwl_seat->pointer, &x, &y);
 
     if (xwl_pointer_warp_emulator_is_locked(warp_emulator) &&
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 04c3033a5..2153ce6fb 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -785,7 +785,7 @@ xwl_present_check_flip(RRCrtcPtr crtc,
      * window's, e.g. because a client redirected this window or one of its
      * parents.
      */
-    if (screen->GetWindowPixmap(xwl_window->window) != screen->GetWindowPixmap(present_window))
+    if (screen->GetWindowPixmap(xwl_window->toplevel) != screen->GetWindowPixmap(present_window))
         return FALSE;
 
     /*
@@ -793,7 +793,7 @@ xwl_present_check_flip(RRCrtcPtr crtc,
      * dimensions as their xwl_window parent window. For the case of
      * different sizes subsurfaces are presumably the way forward.
      */
-    if (!RegionEqual(&xwl_window->window->winSize, &present_window->winSize))
+    if (!RegionEqual(&xwl_window->toplevel->winSize, &present_window->winSize))
         return FALSE;
 
     return TRUE;
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index 42c9a0e20..701425c08 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -305,7 +305,7 @@ xwl_cursor_warped_to(DeviceIntPtr device,
 
     xwl_window = xwl_window_from_window(window);
     if (!xwl_window && xwl_seat->focus_window) {
-        focus = xwl_seat->focus_window->window;
+        focus = xwl_seat->focus_window->toplevel;
 
         /* Warps on non wl_surface backed Windows are only allowed
          * as long as the pointer stays within the focus window.
@@ -339,15 +339,15 @@ find_matching_input_output_window(struct xwl_screen *xwl_screen,
         /* When confining happens on InputOnly windows, work out the InputOutput
          * window that would be covered by its geometry.
          */
-        if (window->drawable.x < xwl_window->window->drawable.x ||
+        if (window->drawable.x < xwl_window->toplevel->drawable.x ||
             window->drawable.x + window->drawable.width >
-            xwl_window->window->drawable.x + xwl_window->window->drawable.width ||
-            window->drawable.y < xwl_window->window->drawable.y ||
+            xwl_window->toplevel->drawable.x + xwl_window->toplevel->drawable.width ||
+            window->drawable.y < xwl_window->toplevel->drawable.y ||
             window->drawable.y + window->drawable.height >
-            xwl_window->window->drawable.y + xwl_window->window->drawable.height)
+            xwl_window->toplevel->drawable.y + xwl_window->toplevel->drawable.height)
             continue;
 
-        if (xwl_window->window->drawable.class == InputOnly)
+        if (xwl_window->toplevel->drawable.class == InputOnly)
             continue;
 
         return xwl_window;
diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c
index 042a55fc0..f66f36169 100644
--- a/hw/xwayland/xwayland-window-buffers.c
+++ b/hw/xwayland/xwayland-window-buffers.c
@@ -339,7 +339,7 @@ xwl_window_allocate_pixmap(struct xwl_window *xwl_window)
         return window_pixmap;
 #endif /* XWL_HAS_GLAMOR */
 
-    window_pixmap = screen->GetWindowPixmap(xwl_window->window);
+    window_pixmap = screen->GetWindowPixmap(xwl_window->toplevel);
     return screen->CreatePixmap(screen,
                                 window_pixmap->drawable.width,
                                 window_pixmap->drawable.height,
@@ -358,7 +358,7 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window)
     if (!new_window_pixmap)
         return;
 
-    window = xwl_window->window;
+    window = xwl_window->toplevel;
     screen = window->drawable.pScreen;
     window_pixmap = screen->GetWindowPixmap(window);
     copy_pixmap_area(window_pixmap,
@@ -366,7 +366,7 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window)
                      0, 0,
                      window_pixmap->drawable.width,
                      window_pixmap->drawable.height);
-    xwl_window_set_pixmap(xwl_window->window, new_window_pixmap);
+    xwl_window_set_pixmap(xwl_window->toplevel, new_window_pixmap);
     screen->DestroyPixmap(window_pixmap);
 }
 
@@ -393,7 +393,7 @@ xwl_window_buffers_set_syncpts(struct xwl_window_buffer *xwl_window_buffer)
     else
         goto fail;
 
-    xwl_glamor_dri3_syncobj_passthrough(xwl_window->window,
+    xwl_glamor_dri3_syncobj_passthrough(xwl_window->toplevel,
                                         xwl_window_buffer->syncobj,
                                         xwl_window_buffer->syncobj,
                                         acquire_point,
@@ -418,7 +418,7 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window)
     PixmapPtr window_pixmap;
     Bool implicit_sync = TRUE;
 
-    window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window);
+    window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->toplevel);
 
     xwl_window_buffer_add_damage_region(xwl_window);
 
@@ -441,8 +441,8 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window)
         while (nBox--) {
             copy_pixmap_area(window_pixmap,
                              xwl_window_buffer->pixmap,
-                             pBox->x1 + xwl_window->window->borderWidth,
-                             pBox->y1 + xwl_window->window->borderWidth,
+                             pBox->x1 + xwl_window->toplevel->borderWidth,
+                             pBox->y1 + xwl_window->toplevel->borderWidth,
                              pBox->x2 - pBox->x1,
                              pBox->y2 - pBox->y1);
 
@@ -451,7 +451,7 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window)
 
         RegionEmpty(xwl_window_buffer->damage_region);
         xorg_list_del(&xwl_window_buffer->link_buffer);
-        xwl_window_set_pixmap(xwl_window->window, xwl_window_buffer->pixmap);
+        xwl_window_set_pixmap(xwl_window->toplevel, xwl_window_buffer->pixmap);
 
         /* Can't re-use client pixmap as a window buffer */
         if (xwl_is_client_pixmap(window_pixmap)) {
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 2650e5cdd..51ea27243 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -87,7 +87,7 @@ window_get_damage(WindowPtr window)
 RegionPtr
 xwl_window_get_damage_region(struct xwl_window *xwl_window)
 {
-    return DamageRegion(window_get_damage(xwl_window->window));
+    return DamageRegion(window_get_damage(xwl_window->toplevel));
 }
 
 struct xwl_window *
@@ -133,9 +133,9 @@ xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow,
 
     xwl_window->allow_commits = allow;
     DebugF("XWAYLAND: win %d allow_commits = %d (%s)\n",
-           xwl_window->window->drawable.id, allow, debug_msg);
+           xwl_window->toplevel->drawable.id, allow, debug_msg);
 
-    damage = window_get_damage(xwl_window->window);
+    damage = window_get_damage(xwl_window->toplevel);
     if (allow &&
         xorg_list_is_empty(&xwl_window->link_damage) &&
         damage &&
@@ -207,7 +207,7 @@ damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
     if (xorg_list_is_empty(&xwl_window->link_damage))
         xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list);
 
-    window_pixmap = xwl_screen->screen->GetWindowPixmap(xwl_window->window);
+    window_pixmap = xwl_screen->screen->GetWindowPixmap(xwl_window->toplevel);
     if (xwl_is_client_pixmap(window_pixmap))
         xwl_screen->screen->DestroyPixmap(xwl_window_swap_pixmap(xwl_window));
 }
@@ -447,7 +447,7 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
     if (!xwl_screen->rootless)
         return FALSE;
 
-    window = window_get_client_toplevel(xwl_window->window);
+    window = window_get_client_toplevel(xwl_window->toplevel);
     if (!window)
         return FALSE;
 
@@ -479,7 +479,7 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
      */
     xwl_output = xwl_screen_get_first_output(xwl_screen);
     emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner);
-    if (xwl_output && xwl_window->window->overrideRedirect &&
+    if (xwl_output && xwl_window->toplevel->overrideRedirect &&
         emulated_mode && emulated_mode->from_vidmode &&
         drawable->x == 0 && drawable->y == 0 &&
         drawable->width  == xwl_screen_get_width(xwl_screen) &&
@@ -561,7 +561,7 @@ xwl_window_init_allow_commits(struct xwl_window *xwl_window)
     PropertyPtr prop = NULL;
     int ret;
 
-    ret = dixLookupProperty(&prop, xwl_window->window,
+    ret = dixLookupProperty(&prop, xwl_window->toplevel,
                             xwl_window->xwl_screen->allow_commits_prop,
                             serverClient, DixReadAccess);
     if (ret == Success && prop)
@@ -590,7 +590,7 @@ send_window_client_message(struct xwl_window *xwl_window, Atom type_atom, uint64
 
     e.u.u.type = ClientMessage;
     e.u.u.detail = 32;
-    e.u.clientMessage.window = xwl_window->window->drawable.id;
+    e.u.clientMessage.window = xwl_window->toplevel->drawable.id;
     e.u.clientMessage.u.l.type = type_atom;
     e.u.clientMessage.u.l.longs0 = serial_lo(value);
     e.u.clientMessage.u.l.longs1 = serial_hi(value);
@@ -685,7 +685,7 @@ xwl_window_rootful_update_fullscreen(struct xwl_window *xwl_window,
     if (!xwl_screen->fullscreen)
         return;
 
-    if (xwl_window->window != xwl_screen->screen->root)
+    if (xwl_window->toplevel != xwl_screen->screen->root)
         return;
 
     if (xwl_window->wl_output_fullscreen != xwl_output->output)
@@ -1148,7 +1148,7 @@ static Bool
 xwl_create_root_surface(struct xwl_window *xwl_window)
 {
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
-    WindowPtr window = xwl_window->window;
+    WindowPtr window = xwl_window->toplevel;
     struct wl_region *region;
 
 
@@ -1252,7 +1252,7 @@ ensure_surface_for_window(WindowPtr window)
         return FALSE;
 
     xwl_window->xwl_screen = xwl_screen;
-    xwl_window->window = window;
+    xwl_window->toplevel = window;
     xwl_window->fractional_scale_numerator = FRACTIONAL_SCALE_DENOMINATOR;
     xwl_window->viewport_scale_x = 1.0;
     xwl_window->viewport_scale_y = 1.0;
@@ -1723,15 +1723,15 @@ xwl_window_attach_buffer(struct xwl_window *xwl_window)
     if (RegionNumRects(region) > 256) {
         box = RegionExtents(region);
         xwl_surface_damage(xwl_screen, xwl_window->surface,
-                           box->x1 + xwl_window->window->borderWidth,
-                           box->y1 + xwl_window->window->borderWidth,
+                           box->x1 + xwl_window->toplevel->borderWidth,
+                           box->y1 + xwl_window->toplevel->borderWidth,
                            box->x2 - box->x1, box->y2 - box->y1);
     } else {
         box = RegionRects(region);
         for (i = 0; i < RegionNumRects(region); i++, box++) {
             xwl_surface_damage(xwl_screen, xwl_window->surface,
-                               box->x1 + xwl_window->window->borderWidth,
-                               box->y1 + xwl_window->window->borderWidth,
+                               box->x1 + xwl_window->toplevel->borderWidth,
+                               box->y1 + xwl_window->toplevel->borderWidth,
                                box->x2 - box->x1, box->y2 - box->y1);
         }
     }
@@ -1748,7 +1748,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
         return;
 
     xwl_window_create_frame_callback(xwl_window);
-    DamageEmpty(window_get_damage(xwl_window->window));
+    DamageEmpty(window_get_damage(xwl_window->toplevel));
 }
 
 Bool
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index a00284fde..7c75f9b80 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -62,7 +62,13 @@ struct xwl_window {
     int surface_scale;
     struct xdg_surface *xdg_surface;
     struct xdg_toplevel *xdg_toplevel;
-    WindowPtr window;
+
+    /* Top-level window for the Wayland surface:
+     * - With rootful, the root window itself
+     * - With rootless, a direct child of the root window
+     */
+    WindowPtr toplevel;
+
     struct xorg_list link_damage;
     struct xorg_list link_window;
     struct wl_callback *frame_callback;
commit 59a0259152a34801736548cb137b6264b283ea8a
Author: Michel Dänzer <mdaenzer at redhat.com>
Date:   Tue Mar 12 10:51:25 2024 +0100

    xwayland: Use xwl_window for tracking focus/touch
    
    Slightly simpler, and might work better in some cases when X windows
    get reparented.
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 3c546057d..3b3337869 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -547,7 +547,7 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
     dy = xwl_seat->focus_window->window->drawable.y;
 
     /* We just entered a new xwindow, forget about the old last xwindow */
-    xwl_seat->last_xwindow = NullWindow;
+    xwl_seat->last_focus_window = NULL;
 
     master = GetMaster(dev, POINTER_OR_FLOAT);
     (*pScreen->SetCursorPosition) (dev, pScreen, dx + sx, dy + sy, TRUE);
@@ -615,7 +615,7 @@ pointer_handle_leave(void *data, struct wl_pointer *pointer,
      * in sprite_check_lost_focus()
      */
     if (xwl_seat->focus_window) {
-        xwl_seat->last_xwindow = xwl_seat->focus_window->window;
+        xwl_seat->last_focus_window = xwl_seat->focus_window;
         xwl_seat->focus_window = NULL;
         focus_lost = TRUE;
     }
@@ -3192,8 +3192,9 @@ sprite_check_lost_focus(SpritePtr sprite, WindowPtr window)
         return TRUE;
 
     if (xwl_seat->focus_window == NULL &&
-        xwl_seat->last_xwindow != NullWindow &&
-        (IsParent(xwl_seat->last_xwindow, window) || xwl_seat->last_xwindow == window))
+        xwl_seat->last_focus_window != NULL &&
+        (xwl_seat->last_focus_window->window == window ||
+         IsParent(xwl_seat->last_focus_window->window, window)))
         return TRUE;
 
     return FALSE;
@@ -3227,13 +3228,13 @@ xwl_xy_to_window(ScreenPtr screen, SpritePtr sprite, int x, int y)
 }
 
 void
-xwl_seat_clear_touch(struct xwl_seat *xwl_seat, WindowPtr window)
+xwl_seat_clear_touch(struct xwl_seat *xwl_seat, struct xwl_window *xwl_window)
 {
     struct xwl_touch *xwl_touch, *next_xwl_touch;
 
     xorg_list_for_each_entry_safe(xwl_touch, next_xwl_touch,
                                   &xwl_seat->touches, link_touch) {
-        if (xwl_touch->window->window == window) {
+        if (xwl_touch->window == xwl_window) {
             xorg_list_del(&xwl_touch->link_touch);
             free(xwl_touch);
         }
diff --git a/hw/xwayland/xwayland-input.h b/hw/xwayland/xwayland-input.h
index 2e686f945..d40bca08a 100644
--- a/hw/xwayland/xwayland-input.h
+++ b/hw/xwayland/xwayland-input.h
@@ -81,7 +81,7 @@ struct xwl_seat {
     OsTimerPtr x_cursor_timer;
     CursorPtr pending_x_cursor;
     struct xwl_cursor cursor;
-    WindowPtr last_xwindow;
+    struct xwl_window *last_focus_window;
 
     uint32_t pointer_gesture_swipe_fingers;
     uint32_t pointer_gesture_pinch_fingers;
@@ -195,7 +195,7 @@ void xwl_seat_leave_kbd(struct xwl_seat *xwl_seat);
 
 void xwl_seat_destroy(struct xwl_seat *xwl_seat);
 
-void xwl_seat_clear_touch(struct xwl_seat *xwl_seat, WindowPtr window);
+void xwl_seat_clear_touch(struct xwl_seat *xwl_seat, struct xwl_window *xwl_window);
 
 void xwl_seat_emulate_pointer_warp(struct xwl_seat *xwl_seat,
                                    struct xwl_window *xwl_window,
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index a8731f4dd..2650e5cdd 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -1452,23 +1452,6 @@ xwl_unrealize_window(WindowPtr window)
 
     xwl_screen = xwl_screen_get(screen);
 
-    xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) {
-        if (xwl_seat->focus_window && xwl_seat->focus_window->window == window)
-            xwl_seat->focus_window = NULL;
-        if (xwl_seat->tablet_focus_window && xwl_seat->tablet_focus_window->window == window)
-            xwl_seat->tablet_focus_window = NULL;
-        if (xwl_seat->last_xwindow == window)
-            xwl_seat->last_xwindow = NullWindow;
-        if (xwl_seat->cursor_confinement_window &&
-            xwl_seat->cursor_confinement_window->window == window)
-            xwl_seat_unconfine_pointer(xwl_seat);
-        if (xwl_seat->pointer_warp_emulator &&
-            xwl_seat->pointer_warp_emulator->locked_window &&
-            xwl_seat->pointer_warp_emulator->locked_window->window == window)
-            xwl_seat_destroy_pointer_warp_emulator(xwl_seat);
-        xwl_seat_clear_touch(xwl_seat, window);
-    }
-
     compUnredirectWindow(serverClient, window, CompositeRedirectManual);
 
     screen->UnrealizeWindow = xwl_screen->UnrealizeWindow;
@@ -1480,6 +1463,21 @@ xwl_unrealize_window(WindowPtr window)
     if (!xwl_window)
         return ret;
 
+    xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) {
+        if (xwl_seat->focus_window == xwl_window)
+            xwl_seat->focus_window = NULL;
+        if (xwl_seat->tablet_focus_window == xwl_window)
+            xwl_seat->tablet_focus_window = NULL;
+        if (xwl_seat->last_focus_window == xwl_window)
+            xwl_seat->last_focus_window = NULL;
+        if (xwl_seat->cursor_confinement_window == xwl_window)
+            xwl_seat_unconfine_pointer(xwl_seat);
+        if (xwl_seat->pointer_warp_emulator &&
+            xwl_seat->pointer_warp_emulator->locked_window == xwl_window)
+            xwl_seat_destroy_pointer_warp_emulator(xwl_seat);
+        xwl_seat_clear_touch(xwl_seat, xwl_window);
+    }
+
     if (xwl_window_has_viewport_enabled(xwl_window))
         xwl_window_disable_viewport(xwl_window);
 #ifdef XWL_HAS_GLAMOR


More information about the xorg-commit mailing list