feat(wm): track virtual desktop ids on state and global state

Also moved out State and GlobalState to state.rs to match the emerging
pattern in komorebi for Mac.
This commit is contained in:
LGUG2Z
2025-10-14 13:11:10 -07:00
parent 2ac1929117
commit e953715fef
9 changed files with 320 additions and 295 deletions

View File

@@ -103,7 +103,7 @@ fn process_hwnd() -> Option<isize> {
}
pub enum KomorebiEvent {
Notification(komorebi_client::Notification),
Notification(Box<komorebi_client::Notification>),
Reconnect,
}
@@ -381,7 +381,7 @@ fn main() -> color_eyre::Result<()> {
Ok(notification) => {
tracing::debug!("received notification from komorebi");
if let Err(error) = tx_gui.send(KomorebiEvent::Notification(notification)) {
if let Err(error) = tx_gui.send(KomorebiEvent::Notification(Box::new(notification))) {
tracing::error!("could not send komorebi notification update to gui thread: {error}")
}

View File

@@ -7,7 +7,6 @@ pub use komorebi::AspectRatio;
pub use komorebi::BorderColours;
pub use komorebi::Colour;
pub use komorebi::CrossBoundaryBehaviour;
pub use komorebi::GlobalState;
pub use komorebi::KomorebiTheme;
pub use komorebi::MonitorConfig;
pub use komorebi::Notification;
@@ -16,7 +15,6 @@ pub use komorebi::PredefinedAspectRatio;
pub use komorebi::Rgb;
pub use komorebi::RuleDebug;
pub use komorebi::StackbarConfig;
pub use komorebi::State;
pub use komorebi::StaticConfig;
pub use komorebi::SubscribeOptions;
pub use komorebi::TabsConfig;
@@ -68,6 +66,8 @@ pub use komorebi::core::replace_env_in_path;
pub use komorebi::monitor::Monitor;
pub use komorebi::monitor_reconciliator::MonitorNotification;
pub use komorebi::ring::Ring;
pub use komorebi::state::GlobalState;
pub use komorebi::state::State;
pub use komorebi::win32_display_data;
pub use komorebi::window::Window;
pub use komorebi::window_manager_event::WindowManagerEvent;

View File

@@ -17,6 +17,7 @@ pub mod process_movement;
pub mod reaper;
pub mod set_window_position;
pub mod stackbar_manager;
pub mod state;
pub mod static_config;
pub mod styles;
pub mod theme_manager;
@@ -70,6 +71,7 @@ use parking_lot::RwLock;
use regex::Regex;
use serde::Deserialize;
use serde::Serialize;
use state::State;
use uds_windows::UnixStream;
use which::which;
use winreg::RegKey;

View File

@@ -50,10 +50,10 @@ use komorebi::process_event::listen_for_events;
use komorebi::process_movement::listen_for_movements;
use komorebi::reaper;
use komorebi::stackbar_manager;
use komorebi::state::State;
use komorebi::static_config::StaticConfig;
use komorebi::theme_manager;
use komorebi::transparency_manager;
use komorebi::window_manager::State;
use komorebi::window_manager::WindowManager;
use komorebi::windows_api::WindowsApi;
use komorebi::winevent_listener;

View File

@@ -4,7 +4,6 @@ use crate::DISPLAY_INDEX_PREFERENCES;
use crate::DUPLICATE_MONITOR_SERIAL_IDS;
use crate::Notification;
use crate::NotificationEvent;
use crate::State;
use crate::WORKSPACE_MATCHING_RULES;
use crate::WindowManager;
use crate::WindowsApi;
@@ -15,6 +14,7 @@ use crate::monitor;
use crate::monitor::Monitor;
use crate::monitor_reconciliator::hidden::Hidden;
use crate::notify_subscribers;
use crate::state::State;
use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
use crossbeam_utils::atomic::AtomicConsume;

View File

@@ -24,7 +24,6 @@ use crate::CUSTOM_FFM;
use crate::DATA_DIR;
use crate::DISPLAY_INDEX_PREFERENCES;
use crate::FLOATING_APPLICATIONS;
use crate::GlobalState;
use crate::HIDING_BEHAVIOUR;
use crate::IGNORE_IDENTIFIERS;
use crate::INITIAL_CONFIGURATION_LOADED;
@@ -40,7 +39,6 @@ use crate::SESSION_FLOATING_APPLICATIONS;
use crate::SUBSCRIPTION_PIPES;
use crate::SUBSCRIPTION_SOCKET_OPTIONS;
use crate::SUBSCRIPTION_SOCKETS;
use crate::State;
use crate::TCP_CONNECTIONS;
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
use crate::WINDOWS_11;
@@ -81,12 +79,14 @@ use crate::notify_subscribers;
use crate::stackbar_manager;
use crate::stackbar_manager::STACKBAR_FONT_FAMILY;
use crate::stackbar_manager::STACKBAR_FONT_SIZE;
use crate::state;
use crate::state::GlobalState;
use crate::state::State;
use crate::static_config::StaticConfig;
use crate::theme_manager;
use crate::transparency_manager;
use crate::window::RuleDebug;
use crate::window::Window;
use crate::window_manager;
use crate::window_manager::WindowManager;
use crate::windows_api::WindowsApi;
use crate::winevent_listener;
@@ -1358,8 +1358,7 @@ impl WindowManager {
self.set_workspace_name(monitor_idx, workspace_idx, name.to_string())?;
}
SocketMessage::State => {
let state = match serde_json::to_string_pretty(&window_manager::State::from(&*self))
{
let state = match serde_json::to_string_pretty(&state::State::from(&*self)) {
Ok(state) => state,
Err(error) => error.to_string(),
};

View File

@@ -19,7 +19,6 @@ use crate::Layout;
use crate::Notification;
use crate::NotificationEvent;
use crate::REGEX_IDENTIFIERS;
use crate::State;
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
use crate::VirtualDesktopNotification;
use crate::Window;
@@ -29,6 +28,7 @@ use crate::border_manager::BORDER_WIDTH;
use crate::current_virtual_desktop;
use crate::notify_subscribers;
use crate::stackbar_manager;
use crate::state::State;
use crate::transparency_manager;
use crate::window::RuleDebug;
use crate::window::should_act;

306
komorebi/src/state.rs Normal file
View File

@@ -0,0 +1,306 @@
use crate::BorderColours;
use crate::BorderStyle;
use crate::CURRENT_VIRTUAL_DESKTOP;
use crate::CUSTOM_FFM;
use crate::DATA_DIR;
use crate::DISPLAY_INDEX_PREFERENCES;
use crate::DUPLICATE_MONITOR_SERIAL_IDS;
use crate::FocusFollowsMouseImplementation;
use crate::HIDING_BEHAVIOUR;
use crate::HOME_DIR;
use crate::HidingBehaviour;
use crate::IGNORE_IDENTIFIERS;
use crate::LAYERED_WHITELIST;
use crate::MANAGE_IDENTIFIERS;
use crate::MONITOR_INDEX_PREFERENCES;
use crate::MoveBehaviour;
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
use crate::OperationBehaviour;
use crate::REMOVE_TITLEBARS;
use crate::Rect;
use crate::StackbarLabel;
use crate::StackbarMode;
use crate::TRANSPARENCY_BLACKLIST;
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
use crate::WORKSPACE_MATCHING_RULES;
use crate::WindowContainerBehaviour;
use crate::WindowManager;
use crate::border_manager;
use crate::border_manager::STYLE;
use crate::config_generation::MatchingRule;
use crate::config_generation::WorkspaceMatchingRule;
use crate::monitor::Monitor;
use crate::ring::Ring;
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
use crate::stackbar_manager::STACKBAR_LABEL;
use crate::stackbar_manager::STACKBAR_MODE;
use crate::stackbar_manager::STACKBAR_TAB_BACKGROUND_COLOUR;
use crate::stackbar_manager::STACKBAR_TAB_HEIGHT;
use crate::stackbar_manager::STACKBAR_TAB_WIDTH;
use crate::stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR;
use crate::transparency_manager::TRANSPARENCY_ALPHA;
use crate::transparency_manager::TRANSPARENCY_ENABLED;
use crate::workspace::Workspace;
use komorebi_themes::colour::Colour;
use komorebi_themes::colour::Rgb;
use serde::Deserialize;
use serde::Serialize;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::path::PathBuf;
use std::sync::atomic::Ordering;
#[allow(clippy::struct_excessive_bools)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct State {
pub monitors: Ring<Monitor>,
pub monitor_usr_idx_map: HashMap<usize, usize>,
pub is_paused: bool,
pub resize_delta: i32,
pub new_window_behaviour: WindowContainerBehaviour,
pub float_override: bool,
pub cross_monitor_move_behaviour: MoveBehaviour,
pub unmanaged_window_operation_behaviour: OperationBehaviour,
pub work_area_offset: Option<Rect>,
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
pub mouse_follows_focus: bool,
pub has_pending_raise_op: bool,
pub virtual_desktop_id: Option<Vec<u8>>,
}
impl State {
pub fn has_been_modified(&self, wm: &WindowManager) -> bool {
let new = Self::from(wm);
if self.monitors != new.monitors {
return true;
}
if self.is_paused != new.is_paused {
return true;
}
if self.new_window_behaviour != new.new_window_behaviour {
return true;
}
if self.float_override != new.float_override {
return true;
}
if self.cross_monitor_move_behaviour != new.cross_monitor_move_behaviour {
return true;
}
if self.unmanaged_window_operation_behaviour != new.unmanaged_window_operation_behaviour {
return true;
}
if self.work_area_offset != new.work_area_offset {
return true;
}
if self.focus_follows_mouse != new.focus_follows_mouse {
return true;
}
if self.mouse_follows_focus != new.mouse_follows_focus {
return true;
}
if self.has_pending_raise_op != new.has_pending_raise_op {
return true;
}
false
}
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct GlobalState {
pub border_enabled: bool,
pub border_colours: BorderColours,
pub border_style: BorderStyle,
pub border_offset: i32,
pub border_width: i32,
pub stackbar_mode: StackbarMode,
pub stackbar_label: StackbarLabel,
pub stackbar_focused_text_colour: Colour,
pub stackbar_unfocused_text_colour: Colour,
pub stackbar_tab_background_colour: Colour,
pub stackbar_tab_width: i32,
pub stackbar_height: i32,
pub transparency_enabled: bool,
pub transparency_alpha: u8,
pub transparency_blacklist: Vec<MatchingRule>,
pub remove_titlebars: bool,
#[serde(alias = "float_identifiers")]
pub ignore_identifiers: Vec<MatchingRule>,
pub manage_identifiers: Vec<MatchingRule>,
pub layered_whitelist: Vec<MatchingRule>,
pub tray_and_multi_window_identifiers: Vec<MatchingRule>,
pub name_change_on_launch_identifiers: Vec<MatchingRule>,
pub monitor_index_preferences: HashMap<usize, Rect>,
pub display_index_preferences: HashMap<usize, String>,
pub ignored_duplicate_monitor_serial_ids: Vec<String>,
pub workspace_rules: Vec<WorkspaceMatchingRule>,
pub window_hiding_behaviour: HidingBehaviour,
pub configuration_dir: PathBuf,
pub data_dir: PathBuf,
pub custom_ffm: bool,
pub current_virtual_desktop_id: Option<Vec<u8>>,
}
impl Default for GlobalState {
fn default() -> Self {
Self {
border_enabled: border_manager::BORDER_ENABLED.load(Ordering::SeqCst),
border_colours: BorderColours {
single: Option::from(Colour::Rgb(Rgb::from(
border_manager::FOCUSED.load(Ordering::SeqCst),
))),
stack: Option::from(Colour::Rgb(Rgb::from(
border_manager::STACK.load(Ordering::SeqCst),
))),
monocle: Option::from(Colour::Rgb(Rgb::from(
border_manager::MONOCLE.load(Ordering::SeqCst),
))),
floating: Option::from(Colour::Rgb(Rgb::from(
border_manager::FLOATING.load(Ordering::SeqCst),
))),
unfocused: Option::from(Colour::Rgb(Rgb::from(
border_manager::UNFOCUSED.load(Ordering::SeqCst),
))),
unfocused_locked: Option::from(Colour::Rgb(Rgb::from(
border_manager::UNFOCUSED_LOCKED.load(Ordering::SeqCst),
))),
},
border_style: STYLE.load(),
border_offset: border_manager::BORDER_OFFSET.load(Ordering::SeqCst),
border_width: border_manager::BORDER_WIDTH.load(Ordering::SeqCst),
stackbar_mode: STACKBAR_MODE.load(),
stackbar_label: STACKBAR_LABEL.load(),
stackbar_focused_text_colour: Colour::Rgb(Rgb::from(
STACKBAR_FOCUSED_TEXT_COLOUR.load(Ordering::SeqCst),
)),
stackbar_unfocused_text_colour: Colour::Rgb(Rgb::from(
STACKBAR_UNFOCUSED_TEXT_COLOUR.load(Ordering::SeqCst),
)),
stackbar_tab_background_colour: Colour::Rgb(Rgb::from(
STACKBAR_TAB_BACKGROUND_COLOUR.load(Ordering::SeqCst),
)),
stackbar_tab_width: STACKBAR_TAB_WIDTH.load(Ordering::SeqCst),
stackbar_height: STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst),
transparency_enabled: TRANSPARENCY_ENABLED.load(Ordering::SeqCst),
transparency_alpha: TRANSPARENCY_ALPHA.load(Ordering::SeqCst),
transparency_blacklist: TRANSPARENCY_BLACKLIST.lock().clone(),
remove_titlebars: REMOVE_TITLEBARS.load(Ordering::SeqCst),
ignore_identifiers: IGNORE_IDENTIFIERS.lock().clone(),
manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(),
layered_whitelist: LAYERED_WHITELIST.lock().clone(),
tray_and_multi_window_identifiers: TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock().clone(),
name_change_on_launch_identifiers: OBJECT_NAME_CHANGE_ON_LAUNCH.lock().clone(),
monitor_index_preferences: MONITOR_INDEX_PREFERENCES.lock().clone(),
display_index_preferences: DISPLAY_INDEX_PREFERENCES.read().clone(),
ignored_duplicate_monitor_serial_ids: DUPLICATE_MONITOR_SERIAL_IDS.read().clone(),
workspace_rules: WORKSPACE_MATCHING_RULES.lock().clone(),
window_hiding_behaviour: *HIDING_BEHAVIOUR.lock(),
configuration_dir: HOME_DIR.clone(),
data_dir: DATA_DIR.clone(),
custom_ffm: CUSTOM_FFM.load(Ordering::SeqCst),
current_virtual_desktop_id: CURRENT_VIRTUAL_DESKTOP.lock().clone(),
}
}
}
impl From<&WindowManager> for State {
fn from(wm: &WindowManager) -> Self {
// This is used to remove any information that doesn't need to be passed on to subscribers
// or to be shown with the `komorebic state` command. Currently it is only removing the
// `workspace_config` field from every workspace, but more stripping can be added later if
// needed.
let mut stripped_monitors = Ring::default();
*stripped_monitors.elements_mut() = wm
.monitors()
.iter()
.map(|monitor| Monitor {
id: monitor.id,
name: monitor.name.clone(),
device: monitor.device.clone(),
device_id: monitor.device_id.clone(),
serial_number_id: monitor.serial_number_id.clone(),
size: monitor.size,
work_area_size: monitor.work_area_size,
work_area_offset: monitor.work_area_offset,
window_based_work_area_offset: monitor.window_based_work_area_offset,
window_based_work_area_offset_limit: monitor.window_based_work_area_offset_limit,
workspaces: {
let mut ws = Ring::default();
*ws.elements_mut() = monitor
.workspaces()
.iter()
.map(|workspace| Workspace {
name: workspace.name.clone(),
containers: workspace.containers.clone(),
monocle_container: workspace.monocle_container.clone(),
monocle_container_restore_idx: workspace.monocle_container_restore_idx,
maximized_window: workspace.maximized_window,
maximized_window_restore_idx: workspace.maximized_window_restore_idx,
floating_windows: workspace.floating_windows.clone(),
layout: workspace.layout.clone(),
layout_options: workspace.layout_options,
layout_rules: workspace.layout_rules.clone(),
layout_flip: workspace.layout_flip,
workspace_padding: workspace.workspace_padding,
container_padding: workspace.container_padding,
latest_layout: workspace.latest_layout.clone(),
resize_dimensions: workspace.resize_dimensions.clone(),
tile: workspace.tile,
work_area_offset: workspace.work_area_offset,
apply_window_based_work_area_offset: workspace
.apply_window_based_work_area_offset,
window_container_behaviour: workspace.window_container_behaviour,
window_container_behaviour_rules: workspace
.window_container_behaviour_rules
.clone(),
float_override: workspace.float_override,
layer: workspace.layer,
floating_layer_behaviour: workspace.floating_layer_behaviour,
globals: workspace.globals,
wallpaper: workspace.wallpaper.clone(),
workspace_config: None,
})
.collect::<VecDeque<_>>();
ws.focus(monitor.workspaces.focused_idx());
ws
},
last_focused_workspace: monitor.last_focused_workspace,
workspace_names: monitor.workspace_names.clone(),
container_padding: monitor.container_padding,
workspace_padding: monitor.workspace_padding,
wallpaper: monitor.wallpaper.clone(),
floating_layer_behaviour: monitor.floating_layer_behaviour,
})
.collect::<VecDeque<_>>();
stripped_monitors.focus(wm.monitors.focused_idx());
Self {
monitors: stripped_monitors,
monitor_usr_idx_map: wm.monitor_usr_idx_map.clone(),
is_paused: wm.is_paused,
work_area_offset: wm.work_area_offset,
resize_delta: wm.resize_delta,
new_window_behaviour: wm.window_management_behaviour.current_behaviour,
float_override: wm.window_management_behaviour.float_override,
cross_monitor_move_behaviour: wm.cross_monitor_move_behaviour,
focus_follows_mouse: wm.focus_follows_mouse,
mouse_follows_focus: wm.mouse_follows_focus,
has_pending_raise_op: wm.has_pending_raise_op,
unmanaged_window_operation_behaviour: wm.unmanaged_window_operation_behaviour,
virtual_desktop_id: wm.virtual_desktop_id.clone(),
}
}
}

View File

@@ -19,8 +19,6 @@ use hotwatch::EventKind;
use hotwatch::Hotwatch;
use hotwatch::notify::ErrorKind as NotifyErrorKind;
use parking_lot::Mutex;
use serde::Deserialize;
use serde::Serialize;
use uds_windows::UnixListener;
use uds_windows::UnixStream;
@@ -30,69 +28,40 @@ use crate::animation::AnimationEngine;
use crate::core::Arrangement;
use crate::core::Axis;
use crate::core::BorderImplementation;
use crate::core::BorderStyle;
use crate::core::CycleDirection;
use crate::core::DefaultLayout;
use crate::core::FocusFollowsMouseImplementation;
use crate::core::HidingBehaviour;
use crate::core::Layout;
use crate::core::MoveBehaviour;
use crate::core::OperationBehaviour;
use crate::core::OperationDirection;
use crate::core::Rect;
use crate::core::Sizing;
use crate::core::StackbarLabel;
use crate::core::WindowContainerBehaviour;
use crate::core::WindowManagementBehaviour;
use crate::core::config_generation::MatchingRule;
use crate::core::custom_layout::CustomLayout;
use crate::BorderColours;
use crate::CUSTOM_FFM;
use crate::Colour;
use crate::CrossBoundaryBehaviour;
use crate::DATA_DIR;
use crate::DISPLAY_INDEX_PREFERENCES;
use crate::DUPLICATE_MONITOR_SERIAL_IDS;
use crate::HIDING_BEHAVIOUR;
use crate::HOME_DIR;
use crate::IGNORE_IDENTIFIERS;
use crate::LAYERED_WHITELIST;
use crate::MANAGE_IDENTIFIERS;
use crate::MONITOR_INDEX_PREFERENCES;
use crate::NO_TITLEBAR;
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
use crate::REGEX_IDENTIFIERS;
use crate::REMOVE_TITLEBARS;
use crate::Rgb;
use crate::SUBSCRIPTION_SOCKETS;
use crate::TRANSPARENCY_BLACKLIST;
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
use crate::WORKSPACE_MATCHING_RULES;
use crate::border_manager;
use crate::border_manager::BORDER_OFFSET;
use crate::border_manager::BORDER_WIDTH;
use crate::border_manager::STYLE;
use crate::config_generation::WorkspaceMatchingRule;
use crate::container::Container;
use crate::core::StackbarMode;
use crate::current_virtual_desktop;
use crate::load_configuration;
use crate::monitor::Monitor;
use crate::ring::Ring;
use crate::should_act;
use crate::should_act_individual;
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
use crate::stackbar_manager::STACKBAR_LABEL;
use crate::stackbar_manager::STACKBAR_MODE;
use crate::stackbar_manager::STACKBAR_TAB_BACKGROUND_COLOUR;
use crate::stackbar_manager::STACKBAR_TAB_HEIGHT;
use crate::stackbar_manager::STACKBAR_TAB_WIDTH;
use crate::stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR;
use crate::state::State;
use crate::static_config::StaticConfig;
use crate::transparency_manager;
use crate::transparency_manager::TRANSPARENCY_ALPHA;
use crate::transparency_manager::TRANSPARENCY_ENABLED;
use crate::window::Window;
use crate::window_manager_event::WindowManagerEvent;
use crate::windows_api::WindowsApi;
@@ -125,263 +94,12 @@ pub struct WindowManager {
pub known_hwnds: HashMap<isize, (usize, usize)>,
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct State {
pub monitors: Ring<Monitor>,
pub monitor_usr_idx_map: HashMap<usize, usize>,
pub is_paused: bool,
pub resize_delta: i32,
pub new_window_behaviour: WindowContainerBehaviour,
pub float_override: bool,
pub cross_monitor_move_behaviour: MoveBehaviour,
pub unmanaged_window_operation_behaviour: OperationBehaviour,
pub work_area_offset: Option<Rect>,
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
pub mouse_follows_focus: bool,
pub has_pending_raise_op: bool,
}
impl State {
pub fn has_been_modified(&self, wm: &WindowManager) -> bool {
let new = Self::from(wm);
if self.monitors != new.monitors {
return true;
}
if self.is_paused != new.is_paused {
return true;
}
if self.new_window_behaviour != new.new_window_behaviour {
return true;
}
if self.float_override != new.float_override {
return true;
}
if self.cross_monitor_move_behaviour != new.cross_monitor_move_behaviour {
return true;
}
if self.unmanaged_window_operation_behaviour != new.unmanaged_window_operation_behaviour {
return true;
}
if self.work_area_offset != new.work_area_offset {
return true;
}
if self.focus_follows_mouse != new.focus_follows_mouse {
return true;
}
if self.mouse_follows_focus != new.mouse_follows_focus {
return true;
}
if self.has_pending_raise_op != new.has_pending_raise_op {
return true;
}
false
}
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct GlobalState {
pub border_enabled: bool,
pub border_colours: BorderColours,
pub border_style: BorderStyle,
pub border_offset: i32,
pub border_width: i32,
pub stackbar_mode: StackbarMode,
pub stackbar_label: StackbarLabel,
pub stackbar_focused_text_colour: Colour,
pub stackbar_unfocused_text_colour: Colour,
pub stackbar_tab_background_colour: Colour,
pub stackbar_tab_width: i32,
pub stackbar_height: i32,
pub transparency_enabled: bool,
pub transparency_alpha: u8,
pub transparency_blacklist: Vec<MatchingRule>,
pub remove_titlebars: bool,
#[serde(alias = "float_identifiers")]
pub ignore_identifiers: Vec<MatchingRule>,
pub manage_identifiers: Vec<MatchingRule>,
pub layered_whitelist: Vec<MatchingRule>,
pub tray_and_multi_window_identifiers: Vec<MatchingRule>,
pub name_change_on_launch_identifiers: Vec<MatchingRule>,
pub monitor_index_preferences: HashMap<usize, Rect>,
pub display_index_preferences: HashMap<usize, String>,
pub ignored_duplicate_monitor_serial_ids: Vec<String>,
pub workspace_rules: Vec<WorkspaceMatchingRule>,
pub window_hiding_behaviour: HidingBehaviour,
pub configuration_dir: PathBuf,
pub data_dir: PathBuf,
pub custom_ffm: bool,
}
impl Default for GlobalState {
fn default() -> Self {
Self {
border_enabled: border_manager::BORDER_ENABLED.load(Ordering::SeqCst),
border_colours: BorderColours {
single: Option::from(Colour::Rgb(Rgb::from(
border_manager::FOCUSED.load(Ordering::SeqCst),
))),
stack: Option::from(Colour::Rgb(Rgb::from(
border_manager::STACK.load(Ordering::SeqCst),
))),
monocle: Option::from(Colour::Rgb(Rgb::from(
border_manager::MONOCLE.load(Ordering::SeqCst),
))),
floating: Option::from(Colour::Rgb(Rgb::from(
border_manager::FLOATING.load(Ordering::SeqCst),
))),
unfocused: Option::from(Colour::Rgb(Rgb::from(
border_manager::UNFOCUSED.load(Ordering::SeqCst),
))),
unfocused_locked: Option::from(Colour::Rgb(Rgb::from(
border_manager::UNFOCUSED_LOCKED.load(Ordering::SeqCst),
))),
},
border_style: STYLE.load(),
border_offset: border_manager::BORDER_OFFSET.load(Ordering::SeqCst),
border_width: border_manager::BORDER_WIDTH.load(Ordering::SeqCst),
stackbar_mode: STACKBAR_MODE.load(),
stackbar_label: STACKBAR_LABEL.load(),
stackbar_focused_text_colour: Colour::Rgb(Rgb::from(
STACKBAR_FOCUSED_TEXT_COLOUR.load(Ordering::SeqCst),
)),
stackbar_unfocused_text_colour: Colour::Rgb(Rgb::from(
STACKBAR_UNFOCUSED_TEXT_COLOUR.load(Ordering::SeqCst),
)),
stackbar_tab_background_colour: Colour::Rgb(Rgb::from(
STACKBAR_TAB_BACKGROUND_COLOUR.load(Ordering::SeqCst),
)),
stackbar_tab_width: STACKBAR_TAB_WIDTH.load(Ordering::SeqCst),
stackbar_height: STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst),
transparency_enabled: TRANSPARENCY_ENABLED.load(Ordering::SeqCst),
transparency_alpha: TRANSPARENCY_ALPHA.load(Ordering::SeqCst),
transparency_blacklist: TRANSPARENCY_BLACKLIST.lock().clone(),
remove_titlebars: REMOVE_TITLEBARS.load(Ordering::SeqCst),
ignore_identifiers: IGNORE_IDENTIFIERS.lock().clone(),
manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(),
layered_whitelist: LAYERED_WHITELIST.lock().clone(),
tray_and_multi_window_identifiers: TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock().clone(),
name_change_on_launch_identifiers: OBJECT_NAME_CHANGE_ON_LAUNCH.lock().clone(),
monitor_index_preferences: MONITOR_INDEX_PREFERENCES.lock().clone(),
display_index_preferences: DISPLAY_INDEX_PREFERENCES.read().clone(),
ignored_duplicate_monitor_serial_ids: DUPLICATE_MONITOR_SERIAL_IDS.read().clone(),
workspace_rules: WORKSPACE_MATCHING_RULES.lock().clone(),
window_hiding_behaviour: *HIDING_BEHAVIOUR.lock(),
configuration_dir: HOME_DIR.clone(),
data_dir: DATA_DIR.clone(),
custom_ffm: CUSTOM_FFM.load(Ordering::SeqCst),
}
}
}
impl AsRef<Self> for WindowManager {
fn as_ref(&self) -> &Self {
self
}
}
impl From<&WindowManager> for State {
fn from(wm: &WindowManager) -> Self {
// This is used to remove any information that doesn't need to be passed on to subscribers
// or to be shown with the `komorebic state` command. Currently it is only removing the
// `workspace_config` field from every workspace, but more stripping can be added later if
// needed.
let mut stripped_monitors = Ring::default();
*stripped_monitors.elements_mut() = wm
.monitors()
.iter()
.map(|monitor| Monitor {
id: monitor.id,
name: monitor.name.clone(),
device: monitor.device.clone(),
device_id: monitor.device_id.clone(),
serial_number_id: monitor.serial_number_id.clone(),
size: monitor.size,
work_area_size: monitor.work_area_size,
work_area_offset: monitor.work_area_offset,
window_based_work_area_offset: monitor.window_based_work_area_offset,
window_based_work_area_offset_limit: monitor.window_based_work_area_offset_limit,
workspaces: {
let mut ws = Ring::default();
*ws.elements_mut() = monitor
.workspaces()
.iter()
.map(|workspace| Workspace {
name: workspace.name.clone(),
containers: workspace.containers.clone(),
monocle_container: workspace.monocle_container.clone(),
monocle_container_restore_idx: workspace.monocle_container_restore_idx,
maximized_window: workspace.maximized_window,
maximized_window_restore_idx: workspace.maximized_window_restore_idx,
floating_windows: workspace.floating_windows.clone(),
layout: workspace.layout.clone(),
layout_options: workspace.layout_options,
layout_rules: workspace.layout_rules.clone(),
layout_flip: workspace.layout_flip,
workspace_padding: workspace.workspace_padding,
container_padding: workspace.container_padding,
latest_layout: workspace.latest_layout.clone(),
resize_dimensions: workspace.resize_dimensions.clone(),
tile: workspace.tile,
work_area_offset: workspace.work_area_offset,
apply_window_based_work_area_offset: workspace
.apply_window_based_work_area_offset,
window_container_behaviour: workspace.window_container_behaviour,
window_container_behaviour_rules: workspace
.window_container_behaviour_rules
.clone(),
float_override: workspace.float_override,
layer: workspace.layer,
floating_layer_behaviour: workspace.floating_layer_behaviour,
globals: workspace.globals,
wallpaper: workspace.wallpaper.clone(),
workspace_config: None,
})
.collect::<VecDeque<_>>();
ws.focus(monitor.workspaces.focused_idx());
ws
},
last_focused_workspace: monitor.last_focused_workspace,
workspace_names: monitor.workspace_names.clone(),
container_padding: monitor.container_padding,
workspace_padding: monitor.workspace_padding,
wallpaper: monitor.wallpaper.clone(),
floating_layer_behaviour: monitor.floating_layer_behaviour,
})
.collect::<VecDeque<_>>();
stripped_monitors.focus(wm.monitors.focused_idx());
Self {
monitors: stripped_monitors,
monitor_usr_idx_map: wm.monitor_usr_idx_map.clone(),
is_paused: wm.is_paused,
work_area_offset: wm.work_area_offset,
resize_delta: wm.resize_delta,
new_window_behaviour: wm.window_management_behaviour.current_behaviour,
float_override: wm.window_management_behaviour.float_override,
cross_monitor_move_behaviour: wm.cross_monitor_move_behaviour,
focus_follows_mouse: wm.focus_follows_mouse,
mouse_follows_focus: wm.mouse_follows_focus,
has_pending_raise_op: wm.has_pending_raise_op,
unmanaged_window_operation_behaviour: wm.unmanaged_window_operation_behaviour,
}
}
}
impl_ring_elements!(WindowManager, Monitor);
#[derive(Debug, Clone, Copy)]