rust-windowing / rust-windowing/winit

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

Open
#4,600 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
6.2k
Forks
1.3k
Avg merge
2d 19h
Merged PRs (30d)
9

Description

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)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the Windows WM_DPICHANGED handling for WindowFlags::MARKER_IN_SIZE_MOVE, then run the minimal winit binary on the documented mixed-DPI monitor layout. Compare the drag path with the existing conservative-rect and monitor-nudge logic; done means the restored window lands on the target monitor without growing excessively, while preserving the non-drag behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.