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.
This commit is contained in:
lkn 2026-06-27 19:14:55 +02:00
parent 0e0847b48b
commit 04f9a36da7
3 changed files with 21 additions and 5 deletions

View File

@ -3,6 +3,7 @@
#endif
#include <wayland-server-core.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_output.h>
#include <wlr/backend/session.h>
#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)

View File

@ -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;

View File

@ -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);