From a080e883e2e5eb60052c66054cf9c9b5670726d5 Mon Sep 17 00:00:00 2001 From: Alex <261782908+amail80@users.noreply.github.com> Date: Sat, 1 Aug 2026 05:13:32 +0000 Subject: [PATCH] Windows: bring the main window back on screen when its restore position 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. --- src/Mount/Mount.c | 137 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 8 deletions(-) diff --git a/src/Mount/Mount.c b/src/Mount/Mount.c index 8d72805d73..5ea0a04843 100644 --- a/src/Mount/Mount.c +++ b/src/Mount/Mount.c @@ -958,6 +958,11 @@ void EndMainDlg (HWND hwndDlg) } } +/* Outer size of the main window, refreshed at the end of InitMainDialog once the + layout is final. A window parked off screen carries the parking size, so it + cannot serve as a source for the normal dimensions. */ +static SIZE MainDlgNormalSize = {0}; + static void InitMainDialog (HWND hwndDlg) { MENUITEMINFOW info; @@ -1089,6 +1094,19 @@ static void InitMainDialog (HWND hwndDlg) { SetWindowPos (hwndDlg, NULL, 0, 0, mainWidth, correctHeigth , SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); } + + /* The layout is final here, including the font compensation above, so + record the window size for RepairMainWindowPlacement. A minimized + window would report the parking size instead. */ + if (!IsIconic (hwndDlg)) + { + RECT rcNormal; + if (GetWindowRect (hwndDlg, &rcNormal)) + { + MainDlgNormalSize.cx = rcNormal.right - rcNormal.left; + MainDlgNormalSize.cy = rcNormal.bottom - rcNormal.top; + } + } } } @@ -8005,6 +8023,76 @@ static void SignalExitCode (int exitCode) } } +/* Repair the main window's restore position when it points outside every monitor. + + 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 clear WS_MINIMIZE. The + window is then, by every API, a normal visible window that happens to live + 32000 pixels off screen, and no amount of ShowWindow (SW_RESTORE) brings it + back: the restore rectangle is exactly where it already is. + + showCmd is deliberately left as GetWindowPlacement returned it, so that a + legitimately minimized window stays minimized and only its future restore + position is corrected. Returns TRUE when a repair was performed. */ +static BOOL RepairMainWindowPlacement (HWND hwnd) +{ + WINDOWPLACEMENT wp; + MONITORINFO mi; + RECT workArea; + LONG width, height; + + memset (&wp, 0, sizeof (wp)); + wp.length = sizeof (wp); + + if (!GetWindowPlacement (hwnd, &wp)) + return FALSE; + + width = MainDlgNormalSize.cx; + height = MainDlgNormalSize.cy; + if (width <= 0 || height <= 0) + return FALSE; + + /* Repair when the restore rectangle lies outside every monitor, and also + when it is no larger than a minimized window: the position may have been + pulled back inside the desktop while the parking dimensions were left + behind, which would restore the dialog as a sliver. Neither state can be + reached by resizing, the dialog having a fixed size. */ + if (MonitorFromRect (&wp.rcNormalPosition, MONITOR_DEFAULTTONULL) + && ((wp.rcNormalPosition.right - wp.rcNormalPosition.left) > GetSystemMetrics (SM_CXMINIMIZED) + || (wp.rcNormalPosition.bottom - wp.rcNormalPosition.top) > GetSystemMetrics (SM_CYMINIMIZED))) + return FALSE; + + mi.cbSize = sizeof (mi); + if (!GetMonitorInfo (MonitorFromWindow (hwnd, MONITOR_DEFAULTTOPRIMARY), &mi)) + return FALSE; + + wp.rcNormalPosition.left = mi.rcWork.left + ((mi.rcWork.right - mi.rcWork.left) - width) / 2; + wp.rcNormalPosition.top = mi.rcWork.top + ((mi.rcWork.bottom - mi.rcWork.top) - height) / 2; + wp.rcNormalPosition.right = wp.rcNormalPosition.left + width; + wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + height; + + /* rcNormalPosition is expressed in workspace coordinates: screen coordinates + minus the origin of the work area of the PRIMARY monitor, whichever + monitor the window itself lives on. This is a property of the coordinate + system, not of the target monitor, so SPI_GETWORKAREA is deliberately used + here rather than the rcWork of the monitor we center on. The two coincide + unless an appbar is docked to the top or the left of the primary monitor. */ + if (SystemParametersInfo (SPI_GETWORKAREA, 0, &workArea, 0)) + OffsetRect (&wp.rcNormalPosition, -workArea.left, -workArea.top); + + SetWindowPlacement (hwnd, &wp); + return TRUE; +} + +static void ShowMainWindow (HWND hwnd) +{ + RepairMainWindowPlacement (hwnd); + ShowWindow (hwnd, SW_SHOW); + ShowWindow (hwnd, SW_RESTORE); +} + /* Except in response to the WM_INITDIALOG and WM_ENDSESSION messages, the dialog box procedure should return nonzero if it processes a message, and zero if it does not. */ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -8540,6 +8628,19 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa DialogBoxW (hInst, MAKEINTRESOURCEW (IDD_ABOUT_DLG), hwndDlg, (DLGPROC) AboutDlgProc); return 1; } + if ((wParam & 0xFFF0) == SC_RESTORE) + { + /* Sent when the taskbar button of a minimized window is clicked, a + path that reaches no other code of ours. Repair the restore + position first; when it had to be corrected, restore the window + here as well, the default handling having already read the + placement that was in effect when the message was dispatched. */ + if (RepairMainWindowPlacement (hwndDlg)) + { + ShowWindow (hwndDlg, SW_RESTORE); + return 1; + } + } return 0; case WM_HELP: @@ -8563,6 +8664,28 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa DismountAll (hwndDlg, bForceAutoDismount, TRUE, UNMOUNT_MAX_AUTO_RETRIES, UNMOUNT_AUTO_RETRY_DELAY); } } + + if (WTS_SESSION_UNLOCK == wParam) + { + /* Late in the sequence that follows a session lock, after the + deferred window repositioning the system performs when the + display topology changed while the session was locked. The + WM_DISPLAYCHANGE handler may run before that repositioning is + applied, so repeat the check here. */ + if (IsWindowVisible (hwndDlg)) + RepairMainWindowPlacement (hwndDlg); + } + return 0; + + case WM_DISPLAYCHANGE: + /* The display topology changed. Correct the restore position now if it + was left outside every monitor, so that the window can be shown again + through paths that do not run any of our code - clicking the taskbar + button merely activates an already visible window. A window hidden in + the notification area is skipped; its position is repaired by + ShowMainWindow when the user asks for it. */ + if (IsWindowVisible (hwndDlg)) + RepairMainWindowPlacement (hwndDlg); return 0; case WM_ENDSESSION: @@ -8803,8 +8926,7 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa case WM_LBUTTONDOWN: SetForegroundWindow (hwndDlg); MainWindowHidden = FALSE; - ShowWindow (hwndDlg, SW_SHOW); - ShowWindow (hwndDlg, SW_RESTORE); + ShowMainWindow (hwndDlg); return 1; case WM_RBUTTONUP: @@ -10055,8 +10177,7 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa case TC_APPMSG_MOUNT_SHOW_WINDOW: MainWindowHidden = FALSE; - ShowWindow (hwndDlg, SW_SHOW); - ShowWindow (hwndDlg, SW_RESTORE); + ShowMainWindow (hwndDlg); return 1; case VC_APPMSG_CREATE_RESCUE_DISK: @@ -12198,10 +12319,10 @@ void ChangeMainWindowVisibility () if (!MainWindowHidden) SetForegroundWindow (MainDlg); - ShowWindow (MainDlg, !MainWindowHidden ? SW_SHOW : SW_HIDE); - - if (!MainWindowHidden) - ShowWindow (MainDlg, SW_RESTORE); + if (MainWindowHidden) + ShowWindow (MainDlg, SW_HIDE); + else + ShowMainWindow (MainDlg); }