Skip to content

Commit

Permalink
feat(wm): notify subscribers of monitor events
Browse files Browse the repository at this point in the history
This commit allows notifying the subscribers of any monitor events like
display connection change or work area change.
  • Loading branch information
alex-ds13 authored and LGUG2Z committed Jan 24, 2025
1 parent 4123c9a commit 5c3c365
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 19 deletions.
1 change: 1 addition & 0 deletions komorebi-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions komorebi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -283,6 +284,7 @@ pub fn current_virtual_desktop() -> Option<Vec<u8>> {
pub enum NotificationEvent {
WindowManager(WindowManagerEvent),
Socket(SocketMessage),
Monitor(MonitorNotification),
}

#[derive(Debug, Serialize, Deserialize, JsonSchema)]
Expand Down
14 changes: 7 additions & 7 deletions komorebi/src/monitor_reconciliator/hidden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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,
);
}
_ => {}
Expand All @@ -165,7 +165,7 @@ impl Hidden {
);

monitor_reconciliator::send_notification(
monitor_reconciliator::Notification::ResolutionScalingChanged,
monitor_reconciliator::MonitorNotification::ResolutionScalingChanged,
);
LRESULT(0)
}
Expand All @@ -179,7 +179,7 @@ impl Hidden {
);

monitor_reconciliator::send_notification(
monitor_reconciliator::Notification::WorkAreaChanged,
monitor_reconciliator::MonitorNotification::WorkAreaChanged,
);
}
LRESULT(0)
Expand All @@ -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,
);
}

Expand Down
46 changes: 34 additions & 12 deletions komorebi/src/monitor_reconciliator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -32,23 +41,24 @@ pub enum Notification {

static ACTIVE: AtomicBool = AtomicBool::new(true);

static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new();
static CHANNEL: OnceLock<(Sender<MonitorNotification>, Receiver<MonitorNotification>)> =
OnceLock::new();

static MONITOR_CACHE: OnceLock<Mutex<HashMap<String, MonitorConfig>>> = OnceLock::new();

pub fn channel() -> &'static (Sender<Notification>, Receiver<Notification>) {
pub fn channel() -> &'static (Sender<MonitorNotification>, Receiver<MonitorNotification>) {
CHANNEL.get_or_init(|| crossbeam_channel::bounded(1))
}

fn event_tx() -> Sender<Notification> {
fn event_tx() -> Sender<MonitorNotification> {
channel().0.clone()
}

fn event_rx() -> Receiver<Notification> {
fn event_rx() -> Receiver<MonitorNotification> {
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")
}
Expand Down Expand Up @@ -125,7 +135,8 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> 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"
Expand All @@ -140,17 +151,20 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> 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() {
Expand Down Expand Up @@ -182,7 +196,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> 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() {
Expand Down Expand Up @@ -229,7 +243,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> 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()))
Expand Down Expand Up @@ -411,6 +425,14 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
}
}
}

notify_subscribers(
Notification {
event: NotificationEvent::Monitor(notification),
state: wm.as_ref().into(),
},
initial_state.has_been_modified(&wm),
)?;
}

Ok(())
Expand Down

0 comments on commit 5c3c365

Please sign in to comment.