From 948f7de3a9392620f45fd371dc8945e88fd92699 Mon Sep 17 00:00:00 2001 From: Helios Date: Fri, 6 Mar 2026 02:19:27 +0100 Subject: [PATCH] fix: loosen ghost window filter, only block Program Manager --- crates/client/src/windows_mgmt.rs | 70 ++++++++++--------------------- 1 file changed, 21 insertions(+), 49 deletions(-) diff --git a/crates/client/src/windows_mgmt.rs b/crates/client/src/windows_mgmt.rs index 6f766f7..8210a21 100644 --- a/crates/client/src/windows_mgmt.rs +++ b/crates/client/src/windows_mgmt.rs @@ -8,9 +8,9 @@ mod win_impl { use super::*; use windows::Win32::Foundation::{BOOL, HWND, LPARAM}; use windows::Win32::UI::WindowsAndMessaging::{ - BringWindowToTop, EnumWindows, GetWindowLongA, GetWindowTextW, IsIconic, - IsWindowVisible, SetForegroundWindow, ShowWindow, GWL_EXSTYLE, - SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, WS_EX_TOOLWINDOW, + BringWindowToTop, EnumWindows, GetAncestor, GetWindowLongA, GetWindowTextW, + IsIconic, IsWindowVisible, SetForegroundWindow, ShowWindow, GA_ROOT, + GWL_EXSTYLE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, WS_EX_TOOLWINDOW, }; use windows::Win32::UI::Input::KeyboardAndMouse::{ keybd_event, KEYEVENTF_KEYUP, VK_MENU, @@ -20,26 +20,7 @@ mod win_impl { }; use windows::Win32::System::ProcessStatus::GetModuleBaseNameW; - /// Process names that are always excluded (ghost/system windows). - const GHOST_PROCESSES: &[&str] = &[ - "textinputhost", - "shellexperiencehost", - "searchhost", - "startmenuexperiencehost", - "lockapp", - "systemsettings", - "widgets", - ]; - - /// Process names excluded unless the window has a "real" (non-empty) title. - const GHOST_UNLESS_TITLED: &[&str] = &[ - "applicationframehost", - ]; - - /// Window titles that are always excluded. - const GHOST_TITLES: &[&str] = &[ - "program manager", - ]; + // No broad blocklists — only explorer's "Program Manager" is filtered. unsafe extern "system" fn enum_callback(hwnd: HWND, lparam: LPARAM) -> BOOL { let list = &mut *(lparam.0 as *mut Vec); @@ -85,35 +66,16 @@ mod win_impl { } } - /// Check if a window is a ghost/invisible window that should be filtered out. - fn is_ghost_window(hwnd: HWND, title: &str, process_name: &str) -> bool { - let title_lower = title.to_lowercase(); + /// Minimal filter: only block explorer's "Program Manager" desktop window. + fn is_ghost_window(_hwnd: HWND, title: &str, process_name: &str) -> bool { let proc_lower = process_name.to_lowercase(); - - // Exclude by title - if GHOST_TITLES.iter().any(|&t| title_lower == t) { - return true; - } - - // Exclude always-ghost processes - if GHOST_PROCESSES.iter().any(|&p| proc_lower == p) { - return true; - } - - // Exclude ghost-unless-titled processes (title == process name means no real title) - if GHOST_UNLESS_TITLED.iter().any(|&p| proc_lower == p) { - // If the title is just the process name or very generic, filter it - if title_lower == proc_lower || title.trim().is_empty() { + // Only block explorer when title is "Program Manager" or empty + if proc_lower == "explorer" { + let t = title.trim(); + if t.is_empty() || t.eq_ignore_ascii_case("program manager") { return true; } } - - // Exclude tool windows (WS_EX_TOOLWINDOW) - let ex_style = unsafe { GetWindowLongA(hwnd, GWL_EXSTYLE) } as u32; - if ex_style & WS_EX_TOOLWINDOW.0 != 0 { - return true; - } - false } @@ -131,11 +93,21 @@ mod win_impl { if title.is_empty() { continue; } - // Skip minimized-to-nothing windows (iconic) + // Skip minimized windows let iconic = unsafe { IsIconic(*hwnd).as_bool() }; if iconic { continue; } + // Skip tool windows + let ex_style = unsafe { GetWindowLongA(*hwnd, GWL_EXSTYLE) } as u32; + if ex_style & WS_EX_TOOLWINDOW.0 != 0 { + continue; + } + // Only keep top-level windows + let root = unsafe { GetAncestor(*hwnd, GA_ROOT) }; + if root != *hwnd { + continue; + } let process_name = hwnd_process_name(*hwnd).unwrap_or_default(); if process_name.is_empty() { continue;