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`).
This commit is contained in:
alex-ds13
2025-01-29 18:16:03 +00:00
committed by LGUG2Z
parent c05eab9044
commit 302e96c172
3 changed files with 64 additions and 2 deletions

View File

@@ -61,6 +61,7 @@ use std::sync::Arc;
pub struct Komobar {
pub hwnd: Option<isize>,
pub monitor_index: usize,
pub disabled: bool,
pub config: Arc<KomobarConfig>,
pub render_config: Rc<RefCell<RenderConfig>>,
pub komorebi_notification_state: Option<Rc<RefCell<KomorebiNotificationState>>>,
@@ -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 = &notification.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;

View File

@@ -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<Rect>,
pub stack_accent: Option<Color32>,
pub monitor_index: usize,
pub monitor_usr_idx_map: HashMap<usize, usize>,
}
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;

View File

@@ -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,