mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
On Windows, fix window shrinking when leaving fullscreen in some situations (#718)
* Fix resize border appearing in some cases after leaving fullscreen. * On fullscreen, save client rect instead of window rect * Add CHANGELOG entry * Revert test changes to fullscreen example * Update panic message when unable to get client area
This commit is contained in:
parent
92873b06ed
commit
aabf0e13b7
|
@ -5,6 +5,7 @@
|
||||||
- On Windows, catch panics in event loop child thread and forward them to the parent thread. This prevents an invocation of undefined behavior due to unwinding into foreign code.
|
- On Windows, catch panics in event loop child thread and forward them to the parent thread. This prevents an invocation of undefined behavior due to unwinding into foreign code.
|
||||||
- On Windows, fix issue where resizing or moving window combined with grabbing the cursor would freeze program.
|
- On Windows, fix issue where resizing or moving window combined with grabbing the cursor would freeze program.
|
||||||
- On Windows, fix issue where resizing or moving window would eat `Awakened` events.
|
- On Windows, fix issue where resizing or moving window would eat `Awakened` events.
|
||||||
|
- On Windows, exiting fullscreen after entering fullscreen with disabled decorations no longer shrinks window.
|
||||||
- On X11, fixed a segfault when using virtual monitors with XRandR.
|
- On X11, fixed a segfault when using virtual monitors with XRandR.
|
||||||
- Derive `Ord` and `PartialOrd` for `VirtualKeyCode` enum.
|
- Derive `Ord` and `PartialOrd` for `VirtualKeyCode` enum.
|
||||||
- On Windows, fix issue where hovering or dropping a non file item would create a panic.
|
- On Windows, fix issue where hovering or dropping a non file item would create a panic.
|
||||||
|
|
|
@ -72,7 +72,7 @@ pub struct SavedWindowInfo {
|
||||||
/// Window ex-style
|
/// Window ex-style
|
||||||
pub ex_style: LONG,
|
pub ex_style: LONG,
|
||||||
/// Window position and size
|
/// Window position and size
|
||||||
pub rect: RECT,
|
pub client_rect: RECT,
|
||||||
// Since a window can be fullscreened to a different monitor, a DPI change can be triggered. This could result in
|
// Since a window can be fullscreened to a different monitor, a DPI change can be triggered. This could result in
|
||||||
// the window being automitcally resized to smaller/larger than it was supposed to be restored to, so we thus must
|
// the window being automitcally resized to smaller/larger than it was supposed to be restored to, so we thus must
|
||||||
// check if the post-fullscreen DPI matches the pre-fullscreen DPI.
|
// check if the post-fullscreen DPI matches the pre-fullscreen DPI.
|
||||||
|
|
|
@ -55,6 +55,19 @@ pub fn get_window_rect(hwnd: HWND) -> Option<RECT> {
|
||||||
unsafe { status_map(|rect| winuser::GetWindowRect(hwnd, rect)) }
|
unsafe { status_map(|rect| winuser::GetWindowRect(hwnd, rect)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_client_rect(hwnd: HWND) -> Option<RECT> {
|
||||||
|
unsafe { status_map(|rect| {
|
||||||
|
let mut top_left = mem::zeroed();
|
||||||
|
if 0 == winuser::ClientToScreen(hwnd, &mut top_left) {return 0;};
|
||||||
|
if 0 == winuser::GetClientRect(hwnd, rect) {return 0};
|
||||||
|
rect.left += top_left.x;
|
||||||
|
rect.top += top_left.y;
|
||||||
|
rect.right += top_left.x;
|
||||||
|
rect.bottom += top_left.y;
|
||||||
|
1
|
||||||
|
}) }
|
||||||
|
}
|
||||||
|
|
||||||
// This won't be needed anymore if we just add a derive to winapi.
|
// This won't be needed anymore if we just add a derive to winapi.
|
||||||
pub fn rect_eq(a: &RECT, b: &RECT) -> bool {
|
pub fn rect_eq(a: &RECT, b: &RECT) -> bool {
|
||||||
let left_eq = a.left == b.left;
|
let left_eq = a.left == b.left;
|
||||||
|
|
|
@ -49,28 +49,6 @@ pub struct Window {
|
||||||
events_loop_proxy: events_loop::EventsLoopProxy,
|
events_loop_proxy: events_loop::EventsLoopProxy,
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://blogs.msdn.microsoft.com/oldnewthing/20131017-00/?p=2903
|
|
||||||
// The idea here is that we use the AdjustWindowRectEx function to calculate how much additional
|
|
||||||
// non-client area gets added due to the styles we passed. To make the math simple,
|
|
||||||
// we ask for a zero client rectangle, so that the resulting window is all non-client.
|
|
||||||
// And then we pass in the empty rectangle represented by the dot in the middle,
|
|
||||||
// and the AdjustWindowRectEx expands the rectangle in all dimensions.
|
|
||||||
// We see that it added ten pixels to the left, right, and bottom,
|
|
||||||
// and it added fifty pixels to the top.
|
|
||||||
// From this we can perform the reverse calculation: Instead of expanding the rectangle, we shrink it.
|
|
||||||
unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> BOOL {
|
|
||||||
let mut rc: RECT = mem::uninitialized();
|
|
||||||
winuser::SetRectEmpty(&mut rc);
|
|
||||||
let status = winuser::AdjustWindowRectEx(&mut rc, style, 0, ex_style);
|
|
||||||
if status != 0 {
|
|
||||||
prc.left -= rc.left;
|
|
||||||
prc.top -= rc.top;
|
|
||||||
prc.right -= rc.right;
|
|
||||||
prc.bottom -= rc.bottom;
|
|
||||||
}
|
|
||||||
status
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
events_loop: &EventsLoop,
|
events_loop: &EventsLoop,
|
||||||
|
@ -477,12 +455,12 @@ impl Window {
|
||||||
|
|
||||||
unsafe fn set_fullscreen_style(&self, window_state: &mut WindowState) -> (LONG, LONG) {
|
unsafe fn set_fullscreen_style(&self, window_state: &mut WindowState) -> (LONG, LONG) {
|
||||||
if window_state.fullscreen.is_none() || window_state.saved_window_info.is_none() {
|
if window_state.fullscreen.is_none() || window_state.saved_window_info.is_none() {
|
||||||
let rect = util::get_window_rect(self.window.0).expect("`GetWindowRect` failed");
|
let client_rect = util::get_client_rect(self.window.0).expect("client rect retrieval failed");
|
||||||
let dpi_factor = Some(window_state.dpi_factor);
|
let dpi_factor = Some(window_state.dpi_factor);
|
||||||
window_state.saved_window_info = Some(events_loop::SavedWindowInfo {
|
window_state.saved_window_info = Some(events_loop::SavedWindowInfo {
|
||||||
style: winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE),
|
style: winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE),
|
||||||
ex_style: winuser::GetWindowLongW(self.window.0, winuser::GWL_EXSTYLE),
|
ex_style: winuser::GetWindowLongW(self.window.0, winuser::GWL_EXSTYLE),
|
||||||
rect,
|
client_rect,
|
||||||
is_fullscreen: true,
|
is_fullscreen: true,
|
||||||
dpi_factor,
|
dpi_factor,
|
||||||
});
|
});
|
||||||
|
@ -499,7 +477,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn restore_saved_window(&self, window_state_lock: &mut WindowState) {
|
unsafe fn restore_saved_window(&self, window_state_lock: &mut WindowState) {
|
||||||
let (rect, mut style, ex_style) = {
|
let (client_rect, mut style, ex_style) = {
|
||||||
// 'saved_window_info' can be None if the window has never been
|
// 'saved_window_info' can be None if the window has never been
|
||||||
// in fullscreen mode before this method gets called.
|
// in fullscreen mode before this method gets called.
|
||||||
if window_state_lock.saved_window_info.is_none() {
|
if window_state_lock.saved_window_info.is_none() {
|
||||||
|
@ -513,14 +491,15 @@ impl Window {
|
||||||
// repainted. Better-looking methods welcome.
|
// repainted. Better-looking methods welcome.
|
||||||
saved_window_info.is_fullscreen = false;
|
saved_window_info.is_fullscreen = false;
|
||||||
|
|
||||||
let rect = saved_window_info.rect.clone();
|
let client_rect = saved_window_info.client_rect.clone();
|
||||||
let (style, ex_style) = (saved_window_info.style, saved_window_info.ex_style);
|
let (style, ex_style) = (saved_window_info.style, saved_window_info.ex_style);
|
||||||
(rect, style, ex_style)
|
(client_rect, style, ex_style)
|
||||||
};
|
};
|
||||||
let window = self.window.clone();
|
let window = self.window.clone();
|
||||||
let window_state = Arc::clone(&self.window_state);
|
let window_state = Arc::clone(&self.window_state);
|
||||||
|
|
||||||
let resizable = window_state_lock.resizable;
|
let resizable = window_state_lock.resizable;
|
||||||
|
let decorations = window_state_lock.decorations;
|
||||||
let maximized = window_state_lock.maximized;
|
let maximized = window_state_lock.maximized;
|
||||||
|
|
||||||
// We're restoring the window to its size and position from before being fullscreened.
|
// We're restoring the window to its size and position from before being fullscreened.
|
||||||
|
@ -528,7 +507,7 @@ impl Window {
|
||||||
self.events_loop_proxy.execute_in_thread(move |_| {
|
self.events_loop_proxy.execute_in_thread(move |_| {
|
||||||
let _ = Self::grab_cursor_inner(&window, false);
|
let _ = Self::grab_cursor_inner(&window, false);
|
||||||
|
|
||||||
if resizable {
|
if resizable && decorations {
|
||||||
style |= WS_RESIZABLE as LONG;
|
style |= WS_RESIZABLE as LONG;
|
||||||
} else {
|
} else {
|
||||||
style &= !WS_RESIZABLE as LONG;
|
style &= !WS_RESIZABLE as LONG;
|
||||||
|
@ -536,6 +515,9 @@ impl Window {
|
||||||
winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style);
|
winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style);
|
||||||
winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style);
|
winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style);
|
||||||
|
|
||||||
|
let mut rect = client_rect;
|
||||||
|
winuser::AdjustWindowRectEx(&mut rect, style as _, 0, ex_style as _);
|
||||||
|
|
||||||
winuser::SetWindowPos(
|
winuser::SetWindowPos(
|
||||||
window.0,
|
window.0,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
|
@ -634,12 +616,9 @@ impl Window {
|
||||||
|
|
||||||
// if we are in fullscreen mode, we only change the saved window info
|
// if we are in fullscreen mode, we only change the saved window info
|
||||||
if window_state.fullscreen.is_some() {
|
if window_state.fullscreen.is_some() {
|
||||||
|
let resizable = window_state.resizable;
|
||||||
let saved = window_state.saved_window_info.as_mut().unwrap();
|
let saved = window_state.saved_window_info.as_mut().unwrap();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
unjust_window_rect(&mut saved.rect, saved.style as _, saved.ex_style as _);
|
|
||||||
}
|
|
||||||
|
|
||||||
if decorations {
|
if decorations {
|
||||||
saved.style = saved.style | style_flags;
|
saved.style = saved.style | style_flags;
|
||||||
saved.ex_style = saved.ex_style | ex_style_flags;
|
saved.ex_style = saved.ex_style | ex_style_flags;
|
||||||
|
@ -647,23 +626,17 @@ impl Window {
|
||||||
saved.style = saved.style & !style_flags;
|
saved.style = saved.style & !style_flags;
|
||||||
saved.ex_style = saved.ex_style & !ex_style_flags;
|
saved.ex_style = saved.ex_style & !ex_style_flags;
|
||||||
}
|
}
|
||||||
|
if resizable {
|
||||||
unsafe {
|
saved.style |= WS_RESIZABLE as LONG;
|
||||||
winuser::AdjustWindowRectEx(
|
} else {
|
||||||
&mut saved.rect,
|
saved.style &= !WS_RESIZABLE as LONG;
|
||||||
saved.style as _,
|
|
||||||
0,
|
|
||||||
saved.ex_style as _,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut rect: RECT = mem::zeroed();
|
let mut rect = util::get_client_rect(self.window.0).expect("Get client rect failed!");
|
||||||
winuser::GetWindowRect(self.window.0, &mut rect);
|
|
||||||
|
|
||||||
let mut style = winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE);
|
let mut style = winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE);
|
||||||
let mut ex_style = winuser::GetWindowLongW(self.window.0, winuser::GWL_EXSTYLE);
|
let mut ex_style = winuser::GetWindowLongW(self.window.0, winuser::GWL_EXSTYLE);
|
||||||
unjust_window_rect(&mut rect, style as _, ex_style as _);
|
|
||||||
|
|
||||||
if decorations {
|
if decorations {
|
||||||
style = style | style_flags;
|
style = style | style_flags;
|
||||||
|
|
Loading…
Reference in a new issue