diff options
Diffstat (limited to 'crates/config/src')
| -rw-r--r-- | crates/config/src/engine/general.rs | 35 | ||||
| -rw-r--r-- | crates/config/src/engine/register.rs | 5 | ||||
| -rw-r--r-- | crates/config/src/engine/support.rs | 33 | ||||
| -rw-r--r-- | crates/config/src/engine/tests.rs | 52 |
4 files changed, 117 insertions, 8 deletions
diff --git a/crates/config/src/engine/general.rs b/crates/config/src/engine/general.rs index 98cfebe..94b029b 100644 --- a/crates/config/src/engine/general.rs +++ b/crates/config/src/engine/general.rs @@ -194,6 +194,41 @@ impl Engine { })?) } + /// `srd.monitor.split(name, parts[, direction])` - divides connector + /// `name`'s real output into `parts` equal logical monitors for + /// placement/tiling purposes ("monitors inside monitors"), no new + /// `wl_output` involved - see `srdwm_core::monitor::MonitorSplit`'s + /// own doc comment for exactly what that does and doesn't give a + /// client. `direction` is `"columns"` (default, side-by-side) or + /// `"rows"` (stacked); any other value is treated as `"columns"` + /// rather than erroring, same "malformed value falls back to a + /// sensible default" stance other config setters already take. + /// `parts <= 1` clears an existing split for `name`. + pub(super) fn fn_monitor_split(&self) -> Result<mlua::Function<'_>> { + let state = self.state.clone(); + Ok(self.lua.create_function(move |_, (name, parts, direction): (String, u32, Option<String>)| { + let rows = matches!(direction.as_deref(), Some("rows")); + state.borrow().wm.borrow_mut().set_monitor_split(name, parts, rows); + Ok(()) + })?) + } + + /// `srd.monitor.scale(name, factor)` - sets connector `name`'s + /// output scale, applied the next time a backend brings that head up + /// (startup, hotplug, or re-enable). A physically large monitor with + /// the same pixel count as a smaller one (a big low-DPI external + /// display next to a small high-DPI laptop panel, say) can run below + /// `1.0` to show more logical desktop space rather than just larger + /// text at the same resolution. `factor <= 0` clears an existing + /// override. + pub(super) fn fn_monitor_scale(&self) -> Result<mlua::Function<'_>> { + let state = self.state.clone(); + Ok(self.lua.create_function(move |_, (name, factor): (String, f64)| { + state.borrow().wm.borrow_mut().set_monitor_scale(name, factor); + Ok(()) + })?) + } + pub(super) fn fn_load(&self) -> Result<mlua::Function<'_>> { let state = self.state.clone(); Ok(self.lua.create_function(move |lua, module: String| { diff --git a/crates/config/src/engine/register.rs b/crates/config/src/engine/register.rs index 0cf64bc..4ef6844 100644 --- a/crates/config/src/engine/register.rs +++ b/crates/config/src/engine/register.rs @@ -75,6 +75,11 @@ impl Engine { workspace.set("move_window", self.fn_workspace_move_window()?)?; srd.set("workspace", workspace)?; + let monitor = lua.create_table()?; + monitor.set("split", self.fn_monitor_split()?)?; + monitor.set("scale", self.fn_monitor_scale()?)?; + srd.set("monitor", monitor)?; + let theme = lua.create_table()?; theme.set("set_colors", self.fn_theme_set("theme.colors")?)?; theme.set("set_decorations", self.fn_theme_set("theme.decorations")?)?; diff --git a/crates/config/src/engine/support.rs b/crates/config/src/engine/support.rs index 0f83885..b67a688 100644 --- a/crates/config/src/engine/support.rs +++ b/crates/config/src/engine/support.rs @@ -80,13 +80,13 @@ pub(super) fn validate(s: &SharedState) -> Vec<String> { check_range("layout.dynamic.gaps.outer", 0.0, 100.0); check_range("layout.floating.gaps.inner", 0.0, 100.0); check_range("layout.floating.gaps.outer", 0.0, 100.0); - check_range("general.border_width", 0.0, 20.0); check_range("theme.decorations.border.width", 0.0, 20.0); check_range("theme.decorations.border.radius", 0.0, 100.0); check_range("general.animation_duration", 0.0, 1000.0); check_range("general.resize_margin", 1.0, 50.0); check_range("performance.max_fps", 30.0, 240.0); check_range("performance.window_cache_size", 10.0, 10000.0); + check_range("theme.decorations.border.inactive_dim", 0.0, 1.0); let layouts: Vec<String> = s.wm.borrow().available_layouts().iter().map(|l| l.to_string()).collect(); for key in ["general.default_layout", "monitor.primary_layout", "monitor.secondary_layout"] { @@ -110,6 +110,8 @@ pub(super) fn validate(s: &SharedState) -> Vec<String> { "theme.decorations.border.inactive_color", "theme.decorations.title_bar.background", "theme.decorations.title_bar.foreground", + "theme.decorations.title_bar.foreground_focused", + "theme.decorations.title_bar.foreground_unfocused", ]; for key in color_keys { if let Some(v) = s.values.get(key).and_then(ConfigValue::as_str) { @@ -138,7 +140,6 @@ pub(super) fn default_config() -> HashMap<String, ConfigValue> { set("general.default_layout", String("dynamic".into())); set("general.smart_placement", Bool(true)); set("general.window_gap", Number(8.0)); - set("general.border_width", Number(2.0)); set("general.animations", Bool(true)); set("general.animation_duration", Number(200.0)); set("general.shadows", Bool(true)); @@ -163,12 +164,11 @@ pub(super) fn default_config() -> HashMap<String, ConfigValue> { set("monitor.primary_layout", String("dynamic".into())); set("monitor.secondary_layout", String("tiling".into())); set("monitor.auto_detect", Bool(true)); - // Deliberately *not* seeded, unlike everything else here: srdwm has one - // flat workspace list shared by every monitor (see WindowManager's - // `current_workspace` doc comment), not Hyprland-style independent - // per-monitor workspace sets - "this monitor's primary workspace" and - // "this monitor's workspace count" describe a design that doesn't - // exist. `workspace.count` is the one knob that actually does anything. + // "This monitor's workspace *count*" specifically is still deliberately + // not seeded/implemented - `workspace.count` is one flat number for + // the whole desktop, not per-monitor. Independent per-monitor + // workspace *sets* (which workspace each monitor is showing) is a + // different, now-real knob: see `workspace.per_monitor` below. // The `window.*` namespace this codebase's own `docs/DEFAULTS.md` // documented (focus_follows_mouse/mouse_follows_focus/auto_raise/ @@ -190,6 +190,13 @@ pub(super) fn default_config() -> HashMap<String, ConfigValue> { // absence from this function, though that one differs by backend // rather than being simply unbuilt. set("workspace.auto_back_and_forth", Bool(false)); + // `false`: srdwm's original single-shared-workspace design (switching + // workspace changes what's visible on every monitor at once) - `true` + // switches to Hyprland/niri-style independent per-monitor workspace + // sets, each monitor tracking and displaying its own current + // workspace. See `WindowManager::per_monitor_workspaces`'s own doc + // comment. + set("workspace.per_monitor", Bool(false)); set("performance.vsync", Bool(true)); set("performance.max_fps", Number(60.0)); @@ -246,6 +253,11 @@ pub(super) fn default_config() -> HashMap<String, ConfigValue> { set("theme.decorations.border.radius", Number(6.0)); set("theme.decorations.border.active_color", String("#88c0d0".into())); set("theme.decorations.border.inactive_color", String("#2e3440".into())); + // The actually-wired unfocused-border knob (`apply_general_settings`, + // `srdwm_core::ThemeConfig::border_inactive_dim`): a factor applied to + // `border.active_color`, not the unused absolute `inactive_color` + // above. `1.0` matches focused exactly; `0.0` fades to black. + set("theme.decorations.border.inactive_dim", Number(0.35)); set("theme.decorations.border.focused_style", String("solid".into())); set("theme.decorations.border.unfocused_style", String("solid".into())); set("theme.decorations.title_bar.height", Number(24.0)); @@ -253,6 +265,11 @@ pub(super) fn default_config() -> HashMap<String, ConfigValue> { set("theme.decorations.title_bar.font", String("JetBrains Mono 10".into())); set("theme.decorations.title_bar.background", String("#2e3440".into())); set("theme.decorations.title_bar.foreground", String("#eceff4".into())); + // The actually-wired pair (`apply_general_settings`): titlebar text has + // always used two colours - brighter on the focused window, dimmer on + // every other one - never the single `foreground` key above. + set("theme.decorations.title_bar.foreground_focused", String("#88c0d0".into())); + set("theme.decorations.title_bar.foreground_unfocused", String("#4c566a".into())); set("platform.backend", String("auto".into())); set("platform.x11.use_ewmh", Bool(true)); diff --git a/crates/config/src/engine/tests.rs b/crates/config/src/engine/tests.rs index 521dc5a..f170320 100644 --- a/crates/config/src/engine/tests.rs +++ b/crates/config/src/engine/tests.rs @@ -197,6 +197,58 @@ } #[test] + fn srd_monitor_split_stores_a_split_request_by_connector_name() { + let dir = tempfile::tempdir().unwrap(); + let wm = Rc::new(RefCell::new(WindowManager::new())); + let engine = Engine::new(wm.clone(), dir.path()).unwrap(); + engine.lua.load(r#"srd.monitor.split("eDP-1", 2, "rows")"#).exec().unwrap(); + let split = wm.borrow().monitor_split("eDP-1").unwrap(); + assert_eq!(split.parts, 2); + assert!(split.rows); + } + + #[test] + fn srd_monitor_split_direction_defaults_to_columns() { + let dir = tempfile::tempdir().unwrap(); + let wm = Rc::new(RefCell::new(WindowManager::new())); + let engine = Engine::new(wm.clone(), dir.path()).unwrap(); + engine.lua.load(r#"srd.monitor.split("HDMI-A-1", 3)"#).exec().unwrap(); + let split = wm.borrow().monitor_split("HDMI-A-1").unwrap(); + assert_eq!(split.parts, 3); + assert!(!split.rows); + } + + #[test] + fn srd_monitor_scale_stores_a_factor_by_connector_name() { + let dir = tempfile::tempdir().unwrap(); + let wm = Rc::new(RefCell::new(WindowManager::new())); + let engine = Engine::new(wm.clone(), dir.path()).unwrap(); + engine.lua.load(r#"srd.monitor.scale("HDMI-A-1", 0.75)"#).exec().unwrap(); + assert_eq!(wm.borrow().monitor_scale("HDMI-A-1"), Some(0.75)); + } + + #[test] + fn srd_monitor_scale_with_a_non_positive_factor_clears_it() { + let dir = tempfile::tempdir().unwrap(); + let wm = Rc::new(RefCell::new(WindowManager::new())); + let engine = Engine::new(wm.clone(), dir.path()).unwrap(); + engine.lua.load(r#"srd.monitor.scale("HDMI-A-1", 0.75)"#).exec().unwrap(); + engine.lua.load(r#"srd.monitor.scale("HDMI-A-1", 0)"#).exec().unwrap(); + assert_eq!(wm.borrow().monitor_scale("HDMI-A-1"), None); + } + + #[test] + fn srd_monitor_split_with_one_part_clears_an_existing_split() { + let dir = tempfile::tempdir().unwrap(); + let wm = Rc::new(RefCell::new(WindowManager::new())); + let engine = Engine::new(wm.clone(), dir.path()).unwrap(); + engine.lua.load(r#"srd.monitor.split("eDP-1", 2)"#).exec().unwrap(); + assert!(wm.borrow().monitor_split("eDP-1").is_some()); + engine.lua.load(r#"srd.monitor.split("eDP-1", 1)"#).exec().unwrap(); + assert!(wm.borrow().monitor_split("eDP-1").is_none()); + } + + #[test] fn srd_window_scratchpad_hides_the_focused_window_and_show_brings_it_back() { let dir = tempfile::tempdir().unwrap(); let wm = Rc::new(RefCell::new(WindowManager::new())); |