git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commite29c57f349b1cc94a025705c51447337190b4262
parentbb9dcb65e4
authorIsaac Freund <[email protected]>
date2025-07-21 12:35
InputPopup: support river shell surfaces

Untested, but pretty simple

 river/InputPopup.zig    | 5 +++--
 river/ShellSurface.zig  | 8 ++++++++
 river/WindowManager.zig | 1 +
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/river/InputPopup.zig b/river/InputPopup.zig
index a7d54c5..8fc3dd9 100644
--- a/river/InputPopup.zig
+++ b/river/InputPopup.zig
@@ -109,8 +109,9 @@ pub fn update(input_popup: *InputPopup) void {
 
     const popup_tree = switch (focused.data) {
         .window => |window| window.popup_tree,
-        .shell_surface => @panic("TODO"),
-        .lock_surface => |_| server.scene.layers.popups, // XXX Do we need per-lock-surface popup trees?
+        .shell_surface => |shell_surface| shell_surface.popup_tree,
+        // TODO fix positioning for lock surfaces not at 0,0 in layout coords
+        .lock_surface => |_| server.scene.layers.popups,
         // Xwayland doesn't use the text-input protocol
         .override_redirect => unreachable,
     };
diff --git a/river/ShellSurface.zig b/river/ShellSurface.zig
index 9b88df3..6bd9fbd 100644
--- a/river/ShellSurface.zig
+++ b/river/ShellSurface.zig
@@ -44,6 +44,7 @@ object: *river.ShellSurfaceV1,
 surface: *wlr.Surface,
 tree: *wlr.SceneTree,
 surfaces: Scene.SaveableSurfaces,
+popup_tree: *wlr.SceneTree,
 node: WmNode,
 
 rendering_requested: struct {
@@ -73,16 +74,21 @@ pub fn create(
     const tree = try server.scene.hidden_tree.createSceneTree();
     errdefer tree.node.destroy();
 
+    const popup_tree = try server.scene.hidden_tree.createSceneTree();
+    errdefer popup_tree.node.destroy();
+
     const surfaces = try Scene.SaveableSurfaces.init(tree);
     _ = try surfaces.tree.createSceneSubsurfaceTree(surface);
 
     try SceneNodeData.attach(&tree.node, .{ .shell_surface = shell_surface });
+    try SceneNodeData.attach(&popup_tree.node, .{ .shell_surface = shell_surface });
 
     shell_surface.* = .{
         .object = shell_surface_v1,
         .surface = surface,
         .tree = tree,
         .surfaces = surfaces,
+        .popup_tree = popup_tree,
         .node = undefined,
     };
     shell_surface.node.init(.shell_surface);
@@ -98,6 +104,7 @@ fn handleDestroy(_: *river.ShellSurfaceV1, shell_surface: *ShellSurface) void {
     shell_surface.node.deinit();
 
     shell_surface.tree.node.destroy();
+    shell_surface.popup_tree.node.destroy();
 
     util.gpa.destroy(shell_surface);
 }
@@ -160,4 +167,5 @@ pub fn renderFinish(shell_surface: *ShellSurface) void {
     shell_surface.surfaces.dropSaved();
 
     shell_surface.tree.node.setPosition(rendering_requested.x, rendering_requested.y);
+    shell_surface.popup_tree.node.setPosition(rendering_requested.x, rendering_requested.y);
 }
diff --git a/river/WindowManager.zig b/river/WindowManager.zig
index 65894e2..d95776b 100644
--- a/river/WindowManager.zig
+++ b/river/WindowManager.zig
@@ -441,6 +441,7 @@ fn renderFinish(wm: *WindowManager) void {
                 .shell_surface => |shell_surface| {
                     shell_surface.renderFinish();
                     shell_surface.tree.node.reparent(server.scene.layers.wm);
+                    shell_surface.popup_tree.node.reparent(server.scene.layers.popups);
                     shell_surface.tree.node.raiseToTop();
                 },
             }