From adec6dc991e086e8aba87be7abe2696a9831aec1 Mon Sep 17 00:00:00 2001 From: eythaann Date: Thu, 29 Aug 2024 09:47:13 -0500 Subject: [PATCH] perf(enum): improvements on windows enumerator helpers --- src/background/hook.rs | 12 +-- .../modules/virtual_desk/workspaces.rs | 4 +- src/background/seelen.rs | 43 ++++----- src/background/seelen_weg/handler.rs | 2 - src/background/utils/constants.rs | 5 +- src/background/windows_api/iterator.rs | 91 ++++++++++++------- src/background/windows_api/mod.rs | 28 +----- src/background/windows_api/window.rs | 6 +- src/background/winevent.rs | 4 +- 9 files changed, 90 insertions(+), 105 deletions(-) diff --git a/src/background/hook.rs b/src/background/hook.rs index 807c0f26..54302da6 100644 --- a/src/background/hook.rs +++ b/src/background/hook.rs @@ -42,8 +42,6 @@ lazy_static! { pub static ref HOOK_MANAGER: Arc> = Arc::new(Mutex::new(HookManager::new())); } -pub static LAST_FOREGROUNDED: AtomicIsize = AtomicIsize::new(0); - pub struct HookManager { skip: HashMap>, } @@ -103,11 +101,11 @@ impl HookManager { } let title = WindowsApi::get_window_text(origin); - if event == WinEvent::ObjectFocus || event == WinEvent::SystemForeground { - if IGNORE_FOCUS.contains(&title) { - return; - } - LAST_FOREGROUNDED.store(origin.0, Ordering::SeqCst); + if (event == WinEvent::ObjectFocus || event == WinEvent::SystemForeground) + && IGNORE_FOCUS.contains(&title) + { + log::trace!("Skipping WinEvent::{:?}", event); + return; } std::thread::spawn(move || { diff --git a/src/background/modules/virtual_desk/workspaces.rs b/src/background/modules/virtual_desk/workspaces.rs index dc719ee6..3b831e2a 100644 --- a/src/background/modules/virtual_desk/workspaces.rs +++ b/src/background/modules/virtual_desk/workspaces.rs @@ -127,11 +127,11 @@ impl SeelenWorkspacesManager { fn load(&self) -> Result<()> { let mut workspaces = self.workspaces(); let workspace = workspaces.get_mut(self._current()).ok_or_else(none_err)?; - for hwnd in WindowEnumerator::new_refreshed()? { + WindowEnumerator::new().for_each(|hwnd| { if SeelenWeg::should_be_added(hwnd) && !WindowsApi::is_iconic(hwnd) { workspace.windows.push(hwnd.0); } - } + })?; Ok(()) } diff --git a/src/background/seelen.rs b/src/background/seelen.rs index 09371ee6..9386b8a0 100644 --- a/src/background/seelen.rs +++ b/src/background/seelen.rs @@ -6,10 +6,7 @@ use lazy_static::lazy_static; use parking_lot::Mutex; use tauri::{path::BaseDirectory, AppHandle, Manager, Wry}; use tauri_plugin_shell::ShellExt; -use windows::Win32::{ - Foundation::{BOOL, HWND, LPARAM}, - Graphics::Gdi::HMONITOR, -}; +use windows::Win32::Graphics::Gdi::HMONITOR; use crate::{ error_handler::Result, @@ -23,7 +20,7 @@ use crate::{ system::{declare_system_events_handlers, release_system_events_handlers}, trace_lock, utils::{ahk::AutoHotKey, sleep_millis, spawn_named_thread, PERFORMANCE_HELPER}, - windows_api::WindowsApi, + windows_api::{WindowEnumerator, WindowsApi}, }; lazy_static! { @@ -140,7 +137,22 @@ impl Seelen { ); log::trace!("Enumerating windows"); - WindowsApi::enum_windows(Some(Self::enum_windows_proc), 0)?; + WindowEnumerator::new().for_each(|hwnd| { + let mut seelen = trace_lock!(SEELEN); + + if SeelenWeg::should_be_added(hwnd) { + SeelenWeg::add_hwnd(hwnd); + } + + for monitor in seelen.monitors_mut() { + if let Some(wm) = monitor.wm_mut() { + if WindowManager::is_manageable_window(hwnd) { + log_error!(wm.add_hwnd(hwnd)); + } + } + } + })?; + register_win_hook()?; Ok(()) } @@ -388,22 +400,3 @@ impl Seelen { Ok(()) } } - -impl Seelen { - unsafe extern "system" fn enum_windows_proc(hwnd: HWND, _: LPARAM) -> BOOL { - let mut seelen = trace_lock!(SEELEN); - - if SeelenWeg::should_be_added(hwnd) { - SeelenWeg::add_hwnd(hwnd); - } - - for monitor in seelen.monitors_mut() { - if let Some(wm) = monitor.wm_mut() { - if WindowManager::is_manageable_window(hwnd) { - log_error!(wm.add_hwnd(hwnd)); - } - } - } - true.into() - } -} diff --git a/src/background/seelen_weg/handler.rs b/src/background/seelen_weg/handler.rs index 647ada55..5a18cbe7 100644 --- a/src/background/seelen_weg/handler.rs +++ b/src/background/seelen_weg/handler.rs @@ -68,8 +68,6 @@ pub fn weg_toggle_window_state(window: WebviewWindow, hwnd: isize, exe_path: Str } if WindowsApi::is_iconic(hwnd) { - println!("iconic"); - WindowsApi::show_window(hwnd, SW_SHOWNORMAL)?; WindowsApi::show_window(hwnd, SW_RESTORE)?; return Ok(()); diff --git a/src/background/utils/constants.rs b/src/background/utils/constants.rs index a0ae7515..04ccf599 100644 --- a/src/background/utils/constants.rs +++ b/src/background/utils/constants.rs @@ -7,10 +7,7 @@ lazy_static! { "Task View", "Virtual desktop switching preview", "Virtual desktop hotkey switching preview", - "Seelen Window Manager", - "SeelenWeg", - "SeelenWeg Hitbox", - "Seelen Fancy Toolbar", + "Seelen Window Manager", // for some reason this sometimes is focused, maybe could be deleted ] .iter() .map(|x| x.to_string()) diff --git a/src/background/windows_api/iterator.rs b/src/background/windows_api/iterator.rs index d00961d6..7205b098 100644 --- a/src/background/windows_api/iterator.rs +++ b/src/background/windows_api/iterator.rs @@ -3,7 +3,7 @@ use std::slice::Iter; use windows::Win32::{ Foundation::{BOOL, HWND, LPARAM, RECT}, Graphics::Gdi::{HDC, HMONITOR}, - UI::WindowsAndMessaging::EnumChildWindows, + UI::WindowsAndMessaging::{EnumChildWindows, EnumWindows}, }; use crate::{error_handler::Result, windows_api::WindowsApi}; @@ -11,54 +11,79 @@ use crate::{error_handler::Result, windows_api::WindowsApi}; #[derive(Debug, Clone)] pub struct WindowEnumerator { parent: Option, - handles: Vec, } -impl IntoIterator for WindowEnumerator { - type Item = HWND; - type IntoIter = std::vec::IntoIter; +impl WindowEnumerator { + pub fn new() -> Self { + Self { parent: None } + } - fn into_iter(self) -> Self::IntoIter { - self.handles.into_iter() + pub fn with_parent(mut self, parent: HWND) -> Self { + self.parent = Some(parent); + self } -} -impl WindowEnumerator { - pub fn new(parent: Option) -> Self { - Self { - parent, - handles: Vec::new(), + fn enumerate( + &self, + enum_proc: unsafe extern "system" fn(HWND, LPARAM) -> BOOL, + ptr: LPARAM, + ) -> Result<()> { + if let Some(parent) = self.parent { + unsafe { EnumChildWindows(parent, Some(enum_proc), ptr).ok()? }; + } else { + unsafe { EnumWindows(Some(enum_proc), ptr)? }; } + Ok(()) } - pub fn new_refreshed() -> Result { - let mut enumerator = Self::new(None); - enumerator.refresh()?; - Ok(enumerator) - } - - pub fn refresh(&mut self) -> Result<()> { - self.handles.clear(); - let ptr = &mut self.handles as *mut _ as isize; + /// Will call the callback for each window while enumerating. + /// If enumeration fails it will return error. + pub fn for_each(&self, cb: F) -> Result<()> + where + F: FnMut(HWND) + Sync, + { + type ForEachCallback<'a> = Box; + let mut callback: ForEachCallback = Box::new(cb); unsafe extern "system" fn enum_proc(hwnd: HWND, lparam: LPARAM) -> BOOL { - let data_ptr = lparam.0 as *mut Vec; - if let Some(data) = data_ptr.as_mut() { - data.push(hwnd); + if let Some(boxed) = (lparam.0 as *mut ForEachCallback).as_mut() { + (*boxed)(hwnd) } true.into() } - if let Some(parent) = self.parent { - unsafe { EnumChildWindows(parent, Some(enum_proc), LPARAM(ptr)).ok()? }; - } else { - WindowsApi::enum_windows(Some(enum_proc), ptr)?; - } - Ok(()) + let ptr = &mut callback as *mut _ as isize; + self.enumerate(enum_proc, LPARAM(ptr)) } - pub fn iter(&self) -> Iter<'_, HWND> { - self.handles.iter() + /// Will call the callback for each window while enumerating. + /// If enumeration fails it will return error. + pub fn map(&self, cb: F) -> Result> + where + F: FnMut(HWND) -> T + Sync, + T: Sync, + { + type MapCallback<'a, T> = Box T + 'a>; + struct MapCallbackWrapper<'a, T> { + cb: MapCallback<'a, T>, + processed: Vec, + } + + unsafe extern "system" fn enum_proc(hwnd: HWND, lparam: LPARAM) -> BOOL { + if let Some(wrapper) = (lparam.0 as *mut MapCallbackWrapper).as_mut() { + wrapper.processed.push((wrapper.cb)(hwnd)); + } + true.into() + } + + let mut wrapper = MapCallbackWrapper { + cb: Box::new(cb), + processed: Vec::new(), + }; + + let ptr = &mut wrapper as *mut _ as isize; + self.enumerate(enum_proc::, LPARAM(ptr))?; + Ok(wrapper.processed) } } diff --git a/src/background/windows_api/mod.rs b/src/background/windows_api/mod.rs index dbd72ded..ff60ffe7 100644 --- a/src/background/windows_api/mod.rs +++ b/src/background/windows_api/mod.rs @@ -81,7 +81,7 @@ use windows::{ use crate::{ error_handler::{AppError, Result}, - hook::{HOOK_MANAGER, LAST_FOREGROUNDED}, + hook::HOOK_MANAGER, log_error, trace_lock, utils::{is_virtual_desktop_supported, is_windows_11}, winevent::WinEvent, @@ -169,13 +169,7 @@ impl WindowsApi { } } - /// this is a modified version of the original GetForegroundWindow function - /// used to handle last foregrounded window ignoring some windows pub fn get_foreground_window() -> HWND { - let foreground = LAST_FOREGROUNDED.load(std::sync::atomic::Ordering::Acquire); - if foreground != 0 { - return HWND(foreground); - } unsafe { GetForegroundWindow() } } @@ -741,23 +735,3 @@ impl WindowsApi { Self::extract_thumbnail_from_stream(stream.OpenReadAsync()?.get()?) } } - -/* -may be this is useful later - -static CHILD_FROM_FRAME: AtomicIsize = AtoumicIsize::new(0); -unsafe extern "system" fn enum_childs_uwp(hwnd: HWND, _: LPARAM) -> BOOL { - let exe = WindowsApi::exe(hwnd).unwrap_or_default(); - println!("enum_childs_uwp {} {}", hwnd.0, exe); - if exe != "ApplicationFrameHost.exe" { - CHILD_FROM_FRAME.store(hwnd.0, Ordering::SeqCst); - return false.into(); - } - true.into() -} - -pub fn get_child_from_frame_host(hwnd: HWND) -> HWND { - CHILD_FROM_FRAME.store(0, Ordering::SeqCst); - unsafe { EnumChildWindows(hwnd, Some(enum_childs_uwp), LPARAM(0)) }; - HWND(CHILD_FROM_FRAME.load(Ordering::SeqCst)) -} */ diff --git a/src/background/windows_api/window.rs b/src/background/windows_api/window.rs index 1dd1a374..58c6541e 100644 --- a/src/background/windows_api/window.rs +++ b/src/background/windows_api/window.rs @@ -63,9 +63,9 @@ impl Window { } pub fn children(&self) -> Result> { - let mut enumerator = WindowEnumerator::new(Some(self.0)); - enumerator.refresh()?; - Ok(enumerator.into_iter().map(Window).collect()) + WindowEnumerator::new() + .with_parent(self.0) + .map(Window::from) } pub fn is_visible(&self) -> bool { diff --git a/src/background/winevent.rs b/src/background/winevent.rs index 21441fa4..a522e4aa 100644 --- a/src/background/winevent.rs +++ b/src/background/winevent.rs @@ -316,7 +316,7 @@ impl WinEvent { return None; } - let fullscreened = trace_lock!(FULLSCREENED); + let mut fullscreened = trace_lock!(FULLSCREENED); if WindowsApi::is_fullscreen(origin).ok()? && !fullscreened.iter().any(|x| x.handle == origin) { @@ -324,7 +324,7 @@ impl WinEvent { handle: origin, monitor: WindowsApi::monitor_from_window(origin), }; - trace_lock!(FULLSCREENED).push(data); + fullscreened.push(data); Some(Self::SyntheticFullscreenStart(data)) } else { None