From 2dbf7da249189977d0006a0b3cfc8f526e05d523 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Mon, 5 Jan 2026 18:51:02 -0800 Subject: [PATCH] feat(config): add default_workspace_layout opt This commit adds a default_workspace_layout opt, which defaults to BSP to maintain backwards compatibility. This can also be set to "None". When set to "None" or omitted, the default behaviour for new or undefined workspaces (i.e. on monitors without config blocks) will be non-tiling. Otherwise, the given value will be the default layout applied. --- komorebi-bar/src/config.rs | 2 +- komorebi/src/core/default_layout.rs | 17 +++++++++++++++++ komorebi/src/lib.rs | 2 ++ komorebi/src/static_config.rs | 9 +++++++++ komorebi/src/window_manager.rs | 2 ++ komorebi/src/workspace.rs | 7 +++++-- schema.bar.json | 13 ++++++++++--- schema.json | 12 ++++++++++++ 8 files changed, 58 insertions(+), 6 deletions(-) diff --git a/komorebi-bar/src/config.rs b/komorebi-bar/src/config.rs index 21d67cf8..38fcea31 100644 --- a/komorebi-bar/src/config.rs +++ b/komorebi-bar/src/config.rs @@ -18,7 +18,7 @@ use std::path::PathBuf; /// The `komorebi.bar.json` configuration file reference for `v0.1.40` pub struct KomobarConfig { /// Bar height - #[cfg_attr(feature = "schemars", schemars(extend("default" = 50)))] + #[cfg_attr(feature = "schemars", schemars(extend("default" = 50.0)))] pub height: Option, /// Bar padding. Use one value for all sides or use a grouped padding for horizontal and/or /// vertical definition which can each take a single value for a symmetric padding or two diff --git a/komorebi/src/core/default_layout.rs b/komorebi/src/core/default_layout.rs index f4bd365a..47677a61 100644 --- a/komorebi/src/core/default_layout.rs +++ b/komorebi/src/core/default_layout.rs @@ -1,4 +1,5 @@ use clap::ValueEnum; +use core::str::FromStr; use serde::Deserialize; use serde::Serialize; use strum::Display; @@ -8,6 +9,22 @@ use super::OperationDirection; use super::Rect; use super::Sizing; +pub fn deserialize_option_none_default_layout<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + if s == "None" { + Ok(None) + } else { + ::from_str(&s) + .map(Some) + .map_err(serde::de::Error::custom) + } +} + #[derive( Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq, Display, EnumString, ValueEnum, )] diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index 230dd2bc..bf97d4a5 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -240,6 +240,8 @@ lazy_static! { static ref CURRENT_VIRTUAL_DESKTOP: Arc>>> = Arc::new(Mutex::new(None)); } +pub static DEFAULT_WORKSPACE_LAYOUT: AtomicCell> = + AtomicCell::new(Some(DefaultLayout::BSP)); pub static DEFAULT_WORKSPACE_PADDING: AtomicI32 = AtomicI32::new(10); pub static DEFAULT_CONTAINER_PADDING: AtomicI32 = AtomicI32::new(10); pub static DEFAULT_RESIZE_DELTA: i32 = 50; diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 34981f51..55d31b0b 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -5,6 +5,7 @@ use crate::DATA_DIR; use crate::DEFAULT_CONTAINER_PADDING; use crate::DEFAULT_MOUSE_FOLLOWS_FOCUS; use crate::DEFAULT_RESIZE_DELTA; +use crate::DEFAULT_WORKSPACE_LAYOUT; use crate::DEFAULT_WORKSPACE_PADDING; use crate::DISPLAY_INDEX_PREFERENCES; use crate::FLOATING_APPLICATIONS; @@ -557,6 +558,11 @@ pub struct StaticConfig { /// Individual window transparency ignore rules #[serde(skip_serializing_if = "Option::is_none")] pub transparency_ignore_rules: Option>, + /// Global default workspace layout for new workspaces + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg_attr(feature = "schemars", schemars(extend("default" = DefaultLayout::BSP)))] + #[serde(deserialize_with = "crate::default_layout::deserialize_option_none_default_layout")] + pub default_workspace_layout: Option, /// Global default workspace padding #[serde(skip_serializing_if = "Option::is_none")] #[cfg_attr(feature = "schemars", schemars(extend("default" = DEFAULT_WORKSPACE_PADDING)))] @@ -907,6 +913,7 @@ impl From<&WindowManager> for StaticConfig { remove_titlebar_applications: Option::from(NO_TITLEBAR.lock().clone()), floating_window_aspect_ratio: Option::from(*FLOATING_WINDOW_TOGGLE_ASPECT_RATIO.lock()), window_handling_behaviour: Option::from(WINDOW_HANDLING_BEHAVIOUR.load()), + default_workspace_layout: DEFAULT_WORKSPACE_LAYOUT.load(), } } } @@ -985,6 +992,8 @@ impl StaticConfig { DEFAULT_CONTAINER_PADDING.store(container, Ordering::SeqCst); } + DEFAULT_WORKSPACE_LAYOUT.store(self.default_workspace_layout); + if let Some(workspace) = self.default_workspace_padding { DEFAULT_WORKSPACE_PADDING.store(workspace, Ordering::SeqCst); } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index abd7228c..aec210ad 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -3876,6 +3876,7 @@ impl WindowManager { #[cfg(test)] mod tests { use super::*; + use crate::DEFAULT_WORKSPACE_LAYOUT; use crate::monitor; use crossbeam_channel::Sender; use crossbeam_channel::bounded; @@ -5202,6 +5203,7 @@ mod tests { #[test] fn test_toggle_tiling() { let (mut wm, _context) = setup_window_manager(); + DEFAULT_WORKSPACE_LAYOUT.store(Some(DefaultLayout::BSP)); { let mut m = monitor::new( diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 65c4062b..0112863c 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -8,6 +8,7 @@ use std::sync::atomic::Ordering; use crate::DATA_DIR; use crate::DEFAULT_CONTAINER_PADDING; +use crate::DEFAULT_WORKSPACE_LAYOUT; use crate::DEFAULT_WORKSPACE_PADDING; use crate::FloatingLayerBehaviour; use crate::INITIAL_CONFIGURATION_LOADED; @@ -107,6 +108,8 @@ impl_ring_elements!(Workspace, Window, "floating_window"); impl Default for Workspace { fn default() -> Self { + let default_layout = DEFAULT_WORKSPACE_LAYOUT.load(); + Self { name: None, containers: Ring::default(), @@ -115,7 +118,7 @@ impl Default for Workspace { maximized_window_restore_idx: None, monocle_container_restore_idx: None, floating_windows: Ring::default(), - layout: Layout::Default(DefaultLayout::BSP), + layout: Layout::Default(default_layout.unwrap_or(DefaultLayout::BSP)), layout_options: None, layout_rules: vec![], layout_flip: None, @@ -123,7 +126,7 @@ impl Default for Workspace { container_padding: Option::from(DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst)), latest_layout: vec![], resize_dimensions: vec![], - tile: true, + tile: default_layout.is_some(), work_area_offset: None, apply_window_based_work_area_offset: true, window_container_behaviour: None, diff --git a/schema.bar.json b/schema.bar.json index df4ab75f..1f808823 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -68,7 +68,7 @@ "null" ], "format": "float", - "default": 1.399999976158142 + "default": 1.4 }, "left_widgets": { "description": "Left side widgets (ordered left-to-right)", @@ -99,7 +99,15 @@ }, "monitor": { "description": "The monitor index or the full monitor options", - "$ref": "#/$defs/MonitorConfigOrIndex" + "anyOf": [ + { + "$ref": "#/$defs/MonitorConfigOrIndex" + }, + { + "type": "null" + } + ], + "default": 0 }, "mouse": { "description": "Options for mouse interaction on the bar", @@ -174,7 +182,6 @@ } }, "required": [ - "monitor", "left_widgets", "right_widgets" ], diff --git a/schema.json b/schema.json index 6965c6ca..0851bb28 100644 --- a/schema.json +++ b/schema.json @@ -152,6 +152,18 @@ "format": "int32", "default": 10 }, + "default_workspace_layout": { + "description": "Global default workspace layout for new workspaces", + "anyOf": [ + { + "$ref": "#/$defs/DefaultLayout" + }, + { + "type": "null" + } + ], + "default": "BSP" + }, "default_workspace_padding": { "description": "Global default workspace padding", "type": [