From 302e96c1725db22153ffd3821f28caeeabc57845 Mon Sep 17 00:00:00 2001 From: alex-ds13 <145657253+alex-ds13@users.noreply.github.com> Date: Wed, 29 Jan 2025 18:16:03 +0000 Subject: [PATCH] fix(bar): handle monitor disconnect/reconnect This commit allows a bar to be disabled when it's monitor is disconnected and re-enabled when said monitor reconnects. This commit also uses the new `monitor_usr_idx_map` to properly map the monitor index given by the users on config to the actual monitor index on the `WindowManager` - in case some middle monitor gets disconnected the index of the monitors to the "right" of that one will be lowered by 1. This should allow for the following in cases with monitor A, B and C: if monitor B disconnects, its bar will be disabled and monitor C will properly change its monitor index internally to 1 so it still gets the infos from monitor C (which now will have index 1 on the `WindowManager`). --- komorebi-bar/src/bar.rs | 50 +++++++++++++++++++++++++++++++++++- komorebi-bar/src/komorebi.rs | 10 ++++++++ komorebi-bar/src/main.rs | 6 ++++- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index 1fcb56bb..f07db84a 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -61,6 +61,7 @@ use std::sync::Arc; pub struct Komobar { pub hwnd: Option, pub monitor_index: usize, + pub disabled: bool, pub config: Arc, pub render_config: Rc>, pub komorebi_notification_state: Option>>, @@ -305,12 +306,22 @@ impl Komobar { self.center_widgets = center_widgets; self.right_widgets = right_widgets; - let (monitor_index, config_work_area_offset) = match &config.monitor { + let (usr_monitor_index, config_work_area_offset) = match &config.monitor { MonitorConfigOrIndex::MonitorConfig(monitor_config) => { (monitor_config.index, monitor_config.work_area_offset) } MonitorConfigOrIndex::Index(idx) => (*idx, None), }; + let monitor_index = if let Some(state) = &self.komorebi_notification_state { + state + .borrow() + .monitor_usr_idx_map + .get(&usr_monitor_index) + .map_or(usr_monitor_index, |i| *i) + } else { + usr_monitor_index + }; + self.monitor_index = monitor_index; if let (prev_rect, Some(new_rect)) = (&self.work_area_offset, &config_work_area_offset) { @@ -515,6 +526,7 @@ impl Komobar { let mut komobar = Self { hwnd: process_hwnd(), monitor_index: 0, + disabled: false, config: config.clone(), render_config: Rc::new(RefCell::new(RenderConfig::new())), komorebi_notification_state: None, @@ -652,6 +664,32 @@ impl eframe::App for Komobar { NotificationEvent::Monitor(MonitorNotification::DisplayConnectionChange) ) { let state = ¬ification.state; + let usr_monitor_index = match &self.config.monitor { + MonitorConfigOrIndex::MonitorConfig(monitor_config) => monitor_config.index, + MonitorConfigOrIndex::Index(idx) => *idx, + }; + let monitor_index = state + .monitor_usr_idx_map + .get(&usr_monitor_index) + .map_or(usr_monitor_index, |i| *i); + self.monitor_index = monitor_index; + + if self.monitor_index >= state.monitors.elements().len() { + // Monitor for this bar got disconnected lets disable the bar until it + // reconnects + self.disabled = true; + tracing::warn!( + "This bar's monitor got disconnected. The bar will be disabled until it reconnects..." + ); + return; + } else { + if self.disabled { + tracing::info!( + "This bar's monitor reconnected. The bar will be enabled again!" + ); + } + self.disabled = false; + } // Store the monitor coordinates in case they've changed MONITOR_RIGHT.store( @@ -674,6 +712,10 @@ impl eframe::App for Komobar { false }; + if self.disabled { + return; + } + if let Some(komorebi_notification_state) = &self.komorebi_notification_state { komorebi_notification_state .borrow_mut() @@ -719,6 +761,12 @@ impl eframe::App for Komobar { } } + if self.disabled { + // The check for disabled is performed above, if we get here and the bar is still + // disabled then we should return without drawing anything. + return; + } + if !self.applied_theme_on_first_frame { self.try_apply_theme(&self.config.clone(), ctx); self.applied_theme_on_first_frame = true; diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index 61878fef..34c3bbe8 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -38,6 +38,7 @@ use serde::Deserialize; use serde::Serialize; use std::cell::RefCell; use std::collections::BTreeMap; +use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; use std::sync::atomic::Ordering; @@ -121,6 +122,7 @@ impl From<&KomorebiConfig> for Komorebi { focused_container_information: KomorebiNotificationStateContainerInformation::EMPTY, stack_accent: None, monitor_index: MONITOR_INDEX.load(Ordering::SeqCst), + monitor_usr_idx_map: HashMap::new(), })), workspaces: value.workspaces, layout: value.layout.clone(), @@ -483,6 +485,7 @@ pub struct KomorebiNotificationState { pub work_area_offset: Option, pub stack_accent: Option, pub monitor_index: usize, + pub monitor_usr_idx_map: HashMap, } impl KomorebiNotificationState { @@ -553,6 +556,13 @@ impl KomorebiNotificationState { } self.monitor_index = monitor_index; + self.monitor_usr_idx_map = notification.state.monitor_usr_idx_map.clone(); + + if monitor_index >= notification.state.monitors.elements().len() { + // The bar's monitor is diconnected, so the bar is disabled no need to check anything + // any further otherwise we'll get `OutOfBounds` panics. + return; + } self.mouse_follows_focus = notification.state.mouse_follows_focus; diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index b60bf449..d12d00d9 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -238,12 +238,16 @@ fn main() -> color_eyre::Result<()> { &SocketMessage::State, )?)?; - let (monitor_index, work_area_offset) = match &config.monitor { + let (usr_monitor_index, work_area_offset) = match &config.monitor { MonitorConfigOrIndex::MonitorConfig(monitor_config) => { (monitor_config.index, monitor_config.work_area_offset) } MonitorConfigOrIndex::Index(idx) => (*idx, None), }; + let monitor_index = state + .monitor_usr_idx_map + .get(&usr_monitor_index) + .map_or(usr_monitor_index, |i| *i); MONITOR_RIGHT.store( state.monitors.elements()[monitor_index].size().right,