From 23b821285ce93bddb38dd71e0290296488140910 Mon Sep 17 00:00:00 2001 From: Markus Siglreithmaier Date: Sat, 28 Jan 2023 14:04:47 +0100 Subject: [PATCH] On Windows, fix window size for maximized, undecorated windows (#2584) Co-authored-by: Amr Bashir --- CHANGELOG.md | 1 + src/platform_impl/windows/event_loop.rs | 38 ++++++++++++++++--------- src/platform_impl/windows/util.rs | 19 +++++++++---- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25918f8928..56a82545c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre # Unreleased +- On Windows, fix window size for maximized, undecorated windows. - On Windows and macOS, add `WindowBuilder::with_active`. - Add `Window::is_minimized`. - On X11, fix errors handled during `register_xlib_error_hook` invocation bleeding into winit. diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 31d39d90fc..dbce31e8b2 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -977,19 +977,31 @@ unsafe fn public_window_callback_inner( return DefWindowProcW(window, msg, wparam, lparam); } - // Extend the client area to cover the whole non-client area. - // https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize#remarks - // - // HACK(msiglreith): To add the drop shadow we slightly tweak the non-client area. - // This leads to a small black 1px border on the top. Adding a margin manually - // on all 4 borders would result in the caption getting drawn by the DWM. - // - // Another option would be to allow the DWM to paint inside the client area. - // Unfortunately this results in janky resize behavior, where the compositor is - // ahead of the window surface. Currently, there seems no option to achieve this - // with the Windows API. - if window_flags.contains(WindowFlags::MARKER_UNDECORATED_SHADOW) { - let params = &mut *(lparam as *mut NCCALCSIZE_PARAMS); + let params = &mut *(lparam as *mut NCCALCSIZE_PARAMS); + + if util::is_maximized(window) { + // Limit the window size when maximized to the current monitor. + // Otherwise it would include the non-existent decorations. + // + // Use `MonitorFromRect` instead of `MonitorFromWindow` to select + // the correct monitor here. + // See https://github.com/MicrosoftEdge/WebView2Feedback/issues/2549 + let monitor = MonitorFromRect(¶ms.rgrc[0], MONITOR_DEFAULTTONULL); + if let Ok(monitor_info) = monitor::get_monitor_info(monitor) { + params.rgrc[0] = monitor_info.monitorInfo.rcWork; + } + } else if window_flags.contains(WindowFlags::MARKER_UNDECORATED_SHADOW) { + // Extend the client area to cover the whole non-client area. + // https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize#remarks + // + // HACK(msiglreith): To add the drop shadow we slightly tweak the non-client area. + // This leads to a small black 1px border on the top. Adding a margin manually + // on all 4 borders would result in the caption getting drawn by the DWM. + // + // Another option would be to allow the DWM to paint inside the client area. + // Unfortunately this results in janky resize behavior, where the compositor is + // ahead of the window surface. Currently, there seems no option to achieve this + // with the Windows API. params.rgrc[0].top += 1; params.rgrc[0].bottom += 1; } diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index 1f94220c78..350097646a 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -23,11 +23,11 @@ use windows_sys::{ HiDpi::{DPI_AWARENESS_CONTEXT, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS}, Input::KeyboardAndMouse::GetActiveWindow, WindowsAndMessaging::{ - ClipCursor, GetClientRect, GetClipCursor, GetSystemMetrics, GetWindowRect, - IsIconic, ShowCursor, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, - IDC_IBEAM, IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, IDC_SIZEWE, - IDC_WAIT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, - SM_YVIRTUALSCREEN, + ClipCursor, GetClientRect, GetClipCursor, GetSystemMetrics, GetWindowPlacement, + GetWindowRect, IsIconic, ShowCursor, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, + IDC_HAND, IDC_HELP, IDC_IBEAM, IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, + IDC_SIZENWSE, IDC_SIZEWE, IDC_WAIT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, + SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, SW_MAXIMIZE, WINDOWPLACEMENT, }, }, }, @@ -91,6 +91,15 @@ impl WindowArea { } } +pub fn is_maximized(window: HWND) -> bool { + unsafe { + let mut placement: WINDOWPLACEMENT = mem::zeroed(); + placement.length = mem::size_of::() as u32; + GetWindowPlacement(window, &mut placement); + placement.showCmd == SW_MAXIMIZE + } +} + pub fn set_cursor_hidden(hidden: bool) { static HIDDEN: AtomicBool = AtomicBool::new(false); let changed = HIDDEN.swap(hidden, Ordering::SeqCst) ^ hidden;