From 27bcf8c2ad3827e80f682e31991c070c91fd7162 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Mon, 6 Apr 2026 19:47:01 +0200 Subject: [PATCH] toplevel-capture: work around stalls for captured windows in the capture scene This is part of the missing frame event workaround, this one handles stalls of the capture side when changing the visibility of the captured surface on the usual output. --- include/view.h | 1 + src/server.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++- src/view.c | 1 - 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/include/view.h b/include/view.h index cc1731b5..4f32013d 100644 --- a/include/view.h +++ b/include/view.h @@ -180,6 +180,7 @@ struct view { struct { struct wlr_scene *scene; struct wlr_ext_image_capture_source_v1 *source; + struct wl_listener on_capture_frame; struct wl_listener on_capture_source_destroy; } capture; diff --git a/src/server.c b/src/server.c index 189f0d15..29d8af24 100644 --- a/src/server.c +++ b/src/server.c @@ -429,14 +429,58 @@ handle_renderer_lost(struct wl_listener *listener, void *data) wlr_renderer_destroy(old_renderer); } +/* + * Partial workaround for toplevel capture on wlroots 0.20.0 + * There is a second part of this workaround in src/output.c which handles + * stalls on the primary output itself. This one handles stalls on the capture + * source only. + * + * See https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5315 + * + * TODO: Remove once we start tracking wlroots 0.21.x + * or labwc depends on wlroots >= 0.20.1 + */ + +static void +workaround_frame_done_iter(struct wlr_scene_buffer *buffer, int sx, int sy, void *data) +{ + struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(buffer); + if (!scene_surface) { + return; + } + wlr_surface_send_frame_done(scene_surface->surface, (struct timespec *)data); +} + +static void +handle_toplevel_capture_frame(struct wl_listener *listener, void *data) +{ + struct view *view = wl_container_of(listener, view, capture.on_capture_frame); + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_scene_node_for_each_buffer(&view->capture.scene->tree.node, + workaround_frame_done_iter, &now); +} + +/* Workaround for toplevel capture end */ + static void handle_toplevel_capture_source_destroy(struct wl_listener *listener, void *data) { struct view *view = wl_container_of(listener, view, capture.on_capture_source_destroy); assert(view->capture.source); view->capture.source = NULL; + + if (LAB_WLR_VERSION_LOWER(0, 20, 1)) { + /* + * Workaround for toplevel capture on wlroots 0.20.0 + * + * TODO: Remove once we start tracking wlroots 0.21.x + * or labwc depends on wlroots >= 0.20.1 + */ + wl_list_remove(&view->capture.on_capture_frame.link); + } + wl_list_remove(&listener->link); - wl_list_init(&listener->link); } static void @@ -457,7 +501,20 @@ handle_toplevel_capture_request(struct wl_listener *listener, void *data) handle_toplevel_capture_source_destroy; wl_signal_add(&view->capture.source->events.destroy, &view->capture.on_capture_source_destroy); + + /* + * Workaround for toplevel capture on wlroots 0.20.0 + * + * TODO: Remove once we start tracking wlroots 0.21.x + * or labwc depends on wlroots >= 0.20.1 + */ + if (LAB_WLR_VERSION_LOWER(0, 20, 1)) { + view->capture.on_capture_frame.notify = handle_toplevel_capture_frame; + wl_signal_add(&view->capture.source->events.frame, + &view->capture.on_capture_frame); + } } + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept( request, view->capture.source); diff --git a/src/view.c b/src/view.c index 4321285d..7bd1d898 100644 --- a/src/view.c +++ b/src/view.c @@ -2507,7 +2507,6 @@ view_destroy(struct view *view) wl_list_remove(&view->request_fullscreen.link); wl_list_remove(&view->set_title.link); wl_list_remove(&view->destroy.link); - wl_list_remove(&view->capture.on_capture_source_destroy.link); wlr_scene_node_destroy(&view->capture.scene->tree.node);