diff options
| author | Orfeas <38209077+0xfea5@users.noreply.github.com> | 2024-01-03 16:33:13 +0200 |
|---|---|---|
| committer | Isaac Freund <mail@isaacfreund.com> | 2024-01-13 12:29:09 -0600 |
| commit | 6a71fc65b0d64a03fd0f37602b14b3d91e61be51 (patch) | |
| tree | b4f5a9cc8ca6295bf69c0ffbddb2864ecc114dc2 | |
| parent | 6e9bd83e1d0e2132d2def338b51f66867cd88907 (diff) | |
| download | river-6a71fc65b0d64a03fd0f37602b14b3d91e61be51.tar.gz river-6a71fc65b0d64a03fd0f37602b14b3d91e61be51.tar.xz | |
attach-mode: implement after <N>
| -rw-r--r-- | doc/riverctl.1.scd | 16 | ||||
| -rw-r--r-- | river/Config.zig | 9 | ||||
| -rw-r--r-- | river/Output.zig | 7 | ||||
| -rw-r--r-- | river/View.zig | 21 | ||||
| -rw-r--r-- | river/command.zig | 4 | ||||
| -rw-r--r-- | river/command/attach_mode.zig | 36 |
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); } |
