Windows: bring the main window back on screen when its restore position is off screen - #1858
Open
amail80 wants to merge 1 commit into
Open
Windows: bring the main window back on screen when its restore position is off screen#1858amail80 wants to merge 1 commit into
amail80 wants to merge 1 commit into
Conversation
…on is off screen A minimized window is parked by Windows at (-32000,-32000). When the display topology changes while it is minimized - which happens on every session lock that powers off a monitor - Windows can copy that parking position into the window's restore rectangle and clear WS_MINIMIZE. The window then is, by every API, a normal visible window living 32000 pixels off screen: IsIconic returns FALSE, IsWindowVisible returns TRUE, and ShowWindow (SW_RESTORE) is a no-op because the restore rectangle is exactly where the window already is. The user is left with an application that answers its notification area icon but whose main window cannot be shown by any means, and only restarting VeraCrypt recovers it. Validate the restore rectangle and re-center it on the primary monitor when it intersects none. The repair runs from the three paths that show the window and, because clicking the taskbar button of an already visible window runs no application code at all, also on WM_DISPLAYCHANGE. showCmd is left as GetWindowPlacement returned it, so a legitimately minimized window stays minimized and only its future restore position is corrected. The window size is captured once after the dialog has been laid out: a parked window carries the parking size, so it cannot serve as a source for the normal dimensions. Verified on Windows 11 26200.8875 with two monitors at different scale factors, the primary one being powered off by the session lock: GetWindowPlacement returned rcNormalPosition = (-32000,-32000)-(-31840,-31972), and neither a notification area click nor an explicit minimize/restore cycle brought the window back.
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.
Windows can leave the main window in a state where it cannot be shown by any means, and only restarting VeraCrypt recovers it.
What happens
A minimized window is parked by Windows at
(-32000,-32000). When the display topology changes while the window is minimized — which happens on every session lock that powers off a monitor — Windows can copy that parking position into the window's restore rectangle and clearWS_MINIMIZE.The window is then, by every API, a normal visible window that happens to live 32000 pixels off screen.
IsIconicreturns FALSE,IsWindowVisiblereturns TRUE,IsHungAppWindowreturns FALSE, and the process is fully responsive — the notification area menu works, the message loop runs. But the window is nowhere, andShowWindow (SW_RESTORE)is a no-op because the restore rectangle is exactly where the window already is.Evidence
Captured during an occurrence, three snapshots half an hour apart, byte-for-byte identical:
The same window before the occurrence, normally minimized:
The styles differ by exactly
0x20000000, that isWS_MINIMIZE. The coordinates are the same.GetWindowPlacementshowed the cause directly:The position the window is supposed to return to points into the parking area. Every normal path therefore restores it there: a notification area click, an explicit
SW_RESTORE, and a forced minimize/restore cycle all put the window back in the same place. Only a directSetWindowPos, which bypasses the stored placement, brought it back.Not specific to VeraCrypt
The same loss was observed on the same machine with BiglyBT (Java/SWT) and Clash Verge — unrelated applications on unrelated toolkits, sharing only the fact that they were minimized when the topology changed. VeraCrypt cannot fix the cause, only guard against it; there is currently no code in the project that touches the main window position at all.
The change
RepairMainWindowPlacementvalidates the restore rectangle and re-centers it when it is unusable. It runs from the three paths that show the window, and — because clicking the taskbar button of a visible window runs no application code at all — also onWM_DISPLAYCHANGE, on session unlock, and onSC_RESTORE.Two conditions trigger a repair: the rectangle intersects no monitor, or it is no larger than a minimized window. The second case matters because Windows may pull a corrupted position back inside the desktop while leaving the parking dimensions behind, which would restore the dialog as a sliver a few pixels high. The comparison uses
SM_CXMINIMIZED/SM_CYMINIMIZEDrather than the dialog's own size, so a legitimate placement can never trigger it.showCmdis left asGetWindowPlacementreturned it, so a legitimately minimized window stays minimized and only its future restore position is corrected.SetWindowPlacementis used rather thanSetWindowPosso the correction also survives the next minimize/restore cycle.The window size is recorded at the end of
InitMainDialog, after the large-font compensation that may resize the dialog, so all three callers — including the language switch — refresh it. A parked window carries the parking size and is skipped.rcNormalPositionis in workspace coordinates, offset by the origin of the primary monitor's work area; the correction accounts for that withSPI_GETWORKAREA. On a default taskbar layout the offset is zero, but it is not with an appbar docked to the top or the left.When the placement is valid the whole thing costs one
MonitorFromRectcall on a path that only runs when the user asks for the window, and changes nothing.Testing
Built on Windows 11 26200.8875, MSVC,
/t:Mount /p:Configuration=Debug /p:Platform=x64. Two monitors at different scale factors, the primary one being the external display that the session lock powers off.The corrupted state can be produced on demand with
SetWindowPlacement, writing the parking rectangle intorcNormalPositionand then cyclingSW_MINIMIZE/SW_RESTOREso it settles. Verified that before the change no path shows the window, and after it the window returns centered.Verified unchanged behaviour for: a normally minimized window restored from the taskbar and from the notification area, a window shown and hidden through the notification area menu, and a resolution change with a valid placement (no repair triggered).