Commit Diff


commit - fa1a1b01bda020cb10fee649d8c5f34b749289cd
commit + 0d2b1235479134adf59940ca6d8dd58de7ccfbd1
blob - 5d0f06871a5a131915fdae0264cf28dd28031cbf
blob + d6c8e420e337d750ddf45767c43548b31995b359
--- river/Server.zig
+++ river/Server.zig
@@ -46,6 +46,7 @@ const XdgDecoration = @import("XdgDecoration.zig");
 const XdgToplevel = @import("XdgToplevel.zig");
 const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig");
 const XwaylandView = @import("XwaylandView.zig");
+const View = @import("View.zig");
 
 const log = std.log.scoped(.server);
 
@@ -93,6 +94,7 @@ screencopy_manager: *wlr.ScreencopyManagerV1,
 
 image_copy_capture_manager: *wlr.ExtImageCopyCaptureManagerV1,
 output_image_capture_source_manager: *wlr.ExtOutputImageCaptureSourceManagerV1,
+foreign_toplevel_image_capture_source_manager: *wlr.ExtForeignToplevelImageCaptureSourceManagerV1,
 
 foreign_toplevel_manager: *wlr.ForeignToplevelManagerV1,
 
@@ -127,6 +129,8 @@ request_activate: wl.Listener(*wlr.XdgActivationV1.eve
     wl.Listener(*wlr.XdgActivationV1.event.RequestActivate).init(handleRequestActivate),
 request_set_cursor_shape: wl.Listener(*wlr.CursorShapeManagerV1.event.RequestSetShape) =
     wl.Listener(*wlr.CursorShapeManagerV1.event.RequestSetShape).init(handleRequestSetCursorShape),
+new_foreign_toplevel_capture_request: wl.Listener(*wlr.ExtForeignToplevelImageCaptureSourceManagerV1.Request) =
+    wl.Listener(*wlr.ExtForeignToplevelImageCaptureSourceManagerV1.Request).init(handleNewForeignToplevelCaptureRequest),
 
 pub fn init(server: *Server, runtime_xwayland: bool) !void {
     // We intentionally don't try to prevent memory leaks on error in this function
@@ -181,6 +185,7 @@ pub fn init(server: *Server, runtime_xwayland: bool) !
 
         .image_copy_capture_manager = try wlr.ExtImageCopyCaptureManagerV1.create(wl_server, 1),
         .output_image_capture_source_manager = try wlr.ExtOutputImageCaptureSourceManagerV1.create(wl_server, 1),
+        .foreign_toplevel_image_capture_source_manager = try wlr.ExtForeignToplevelImageCaptureSourceManagerV1.create(wl_server, 1),
 
         .foreign_toplevel_manager = try wlr.ForeignToplevelManagerV1.create(wl_server),
 
@@ -392,6 +397,7 @@ fn blocklist(server: *Server, global: *const wl.Global
         global == server.screencopy_manager.global or
         global == server.image_copy_capture_manager.global or
         global == server.output_image_capture_source_manager.global or
+        global == server.foreign_toplevel_image_capture_source_manager.global or
         global == server.export_dmabuf_manager.global or
         global == server.data_control_manager.global or
         global == server.layout_manager.global or
@@ -597,3 +603,24 @@ fn handleRequestSetCursorShape(
         }
     }
 }
+
+fn handleNewForeignToplevelCaptureRequest(
+    listener: *wl.Listener(*wlr.ExtForeignToplevelImageCaptureSourceManagerV1.Request),
+    request: *wlr.ExtForeignToplevelImageCaptureSourceManagerV1.Request,
+) void {
+    const server: *Server = @fieldParentPtr("new_foreign_toplevel_capture_request", listener);
+    if (request.toplevel_handle.data) |opaque_view| {
+        const view: *View = @ptrCast(@alignCast(opaque_view));
+        const capture_source = view.image_capture_source orelse wlr.ExtImageCaptureSourceV1.createWithSceneNode(
+            &view.image_capture_scene.tree.node,
+            server.wl_server.getEventLoop(),
+            server.allocator,
+            server.renderer,
+        ) catch {
+            log.err("failed to create ext image capture source", .{});
+            return;
+        };
+
+        _ = request.accept(capture_source);
+    }
+}
blob - f3380a0bae03f8a0123832fd443b8c16891a0229
blob + 8cba7d0e9ab5371a213a477a38d87eb33754ae7b
--- river/View.zig
+++ river/View.zig
@@ -140,6 +140,9 @@ saved_surface_tree: *wlr.SceneTree,
 borders: [4]*wlr.SceneRect,
 popup_tree: *wlr.SceneTree,
 
+image_capture_scene: *wlr.Scene,
+image_capture_source: ?*wlr.ExtImageCaptureSourceV1,
+
 /// Bounds on the width/height of the view, set by the toplevel/xwayland_view implementation.
 constraints: Constraints = .{},
 
@@ -215,6 +218,9 @@ pub fn create(impl: Impl) error{OutOfMemory}!*View {
         },
         .popup_tree = popup_tree,
 
+        .image_capture_scene = try wlr.Scene.create(),
+        .image_capture_source = null,
+
         .pending_wm_stack_link = undefined,
         .pending_focus_stack_link = undefined,
         .inflight_wm_stack_link = undefined,
@@ -230,6 +236,7 @@ pub fn create(impl: Impl) error{OutOfMemory}!*View {
     view.tree.node.setEnabled(false);
     view.popup_tree.node.setEnabled(false);
     view.saved_surface_tree.node.setEnabled(false);
+    view.image_capture_scene.restack_xwayland_surfaces = false;
 
     try SceneNodeData.attach(&view.tree.node, .{ .view = view });
     try SceneNodeData.attach(&view.popup_tree.node, .{ .view = view });
@@ -250,6 +257,7 @@ pub fn destroy(view: *View, when: enum { lazy, assert 
     // around until the current transaction completes. This function will be
     // called again in Root.commitTransaction()
     if (!view.saved_surface_tree.node.enabled) {
+        view.image_capture_scene.tree.node.destroy();
         view.tree.node.destroy();
         view.popup_tree.node.destroy();
 
@@ -665,6 +673,7 @@ pub fn map(view: *View) !void {
         .app_id = view.getAppId(),
     })) |handle| {
         view.ext_foreign_toplevel_handle = handle;
+        handle.data = view;
     } else |_| {
         log.err("failed to create ext foreign toplevel handle", .{});
     }
blob - 4fa775c12567c57d744b96a1fad5ddf3faf90738
blob + 02c0537e15b1c24b9cf313a3919061945d9fffcf
--- river/XdgToplevel.zig
+++ river/XdgToplevel.zig
@@ -97,6 +97,7 @@ pub fn create(wlr_toplevel: *wlr.XdgToplevel) error{Ou
     errdefer toplevel.unmap.link.remove();
 
     _ = try view.surface_tree.createSceneXdgSurface(wlr_toplevel.base);
+    _ = try view.image_capture_scene.tree.createSceneXdgSurface(wlr_toplevel.base);
 
     toplevel.view = view;
 
blob - 836de81edddcbb8bb5c7a260519323a0658dc1c7
blob + 5224be4b194d184fd7e72a430345e29f5d72fbc2
--- river/XwaylandView.zig
+++ river/XwaylandView.zig
@@ -179,6 +179,12 @@ pub fn handleMap(listener: *wl.Listener(void)) void {
         return;
     };
 
+    _ = view.image_capture_scene.tree.createSceneSurface(surface) catch {
+        log.err("out of memory", .{});
+        surface.resource.getClient().postNoMemory();
+        return;
+    };
+
     view.pending.box = .{
         .x = 0,
         .y = 0,