Fix Windows multi-monitor window restore via WINDOWPLACEMENT - #8331
Open
Dvow wants to merge 5 commits into
Open
Conversation
Persisting logical pos/size breaks on mixed-DPI setups and loses the true restore rect when maximized or Aero-snapped. Capture Win32 WINDOWPLACEMENT, apply it twice with SW_HIDE before the first paint (so WM_DPICHANGED settles), create with position only using GetDpiForMonitor (never with_inner_size), cloak until after the first present, and defer geometry persist until reveal settles. When not max/min, prefer the visible GetWindowRect (screen→workspace) if width/height differs from rcNormalPosition (wxWidgets snap rule), so Aero Snap size is remembered without DPI jitter creep. Non-Windows paths stay on winit with a plain set_visible; only Windows links windows-sys / DWM cloak.
|
Preview is being built... Preview will be available at https://egui-pr-preview.github.io/pr/8331-fix/windows-windowplacement-restore View snapshot changes at kitdiff |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Persisting logical window position/size is not enough on Windows. On mixed-DPI and multi-monitor setups, winit-based restore can land on the wrong monitor, grow across restarts, fail to restore maximized state correctly (especially on a secondary display), forget Aero Snap size, and flash an empty frame on first show.
This change saves and restores the native Win32
WINDOWPLACEMENTblob. On create we apply only the restored position, scaled withGetDpiForMonitorfor the target rect, and intentionally skipwith_inner_sizeso create DPI and placement DPI cannot compound. Placement is applied twice while the window is still hidden (SW_HIDE) soWM_DPICHANGEDcan settle before the first paint. Maximized restore additionally sizes to the monitor work area before show.First show is DWM-cloaked, then revealed around the first present (glow uncloaks in the same frame; wgpu needs one extra redraw), and window-geometry persistence is deferred until after that reveal so mid-restore geometry is never written back. When a restored placement is present, centering and the old clamp/size paths are skipped so they cannot fight Win32 restore.
Aero Snap is handled explicitly:
GetWindowPlacementkeeps the pre-snap restore rect inrcNormalPosition, so when the window is not min/max and the visible size differs, we store the visibleGetWindowRectconverted screen→workspace (wxWidgets-style size compare with tolerance) instead.Non-Windows keeps the existing winit path with a plain
set_visibleon first show.windows-sysis linked on Windows only.