From da7ff7bc4443e0405e1adec2b2ac02f3db7ab5a4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 1 Aug 2025 16:49:02 +0800 Subject: [PATCH 1/4] feat: support capture window in obs --- src/mango.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/mango.c b/src/mango.c index 48626455..a36427c0 100644 --- a/src/mango.c +++ b/src/mango.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -236,6 +237,11 @@ struct Client { struct wlr_scene_rect *border; /* top, bottom, left, right */ struct wlr_scene_shadow *shadow; struct wlr_scene_tree *scene_surface; + + struct wlr_scene_tree *image_capture_tree; + struct wlr_scene *image_capture_scene; + struct wlr_ext_image_capture_source_v1 *image_capture_source; + struct wl_list link; struct wl_list flink; struct wl_list fadeout_link; @@ -252,6 +258,8 @@ struct Client { struct wl_listener set_title; struct wl_listener fullscreen; #ifdef XWAYLAND + struct wlr_scene_surface *image_capture_scene_surface; + struct wl_listener activate; struct wl_listener associate; struct wl_listener dissociate; @@ -311,6 +319,7 @@ struct Client { char oldmonname[128]; int scratchpad_width, scratchpad_height; int noblur; + struct wlr_ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel; }; typedef struct { @@ -723,6 +732,11 @@ static unsigned int cursor_mode; static Client *grabc; static int grabcx, grabcy; /* client-relative */ +static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 + *ext_foreign_toplevel_image_capture_source_manager_v1; +static struct wl_listener new_foreign_toplevel_capture_request; +static struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list; + static struct wlr_output_layout *output_layout; static struct wlr_box sgeom; static struct wl_list mons; @@ -1886,6 +1900,7 @@ void 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); @@ -3281,6 +3296,22 @@ mapnotify(struct wl_listener *listener, void *data) { c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; + c->image_capture_scene = wlr_scene_create(); + + struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state = { + .app_id = client_get_appid(c), + .title = client_get_title(c), + }; + c->image_capture_scene = wlr_scene_create(); + c->ext_foreign_toplevel = wlr_ext_foreign_toplevel_handle_v1_create( + foreign_toplevel_list, &foreign_toplevel_state); + c->ext_foreign_toplevel->data = c; + +#ifdef XWAYLAND + c->image_capture_scene_surface = wlr_scene_surface_create( + &c->image_capture_scene->tree, client_surface(c)); +#endif + /* Handle unmanaged clients first so we can return prior create borders */ if (client_is_unmanaged(c)) { /* Unmanaged clients always are floating */ @@ -3583,6 +3614,26 @@ void outputmgrapply(struct wl_listener *listener, void *data) { outputmgrapplyortest(config, 0); } +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; + Client *c = request->toplevel_handle->data; + + if (c->image_capture_source == NULL) { + c->image_capture_source = + wlr_ext_image_capture_source_v1_create_with_scene_node( + &c->image_capture_scene->tree.node, event_loop, alloc, drw); + if (c->image_capture_source == NULL) { + return; + } + } + + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept( + request, c->image_capture_source); +} + void // 0.7 custom outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) { /* @@ -4407,6 +4458,15 @@ void setup(void) { power_mgr = wlr_output_power_manager_v1_create(dpy); wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode); + 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); + new_foreign_toplevel_capture_request.notify = + handle_new_foreign_toplevel_capture_request; + wl_signal_add(&ext_foreign_toplevel_image_capture_source_manager_v1->events + .new_request, + &new_foreign_toplevel_capture_request); + /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ output_layout = wlr_output_layout_create(dpy); @@ -4857,6 +4917,11 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->foreign_toplevel = NULL; } + if (c->ext_foreign_toplevel) { + wlr_ext_foreign_toplevel_handle_v1_destroy(c->ext_foreign_toplevel); + c->ext_foreign_toplevel = NULL; + } + if (c->swallowedby) { setfullscreen(c->swallowedby, c->isfullscreen); setmaxmizescreen(c->swallowedby, c->ismaxmizescreen); @@ -4869,6 +4934,13 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->swallowing = NULL; } +#ifdef XWAYLAND + if (client_is_x11(c)) { + wlr_scene_node_destroy(&c->image_capture_scene_surface->buffer->node); + c->image_capture_scene_surface = NULL; + } +#endif + wlr_scene_node_destroy(&c->image_capture_scene->tree.node); wlr_scene_node_destroy(&c->scene->node); printstatus(); motionnotify(0, NULL, 0, 0, 0, 0); From 9f709ef5e8530737e5b6806c7ea7225997d8086e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 1 Aug 2025 19:09:28 +0800 Subject: [PATCH 2/4] opt: auto update ext_foreign_toplevel title --- src/mango.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mango.c b/src/mango.c index a36427c0..abef805c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5092,6 +5092,14 @@ void updatetitle(struct wl_listener *listener, void *data) { title = client_get_title(c); if (title && c->foreign_toplevel) wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title); + if (title && c->ext_foreign_toplevel) { + wlr_ext_foreign_toplevel_handle_v1_update_state( + c->ext_foreign_toplevel, + &(struct wlr_ext_foreign_toplevel_handle_v1_state){ + .title = title, + .app_id = c->ext_foreign_toplevel->app_id, + }); + } if (c == focustop(c->mon)) printstatus(); } From 140137c5dc80aa5acb6faa23f8678044011bf5c6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 1 Aug 2025 19:47:09 +0800 Subject: [PATCH 3/4] fix: not need to judge x11 for image_capture_scene_surface --- src/mango.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/mango.c b/src/mango.c index abef805c..085244b2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -241,6 +241,7 @@ struct Client { struct wlr_scene_tree *image_capture_tree; struct wlr_scene *image_capture_scene; struct wlr_ext_image_capture_source_v1 *image_capture_source; + struct wlr_scene_surface *image_capture_scene_surface; struct wl_list link; struct wl_list flink; @@ -258,8 +259,6 @@ struct Client { struct wl_listener set_title; struct wl_listener fullscreen; #ifdef XWAYLAND - struct wlr_scene_surface *image_capture_scene_surface; - struct wl_listener activate; struct wl_listener associate; struct wl_listener dissociate; @@ -3306,11 +3305,8 @@ mapnotify(struct wl_listener *listener, void *data) { c->ext_foreign_toplevel = wlr_ext_foreign_toplevel_handle_v1_create( foreign_toplevel_list, &foreign_toplevel_state); c->ext_foreign_toplevel->data = c; - -#ifdef XWAYLAND c->image_capture_scene_surface = wlr_scene_surface_create( &c->image_capture_scene->tree, client_surface(c)); -#endif /* Handle unmanaged clients first so we can return prior create borders */ if (client_is_unmanaged(c)) { @@ -4934,12 +4930,7 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->swallowing = NULL; } -#ifdef XWAYLAND - if (client_is_x11(c)) { - wlr_scene_node_destroy(&c->image_capture_scene_surface->buffer->node); - c->image_capture_scene_surface = NULL; - } -#endif + wlr_scene_node_destroy(&c->image_capture_scene_surface->buffer->node); wlr_scene_node_destroy(&c->image_capture_scene->tree.node); wlr_scene_node_destroy(&c->scene->node); printstatus(); From 26f1bccca768ba153e444a47742c05f75c7aba86 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 6 Aug 2025 11:52:02 +0800 Subject: [PATCH 4/4] fix: extra scene to be create --- src/mango.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 085244b2..ae55362f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3295,12 +3295,11 @@ mapnotify(struct wl_listener *listener, void *data) { c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; - c->image_capture_scene = wlr_scene_create(); - struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state = { .app_id = client_get_appid(c), .title = client_get_title(c), }; + c->image_capture_scene = wlr_scene_create(); c->ext_foreign_toplevel = wlr_ext_foreign_toplevel_handle_v1_create( foreign_toplevel_list, &foreign_toplevel_state);