mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-04-25 18:18:55 +02:00
fix(wm): restart bm and wsr notif handlers on fail
This commit ensures that if and when either the border_manager or workspace_reconciliator notification handlers crash in their respective threads, they will be restarted instead of killing the whole thread. This is acheived via a loop running in the spawned threads of both listeners, which will report whichever error killed the notification handler functions. Clippy annotations to deny expect and unwrap calls have been added to these two modules. Calls to DestroyWindow for expired borders were sporadically failing in unpredictable circumstances, so these have been switched out with calls to CloseWindow which has been working well so far with the stackbar feature.
This commit is contained in:
@@ -60,6 +60,7 @@ pub extern "system" fn border_hwnds(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
true.into()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Border {
|
||||
pub hwnd: isize,
|
||||
}
|
||||
@@ -116,7 +117,7 @@ impl Border {
|
||||
}
|
||||
|
||||
pub fn destroy(&self) -> color_eyre::Result<()> {
|
||||
WindowsApi::destroy_window(self.hwnd())
|
||||
WindowsApi::close_window(self.hwnd())
|
||||
}
|
||||
|
||||
pub fn update(&self, rect: &Rect) -> color_eyre::Result<()> {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
||||
|
||||
mod border;
|
||||
|
||||
use crossbeam_channel::Receiver;
|
||||
@@ -9,6 +11,7 @@ use parking_lot::Mutex;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicI32;
|
||||
@@ -69,6 +72,11 @@ pub fn event_rx() -> Receiver<Notification> {
|
||||
|
||||
pub fn destroy_all_borders() -> color_eyre::Result<()> {
|
||||
let mut borders = BORDER_STATE.lock();
|
||||
tracing::info!(
|
||||
"purging known borders: {:?}",
|
||||
borders.iter().map(|b| b.1.hwnd).collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
for (_, border) in borders.iter() {
|
||||
border.destroy()?;
|
||||
}
|
||||
@@ -85,18 +93,35 @@ pub fn destroy_all_borders() -> color_eyre::Result<()> {
|
||||
&mut remaining_hwnds as *mut Vec<isize> as isize,
|
||||
)?;
|
||||
|
||||
if !remaining_hwnds.is_empty() {
|
||||
tracing::info!("purging unknown borders: {:?}", remaining_hwnds);
|
||||
|
||||
for hwnd in remaining_hwnds {
|
||||
Border::from(hwnd).destroy()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result<()> {
|
||||
tracing::info!("listening");
|
||||
|
||||
let receiver = event_rx();
|
||||
|
||||
std::thread::spawn(move || -> color_eyre::Result<()> {
|
||||
'receiver: for _ in receiver {
|
||||
let mut borders = BORDER_STATE.lock();
|
||||
let mut borders_monitors = BORDERS_MONITORS.lock();
|
||||
@@ -125,8 +150,7 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
if !ws.tile() {
|
||||
let mut to_remove = vec![];
|
||||
for (id, border) in borders.iter() {
|
||||
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx
|
||||
{
|
||||
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx {
|
||||
border.destroy()?;
|
||||
to_remove.push(id.clone());
|
||||
}
|
||||
@@ -143,8 +167,7 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
if let Some(monocle) = ws.monocle_container() {
|
||||
let mut to_remove = vec![];
|
||||
for (id, border) in borders.iter() {
|
||||
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx
|
||||
{
|
||||
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx {
|
||||
border.destroy()?;
|
||||
to_remove.push(id.clone());
|
||||
}
|
||||
@@ -154,9 +177,16 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
borders.remove(id);
|
||||
}
|
||||
|
||||
let border = borders.entry(monocle.id().clone()).or_insert_with(|| {
|
||||
Border::create(monocle.id()).expect("border creation failed")
|
||||
});
|
||||
let border = match borders.entry(monocle.id().clone()) {
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => {
|
||||
if let Ok(border) = Border::create(monocle.id()) {
|
||||
entry.insert(border)
|
||||
} else {
|
||||
continue 'receiver;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
borders_monitors.insert(monocle.id().clone(), monitor_idx);
|
||||
|
||||
@@ -166,10 +196,7 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
}
|
||||
|
||||
let rect = WindowsApi::window_rect(
|
||||
monocle
|
||||
.focused_window()
|
||||
.expect("monocle container has no focused window")
|
||||
.hwnd(),
|
||||
monocle.focused_window().copied().unwrap_or_default().hwnd(),
|
||||
)?;
|
||||
|
||||
border.update(&rect)?;
|
||||
@@ -183,8 +210,7 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
if is_maximized {
|
||||
let mut to_remove = vec![];
|
||||
for (id, border) in borders.iter() {
|
||||
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx
|
||||
{
|
||||
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx {
|
||||
border.destroy()?;
|
||||
to_remove.push(id.clone());
|
||||
}
|
||||
@@ -206,7 +232,9 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
|
||||
let mut to_remove = vec![];
|
||||
for (id, border) in borders.iter() {
|
||||
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx && !container_ids.contains(id) {
|
||||
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx
|
||||
&& !container_ids.contains(id)
|
||||
{
|
||||
border.destroy()?;
|
||||
to_remove.push(id.clone());
|
||||
}
|
||||
@@ -223,20 +251,23 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
*Z_ORDER.lock() = ZOrder::TopMost;
|
||||
|
||||
let mut rect = WindowsApi::window_rect(
|
||||
c.focused_window()
|
||||
.expect("container has no focused window")
|
||||
.hwnd(),
|
||||
c.focused_window().copied().unwrap_or_default().hwnd(),
|
||||
)?;
|
||||
|
||||
while WindowsApi::lbutton_is_pressed() {
|
||||
let border = borders.entry(c.id().clone()).or_insert_with(|| {
|
||||
Border::create(c.id()).expect("border creation failed")
|
||||
});
|
||||
let border = match borders.entry(c.id().clone()) {
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => {
|
||||
if let Ok(border) = Border::create(c.id()) {
|
||||
entry.insert(border)
|
||||
} else {
|
||||
continue 'receiver;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let new_rect = WindowsApi::window_rect(
|
||||
c.focused_window()
|
||||
.expect("container has no focused window")
|
||||
.hwnd(),
|
||||
c.focused_window().copied().unwrap_or_default().hwnd(),
|
||||
)?;
|
||||
|
||||
if rect != new_rect {
|
||||
@@ -251,9 +282,16 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
}
|
||||
|
||||
// Get the border entry for this container from the map or create one
|
||||
let border = borders.entry(c.id().clone()).or_insert_with(|| {
|
||||
Border::create(c.id()).expect("border creation failed")
|
||||
});
|
||||
let border = match borders.entry(c.id().clone()) {
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => {
|
||||
if let Ok(border) = Border::create(c.id()) {
|
||||
entry.insert(border)
|
||||
} else {
|
||||
continue 'receiver;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
borders_monitors.insert(c.id().clone(), monitor_idx);
|
||||
|
||||
@@ -275,9 +313,7 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
}
|
||||
|
||||
let rect = WindowsApi::window_rect(
|
||||
c.focused_window()
|
||||
.expect("container has no focused window")
|
||||
.hwnd(),
|
||||
c.focused_window().copied().unwrap_or_default().hwnd(),
|
||||
)?;
|
||||
|
||||
border.update(&rect)?;
|
||||
@@ -287,7 +323,6 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
|
||||
@@ -38,7 +38,7 @@ use crate::PERMAIGNORE_CLASSES;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::WSL2_UI_PROCESSES;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, JsonSchema)]
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, JsonSchema)]
|
||||
pub struct Window {
|
||||
pub hwnd: isize,
|
||||
}
|
||||
|
||||
@@ -121,7 +121,6 @@ use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_CLOSE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_DESTROY;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_DISABLED;
|
||||
@@ -433,13 +432,6 @@ impl WindowsApi {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy_window(hwnd: HWND) -> Result<()> {
|
||||
match Self::post_message(hwnd, WM_DESTROY, WPARAM(0), LPARAM(0)) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(_) => Err(anyhow!("could not close window")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hide_window(hwnd: HWND) {
|
||||
Self::show_window(hwnd, SW_HIDE);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
||||
|
||||
use crate::WindowManager;
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
@@ -26,10 +28,22 @@ pub fn event_rx() -> Receiver<Notification> {
|
||||
}
|
||||
|
||||
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result<()> {
|
||||
tracing::info!("listening");
|
||||
|
||||
let receiver = event_rx();
|
||||
|
||||
std::thread::spawn(move || -> color_eyre::Result<()> {
|
||||
for notification in receiver {
|
||||
tracing::info!("running reconciliation");
|
||||
let mut wm = wm.lock();
|
||||
@@ -52,5 +66,4 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user