mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-28 07:33:14 -04:00
win32: disable DPI re-adjustments on Windows 11
For earlier Windows 10 builds (pre-22000), a workaround was necessary to fix dragging window onto a monitor with different DPI. This commit makes the old DPI workaround to only apply conditionally on affected Windows versions. Fixes #4041.
This commit is contained in:
@@ -88,7 +88,7 @@ use crate::ime::ImeContext;
|
||||
use crate::keyboard::KeyEventBuilder;
|
||||
use crate::keyboard_layout::LAYOUT_CACHE;
|
||||
use crate::monitor::{self, MonitorHandle};
|
||||
use crate::util::wrap_device_id;
|
||||
use crate::util::{wrap_device_id, WIN10_BUILD_VERSION};
|
||||
use crate::window::{InitData, Window};
|
||||
use crate::window_state::{CursorFlags, ImeState, WindowFlags, WindowState};
|
||||
use crate::{raw_input, util};
|
||||
@@ -2346,105 +2346,22 @@ unsafe fn public_window_callback_inner(
|
||||
}
|
||||
}
|
||||
|
||||
let new_outer_rect: RECT;
|
||||
let new_outer_rect: RECT = if WIN10_BUILD_VERSION.is_some_and(|version| version < 22000)
|
||||
{
|
||||
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_surface_size.width as i32,
|
||||
bottom: suggested_ul.1 + new_physical_surface_size.height as i32,
|
||||
};
|
||||
|
||||
conservative_rect = window_flags
|
||||
.adjust_rect(window, 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 = unsafe { mem::zeroed() };
|
||||
unsafe { 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;
|
||||
|
||||
(cursor_pos.x
|
||||
- (suggested_cursor_horizontal_ratio
|
||||
* (conservative_rect.right - conservative_rect.left) as f64)
|
||||
as i32)
|
||||
- conservative_rect.left
|
||||
};
|
||||
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 = unsafe { MonitorFromWindow(window, MONITOR_DEFAULTTONULL) };
|
||||
let conservative_rect_monitor =
|
||||
unsafe { MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL) };
|
||||
new_outer_rect = if conservative_rect_monitor == new_dpi_monitor {
|
||||
conservative_rect
|
||||
} else {
|
||||
let get_monitor_rect = |monitor| {
|
||||
let mut monitor_info = MONITORINFO {
|
||||
cbSize: mem::size_of::<MONITORINFO>() as _,
|
||||
..unsafe { mem::zeroed() }
|
||||
};
|
||||
unsafe { 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.
|
||||
#[allow(clippy::bool_to_int_with_if)]
|
||||
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 unsafe { MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL) }
|
||||
== new_dpi_monitor
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
conservative_rect
|
||||
};
|
||||
}
|
||||
// Apply Windows 10-specific DPI adjustment workaround
|
||||
apply_win10_dpi_adjustment(
|
||||
window,
|
||||
suggested_rect,
|
||||
margin_left,
|
||||
margin_top,
|
||||
new_physical_surface_size,
|
||||
window_flags,
|
||||
dragging_window,
|
||||
)
|
||||
} else {
|
||||
// The suggested position is fine w/o adjustment on Windows 11+
|
||||
suggested_rect
|
||||
};
|
||||
|
||||
unsafe {
|
||||
SetWindowPos(
|
||||
@@ -2669,3 +2586,108 @@ fn get_pointer_move_kind(
|
||||
PointerMoveKind::None
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply Windows 10-specific DPI adjustment workaround for window positioning.
|
||||
/// This fixes DPI switching issues on older Windows 10 but should not be applied on Windows 11+
|
||||
/// where it would break DPI switching.
|
||||
fn apply_win10_dpi_adjustment(
|
||||
window: HWND,
|
||||
suggested_rect: RECT,
|
||||
margin_left: i32,
|
||||
margin_top: i32,
|
||||
new_physical_surface_size: PhysicalSize<u32>,
|
||||
window_flags: WindowFlags,
|
||||
dragging_window: bool,
|
||||
) -> 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_surface_size.width as i32,
|
||||
bottom: suggested_ul.1 + new_physical_surface_size.height as i32,
|
||||
};
|
||||
|
||||
conservative_rect =
|
||||
window_flags.adjust_rect(window, 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 = unsafe { mem::zeroed() };
|
||||
unsafe { 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;
|
||||
|
||||
(cursor_pos.x
|
||||
- (suggested_cursor_horizontal_ratio
|
||||
* (conservative_rect.right - conservative_rect.left) as f64)
|
||||
as i32)
|
||||
- conservative_rect.left
|
||||
};
|
||||
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 = unsafe { MonitorFromWindow(window, MONITOR_DEFAULTTONULL) };
|
||||
let conservative_rect_monitor =
|
||||
unsafe { MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL) };
|
||||
|
||||
if conservative_rect_monitor == new_dpi_monitor {
|
||||
return conservative_rect;
|
||||
}
|
||||
|
||||
let get_monitor_rect = |monitor| {
|
||||
let mut monitor_info =
|
||||
MONITORINFO { cbSize: mem::size_of::<MONITORINFO>() as _, ..unsafe { mem::zeroed() } };
|
||||
unsafe { 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.
|
||||
#[allow(clippy::bool_to_int_with_if)]
|
||||
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 unsafe { MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL) } == new_dpi_monitor
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
conservative_rect
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user