@@ -88,7 +88,7 @@ use crate::ime::ImeContext;
8888use crate :: keyboard:: KeyEventBuilder ;
8989use crate :: keyboard_layout:: LAYOUT_CACHE ;
9090use crate :: monitor:: { self , MonitorHandle } ;
91- use crate :: util:: wrap_device_id;
91+ use crate :: util:: { wrap_device_id, WIN10_BUILD_VERSION } ;
9292use crate :: window:: { InitData , Window } ;
9393use crate :: window_state:: { CursorFlags , ImeState , WindowFlags , WindowState } ;
9494use crate :: { raw_input, util} ;
@@ -2346,105 +2346,22 @@ unsafe fn public_window_callback_inner(
23462346 }
23472347 }
23482348
2349- let new_outer_rect: RECT ;
2349+ let new_outer_rect: RECT = if WIN10_BUILD_VERSION . is_some_and ( |version| version < 22000 )
23502350 {
2351- let suggested_ul =
2352- ( suggested_rect. left + margin_left, suggested_rect. top + margin_top) ;
2353-
2354- let mut conservative_rect = RECT {
2355- left : suggested_ul. 0 ,
2356- top : suggested_ul. 1 ,
2357- right : suggested_ul. 0 + new_physical_surface_size. width as i32 ,
2358- bottom : suggested_ul. 1 + new_physical_surface_size. height as i32 ,
2359- } ;
2360-
2361- conservative_rect = window_flags
2362- . adjust_rect ( window, conservative_rect)
2363- . unwrap_or ( conservative_rect) ;
2364-
2365- // If we're dragging the window, offset the window so that the cursor's
2366- // relative horizontal position in the title bar is preserved.
2367- if dragging_window {
2368- let bias = {
2369- let cursor_pos = {
2370- let mut pos = unsafe { mem:: zeroed ( ) } ;
2371- unsafe { GetCursorPos ( & mut pos) } ;
2372- pos
2373- } ;
2374- let suggested_cursor_horizontal_ratio = ( cursor_pos. x - suggested_rect. left )
2375- as f64
2376- / ( suggested_rect. right - suggested_rect. left ) as f64 ;
2377-
2378- ( cursor_pos. x
2379- - ( suggested_cursor_horizontal_ratio
2380- * ( conservative_rect. right - conservative_rect. left ) as f64 )
2381- as i32 )
2382- - conservative_rect. left
2383- } ;
2384- conservative_rect. left += bias;
2385- conservative_rect. right += bias;
2386- }
2387-
2388- // Check to see if the new window rect is on the monitor with the new DPI factor.
2389- // If it isn't, offset the window so that it is.
2390- let new_dpi_monitor = unsafe { MonitorFromWindow ( window, MONITOR_DEFAULTTONULL ) } ;
2391- let conservative_rect_monitor =
2392- unsafe { MonitorFromRect ( & conservative_rect, MONITOR_DEFAULTTONULL ) } ;
2393- new_outer_rect = if conservative_rect_monitor == new_dpi_monitor {
2394- conservative_rect
2395- } else {
2396- let get_monitor_rect = |monitor| {
2397- let mut monitor_info = MONITORINFO {
2398- cbSize : mem:: size_of :: < MONITORINFO > ( ) as _ ,
2399- ..unsafe { mem:: zeroed ( ) }
2400- } ;
2401- unsafe { GetMonitorInfoW ( monitor, & mut monitor_info) } ;
2402- monitor_info. rcMonitor
2403- } ;
2404- let wrong_monitor = conservative_rect_monitor;
2405- let wrong_monitor_rect = get_monitor_rect ( wrong_monitor) ;
2406- let new_monitor_rect = get_monitor_rect ( new_dpi_monitor) ;
2407-
2408- // The direction to nudge the window in to get the window onto the monitor with
2409- // the new DPI factor. We calculate this by seeing which monitor edges are
2410- // shared and nudging away from the wrong monitor based on those.
2411- #[ allow( clippy:: bool_to_int_with_if) ]
2412- let delta_nudge_to_dpi_monitor = (
2413- if wrong_monitor_rect. left == new_monitor_rect. right {
2414- -1
2415- } else if wrong_monitor_rect. right == new_monitor_rect. left {
2416- 1
2417- } else {
2418- 0
2419- } ,
2420- if wrong_monitor_rect. bottom == new_monitor_rect. top {
2421- 1
2422- } else if wrong_monitor_rect. top == new_monitor_rect. bottom {
2423- -1
2424- } else {
2425- 0
2426- } ,
2427- ) ;
2428-
2429- let abort_after_iterations = new_monitor_rect. right - new_monitor_rect. left
2430- + new_monitor_rect. bottom
2431- - new_monitor_rect. top ;
2432- for _ in 0 ..abort_after_iterations {
2433- conservative_rect. left += delta_nudge_to_dpi_monitor. 0 ;
2434- conservative_rect. right += delta_nudge_to_dpi_monitor. 0 ;
2435- conservative_rect. top += delta_nudge_to_dpi_monitor. 1 ;
2436- conservative_rect. bottom += delta_nudge_to_dpi_monitor. 1 ;
2437-
2438- if unsafe { MonitorFromRect ( & conservative_rect, MONITOR_DEFAULTTONULL ) }
2439- == new_dpi_monitor
2440- {
2441- break ;
2442- }
2443- }
2444-
2445- conservative_rect
2446- } ;
2447- }
2351+ // Apply Windows 10-specific DPI adjustment workaround
2352+ apply_win10_dpi_adjustment (
2353+ window,
2354+ suggested_rect,
2355+ margin_left,
2356+ margin_top,
2357+ new_physical_surface_size,
2358+ window_flags,
2359+ dragging_window,
2360+ )
2361+ } else {
2362+ // The suggested position is fine w/o adjustment on Windows 11+
2363+ suggested_rect
2364+ } ;
24482365
24492366 unsafe {
24502367 SetWindowPos (
@@ -2669,3 +2586,108 @@ fn get_pointer_move_kind(
26692586 PointerMoveKind :: None
26702587 }
26712588}
2589+
2590+ /// Apply Windows 10-specific DPI adjustment workaround for window positioning.
2591+ /// This fixes DPI switching issues on older Windows 10 but should not be applied on Windows 11+
2592+ /// where it would break DPI switching.
2593+ fn apply_win10_dpi_adjustment (
2594+ window : HWND ,
2595+ suggested_rect : RECT ,
2596+ margin_left : i32 ,
2597+ margin_top : i32 ,
2598+ new_physical_surface_size : PhysicalSize < u32 > ,
2599+ window_flags : WindowFlags ,
2600+ dragging_window : bool ,
2601+ ) -> RECT {
2602+ let suggested_ul = ( suggested_rect. left + margin_left, suggested_rect. top + margin_top) ;
2603+
2604+ let mut conservative_rect = RECT {
2605+ left : suggested_ul. 0 ,
2606+ top : suggested_ul. 1 ,
2607+ right : suggested_ul. 0 + new_physical_surface_size. width as i32 ,
2608+ bottom : suggested_ul. 1 + new_physical_surface_size. height as i32 ,
2609+ } ;
2610+
2611+ conservative_rect =
2612+ window_flags. adjust_rect ( window, conservative_rect) . unwrap_or ( conservative_rect) ;
2613+
2614+ // If we're dragging the window, offset the window so that the cursor's
2615+ // relative horizontal position in the title bar is preserved.
2616+ if dragging_window {
2617+ let bias = {
2618+ let cursor_pos = {
2619+ let mut pos = unsafe { mem:: zeroed ( ) } ;
2620+ unsafe { GetCursorPos ( & mut pos) } ;
2621+ pos
2622+ } ;
2623+ let suggested_cursor_horizontal_ratio = ( cursor_pos. x - suggested_rect. left ) as f64
2624+ / ( suggested_rect. right - suggested_rect. left ) as f64 ;
2625+
2626+ ( cursor_pos. x
2627+ - ( suggested_cursor_horizontal_ratio
2628+ * ( conservative_rect. right - conservative_rect. left ) as f64 )
2629+ as i32 )
2630+ - conservative_rect. left
2631+ } ;
2632+ conservative_rect. left += bias;
2633+ conservative_rect. right += bias;
2634+ }
2635+
2636+ // Check to see if the new window rect is on the monitor with the new DPI factor.
2637+ // If it isn't, offset the window so that it is.
2638+ let new_dpi_monitor = unsafe { MonitorFromWindow ( window, MONITOR_DEFAULTTONULL ) } ;
2639+ let conservative_rect_monitor =
2640+ unsafe { MonitorFromRect ( & conservative_rect, MONITOR_DEFAULTTONULL ) } ;
2641+
2642+ if conservative_rect_monitor == new_dpi_monitor {
2643+ return conservative_rect;
2644+ }
2645+
2646+ let get_monitor_rect = |monitor| {
2647+ let mut monitor_info =
2648+ MONITORINFO { cbSize : mem:: size_of :: < MONITORINFO > ( ) as _ , ..unsafe { mem:: zeroed ( ) } } ;
2649+ unsafe { GetMonitorInfoW ( monitor, & mut monitor_info) } ;
2650+ monitor_info. rcMonitor
2651+ } ;
2652+ let wrong_monitor = conservative_rect_monitor;
2653+ let wrong_monitor_rect = get_monitor_rect ( wrong_monitor) ;
2654+ let new_monitor_rect = get_monitor_rect ( new_dpi_monitor) ;
2655+
2656+ // The direction to nudge the window in to get the window onto the monitor with
2657+ // the new DPI factor. We calculate this by seeing which monitor edges are
2658+ // shared and nudging away from the wrong monitor based on those.
2659+ #[ allow( clippy:: bool_to_int_with_if) ]
2660+ let delta_nudge_to_dpi_monitor = (
2661+ if wrong_monitor_rect. left == new_monitor_rect. right {
2662+ -1
2663+ } else if wrong_monitor_rect. right == new_monitor_rect. left {
2664+ 1
2665+ } else {
2666+ 0
2667+ } ,
2668+ if wrong_monitor_rect. bottom == new_monitor_rect. top {
2669+ 1
2670+ } else if wrong_monitor_rect. top == new_monitor_rect. bottom {
2671+ -1
2672+ } else {
2673+ 0
2674+ } ,
2675+ ) ;
2676+
2677+ let abort_after_iterations = new_monitor_rect. right - new_monitor_rect. left
2678+ + new_monitor_rect. bottom
2679+ - new_monitor_rect. top ;
2680+ for _ in 0 ..abort_after_iterations {
2681+ conservative_rect. left += delta_nudge_to_dpi_monitor. 0 ;
2682+ conservative_rect. right += delta_nudge_to_dpi_monitor. 0 ;
2683+ conservative_rect. top += delta_nudge_to_dpi_monitor. 1 ;
2684+ conservative_rect. bottom += delta_nudge_to_dpi_monitor. 1 ;
2685+
2686+ if unsafe { MonitorFromRect ( & conservative_rect, MONITOR_DEFAULTTONULL ) } == new_dpi_monitor
2687+ {
2688+ break ;
2689+ }
2690+ }
2691+
2692+ conservative_rect
2693+ }
0 commit comments