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

commit21c46bb4998782a0ca80b9438d05030b805a894d
parentd6c24e0837
authorIsaac Freund <[email protected]>
date2023-11-09 16:36
View: handle map while no outputs are available

Currently views which are mapped while no outputs are available can
never actually get rendered because they have 0 tags and are stuck in
the hidden stack.

This commit fixes this and they should now be restored when a new output
becomes available.

 river/Root.zig |  3 +++
 river/View.zig | 63 +++++++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 46 insertions(+), 20 deletions(-)

diff --git a/river/Root.zig b/river/Root.zig
index bb6f7ee..cc3a630 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -362,6 +362,9 @@ pub fn activateOutput(root: *Self, output: *Output) void {
 
     // If we previously had no outputs, move all views to the new output and focus it.
     if (first) {
+        const log = std.log.scoped(.output_manager);
+        log.debug("moving views from fallback stacks to new output", .{});
+
         output.pending.tags = root.fallback.tags;
         {
             var it = root.fallback.pending.focus_stack.safeIterator(.reverse);
diff --git a/river/View.zig b/river/View.zig
index e4ea30d..f22cc43 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -495,32 +495,55 @@ pub fn map(view: *Self) !void {
         view.pending.ssd = ssd;
     }
 
-    const focused_output = server.input_manager.defaultSeat().focused_output;
-    if (try server.config.outputRuleMatch(view) orelse focused_output) |output| {
-        if (server.config.rules.position.match(view)) |position| {
-            view.pending.box.x = position.x;
-            view.pending.box.y = position.y;
-        } else {
-            // Center the initial pending box on the output
-            view.pending.box.x = @divTrunc(@max(0, output.usable_box.width - view.pending.box.width), 2);
-            view.pending.box.y = @divTrunc(@max(0, output.usable_box.height - view.pending.box.height), 2);
-        }
+    if (server.config.rules.dimensions.match(view)) |dimensions| {
+        view.pending.box.width = dimensions.width;
+        view.pending.box.height = dimensions.height;
+    }
 
-        if (server.config.rules.dimensions.match(view)) |dimensions| {
-            view.pending.box.width = dimensions.width;
-            view.pending.box.height = dimensions.height;
-        }
+    const output = try server.config.outputRuleMatch(view) orelse
+        server.input_manager.defaultSeat().focused_output;
 
-        view.pending.tags = blk: {
-            if (server.config.rules.tags.match(view)) |tags| break :blk tags;
-            const tags = output.pending.tags & server.config.spawn_tagmask;
-            break :blk if (tags != 0) tags else output.pending.tags;
-        };
+    if (server.config.rules.position.match(view)) |position| {
+        view.pending.box.x = position.x;
+        view.pending.box.y = position.y;
+    } else if (output) |o| {
+        // Center the initial pending box on the output
+        view.pending.box.x = @divTrunc(@max(0, o.usable_box.width - view.pending.box.width), 2);
+        view.pending.box.y = @divTrunc(@max(0, o.usable_box.height - view.pending.box.height), 2);
+    }
+
+    view.pending.tags = blk: {
+        const default = if (output) |o| o.pending.tags else server.root.fallback.tags;
+        if (server.config.rules.tags.match(view)) |tags| break :blk tags;
+        const tags = default & server.config.spawn_tagmask;
+        break :blk if (tags != 0) tags else default;
+    };
 
-        view.setPendingOutput(output);
+    if (output) |o| {
+        view.setPendingOutput(o);
 
         var it = server.input_manager.seats.first;
         while (it) |seat_node| : (it = seat_node.next) seat_node.data.focus(view);
+    } else {
+        log.debug("no output available for newly mapped view, adding to fallback stacks", .{});
+
+        view.pending_wm_stack_link.remove();
+        view.pending_focus_stack_link.remove();
+        view.inflight_wm_stack_link.remove();
+        view.inflight_focus_stack_link.remove();
+
+        switch (server.config.attach_mode) {
+            .top => {
+                server.root.fallback.pending.wm_stack.prepend(view);
+                server.root.fallback.inflight.wm_stack.prepend(view);
+            },
+            .bottom => {
+                server.root.fallback.pending.wm_stack.append(view);
+                server.root.fallback.inflight.wm_stack.append(view);
+            },
+        }
+        server.root.fallback.pending.focus_stack.prepend(view);
+        server.root.fallback.inflight.focus_stack.prepend(view);
     }
 
     view.float_box = view.pending.box;