mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-14 04:43:42 +01:00
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.
This commit is contained in:
1 parent
857e14320e
commit
93e4d51108
4 files changed
+42
-454
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Colour>,
|
||||
/// Border colour when the container contains multiple windows
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stack: Option<Colour>,
|
||||
/// Border colour when the container is in monocle mode
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub monocle: Option<Colour>,
|
||||
/// Border colour when the container is in floating mode
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub floating: Option<Colour>,
|
||||
/// Border colour when the container is unfocused
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unfocused: Option<Colour>,
|
||||
/// Border colour when the container is unfocused and locked
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unfocused_locked: Option<Colour>,
|
||||
}
|
||||
|
||||
#[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<komorebi_themes::ThemeVariant>,
|
||||
/// 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<komorebi_themes::Base16Value>,
|
||||
/// 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<komorebi_themes::Base16Value>,
|
||||
/// 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<komorebi_themes::Base16Value>,
|
||||
/// 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<komorebi_themes::Base16Value>,
|
||||
/// 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<komorebi_themes::Base16Value>,
|
||||
/// 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<komorebi_themes::Base16Value>,
|
||||
// /// Stackbar focused tab text colour (default: Base0B)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub stackbar_focused_text: Option<komorebi_themes::Base16Value>,
|
||||
// /// Stackbar unfocused tab text colour (default: Base05)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub stackbar_unfocused_text: Option<komorebi_themes::Base16Value>,
|
||||
// /// Stackbar tab background colour (default: Base01)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub stackbar_background: Option<komorebi_themes::Base16Value>,
|
||||
/// 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<komorebi_themes::Base16Value>,
|
||||
}
|
||||
|
||||
#[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<bool>,
|
||||
/// Specify theme options
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub theme_options: Option<ThemeOptions>,
|
||||
}
|
||||
|
||||
// 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<DefaultLayout>,
|
||||
/// Layout-specific options
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub layout_options: Option<LayoutOptions>,
|
||||
/// 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<HashMap<usize, LayoutOptions>>,
|
||||
// /// END OF LIFE FEATURE: Custom Layout (default: None)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// #[serde_as(as = "Option<ResolvedPathBuf>")]
|
||||
// pub custom_layout: Option<PathBuf>,
|
||||
/// Layout rules in the format of threshold => layout
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub layout_rules: Option<HashMap<usize, DefaultLayout>>,
|
||||
/// Container padding (default: global)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub container_padding: Option<i32>,
|
||||
/// Workspace padding (default: global)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub workspace_padding: Option<i32>,
|
||||
/// Initial workspace application rules
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub initial_workspace_rules: Option<Vec<MatchingRule>>,
|
||||
/// Permanent workspace application rules
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub workspace_rules: Option<Vec<MatchingRule>>,
|
||||
/// 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<HashMap<usize, Rect>>,
|
||||
/// Workspace specific work area offset
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub work_area_offset: Option<Rect>,
|
||||
/// 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<bool>,
|
||||
/// 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<WindowContainerBehaviour>,
|
||||
/// Window container behaviour rules in the format of threshold => behaviour
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub window_container_behaviour_rules: Option<HashMap<usize, WindowContainerBehaviour>>,
|
||||
/// 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<bool>,
|
||||
/// 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<bool>,
|
||||
/// Specify an axis on which to flip the selected layout
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub layout_flip: Option<Axis>,
|
||||
/// 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<FloatingLayerBehaviour>,
|
||||
/// Specify a wallpaper for this workspace
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub wallpaper: Option<Wallpaper>,
|
||||
}
|
||||
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<WorkspaceConfig>,
|
||||
/// Monitor-specific work area offset
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub work_area_offset: Option<Rect>,
|
||||
/// Window based work area offset
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub window_based_work_area_offset: Option<Rect>,
|
||||
/// 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<isize>,
|
||||
/// Container padding
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub container_padding: Option<i32>,
|
||||
/// Workspace padding (default: global)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub workspace_padding: Option<i32>,
|
||||
/// Specify a wallpaper for this monitor
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub wallpaper: Option<Wallpaper>,
|
||||
/// 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<FloatingLayerBehaviour>,
|
||||
/// Determine which position windows should be hidden at on this monitor
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub window_hiding_position: Option<WindowHidingPosition>,
|
||||
}
|
||||
|
||||
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<ResolvedPathBuf>")] Vec<PathBuf>),
|
||||
}
|
||||
|
||||
#[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<i32>,
|
||||
// /// DISCOURAGED: Minimum height for a window to be eligible for tiling
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub minimum_window_height: Option<i32>,
|
||||
/// 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<i32>,
|
||||
/// 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<WindowContainerBehaviour>,
|
||||
/// 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<bool>,
|
||||
/// 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<FloatingLayerBehaviour>,
|
||||
/// 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<Placement>,
|
||||
/// 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<Placement>,
|
||||
/// 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<Placement>,
|
||||
/// 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<Placement>,
|
||||
/// 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<MoveBehaviour>,
|
||||
/// 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<CrossBoundaryBehaviour>,
|
||||
/// 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<MonocleFocusBehaviour>,
|
||||
/// 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<OperationBehaviour>,
|
||||
/// 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<bool>,
|
||||
/// Path to applications.json from komorebi-application-specific-configurations
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub app_specific_configuration_path: Option<AppSpecificConfigurationPath>,
|
||||
/// 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<i32>,
|
||||
/// 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<i32>,
|
||||
/// 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<i32>,
|
||||
/// 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<bool>,
|
||||
/// 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<BorderColours>,
|
||||
// /// Active window border style (default: System)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// #[serde(alias = "active_window_border_style")]
|
||||
// pub border_style: Option<BorderStyle>,
|
||||
// /// Active window border implementation (default: Komorebi)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub border_implementation: Option<BorderImplementation>,
|
||||
// /// Add transparency to unfocused windows (default: false)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub transparency: Option<bool>,
|
||||
// /// Alpha value for unfocused window transparency [[0-255]] (default: 200)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub transparency_alpha: Option<u8>,
|
||||
// /// Individual window transparency ignore rules
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub transparency_ignore_rules: Option<Vec<MatchingRule>>,
|
||||
/// 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<i32>,
|
||||
/// 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<i32>,
|
||||
/// 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<HashMap<DefaultLayout, LayoutDefaultEntry>>,
|
||||
/// Monitor and workspace configurations
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub monitors: Option<Vec<MonitorConfig>>,
|
||||
// /// Which Windows signal to use when hiding windows (default: Cloak)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub window_hiding_behaviour: Option<HidingBehaviour>,
|
||||
/// Global work area (space used for tiling) offset
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub global_work_area_offset: Option<Rect>,
|
||||
/// Individual window floating rules
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(alias = "float_rules")]
|
||||
pub ignore_rules: Option<Vec<MatchingRule>>,
|
||||
/// Individual window force-manage rules
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub manage_rules: Option<Vec<MatchingRule>>,
|
||||
/// Identify applications which should be managed as floating windows
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub floating_applications: Option<Vec<MatchingRule>>,
|
||||
/// Identify applications which should be managed despite not reporting titles to the system
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub titleless_applications: Option<Vec<String>>,
|
||||
/// Identify applications which use native tabs for special handling
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tabbed_applications: Option<Vec<String>>,
|
||||
// /// Identify border overflow applications
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub border_overflow_applications: Option<Vec<MatchingRule>>,
|
||||
// /// Identify tray and multi-window applications
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub tray_and_multi_window_applications: Option<Vec<MatchingRule>>,
|
||||
// /// Identify applications that have the WS_EX_LAYERED extended window style
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub layered_applications: Option<Vec<MatchingRule>>,
|
||||
// /// Identify applications that send EVENT_OBJECT_NAMECHANGE on launch (very rare)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub object_name_change_applications: Option<Vec<MatchingRule>>,
|
||||
// /// 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<Vec<String>>,
|
||||
// /// Set monitor index preferences
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub monitor_index_preferences: Option<HashMap<usize, Rect>>,
|
||||
/// Set display index preferences
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub display_index_preferences: Option<HashMap<usize, String>>,
|
||||
// /// Stackbar configuration options
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub stackbar: Option<StackbarConfig>,
|
||||
/// Animations configuration options
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub animation: Option<AnimationsConfig>,
|
||||
/// Theme configuration options
|
||||
///
|
||||
/// If a theme is specified, `border_colours` will have no effect
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub theme: Option<KomorebiTheme>,
|
||||
/// Identify applications which are slow to send initial event notifications
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub slow_application_identifiers: Option<Vec<MatchingRule>>,
|
||||
// /// 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<u64>,
|
||||
// /// 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<Vec<ResolvedPathBuf>>")]
|
||||
// pub bar_configurations: Option<Vec<PathBuf>>,
|
||||
// /// HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub remove_titlebar_applications: Option<Vec<MatchingRule>>,
|
||||
/// 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<AspectRatio>,
|
||||
// /// Which Windows API behaviour to use when manipulating windows (default: Sync)
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// pub window_handling_behaviour: Option<WindowHandlingBehaviour>,
|
||||
}
|
||||
|
||||
#[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<bool>,
|
||||
/// 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<PerAnimationPrefixConfig<u64>>,
|
||||
/// 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<PerAnimationPrefixConfig<AnimationStyle>>,
|
||||
/// Set the animation FPS
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[cfg_attr(feature = "schemars", schemars(extend("default" = DEFAULT_ANIMATION_FPS)))]
|
||||
pub fps: Option<u64>,
|
||||
}
|
||||
|
||||
// #[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<Self> {
|
||||
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<WindowManagerEvent>,
|
||||
unix_listener: Option<UnixListener>,
|
||||
run_loop: &CFRetained<CFRunLoop>,
|
||||
) -> eyre::Result<WindowManager>;
|
||||
|
||||
pub fn read(path: &PathBuf) -> eyre::Result<Self> {
|
||||
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<Mutex<WindowManager>>) -> 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<WindowManagerEvent>,
|
||||
unix_listener: Option<UnixListener>,
|
||||
@@ -1243,7 +828,7 @@ impl StaticConfig {
|
||||
Ok(wm)
|
||||
}
|
||||
|
||||
pub fn postload(path: &PathBuf, wm: &Arc<Mutex<WindowManager>>) -> eyre::Result<()> {
|
||||
fn postload(path: &PathBuf, wm: &Arc<Mutex<WindowManager>>) -> 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()?;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user