river: Allow applying CSD based on window titles
This extends the `csd-filter-add` command to allow matching on window titles as well, using a `csd-filter-add kind pattern` syntax. The following kinds are supported: * `title`, which matches window titles * `app-id`, which matches app ids Only exact matches are considered. As an example following configuration applies client-side decorations to all windows with the title 'asdf with spaces'. riverctl csd-filter-add title 'asdf with spaces'
This commit is contained in:
committed by
Isaac Freund
parent
98aed8d47e
commit
5f6428bafe
@ -79,15 +79,22 @@ pub fn csdFilterAdd(
|
||||
args: []const [:0]const u8,
|
||||
out: *?[]const u8,
|
||||
) Error!void {
|
||||
if (args.len < 2) return Error.NotEnoughArguments;
|
||||
if (args.len > 2) return Error.TooManyArguments;
|
||||
if (args.len < 3) return Error.NotEnoughArguments;
|
||||
if (args.len > 3) return Error.TooManyArguments;
|
||||
|
||||
const gop = try server.config.csd_filter.getOrPut(util.gpa, args[1]);
|
||||
const kind = std.meta.stringToEnum(FilterKind, args[1]) orelse return Error.UnknownOption;
|
||||
const map = switch (kind) {
|
||||
.@"app-id" => &server.config.csd_filter_app_ids,
|
||||
.title => &server.config.csd_filter_titles,
|
||||
};
|
||||
|
||||
const key = args[2];
|
||||
const gop = try map.getOrPut(util.gpa, key);
|
||||
if (gop.found_existing) return;
|
||||
errdefer assert(server.config.csd_filter.remove(args[1]));
|
||||
gop.key_ptr.* = try std.mem.dupe(util.gpa, u8, args[1]);
|
||||
errdefer assert(map.remove(key));
|
||||
gop.key_ptr.* = try std.mem.dupe(util.gpa, u8, key);
|
||||
|
||||
csdFilterUpdateViews(args[1], .add);
|
||||
csdFilterUpdateViews(kind, key, .add);
|
||||
}
|
||||
|
||||
pub fn csdFilterRemove(
|
||||
@ -96,23 +103,29 @@ pub fn csdFilterRemove(
|
||||
args: []const [:0]const u8,
|
||||
out: *?[]const u8,
|
||||
) Error!void {
|
||||
if (args.len < 2) return Error.NotEnoughArguments;
|
||||
if (args.len > 2) return Error.TooManyArguments;
|
||||
if (args.len < 3) return Error.NotEnoughArguments;
|
||||
if (args.len > 3) return Error.TooManyArguments;
|
||||
|
||||
if (server.config.csd_filter.fetchRemove(args[1])) |kv| {
|
||||
const kind = std.meta.stringToEnum(FilterKind, args[1]) orelse return Error.UnknownOption;
|
||||
const map = switch (kind) {
|
||||
.@"app-id" => &server.config.csd_filter_app_ids,
|
||||
.title => &server.config.csd_filter_titles,
|
||||
};
|
||||
|
||||
const key = args[2];
|
||||
if (map.fetchRemove(key)) |kv| {
|
||||
util.gpa.free(kv.key);
|
||||
csdFilterUpdateViews(args[1], .remove);
|
||||
csdFilterUpdateViews(kind, key, .remove);
|
||||
}
|
||||
}
|
||||
|
||||
fn csdFilterUpdateViews(app_id: []const u8, operation: enum { add, remove }) void {
|
||||
fn csdFilterUpdateViews(kind: FilterKind, pattern: []const u8, operation: enum { add, remove }) void {
|
||||
var decoration_it = server.decoration_manager.decorations.first;
|
||||
while (decoration_it) |decoration_node| : (decoration_it = decoration_node.next) {
|
||||
const xdg_toplevel_decoration = decoration_node.data.xdg_toplevel_decoration;
|
||||
const view = @intToPtr(*View, xdg_toplevel_decoration.surface.data);
|
||||
const view_app_id = mem.span(view.getAppId()) orelse continue;
|
||||
|
||||
if (mem.eql(u8, app_id, view_app_id)) {
|
||||
const view = @intToPtr(*View, xdg_toplevel_decoration.surface.data);
|
||||
if (viewMatchesPattern(kind, pattern, view)) {
|
||||
const toplevel = view.impl.xdg_toplevel.xdg_surface.role_data.toplevel;
|
||||
switch (operation) {
|
||||
.add => {
|
||||
@ -129,3 +142,12 @@ fn csdFilterUpdateViews(app_id: []const u8, operation: enum { add, remove }) voi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn viewMatchesPattern(kind: FilterKind, pattern: []const u8, view: *View) bool {
|
||||
const p = switch (kind) {
|
||||
.@"app-id" => mem.span(view.getAppId()),
|
||||
.title => mem.span(view.getTitle()),
|
||||
} orelse return false;
|
||||
|
||||
return mem.eql(u8, pattern, p);
|
||||
}
|
||||
|
Reference in New Issue
Block a user