Merge pull request 'Add support for reloading config' (#6) from config-reload into main

Reviewed-on: https://codeberg.org/bwbuhse/beansprout/pulls/6
This commit is contained in:
Ben Buhse 2026-01-31 21:38:10 +01:00
commit 342c0fdf8f
4 changed files with 57 additions and 25 deletions

View file

@ -313,15 +313,6 @@ fn loadKeybindsChildBlock(config: *Config, parser: *kdl.Parser) !void {
const split_exec = try utils.tokenizeToOwnedSlices(exec_str, ' '); const split_exec = try utils.tokenizeToOwnedSlices(exec_str, ' ');
break :sw .{ .spawn = split_exec }; break :sw .{ .spawn = split_exec };
}, },
.focus_next => {
break :sw .focus_next;
},
.focus_prev => {
break :sw .focus_prev;
},
.zoom => {
break :sw .zoom;
},
.change_ratio => { .change_ratio => {
const diff_str = utils.stripQuotes(node.arg(parser, 2) orelse { const diff_str = utils.stripQuotes(node.arg(parser, 2) orelse {
logWarnMissingNodeArg(name, "diff"); logWarnMissingNodeArg(name, "diff");
@ -333,11 +324,13 @@ fn loadKeybindsChildBlock(config: *Config, parser: *kdl.Parser) !void {
}; };
break :sw .{ .change_ratio = diff }; break :sw .{ .change_ratio = diff };
}, },
.toggle_fullscreen => { inline .focus_next, .focus_prev, .zoom, .reload_config, .toggle_fullscreen, .close_window => |cmd| {
break :sw .toggle_fullscreen; // None of these have arguments, just create the union and give it back
}, break :sw @unionInit(
.close_window => { XkbBindings.Command,
break :sw .close_window; @tagName(cmd),
{},
);
}, },
inline .set_output_tags, .set_window_tags, .toggle_output_tags, .toggle_window_tags => |cmd| { inline .set_output_tags, .set_window_tags, .toggle_output_tags, .toggle_window_tags => |cmd| {
const tags_str = utils.stripQuotes(node.arg(parser, 2) orelse { const tags_str = utils.stripQuotes(node.arg(parser, 2) orelse {
@ -348,7 +341,11 @@ fn loadKeybindsChildBlock(config: *Config, parser: *kdl.Parser) !void {
logWarnInvalidNodeArg(name, tags_str); logWarnInvalidNodeArg(name, tags_str);
continue; continue;
}; };
break :sw @unionInit(XkbBindings.Command, @tagName(cmd), tags); break :sw @unionInit(
XkbBindings.Command,
@tagName(cmd),
tags,
);
}, },
}; };

View file

@ -21,6 +21,13 @@ xkb_bindings: *XkbBindings,
// WM Configuration // WM Configuration
config: *Config, config: *Config,
/// State consumed in manage() phase, reset at end of manage().
pending_manage: PendingManage = .{},
pub const PendingManage = struct {
config: ?*Config = null,
};
pub fn create( pub fn create(
wl_display: *wl.Display, wl_display: *wl.Display,
wl_registry: *wl.Registry, wl_registry: *wl.Registry,
@ -52,6 +59,22 @@ pub fn destroy(context: *Context) void {
utils.allocator.destroy(context); utils.allocator.destroy(context);
} }
pub fn manage(context: *Context) void {
defer context.pending_manage = .{};
if (context.pending_manage.config) |new_config| {
// Destroy all existing bindings
var it = context.xkb_bindings.bindings.safeIterator(.forward);
while (it.next()) |binding| {
binding.link.remove();
binding.destroy();
}
context.config.destroy();
context.config = new_config;
context.initialized = false;
}
}
const std = @import("std"); const std = @import("std");
const wayland = @import("wayland"); const wayland = @import("wayland");

View file

@ -186,9 +186,12 @@ fn manage_start(wm: *WindowManager) void {
const river_window_manager_v1 = wm.river_window_manager_v1; const river_window_manager_v1 = wm.river_window_manager_v1;
const context = wm.context; const context = wm.context;
// This gets used shortly, so it goes at the beginning
context.manage();
if (!context.initialized) { if (!context.initialized) {
// This code (should) only be run once while initializing the WM, so let's // This code runs during initial startup and after config reloads.
// mark it as cold.
@branchHint(.cold); @branchHint(.cold);
context.initialized = true; context.initialized = true;
@ -220,7 +223,7 @@ fn manage_start(wm: *WindowManager) void {
} }
} }
// Manage the WM itself first // Manage the WM itself before outputs/windows/seats
if (wm.pending_manage.primary_ratio) |primary_ratio| { if (wm.pending_manage.primary_ratio) |primary_ratio| {
// Ratios outside of this range can cause crashes anyways (when doing the layout calulcation) // Ratios outside of this range can cause crashes anyways (when doing the layout calulcation)
std.debug.assert(primary_ratio >= 0.10 and primary_ratio <= 0.90); std.debug.assert(primary_ratio >= 0.10 and primary_ratio <= 0.90);

View file

@ -10,10 +10,9 @@ pub const Command = union(enum) {
focus_prev, focus_prev,
zoom, zoom,
change_ratio: f32, change_ratio: f32,
// reload_config, // TODO reload_config,
toggle_fullscreen, toggle_fullscreen,
close_window, close_window,
// exit, // TODO: Delete?
// Tag management // Tag management
set_output_tags: u32, set_output_tags: u32,
set_window_tags: u32, set_window_tags: u32,
@ -46,7 +45,7 @@ const XkbBinding = struct {
return xkb_binding; return xkb_binding;
} }
fn destroy(xkb_binding: *XkbBinding) void { pub fn destroy(xkb_binding: *XkbBinding) void {
xkb_binding.xkb_binding_v1.destroy(); xkb_binding.xkb_binding_v1.destroy();
utils.allocator.destroy(xkb_binding); utils.allocator.destroy(xkb_binding);
} }
@ -128,10 +127,19 @@ const XkbBinding = struct {
current_focus.link.swapWith(&first_window.link); current_focus.link.swapWith(&first_window.link);
}, },
.change_ratio => |diff| { .change_ratio => |diff| {
const new_ratio = context.wm.primary_ratio + diff; context.wm.pending_manage.primary_ratio = std.math.clamp(context.wm.primary_ratio + diff, 0.10, 0.90);
if (new_ratio >= 0.10 and new_ratio <= 0.90) { },
context.wm.pending_manage.primary_ratio = context.wm.primary_ratio + diff; .reload_config => {
} // Try create new config
const new_config = Config.create() catch {
// We do this so that, if the Config fails to reload, the
// user still has *some* config.
log.err("Failed to reload Config. Not deleting old one", .{});
return;
};
// Send the config to the WM to handle during next manage
context.pending_manage.config = new_config;
context.wm.river_window_manager_v1.manageDirty();
}, },
.toggle_fullscreen => { .toggle_fullscreen => {
const seat = context.wm.seats.first() orelse return; const seat = context.wm.seats.first() orelse return;
@ -241,6 +249,7 @@ const xkbcommon = @import("xkbcommon");
const utils = @import("utils.zig"); const utils = @import("utils.zig");
const Context = @import("Context.zig"); const Context = @import("Context.zig");
const Config = @import("Config.zig");
const Seat = @import("Seat.zig"); const Seat = @import("Seat.zig");
const Window = @import("Window.zig"); const Window = @import("Window.zig");