aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/riverctl.1.scd16
-rw-r--r--river/Config.zig32
-rw-r--r--river/XdgToplevel.zig13
-rw-r--r--river/XwaylandView.zig13
-rw-r--r--river/command/filter.zig35
5 files changed, 71 insertions, 38 deletions
diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd
index ae6ac48..68cbbb6 100644
--- a/doc/riverctl.1.scd
+++ b/doc/riverctl.1.scd
@@ -41,14 +41,14 @@ over the Wayland protocol.
*exit*
Exit the compositor, terminating the Wayland session.
-*float-filter-add* _app-id_
- Add _app-id_ to the float filter list. Views with this _app-id_
- will start floating. Note that this affects only new views, not already
- existing ones.
-
-*float-filter-remove* _app-id_
- Remove an _app-id_ from the float filter list. Note that this affects only
- new views, not already existing ones.
+*float-filter-add* *app-id*|*title* _pattern_
+ Add a pattern to the float filter list. Note that this affects only new
+ views, not already existing ones. Title updates are also not taken into
+ account.
+
+*float-filter-remove* *app-id*|*title* _pattern_
+ Remove an app-id or title from the float filter list. Note that this
+ affects only new views, not already existing ones.
*focus-output* *next*|*previous*|*up*|*right*|*down*|*left*
Focus the next or previous output or the closest output in any direction.
diff --git a/river/Config.zig b/river/Config.zig
index af80a19..113264c 100644
--- a/river/Config.zig
+++ b/river/Config.zig
@@ -24,6 +24,7 @@ const util = @import("util.zig");
const Server = @import("Server.zig");
const Mode = @import("Mode.zig");
const AttachMode = @import("view_stack.zig").AttachMode;
+const View = @import("View.zig");
pub const FocusFollowsCursorMode = enum {
disabled,
@@ -57,8 +58,9 @@ mode_to_id: std.StringHashMap(usize),
/// All user-defined keymap modes, indexed by mode id
modes: std.ArrayList(Mode),
-/// Set of app_ids which will be started floating
-float_filter: std.StringHashMapUnmanaged(void) = .{},
+/// Sets of app_ids and titles which will be started floating
+float_filter_app_ids: std.StringHashMapUnmanaged(void) = .{},
+float_filter_titles: std.StringHashMapUnmanaged(void) = .{},
/// Set of app_ids which are allowed to use client side decorations
csd_filter: std.StringHashMapUnmanaged(void) = .{},
@@ -119,9 +121,15 @@ pub fn deinit(self: *Self) void {
self.modes.deinit();
{
- var it = self.float_filter.keyIterator();
+ var it = self.float_filter_app_ids.keyIterator();
while (it.next()) |key| util.gpa.free(key.*);
- self.float_filter.deinit(util.gpa);
+ self.float_filter_app_ids.deinit(util.gpa);
+ }
+
+ {
+ var it = self.float_filter_titles.keyIterator();
+ while (it.next()) |key| util.gpa.free(key.*);
+ self.float_filter_titles.deinit(util.gpa);
}
{
@@ -132,3 +140,19 @@ pub fn deinit(self: *Self) void {
util.gpa.free(self.default_layout_namespace);
}
+
+pub fn shouldFloat(self: Self, view: *View) bool {
+ if (view.getAppId()) |app_id| {
+ if (self.float_filter_app_ids.contains(std.mem.span(app_id))) {
+ return true;
+ }
+ }
+
+ if (view.getTitle()) |title| {
+ if (self.float_filter_titles.contains(std.mem.span(title))) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index dfdf188..b837c0d 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -212,15 +212,10 @@ fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurfa
view.current.float = true;
view.pending.float = true;
view.pending.box = view.float_box;
- } else {
- // Make views with app_ids listed in the float filter float
- if (toplevel.app_id) |app_id| {
- if (server.config.float_filter.contains(mem.span(app_id))) {
- view.current.float = true;
- view.pending.float = true;
- view.pending.box = view.float_box;
- }
- }
+ } else if (server.config.shouldFloat(view)) {
+ view.current.float = true;
+ view.pending.float = true;
+ view.pending.box = view.float_box;
}
// If the toplevel has an app_id which is not configured to use client side
diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig
index e467dc2..2b428e1 100644
--- a/river/XwaylandView.zig
+++ b/river/XwaylandView.zig
@@ -196,15 +196,10 @@ fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wl
view.current.float = true;
view.pending.float = true;
view.pending.box = view.float_box;
- } else {
- // Make views with app_ids listed in the float filter float
- if (self.xwayland_surface.class) |app_id| {
- if (server.config.float_filter.contains(std.mem.span(app_id))) {
- view.current.float = true;
- view.pending.float = true;
- view.pending.box = view.float_box;
- }
- }
+ } else if (server.config.shouldFloat(view)) {
+ view.current.float = true;
+ view.pending.float = true;
+ view.pending.box = view.float_box;
}
view.map() catch {
diff --git a/river/command/filter.zig b/river/command/filter.zig
index 4886aed..f8f6143 100644
--- a/river/command/filter.zig
+++ b/river/command/filter.zig
@@ -27,19 +27,31 @@ const ViewStack = @import("view_stack.zig").ViewStack;
const Error = @import("../command.zig").Error;
const Seat = @import("../Seat.zig");
+const FilterKind = enum {
+ @"app-id",
+ title,
+};
+
pub fn floatFilterAdd(
allocator: *mem.Allocator,
seat: *Seat,
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 kind = std.meta.stringToEnum(FilterKind, args[1]) orelse return Error.UnknownOption;
+ const map = switch (kind) {
+ .@"app-id" => &server.config.float_filter_app_ids,
+ .title => &server.config.float_filter_titles,
+ };
- const gop = try server.config.float_filter.getOrPut(util.gpa, args[1]);
+ const key = args[2];
+ const gop = try map.getOrPut(util.gpa, key);
if (gop.found_existing) return;
- errdefer assert(server.config.float_filter.remove(args[1]));
- gop.key_ptr.* = try std.mem.dupe(util.gpa, u8, args[1]);
+ errdefer assert(map.remove(args[1]));
+ gop.key_ptr.* = try std.mem.dupe(util.gpa, u8, key);
}
pub fn floatFilterRemove(
@@ -48,10 +60,17 @@ pub fn floatFilterRemove(
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 kind = std.meta.stringToEnum(FilterKind, args[1]) orelse return Error.UnknownOption;
+ const map = switch (kind) {
+ .@"app-id" => &server.config.float_filter_app_ids,
+ .title => &server.config.float_filter_titles,
+ };
- if (server.config.float_filter.fetchRemove(args[1])) |kv| util.gpa.free(kv.key);
+ const key = args[2];
+ if (map.fetchRemove(key)) |kv| util.gpa.free(kv.key);
}
pub fn csdFilterAdd(