-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Retrieve active monitor before going full screen
- Loading branch information
Showing
1 changed file
with
156 additions
and
147 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} | ||
} |