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

commitaa34a0e89b6b093696fb71e607c41a0d2bf6bf70
parent6312dc39e0
authorPeter Kaplan <[email protected]>
date2024-03-05 09:47
command/attach-modes: above and below options

 doc/riverctl.1.scd            |  6 ++++--
 river/Config.zig              |  2 ++
 river/Output.zig              | 14 ++++++++++++++
 river/View.zig                | 16 ++++++++++++++++
 river/command/attach_mode.zig |  2 +-
 5 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd
index ea910d4..6a0edd1 100644
--- a/doc/riverctl.1.scd
+++ b/doc/riverctl.1.scd
@@ -345,18 +345,20 @@ matches everything while _\*\*_ and the empty string are invalid.
 
 ## CONFIGURATION
 
-*default-attach-mode* *top*|*bottom*|*after <N>*
+*default-attach-mode* *top*|*bottom*|*above*|*below*|*after <N>*
 	Set the attach mode to be used by all outputs by default.
 
 	Possible values:
 	- top: Prepends the newly spawned view at the top of the stack.
 	- bottom: Appends the newly spawned view at the bottom of the stack.
+	- above: Inserts the newly spawned view above the currently focused view.
+	- below: Inserts the newly spawned view below the currently focused view.
 	- after <N>: Inserts the newly spawned view after N views in the stack.
 
 	Note that the deprecated *attach-mode* command is aliased to
 	*default-attach-mode* for backwards compatibility.
 
-*output-attach-mode* *top*|*bottom*|*after <N>*
+*output-attach-mode* *top*|*bottom*|*above*|*below*|*after <N>*
 	Set the attach mode of the currently focused output, overriding the value of
 	default-attach-mode if any.
 
diff --git a/river/Config.zig b/river/Config.zig
index 005cd48..539a02b 100644
--- a/river/Config.zig
+++ b/river/Config.zig
@@ -35,6 +35,8 @@ pub const AttachMode = union(enum) {
     top,
     bottom,
     after: u32,
+    above,
+    below,
 };
 
 pub const FocusFollowsCursorMode = enum {
diff --git a/river/Output.zig b/river/Output.zig
index d208cb6..32f221a 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -60,6 +60,20 @@ pub const PendingState = struct {
     ///
     /// This includes both floating/fullscreen views and those arranged in the layout.
     wm_stack: wl.list.Head(View, .pending_wm_stack_link),
+    ///
+    /// Index of the first view in focus_stack in the wm_stack list.
+    pub fn focusedIndex(self: *PendingState) ?u32 {
+        var focus_stack_it = self.focus_stack.iterator(.forward);
+        const focused_view = focus_stack_it.next() orelse return null;
+
+        var it = self.wm_stack.iterator(.forward);
+        var count: u32 = 0;
+        while (it.next()) |other| {
+            if (other == focused_view) break;
+            count += 1;
+        }
+        return count;
+    }
 };
 
 wlr_output: *wlr.Output,
diff --git a/river/View.zig b/river/View.zig
index 5bd0084..592f2d9 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -479,6 +479,14 @@ pub fn setPendingOutput(view: *Self, output: *Output) void {
         .top => output.pending.wm_stack.prepend(view),
         .bottom => output.pending.wm_stack.append(view),
         .after => |n| view.attachAfter(&output.pending, n),
+        .above => view.attachAfter(
+            &output.pending,
+            output.pending.focusedIndex() orelse 0,
+        ),
+        .below => view.attachAfter(
+            &output.pending,
+            (output.pending.focusedIndex() orelse 0) + 1,
+        ),
     }
     output.pending.focus_stack.prepend(view);
 
@@ -607,6 +615,14 @@ pub fn map(view: *Self) !void {
             .top => server.root.fallback_pending.wm_stack.prepend(view),
             .bottom => server.root.fallback_pending.wm_stack.append(view),
             .after => |n| view.attachAfter(&server.root.fallback_pending, n),
+            .above => view.attachAfter(
+                &server.root.fallback_pending,
+                server.root.fallback_pending.focusedIndex() orelse 0,
+            ),
+            .below => view.attachAfter(
+                &server.root.fallback_pending,
+                (server.root.fallback_pending.focusedIndex() orelse 0) + 1,
+            ),
         }
         server.root.fallback_pending.focus_stack.prepend(view);
 
diff --git a/river/command/attach_mode.zig b/river/command/attach_mode.zig
index ef74edd..6ffc615 100644
--- a/river/command/attach_mode.zig
+++ b/river/command/attach_mode.zig
@@ -29,7 +29,7 @@ fn parseAttachMode(args: []const [:0]const u8) Error!Config.AttachMode {
 
     const tag = meta.stringToEnum(meta.Tag(Config.AttachMode), args[1]) orelse return Error.UnknownOption;
     switch (tag) {
-        inline .top, .bottom => |mode| {
+        inline .top, .bottom, .above, .below => |mode| {
             if (args.len > 2) return Error.TooManyArguments;
 
             return mode;