xwayland: Avoid premature surface commit running rootfull

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 <ofourdan@redhat.com>

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: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2110>
(cherry picked from commit 37f59e1a4d)
This commit is contained in:
Olivier Fourdan 2026-01-09 14:10:38 +01:00 committed by Alan Coopersmith
parent cdb2cb6cbc
commit f5d8e11288
4 changed files with 33 additions and 6 deletions

View file

@ -873,7 +873,9 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage)
struct xwl_present_event *event = xwl_present_event_from_vblank(vblank); struct xwl_present_event *event = xwl_present_event_from_vblank(vblank);
Bool implicit_sync = TRUE; 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; return FALSE;
buffer = xwl_pixmap_get_wl_buffer(pixmap); buffer = xwl_pixmap_get_wl_buffer(pixmap);

View file

@ -454,6 +454,12 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen)
if (!xwl_window->allow_commits) if (!xwl_window->allow_commits)
continue; 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); xwl_window_post_damage(xwl_window);
xorg_list_del(&xwl_window->link_damage); xorg_list_del(&xwl_window->link_damage);
xorg_list_append(&xwl_window->link_damage, &commit_window_list); xorg_list_append(&xwl_window->link_damage, &commit_window_list);

View file

@ -360,6 +360,13 @@ unregister_damage(struct xwl_window *xwl_window)
dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, NULL); 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 static Bool
xwl_window_update_fractional_scale(struct xwl_window *xwl_window, xwl_window_update_fractional_scale(struct xwl_window *xwl_window,
int fractional_scale_numerator) 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); xdg_toplevel_set_fullscreen(xwl_window->xdg_toplevel, wl_output);
xwl_window_check_resolution_change_emulation(xwl_window); 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; 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, xwl_window_update_libdecor_size(xwl_window, configuration,
round(new_width), round(new_height)); 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 static void
@ -1054,7 +1066,12 @@ xdg_surface_handle_configure(void *data,
xwl_window_set_fullscreen(xwl_window); xwl_window_set_fullscreen(xwl_window);
xdg_surface_ack_configure(xdg_surface, serial); 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 = { static const struct xdg_surface_listener xdg_surface_listener = {
@ -1095,7 +1112,7 @@ xwl_window_update_surface_scale(struct xwl_window *xwl_window)
} }
else else
#endif #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 else
#endif #endif
wl_surface_commit(xwl_window->surface); xwl_window_maybe_commit_surface(xwl_window);
} }
static void 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_update_title(xwl_window);
xwl_window_rootful_set_app_id(xwl_window); xwl_window_rootful_set_app_id(xwl_window);
wl_surface_commit(xwl_window->surface); wl_surface_commit(xwl_window->surface);
xwl_window->awaiting_initial_configure_event = TRUE;
region = wl_compositor_create_region(xwl_screen->compositor); region = wl_compositor_create_region(xwl_screen->compositor);
if (region == NULL) { if (region == NULL) {

View file

@ -106,6 +106,7 @@ struct xwl_window {
struct wp_fractional_scale_v1 *fractional_scale; struct wp_fractional_scale_v1 *fractional_scale;
int fractional_scale_numerator; int fractional_scale_numerator;
struct wp_linux_drm_syncobj_surface_v1 *surface_sync; struct wp_linux_drm_syncobj_surface_v1 *surface_sync;
Bool awaiting_initial_configure_event;
}; };
struct xwl_window *xwl_window_get(WindowPtr window); struct xwl_window *xwl_window_get(WindowPtr window);