river: add outputs rule

This commit is contained in:
Doclic
2023-10-19 12:58:11 +02:00
parent 206bb2e713
commit bf4154007d
8 changed files with 78 additions and 24 deletions

View File

@ -17,15 +17,19 @@
const Self = @This();
const std = @import("std");
const fmt = std.fmt;
const mem = std.mem;
const globber = @import("globber");
const xkb = @import("xkbcommon");
const server = &@import("main.zig").server;
const util = @import("util.zig");
const Server = @import("Server.zig");
const Output = @import("Output.zig");
const Mode = @import("Mode.zig");
const RuleList = @import("rule_list.zig").RuleList;
const View = @import("View.zig");
pub const AttachMode = enum {
top,
@ -76,6 +80,7 @@ modes: std.ArrayListUnmanaged(Mode),
float_rules: RuleList(bool) = .{},
ssd_rules: RuleList(bool) = .{},
tag_rules: RuleList(u32) = .{},
output_rules: RuleList([]const u8) = .{},
/// The selected focus_follows_cursor mode
focus_follows_cursor: FocusFollowsCursorMode = .disabled,
@ -152,9 +157,33 @@ pub fn deinit(self: *Self) void {
self.float_rules.deinit();
self.ssd_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);
self.keymap.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;
}

View File

@ -492,7 +492,8 @@ pub fn map(view: *Self) !void {
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
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 File

@ -33,6 +33,7 @@ const Action = enum {
ssd,
csd,
tag,
output,
};
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) {
.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.NotEnoughArguments;
@ -85,6 +86,15 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
.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;
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) {
.float, .@"no-float" => {
_ = server.config.float_rules.del(.{
.app_id_glob = app_id_glob,
.title_glob = title_glob,
});
_ = server.config.float_rules.del(rule);
},
.ssd, .csd => {
_ = server.config.ssd_rules.del(.{
.app_id_glob = app_id_glob,
.title_glob = title_glob,
});
_ = server.config.ssd_rules.del(rule);
apply_ssd_rules();
server.root.applyPending();
},
.tag => {
_ = server.config.tag_rules.del(.{
.app_id_glob = app_id_glob,
.title_glob = title_glob,
});
_ = server.config.tag_rules.del(rule);
},
.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,
ssd,
tag,
output,
}, args[1]) orelse return Error.UnknownOption;
const max_glob_len = switch (list) {
.float => server.config.float_rules.getMaxGlobLen(),
.ssd => server.config.ssd_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 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});
}
},
.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();