From 281980b010a72f059849c8d86bc7f82f4c04e9a5 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 4 Jan 2025 12:04:53 -0800 Subject: [PATCH] fix(wm): avoid obvious border manager thread crash This commit adds an early exit from the border manager's event processing loop whenever a window which still exists in the state but has been destroyed is encountered. Instead of returning an error, the 'containers loop will now skip ahead to the next iteration. This commit also makes an adjustment to the frequency with which the reaper sends border manager notifications - a single notification is now sent at the end of each iteration if necessary, rather than one notification per workspace. --- komorebi/src/border_manager/mod.rs | 14 ++++++++++++-- komorebi/src/reaper.rs | 8 +++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/komorebi/src/border_manager/mod.rs b/komorebi/src/border_manager/mod.rs index 4d9d6a9d..6d07d795 100644 --- a/komorebi/src/border_manager/mod.rs +++ b/komorebi/src/border_manager/mod.rs @@ -427,7 +427,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result borders.remove(id); } - for (idx, c) in ws.containers().iter().enumerate() { + 'containers: for (idx, c) in ws.containers().iter().enumerate() { // Get the border entry for this container from the map or create one let mut new_border = false; let border = match borders.entry(c.id().clone()) { @@ -471,7 +471,17 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result let reference_hwnd = c.focused_window().copied().unwrap_or_default().hwnd; - let rect = WindowsApi::window_rect(reference_hwnd)?; + // avoid getting into a thread restart loop if we try to look up + // rect info for a window that has been destroyed by the time + // we get here + let rect = match WindowsApi::window_rect(reference_hwnd) { + Ok(rect) => rect, + Err(_) => { + let _ = border.destroy(); + borders.remove(c.id()); + continue 'containers; + } + }; let should_invalidate = match last_focus_state { None => true, diff --git a/komorebi/src/reaper.rs b/komorebi/src/reaper.rs index 28341725..6ca14e2f 100644 --- a/komorebi/src/reaper.rs +++ b/komorebi/src/reaper.rs @@ -34,6 +34,8 @@ pub fn find_orphans(wm: Arc>) -> color_eyre::Result<()> { let mut wm = arc.lock(); let offset = wm.work_area_offset; + let mut update_borders = false; + for (i, monitor) in wm.monitors_mut().iter_mut().enumerate() { let work_area = *monitor.work_area_size(); let window_based_work_area_offset = ( @@ -51,7 +53,7 @@ pub fn find_orphans(wm: Arc>) -> color_eyre::Result<()> { let reaped_orphans = workspace.reap_orphans()?; if reaped_orphans.0 > 0 || reaped_orphans.1 > 0 { workspace.update(&work_area, offset, window_based_work_area_offset)?; - border_manager::send_notification(None); + update_borders = true; tracing::info!( "reaped {} orphan window(s) and {} orphaned container(s) on monitor: {}, workspace: {}", reaped_orphans.0, @@ -62,5 +64,9 @@ pub fn find_orphans(wm: Arc>) -> color_eyre::Result<()> { } } } + + if update_borders { + border_manager::send_notification(None); + } } }