From fb4102b5ae1891282c0d35a856e4eaa2118dfd02 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 12 Sep 2026 10:28:05 +0200 Subject: [PATCH] support screenshare of single windows Supersedes https://codeberg.org/dwl/dwl/pulls/1157. Co-authored-by: Zuki Air --- dwl.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/dwl.c b/dwl.c index bbd5b98..fa8c8ae 100644 --- a/dwl.c +++ b/dwl.c @@ -121,6 +121,12 @@ typedef struct { } surface; struct wlr_xdg_toplevel_decoration_v1 *decoration; struct wlr_ext_foreign_toplevel_handle_v1 *foreign_toplevel_handle; + struct wlr_scene *image_capture_scene; + struct wlr_ext_image_capture_source_v1 *image_capture_source; + union { + struct wlr_scene_tree *image_capture_tree; + struct wlr_scene_surface *image_capture_scene_surface; + } capture; struct wl_listener commit; struct wl_listener map; struct wl_listener maximize; @@ -251,6 +257,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list, static void arrangelayers(Monitor *m); static void axisnotify(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data); +static void capturerequest(struct wl_listener *listener, void *data); static void chvt(const Arg *arg); static void checkidleinhibitor(struct wlr_surface *exclude); static void cleanup(void); @@ -386,6 +393,7 @@ static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; static struct wlr_output_power_manager_v1 *power_mgr; static struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list; +static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *ext_foreign_toplevel_image_capture_source_manager_v1; static struct wlr_pointer_constraints_v1 *pointer_constraints; static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; @@ -440,6 +448,7 @@ static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape}; static struct wl_listener request_start_drag = {.notify = requeststartdrag}; static struct wl_listener start_drag = {.notify = startdrag}; static struct wl_listener new_session_lock = {.notify = locksession}; +static struct wl_listener new_foreign_toplevel_capture_request = {.notify = capturerequest}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -688,6 +697,23 @@ buttonpress(struct wl_listener *listener, void *data) event->time_msec, event->button, event->state); } +void +capturerequest(struct wl_listener *listener, void *data) +{ + struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request = data; + Client *view = request->toplevel_handle->data; + + if (!view->image_capture_source) { + view->image_capture_source = wlr_ext_image_capture_source_v1_create_with_scene_node( + &view->image_capture_scene->tree.node, event_loop, alloc, drw); + if (!view->image_capture_source) + return; + } + + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept( + request, view->image_capture_source); +} + void chvt(const Arg *arg) { @@ -800,6 +826,7 @@ cleanuplisteners(void) wl_list_remove(&request_start_drag.link); wl_list_remove(&start_drag.link); wl_list_remove(&new_session_lock.link); + wl_list_remove(&new_foreign_toplevel_capture_request.link); #ifdef XWAYLAND wl_list_remove(&new_xwayland_surface.link); wl_list_remove(&xwayland_ready.link); @@ -1838,6 +1865,14 @@ mapnotify(struct wl_listener *listener, void *data) c->foreign_toplevel_handle = wlr_ext_foreign_toplevel_handle_v1_create( foreign_toplevel_list, &foreign_toplevel_state); c->foreign_toplevel_handle->data = c; + c->image_capture_scene = wlr_scene_create(); + if (c->type == XDGShell) + c->capture.image_capture_tree = wlr_scene_xdg_surface_create(&c->image_capture_scene->tree, c->surface.xdg); +#ifdef XWAYLAND + else + c->capture.image_capture_scene_surface = wlr_scene_surface_create(&c->image_capture_scene->tree, c->surface.xwayland->surface); +#endif + /* Set initial monitor, tags, floating status, and focus: * we always consider floating, clients that have parent and thus @@ -2630,6 +2665,10 @@ setup(void) wlr_scene_node_set_enabled(&locked_bg->node, 0); foreign_toplevel_list = wlr_ext_foreign_toplevel_list_v1_create(dpy,1); + ext_foreign_toplevel_image_capture_source_manager_v1 = + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(dpy, 1); + wl_signal_add(&ext_foreign_toplevel_image_capture_source_manager_v1->events.new_request, + &new_foreign_toplevel_capture_request); /* Use decoration protocols to negotiate server-side decorations */ wlr_server_decoration_manager_set_default_mode( @@ -2898,6 +2937,14 @@ unmapnotify(struct wl_listener *listener, void *data) wlr_ext_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel_handle); c->foreign_toplevel_handle = NULL; } +#ifdef XWAYLAND + if (c->type != XDGShell && c->capture.image_capture_scene_surface) { + wlr_scene_node_destroy(&c->capture.image_capture_scene_surface->buffer->node); + c->capture.image_capture_scene_surface = NULL; + } +#endif + + wlr_scene_node_destroy(&c->image_capture_scene->tree.node); wlr_scene_node_destroy(&c->scene->node); client_surface(c)->data = NULL; printstatus();