config: use hash sets for filters, clean up code
This commit is contained in:
parent
968aef3459
commit
7b18b4944e
5 changed files with 77 additions and 98 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
const view = @intToPtr(*View, xdg_toplevel_decoration.surface.data);
|
||||
const view_app_id = mem.span(view.getAppId()) orelse continue;
|
||||
|
||||
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_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 });
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue