From 04f9a36da746dcf9bab2d63271c7ccf162a60e19 Mon Sep 17 00:00:00 2001 From: lkn Date: Sat, 27 Jun 2026 19:14:55 +0200 Subject: [PATCH] wayland: fix XWayland startup speed and swapchain exhaustion Two fixes: 1. Handle request_configure for XWayland surfaces. Without this, X clients block waiting for ConfigureNotify on startup (5s timeout). Now we immediately ACK with wlr_xwayland_surface_configure. 2. Replace direct wlr_scene_output_commit in wl_event_flush with wlr_output_schedule_frame. Rendering happens in handle_output_frame when the output is ready. Eliminates 'No free output buffer slot' spam and prevents reentrant dispatch crashes. --- src/backend/wayland/wl_event.c | 13 ++++++++----- src/backend/wayland/wl_types.h | 1 + src/backend/wayland/wl_xwayland.c | 12 ++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/backend/wayland/wl_event.c b/src/backend/wayland/wl_event.c index 4ff5877..d40133c 100644 --- a/src/backend/wayland/wl_event.c +++ b/src/backend/wayland/wl_event.c @@ -3,6 +3,7 @@ #endif #include #include +#include #include #include "../../screen.h" #include "wl_types.h" @@ -11,12 +12,14 @@ void wl_event_flush(void) { wl_xdisplay_flush(); - /* Commit the scene so intermediate animation frames are visible */ - if (wl_state.scene_output && wl_state.allocator && - (!wl_state.session || wl_state.session->active)) { - wlr_scene_output_commit(wl_state.scene_output, NULL); + /* Schedule a frame so the output callback commits the scene. + * Do NOT commit directly here — reentrant commits exhaust the + * swapchain ("No free output buffer slot") and cause UAF when + * the dispatch processes unmap signals recursively. */ + if (wl_state.output) + wlr_output_schedule_frame(wl_state.output); + if (wl_state.display) wl_display_flush_clients(wl_state.display); - } } void wl_event_flush_expose(void) {} void wl_event_sync(int discard) diff --git a/src/backend/wayland/wl_types.h b/src/backend/wayland/wl_types.h index 4bb44ef..23c035b 100644 --- a/src/backend/wayland/wl_types.h +++ b/src/backend/wayland/wl_types.h @@ -45,6 +45,7 @@ struct wl_toplevel_view { struct wlr_xwayland_surface *xw_surface; /* Path 1: geometry listener — keeps scene node in sync when X11 window moves. */ struct wl_listener xw_geometry_listener; + struct wl_listener xw_request_configure_listener; struct wl_listener xw_surface_map_listener; /* fires when wlr_surface maps */ /* Phase 18: scene graph tree for this surface (NULL if scene unavailable). */ struct wlr_scene_tree *scene_node; diff --git a/src/backend/wayland/wl_xwayland.c b/src/backend/wayland/wl_xwayland.c index 7ec4284..2d37ccc 100644 --- a/src/backend/wayland/wl_xwayland.c +++ b/src/backend/wayland/wl_xwayland.c @@ -97,6 +97,15 @@ handle_or_set_geometry(struct wl_listener *listener, void *data) /* --- Managed XWayland surface handlers --- */ +static void +handle_xwayland_request_configure(struct wl_listener *listener, void *data) +{ + struct wl_toplevel_view *view = VIEW_FROM_LISTENER(listener, xw_request_configure_listener); + struct wlr_xwayland_surface_configure_event *ev = data; + wlr_xwayland_surface_configure(view->xw_surface, + ev->x, ev->y, ev->width, ev->height); +} + static void handle_xwayland_request_fullscreen(struct wl_listener *listener, void *data) { @@ -244,6 +253,7 @@ handle_xwayland_destroy(struct wl_listener *listener, void *data) wl_list_remove(&view->destroy_listener.link); wl_list_remove(&view->title_listener.link); wl_list_remove(&view->request_fullscreen_listener.link); + wl_list_remove(&view->xw_request_configure_listener.link); if (view->xw_surface_map_listener.link.next && view->xw_surface_map_listener.link.next != &view->xw_surface_map_listener.link) wl_list_remove(&view->xw_surface_map_listener.link); @@ -407,6 +417,7 @@ handle_xwayland_new_surface(struct wl_listener *listener, void *data) view->destroy_listener.notify = handle_xwayland_destroy; view->title_listener.notify = handle_xwayland_set_class; view->xw_geometry_listener.notify = handle_xwayland_set_geometry; + view->xw_request_configure_listener.notify = handle_xwayland_request_configure; view->request_fullscreen_listener.notify = handle_xwayland_request_fullscreen; wl_signal_add(&xw->events.associate, &view->map_listener); @@ -414,6 +425,7 @@ handle_xwayland_new_surface(struct wl_listener *listener, void *data) wl_signal_add(&xw->events.destroy, &view->destroy_listener); wl_signal_add(&xw->events.set_class, &view->title_listener); wl_signal_add(&xw->events.set_geometry, &view->xw_geometry_listener); + wl_signal_add(&xw->events.request_configure, &view->xw_request_configure_listener); wl_signal_add(&xw->events.request_fullscreen, &view->request_fullscreen_listener); wl_list_insert(&wl_state.toplevel_list, &view->link);