mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2026-06-21 15:33:04 +00:00
195 lines
6.8 KiB
Diff
195 lines
6.8 KiB
Diff
From e0fe17a27625440a1a4ac8cfe91639a938589925 Mon Sep 17 00:00:00 2001
|
|
From: skeetamine <lesrallidenud@gmail.com>
|
|
Date: Fri, 19 Jun 2026 18:37:41 +0300
|
|
Subject: [PATCH] per-app-cast: capture individual toplevels
|
|
|
|
Implement ext-foreign-toplevel-image-capture-source-v1 so portals can
|
|
offer per-window screen sharing alongside per-output. Each toplevel is
|
|
rendered into a dedicated offscreen scene so capture isolates the window
|
|
regardless of tag/position.
|
|
---
|
|
dwl.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 83 insertions(+)
|
|
|
|
diff --git a/dwl.c b/dwl.c
|
|
index 8101ffa..7f4d059 100644
|
|
--- a/dwl.c
|
|
+++ b/dwl.c
|
|
@@ -25,6 +25,7 @@
|
|
#include <wlr/types/wlr_drm.h>
|
|
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
|
#include <wlr/types/wlr_ext_data_control_v1.h>
|
|
+#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
|
|
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
|
|
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
|
|
#include <wlr/types/wlr_fractional_scale_v1.h>
|
|
@@ -123,6 +124,7 @@ typedef struct {
|
|
struct wlr_xwayland_surface *xwayland;
|
|
} surface;
|
|
struct wlr_xdg_toplevel_decoration_v1 *decoration;
|
|
+ struct wlr_ext_foreign_toplevel_handle_v1 *foreign_toplevel;
|
|
struct wl_listener commit;
|
|
struct wl_listener map;
|
|
struct wl_listener maximize;
|
|
@@ -243,6 +245,11 @@ typedef struct {
|
|
struct wl_listener destroy;
|
|
} SessionLock;
|
|
|
|
+typedef struct {
|
|
+ struct wlr_scene *scene;
|
|
+ struct wl_listener source_destroy;
|
|
+} CaptureScene;
|
|
+
|
|
/* function declarations */
|
|
static void applybounds(Client *c, struct wlr_box *bbox);
|
|
static void applyrules(Client *c);
|
|
@@ -252,6 +259,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 capturescenedestroy(struct wl_listener *listener, void *data);
|
|
static void chvt(const Arg *arg);
|
|
static void checkidleinhibitor(struct wlr_surface *exclude);
|
|
static void cleanup(void);
|
|
@@ -292,6 +300,7 @@ static void focusstack(const Arg *arg);
|
|
static Client *focustop(Monitor *m);
|
|
static void fullscreennotify(struct wl_listener *listener, void *data);
|
|
static void gpureset(struct wl_listener *listener, void *data);
|
|
+static void handlecapturerequest(struct wl_listener *listener, void *data);
|
|
static void handlesig(int signo);
|
|
static void incnmaster(const Arg *arg);
|
|
static void inputdevice(struct wl_listener *listener, void *data);
|
|
@@ -399,6 +408,10 @@ static struct wlr_session_lock_manager_v1 *session_lock_mgr;
|
|
static struct wlr_scene_rect *locked_bg;
|
|
static struct wlr_session_lock_v1 *cur_lock;
|
|
|
|
+static struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list;
|
|
+static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *toplevel_capture_mgr;
|
|
+static struct wl_listener foreign_toplevel_capture_request = {.notify = handlecapturerequest};
|
|
+
|
|
static struct wlr_seat *seat;
|
|
static KeyboardGroup *kb_group;
|
|
static unsigned int cursor_mode;
|
|
@@ -676,6 +689,15 @@ buttonpress(struct wl_listener *listener, void *data)
|
|
event->time_msec, event->button, event->state);
|
|
}
|
|
|
|
+void
|
|
+capturescenedestroy(struct wl_listener *listener, void *data)
|
|
+{
|
|
+ CaptureScene *cs = wl_container_of(listener, cs, source_destroy);
|
|
+ wl_list_remove(&cs->source_destroy.link);
|
|
+ wlr_scene_node_destroy(&cs->scene->tree.node);
|
|
+ free(cs);
|
|
+}
|
|
+
|
|
void
|
|
chvt(const Arg *arg)
|
|
{
|
|
@@ -786,6 +808,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(&foreign_toplevel_capture_request.link);
|
|
#ifdef XWAYLAND
|
|
wl_list_remove(&new_xwayland_surface.link);
|
|
wl_list_remove(&xwayland_ready.link);
|
|
@@ -1561,6 +1584,41 @@ gpureset(struct wl_listener *listener, void *data)
|
|
wlr_renderer_destroy(old_drw);
|
|
}
|
|
|
|
+void
|
|
+handlecapturerequest(struct wl_listener *listener, void *data)
|
|
+{
|
|
+ struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *req = data;
|
|
+ Client *c;
|
|
+ CaptureScene *cs;
|
|
+ struct wlr_ext_image_capture_source_v1 *source;
|
|
+
|
|
+ wl_list_for_each(c, &clients, link) {
|
|
+ if (c->foreign_toplevel != req->toplevel_handle)
|
|
+ continue;
|
|
+
|
|
+ cs = ecalloc(1, sizeof(*cs));
|
|
+ cs->scene = wlr_scene_create();
|
|
+ if (c->type == XDGShell)
|
|
+ wlr_scene_xdg_surface_create(&cs->scene->tree, c->surface.xdg);
|
|
+ else
|
|
+ wlr_scene_subsurface_tree_create(&cs->scene->tree, client_surface(c));
|
|
+
|
|
+ source =
|
|
+ wlr_ext_image_capture_source_v1_create_with_scene_node(
|
|
+ &cs->scene->tree.node, event_loop, alloc, drw);
|
|
+
|
|
+ if (source) {
|
|
+ cs->source_destroy.notify = capturescenedestroy;
|
|
+ wl_signal_add(&source->events.destroy, &cs->source_destroy);
|
|
+ wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept(req, source);
|
|
+ } else {
|
|
+ wlr_scene_node_destroy(&cs->scene->tree.node);
|
|
+ free(cs);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
void
|
|
handlesig(int signo)
|
|
{
|
|
@@ -1786,6 +1844,14 @@ mapnotify(struct wl_listener *listener, void *data)
|
|
wl_list_insert(&clients, &c->link);
|
|
wl_list_insert(&fstack, &c->flink);
|
|
|
|
+ {
|
|
+ struct wlr_ext_foreign_toplevel_handle_v1_state ft_state = {
|
|
+ .title = client_get_title(c),
|
|
+ .app_id = client_get_appid(c),
|
|
+ };
|
|
+ c->foreign_toplevel = wlr_ext_foreign_toplevel_handle_v1_create(foreign_toplevel_list, &ft_state);
|
|
+ }
|
|
+
|
|
/* Set initial monitor, tags, floating status, and focus:
|
|
* we always consider floating, clients that have parent and thus
|
|
* we set the same tags and monitor as its parent.
|
|
@@ -2532,6 +2598,10 @@ setup(void)
|
|
wlr_presentation_create(dpy, backend, 2);
|
|
wlr_alpha_modifier_v1_create(dpy);
|
|
|
|
+ foreign_toplevel_list = wlr_ext_foreign_toplevel_list_v1_create(dpy, 1);
|
|
+ toplevel_capture_mgr = wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(dpy, 1);
|
|
+ wl_signal_add(&toplevel_capture_mgr->events.new_request, &foreign_toplevel_capture_request);
|
|
+
|
|
/* Initializes the interface used to implement urgency hints */
|
|
activation = wlr_xdg_activation_v1_create(dpy);
|
|
wl_signal_add(&activation->events.request_activate, &request_activate);
|
|
@@ -2838,6 +2908,11 @@ unmapnotify(struct wl_listener *listener, void *data)
|
|
wl_list_remove(&c->flink);
|
|
}
|
|
|
|
+ if (c->foreign_toplevel) {
|
|
+ wlr_ext_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel);
|
|
+ c->foreign_toplevel = NULL;
|
|
+ }
|
|
+
|
|
wlr_scene_node_destroy(&c->scene->node);
|
|
printstatus();
|
|
motionnotify(0, NULL, 0, 0, 0, 0);
|
|
@@ -2955,6 +3030,14 @@ updatetitle(struct wl_listener *listener, void *data)
|
|
Client *c = wl_container_of(listener, c, set_title);
|
|
if (c == focustop(c->mon))
|
|
printstatus();
|
|
+
|
|
+ if (c->foreign_toplevel) {
|
|
+ struct wlr_ext_foreign_toplevel_handle_v1_state ft_state = {
|
|
+ .title = client_get_title(c),
|
|
+ .app_id = client_get_appid(c),
|
|
+ };
|
|
+ wlr_ext_foreign_toplevel_handle_v1_update_state(c->foreign_toplevel, &ft_state);
|
|
+ }
|
|
}
|
|
|
|
void
|
|
--
|
|
2.54.0
|
|
|