From 4b0d042fdd2b841d8627d69bee189541c3ee82f3 Mon Sep 17 00:00:00 2001 From: Daniel Gerhardt Date: Mon, 10 Feb 2025 10:49:54 +0100 Subject: [PATCH] fix(windows): use correct position/size on WM_DPICHANGED for Windows 11 Adjustments to the OS-suggested position are now only applied on Windows 10. They are not needed anymore on Windows 11. Fixes #1053, tauri-apps/tauri#10263, tauri-apps/tauri#12626. --- .changes/fix-win11-dpichanged-position.md | 5 + src/platform_impl/windows/event_loop.rs | 176 +++++++++++----------- 2 files changed, 97 insertions(+), 84 deletions(-) create mode 100644 .changes/fix-win11-dpichanged-position.md diff --git a/.changes/fix-win11-dpichanged-position.md b/.changes/fix-win11-dpichanged-position.md new file mode 100644 index 000000000..2fd168c00 --- /dev/null +++ b/.changes/fix-win11-dpichanged-position.md @@ -0,0 +1,5 @@ +--- +"tao": patch +--- + +On Windows 11, fix incorrect window positioning and sizing on `WM_DPICHANGED`. diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index bf5accff5..689292c63 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -1997,99 +1997,107 @@ unsafe fn public_window_callback_inner( } let new_outer_rect: RECT; - { - let suggested_ul = ( - suggested_rect.left + margin_left, - suggested_rect.top + margin_top, - ); - - let mut conservative_rect = RECT { - left: suggested_ul.0, - top: suggested_ul.1, - right: suggested_ul.0 + new_physical_inner_size.width as i32, - bottom: suggested_ul.1 + new_physical_inner_size.height as i32, - }; - - conservative_rect = - util::adjust_window_rect_with_styles(window, style, style_ex, conservative_rect) - .unwrap_or(conservative_rect); - - // If we're dragging the window, offset the window so that the cursor's - // relative horizontal position in the title bar is preserved. - if dragging_window { - let bias = { - let cursor_pos = { - let mut pos = POINT::default(); - let _ = GetCursorPos(&mut pos); - pos - }; - let suggested_cursor_horizontal_ratio = (cursor_pos.x - suggested_rect.left) as f64 - / (suggested_rect.right - suggested_rect.left) as f64; + if util::WIN_VERSION.build < 22000 { + // The window position needs adjustment on Windows 10. + { + let suggested_ul = ( + suggested_rect.left + margin_left, + suggested_rect.top + margin_top, + ); - (cursor_pos.x - - (suggested_cursor_horizontal_ratio - * (conservative_rect.right - conservative_rect.left) as f64) as i32) - - conservative_rect.left + let mut conservative_rect = RECT { + left: suggested_ul.0, + top: suggested_ul.1, + right: suggested_ul.0 + new_physical_inner_size.width as i32, + bottom: suggested_ul.1 + new_physical_inner_size.height as i32, }; - conservative_rect.left += bias; - conservative_rect.right += bias; - } - // Check to see if the new window rect is on the monitor with the new DPI factor. - // If it isn't, offset the window so that it is. - let new_dpi_monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); - let conservative_rect_monitor = MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL); - new_outer_rect = { - if conservative_rect_monitor != new_dpi_monitor { - let get_monitor_rect = |monitor| { - let mut monitor_info = MONITORINFO { - cbSize: mem::size_of::() as _, - ..Default::default() + conservative_rect = + util::adjust_window_rect_with_styles(window, style, style_ex, conservative_rect) + .unwrap_or(conservative_rect); + + // If we're dragging the window, offset the window so that the cursor's + // relative horizontal position in the title bar is preserved. + if dragging_window { + let bias = { + let cursor_pos = { + let mut pos = POINT::default(); + let _ = GetCursorPos(&mut pos); + pos }; - let _ = GetMonitorInfoW(monitor, &mut monitor_info); - monitor_info.rcMonitor + let suggested_cursor_horizontal_ratio = (cursor_pos.x - suggested_rect.left) as f64 + / (suggested_rect.right - suggested_rect.left) as f64; + + (cursor_pos.x + - (suggested_cursor_horizontal_ratio + * (conservative_rect.right - conservative_rect.left) as f64) + as i32) + - conservative_rect.left }; - let wrong_monitor = conservative_rect_monitor; - let wrong_monitor_rect = get_monitor_rect(wrong_monitor); - let new_monitor_rect = get_monitor_rect(new_dpi_monitor); - - // The direction to nudge the window in to get the window onto the monitor with - // the new DPI factor. We calculate this by seeing which monitor edges are - // shared and nudging away from the wrong monitor based on those. - let delta_nudge_to_dpi_monitor = ( - if wrong_monitor_rect.left == new_monitor_rect.right { - -1 - } else if wrong_monitor_rect.right == new_monitor_rect.left { - 1 - } else { - 0 - }, - if wrong_monitor_rect.bottom == new_monitor_rect.top { - 1 - } else if wrong_monitor_rect.top == new_monitor_rect.bottom { - -1 - } else { - 0 - }, - ); + conservative_rect.left += bias; + conservative_rect.right += bias; + } - let abort_after_iterations = new_monitor_rect.right - new_monitor_rect.left - + new_monitor_rect.bottom - - new_monitor_rect.top; - for _ in 0..abort_after_iterations { - conservative_rect.left += delta_nudge_to_dpi_monitor.0; - conservative_rect.right += delta_nudge_to_dpi_monitor.0; - conservative_rect.top += delta_nudge_to_dpi_monitor.1; - conservative_rect.bottom += delta_nudge_to_dpi_monitor.1; - - if MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL) == new_dpi_monitor { - break; + // Check to see if the new window rect is on the monitor with the new DPI factor. + // If it isn't, offset the window so that it is. + let new_dpi_monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); + let conservative_rect_monitor = + MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL); + new_outer_rect = { + if conservative_rect_monitor != new_dpi_monitor { + let get_monitor_rect = |monitor| { + let mut monitor_info = MONITORINFO { + cbSize: mem::size_of::() as _, + ..Default::default() + }; + let _ = GetMonitorInfoW(monitor, &mut monitor_info); + monitor_info.rcMonitor + }; + let wrong_monitor = conservative_rect_monitor; + let wrong_monitor_rect = get_monitor_rect(wrong_monitor); + let new_monitor_rect = get_monitor_rect(new_dpi_monitor); + + // The direction to nudge the window in to get the window onto the monitor with + // the new DPI factor. We calculate this by seeing which monitor edges are + // shared and nudging away from the wrong monitor based on those. + let delta_nudge_to_dpi_monitor = ( + if wrong_monitor_rect.left == new_monitor_rect.right { + -1 + } else if wrong_monitor_rect.right == new_monitor_rect.left { + 1 + } else { + 0 + }, + if wrong_monitor_rect.bottom == new_monitor_rect.top { + 1 + } else if wrong_monitor_rect.top == new_monitor_rect.bottom { + -1 + } else { + 0 + }, + ); + + let abort_after_iterations = new_monitor_rect.right - new_monitor_rect.left + + new_monitor_rect.bottom + - new_monitor_rect.top; + for _ in 0..abort_after_iterations { + conservative_rect.left += delta_nudge_to_dpi_monitor.0; + conservative_rect.right += delta_nudge_to_dpi_monitor.0; + conservative_rect.top += delta_nudge_to_dpi_monitor.1; + conservative_rect.bottom += delta_nudge_to_dpi_monitor.1; + + if MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL) == new_dpi_monitor { + break; + } } } - } - conservative_rect - }; + conservative_rect + }; + } + } else { + // The suggested position is fine w/o adjustment on Windows 11. + new_outer_rect = suggested_rect } let _ = SetWindowPos(