mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +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, 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, exiting fullscreen after entering fullscreen with disabled decorations no longer shrinks window.
|
||||
- On X11, fixed a segfault when using virtual monitors with XRandR.
|
||||
- Derive `Ord` and `PartialOrd` for `VirtualKeyCode` enum.
|
||||
- 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
|
||||
pub ex_style: LONG,
|
||||
/// 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
|
||||
// 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.
|
||||
|
|
|
@ -55,6 +55,19 @@ pub fn get_window_rect(hwnd: HWND) -> Option<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.
|
||||
pub fn rect_eq(a: &RECT, b: &RECT) -> bool {
|
||||
let left_eq = a.left == b.left;
|
||||
|
|
|
@ -49,28 +49,6 @@ pub struct Window {
|
|||
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 {
|
||||
pub fn new(
|
||||
events_loop: &EventsLoop,
|
||||
|
@ -477,12 +455,12 @@ impl Window {
|
|||
|
||||
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() {
|
||||
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);
|
||||
window_state.saved_window_info = Some(events_loop::SavedWindowInfo {
|
||||
style: winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE),
|
||||
ex_style: winuser::GetWindowLongW(self.window.0, winuser::GWL_EXSTYLE),
|
||||
rect,
|
||||
client_rect,
|
||||
is_fullscreen: true,
|
||||
dpi_factor,
|
||||
});
|
||||
|
@ -499,7 +477,7 @@ impl Window {
|
|||
}
|
||||
|
||||
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
|
||||
// in fullscreen mode before this method gets called.
|
||||
if window_state_lock.saved_window_info.is_none() {
|
||||
|
@ -513,14 +491,15 @@ impl Window {
|
|||
// repainted. Better-looking methods welcome.
|
||||
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);
|
||||
(rect, style, ex_style)
|
||||
(client_rect, style, ex_style)
|
||||
};
|
||||
let window = self.window.clone();
|
||||
let window_state = Arc::clone(&self.window_state);
|
||||
|
||||
let resizable = window_state_lock.resizable;
|
||||
let decorations = window_state_lock.decorations;
|
||||
let maximized = window_state_lock.maximized;
|
||||
|
||||
// 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 |_| {
|
||||
let _ = Self::grab_cursor_inner(&window, false);
|
||||
|
||||
if resizable {
|
||||
if resizable && decorations {
|
||||
style |= WS_RESIZABLE as LONG;
|
||||
} else {
|
||||
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_EXSTYLE, ex_style);
|
||||
|
||||
let mut rect = client_rect;
|
||||
winuser::AdjustWindowRectEx(&mut rect, style as _, 0, ex_style as _);
|
||||
|
||||
winuser::SetWindowPos(
|
||||
window.0,
|
||||
ptr::null_mut(),
|
||||
|
@ -629,17 +611,14 @@ impl Window {
|
|||
pub fn set_decorations(&self, decorations: bool) {
|
||||
let mut window_state = self.window_state.lock().unwrap();
|
||||
if mem::replace(&mut window_state.decorations, decorations) != decorations {
|
||||
let style_flags = (winuser::WS_CAPTION | winuser::WS_THICKFRAME) as LONG;
|
||||
let ex_style_flags = (winuser::WS_EX_WINDOWEDGE) as LONG;
|
||||
let style_flags = (winuser::WS_CAPTION | winuser::WS_THICKFRAME) as LONG;
|
||||
let ex_style_flags = (winuser::WS_EX_WINDOWEDGE) as LONG;
|
||||
|
||||
// if we are in fullscreen mode, we only change the saved window info
|
||||
if window_state.fullscreen.is_some() {
|
||||
let resizable = window_state.resizable;
|
||||
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 {
|
||||
saved.style = saved.style | style_flags;
|
||||
saved.ex_style = saved.ex_style | ex_style_flags;
|
||||
|
@ -647,23 +626,17 @@ impl Window {
|
|||
saved.style = saved.style & !style_flags;
|
||||
saved.ex_style = saved.ex_style & !ex_style_flags;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
winuser::AdjustWindowRectEx(
|
||||
&mut saved.rect,
|
||||
saved.style as _,
|
||||
0,
|
||||
saved.ex_style as _,
|
||||
);
|
||||
if resizable {
|
||||
saved.style |= WS_RESIZABLE as LONG;
|
||||
} else {
|
||||
saved.style &= !WS_RESIZABLE as LONG;
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
let mut rect: RECT = mem::zeroed();
|
||||
winuser::GetWindowRect(self.window.0, &mut rect);
|
||||
let mut rect = util::get_client_rect(self.window.0).expect("Get client rect failed!");
|
||||
|
||||
let mut style = winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE);
|
||||
let mut ex_style = winuser::GetWindowLongW(self.window.0, winuser::GWL_EXSTYLE);
|
||||
unjust_window_rect(&mut rect, style as _, ex_style as _);
|
||||
|
||||
if decorations {
|
||||
style = style | style_flags;
|
||||
|
|
Loading…
Reference in a new issue