diff --git a/build.rs b/build.rs index 2721700..161ea3a 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,5 @@ -use std::env; use copy_to_output::copy_to_output; +use std::env; fn main() { copy_to_output("default.yaml", &env::var("PROFILE").unwrap()).expect("Could not copy"); diff --git a/src/appwindow.rs b/src/appwindow.rs index 27bfe04..ee58a95 100644 --- a/src/appwindow.rs +++ b/src/appwindow.rs @@ -1,6 +1,6 @@ use std::{ffi::c_void, sync::OnceLock}; -use log::{error, info}; +use log::{debug, error, info}; use windows::{ w, Win32::{ @@ -12,7 +12,8 @@ use windows::{ CreateWindowExW, DeregisterShellHookWindow, CHILDID_SELF, CREATESTRUCTA, CW_USEDEFAULT, EVENT_OBJECT_CLOAKED, EVENT_OBJECT_UNCLOAKED, EVENT_SYSTEM_MINIMIZEEND, EVENT_SYSTEM_MINIMIZESTART, GWLP_USERDATA, OBJID_WINDOW, - WINDOW_EX_STYLE, WM_CREATE, WM_DESTROY, WNDCLASSW, WS_OVERLAPPEDWINDOW, + WINDOW_EX_STYLE, WM_APP, WM_CREATE, WM_DESTROY, WM_USER, WNDCLASSW, + WS_OVERLAPPEDWINDOW, }, }, }, @@ -22,7 +23,9 @@ use grout_wm::Result; use crate::{ win32, - windowmanager::{WindowManager, WM_CLOAKED, WM_MINIMIZEEND, WM_MINIMIZESTART, WM_UNCLOAKED}, + windowmanager::{ + WindowManager, MSG_CLOAKED, MSG_MINIMIZEEND, MSG_MINIMIZESTART, MSG_UNCLOAKED, + }, }; static MY_HWND: OnceLock = OnceLock::new(); @@ -139,16 +142,17 @@ impl AppWindow { return; } if let Some(&my_hwnd) = MY_HWND.get() { - if event == EVENT_SYSTEM_MINIMIZEEND { - win32::post_message(my_hwnd, WM_MINIMIZEEND, WPARAM(0), LPARAM(hwnd.0)); - } - if event == EVENT_SYSTEM_MINIMIZESTART { - win32::post_message(my_hwnd, WM_MINIMIZESTART, WPARAM(0), LPARAM(hwnd.0)); - } - if event == EVENT_OBJECT_UNCLOAKED { - win32::post_message(my_hwnd, WM_UNCLOAKED, WPARAM(0), LPARAM(hwnd.0)); - } else if event == EVENT_OBJECT_CLOAKED { - win32::post_message(my_hwnd, WM_CLOAKED, WPARAM(0), LPARAM(hwnd.0)); + debug!("event: {event}"); + let msg = match event { + EVENT_OBJECT_CLOAKED => MSG_CLOAKED, + EVENT_OBJECT_UNCLOAKED => MSG_UNCLOAKED, + EVENT_SYSTEM_MINIMIZEEND => MSG_MINIMIZEEND, + EVENT_SYSTEM_MINIMIZESTART => MSG_MINIMIZESTART, + _ => event, + }; + debug!("msg: {msg}"); + if msg >= WM_USER || msg < WM_APP { + win32::post_message(my_hwnd, msg, WPARAM(0), LPARAM(hwnd.0)); } } } @@ -160,7 +164,7 @@ impl AppWindow { win32::post_quit_message(0); LRESULT(0) } - WM_CREATE=> { + WM_CREATE => { info!("Creating application window"); let create_struct = lparam.0 as *const CREATESTRUCTA; let wm = unsafe { (*create_struct).lpCreateParams as *mut WindowManager }; diff --git a/src/config.rs b/src/config.rs index 294879f..ed7f98b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ -use std::env; -use serde::{Deserialize, Serialize}; use log::info; +use serde::{Deserialize, Serialize}; +use std::env; #[derive(Deserialize, Serialize)] pub struct Config { diff --git a/src/lib.rs b/src/lib.rs index b4c040a..9865328 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,17 @@ +#[macro_export] +macro_rules! any { + ($xs:expr, $x:expr) => { + $xs.iter().any(|&x| x.0 == $x) + }; +} + +#[macro_export] +macro_rules! has_flag { + ($value:expr, $flag:expr) => { + ($value & $flag) != 0 + }; +} + pub struct Error { pub(crate) message: String, } @@ -19,13 +33,17 @@ impl std::fmt::Display for Error { impl std::convert::From<&str> for Error { fn from(err: &str) -> Self { - Error { message: String::from(err) } + Error { + message: String::from(err), + } } } impl std::convert::From for Error { fn from(err: windows::core::Error) -> Self { - Error { message: err.to_string() } + Error { + message: err.to_string(), + } } } diff --git a/src/main.rs b/src/main.rs index 03daec5..3bb9cfc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,11 +13,11 @@ mod window; mod windowmanager; use crate::appwindow::AppWindow; -use crate::windowmanager::WindowManager; use crate::config::Config; +use crate::windowmanager::WindowManager; fn main() -> Result<()> { - let mutex_handle = win32::get_mutex().unwrap_or_else(|_e|{ + let mutex_handle = win32::get_mutex().unwrap_or_else(|_e| { error!("Can't run multiple instances"); std::process::exit(1); }); diff --git a/src/win32.rs b/src/win32.rs index af87a5e..de1ecb7 100644 --- a/src/win32.rs +++ b/src/win32.rs @@ -17,27 +17,29 @@ use windows::{ DWM_CLOAKED_SHELL, }, System::{ + Com::{CoCreateInstance, CoInitialize, CoUninitialize, CLSCTX_ALL}, LibraryLoader::GetModuleHandleA, ProcessStatus::{ EnumProcessModules, GetModuleBaseNameW, GetModuleInformation, MODULEINFO, }, Threading::{ CreateMutexW, OpenProcess, ReleaseMutex, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ, - }, Com::{CoUninitialize, CoInitialize, CLSCTX_ALL, CoCreateInstance}, + }, }, UI::{ Accessibility::{SetWinEventHook, HWINEVENTHOOK, WINEVENTPROC}, + Shell::{IVirtualDesktopManager, VirtualDesktopManager as VirtualDesktopManager_ID}, WindowsAndMessaging::{ - DefWindowProcW, EnumWindows, FindWindowW, GetClassNameW, GetParent, - GetSystemMetrics, GetWindow, GetWindowLongPtrW, GetWindowTextLengthW, - GetWindowTextW, GetWindowThreadProcessId, IsIconic, IsWindowVisible, PostMessageW, - PostQuitMessage, RegisterClassW, RegisterShellHookWindow, RegisterWindowMessageW, - SetWindowLongPtrW, SetWindowPos, ShowWindow, SystemParametersInfoW, GET_WINDOW_CMD, - GWL_EXSTYLE, GWL_STYLE, HWND_TOP, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, - SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, SPI_GETWORKAREA, SWP_NOACTIVATE, - SW_SHOWMINNOACTIVE, SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, WINDOW_LONG_PTR_INDEX, - WINEVENT_OUTOFCONTEXT, WNDCLASSW, WNDENUMPROC, - }, Shell::{IVirtualDesktopManager, VirtualDesktopManager as VirtualDesktopManager_ID}, + DefWindowProcW, EnumWindows, FindWindowW, GetClassNameW, GetSystemMetrics, + GetWindow, GetWindowLongPtrW, GetWindowTextLengthW, GetWindowTextW, + GetWindowThreadProcessId, IsIconic, IsWindowVisible, PostMessageW, PostQuitMessage, + RegisterClassW, RegisterShellHookWindow, RegisterWindowMessageW, SetWindowLongPtrW, + SetWindowPos, ShowWindow, SystemParametersInfoW, GET_WINDOW_CMD, GWL_EXSTYLE, + GWL_STYLE, HWND_TOP, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, + SM_YVIRTUALSCREEN, SPI_GETWORKAREA, SWP_NOACTIVATE, SW_SHOWMINNOACTIVE, + SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, WINDOW_LONG_PTR_INDEX, WINEVENT_OUTOFCONTEXT, + WNDCLASSW, WNDENUMPROC, + }, }, }, }; @@ -49,7 +51,9 @@ pub struct Win32Com; impl Win32Com { pub fn new() -> Result { info!("Initialize COM"); - unsafe { CoInitialize(None)?; } + unsafe { + CoInitialize(None)?; + } Ok(Win32Com) } } @@ -57,7 +61,9 @@ impl Win32Com { impl Drop for Win32Com { fn drop(&mut self) { info!("Uninitializing COM"); - unsafe { CoUninitialize(); } + unsafe { + CoUninitialize(); + } } } pub fn is_cloaked(hwnd: HWND) -> bool { @@ -83,10 +89,6 @@ pub fn is_iconic(hwnd: HWND) -> bool { unsafe { IsIconic(hwnd).into() } } -pub fn get_parent(hwnd: HWND) -> HWND { - unsafe { GetParent(hwnd) } -} - pub fn get_window_long_ptr(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize { unsafe { GetWindowLongPtrW(hwnd, nindex) } } @@ -284,7 +286,9 @@ pub struct VirtualDesktopManager(IVirtualDesktopManager); impl VirtualDesktopManager { pub fn new() -> Result { info!("Instanciate VirtualDesktopManager"); - unsafe { CoInitialize(None)?; } + unsafe { + CoInitialize(None)?; + } let virtual_desktop_managr = unsafe { CoCreateInstance(&VirtualDesktopManager_ID, None, CLSCTX_ALL)? }; Ok(Self(virtual_desktop_managr)) diff --git a/src/window.rs b/src/window.rs index 624a9dc..a695941 100644 --- a/src/window.rs +++ b/src/window.rs @@ -5,33 +5,48 @@ use windows::Win32::Foundation::HWND; use crate::win32; #[derive(Clone, Copy)] -pub struct Window { - pub hwnd: HWND, - pub minimized: bool, - pub selected: bool, -} +pub struct Window(pub HWND); impl Window { pub fn new(hwnd: HWND) -> Self { - Window { - hwnd, - minimized: Default::default(), - selected: Default::default(), - } + Window(hwnd) + } + + pub fn is_iconic(&self) -> bool { + win32::is_iconic(self.0) + } + + pub fn title(&self) -> String { + win32::get_window_text(self.0) + } + + pub fn class_name(&self) -> String { + win32::get_window_classname(self.0) + } + + pub fn exstyle(&self) -> u32 { + win32::get_window_exstyle(self.0) + } + + pub fn style(&self) -> u32 { + win32::get_window_style(self.0) + } + + pub fn process_name(&self) -> String { + win32::get_exe_filename(self.0).unwrap_or("".to_owned()) } } impl fmt::Debug for Window { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Window") - .field("hwnd", &self.hwnd) - .field("title", &win32::get_window_text(self.hwnd)) - .field("class", &win32::get_window_classname(self.hwnd)) - .field("minimized", &self.minimized) - .field("parent", &win32::get_parent(self.hwnd)) - .field("ex_style", &win32::get_window_exstyle(self.hwnd)) - .field("style", &win32::get_window_style(self.hwnd)) - .field("process", &win32::get_exe_filename(self.hwnd)) + .field("hwnd", &self.0) + .field("title", &self.title()) + .field("class", &self.class_name()) + .field("minimized", &self.is_iconic()) + .field("ex_style", &self.exstyle()) + .field("style", &self.style()) + .field("process", &self.process_name()) .finish() } } diff --git a/src/windowmanager.rs b/src/windowmanager.rs index 0e4f218..fdbf549 100644 --- a/src/windowmanager.rs +++ b/src/windowmanager.rs @@ -7,25 +7,18 @@ use windows::Win32::{ }, }; -use grout_wm::Result; -use crate::{arrange::spiral_subdivide, config::Config, win32::{self, VirtualDesktopManager}, window::Window}; - -macro_rules! any { - ($xs:expr, $x:expr) => { - $xs.iter().any(|&x| x.hwnd == $x) - }; -} - -macro_rules! has_flag { - ($value:expr, $flag:expr) => { - ($value & $flag) != 0 - }; -} +use crate::{ + arrange::spiral_subdivide, + config::Config, + win32::{self, VirtualDesktopManager}, + window::Window, +}; +use grout_wm::{any, has_flag, Result}; -pub const WM_UNCLOAKED: u32 = WM_USER + 0x0001; -pub const WM_CLOAKED: u32 = WM_USER + 0x0002; -pub const WM_MINIMIZEEND: u32 = WM_USER + 0x0004; -pub const WM_MINIMIZESTART: u32 = WM_USER + 0x0008; +pub const MSG_UNCLOAKED: u32 = WM_USER; +pub const MSG_CLOAKED: u32 = WM_USER + 0x0001; +pub const MSG_MINIMIZEEND: u32 = WM_USER + 0x0003; +pub const MSG_MINIMIZESTART: u32 = WM_USER + 0x0004; pub struct WindowManager { managed_windows: Vec, @@ -50,10 +43,7 @@ impl WindowManager { } fn get_window(&mut self, hwnd: HWND) -> Option { - self.managed_windows - .iter() - .find(|w| w.hwnd == hwnd) - .copied() + self.managed_windows.iter().find(|w| w.0 == hwnd).copied() } pub fn manage(&mut self, hwnd: HWND) -> Option { @@ -93,20 +83,20 @@ impl WindowManager { if class_name.contains("Windows.UI.Core.CoreWindow") && titles.iter().any(|t| title.contains(t)) { - info!("Window {title} is not suitable to manage"); + info!("Window {title} is not suitable to manage"); return false; } } if let Some(classes) = &self.config.class_names { if classes.iter().any(|cn| class_name.contains(cn)) { - info!("Window {title} is not suitable to manage"); + info!("Window {title} is not suitable to manage"); return false; } } if let Some(processes) = &self.config.process_names { if let Some(process_name) = process_name { if processes.iter().any(|p| process_name.contains(p)) { - info!("Window {title} is not suitable to manage"); + info!("Window {title} is not suitable to manage"); return false; } } @@ -124,12 +114,15 @@ impl WindowManager { fn unmanage(&mut self, hwnd: HWND) { if !any!(self.managed_windows, hwnd) { - return + return; } - let is_on_desktop = self.virtual_desktop.is_window_on_current_desktop(hwnd).unwrap_or(false); + let is_on_desktop = self + .virtual_desktop + .is_window_on_current_desktop(hwnd) + .unwrap_or(false); if is_on_desktop { info!("unmanage {:#?}", self.get_window(hwnd)); - self.managed_windows.retain(|w| w.hwnd != hwnd); + self.managed_windows.retain(|w| w.0 != hwnd); } } @@ -138,17 +131,17 @@ impl WindowManager { .managed_windows .clone() .into_iter() + .filter(|w| !w.is_iconic()) .filter(|w| { - let min = win32::is_iconic(w.hwnd); - // let visible = win32::is_window_visible(w.hwnd); - let is_on_desktop = self.virtual_desktop.is_window_on_current_desktop(w.hwnd).unwrap_or(false); - !min && is_on_desktop + self.virtual_desktop + .is_window_on_current_desktop(w.0) + .unwrap_or(false) }) .collect(); let number_of_windows = windows_on_screen.len(); let ds = spiral_subdivide(self.working_area, number_of_windows); for (w, d) in windows_on_screen.iter().zip(ds.iter()) { - win32::set_window_pos(w.hwnd, *d); + win32::set_window_pos(w.0, *d); } } @@ -163,7 +156,7 @@ impl WindowManager { let managed_window = self.get_window(handle); let wmsg = wparam.0 as u32 & 0x7FFF; match (msg, wmsg) { - (WM_CLOAKED, _) => { + (MSG_CLOAKED, _) => { if managed_window.is_some() { debug!("Cloaked: {managed_window:#?}"); self.unmanage(handle); @@ -171,32 +164,27 @@ impl WindowManager { self.arrange(); } } - (WM_UNCLOAKED, _) => { + (MSG_UNCLOAKED, _) => { if managed_window.is_none() && self.is_manageable(handle) { debug!("{handle:?} is uncloaked"); self.manage(handle); self.arrange(); } } - (WM_MINIMIZEEND, _) => { - if let Some(index) = self.managed_windows.iter().position(|&w| w.hwnd == handle) { + (MSG_MINIMIZEEND, _) => { + if let Some(index) = self.managed_windows.iter().position(|&w| w.0 == handle) { let sel = &mut self.managed_windows[index]; debug!("Restored: {sel:#?}"); - sel.minimized = false; self.arrange(); } } - (WM_MINIMIZESTART, _) => { + (MSG_MINIMIZESTART, _) => { if managed_window.is_some() { - if let Some(index) = self.managed_windows.iter().position(|&w| w.hwnd == handle) - { - let t = &mut self.managed_windows[index]; - debug!("Minimized {managed_window:#?}"); - t.minimized = win32::is_iconic(t.hwnd); - if t.minimized { - self.arrange(); - } - } + debug!( + "Minimized + {managed_window:#?}" + ); + self.arrange(); } } (id, HSHELL_WINDOWCREATED) if id == self.shell_hook_id => {