diff --git a/komorebi-client/src/lib.rs b/komorebi-client/src/lib.rs index 23c771fb5..8c53c7e08 100644 --- a/komorebi-client/src/lib.rs +++ b/komorebi-client/src/lib.rs @@ -34,6 +34,7 @@ pub use komorebi::core::StackbarMode; pub use komorebi::core::StateQuery; pub use komorebi::core::WindowKind; pub use komorebi::monitor::Monitor; +pub use komorebi::monitor_reconciliator::MonitorNotification; pub use komorebi::ring::Ring; pub use komorebi::window::Window; pub use komorebi::window_manager_event::WindowManagerEvent; diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index 8899700b2..2fa4b3cd0 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -32,6 +32,7 @@ pub mod workspace; pub mod workspace_reconciliator; use lazy_static::lazy_static; +use monitor_reconciliator::MonitorNotification; use std::collections::HashMap; use std::collections::VecDeque; use std::fs::File; @@ -283,6 +284,7 @@ pub fn current_virtual_desktop() -> Option> { pub enum NotificationEvent { WindowManager(WindowManagerEvent), Socket(SocketMessage), + Monitor(MonitorNotification), } #[derive(Debug, Serialize, Deserialize, JsonSchema)] diff --git a/komorebi/src/monitor_reconciliator/hidden.rs b/komorebi/src/monitor_reconciliator/hidden.rs index 5d54c8540..225d5e752 100644 --- a/komorebi/src/monitor_reconciliator/hidden.rs +++ b/komorebi/src/monitor_reconciliator/hidden.rs @@ -114,7 +114,7 @@ impl Hidden { "WM_POWERBROADCAST event received - resume from suspend" ); monitor_reconciliator::send_notification( - monitor_reconciliator::Notification::ResumingFromSuspendedState, + monitor_reconciliator::MonitorNotification::ResumingFromSuspendedState, ); LRESULT(0) } @@ -124,7 +124,7 @@ impl Hidden { "WM_POWERBROADCAST event received - entering suspended state" ); monitor_reconciliator::send_notification( - monitor_reconciliator::Notification::EnteringSuspendedState, + monitor_reconciliator::MonitorNotification::EnteringSuspendedState, ); LRESULT(0) } @@ -137,14 +137,14 @@ impl Hidden { tracing::debug!("WM_WTSSESSION_CHANGE event received with WTS_SESSION_LOCK - screen locked"); monitor_reconciliator::send_notification( - monitor_reconciliator::Notification::SessionLocked, + monitor_reconciliator::MonitorNotification::SessionLocked, ); } WTS_SESSION_UNLOCK => { tracing::debug!("WM_WTSSESSION_CHANGE event received with WTS_SESSION_UNLOCK - screen unlocked"); monitor_reconciliator::send_notification( - monitor_reconciliator::Notification::SessionUnlocked, + monitor_reconciliator::MonitorNotification::SessionUnlocked, ); } _ => {} @@ -165,7 +165,7 @@ impl Hidden { ); monitor_reconciliator::send_notification( - monitor_reconciliator::Notification::ResolutionScalingChanged, + monitor_reconciliator::MonitorNotification::ResolutionScalingChanged, ); LRESULT(0) } @@ -179,7 +179,7 @@ impl Hidden { ); monitor_reconciliator::send_notification( - monitor_reconciliator::Notification::WorkAreaChanged, + monitor_reconciliator::MonitorNotification::WorkAreaChanged, ); } LRESULT(0) @@ -193,7 +193,7 @@ impl Hidden { "WM_DEVICECHANGE event received with DBT_DEVNODES_CHANGED - display added or removed" ); monitor_reconciliator::send_notification( - monitor_reconciliator::Notification::DisplayConnectionChange, + monitor_reconciliator::MonitorNotification::DisplayConnectionChange, ); } diff --git a/komorebi/src/monitor_reconciliator/mod.rs b/komorebi/src/monitor_reconciliator/mod.rs index d91f211f6..ae3122cd1 100644 --- a/komorebi/src/monitor_reconciliator/mod.rs +++ b/komorebi/src/monitor_reconciliator/mod.rs @@ -5,13 +5,20 @@ use crate::core::Rect; use crate::monitor; use crate::monitor::Monitor; use crate::monitor_reconciliator::hidden::Hidden; +use crate::notify_subscribers; use crate::MonitorConfig; +use crate::Notification; +use crate::NotificationEvent; +use crate::State; use crate::WindowManager; use crate::WindowsApi; use crossbeam_channel::Receiver; use crossbeam_channel::Sender; use crossbeam_utils::atomic::AtomicConsume; use parking_lot::Mutex; +use schemars::JsonSchema; +use serde::Deserialize; +use serde::Serialize; use std::collections::HashMap; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; @@ -20,7 +27,9 @@ use std::sync::OnceLock; pub mod hidden; -pub enum Notification { +#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "type", content = "content")] +pub enum MonitorNotification { ResolutionScalingChanged, WorkAreaChanged, DisplayConnectionChange, @@ -32,23 +41,24 @@ pub enum Notification { static ACTIVE: AtomicBool = AtomicBool::new(true); -static CHANNEL: OnceLock<(Sender, Receiver)> = OnceLock::new(); +static CHANNEL: OnceLock<(Sender, Receiver)> = + OnceLock::new(); static MONITOR_CACHE: OnceLock>> = OnceLock::new(); -pub fn channel() -> &'static (Sender, Receiver) { +pub fn channel() -> &'static (Sender, Receiver) { CHANNEL.get_or_init(|| crossbeam_channel::bounded(1)) } -fn event_tx() -> Sender { +fn event_tx() -> Sender { channel().0.clone() } -fn event_rx() -> Receiver { +fn event_rx() -> Receiver { channel().1.clone() } -pub fn send_notification(notification: Notification) { +pub fn send_notification(notification: MonitorNotification) { if event_tx().try_send(notification).is_err() { tracing::warn!("channel is full; dropping notification") } @@ -125,7 +135,8 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result if !ACTIVE.load_consume() { if matches!( notification, - Notification::ResumingFromSuspendedState | Notification::SessionUnlocked + MonitorNotification::ResumingFromSuspendedState + | MonitorNotification::SessionUnlocked ) { tracing::debug!( "reactivating reconciliator - system has resumed from suspended state or session has been unlocked" @@ -140,17 +151,20 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result let mut wm = wm.lock(); + let initial_state = State::from(wm.as_ref()); + match notification { - Notification::EnteringSuspendedState | Notification::SessionLocked => { + MonitorNotification::EnteringSuspendedState | MonitorNotification::SessionLocked => { tracing::debug!( "deactivating reconciliator until system resumes from suspended state or session is unlocked" ); ACTIVE.store(false, Ordering::SeqCst); } - Notification::ResumingFromSuspendedState | Notification::SessionUnlocked => { + MonitorNotification::ResumingFromSuspendedState + | MonitorNotification::SessionUnlocked => { // this is only handled above if the reconciliator is paused } - Notification::WorkAreaChanged => { + MonitorNotification::WorkAreaChanged => { tracing::debug!("handling work area changed notification"); let offset = wm.work_area_offset; for monitor in wm.monitors_mut() { @@ -182,7 +196,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result } } } - Notification::ResolutionScalingChanged => { + MonitorNotification::ResolutionScalingChanged => { tracing::debug!("handling resolution/scaling changed notification"); let offset = wm.work_area_offset; for monitor in wm.monitors_mut() { @@ -229,7 +243,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result } } } - Notification::DisplayConnectionChange => { + MonitorNotification::DisplayConnectionChange => { tracing::debug!("handling display connection change notification"); let mut monitor_cache = MONITOR_CACHE .get_or_init(|| Mutex::new(HashMap::new())) @@ -411,6 +425,14 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result } } } + + notify_subscribers( + Notification { + event: NotificationEvent::Monitor(notification), + state: wm.as_ref().into(), + }, + initial_state.has_been_modified(&wm), + )?; } Ok(())