From 93e4d511084d481baf5415862bd78e7599508de6 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 30 Oct 2026 23:24:43 -0700 Subject: [PATCH] refactor(mac): use StaticConfig and its family of komorebi-config static_config re-exports StaticConfig, WorkspaceConfig, MonitorConfig, BorderColours, ThemeOptions, Wallpaper, AnimationsConfig and AppSpecificConfigurationPath from komorebi-config and loses their definitions, read_raw and read (about 410 lines). The inherent impl StaticConfig cannot stay in the daemon (orphan rule): apply_globals is a private trait (ApplyGlobals) and preload, postload and reload are the public extension trait StaticConfigExt (the macOS preload keeps its run_loop parameter), bodies unchanged; process_command, window_manager and main import the trait. The From conversions stay and fill the keys macOS never writes with None or Default. Verified: macOS fake-CC cargo check --locked --target aarch64-apple-darwin --workspace --all-targets: finished, 0 errors, no warnings in komorebi (tier 2). Not verified: macOS unit tests (cannot run), running komorebic. --- komorebi-for-mac/komorebi/src/main.rs | 1 + .../komorebi/src/process_command.rs | 1 + .../komorebi/src/static_config.rs | 493 ++---------------- .../komorebi/src/window_manager.rs | 1 + 4 files changed, 42 insertions(+), 454 deletions(-) diff --git a/komorebi-for-mac/komorebi/src/main.rs b/komorebi-for-mac/komorebi/src/main.rs index a967e2e1..85137d52 100644 --- a/komorebi-for-mac/komorebi/src/main.rs +++ b/komorebi-for-mac/komorebi/src/main.rs @@ -19,6 +19,7 @@ use komorebi::process_event::listen_for_events; use komorebi::reaper; use komorebi::settle; use komorebi::static_config::StaticConfig; +use komorebi::static_config::StaticConfigExt; use komorebi::theme_manager; use komorebi::window_manager::WindowManager; use komorebi::window_manager_event_listener; diff --git a/komorebi-for-mac/komorebi/src/process_command.rs b/komorebi-for-mac/komorebi/src/process_command.rs index e7bca902..5930a2ad 100644 --- a/komorebi-for-mac/komorebi/src/process_command.rs +++ b/komorebi-for-mac/komorebi/src/process_command.rs @@ -46,6 +46,7 @@ use crate::notify_subscribers; use crate::state::GlobalState; use crate::state::State; use crate::static_config::StaticConfig; +use crate::static_config::StaticConfigExt; use crate::theme_manager; use crate::window::AdhocWindow; use crate::window::RuleDebug; diff --git a/komorebi-for-mac/komorebi/src/static_config.rs b/komorebi-for-mac/komorebi/src/static_config.rs index 206145d1..5fe68137 100644 --- a/komorebi-for-mac/komorebi/src/static_config.rs +++ b/komorebi-for-mac/komorebi/src/static_config.rs @@ -25,29 +25,20 @@ use crate::animation::DEFAULT_ANIMATION_FPS; use crate::animation::PerAnimationPrefixConfig; use crate::border_manager; use crate::core::ApplicationIdentifier; -use crate::core::Axis; use crate::core::CrossBoundaryBehaviour; -use crate::core::DefaultLayout; -use crate::core::FloatingLayerBehaviour; use crate::core::Layout; -use crate::core::LayoutDefaultEntry; -use crate::core::LayoutOptions; -use crate::core::MonocleFocusBehaviour; use crate::core::MoveBehaviour; use crate::core::OperationBehaviour; use crate::core::Placement; use crate::core::Rect; use crate::core::SocketMessage; use crate::core::WindowContainerBehaviour; -use crate::core::WindowHidingPosition; use crate::core::WindowManagementBehaviour; -use crate::core::animation::AnimationStyle; use crate::core::asc::ApplicationSpecificConfiguration; use crate::core::asc::AscApplicationRulesOrSchema; use crate::core::config_generation::MatchingRule; use crate::core::config_generation::MatchingStrategy; use crate::core::config_generation::WorkspaceMatchingRule; -use crate::core::pathext::ResolvedPathBuf; use crate::current_space_id; use crate::monitor; use crate::monitor::Monitor; @@ -63,14 +54,11 @@ use color_eyre::eyre; use crossbeam_channel::Receiver; use hotwatch::EventKind; use hotwatch::Hotwatch; -use komorebi_themes::KomorebiTheme; use komorebi_themes::colour::Colour; use objc2_core_foundation::CFRetained; use objc2_core_foundation::CFRunLoop; use parking_lot::Mutex; use regex::Regex; -use serde::Deserialize; -use serde::Serialize; use std::collections::HashMap; use std::io::ErrorKind; use std::io::Write; @@ -80,172 +68,15 @@ use std::path::PathBuf; use std::sync::Arc; use std::sync::atomic::Ordering; -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -/// Border colours for different container states -/// -/// These options will have no effect if a `theme` is set -pub struct BorderColours { - /// Border colour when the container contains a single window - #[serde(skip_serializing_if = "Option::is_none")] - pub single: Option, - /// Border colour when the container contains multiple windows - #[serde(skip_serializing_if = "Option::is_none")] - pub stack: Option, - /// Border colour when the container is in monocle mode - #[serde(skip_serializing_if = "Option::is_none")] - pub monocle: Option, - /// Border colour when the container is in floating mode - #[serde(skip_serializing_if = "Option::is_none")] - pub floating: Option, - /// Border colour when the container is unfocused - #[serde(skip_serializing_if = "Option::is_none")] - pub unfocused: Option, - /// Border colour when the container is unfocused and locked - #[serde(skip_serializing_if = "Option::is_none")] - pub unfocused_locked: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -/// Theme options -pub struct ThemeOptions { - /// Specify Light or Dark variant for theme generation - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = komorebi_themes::ThemeVariant::Dark)))] - pub theme_variant: Option, - /// Border colour when the container contains a single window - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = komorebi_themes::Base16Value::Base0D)))] - pub single_border: Option, - /// Border colour when the container contains multiple windows - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = komorebi_themes::Base16Value::Base0B)))] - pub stack_border: Option, - /// Border colour when the container is in monocle mode - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = komorebi_themes::Base16Value::Base0F)))] - pub monocle_border: Option, - /// Border colour when the window is floating - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = komorebi_themes::Base16Value::Base09)))] - pub floating_border: Option, - /// Border colour when the container is unfocused - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = komorebi_themes::Base16Value::Base01)))] - pub unfocused_border: Option, - /// Border colour when the container is unfocused and locked - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = komorebi_themes::Base16Value::Base08)))] - pub unfocused_locked_border: Option, - // /// Stackbar focused tab text colour (default: Base0B) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub stackbar_focused_text: Option, - // /// Stackbar unfocused tab text colour (default: Base05) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub stackbar_unfocused_text: Option, - // /// Stackbar tab background colour (default: Base01) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub stackbar_background: Option, - /// Komorebi status bar accent - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = komorebi_themes::Base16Value::Base0D)))] - pub bar_accent: Option, -} - -#[serde_with::serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -/// Wallpaper configuration -pub struct Wallpaper { - /// Path to the wallpaper image file - #[serde_as(as = "ResolvedPathBuf")] - pub path: PathBuf, - /// Generate and apply Base16 theme for this wallpaper - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = true)))] - pub generate_theme: Option, - /// Specify theme options - #[serde(skip_serializing_if = "Option::is_none")] - pub theme_options: Option, -} - // serde_as must be before derive -#[serde_with::serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -/// Workspace configuration -pub struct WorkspaceConfig { - /// Name - pub name: String, - /// Layout - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = DefaultLayout::BSP)))] - pub layout: Option, - /// Layout-specific options - #[serde(skip_serializing_if = "Option::is_none")] - pub layout_options: Option, - /// Threshold-based layout options rules in the format of threshold => options. - /// When container count >= threshold, the highest matching threshold's options - /// fully replace the base `layout_options`. - /// This follows the same threshold logic as `layout_rules`. - #[serde(skip_serializing_if = "Option::is_none")] - pub layout_options_rules: Option>, - // /// END OF LIFE FEATURE: Custom Layout (default: None) - // #[serde(skip_serializing_if = "Option::is_none")] - // #[serde_as(as = "Option")] - // pub custom_layout: Option, - /// Layout rules in the format of threshold => layout - #[serde(skip_serializing_if = "Option::is_none")] - pub layout_rules: Option>, - /// Container padding (default: global) - #[serde(skip_serializing_if = "Option::is_none")] - pub container_padding: Option, - /// Workspace padding (default: global) - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_padding: Option, - /// Initial workspace application rules - #[serde(skip_serializing_if = "Option::is_none")] - pub initial_workspace_rules: Option>, - /// Permanent workspace application rules - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_rules: Option>, - /// Work area offset rules in the format of threshold => Rect (default: None) - #[serde(skip_serializing_if = "Option::is_none")] - pub work_area_offset_rules: Option>, - /// Workspace specific work area offset - #[serde(skip_serializing_if = "Option::is_none")] - pub work_area_offset: Option, - /// Apply this monitor's window-based work area offset - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = true)))] - pub apply_window_based_work_area_offset: Option, - /// Determine what happens when a new window is opened - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = WindowContainerBehaviour::Create)))] - pub window_container_behaviour: Option, - /// Window container behaviour rules in the format of threshold => behaviour - #[serde(skip_serializing_if = "Option::is_none")] - pub window_container_behaviour_rules: Option>, - /// Enable or disable float override, which makes it so every new window opens in floating mode - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = false)))] - pub float_override: Option, - /// Enable or disable tiling for the workspace - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = true)))] - pub tile: Option, - /// Specify an axis on which to flip the selected layout - #[serde(skip_serializing_if = "Option::is_none")] - pub layout_flip: Option, - /// Determine what happens to a new window when the Floating workspace layer is active - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = FloatingLayerBehaviour::Tile)))] - pub floating_layer_behaviour: Option, - /// Specify a wallpaper for this workspace - #[serde(skip_serializing_if = "Option::is_none")] - pub wallpaper: Option, -} +pub use komorebi_config::static_config::AnimationsConfig; +pub use komorebi_config::static_config::AppSpecificConfigurationPath; +pub use komorebi_config::static_config::BorderColours; +pub use komorebi_config::static_config::MonitorConfig; +pub use komorebi_config::static_config::StaticConfig; +pub use komorebi_config::static_config::ThemeOptions; +pub use komorebi_config::static_config::Wallpaper; +pub use komorebi_config::static_config::WorkspaceConfig; impl From<&Workspace> for WorkspaceConfig { fn from(value: &Workspace) -> Self { @@ -344,44 +175,13 @@ impl From<&Workspace> for WorkspaceConfig { layout_flip: value.layout_flip, floating_layer_behaviour: value.floating_layer_behaviour, wallpaper: None, + custom_layout: None, + custom_layout_rules: None, + initial_window_placement_rules: None, } } } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -/// Monitor configuration -pub struct MonitorConfig { - /// Workspace configurations - pub workspaces: Vec, - /// Monitor-specific work area offset - #[serde(skip_serializing_if = "Option::is_none")] - pub work_area_offset: Option, - /// Window based work area offset - #[serde(skip_serializing_if = "Option::is_none")] - pub window_based_work_area_offset: Option, - /// Open window limit after which the window based work area offset will no longer be applied - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = 1)))] - pub window_based_work_area_offset_limit: Option, - /// Container padding - #[serde(skip_serializing_if = "Option::is_none")] - pub container_padding: Option, - /// Workspace padding (default: global) - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_padding: Option, - /// Specify a wallpaper for this monitor - #[serde(skip_serializing_if = "Option::is_none")] - pub wallpaper: Option, - /// Determine what happens to a new window when the Floating workspace layer is active - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = FloatingLayerBehaviour::Tile)))] - pub floating_layer_behaviour: Option, - /// Determine which position windows should be hidden at on this monitor - #[serde(skip_serializing_if = "Option::is_none")] - pub window_hiding_position: Option, -} - impl From<&Monitor> for MonitorConfig { fn from(value: &Monitor) -> Self { let mut workspaces = vec![]; @@ -422,238 +222,6 @@ impl From<&Monitor> for MonitorConfig { } } -#[serde_with::serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -#[serde(untagged)] -/// Path(s) to application-specific configuration file(s) -pub enum AppSpecificConfigurationPath { - /// A single applications.json file - Single(#[serde_as(as = "ResolvedPathBuf")] PathBuf), - /// Multiple applications.json files - Multiple(#[serde_as(as = "Vec")] Vec), -} - -#[serde_with::serde_as] -#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -/// The `komorebi.json` static configuration file reference for komorebi for Mac `v0.1.0` -/// -/// `"$schema": "https://komorebi-for-mac.lgug2z.com/komorebi.0.1.0.schema.json"` -pub struct StaticConfig { - // /// DISCOURAGED: Minimum width for a window to be eligible for tiling - // #[serde(skip_serializing_if = "Option::is_none")] - // pub minimum_window_width: Option, - // /// DISCOURAGED: Minimum height for a window to be eligible for tiling - // #[serde(skip_serializing_if = "Option::is_none")] - // pub minimum_window_height: Option, - /// Delta to resize windows by - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = DEFAULT_RESIZE_DELTA)))] - pub resize_delta: Option, - /// Determine what happens when a new window is opened - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = WindowContainerBehaviour::Create)))] - pub window_container_behaviour: Option, - /// Enable or disable float override, which makes it so every new window opens in floating mode - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = false)))] - pub float_override: Option, - /// Determines what happens on a new window when on the `FloatingLayer` - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = FloatingLayerBehaviour::Tile)))] - pub floating_layer_behaviour: Option, - /// Determines the placement of a new window when toggling to float - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = Placement::CenterAndResize)))] - pub toggle_float_placement: Option, - /// Determines the `Placement` to be used when spawning a window on the floating layer with the - /// `FloatingLayerBehaviour` set to `FloatingLayerBehaviour::Float` - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = Placement::Center)))] - pub floating_layer_placement: Option, - /// Determines the `Placement` to be used when spawning a window with float override active - #[serde(skip_serializing_if = "Option::is_none")] - pub float_override_placement: Option, - /// Determines the `Placement` to be used when spawning a window that matches a - /// 'floating_applications' rule - #[serde(skip_serializing_if = "Option::is_none")] - pub float_rule_placement: Option, - /// Determine what happens when a window is moved across a monitor boundary - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = MoveBehaviour::Swap)))] - pub cross_monitor_move_behaviour: Option, - /// Determine what happens when an action is called on a window at a monitor boundary - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = CrossBoundaryBehaviour::Monitor)))] - pub cross_boundary_behaviour: Option, - /// Determine what happens when focusing in a direction while a monocle container is active - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = MonocleFocusBehaviour::NoOp)))] - pub monocle_focus_behaviour: Option, - /// Determine what happens when commands are sent while an unmanaged window is in the foreground - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = OperationBehaviour::Op)))] - pub unmanaged_window_operation_behaviour: Option, - /// Enable or disable mouse follows focus - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = DEFAULT_MOUSE_FOLLOWS_FOCUS)))] - pub mouse_follows_focus: Option, - /// Path to applications.json from komorebi-application-specific-configurations - #[serde(skip_serializing_if = "Option::is_none")] - pub app_specific_configuration_path: Option, - /// Width of window borders - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(alias = "active_window_border_width")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = border_manager::BORDER_WIDTH)))] - pub border_width: Option, - /// Offset of window borders - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(alias = "active_window_border_offset")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = border_manager::BORDER_OFFSET)))] - pub border_offset: Option, - /// Radius of window borders - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = border_manager::BORDER_RADIUS)))] - pub border_radius: Option, - /// Display window borders - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(alias = "active_window_border")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = border_manager::BORDER_ENABLED)))] - pub border: Option, - /// Window border colours for different container types (has no effect if a theme is defined) - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(alias = "active_window_border_colours")] - pub border_colours: Option, - // /// Active window border style (default: System) - // #[serde(skip_serializing_if = "Option::is_none")] - // #[serde(alias = "active_window_border_style")] - // pub border_style: Option, - // /// Active window border implementation (default: Komorebi) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub border_implementation: Option, - // /// Add transparency to unfocused windows (default: false) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub transparency: Option, - // /// Alpha value for unfocused window transparency [[0-255]] (default: 200) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub transparency_alpha: Option, - // /// Individual window transparency ignore rules - // #[serde(skip_serializing_if = "Option::is_none")] - // pub transparency_ignore_rules: Option>, - /// Global default workspace padding - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = DEFAULT_WORKSPACE_PADDING)))] - pub default_workspace_padding: Option, - /// Global default container padding - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = DEFAULT_CONTAINER_PADDING)))] - pub default_container_padding: Option, - /// Per-layout default options and rules, keyed by layout name. - /// Applied as fallback when a workspace does not define its own layout_options or layout_options_rules. - /// If a workspace defines either setting, all global defaults for that layout are completely replaced. - #[serde(skip_serializing_if = "Option::is_none")] - pub layout_defaults: Option>, - /// Monitor and workspace configurations - #[serde(skip_serializing_if = "Option::is_none")] - pub monitors: Option>, - // /// Which Windows signal to use when hiding windows (default: Cloak) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub window_hiding_behaviour: Option, - /// Global work area (space used for tiling) offset - #[serde(skip_serializing_if = "Option::is_none")] - pub global_work_area_offset: Option, - /// Individual window floating rules - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(alias = "float_rules")] - pub ignore_rules: Option>, - /// Individual window force-manage rules - #[serde(skip_serializing_if = "Option::is_none")] - pub manage_rules: Option>, - /// Identify applications which should be managed as floating windows - #[serde(skip_serializing_if = "Option::is_none")] - pub floating_applications: Option>, - /// Identify applications which should be managed despite not reporting titles to the system - #[serde(skip_serializing_if = "Option::is_none")] - pub titleless_applications: Option>, - /// Identify applications which use native tabs for special handling - #[serde(skip_serializing_if = "Option::is_none")] - pub tabbed_applications: Option>, - // /// Identify border overflow applications - // #[serde(skip_serializing_if = "Option::is_none")] - // pub border_overflow_applications: Option>, - // /// Identify tray and multi-window applications - // #[serde(skip_serializing_if = "Option::is_none")] - // pub tray_and_multi_window_applications: Option>, - // /// Identify applications that have the WS_EX_LAYERED extended window style - // #[serde(skip_serializing_if = "Option::is_none")] - // pub layered_applications: Option>, - // /// Identify applications that send EVENT_OBJECT_NAMECHANGE on launch (very rare) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub object_name_change_applications: Option>, - // /// Do not process EVENT_OBJECT_NAMECHANGE events as Show events for identified applications matching these title regexes - // #[serde(skip_serializing_if = "Option::is_none")] - // pub object_name_change_title_ignore_list: Option>, - // /// Set monitor index preferences - // #[serde(skip_serializing_if = "Option::is_none")] - // pub monitor_index_preferences: Option>, - /// Set display index preferences - #[serde(skip_serializing_if = "Option::is_none")] - pub display_index_preferences: Option>, - // /// Stackbar configuration options - // #[serde(skip_serializing_if = "Option::is_none")] - // pub stackbar: Option, - /// Animations configuration options - #[serde(skip_serializing_if = "Option::is_none")] - pub animation: Option, - /// Theme configuration options - /// - /// If a theme is specified, `border_colours` will have no effect - #[serde(skip_serializing_if = "Option::is_none")] - pub theme: Option, - /// Identify applications which are slow to send initial event notifications - // #[serde(skip_serializing_if = "Option::is_none")] - // pub slow_application_identifiers: Option>, - // /// How long to wait when compensating for slow applications, in milliseconds (default: 20) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub slow_application_compensation_time: Option, - // /// Komorebi status bar configuration files for multiple instances on different monitors - // // this option is a little special because it is only consumed by komorebic - // #[serde(skip_serializing_if = "Option::is_none")] - // #[serde_as(as = "Option>")] - // pub bar_configurations: Option>, - // /// HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars - // #[serde(skip_serializing_if = "Option::is_none")] - // pub remove_titlebar_applications: Option>, - /// Aspect ratio to resize with when toggling floating mode for a window - #[serde(skip_serializing_if = "Option::is_none")] - pub floating_window_aspect_ratio: Option, - // /// Which Windows API behaviour to use when manipulating windows (default: Sync) - // #[serde(skip_serializing_if = "Option::is_none")] - // pub window_handling_behaviour: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -/// Animation configuration -pub struct AnimationsConfig { - /// Enable or disable animations - #[cfg_attr(feature = "schemars", schemars(extend("default" = PerAnimationPrefixConfig::Global(false))))] - pub enabled: PerAnimationPrefixConfig, - /// Set the animation duration in ms - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = PerAnimationPrefixConfig::Global(250))))] - pub duration: Option>, - /// Set the animation style - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = PerAnimationPrefixConfig::Global(AnimationStyle::Linear))))] - pub style: Option>, - /// Set the animation FPS - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg_attr(feature = "schemars", schemars(extend("default" = DEFAULT_ANIMATION_FPS)))] - pub fps: Option, -} - // #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] // #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] // pub struct TabsConfig { @@ -809,11 +377,17 @@ impl From<&WindowManager> for StaticConfig { floating_window_aspect_ratio: Option::from(*FLOATING_WINDOW_TOGGLE_ASPECT_RATIO.lock()), // window_handling_behaviour: Option::from(WINDOW_HANDLING_BEHAVIOUR.load()), tabbed_applications: None, + ..Default::default() } } } -impl StaticConfig { +/// Applies the settings of a configuration that are not the window manager's own +trait ApplyGlobals { + fn apply_globals(&mut self) -> eyre::Result<()>; +} + +impl ApplyGlobals for StaticConfig { #[allow(clippy::cognitive_complexity, clippy::too_many_lines)] fn apply_globals(&mut self) -> eyre::Result<()> { *FLOATING_WINDOW_TOGGLE_ASPECT_RATIO.lock() = self @@ -1133,18 +707,29 @@ impl StaticConfig { Ok(()) } +} - pub fn read_raw(raw: &str) -> eyre::Result { - Ok(serde_json::from_str(raw)?) - } +/// What loading a configuration needs from the window manager: the part of `StaticConfig` +/// that cannot be an inherent impl now that the type lives in `komorebi-config`. +pub trait StaticConfigExt: Sized { + /// Makes the window manager from the file at `path`, and starts watching the file + fn preload( + path: &PathBuf, + incoming: Receiver, + unix_listener: Option, + run_loop: &CFRetained, + ) -> eyre::Result; - pub fn read(path: &PathBuf) -> eyre::Result { - let content = std::fs::read_to_string(path)?; - serde_json::from_str(&content).map_err(Into::into) - } + /// Gives the monitors of the window manager what the file says about them + fn postload(path: &PathBuf, wm: &Arc>) -> eyre::Result<()>; + /// Replaces the configuration of the window manager with the file at `path` + fn reload(path: &PathBuf, wm: &mut WindowManager) -> eyre::Result<()>; +} + +impl StaticConfigExt for StaticConfig { #[allow(clippy::too_many_lines)] - pub fn preload( + fn preload( path: &PathBuf, incoming: Receiver, unix_listener: Option, @@ -1243,7 +828,7 @@ impl StaticConfig { Ok(wm) } - pub fn postload(path: &PathBuf, wm: &Arc>) -> eyre::Result<()> { + fn postload(path: &PathBuf, wm: &Arc>) -> eyre::Result<()> { let mut value = Self::read(path)?; let mut wm = wm.lock(); @@ -1405,7 +990,7 @@ impl StaticConfig { Ok(()) } - pub fn reload(path: &PathBuf, wm: &mut WindowManager) -> eyre::Result<()> { + fn reload(path: &PathBuf, wm: &mut WindowManager) -> eyre::Result<()> { let mut value = Self::read(path)?; value.apply_globals()?; diff --git a/komorebi-for-mac/komorebi/src/window_manager.rs b/komorebi-for-mac/komorebi/src/window_manager.rs index b4442bab..3bd9cd3a 100644 --- a/komorebi-for-mac/komorebi/src/window_manager.rs +++ b/komorebi-for-mac/komorebi/src/window_manager.rs @@ -44,6 +44,7 @@ use crate::ring::Ring; use crate::settle; use crate::skylight::BatchedUpdates; use crate::static_config::StaticConfig; +use crate::static_config::StaticConfigExt; use crate::window::AdhocWindow; use crate::window::Snapping; use crate::window::Window;