mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-06-25 03:36:18 +02:00
fix(wm): verify foreground state before mutating focus state
As a defense-in-depth fix independent of the event-conversion layer, the WindowManagerEvent::FocusChange handler should not update the focused monitor/workspace/container/window state when the incoming window is not the actual OS foreground window. The issue notes that after a monitor switch komorebi focuses "the last window focused from monitor 1" while the popout window on the other monitor still receives input. This is exactly the symptom of komorebi processing a stale/background focus event and re-pointing its selection at monitor 1 even though real focus is elsewhere. Verifying foreground state before mutating focus state prevents the desync regardless of which win-event produced the FocusChange. fix #1679 Signed-off-by: ChinhLee <76194645+chinhkrb113@users.noreply.github.com>
This commit is contained in:
@@ -41,6 +41,30 @@ use crate::windows_api::WindowsApi;
|
||||
use crate::winevent::WinEvent;
|
||||
use crate::workspace::WorkspaceLayer;
|
||||
|
||||
fn should_skip_focus_change(foreground_hwnd: Option<isize>, window_hwnd: isize) -> bool {
|
||||
matches!(foreground_hwnd, Some(hwnd) if hwnd != window_hwnd)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod focus_change_tests {
|
||||
use super::should_skip_focus_change;
|
||||
|
||||
#[test]
|
||||
fn skips_focus_change_from_background_window() {
|
||||
assert!(should_skip_focus_change(Some(1), 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allows_focus_change_for_foreground_window() {
|
||||
assert!(!should_skip_focus_change(Some(1), 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allows_focus_change_when_foreground_unknown() {
|
||||
assert!(!should_skip_focus_change(None, 1));
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
||||
let receiver = wm.lock().incoming_events.clone();
|
||||
@@ -341,6 +365,13 @@ impl WindowManager {
|
||||
already_moved_window_handles.remove(&window.hwnd);
|
||||
}
|
||||
WindowManagerEvent::FocusChange(_, window) => {
|
||||
if should_skip_focus_change(WindowsApi::foreground_window().ok(), window.hwnd) {
|
||||
tracing::debug!(
|
||||
"ignoring stale focus change for hwnd {} as it is not the foreground window",
|
||||
window.hwnd
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
// don't want to trigger the full workspace updates when there are no managed
|
||||
// containers - this makes floating windows on empty workspaces go into very
|
||||
// annoying focus change loops which prevents users from interacting with them
|
||||
|
||||
Reference in New Issue
Block a user