Skip to content

Commit

Permalink
fix: Retrieve active monitor before going full screen
Browse files Browse the repository at this point in the history
  • Loading branch information
core1024 committed Jan 13, 2025
1 parent aec176a commit 494be0a
Showing 1 changed file with 156 additions and 147 deletions.
303 changes: 156 additions & 147 deletions src/stremio_app/window_helper.rs
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);
}
}
}

0 comments on commit 494be0a

Please sign in to comment.