srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/config/src
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2026-07-05 16:06:00 +0200
committersrdusr <[email protected]>2026-07-05 16:06:00 +0200
commit744757fad22db7a5ebebca9a685cdb00589a1b02 (patch)
tree1e73a425a307bae3274dad360b145560ce3e3e27 /crates/config/src
parentd448a82990efb5c510064f1de5b5d32e932a4f9e (diff)
downloadsrdwm-744757fad22db7a5ebebca9a685cdb00589a1b02.tar.gz
srdwm-744757fad22db7a5ebebca9a685cdb00589a1b02.zip
Let the config file take back a setting changed at runtime
Reported as windows still being tinted. The tint is the drop shadow, and init.lua sets general.shadows to false - loading that same config in a fresh compositor reports false, while the running session reported true. The reason it could not be corrected is a defect in the live-settings replay added earlier today. That replay re-applies every srd set after a config reload so the titlebar menu's Customize rows survive a save. The unintended half is that a live override then outranked the config file permanently: editing init.lua and saving put the override straight back, which is the state the session was found in. Live-always-wins and config-always-wins are both wrong. The rule is now that the config wins for anything it states, and a live override survives only where the config is silent. That distinction cannot come from `values`, where defaults are seeded before any script runs so every key looks set, so the config engine records which keys srd.set actually touched during the load. That record is cleared and rebuilt on each load and restored along with everything else when a reload fails. Verified both directions: a config-stated key reverts to the file's value on the next reload, and a key the config never mentions keeps its live override. 529 tests pass, clippy clean.
Diffstat (limited to 'crates/config/src')
-rw-r--r--crates/config/src/engine/general.rs7
-rw-r--r--crates/config/src/engine/mod.rs17
-rw-r--r--crates/config/src/engine/support.rs4
3 files changed, 26 insertions, 2 deletions
diff --git a/crates/config/src/engine/general.rs b/crates/config/src/engine/general.rs
index 68b441e..7c22747 100644
--- a/crates/config/src/engine/general.rs
+++ b/crates/config/src/engine/general.rs
@@ -8,7 +8,12 @@ impl Engine {
let state = self.state.clone();
Ok(self.lua.create_function(move |_, (key, value): (String, Value)| {
if let Some(v) = ConfigValue::from_lua(&value) {
- state.borrow_mut().values.insert(key, v);
+ let mut s = state.borrow_mut();
+ // Recorded so a reload can tell "the config states this"
+ // from "this is just the seeded default" - see
+ // `SharedState::config_set_keys`.
+ s.config_set_keys.insert(key.clone());
+ s.values.insert(key, v);
}
Ok(())
})?)
diff --git a/crates/config/src/engine/mod.rs b/crates/config/src/engine/mod.rs
index 8facd56..1dd3c35 100644
--- a/crates/config/src/engine/mod.rs
+++ b/crates/config/src/engine/mod.rs
@@ -35,6 +35,17 @@ struct SharedState {
/// `WindowManager` by `main.rs` and served over IPC as
/// `srd keybindings`.
key_descriptions: HashMap<String, String>,
+ /// Every key the *config* set via `srd.set`, as opposed to a seeded
+ /// default. Cleared and rebuilt on each load, so it always describes
+ /// the config currently in force.
+ ///
+ /// `values` alone cannot answer this: defaults are seeded into it
+ /// before any script runs, so every key looks set. The distinction
+ /// matters because a config file stating a value must be able to
+ /// override a live `srd set` when it is reloaded - otherwise a
+ /// setting changed at runtime can never be corrected from the config
+ /// again.
+ config_set_keys: std::collections::HashSet<String>,
/// Combos registered with `srd.bind_repeat`, which fire repeatedly while
/// held (Hyprland's `binde`). A subset of `key_bindings`.
repeat_keys: std::collections::HashSet<String>,
@@ -77,6 +88,7 @@ impl Engine {
values: default_config(),
key_bindings: HashMap::new(),
key_descriptions: HashMap::new(),
+ config_set_keys: std::collections::HashSet::new(),
repeat_keys: std::collections::HashSet::new(),
event_handlers: HashMap::new(),
config_dir: config_dir.into(),
@@ -195,6 +207,11 @@ impl Engine {
}
}
+ /// Keys the loaded config explicitly set - see `config_set_keys`.
+ pub fn config_set_keys(&self) -> Vec<String> {
+ self.state.borrow().config_set_keys.iter().cloned().collect()
+ }
+
pub fn bound_keys(&self) -> Vec<String> {
self.state.borrow().key_bindings.keys().cloned().collect()
}
diff --git a/crates/config/src/engine/support.rs b/crates/config/src/engine/support.rs
index 9d81035..b0c8caf 100644
--- a/crates/config/src/engine/support.rs
+++ b/crates/config/src/engine/support.rs
@@ -34,10 +34,11 @@ pub(super) fn do_reload(lua: &Lua, state: &Rc<RefCell<SharedState>>) -> Result<(
std::mem::take(&mut s.event_handlers),
std::mem::take(&mut s.repeat_keys),
std::mem::take(&mut s.key_descriptions),
+ std::mem::take(&mut s.config_set_keys),
);
(s.config_dir.clone(), previous)
};
- let restore = |state: &Rc<RefCell<SharedState>>, previous: (_, _, _, _)| {
+ let restore = |state: &Rc<RefCell<SharedState>>, previous: (_, _, _, _, _)| {
let mut s = state.borrow_mut();
// Whatever the failed run managed to register before erroring is
// discarded, not merged: half of a broken config is not a config.
@@ -45,6 +46,7 @@ pub(super) fn do_reload(lua: &Lua, state: &Rc<RefCell<SharedState>>) -> Result<(
s.event_handlers = previous.1;
s.repeat_keys = previous.2;
s.key_descriptions = previous.3;
+ s.config_set_keys = previous.4;
};
let path = config_dir.join("init.lua");
let src = match std::fs::read_to_string(&path) {