From b2f6329963268f652223fc772d529f76fa05aa3a Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 16 Mar 2024 15:35:34 -0700 Subject: [PATCH] fix(wm): raise applicationframehost apps via state This commit ensures that ApplicationFrameHost.exe applications developed by Microsoft are raised correctly when a user has the custom komorebi ffm implementation enabled. The Win32 API calls EnumWindows and WindowFromPoint return different HWNDs for the same windows because of some jank in how the ApplicationFrameHost apps are developed. To avoid this inconsistency on the Win32 API level, komorebi now queries its own state when looking up HWNDs for windows at any given cursor position. --- komorebi/src/window_manager.rs | 83 +++++++++++++--------------------- 1 file changed, 32 insertions(+), 51 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 185fb635..f4366d4f 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -671,63 +671,44 @@ impl WindowManager { #[tracing::instrument(skip(self))] pub fn raise_window_at_cursor_pos(&mut self) -> Result<()> { - let mut hwnd = WindowsApi::window_at_cursor_pos()?; + let mut hwnd = None; - if self.has_pending_raise_op - || self.focused_window()?.hwnd == hwnd - // Sometimes we need this check, because the focus may have been given by a click - // to a non-window such as the taskbar or system tray, and komorebi doesn't know that - // the focused window of the workspace is not actually focused by the OS at that point - || WindowsApi::foreground_window()? == hwnd - { - Ok(()) - } else { - let mut known_hwnd = false; - for monitor in self.monitors() { - for workspace in monitor.workspaces() { - if workspace.contains_window(hwnd) { - known_hwnd = true; - } - } - } - - // TODO: Not sure if this needs to be made configurable just yet... - let overlay_classes = [ - // Chromium/Electron - "Chrome_RenderWidgetHostHWND".to_string(), - // Explorer - "DirectUIHWND".to_string(), - "SysTreeView32".to_string(), - "ToolbarWindow32".to_string(), - "NetUIHWND".to_string(), - ]; - - if !known_hwnd { - let class = Window { hwnd }.class()?; - // Some applications (Electron/Chromium-based, explorer) have (invisible?) overlays - // windows that we need to look beyond to find the actual window to raise - if overlay_classes.contains(&class) { - for monitor in self.monitors() { - for workspace in monitor.workspaces() { - if let Some(exe_hwnd) = workspace.hwnd_from_exe(&Window { hwnd }.exe()?) - { - hwnd = exe_hwnd; - known_hwnd = true; - } + for monitor in self.monitors() { + for workspace in monitor.workspaces() { + if let Some(container_idx) = workspace.container_idx_from_current_point() { + if let Some(container) = workspace.containers().get(container_idx) { + if let Some(window) = container.focused_window() { + hwnd = Some(window.hwnd); } } } } - - if known_hwnd { - let event = WindowManagerEvent::Raise(Window { hwnd }); - self.has_pending_raise_op = true; - Ok(winevent_listener::event_tx().send(event)?) - } else { - tracing::debug!("not raising unknown window: {}", Window { hwnd }); - Ok(()) - } } + + if let Some(hwnd) = hwnd { + if self.has_pending_raise_op + || self.focused_window()?.hwnd == hwnd + // Sometimes we need this check, because the focus may have been given by a click + // to a non-window such as the taskbar or system tray, and komorebi doesn't know that + // the focused window of the workspace is not actually focused by the OS at that point + || WindowsApi::foreground_window()? == hwnd + { + return Ok(()); + } + + let event = WindowManagerEvent::Raise(Window { hwnd }); + self.has_pending_raise_op = true; + winevent_listener::event_tx().send(event)?; + } else { + tracing::debug!( + "not raising unknown window: {}", + Window { + hwnd: WindowsApi::window_at_cursor_pos()? + } + ); + } + + Ok(()) } #[tracing::instrument(skip(self))]