diff --git a/river/Server.zig b/river/Server.zig index 5d0f068..d6c8e42 100644 --- a/river/Server.zig +++ b/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.event.RequestActivate) = 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) !void { .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) bool { 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); + } +} diff --git a/river/View.zig b/river/View.zig index f3380a0..8cba7d0 100644 --- a/river/View.zig +++ b/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 }) void { // 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", .{}); } diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index 4fa775c..02c0537 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -97,6 +97,7 @@ pub fn create(wlr_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void { 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; diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig index 836de81..5224be4 100644 --- a/river/XwaylandView.zig +++ b/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,