Skip to content

Windows 11 24H2 mixed-DPI drag still grows windows in 0.30.13 #4600

Description

@wnunezc

Description

This is a follow-up to the closed issue #4041. The same Windows mixed-DPI drag/resize feedback loop is still reproducible with winit 0.30.13 on Windows 11 24H2.

When a maximized window is dragged from a 125% scaled primary monitor to a 100% scaled monitor, the restored window can grow to an extremely large size and remain attached to the original monitor instead of landing on the target monitor. This also reproduces through eframe 0.29.1, because it uses winit underneath.

Monitor layout used for reproduction

  • DISPLAY5: 1920x1080, 100% scale, positioned left of primary: (-1920,0)-(0,1080)
  • DISPLAY1: 1920x1080, 125% scale, primary: (0,0)-(1920,1080)
  • DISPLAY6: 1920x1200, 125% scale, positioned right: (1920,-65)-(3456,895)

Minimal repro

Two minimal binaries were tested:

  1. Raw winit 0.30.13:
use winit::{
    application::ApplicationHandler,
    dpi::LogicalSize,
    event::WindowEvent,
    event_loop::{ActiveEventLoop, EventLoop},
    window::{Window, WindowAttributes, WindowId},
};

#[derive(Default)]
struct App { window: Option<Window> }

impl ApplicationHandler for App {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        if self.window.is_none() {
            let attrs = WindowAttributes::default()
                .with_title("repro_winit")
                .with_inner_size(LogicalSize::new(1000.0, 650.0))
                .with_maximized(true);
            self.window = Some(event_loop.create_window(attrs).expect("create window"));
        }
    }

    fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) {
        if matches!(event, WindowEvent::CloseRequested) {
            event_loop.exit();
        }
    }
}

fn main() {
    let event_loop = EventLoop::new().expect("event loop");
    let mut app = App::default();
    event_loop.run_app(&mut app).expect("run app");
}
  1. eframe 0.29.1 with ViewportBuilder::with_maximized(true) also reproduces the same behavior.

Both binaries used a PerMonitorV2 manifest.

Observed measurement without patch

Raw winit 0.30.13, after dragging from DISPLAY1 to the left monitor:

Before:
  ShowCmd: 3
  Rect: (-9,-9)-(1929,1029)
  Normal: (32,32)-(1300,892)
  Monitor: \\.\DISPLAY1
  DPI: 120

After drag:
  ShowCmd: 1
  Rect: (-1329,75)-(2545,2701)
  Size: 3874x2626
  Monitor: \\.\DISPLAY1
  DPI: 120

eframe 0.29.1 showed the same class of failure:

After drag:
  Rect: (-1164,75)-(1935,2176)
  Size: 3099x2101
  Monitor: \\.\DISPLAY1
  DPI: 120

Local patch tested

The issue disappears when WM_DPICHANGED while WindowFlags::MARKER_IN_SIZE_MOVE uses the Windows-provided suggested_rect directly instead of applying the current conservative rect / monitor nudge logic.

Patch tested locally against winit 0.30.13:

let new_outer_rect: RECT;
if dragging_window {
    new_outer_rect = suggested_rect;
} else {
    // existing conservative_rect + monitor nudge logic
}

Observed measurement with local patch

Raw winit 0.30.13 patched:

Before:
  ShowCmd: 3
  Rect: (-9,-9)-(1929,1029)
  Normal: (160,160)-(1428,1020)
  Monitor: \\.\DISPLAY1
  DPI: 120

After drag:
  ShowCmd: 1
  Rect: (-1417,79)-(-403,767)
  Size: 1014x688
  Monitor: \\.\DISPLAY5
  DPI: 96

eframe 0.29.1 using the patched winit also behaves correctly:

After drag:
  Rect: (-1404,79)-(-390,767)
  Size: 1014x688
  Monitor: \\.\DISPLAY5
  DPI: 96

Notes

This matches the analysis already posted in #4041: during WM_DPICHANGED, the current monitor check / nudge logic can keep the window on the old monitor, trigger another DPI change, and repeatedly enlarge the window. Microsoft's WM_DPICHANGED guidance recommends applying the suggested rectangle from lParam with SetWindowPos.

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

Platform

  • Windows 11 24H2
  • winit 0.30.13
  • Reproduces with raw winit and through eframe 0.29.1
  • Process DPI awareness: Per Monitor Aware (GetProcessDpiAwareness == 2)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions