aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOrfeas <38209077+0xfea5@users.noreply.github.com>2024-01-03 16:33:13 +0200
committerIsaac Freund <mail@isaacfreund.com>2024-01-13 12:29:09 -0600
commit6a71fc65b0d64a03fd0f37602b14b3d91e61be51 (patch)
treeb4f5a9cc8ca6295bf69c0ffbddb2864ecc114dc2
parent6e9bd83e1d0e2132d2def338b51f66867cd88907 (diff)
downloadriver-6a71fc65b0d64a03fd0f37602b14b3d91e61be51.tar.gz
river-6a71fc65b0d64a03fd0f37602b14b3d91e61be51.tar.xz
attach-mode: implement after <N>
-rw-r--r--doc/riverctl.1.scd16
-rw-r--r--river/Config.zig9
-rw-r--r--river/Output.zig7
-rw-r--r--river/View.zig21
-rw-r--r--river/command.zig4
-rw-r--r--river/command/attach_mode.zig36
6 files changed, 74 insertions, 19 deletions
diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd
index b46185d..b3c95b2 100644
--- a/doc/riverctl.1.scd
+++ b/doc/riverctl.1.scd
@@ -347,8 +347,20 @@ matches everything while _\*\*_ and the empty string are invalid.
## CONFIGURATION
-*attach-mode* *top*|*bottom*
- Configure where new views should attach to the view stack.
+*attach-mode* *top*|*bottom*|*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.
+ - after <N>: Inserts the newly spawned view after N views in the stack.
+
+*default-attach-mode* *top*|*bottom*|*after <N>*
+ Alias to attach-mode.
+
+*output-attach-mode* *top*|*bottom*|*after <N>*
+ Set the attach mode of the currently focused output, overriding the value of
+ default-attach-mode if any.
*background-color* _0xRRGGBB_|_0xRRGGBBAA_
Set the background color.
diff --git a/river/Config.zig b/river/Config.zig
index 34336a7..75730f4 100644
--- a/river/Config.zig
+++ b/river/Config.zig
@@ -31,9 +31,10 @@ const Mode = @import("Mode.zig");
const RuleList = @import("rule_list.zig").RuleList;
const View = @import("View.zig");
-pub const AttachMode = enum {
- top,
- bottom,
+pub const AttachMode = union(enum) {
+ top: void,
+ bottom: void,
+ after: usize,
};
pub const FocusFollowsCursorMode = enum {
@@ -112,7 +113,7 @@ default_layout_namespace: []const u8 = &[0]u8{},
spawn_tagmask: u32 = std.math.maxInt(u32),
/// Determines where new views will be attached to the view stack.
-attach_mode: AttachMode = .top,
+default_attach_mode: AttachMode = .top,
/// Keyboard repeat rate in characters per second
repeat_rate: u31 = 25,
diff --git a/river/Output.zig b/river/Output.zig
index f9c3b0e..be370d9 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -36,6 +36,7 @@ const LockSurface = @import("LockSurface.zig");
const OutputStatus = @import("OutputStatus.zig");
const SceneNodeData = @import("SceneNodeData.zig");
const View = @import("View.zig");
+const AttachMode = @import("Config.zig").AttachMode;
const log = std.log.scoped(.output);
@@ -166,6 +167,8 @@ current: struct {
/// Remembered version of tags (from last run)
previous_tags: u32 = 1 << 0,
+attach_mode: ?AttachMode = null,
+
/// List of all layouts
layouts: std.TailQueue(Layout) = .{},
@@ -608,3 +611,7 @@ pub fn handleLayoutNamespaceChange(self: *Self) void {
pub fn layoutNamespace(self: Self) []const u8 {
return self.layout_namespace orelse server.config.default_layout_namespace;
}
+
+pub fn attachMode(self: Self) AttachMode {
+ return self.attach_mode orelse server.config.default_attach_mode;
+}
diff --git a/river/View.zig b/river/View.zig
index 4deea21..7cdc82f 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -33,6 +33,7 @@ const SceneNodeData = @import("SceneNodeData.zig");
const Seat = @import("Seat.zig");
const XdgToplevel = @import("XdgToplevel.zig");
const XwaylandView = @import("XwaylandView.zig");
+const PendingState = @import("Output.zig").PendingState;
const log = std.log.scoped(.view);
@@ -418,9 +419,10 @@ pub fn setPendingOutput(view: *Self, output: *Output) void {
view.pending_wm_stack_link.remove();
view.pending_focus_stack_link.remove();
- switch (server.config.attach_mode) {
+ switch (output.attachMode()) {
.top => output.pending.wm_stack.prepend(view),
.bottom => output.pending.wm_stack.append(view),
+ .after => |n| view.attach_after(&output.pending, n),
}
output.pending.focus_stack.prepend(view);
@@ -476,6 +478,20 @@ pub fn applyConstraints(self: *Self, box: *wlr.Box) void {
box.height = math.clamp(box.height, self.constraints.min_height, self.constraints.max_height);
}
+/// Attach current view after n Views on the pending wm_stack
+pub fn attach_after(view: *Self, pending_state: *PendingState, n: usize) void {
+ var nvisible: u32 = 0;
+ var it = pending_state.wm_stack.iterator(.forward);
+
+ while (it.next()) |cur_view| {
+ if (nvisible >= n) break;
+ if (!cur_view.pending.float // ignore floating views
+ and cur_view.pending.tags & pending_state.tags != 0) nvisible += 1;
+ }
+
+ it.current.prev.?.insert(&view.pending_wm_stack_link);
+}
+
/// Called by the impl when the surface is ready to be displayed
pub fn map(view: *Self) !void {
log.debug("view '{?s}' mapped", .{view.getTitle()});
@@ -530,9 +546,10 @@ pub fn map(view: *Self) !void {
view.pending_wm_stack_link.remove();
view.pending_focus_stack_link.remove();
- switch (server.config.attach_mode) {
+ switch (server.config.default_attach_mode) {
.top => server.root.fallback_pending.wm_stack.prepend(view),
.bottom => server.root.fallback_pending.wm_stack.append(view),
+ .after => |n| view.attach_after(&server.root.fallback_pending, n),
}
server.root.fallback_pending.focus_stack.prepend(view);
diff --git a/river/command.zig b/river/command.zig
index 4a2a647..ad8d21f 100644
--- a/river/command.zig
+++ b/river/command.zig
@@ -40,7 +40,7 @@ pub const Orientation = enum {
const command_impls = std.ComptimeStringMap(
*const fn (*Seat, []const [:0]const u8, *?[]const u8) Error!void,
.{
- .{ "attach-mode", @import("command/attach_mode.zig").attachMode },
+ .{ "attach-mode", @import("command/attach_mode.zig").defaultAttachMode },
.{ "background-color", @import("command/config.zig").backgroundColor },
.{ "border-color-focused", @import("command/config.zig").borderColorFocused },
.{ "border-color-unfocused", @import("command/config.zig").borderColorUnfocused },
@@ -48,6 +48,7 @@ const command_impls = std.ComptimeStringMap(
.{ "border-width", @import("command/config.zig").borderWidth },
.{ "close", @import("command/close.zig").close },
.{ "declare-mode", @import("command/declare_mode.zig").declareMode },
+ .{ "default-attach-mode", @import("command/attach_mode.zig").defaultAttachMode },
.{ "default-layout", @import("command/layout.zig").defaultLayout },
.{ "enter-mode", @import("command/enter_mode.zig").enterMode },
.{ "exit", @import("command/exit.zig").exit },
@@ -70,6 +71,7 @@ const command_impls = std.ComptimeStringMap(
.{ "map-pointer", @import("command/map.zig").mapPointer },
.{ "map-switch", @import("command/map.zig").mapSwitch },
.{ "move", @import("command/move.zig").move },
+ .{ "output-attach-mode", @import("command/attach_mode.zig").outputAttachMode },
.{ "output-layout", @import("command/layout.zig").outputLayout },
.{ "resize", @import("command/move.zig").resize },
.{ "rule-add", @import("command/rule.zig").ruleAdd },
diff --git a/river/command/attach_mode.zig b/river/command/attach_mode.zig
index 7ca3663..bac7ad4 100644
--- a/river/command/attach_mode.zig
+++ b/river/command/attach_mode.zig
@@ -21,20 +21,36 @@ const server = &@import("../main.zig").server;
const Error = @import("../command.zig").Error;
const Seat = @import("../Seat.zig");
+const AttachMode = @import("../Config.zig").AttachMode;
-pub fn attachMode(
- _: *Seat,
- args: []const [:0]const u8,
- _: *?[]const u8,
-) Error!void {
+fn parseAttachMode(args: []const [:0]const u8) Error!AttachMode {
if (args.len < 2) return Error.NotEnoughArguments;
- if (args.len > 2) return Error.TooManyArguments;
if (mem.eql(u8, "top", args[1])) {
- server.config.attach_mode = .top;
+ return if (args.len > 2) Error.TooManyArguments else .top;
} else if (mem.eql(u8, "bottom", args[1])) {
- server.config.attach_mode = .bottom;
- } else {
- return Error.UnknownOption;
+ return if (args.len > 2) Error.TooManyArguments else .bottom;
+ } else if (mem.eql(u8, "after", args[1])) {
+ if (args.len < 3) return Error.NotEnoughArguments;
+ if (args.len > 3) return Error.TooManyArguments;
+ return .{ .after = try std.fmt.parseInt(usize, args[2], 10) };
}
+ return Error.UnknownOption;
+}
+
+pub fn outputAttachMode(
+ seat: *Seat,
+ args: []const [:0]const u8,
+ _: *?[]const u8,
+) Error!void {
+ const output = seat.focused_output orelse return;
+ output.attach_mode = try parseAttachMode(args);
+}
+
+pub fn defaultAttachMode(
+ _: *Seat,
+ args: []const [:0]const u8,
+ _: *?[]const u8,
+) Error!void {
+ server.config.default_attach_mode = try parseAttachMode(args);
}