river: add outputs rule
This commit is contained in:
parent
206bb2e713
commit
bf4154007d
@ -1,6 +1,6 @@
|
|||||||
function __riverctl_completion ()
|
function __riverctl_completion ()
|
||||||
{
|
{
|
||||||
local rule_actions="float no-float ssd csd tag"
|
local rule_actions="float no-float ssd csd tag output"
|
||||||
if [ "${COMP_CWORD}" -eq 1 ]
|
if [ "${COMP_CWORD}" -eq 1 ]
|
||||||
then
|
then
|
||||||
OPTS=" \
|
OPTS=" \
|
||||||
@ -65,7 +65,7 @@ function __riverctl_completion ()
|
|||||||
"move"|"snap") OPTS="up down left right" ;;
|
"move"|"snap") OPTS="up down left right" ;;
|
||||||
"resize") OPTS="horizontal vertical" ;;
|
"resize") OPTS="horizontal vertical" ;;
|
||||||
"rule-add"|"rule-del") OPTS="-app-id -title $rule_actions" ;;
|
"rule-add"|"rule-del") OPTS="-app-id -title $rule_actions" ;;
|
||||||
"list-rules") OPTS="float ssd tag" ;;
|
"list-rules") OPTS="float ssd tag output" ;;
|
||||||
"map") OPTS="-release -repeat -layout" ;;
|
"map") OPTS="-release -repeat -layout" ;;
|
||||||
"unmap") OPTS="-release" ;;
|
"unmap") OPTS="-release" ;;
|
||||||
"attach-mode") OPTS="top bottom" ;;
|
"attach-mode") OPTS="top bottom" ;;
|
||||||
|
@ -83,9 +83,9 @@ complete -c riverctl -x -n '__fish_seen_subcommand_from unmap' -a
|
|||||||
complete -c riverctl -x -n '__fish_seen_subcommand_from attach-mode' -a 'top bottom'
|
complete -c riverctl -x -n '__fish_seen_subcommand_from attach-mode' -a 'top bottom'
|
||||||
complete -c riverctl -x -n '__fish_seen_subcommand_from focus-follows-cursor' -a 'disabled normal always'
|
complete -c riverctl -x -n '__fish_seen_subcommand_from focus-follows-cursor' -a 'disabled normal always'
|
||||||
complete -c riverctl -x -n '__fish_seen_subcommand_from set-cursor-warp' -a 'disabled on-output-change on-focus-change'
|
complete -c riverctl -x -n '__fish_seen_subcommand_from set-cursor-warp' -a 'disabled on-output-change on-focus-change'
|
||||||
complete -c riverctl -x -n '__fish_seen_subcommand_from rule-add' -a 'float no-float ssd csd tag'
|
complete -c riverctl -x -n '__fish_seen_subcommand_from rule-add' -a 'float no-float ssd csd tag output'
|
||||||
complete -c riverctl -x -n '__fish_seen_subcommand_from rule-del' -a 'float no-float ssd csd tag'
|
complete -c riverctl -x -n '__fish_seen_subcommand_from rule-del' -a 'float no-float ssd csd tag output'
|
||||||
complete -c riverctl -x -n '__fish_seen_subcommand_from list-rules' -a 'float ssd tag'
|
complete -c riverctl -x -n '__fish_seen_subcommand_from list-rules' -a 'float ssd tag output'
|
||||||
|
|
||||||
# Subcommands for 'input'
|
# Subcommands for 'input'
|
||||||
complete -c riverctl -x -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 2' -a "(__riverctl_list_input_devices)"
|
complete -c riverctl -x -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 2' -a "(__riverctl_list_input_devices)"
|
||||||
|
@ -183,9 +183,9 @@ _riverctl()
|
|||||||
# In case of a new rule added in river, we just need
|
# In case of a new rule added in river, we just need
|
||||||
# to add it to the third option between '()',
|
# to add it to the third option between '()',
|
||||||
# i.e (float no-float <new-option>)
|
# i.e (float no-float <new-option>)
|
||||||
_arguments '1: :(-app-id -title)' '2: : ' ':: :(float no-float ssd csd tag)'
|
_arguments '1: :(-app-id -title)' '2: : ' ':: :(float no-float ssd csd tag output)'
|
||||||
;;
|
;;
|
||||||
list-rules) _alternative 'arguments:args:(float ssd tag)' ;;
|
list-rules) _alternative 'arguments:args:(float ssd tag output)' ;;
|
||||||
*) return 0 ;;
|
*) return 0 ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
2
deps/zig-wlroots
vendored
2
deps/zig-wlroots
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 021fb4bbae7ea3806344102763adb63bf194ca7c
|
Subproject commit 0f07b2c666125d06529dfc688da4e71bff9a04f9
|
@ -276,6 +276,12 @@ matches everything while _\*\*_ and the empty string are invalid.
|
|||||||
and existing views.
|
and existing views.
|
||||||
- *tag*: Set the initial tags of the view. Requires the tags as
|
- *tag*: Set the initial tags of the view. Requires the tags as
|
||||||
an argument. Applies only to new views.
|
an argument. Applies only to new views.
|
||||||
|
- *output*: Set the initial output of the view. Requires the output
|
||||||
|
as an argument. Applies only to new views. The output can be specified
|
||||||
|
either by connector name (such as _HDMI-A-1_, or _DP-2_), or by
|
||||||
|
identifier in the form of _MAKE MODEL SERIAL_, for example for an output
|
||||||
|
with make: _HP Inc._, model: _HP 22w_, and serial: _CNC93720WF_, the
|
||||||
|
identifier would be: _HP Inc. HP 22w CNC93720WF_.
|
||||||
|
|
||||||
Both *float* and *no-float* rules are added to the same list,
|
Both *float* and *no-float* rules are added to the same list,
|
||||||
which means that adding a *no-float* rule with the same arguments
|
which means that adding a *no-float* rule with the same arguments
|
||||||
|
@ -17,15 +17,19 @@
|
|||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const fmt = std.fmt;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const globber = @import("globber");
|
const globber = @import("globber");
|
||||||
const xkb = @import("xkbcommon");
|
const xkb = @import("xkbcommon");
|
||||||
|
|
||||||
|
const server = &@import("main.zig").server;
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
|
||||||
const Server = @import("Server.zig");
|
const Server = @import("Server.zig");
|
||||||
|
const Output = @import("Output.zig");
|
||||||
const Mode = @import("Mode.zig");
|
const Mode = @import("Mode.zig");
|
||||||
const RuleList = @import("rule_list.zig").RuleList;
|
const RuleList = @import("rule_list.zig").RuleList;
|
||||||
|
const View = @import("View.zig");
|
||||||
|
|
||||||
pub const AttachMode = enum {
|
pub const AttachMode = enum {
|
||||||
top,
|
top,
|
||||||
@ -76,6 +80,7 @@ modes: std.ArrayListUnmanaged(Mode),
|
|||||||
float_rules: RuleList(bool) = .{},
|
float_rules: RuleList(bool) = .{},
|
||||||
ssd_rules: RuleList(bool) = .{},
|
ssd_rules: RuleList(bool) = .{},
|
||||||
tag_rules: RuleList(u32) = .{},
|
tag_rules: RuleList(u32) = .{},
|
||||||
|
output_rules: RuleList([]const u8) = .{},
|
||||||
|
|
||||||
/// The selected focus_follows_cursor mode
|
/// The selected focus_follows_cursor mode
|
||||||
focus_follows_cursor: FocusFollowsCursorMode = .disabled,
|
focus_follows_cursor: FocusFollowsCursorMode = .disabled,
|
||||||
@ -152,9 +157,33 @@ pub fn deinit(self: *Self) void {
|
|||||||
self.float_rules.deinit();
|
self.float_rules.deinit();
|
||||||
self.ssd_rules.deinit();
|
self.ssd_rules.deinit();
|
||||||
self.tag_rules.deinit();
|
self.tag_rules.deinit();
|
||||||
|
for (self.output_rules.rules.items) |rule| {
|
||||||
|
util.gpa.free(rule.value);
|
||||||
|
}
|
||||||
|
self.output_rules.deinit();
|
||||||
|
|
||||||
util.gpa.free(self.default_layout_namespace);
|
util.gpa.free(self.default_layout_namespace);
|
||||||
|
|
||||||
self.keymap.unref();
|
self.keymap.unref();
|
||||||
self.xkb_context.unref();
|
self.xkb_context.unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn outputRuleMatch(self: *Self, view: *View) !?*Output {
|
||||||
|
const output_name = self.output_rules.match(view) orelse return null;
|
||||||
|
var it = server.root.active_outputs.iterator(.forward);
|
||||||
|
while (it.next()) |output| {
|
||||||
|
const wlr_output = output.wlr_output;
|
||||||
|
if (mem.eql(u8, output_name, mem.span(wlr_output.name))) return output;
|
||||||
|
|
||||||
|
// This allows matching with "Maker Model Serial" instead of "Connector"
|
||||||
|
const maker = wlr_output.make orelse "Unknown";
|
||||||
|
const model = wlr_output.model orelse "Unknown";
|
||||||
|
const serial = wlr_output.serial orelse "Unknown";
|
||||||
|
const identifier = try fmt.allocPrint(util.gpa, "{s} {s} {s}", .{ maker, model, serial });
|
||||||
|
defer util.gpa.free(identifier);
|
||||||
|
|
||||||
|
if (mem.eql(u8, output_name, identifier)) return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@ -492,7 +492,8 @@ pub fn map(view: *Self) !void {
|
|||||||
view.pending.ssd = ssd;
|
view.pending.ssd = ssd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server.input_manager.defaultSeat().focused_output) |output| {
|
const focused_output = server.input_manager.defaultSeat().focused_output;
|
||||||
|
if (try server.config.outputRuleMatch(view) orelse focused_output) |output| {
|
||||||
// Center the initial pending box on the output
|
// 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.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);
|
view.pending.box.y = @divTrunc(@max(0, output.usable_box.height - view.pending.box.height), 2);
|
||||||
|
@ -33,6 +33,7 @@ const Action = enum {
|
|||||||
ssd,
|
ssd,
|
||||||
csd,
|
csd,
|
||||||
tag,
|
tag,
|
||||||
|
output,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void {
|
pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void {
|
||||||
@ -49,7 +50,7 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
|
|
||||||
const positional_arguments_count: u8 = switch (action) {
|
const positional_arguments_count: u8 = switch (action) {
|
||||||
.float, .@"no-float", .ssd, .csd => 1,
|
.float, .@"no-float", .ssd, .csd => 1,
|
||||||
.tag => 2,
|
.tag, .output => 2,
|
||||||
};
|
};
|
||||||
if (result.args.len > positional_arguments_count) return Error.TooManyArguments;
|
if (result.args.len > positional_arguments_count) return Error.TooManyArguments;
|
||||||
if (result.args.len < positional_arguments_count) return Error.NotEnoughArguments;
|
if (result.args.len < positional_arguments_count) return Error.NotEnoughArguments;
|
||||||
@ -85,6 +86,15 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
.value = tag,
|
.value = tag,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
.output => {
|
||||||
|
const output_name = try util.gpa.dupe(u8, result.args[1]);
|
||||||
|
errdefer util.gpa.free(output_name);
|
||||||
|
try server.config.output_rules.add(.{
|
||||||
|
.app_id_glob = app_id_glob,
|
||||||
|
.title_glob = title_glob,
|
||||||
|
.value = output_name,
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,29 +110,27 @@ pub fn ruleDel(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
if (result.args.len < 1) return Error.NotEnoughArguments;
|
if (result.args.len < 1) return Error.NotEnoughArguments;
|
||||||
|
|
||||||
const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption;
|
const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption;
|
||||||
const app_id_glob = result.flags.@"app-id" orelse "*";
|
|
||||||
const title_glob = result.flags.title orelse "*";
|
|
||||||
|
|
||||||
|
const rule = .{
|
||||||
|
.app_id_glob = result.flags.@"app-id" orelse "*",
|
||||||
|
.title_glob = result.flags.title orelse "*",
|
||||||
|
};
|
||||||
switch (action) {
|
switch (action) {
|
||||||
.float, .@"no-float" => {
|
.float, .@"no-float" => {
|
||||||
_ = server.config.float_rules.del(.{
|
_ = server.config.float_rules.del(rule);
|
||||||
.app_id_glob = app_id_glob,
|
|
||||||
.title_glob = title_glob,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
.ssd, .csd => {
|
.ssd, .csd => {
|
||||||
_ = server.config.ssd_rules.del(.{
|
_ = server.config.ssd_rules.del(rule);
|
||||||
.app_id_glob = app_id_glob,
|
|
||||||
.title_glob = title_glob,
|
|
||||||
});
|
|
||||||
apply_ssd_rules();
|
apply_ssd_rules();
|
||||||
server.root.applyPending();
|
server.root.applyPending();
|
||||||
},
|
},
|
||||||
.tag => {
|
.tag => {
|
||||||
_ = server.config.tag_rules.del(.{
|
_ = server.config.tag_rules.del(rule);
|
||||||
.app_id_glob = app_id_glob,
|
},
|
||||||
.title_glob = title_glob,
|
.output => {
|
||||||
});
|
if (server.config.output_rules.del(rule)) |output_rule| {
|
||||||
|
util.gpa.free(output_rule);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,11 +152,13 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
float,
|
float,
|
||||||
ssd,
|
ssd,
|
||||||
tag,
|
tag,
|
||||||
|
output,
|
||||||
}, args[1]) orelse return Error.UnknownOption;
|
}, args[1]) orelse return Error.UnknownOption;
|
||||||
const max_glob_len = switch (list) {
|
const max_glob_len = switch (list) {
|
||||||
.float => server.config.float_rules.getMaxGlobLen(),
|
.float => server.config.float_rules.getMaxGlobLen(),
|
||||||
.ssd => server.config.ssd_rules.getMaxGlobLen(),
|
.ssd => server.config.ssd_rules.getMaxGlobLen(),
|
||||||
.tag => server.config.tag_rules.getMaxGlobLen(),
|
.tag => server.config.tag_rules.getMaxGlobLen(),
|
||||||
|
.output => server.config.output_rules.getMaxGlobLen(),
|
||||||
};
|
};
|
||||||
const app_id_column_max = 2 + @max("app-id".len, max_glob_len.app_id);
|
const app_id_column_max = 2 + @max("app-id".len, max_glob_len.app_id);
|
||||||
const title_column_max = 2 + @max("title".len, max_glob_len.title);
|
const title_column_max = 2 + @max("title".len, max_glob_len.title);
|
||||||
@ -185,6 +195,14 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
try writer.print("{b}\n", .{rule.value});
|
try writer.print("{b}\n", .{rule.value});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.output => {
|
||||||
|
const rules = server.config.output_rules.rules.items;
|
||||||
|
for (rules) |rule| {
|
||||||
|
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer);
|
||||||
|
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||||
|
try writer.print("{s}\n", .{rule.value});
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
out.* = try buffer.toOwnedSlice();
|
out.* = try buffer.toOwnedSlice();
|
||||||
|
Loading…
Reference in New Issue
Block a user