windows: Fix maximized window size when DPI scale changes (#40053)
The WM_DPICHANGED suggested RECT is calculated for non-maximized windows. When a maximized window's DPI changes, we now query the monitor's work area directly to ensure the window correctly fills the entire screen. For non-maximized windows, the original behavior using the system-suggested RECT is preserved. Release Notes: - windows: Fixed maximized window size when DPI scale changes Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
This commit is contained in:
@@ -740,31 +740,58 @@ impl WindowsWindowInner {
|
||||
lock.border_offset.update(handle).log_err();
|
||||
drop(lock);
|
||||
|
||||
let rect = unsafe { &*(lparam.0 as *const RECT) };
|
||||
let width = rect.right - rect.left;
|
||||
let height = rect.bottom - rect.top;
|
||||
// this will emit `WM_SIZE` and `WM_MOVE` right here
|
||||
// even before this function returns
|
||||
// the new size is handled in `WM_SIZE`
|
||||
unsafe {
|
||||
SetWindowPos(
|
||||
handle,
|
||||
None,
|
||||
rect.left,
|
||||
rect.top,
|
||||
width,
|
||||
height,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE,
|
||||
)
|
||||
.context("unable to set window position after dpi has changed")
|
||||
.log_err();
|
||||
}
|
||||
|
||||
// When maximized, SetWindowPos doesn't send WM_SIZE, so we need to manually
|
||||
// update the size and call the resize callback
|
||||
if is_maximized {
|
||||
let device_size = size(DevicePixels(width), DevicePixels(height));
|
||||
self.handle_size_change(device_size, new_scale_factor, true);
|
||||
// Get the monitor and its work area at the new DPI
|
||||
let monitor = unsafe { MonitorFromWindow(handle, MONITOR_DEFAULTTONEAREST) };
|
||||
let mut monitor_info: MONITORINFO = unsafe { std::mem::zeroed() };
|
||||
monitor_info.cbSize = std::mem::size_of::<MONITORINFO>() as u32;
|
||||
if unsafe { GetMonitorInfoW(monitor, &mut monitor_info) }.as_bool() {
|
||||
let work_area = monitor_info.rcWork;
|
||||
let width = work_area.right - work_area.left;
|
||||
let height = work_area.bottom - work_area.top;
|
||||
|
||||
// Update the window size to match the new monitor work area
|
||||
// This will trigger WM_SIZE which will handle the size change
|
||||
unsafe {
|
||||
SetWindowPos(
|
||||
handle,
|
||||
None,
|
||||
work_area.left,
|
||||
work_area.top,
|
||||
width,
|
||||
height,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED,
|
||||
)
|
||||
.context("unable to set maximized window position after dpi has changed")
|
||||
.log_err();
|
||||
}
|
||||
|
||||
// SetWindowPos may not send WM_SIZE for maximized windows in some cases,
|
||||
// so we manually update the size to ensure proper rendering
|
||||
let device_size = size(DevicePixels(width), DevicePixels(height));
|
||||
self.handle_size_change(device_size, new_scale_factor, true);
|
||||
}
|
||||
} else {
|
||||
// For non-maximized windows, use the suggested RECT from the system
|
||||
let rect = unsafe { &*(lparam.0 as *const RECT) };
|
||||
let width = rect.right - rect.left;
|
||||
let height = rect.bottom - rect.top;
|
||||
// this will emit `WM_SIZE` and `WM_MOVE` right here
|
||||
// even before this function returns
|
||||
// the new size is handled in `WM_SIZE`
|
||||
unsafe {
|
||||
SetWindowPos(
|
||||
handle,
|
||||
None,
|
||||
rect.left,
|
||||
rect.top,
|
||||
width,
|
||||
height,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE,
|
||||
)
|
||||
.context("unable to set window position after dpi has changed")
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
|
||||
Some(0)
|
||||
|
||||
Reference in New Issue
Block a user