diff --git a/src/stremio_app/window_helper.rs b/src/stremio_app/window_helper.rs index 281882f..68c5547 100644 --- a/src/stremio_app/window_helper.rs +++ b/src/stremio_app/window_helper.rs @@ -1,147 +1,156 @@ -use std::{cmp, mem}; -use winapi::shared::windef::HWND; -use winapi::um::winuser::{ - GetForegroundWindow, GetSystemMetrics, GetWindowLongA, GetWindowRect, IsIconic, IsZoomed, - SetForegroundWindow, SetWindowLongA, SetWindowPos, GWL_EXSTYLE, GWL_STYLE, HWND_NOTOPMOST, - HWND_TOPMOST, SM_CXSCREEN, SM_CYSCREEN, SWP_FRAMECHANGED, SWP_NOMOVE, SWP_NOSIZE, WS_CAPTION, - WS_EX_CLIENTEDGE, WS_EX_DLGMODALFRAME, WS_EX_STATICEDGE, WS_EX_TOPMOST, WS_EX_WINDOWEDGE, - WS_THICKFRAME, -}; -// https://doc.qt.io/qt-5/qt.html#WindowState-enum -bitflags! { - struct WindowState: u8 { - const MINIMIZED = 0x01; - const MAXIMIZED = 0x02; - const FULL_SCREEN = 0x04; - const ACTIVE = 0x08; - } -} - -#[derive(Default, Clone)] -pub struct WindowStyle { - pub full_screen: bool, - pub pos: (i32, i32), - pub size: (i32, i32), - pub style: i32, - pub ex_style: i32, -} - -impl WindowStyle { - pub fn get_window_state(self, hwnd: HWND) -> u32 { - let mut state: WindowState = WindowState::empty(); - if 0 != unsafe { IsIconic(hwnd) } { - state |= WindowState::MINIMIZED; - } - if 0 != unsafe { IsZoomed(hwnd) } { - state |= WindowState::MAXIMIZED; - } - if hwnd == unsafe { GetForegroundWindow() } { - state |= WindowState::ACTIVE - } - if self.full_screen { - state |= WindowState::FULL_SCREEN; - } - state.bits() as u32 - } - pub fn is_window_minimized(&self, hwnd: HWND) -> bool { - 0 != unsafe { IsIconic(hwnd) } - } - pub fn show_window_at(&self, hwnd: HWND, pos: HWND) { - unsafe { - SetWindowPos( - hwnd, - pos, - self.pos.0, - self.pos.1, - self.size.0, - self.size.1, - SWP_FRAMECHANGED, - ); - } - } - pub fn center_window(&mut self, hwnd: HWND, min_width: i32, min_height: i32) { - let monitor_w = unsafe { GetSystemMetrics(SM_CXSCREEN) }; - let monitor_h = unsafe { GetSystemMetrics(SM_CYSCREEN) }; - let small_side = cmp::min(monitor_w, monitor_h) * 70 / 100; - self.size = ( - cmp::max(small_side * 16 / 9, min_width), - cmp::max(small_side, min_height), - ); - self.pos = ((monitor_w - self.size.0) / 2, (monitor_h - self.size.1) / 2); - self.show_window_at(hwnd, HWND_NOTOPMOST); - } - pub fn toggle_full_screen(&mut self, hwnd: HWND) { - if self.full_screen { - let topmost = if self.ex_style as u32 & WS_EX_TOPMOST == WS_EX_TOPMOST { - HWND_TOPMOST - } else { - HWND_NOTOPMOST - }; - unsafe { - SetWindowLongA(hwnd, GWL_STYLE, self.style); - SetWindowLongA(hwnd, GWL_EXSTYLE, self.ex_style); - } - self.show_window_at(hwnd, topmost); - self.full_screen = false; - } else { - unsafe { - let mut rect = mem::zeroed(); - GetWindowRect(hwnd, &mut rect); - self.pos = (rect.left, rect.top); - self.size = ((rect.right - rect.left), (rect.bottom - rect.top)); - self.style = GetWindowLongA(hwnd, GWL_STYLE); - self.ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE); - SetWindowLongA( - hwnd, - GWL_STYLE, - self.style & !(WS_CAPTION as i32 | WS_THICKFRAME as i32), - ); - SetWindowLongA( - hwnd, - GWL_EXSTYLE, - self.ex_style - & !(WS_EX_DLGMODALFRAME as i32 - | WS_EX_WINDOWEDGE as i32 - | WS_EX_CLIENTEDGE as i32 - | WS_EX_STATICEDGE as i32), - ); - SetWindowPos( - hwnd, - HWND_NOTOPMOST, - 0, - 0, - GetSystemMetrics(SM_CXSCREEN), - GetSystemMetrics(SM_CYSCREEN), - SWP_FRAMECHANGED, - ); - } - self.full_screen = true; - } - } - pub fn toggle_topmost(&mut self, hwnd: HWND) { - let topmost = if unsafe { GetWindowLongA(hwnd, GWL_EXSTYLE) } as u32 & WS_EX_TOPMOST - == WS_EX_TOPMOST - { - HWND_NOTOPMOST - } else { - HWND_TOPMOST - }; - unsafe { - SetWindowPos( - hwnd, - topmost, - 0, - 0, - 0, - 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED, - ); - } - self.ex_style = unsafe { GetWindowLongA(hwnd, GWL_EXSTYLE) }; - } - pub fn set_active(&mut self, hwnd: HWND) { - unsafe { - SetForegroundWindow(hwnd); - } - } -} +use std::{cmp, mem}; +use winapi::shared::windef::HWND; +use winapi::um::winuser::{ + GetForegroundWindow, GetMonitorInfoA, GetSystemMetrics, GetWindowLongA, GetWindowRect, + IsIconic, IsZoomed, MonitorFromWindow, SetForegroundWindow, SetWindowLongA, SetWindowPos, + GWL_EXSTYLE, GWL_STYLE, HWND_NOTOPMOST, HWND_TOPMOST, MONITORINFO, MONITOR_DEFAULTTONEAREST, + SM_CXSCREEN, SM_CYSCREEN, SWP_FRAMECHANGED, SWP_NOMOVE, SWP_NOSIZE, WS_CAPTION, + WS_EX_CLIENTEDGE, WS_EX_DLGMODALFRAME, WS_EX_STATICEDGE, WS_EX_TOPMOST, WS_EX_WINDOWEDGE, + WS_THICKFRAME, +}; +// https://doc.qt.io/qt-5/qt.html#WindowState-enum +bitflags! { + struct WindowState: u8 { + const MINIMIZED = 0x01; + const MAXIMIZED = 0x02; + const FULL_SCREEN = 0x04; + const ACTIVE = 0x08; + } +} + +#[derive(Default, Clone)] +pub struct WindowStyle { + pub full_screen: bool, + pub pos: (i32, i32), + pub size: (i32, i32), + pub style: i32, + pub ex_style: i32, +} + +impl WindowStyle { + pub fn get_window_state(self, hwnd: HWND) -> u32 { + let mut state: WindowState = WindowState::empty(); + if 0 != unsafe { IsIconic(hwnd) } { + state |= WindowState::MINIMIZED; + } + if 0 != unsafe { IsZoomed(hwnd) } { + state |= WindowState::MAXIMIZED; + } + if hwnd == unsafe { GetForegroundWindow() } { + state |= WindowState::ACTIVE + } + if self.full_screen { + state |= WindowState::FULL_SCREEN; + } + state.bits() as u32 + } + pub fn is_window_minimized(&self, hwnd: HWND) -> bool { + 0 != unsafe { IsIconic(hwnd) } + } + pub fn show_window_at(&self, hwnd: HWND, pos: HWND) { + unsafe { + SetWindowPos( + hwnd, + pos, + self.pos.0, + self.pos.1, + self.size.0, + self.size.1, + SWP_FRAMECHANGED, + ); + } + } + pub fn center_window(&mut self, hwnd: HWND, min_width: i32, min_height: i32) { + let monitor_w = unsafe { GetSystemMetrics(SM_CXSCREEN) }; + let monitor_h = unsafe { GetSystemMetrics(SM_CYSCREEN) }; + let small_side = cmp::min(monitor_w, monitor_h) * 70 / 100; + self.size = ( + cmp::max(small_side * 16 / 9, min_width), + cmp::max(small_side, min_height), + ); + self.pos = ((monitor_w - self.size.0) / 2, (monitor_h - self.size.1) / 2); + self.show_window_at(hwnd, HWND_NOTOPMOST); + } + pub fn toggle_full_screen(&mut self, hwnd: HWND) { + if self.full_screen { + let topmost = if self.ex_style as u32 & WS_EX_TOPMOST == WS_EX_TOPMOST { + HWND_TOPMOST + } else { + HWND_NOTOPMOST + }; + unsafe { + SetWindowLongA(hwnd, GWL_STYLE, self.style); + SetWindowLongA(hwnd, GWL_EXSTYLE, self.ex_style); + } + self.show_window_at(hwnd, topmost); + self.full_screen = false; + } else { + unsafe { + let mut rect = mem::zeroed(); + GetWindowRect(hwnd, &mut rect); + self.pos = (rect.left, rect.top); + self.size = ((rect.right - rect.left), (rect.bottom - rect.top)); + self.style = GetWindowLongA(hwnd, GWL_STYLE); + self.ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE); + + let monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + let mut monitor_info: MONITORINFO = mem::zeroed(); + monitor_info.cbSize = mem::size_of_val(&monitor_info) as u32; + if GetMonitorInfoA(monitor, &mut monitor_info) == 0 { + println!("GetMonitorInfoA failed"); + return; + } + SetWindowLongA( + hwnd, + GWL_STYLE, + self.style & !(WS_CAPTION as i32 | WS_THICKFRAME as i32), + ); + SetWindowLongA( + hwnd, + GWL_EXSTYLE, + self.ex_style + & !(WS_EX_DLGMODALFRAME as i32 + | WS_EX_WINDOWEDGE as i32 + | WS_EX_CLIENTEDGE as i32 + | WS_EX_STATICEDGE as i32), + ); + SetWindowPos( + hwnd, + HWND_NOTOPMOST, + monitor_info.rcMonitor.left, + monitor_info.rcMonitor.top, + monitor_info.rcMonitor.right - monitor_info.rcMonitor.left, + monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top, + SWP_FRAMECHANGED, + ); + } + self.full_screen = true; + } + } + pub fn toggle_topmost(&mut self, hwnd: HWND) { + let topmost = if unsafe { GetWindowLongA(hwnd, GWL_EXSTYLE) } as u32 & WS_EX_TOPMOST + == WS_EX_TOPMOST + { + HWND_NOTOPMOST + } else { + HWND_TOPMOST + }; + unsafe { + SetWindowPos( + hwnd, + topmost, + 0, + 0, + 0, + 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED, + ); + } + self.ex_style = unsafe { GetWindowLongA(hwnd, GWL_EXSTYLE) }; + } + pub fn set_active(&mut self, hwnd: HWND) { + unsafe { + SetForegroundWindow(hwnd); + } + } +}