From 03a8a6f8a6ecd3afb94f7ab49ceec0c938979c5a Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Sat, 25 Jul 2026 19:58:27 +0100 Subject: [PATCH] fix(window): re-apply maximised after an external minimise (Win+D) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The earlier fix only covered the tray restore path, but Show desktop / taskbar restore never runs our code at all — it is pure Windows + FMX, and FMX brings the window back "normal" after forgetting it was maximised. Track the state the user actually settled on (OnResize, ignoring wsMinimized since that is the state we must survive) and re-apply it on OnActivate, which fires however the user returns: taskbar, tray or Alt+Tab. Gated on FWantMaximized so a window the user deliberately un-maximised is left alone. Co-Authored-By: Claude Opus 4.8 --- delphi-backend/UMainForm.pas | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/delphi-backend/UMainForm.pas b/delphi-backend/UMainForm.pas index 77292da..af5274c 100644 --- a/delphi-backend/UMainForm.pas +++ b/delphi-backend/UMainForm.pas @@ -72,6 +72,13 @@ type procedure btnToggleLogClick(Sender: TObject); procedure btnReloadClick(Sender: TObject); private + // Windows minimising the window from the outside (Win+D / Show desktop / + // taskbar) makes FMX forget it was maximised: the window comes back + // "normal". None of our restore paths run in that case — the taskbar + // restore is pure Windows + FMX — so the state is re-applied on activate, + // which happens however the user comes back. FWantMaximized mirrors the + // user's LAST deliberate choice, so we never fight a normal-size window. + FWantMaximized: Boolean; FServer: TPMHTTPServer; FBridge: TPMBridge; // Accumulates base64 chunks for large file saves (attachments too big @@ -116,6 +123,8 @@ type // needing two .fmx variants. Aligned to Client to fill the remaining // space between PanelTop (top) and PanelLog/Splitter (bottom). WebBrowser: TWebBrowserClass; + procedure FormActivateRestoreState(Sender: TObject); + procedure FormResizeTrackState(Sender: TObject); procedure AutofillTimerTick(Sender: TObject); // Shared by cmd://file/save (single-shot) and file/save-commit // (chunked): decode the base64, show the Save dialog, write, and fire @@ -162,6 +171,12 @@ function MaskAccessToken(const AUrl: string): string; forward; procedure TMainForm.FormCreate(Sender: TObject); begin + // The .fmx ships WindowState = wsMaximized, so that is the starting intent. + // Wired here (not in the .fmx) to keep the designer file untouched. + FWantMaximized := (WindowState = TWindowState.wsMaximized); + OnResize := FormResizeTrackState; + OnActivate := FormActivateRestoreState; + // Create the WebBrowser control programmatically so the {$IFDEF // USE_EDGE_BROWSER} directive can swap the concrete class without a // second .fmx variant. Align Client to fill the area below PanelTop @@ -1488,6 +1503,25 @@ begin Application.Terminate; end; +// Remember the window state the USER settled on. Minimised is skipped on +// purpose: that is precisely the state we have to survive, not record. +procedure TMainForm.FormResizeTrackState(Sender: TObject); +begin + if WindowState = TWindowState.wsMaximized then + FWantMaximized := True + else if WindowState = TWindowState.wsNormal then + FWantMaximized := False; +end; + +// Re-apply "maximised" when the window comes back from an external minimise. +// Runs however the user returns (taskbar, tray, Alt+Tab), because none of our +// own restore paths are involved in a plain taskbar click. +procedure TMainForm.FormActivateRestoreState(Sender: TObject); +begin + if FWantMaximized and (WindowState = TWindowState.wsNormal) then + WindowState := TWindowState.wsMaximized; +end; + procedure TMainForm.AutofillTimerTick(Sender: TObject); var TargetHwnd: HWND;