From f5d8e11288da63a81ab349731420a50d8f406932 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Fri, 9 Jan 2026 14:10:38 +0100 Subject: [PATCH] xwayland: Avoid premature surface commit running rootfull MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running rootful, i.e. as a regular Wayland client, Xwayland needs to wait for the initial configure event before posting its initial buffer and commit the surface. Not doing so may cause mutter to log a warning when Xwayland is started rootful: | Buggy client (org.freedesktop.Xwayland) committed initial non-empty | content without acknowledging configuration, working around. Or running rootful with libdecor: | Client provided invalid window geometry for xdg_surface#nn | (org.freedesktop.Xwayland - Wnn (Xwayland on :nn)). Working around. | | Buggy client (org.freedesktop.Xwayland) committed initial non-empty | content without acknowledging configuration, working around. This is actually mutter being nice, as this should be treated as a protocol error and Xwayland would be terminated. To avoid the issue, we need to hold on attaching a buffer and committing the surface until we actually get the first configure event from the compositor. That, however, only applies to rootful mode, so we can leave the default code path for rootless untouched. Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1853 Signed-off-by: Olivier Fourdan v2: commit the surface after attaching the first buffer on configure event only for the initial configure (Michel Dänzer). v3: return early in present flip if we didn't get the initial configure event (Michel Dänzer). Part-of: (cherry picked from commit 37f59e1a4d2c4bc8a377894102606c214066d0ad) --- hw/xwayland/xwayland-present.c | 4 +++- hw/xwayland/xwayland-screen.c | 6 ++++++ hw/xwayland/xwayland-window.c | 28 +++++++++++++++++++++++----- hw/xwayland/xwayland-window.h | 1 + 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index dcacb8ee8..8e800d91b 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -873,7 +873,9 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage) struct xwl_present_event *event = xwl_present_event_from_vblank(vblank); Bool implicit_sync = TRUE; - if (!xwl_window || !xwl_window->allow_commits) + if (!xwl_window || + !xwl_window->allow_commits || + xwl_window->awaiting_initial_configure_event) return FALSE; buffer = xwl_pixmap_get_wl_buffer(pixmap); diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c index edb8007a5..1bdd957db 100644 --- a/hw/xwayland/xwayland-screen.c +++ b/hw/xwayland/xwayland-screen.c @@ -454,6 +454,12 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen) if (!xwl_window->allow_commits) continue; + /* Running rootful, we must wait for the initial configuration + * negotiation to complete before we can post damage. + */ + if (xwl_window->awaiting_initial_configure_event) + continue; + xwl_window_post_damage(xwl_window); xorg_list_del(&xwl_window->link_damage); xorg_list_append(&xwl_window->link_damage, &commit_window_list); diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index 7a7a54da4..7d6599089 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -360,6 +360,13 @@ unregister_damage(struct xwl_window *xwl_window) dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, NULL); } +static void +xwl_window_maybe_commit_surface(struct xwl_window *xwl_window) +{ + if (!xwl_window->awaiting_initial_configure_event) + wl_surface_commit(xwl_window->surface); +} + static Bool xwl_window_update_fractional_scale(struct xwl_window *xwl_window, int fractional_scale_numerator) @@ -828,7 +835,7 @@ xwl_window_set_fullscreen(struct xwl_window *xwl_window) xdg_toplevel_set_fullscreen(xwl_window->xdg_toplevel, wl_output); xwl_window_check_resolution_change_emulation(xwl_window); - wl_surface_commit(xwl_window->surface); + xwl_window_maybe_commit_surface(xwl_window); xwl_window->wl_output_fullscreen = wl_output; @@ -1008,7 +1015,12 @@ handle_libdecor_configure(struct libdecor_frame *frame, xwl_window_update_libdecor_size(xwl_window, configuration, round(new_width), round(new_height)); - wl_surface_commit(xwl_window->surface); + + if (xwl_window->awaiting_initial_configure_event) { + xwl_window->awaiting_initial_configure_event = FALSE; + xwl_window_attach_buffer(xwl_window); + wl_surface_commit(xwl_window->surface); + } } static void @@ -1054,7 +1066,12 @@ xdg_surface_handle_configure(void *data, xwl_window_set_fullscreen(xwl_window); xdg_surface_ack_configure(xdg_surface, serial); - wl_surface_commit(xwl_window->surface); + + if (xwl_window->awaiting_initial_configure_event) { + xwl_window->awaiting_initial_configure_event = FALSE; + xwl_window_attach_buffer(xwl_window); + wl_surface_commit(xwl_window->surface); + } } static const struct xdg_surface_listener xdg_surface_listener = { @@ -1095,7 +1112,7 @@ xwl_window_update_surface_scale(struct xwl_window *xwl_window) } else #endif - wl_surface_commit(xwl_window->surface); + xwl_window_maybe_commit_surface(xwl_window); } } @@ -1280,7 +1297,7 @@ xwl_window_update_rootful_scale(struct xwl_window *xwl_window, double previous_s } else #endif - wl_surface_commit(xwl_window->surface); + xwl_window_maybe_commit_surface(xwl_window); } static void @@ -1360,6 +1377,7 @@ xwl_create_root_surface(struct xwl_window *xwl_window) xwl_window_rootful_update_title(xwl_window); xwl_window_rootful_set_app_id(xwl_window); wl_surface_commit(xwl_window->surface); + xwl_window->awaiting_initial_configure_event = TRUE; region = wl_compositor_create_region(xwl_screen->compositor); if (region == NULL) { diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h index ac3ce5034..09d53054c 100644 --- a/hw/xwayland/xwayland-window.h +++ b/hw/xwayland/xwayland-window.h @@ -106,6 +106,7 @@ struct xwl_window { struct wp_fractional_scale_v1 *fractional_scale; int fractional_scale_numerator; struct wp_linux_drm_syncobj_surface_v1 *surface_sync; + Bool awaiting_initial_configure_event; }; struct xwl_window *xwl_window_get(WindowPtr window);