Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Unexpected resize when move window to secondary monitor if dpi diff in Windows 11 24H2 #4041

Open
Kr328 opened this issue Dec 14, 2024 · 3 comments
Labels
B - bug Dang, that shouldn't have happened DS - windows

Comments

@Kr328
Copy link

Kr328 commented Dec 14, 2024

Description

When I move the window from monitor 1 (1440p, 150% scale) to monitor 2 (1080p, 125% scale), the window size keeps getting bigger.

Notes

  1. Appears only in Windows 11 24H2
  2. Appears only dragging the left side of the window's title bar.

Reproduce Screen Record

reproduce.mp4

Reproduce Project

reproduce.zip
Just copy from example :)

Windows version

Microsoft Windows [Version 10.0.26100.2605]

Winit version

0.30.5

@Kr328 Kr328 added B - bug Dang, that shouldn't have happened DS - windows labels Dec 14, 2024
@DorianRudolph
Copy link

DorianRudolph commented Jan 1, 2025

I also noticed this. The issue disappears if you remove

let new_physical_surface_size = *new_surface_size.lock().unwrap();
drop(new_surface_size);
let dragging_window: bool;
{
let window_state = userdata.window_state_lock();
dragging_window =
window_state.window_flags().contains(WindowFlags::MARKER_IN_SIZE_MOVE);
// Unset maximized if we're changing the window's size.
if new_physical_surface_size != old_physical_surface_size {
WindowState::set_window_flags(window_state, window, |f| {
f.set(WindowFlags::MAXIMIZED, false)
});
}
}
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_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
};
}
unsafe {
SetWindowPos(
window,
0,
new_outer_rect.left,
new_outer_rect.top,
new_outer_rect.right - new_outer_rect.left,
new_outer_rect.bottom - new_outer_rect.top,
SWP_NOZORDER | SWP_NOACTIVATE,
)
};

Cursory testing did not reveal any adverse effects from removing that snippet.

Edit: If the monitors are stacked vertically, it is practically impossible to drag the window between them, regardless of where you grab it.

@acarl005
Copy link

acarl005 commented Jan 23, 2025

I am observing similar buggy behavior with both alacritty and Warp terminal. I have a video of it linked.

  • I have 2 external monitors. The left monitor is 1440p with a 1x scale factor. The right monitor is 4K with a 1.5x scale factor. Scale factors and resolution were assigned automatically by the OS.
  • I have an alacritty window on the right monitor
  • With the mouse I grab the title bar on the left-hand half (this only happens on the left-hand half) and drag the window toward the right monitor.
  • As I drag, the window starts jumping to the right until it's off of the mouse entirely. The window is also growing in size.
  • The window is now larger than either monitor.
  • I try to grab the top-right corner to resize the window down, but the window jumps downward mostly off-screen.

https://www.loom.com/share/aefc5dc1027a42fc8f462c23621ce9a5?sid=6b51b702-9c4b-4f2a-bc4a-2fca2a036462

Windows 11 Pro, 24H2

Update: moving the window from right to left display via shift+super+left also fails to fully move the window over. It ends up somewhere in the middle straddling the 2 displays instead.

@fredizzimo
Copy link

The code for dealing with the dpi changes looks way too complex to me. Microsoft recommends just this

case WM_DPICHANGED:
    {
        g_dpi = HIWORD(wParam);
        UpdateDpiDependentFontsAndResources();

        RECT* const prcNewWindow = (RECT*)lParam;
        SetWindowPos(hWnd,
            NULL,
            prcNewWindow ->left,
            prcNewWindow ->top,
            prcNewWindow->right - prcNewWindow->left,
            prcNewWindow->bottom - prcNewWindow->top,
            SWP_NOZORDER | SWP_NOACTIVATE);
        break;
    }

https://learn.microsoft.com/en-us/windows/win32/hidpi/wm-dpichanged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B - bug Dang, that shouldn't have happened DS - windows
Development

No branches or pull requests

4 participants