aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsaac Freund <ifreund@ifreund.xyz>2021-07-12 19:37:56 +0200
committerIsaac Freund <ifreund@ifreund.xyz>2021-07-12 17:57:01 +0000
commit7b18b4944e8534733a5d65c343976064532333b4 (patch)
tree8ec81a78c1c7d2bab84a7c29bce64b48b8ddff05
parent968aef345900c0e06ea22a225c37822fddcc31c2 (diff)
downloadriver-7b18b4944e8534733a5d65c343976064532333b4.tar.gz
river-7b18b4944e8534733a5d65c343976064532333b4.tar.xz
config: use hash sets for filters, clean up code
-rw-r--r--river/Config.zig33
-rw-r--r--river/Decoration.zig13
-rw-r--r--river/XdgToplevel.zig14
-rw-r--r--river/XwaylandView.zig7
-rw-r--r--river/command/filter.zig108
5 files changed, 77 insertions, 98 deletions
diff --git a/river/Config.zig b/river/Config.zig
index 606dc6b..dbc7c39 100644
--- a/river/Config.zig
+++ b/river/Config.zig
@@ -56,11 +56,11 @@ mode_to_id: std.StringHashMap(usize),
/// All user-defined keymap modes, indexed by mode id
modes: std.ArrayList(Mode),
-/// List of app_ids which will be started floating
-float_filter: std.ArrayList([]const u8),
+/// Set of app_ids which will be started floating
+float_filter: std.StringHashMapUnmanaged(void) = .{},
-/// List of app_ids which are allowed to use client side decorations
-csd_filter: std.ArrayList([]const u8),
+/// Set of app_ids which are allowed to use client side decorations
+csd_filter: std.StringHashMapUnmanaged(void) = .{},
/// The selected focus_follows_cursor mode
focus_follows_cursor: FocusFollowsCursorMode = .disabled,
@@ -99,10 +99,7 @@ pub fn init() !Self {
var self = Self{
.mode_to_id = std.StringHashMap(usize).init(util.gpa),
.modes = std.ArrayList(Mode).init(util.gpa),
- .float_filter = std.ArrayList([]const u8).init(util.gpa),
- .csd_filter = std.ArrayList([]const u8).init(util.gpa),
};
-
errdefer self.deinit();
// Start with two empty modes, "normal" and "locked"
@@ -124,18 +121,26 @@ pub fn init() !Self {
}
pub fn deinit(self: *Self) void {
- var it = self.mode_to_id.keyIterator();
- while (it.next()) |key| util.gpa.free(key.*);
- self.mode_to_id.deinit();
+ {
+ var it = self.mode_to_id.keyIterator();
+ while (it.next()) |key| util.gpa.free(key.*);
+ self.mode_to_id.deinit();
+ }
for (self.modes.items) |mode| mode.deinit();
self.modes.deinit();
- for (self.float_filter.items) |s| util.gpa.free(s);
- self.float_filter.deinit();
+ {
+ var it = self.float_filter.keyIterator();
+ while (it.next()) |key| util.gpa.free(key.*);
+ self.float_filter.deinit(util.gpa);
+ }
- for (self.csd_filter.items) |s| util.gpa.free(s);
- self.csd_filter.deinit();
+ {
+ var it = self.csd_filter.keyIterator();
+ while (it.next()) |key| util.gpa.free(key.*);
+ self.csd_filter.deinit(util.gpa);
+ }
util.gpa.free(self.default_layout_namespace);
}
diff --git a/river/Decoration.zig b/river/Decoration.zig
index 2af5405..4159bc6 100644
--- a/river/Decoration.zig
+++ b/river/Decoration.zig
@@ -18,6 +18,7 @@
const Self = @This();
const std = @import("std");
+const mem = std.mem;
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
@@ -62,11 +63,9 @@ fn handleRequestMode(
const self = @fieldParentPtr(Self, "request_mode", listener);
const toplevel = self.xdg_toplevel_decoration.surface.role_data.toplevel;
- const app_id: [*:0]const u8 = if (toplevel.app_id) |id| id else "NULL";
-
- _ = self.xdg_toplevel_decoration.setMode(
- for (server.config.csd_filter.items) |filter_app_id| {
- if (std.mem.eql(u8, std.mem.span(app_id), filter_app_id)) break .client_side;
- } else .server_side,
- );
+ if (toplevel.app_id != null and server.config.csd_filter.contains(mem.span(toplevel.app_id.?))) {
+ _ = self.xdg_toplevel_decoration.setMode(.client_side);
+ } else {
+ _ = self.xdg_toplevel_decoration.setMode(.server_side);
+ }
}
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 0b9dcaa..4bd8cc3 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -18,6 +18,7 @@
const Self = @This();
const std = @import("std");
+const mem = std.mem;
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
@@ -208,7 +209,6 @@ fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurfa
const state = &toplevel.current;
const has_fixed_size = state.min_width != 0 and state.min_height != 0 and
(state.min_width == state.max_width or state.min_height == state.max_height);
- const app_id: [*:0]const u8 = if (toplevel.app_id) |id| id else "NULL";
if (toplevel.parent != null or has_fixed_size) {
// If the toplevel has a parent or has a fixed size make it float
@@ -217,23 +217,19 @@ fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurfa
view.pending.box = view.float_box;
} else {
// Make views with app_ids listed in the float filter float
- for (server.config.float_filter.items) |filter_app_id| {
- if (std.mem.eql(u8, std.mem.span(app_id), std.mem.span(filter_app_id))) {
+ 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;
- break;
}
}
}
// If the toplevel has an app_id which is not configured to use client side
// decorations, inform it that it is tiled.
- for (server.config.csd_filter.items) |filter_app_id| {
- if (std.mem.eql(u8, std.mem.span(app_id), filter_app_id)) {
- view.draw_borders = false;
- break;
- }
+ if (toplevel.app_id != null and server.config.csd_filter.contains(mem.span(toplevel.app_id.?))) {
+ view.draw_borders = false;
} else {
_ = toplevel.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
}
diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig
index ecd1747..089aafc 100644
--- a/river/XwaylandView.zig
+++ b/river/XwaylandView.zig
@@ -191,8 +191,6 @@ fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wl
else
false;
- const app_id: [*:0]const u8 = if (self.xwayland_surface.class) |id| id else "NULL";
-
if (self.xwayland_surface.parent != null or has_fixed_size) {
// If the toplevel has a parent or has a fixed size make it float
view.current.float = true;
@@ -200,12 +198,11 @@ fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wl
view.pending.box = view.float_box;
} else {
// Make views with app_ids listed in the float filter float
- for (server.config.float_filter.items) |filter_app_id| {
- if (std.mem.eql(u8, std.mem.span(app_id), std.mem.span(filter_app_id))) {
+ 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;
- break;
}
}
}
diff --git a/river/command/filter.zig b/river/command/filter.zig
index 2818c15..911eb09 100644
--- a/river/command/filter.zig
+++ b/river/command/filter.zig
@@ -16,114 +16,96 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const std = @import("std");
+const assert = std.debug.assert;
+const mem = std.mem;
const server = &@import("../main.zig").server;
const util = @import("../util.zig");
-const View = @import("View.zig");
+const View = @import("../View.zig");
const ViewStack = @import("view_stack.zig").ViewStack;
const Error = @import("../command.zig").Error;
const Seat = @import("../Seat.zig");
pub fn floatFilterAdd(
- allocator: *std.mem.Allocator,
+ allocator: *mem.Allocator,
seat: *Seat,
args: []const []const u8,
out: *?[]const u8,
) Error!void {
- try modifyFilter(allocator, &server.config.float_filter, args, .add);
+ if (args.len < 2) return Error.NotEnoughArguments;
+ if (args.len > 2) return Error.TooManyArguments;
+
+ const gop = try server.config.float_filter.getOrPut(util.gpa, args[1]);
+ 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]);
}
pub fn floatFilterRemove(
- allocator: *std.mem.Allocator,
+ allocator: *mem.Allocator,
seat: *Seat,
args: []const []const u8,
out: *?[]const u8,
) Error!void {
- try modifyFilter(allocator, &server.config.float_filter, args, .remove);
+ if (args.len < 2) return Error.NotEnoughArguments;
+ if (args.len > 2) return Error.TooManyArguments;
+
+ if (server.config.float_filter.fetchRemove(args[1])) |kv| util.gpa.free(kv.key);
}
pub fn csdFilterAdd(
- allocator: *std.mem.Allocator,
+ allocator: *mem.Allocator,
seat: *Seat,
args: []const []const u8,
out: *?[]const u8,
) Error!void {
- try modifyFilter(allocator, &server.config.csd_filter, args, .add);
+ if (args.len < 2) return Error.NotEnoughArguments;
+ if (args.len > 2) return Error.TooManyArguments;
+
+ const gop = try server.config.csd_filter.getOrPut(util.gpa, args[1]);
+ 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]);
+
csdFilterUpdateViews(args[1], .add);
}
pub fn csdFilterRemove(
- allocator: *std.mem.Allocator,
+ allocator: *mem.Allocator,
seat: *Seat,
args: []const []const u8,
out: *?[]const u8,
) Error!void {
- try modifyFilter(allocator, &server.config.csd_filter, args, .remove);
- csdFilterUpdateViews(args[1], .remove);
-}
-
-fn modifyFilter(
- allocator: *std.mem.Allocator,
- list: *std.ArrayList([]const u8),
- args: []const []const u8,
- operation: enum { add, remove },
-) Error!void {
if (args.len < 2) return Error.NotEnoughArguments;
if (args.len > 2) return Error.TooManyArguments;
- for (list.items) |*filter, i| {
- if (std.mem.eql(u8, filter.*, args[1])) {
- if (operation == .remove) {
- allocator.free(list.orderedRemove(i));
- }
- return;
- }
- }
- if (operation == .add) {
- try list.ensureUnusedCapacity(1);
- list.appendAssumeCapacity(try std.mem.dupe(allocator, u8, args[1]));
+
+ if (server.config.csd_filter.fetchRemove(args[1])) |kv| {
+ util.gpa.free(kv.key);
+ csdFilterUpdateViews(args[1], .remove);
}
}
fn csdFilterUpdateViews(app_id: []const u8, operation: enum { add, remove }) void {
- // There is no link between Decoration and View, so we need to iterate over
- // both separately. Note that we do not need to arrange the outputs here; If
- // the clients decoration mode changes, it will receive a configure event.
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;
- if (std.mem.eql(
- u8,
- std.mem.span(xdg_toplevel_decoration.surface.role_data.toplevel.app_id orelse return),
- app_id,
- )) {
- _ = xdg_toplevel_decoration.setMode(switch (operation) {
- .add => .client_side,
- .remove => .server_side,
- });
- }
- }
-
- var output_it = server.root.outputs.first;
- while (output_it) |output_node| : (output_it = output_node.next) {
- var view_it = output_node.data.views.first;
- while (view_it) |view_node| : (view_it = view_node.next) {
- // CSD mode is not supported for XWayland views.
- if (view_node.view.impl == .xwayland_view) continue;
+ const view = @intToPtr(*View, xdg_toplevel_decoration.surface.data);
+ const view_app_id = mem.span(view.getAppId()) orelse continue;
- const view_app_id = std.mem.span(view_node.view.getAppId() orelse continue);
- if (std.mem.eql(u8, app_id, view_app_id)) {
- const toplevel = view_node.view.impl.xdg_toplevel.xdg_surface.role_data.toplevel;
- switch (operation) {
- .add => {
- view_node.view.draw_borders = false;
- _ = toplevel.setTiled(.{ .top = false, .bottom = false, .left = false, .right = false });
- },
- .remove => {
- view_node.view.draw_borders = true;
- _ = toplevel.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
- },
- }
+ if (mem.eql(u8, app_id, view_app_id)) {
+ const toplevel = view.impl.xdg_toplevel.xdg_surface.role_data.toplevel;
+ switch (operation) {
+ .add => {
+ _ = xdg_toplevel_decoration.setMode(.client_side);
+ view.draw_borders = false;
+ _ = toplevel.setTiled(.{ .top = false, .bottom = false, .left = false, .right = false });
+ },
+ .remove => {
+ _ = xdg_toplevel_decoration.setMode(.server_side);
+ view.draw_borders = true;
+ _ = toplevel.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
+ },
}
}
}