use windows::Win32::Foundation::{BOOL, HWND, LPARAM, TRUE};
use windows::Win32::UI::WindowsAndMessaging::{
EnumWindows, GetSystemMetrics, GetWindow, GetWindowLongW, GetWindowTextLengthW,
IsIconic, IsWindow, IsWindowVisible, SetWindowPos, ShowWindow,
GW_OWNER, GWL_EXSTYLE, SM_CXSCREEN, SM_CYSCREEN, SWP_FRAMECHANGED, SWP_NOZORDER,
SW_MAXIMIZE, SW_RESTORE, WS_EX_TOOLWINDOW,
};
pub struct WindowExpander {
expanded: Vec<HWND>,
}
impl WindowExpander {
pub fn new() -> Self {
Self {
expanded: Vec::new(),
}
}
pub fn is_expanded(&self) -> bool {
!self.expanded.is_empty()
}
pub fn expand_all(&mut self) -> Result<usize, String> {
if !self.expanded.is_empty() {
return Ok(0);
}
let (width, height) = full_screen_size()?;
let mut targets: Vec<HWND> = Vec::new();
unsafe {
let _ = EnumWindows(
Some(enum_windows_proc),
LPARAM(&mut targets as *mut Vec<HWND> as isize),
);
}
for hwnd in targets {
unsafe {
if !IsWindow(hwnd).as_bool() {
continue;
}
let _ = ShowWindow(hwnd, SW_RESTORE);
if SetWindowPos(hwnd, None, 0, 0, width, height, SWP_NOZORDER | SWP_FRAMECHANGED)
.is_ok()
{
self.expanded.push(hwnd);
}
}
}
Ok(self.expanded.len())
}
pub fn restore_all(&mut self) -> usize {
let mut restored = 0;
for hwnd in std::mem::take(&mut self.expanded) {
unsafe {
if IsWindow(hwnd).as_bool() {
let _ = ShowWindow(hwnd, SW_MAXIMIZE);
restored += 1;
}
}
}
restored
}
}
impl Drop for WindowExpander {
fn drop(&mut self) {
let _ = self.restore_all();
}
}
fn full_screen_size() -> Result<(i32, i32), String> {
let (width, height) = unsafe { (GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)) };
if width <= 0 || height <= 0 {
return Err("GetSystemMetrics returned invalid screen size.".to_string());
}
Ok((width, height))
}
unsafe extern "system" fn enum_windows_proc(hwnd: HWND, lparam: LPARAM) -> BOOL {
let targets = &mut *(lparam.0 as *mut Vec<HWND>);
if is_expandable(hwnd) {
targets.push(hwnd);
}
TRUE
}
fn is_expandable(hwnd: HWND) -> bool {
unsafe {
if !IsWindowVisible(hwnd).as_bool() || IsIconic(hwnd).as_bool() {
return false;
}
if GetWindowTextLengthW(hwnd) == 0 {
return false;
}
if GetWindow(hwnd, GW_OWNER).map(|o| !o.is_invalid()).unwrap_or(false) {
return false;
}
let ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE) as u32;
if ex_style & WS_EX_TOOLWINDOW.0 != 0 {
return false;
}
true
}
}