Skip to content

Commit

Permalink
perf(enum): improvements on windows enumerator helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
eythaann committed Aug 29, 2024
1 parent c24aeec commit adec6dc
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 105 deletions.
12 changes: 5 additions & 7 deletions src/background/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ lazy_static! {
pub static ref HOOK_MANAGER: Arc<Mutex<HookManager>> = Arc::new(Mutex::new(HookManager::new()));
}

pub static LAST_FOREGROUNDED: AtomicIsize = AtomicIsize::new(0);

pub struct HookManager {
skip: HashMap<isize, Vec<WinEvent>>,
}
Expand Down Expand Up @@ -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 || {
Expand Down
4 changes: 2 additions & 2 deletions src/background/modules/virtual_desk/workspaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

Expand Down
43 changes: 18 additions & 25 deletions src/background/seelen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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! {
Expand Down Expand Up @@ -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(())
}
Expand Down Expand Up @@ -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()
}
}
2 changes: 0 additions & 2 deletions src/background/seelen_weg/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(());
Expand Down
5 changes: 1 addition & 4 deletions src/background/utils/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
91 changes: 58 additions & 33 deletions src/background/windows_api/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,87 @@ 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};

#[derive(Debug, Clone)]
pub struct WindowEnumerator {
parent: Option<HWND>,
handles: Vec<HWND>,
}

impl IntoIterator for WindowEnumerator {
type Item = HWND;
type IntoIter = std::vec::IntoIter<HWND>;
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<HWND>) -> 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<Self> {
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<F>(&self, cb: F) -> Result<()>
where
F: FnMut(HWND) + Sync,
{
type ForEachCallback<'a> = Box<dyn FnMut(HWND) + 'a>;
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<HWND>;
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<F, T>(&self, cb: F) -> Result<Vec<T>>
where
F: FnMut(HWND) -> T + Sync,
T: Sync,
{
type MapCallback<'a, T> = Box<dyn FnMut(HWND) -> T + 'a>;
struct MapCallbackWrapper<'a, T> {
cb: MapCallback<'a, T>,
processed: Vec<T>,
}

unsafe extern "system" fn enum_proc<T>(hwnd: HWND, lparam: LPARAM) -> BOOL {
if let Some(wrapper) = (lparam.0 as *mut MapCallbackWrapper<T>).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::<T>, LPARAM(ptr))?;
Ok(wrapper.processed)
}
}

Expand Down
28 changes: 1 addition & 27 deletions src/background/windows_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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() }
}

Expand Down Expand Up @@ -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))
} */
6 changes: 3 additions & 3 deletions src/background/windows_api/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ impl Window {
}

pub fn children(&self) -> Result<Vec<Window>> {
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 {
Expand Down
4 changes: 2 additions & 2 deletions src/background/winevent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,15 +316,15 @@ 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)
{
let data = SyntheticFullscreenData {
handle: origin,
monitor: WindowsApi::monitor_from_window(origin),
};
trace_lock!(FULLSCREENED).push(data);
fullscreened.push(data);
Some(Self::SyntheticFullscreenStart(data))
} else {
None
Expand Down

0 comments on commit adec6dc

Please sign in to comment.