mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-13 00:22:52 +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::winevent::WinEvent;
|
||||||
use crate::workspace::WorkspaceLayer;
|
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]
|
#[tracing::instrument]
|
||||||
pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
||||||
let receiver = wm.lock().incoming_events.clone();
|
let receiver = wm.lock().incoming_events.clone();
|
||||||
@@ -341,6 +365,13 @@ impl WindowManager {
|
|||||||
already_moved_window_handles.remove(&window.hwnd);
|
already_moved_window_handles.remove(&window.hwnd);
|
||||||
}
|
}
|
||||||
WindowManagerEvent::FocusChange(_, window) => {
|
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
|
// 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
|
// containers - this makes floating windows on empty workspaces go into very
|
||||||
// annoying focus change loops which prevents users from interacting with them
|
// annoying focus change loops which prevents users from interacting with them
|
||||||
|
|||||||
Reference in New Issue
Block a user