From 39573d65d053219385e0333ee50cf10cf477bd99 Mon Sep 17 00:00:00 2001 From: relrelb Date: Sun, 13 Dec 2020 20:06:53 +0200 Subject: [PATCH] Windows: Preserve minimized/maximized state in fullscreen (#1784) --- CHANGELOG.md | 19 ++++++---- src/platform_impl/windows/window.rs | 46 ++++++----------------- src/platform_impl/windows/window_state.rs | 17 ++++----- 3 files changed, 31 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 559cbc8d..15880942 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,25 +1,30 @@ +# Unreleased + +- On Windows, fix fullscreen not preserving minimized/maximized state. + # 0.24.0 (2020-12-09) - On Windows, fix applications not exiting gracefully due to thread_event_target_callback accessing corrupted memory. - On Windows, implement `Window::set_ime_position`. - **Breaking:** On Windows, Renamed `WindowBuilderExtWindows`'s `is_dark_mode` to `theme`. +- **Breaking:** On Windows, renamed `WindowBuilderExtWindows::is_dark_mode` to `theme`. - On Windows, add `WindowBuilderExtWindows::with_theme` to set a preferred theme. - On Windows, fix bug causing message boxes to appear delayed. -- On Android, calling `WindowEvent::Focused` now works properly instead of always returning false. -- On Windows, fix alt-tab behaviour by removing borderless fullscreen "always on top" flag. +- On Android, calling `WindowEvent::Focused` now works properly instead of always returning false. +- On Windows, fix Alt-Tab behaviour by removing borderless fullscreen "always on top" flag. - On Windows, fix bug preventing windows with transparency enabled from having fully-opaque regions. - **Breaking:** On Windows, include prefix byte in scancodes. -- On Wayland, fix window not being resizeable when using `with_min_inner_size` in `WindowBuilder`. +- On Wayland, fix window not being resizeable when using `WindowBuilder::with_min_inner_size`. - On Unix, fix cross-compiling to wasm32 without enabling X11 or Wayland. -- On Windows, fix use after free crash during window destruction. +- On Windows, fix use-after-free crash during window destruction. - On Web, fix `WindowEvent::ReceivedCharacter` never being sent on key input. -- On macOS, fix compilation when targeting aarch64 +- On macOS, fix compilation when targeting aarch64. - On X11, fix `Window::request_redraw` not waking the event loop. - On Wayland, the keypad arrow keys are now recognized. - **Breaking** Rename `desktop::EventLoopExtDesktop` to `run_return::EventLoopExtRunReturn`. - Added `request_user_attention` method to `Window`. -- **Breaking:** On macOS, removed `WindowExt::request_user_attention`, use `Window::request_user_attention`. -- **Breaking:** On X11, removed `WindowExt::set_urgent`, use `Window::request_user_attention`. +- **Breaking:** On macOS, removed `WindowExt::request_user_attention`, use `Window::request_user_attention`. +- **Breaking:** On X11, removed `WindowExt::set_urgent`, use `Window::request_user_attention`. - On Wayland, default font size in CSD increased from 11 to 17. - On Windows, fix bug causing message boxes to appear delayed. - On Android, support multi-touch. diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index c444863e..b0eb2231 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -403,20 +403,6 @@ impl Window { drop(window_state_lock); self.thread_executor.execute_in_thread(move || { - let mut window_state_lock = window_state.lock(); - - // Save window bounds before entering fullscreen - match (&old_fullscreen, &fullscreen) { - (&None, &Some(_)) => { - let client_rect = util::get_client_rect(window.0).unwrap(); - window_state_lock.saved_window = Some(SavedWindow { - client_rect, - scale_factor: window_state_lock.scale_factor, - }); - } - _ => (), - } - // Change video mode if we're transitioning to or from exclusive // fullscreen match (&old_fullscreen, &fullscreen) { @@ -490,7 +476,7 @@ impl Window { } // Update window style - WindowState::set_window_flags(window_state_lock, window.0, |f| { + WindowState::set_window_flags(window_state.lock(), window.0, |f| { f.set( WindowFlags::MARKER_EXCLUSIVE_FULLSCREEN, matches!(fullscreen, Some(Fullscreen::Exclusive(_))), @@ -504,6 +490,15 @@ impl Window { // Update window bounds match &fullscreen { Some(fullscreen) => { + // Save window bounds before entering fullscreen + let placement = unsafe { + let mut placement = mem::zeroed(); + winuser::GetWindowPlacement(window.0, &mut placement); + placement + }; + + window_state.lock().saved_window = Some(SavedWindow { placement }); + let monitor = match &fullscreen { Fullscreen::Exclusive(video_mode) => video_mode.monitor(), Fullscreen::Borderless(Some(monitor)) => monitor.clone(), @@ -530,27 +525,10 @@ impl Window { } None => { let mut window_state_lock = window_state.lock(); - if let Some(SavedWindow { - client_rect, - scale_factor, - }) = window_state_lock.saved_window.take() - { - window_state_lock.scale_factor = scale_factor; + if let Some(SavedWindow { placement }) = window_state_lock.saved_window.take() { drop(window_state_lock); - let client_rect = util::adjust_window_rect(window.0, client_rect).unwrap(); - unsafe { - winuser::SetWindowPos( - window.0, - ptr::null_mut(), - client_rect.left, - client_rect.top, - client_rect.right - client_rect.left, - client_rect.bottom - client_rect.top, - winuser::SWP_ASYNCWINDOWPOS - | winuser::SWP_NOZORDER - | winuser::SWP_NOACTIVATE, - ); + winuser::SetWindowPlacement(window.0, &placement); winuser::InvalidateRgn(window.0, ptr::null_mut(), 0); } } diff --git a/src/platform_impl/windows/window_state.rs b/src/platform_impl/windows/window_state.rs index 1369fe72..d9b43f06 100644 --- a/src/platform_impl/windows/window_state.rs +++ b/src/platform_impl/windows/window_state.rs @@ -39,8 +39,7 @@ pub struct WindowState { #[derive(Clone)] pub struct SavedWindow { - pub client_rect: RECT, - pub scale_factor: f64, + pub placement: winuser::WINDOWPLACEMENT, } #[derive(Clone)] @@ -86,11 +85,6 @@ bitflags! { const MINIMIZED = 1 << 12; - const FULLSCREEN_AND_MASK = !( - WindowFlags::DECORATIONS.bits | - WindowFlags::RESIZABLE.bits | - WindowFlags::MAXIMIZED.bits - ); const EXCLUSIVE_FULLSCREEN_OR_MASK = WindowFlags::ALWAYS_ON_TOP.bits; const NO_DECORATIONS_AND_MASK = !WindowFlags::RESIZABLE.bits; const INVISIBLE_AND_MASK = !WindowFlags::MAXIMIZED.bits; @@ -181,10 +175,7 @@ impl MouseProperties { impl WindowFlags { fn mask(mut self) -> WindowFlags { if self.contains(WindowFlags::MARKER_EXCLUSIVE_FULLSCREEN) { - self &= WindowFlags::FULLSCREEN_AND_MASK; self |= WindowFlags::EXCLUSIVE_FULLSCREEN_OR_MASK; - } else if self.contains(WindowFlags::MARKER_BORDERLESS_FULLSCREEN) { - self &= WindowFlags::FULLSCREEN_AND_MASK; } if !self.contains(WindowFlags::VISIBLE) { self &= WindowFlags::INVISIBLE_AND_MASK; @@ -235,6 +226,12 @@ impl WindowFlags { style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU; style_ex |= WS_EX_ACCEPTFILES; + if self.intersects( + WindowFlags::MARKER_EXCLUSIVE_FULLSCREEN | WindowFlags::MARKER_BORDERLESS_FULLSCREEN, + ) { + style &= !WS_OVERLAPPEDWINDOW; + } + (style, style_ex) }