river: ext-foreign-toplevel-image-capture-source

This commit is contained in:
Peter Kaplan
2025-07-13 00:05:52 +02:00
parent fa1a1b01bd
commit 0d2b123547
4 changed files with 43 additions and 0 deletions

View File

@@ -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);
}
}

View File

@@ -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", .{});
}

View File

@@ -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;

View File

@@ -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,