From f1ac8f600886ebd4eeecbd175120bd271f394ba1 Mon Sep 17 00:00:00 2001 From: Mental-Vortex <206187961+Mental-Vortex@users.noreply.github.com> Date: Thu, 5 Feb 2026 01:53:46 +0800 Subject: [PATCH] Add support for toplevel capture --- include/labwc.h | 3 +++ include/view.h | 5 +++++ src/foreign-toplevel/ext-foreign.c | 2 ++ src/server.c | 26 ++++++++++++++++++++++++++ src/view.c | 11 +++++++++++ src/xdg.c | 5 +++++ 6 files changed, 52 insertions(+) diff --git a/include/labwc.h b/include/labwc.h index c4848a11..968a4276 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -284,6 +284,9 @@ struct server { struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list; + struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *ext_foreign_toplevel_image_capture_source_manager_v1; + struct wl_listener new_foreign_toplevel_capture_request; + struct wlr_drm_lease_v1_manager *drm_lease_manager; struct wl_listener drm_lease_request; diff --git a/include/view.h b/include/view.h index d2ff5ddf..a785833c 100644 --- a/include/view.h +++ b/include/view.h @@ -168,6 +168,9 @@ struct view { struct wlr_scene_tree *scene_tree; struct wlr_scene_tree *content_tree; /* may be NULL for unmapped view */ + struct wlr_scene *image_capture_scene; + struct wlr_ext_image_capture_source_v1 *image_capture_source; + /* These are never NULL and an empty string is set instead. */ char *title; char *app_id; /* WM_CLASS for xwayland windows */ @@ -300,6 +303,8 @@ struct xdg_toplevel_view { /* Optional black background fill behind fullscreen view */ struct wlr_scene_rect *fullscreen_bg; + struct wlr_scene_tree *image_capture_tree; + /* Events unique to xdg-toplevel views */ struct wl_listener set_app_id; struct wl_listener request_show_window_menu; diff --git a/src/foreign-toplevel/ext-foreign.c b/src/foreign-toplevel/ext-foreign.c index 748050fa..e8e68433 100644 --- a/src/foreign-toplevel/ext-foreign.c +++ b/src/foreign-toplevel/ext-foreign.c @@ -75,6 +75,8 @@ ext_foreign_toplevel_init(struct ext_foreign_toplevel *ext_toplevel, return; } + ext_toplevel->handle->data = view; + /* Client side requests */ ext_toplevel->on.handle_destroy.notify = handle_handle_destroy; wl_signal_add(&ext_toplevel->handle->events.destroy, &ext_toplevel->on.handle_destroy); diff --git a/src/server.c b/src/server.c index 76a69fa0..c0fe49c1 100644 --- a/src/server.c +++ b/src/server.c @@ -424,6 +424,25 @@ handle_renderer_lost(struct wl_listener *listener, void *data) wlr_renderer_destroy(old_renderer); } +static void +handle_new_foreign_toplevel_capture_request(struct wl_listener *listener, void *data) { + struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request = data; + struct view *view = request->toplevel_handle->data; + struct server *server = wl_container_of(listener, server, + new_foreign_toplevel_capture_request); + + if (view->image_capture_source == NULL) { + view->image_capture_source = wlr_ext_image_capture_source_v1_create_with_scene_node( + &view->image_capture_scene->tree.node,server->wl_event_loop,server->allocator,server->renderer); + if (view->image_capture_source == NULL) { + wlr_log(WLR_ERROR, "Failed to create image capture source"); + return; + } + } + + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept(request, view->image_capture_source); +} + void server_init(struct server *server) { @@ -671,6 +690,12 @@ server_init(struct server *server) wlr_fractional_scale_manager_v1_create(server->wl_display, LAB_WLR_FRACTIONAL_SCALE_V1_VERSION); + server->ext_foreign_toplevel_image_capture_source_manager_v1 = + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(server->wl_display, 1); + server->new_foreign_toplevel_capture_request.notify = handle_new_foreign_toplevel_capture_request; + wl_signal_add(&server->ext_foreign_toplevel_image_capture_source_manager_v1->events.new_request, + &server->new_foreign_toplevel_capture_request); + idle_manager_create(server->wl_display); server->relative_pointer_manager = wlr_relative_pointer_manager_v1_create( @@ -788,6 +813,7 @@ server_finish(struct server *server) wl_list_remove(&server->new_constraint.link); wl_list_remove(&server->output_power_manager_set_mode.link); wl_list_remove(&server->tearing_new_object.link); + wl_list_remove(&server->new_foreign_toplevel_capture_request.link); if (server->drm_lease_request.notify) { wl_list_remove(&server->drm_lease_request.link); server->drm_lease_request.notify = NULL; diff --git a/src/view.c b/src/view.c index 20f3bbdc..78099f99 100644 --- a/src/view.c +++ b/src/view.c @@ -2525,6 +2525,12 @@ view_init(struct view *view) wl_signal_init(&view->events.set_icon); wl_signal_init(&view->events.destroy); + view->image_capture_scene = wlr_scene_create(); + if (view->image_capture_scene == NULL) { + wlr_log(WLR_ERROR, "not image_capture_scene"); + } + view->image_capture_scene->restack_xwayland_surfaces = false; + view->title = xstrdup(""); view->app_id = xstrdup(""); } @@ -2593,6 +2599,11 @@ view_destroy(struct view *view) view->scene_tree = NULL; } + if (view->image_capture_scene) { + wlr_scene_node_destroy(&view->image_capture_scene->tree.node); + view->image_capture_scene = NULL; + } + assert(wl_list_empty(&view->events.new_app_id.listener_list)); assert(wl_list_empty(&view->events.new_title.listener_list)); assert(wl_list_empty(&view->events.new_outputs.listener_list)); diff --git a/src/xdg.c b/src/xdg.c index b239e8da..a1459c97 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -1030,6 +1030,11 @@ handle_new_xdg_toplevel(struct wl_listener *listener, void *data) free(xdg_toplevel_view); return; } + + xdg_toplevel_view->image_capture_tree = + wlr_scene_xdg_surface_create(&view->image_capture_scene->tree, + xdg_surface); + view->content_tree = tree; node_descriptor_create(&view->scene_tree->node, LAB_NODE_VIEW, view, /*data*/ NULL);