Compare commits

...

6 Commits

Author SHA1 Message Date
dependabot[bot] ccb39abd2e chore(deps): bump starship-battery from 0.10.3 to 0.11.0
Bumps [starship-battery](https://github.com/starship/rust-battery) from 0.10.3 to 0.11.0.
- [Release notes](https://github.com/starship/rust-battery/releases)
- [Changelog](https://github.com/starship/rust-battery/blob/main/CHANGELOG.md)
- [Commits](https://github.com/starship/rust-battery/compare/v0.10.3...v0.11.0)

---
updated-dependencies:
- dependency-name: starship-battery
  dependency-version: 0.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-25 16:12:27 -07:00
dependabot[bot] f22fb8086c chore(deps): bump nanoid from 0.4.0 to 0.5.0
Bumps [nanoid](https://github.com/mrdimidium/nanoid) from 0.4.0 to 0.5.0.
- [Changelog](https://github.com/mrdimidium/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mrdimidium/nanoid/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-version: 0.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-25 16:11:37 -07:00
LGUG2Z 538053c9c8 chore(deps): cargo update 2026-06-24 14:58:47 -07:00
ChinhLee 57b93a7404 fix(wm): verify foreground state before mutating focus state
As a defense-in-depth fix independent of the event-conversion layer, the
WindowManagerEvent::FocusChange handler should not update the focused
monitor/workspace/container/window state when the incoming window is not
the actual OS foreground window.

The issue notes that after a monitor switch komorebi focuses "the last
window focused from monitor 1" while the popout window on the other
monitor still receives input.

This is exactly the symptom of komorebi processing a stale/background
focus event and re-pointing its selection at monitor 1 even though real
focus is elsewhere. Verifying foreground state before mutating focus
state prevents the desync regardless of which win-event produced the
FocusChange.

fix #1679

Signed-off-by: ChinhLee <76194645+chinhkrb113@users.noreply.github.com>
2026-06-24 14:55:43 -07:00
LGUG2Z a3b2e28dd5 feat(animations): set the ghost_movement default to false
There are a bunch of edge cases coming up with this behaviour. Setting
the default to false for now so people on the nightly can opt in as they
feel comfortable.
2026-05-04 19:09:28 -07:00
LGUG2Z 4e7d0e337c feat(wm): add monocle_focus_behaviour to gate monocle cycling
5f629e1f made directional focus cycle the monocle container in the
underlying ring. Useful on a single monitor, but undesired when focusing
across monitors — the focus stays trapped on the monocle workspace
instead of crossing the boundary.

This commit adds a new top-level monocle_focus_behaviour option with two
variants, Cycle (the post-5f629e1f behaviour) and NoOp (the pre-5f629e1f
behaviour, now the default), along with a ToggleMonocleFocusBehaviour
socket message and corresponding komorebic subcommands to flip between
them at runtime.
2026-05-04 19:09:27 -07:00
12 changed files with 461 additions and 508 deletions
Generated
+355 -498
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -34,7 +34,7 @@ reqwest = { version = "0.12", features = ["blocking"] }
schemars = { workspace = true, optional = true } schemars = { workspace = true, optional = true }
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
starship-battery = "0.10" starship-battery = "0.11"
sysinfo = { workspace = true } sysinfo = { workspace = true }
systray-util = "0.2.0" systray-util = "0.2.0"
tokio = { version = "1", features = ["rt", "sync", "time"] } tokio = { version = "1", features = ["rt", "sync", "time"] }
+1
View File
@@ -57,6 +57,7 @@ pub use komorebi::core::FloatingLayerBehaviour;
pub use komorebi::core::FocusFollowsMouseImplementation; pub use komorebi::core::FocusFollowsMouseImplementation;
pub use komorebi::core::HidingBehaviour; pub use komorebi::core::HidingBehaviour;
pub use komorebi::core::Layout; pub use komorebi::core::Layout;
pub use komorebi::core::MonocleFocusBehaviour;
pub use komorebi::core::MoveBehaviour; pub use komorebi::core::MoveBehaviour;
pub use komorebi::core::OperationBehaviour; pub use komorebi::core::OperationBehaviour;
pub use komorebi::core::OperationDirection; pub use komorebi::core::OperationDirection;
+1 -1
View File
@@ -24,7 +24,7 @@ ed25519-dalek = "2"
hotwatch = { workspace = true } hotwatch = { workspace = true }
lazy_static = { workspace = true } lazy_static = { workspace = true }
miow = "0.6" miow = "0.6"
nanoid = "0.4" nanoid = "0.5"
net2 = "0.2" net2 = "0.2"
os_info = "3.10" os_info = "3.10"
parking_lot = { workspace = true } parking_lot = { workspace = true }
+1 -1
View File
@@ -60,7 +60,7 @@ pub const DEFAULT_ANIMATION_ENABLED: bool = false;
pub const DEFAULT_ANIMATION_STYLE: AnimationStyle = AnimationStyle::Linear; pub const DEFAULT_ANIMATION_STYLE: AnimationStyle = AnimationStyle::Linear;
pub const DEFAULT_ANIMATION_DURATION: u64 = 250; pub const DEFAULT_ANIMATION_DURATION: u64 = 250;
pub const DEFAULT_ANIMATION_FPS: u64 = 60; pub const DEFAULT_ANIMATION_FPS: u64 = 60;
pub const DEFAULT_GHOST_MOVEMENT: bool = true; pub const DEFAULT_GHOST_MOVEMENT: bool = false;
lazy_static! { lazy_static! {
pub static ref ANIMATION_MANAGER: Arc<Mutex<AnimationManager>> = pub static ref ANIMATION_MANAGER: Arc<Mutex<AnimationManager>> =
+15
View File
@@ -113,6 +113,8 @@ pub enum SocketMessage {
WindowHidingBehaviour(HidingBehaviour), WindowHidingBehaviour(HidingBehaviour),
ToggleCrossMonitorMoveBehaviour, ToggleCrossMonitorMoveBehaviour,
CrossMonitorMoveBehaviour(MoveBehaviour), CrossMonitorMoveBehaviour(MoveBehaviour),
ToggleMonocleFocusBehaviour,
MonocleFocusBehaviour(MonocleFocusBehaviour),
UnmanagedWindowOperationBehaviour(OperationBehaviour), UnmanagedWindowOperationBehaviour(OperationBehaviour),
// Current Workspace Commands // Current Workspace Commands
ManageFocusedWindow, ManageFocusedWindow,
@@ -530,6 +532,19 @@ pub enum CrossBoundaryBehaviour {
Monitor, Monitor,
} }
#[derive(
Clone, Copy, Debug, Default, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
/// Behaviour when focusing in a direction while a monocle container is active
pub enum MonocleFocusBehaviour {
/// Cycle the monocle container to the next/previous container in the workspace
Cycle,
/// Do nothing, allowing focus to fall through to cross-monitor logic
#[default]
NoOp,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq)] #[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
/// Window hiding behaviour /// Window hiding behaviour
+10
View File
@@ -61,6 +61,7 @@ use crate::core::BorderImplementation;
use crate::core::FocusFollowsMouseImplementation; use crate::core::FocusFollowsMouseImplementation;
use crate::core::Layout; use crate::core::Layout;
use crate::core::LayoutOptions; use crate::core::LayoutOptions;
use crate::core::MonocleFocusBehaviour;
use crate::core::MoveBehaviour; use crate::core::MoveBehaviour;
use crate::core::OperationDirection; use crate::core::OperationDirection;
use crate::core::Rect; use crate::core::Rect;
@@ -2068,6 +2069,15 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
SocketMessage::CrossMonitorMoveBehaviour(behaviour) => { SocketMessage::CrossMonitorMoveBehaviour(behaviour) => {
self.cross_monitor_move_behaviour = behaviour; self.cross_monitor_move_behaviour = behaviour;
} }
SocketMessage::ToggleMonocleFocusBehaviour => {
self.monocle_focus_behaviour = match self.monocle_focus_behaviour {
MonocleFocusBehaviour::Cycle => MonocleFocusBehaviour::NoOp,
MonocleFocusBehaviour::NoOp => MonocleFocusBehaviour::Cycle,
};
}
SocketMessage::MonocleFocusBehaviour(behaviour) => {
self.monocle_focus_behaviour = behaviour;
}
SocketMessage::UnmanagedWindowOperationBehaviour(behaviour) => { SocketMessage::UnmanagedWindowOperationBehaviour(behaviour) => {
self.unmanaged_window_operation_behaviour = behaviour; self.unmanaged_window_operation_behaviour = behaviour;
} }
+31
View File
@@ -41,6 +41,30 @@ use crate::windows_api::WindowsApi;
use crate::winevent::WinEvent; use crate::winevent::WinEvent;
use crate::workspace::WorkspaceLayer; use crate::workspace::WorkspaceLayer;
fn should_skip_focus_change(foreground_hwnd: Option<isize>, window_hwnd: isize) -> bool {
matches!(foreground_hwnd, Some(hwnd) if hwnd != window_hwnd)
}
#[cfg(test)]
mod focus_change_tests {
use super::should_skip_focus_change;
#[test]
fn skips_focus_change_from_background_window() {
assert!(should_skip_focus_change(Some(1), 2));
}
#[test]
fn allows_focus_change_for_foreground_window() {
assert!(!should_skip_focus_change(Some(1), 1));
}
#[test]
fn allows_focus_change_when_foreground_unknown() {
assert!(!should_skip_focus_change(None, 1));
}
}
#[tracing::instrument] #[tracing::instrument]
pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) { pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
let receiver = wm.lock().incoming_events.clone(); let receiver = wm.lock().incoming_events.clone();
@@ -341,6 +365,13 @@ impl WindowManager {
already_moved_window_handles.remove(&window.hwnd); already_moved_window_handles.remove(&window.hwnd);
} }
WindowManagerEvent::FocusChange(_, window) => { WindowManagerEvent::FocusChange(_, window) => {
if should_skip_focus_change(WindowsApi::foreground_window().ok(), window.hwnd) {
tracing::debug!(
"ignoring stale focus change for hwnd {} as it is not the foreground window",
window.hwnd
);
return Ok(());
}
// don't want to trigger the full workspace updates when there are no managed // don't want to trigger the full workspace updates when there are no managed
// containers - this makes floating windows on empty workspaces go into very // containers - this makes floating windows on empty workspaces go into very
// annoying focus change loops which prevents users from interacting with them // annoying focus change loops which prevents users from interacting with them
+7
View File
@@ -13,6 +13,7 @@ use crate::IGNORE_IDENTIFIERS;
use crate::LAYERED_WHITELIST; use crate::LAYERED_WHITELIST;
use crate::MANAGE_IDENTIFIERS; use crate::MANAGE_IDENTIFIERS;
use crate::MONITOR_INDEX_PREFERENCES; use crate::MONITOR_INDEX_PREFERENCES;
use crate::MonocleFocusBehaviour;
use crate::MoveBehaviour; use crate::MoveBehaviour;
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH; use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
use crate::OperationBehaviour; use crate::OperationBehaviour;
@@ -61,6 +62,7 @@ pub struct State {
pub new_window_behaviour: WindowContainerBehaviour, pub new_window_behaviour: WindowContainerBehaviour,
pub float_override: bool, pub float_override: bool,
pub cross_monitor_move_behaviour: MoveBehaviour, pub cross_monitor_move_behaviour: MoveBehaviour,
pub monocle_focus_behaviour: MonocleFocusBehaviour,
pub unmanaged_window_operation_behaviour: OperationBehaviour, pub unmanaged_window_operation_behaviour: OperationBehaviour,
pub work_area_offset: Option<Rect>, pub work_area_offset: Option<Rect>,
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>, pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
@@ -93,6 +95,10 @@ impl State {
return true; return true;
} }
if self.monocle_focus_behaviour != new.monocle_focus_behaviour {
return true;
}
if self.unmanaged_window_operation_behaviour != new.unmanaged_window_operation_behaviour { if self.unmanaged_window_operation_behaviour != new.unmanaged_window_operation_behaviour {
return true; return true;
} }
@@ -301,6 +307,7 @@ impl From<&WindowManager> for State {
new_window_behaviour: wm.window_management_behaviour.current_behaviour, new_window_behaviour: wm.window_management_behaviour.current_behaviour,
float_override: wm.window_management_behaviour.float_override, float_override: wm.window_management_behaviour.float_override,
cross_monitor_move_behaviour: wm.cross_monitor_move_behaviour, cross_monitor_move_behaviour: wm.cross_monitor_move_behaviour,
monocle_focus_behaviour: wm.monocle_focus_behaviour,
focus_follows_mouse: wm.focus_follows_mouse, focus_follows_mouse: wm.focus_follows_mouse,
mouse_follows_focus: wm.mouse_follows_focus, mouse_follows_focus: wm.mouse_follows_focus,
has_pending_raise_op: wm.has_pending_raise_op, has_pending_raise_op: wm.has_pending_raise_op,
+9 -1
View File
@@ -58,6 +58,7 @@ use crate::core::HidingBehaviour;
use crate::core::Layout; use crate::core::Layout;
use crate::core::LayoutDefaultEntry; use crate::core::LayoutDefaultEntry;
use crate::core::LayoutOptions; use crate::core::LayoutOptions;
use crate::core::MonocleFocusBehaviour;
use crate::core::MoveBehaviour; use crate::core::MoveBehaviour;
use crate::core::OperationBehaviour; use crate::core::OperationBehaviour;
use crate::core::Rect; use crate::core::Rect;
@@ -529,6 +530,10 @@ pub struct StaticConfig {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "schemars", schemars(extend("default" = CrossBoundaryBehaviour::Monitor)))] #[cfg_attr(feature = "schemars", schemars(extend("default" = CrossBoundaryBehaviour::Monitor)))]
pub cross_boundary_behaviour: Option<CrossBoundaryBehaviour>, 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 /// Determine what happens when commands are sent while an unmanaged window is in the foreground
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "schemars", schemars(extend("default" = OperationBehaviour::Op)))] #[cfg_attr(feature = "schemars", schemars(extend("default" = OperationBehaviour::Op)))]
@@ -700,7 +705,7 @@ pub struct AnimationsConfig {
/// Render movement animations on a GPU-composited ghost surface (recommended). /// Render movement animations on a GPU-composited ghost surface (recommended).
/// When false, falls back to the legacy per-frame MoveWindow path. /// When false, falls back to the legacy per-frame MoveWindow path.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "schemars", schemars(extend("default" = true)))] #[cfg_attr(feature = "schemars", schemars(extend("default" = false)))]
pub ghost_movement: Option<bool>, pub ghost_movement: Option<bool>,
} }
@@ -886,6 +891,7 @@ impl From<&WindowManager> for StaticConfig {
), ),
cross_monitor_move_behaviour: Option::from(value.cross_monitor_move_behaviour), cross_monitor_move_behaviour: Option::from(value.cross_monitor_move_behaviour),
cross_boundary_behaviour: Option::from(value.cross_boundary_behaviour), cross_boundary_behaviour: Option::from(value.cross_boundary_behaviour),
monocle_focus_behaviour: Option::from(value.monocle_focus_behaviour),
unmanaged_window_operation_behaviour: Option::from( unmanaged_window_operation_behaviour: Option::from(
value.unmanaged_window_operation_behaviour, value.unmanaged_window_operation_behaviour,
), ),
@@ -1348,6 +1354,7 @@ impl StaticConfig {
cross_boundary_behaviour: value cross_boundary_behaviour: value
.cross_boundary_behaviour .cross_boundary_behaviour
.unwrap_or(CrossBoundaryBehaviour::Monitor), .unwrap_or(CrossBoundaryBehaviour::Monitor),
monocle_focus_behaviour: value.monocle_focus_behaviour.unwrap_or_default(),
unmanaged_window_operation_behaviour: value unmanaged_window_operation_behaviour: value
.unmanaged_window_operation_behaviour .unmanaged_window_operation_behaviour
.unwrap_or(OperationBehaviour::Op), .unwrap_or(OperationBehaviour::Op),
@@ -1749,6 +1756,7 @@ impl StaticConfig {
value.float_rule_placement.unwrap_or(Placement::None); value.float_rule_placement.unwrap_or(Placement::None);
wm.cross_monitor_move_behaviour = value.cross_monitor_move_behaviour.unwrap_or_default(); wm.cross_monitor_move_behaviour = value.cross_monitor_move_behaviour.unwrap_or_default();
wm.cross_boundary_behaviour = value.cross_boundary_behaviour.unwrap_or_default(); wm.cross_boundary_behaviour = value.cross_boundary_behaviour.unwrap_or_default();
wm.monocle_focus_behaviour = value.monocle_focus_behaviour.unwrap_or_default();
wm.unmanaged_window_operation_behaviour = value wm.unmanaged_window_operation_behaviour = value
.unmanaged_window_operation_behaviour .unmanaged_window_operation_behaviour
.unwrap_or_default(); .unwrap_or_default();
+12 -6
View File
@@ -33,6 +33,7 @@ use crate::core::CycleDirection;
use crate::core::DefaultLayout; use crate::core::DefaultLayout;
use crate::core::FocusFollowsMouseImplementation; use crate::core::FocusFollowsMouseImplementation;
use crate::core::Layout; use crate::core::Layout;
use crate::core::MonocleFocusBehaviour;
use crate::core::MoveBehaviour; use crate::core::MoveBehaviour;
use crate::core::OperationBehaviour; use crate::core::OperationBehaviour;
use crate::core::OperationDirection; use crate::core::OperationDirection;
@@ -81,6 +82,7 @@ pub struct WindowManager {
pub window_management_behaviour: WindowManagementBehaviour, pub window_management_behaviour: WindowManagementBehaviour,
pub cross_monitor_move_behaviour: MoveBehaviour, pub cross_monitor_move_behaviour: MoveBehaviour,
pub cross_boundary_behaviour: CrossBoundaryBehaviour, pub cross_boundary_behaviour: CrossBoundaryBehaviour,
pub monocle_focus_behaviour: MonocleFocusBehaviour,
pub unmanaged_window_operation_behaviour: OperationBehaviour, pub unmanaged_window_operation_behaviour: OperationBehaviour,
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>, pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
pub mouse_follows_focus: bool, pub mouse_follows_focus: bool,
@@ -158,6 +160,7 @@ impl WindowManager {
window_management_behaviour: WindowManagementBehaviour::default(), window_management_behaviour: WindowManagementBehaviour::default(),
cross_monitor_move_behaviour: MoveBehaviour::Swap, cross_monitor_move_behaviour: MoveBehaviour::Swap,
cross_boundary_behaviour: CrossBoundaryBehaviour::Monitor, cross_boundary_behaviour: CrossBoundaryBehaviour::Monitor,
monocle_focus_behaviour: MonocleFocusBehaviour::default(),
unmanaged_window_operation_behaviour: OperationBehaviour::Op, unmanaged_window_operation_behaviour: OperationBehaviour::Op,
resize_delta: 50, resize_delta: 50,
focus_follows_mouse: None, focus_follows_mouse: None,
@@ -2110,7 +2113,9 @@ impl WindowManager {
tracing::info!("focusing container"); tracing::info!("focusing container");
if workspace.monocle_container.is_some() { if workspace.monocle_container.is_some()
&& matches!(self.monocle_focus_behaviour, MonocleFocusBehaviour::Cycle)
{
let cycle_direction = match direction { let cycle_direction = match direction {
OperationDirection::Left | OperationDirection::Down => CycleDirection::Previous, OperationDirection::Left | OperationDirection::Down => CycleDirection::Previous,
OperationDirection::Right | OperationDirection::Up => CycleDirection::Next, OperationDirection::Right | OperationDirection::Up => CycleDirection::Next,
@@ -2118,11 +2123,12 @@ impl WindowManager {
return self.cycle_monocle(cycle_direction); return self.cycle_monocle(cycle_direction);
} }
let new_idx = if workspace.maximized_window.is_some() { let new_idx =
None if workspace.maximized_window.is_some() || workspace.monocle_container.is_some() {
} else { None
workspace.new_idx_for_direction(direction) } else {
}; workspace.new_idx_for_direction(direction)
};
let mut cross_monitor_monocle_or_max = false; let mut cross_monitor_monocle_or_max = false;
+18
View File
@@ -737,6 +737,13 @@ struct BorderStyle {
style: komorebi_client::BorderStyle, style: komorebi_client::BorderStyle,
} }
#[derive(Parser)]
struct MonocleFocusBehaviour {
/// Desired monocle focus behaviour
#[clap(value_enum)]
behaviour: komorebi_client::MonocleFocusBehaviour,
}
#[derive(Parser)] #[derive(Parser)]
struct BorderImplementation { struct BorderImplementation {
/// Desired border implementation /// Desired border implementation
@@ -1418,6 +1425,11 @@ enum SubCommand {
CrossMonitorMoveBehaviour(CrossMonitorMoveBehaviour), CrossMonitorMoveBehaviour(CrossMonitorMoveBehaviour),
/// Toggle the behaviour when moving windows across monitor boundaries /// Toggle the behaviour when moving windows across monitor boundaries
ToggleCrossMonitorMoveBehaviour, ToggleCrossMonitorMoveBehaviour,
/// Set the behaviour when focusing in a direction while a monocle container is active
#[clap(arg_required_else_help = true)]
MonocleFocusBehaviour(MonocleFocusBehaviour),
/// Toggle the behaviour when focusing in a direction while a monocle container is active
ToggleMonocleFocusBehaviour,
/// Set the operation behaviour when the focused window is not managed /// Set the operation behaviour when the focused window is not managed
#[clap(arg_required_else_help = true)] #[clap(arg_required_else_help = true)]
UnmanagedWindowOperationBehaviour(UnmanagedWindowOperationBehaviour), UnmanagedWindowOperationBehaviour(UnmanagedWindowOperationBehaviour),
@@ -3251,6 +3263,12 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
SubCommand::ToggleCrossMonitorMoveBehaviour => { SubCommand::ToggleCrossMonitorMoveBehaviour => {
send_message(&SocketMessage::ToggleCrossMonitorMoveBehaviour)?; send_message(&SocketMessage::ToggleCrossMonitorMoveBehaviour)?;
} }
SubCommand::MonocleFocusBehaviour(args) => {
send_message(&SocketMessage::MonocleFocusBehaviour(args.behaviour))?;
}
SubCommand::ToggleMonocleFocusBehaviour => {
send_message(&SocketMessage::ToggleMonocleFocusBehaviour)?;
}
SubCommand::UnmanagedWindowOperationBehaviour(args) => { SubCommand::UnmanagedWindowOperationBehaviour(args) => {
send_message(&SocketMessage::UnmanagedWindowOperationBehaviour( send_message(&SocketMessage::UnmanagedWindowOperationBehaviour(
args.operation_behaviour, args.operation_behaviour,