From ab12f6bf66cbc7b238f8f6323c3bf86ae51a1294 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Sat, 25 Jul 2026 20:13:30 +0100 Subject: [PATCH] fix(window): apply the restore correction after FMX finishes, with tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FWasMinimized gate never armed — FMX evidently fires no resize while the window is iconic — so activate bailed out and the maximised window still came back normal. Stop depending on that signal or on event ordering: snapshot the intent at activate (before a restore-time resize can overwrite it) and apply the correction from a queued call, which necessarily runs after FMX has finished sizing the window. FRestoring keeps that resize out of the tracking, and the intent is re-asserted afterwards since our own ShowWindow fires one too. Adds [winstate] LogLine traces so the next iteration works from observed event order instead of guesses (needs config.txt with debug=true). Co-Authored-By: Claude Opus 4.8 --- delphi-backend/UMainForm.pas | 52 +++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/delphi-backend/UMainForm.pas b/delphi-backend/UMainForm.pas index ce19268..016e758 100644 --- a/delphi-backend/UMainForm.pas +++ b/delphi-backend/UMainForm.pas @@ -82,6 +82,9 @@ type // True between an external minimise and the following activate, so the // restore's own resize is not mistaken for a user resize. FWasMinimized: Boolean; + // Set from activate until the queued correction runs, so the restore's + // own resize is not mistaken for the user resizing the window. + FRestoring: Boolean; FServer: TPMHTTPServer; FBridge: TPMBridge; // Accumulates base64 chunks for large file saves (attachments too big @@ -178,6 +181,7 @@ begin // Wired here (not in the .fmx) to keep the designer file untouched. FWantMaximized := (WindowState = TWindowState.wsMaximized); FWasMinimized := False; + FRestoring := False; OnResize := FormResizeTrackState; OnActivate := FormActivateRestoreState; @@ -1523,10 +1527,18 @@ begin if IsIconic(LHwnd) then begin FWasMinimized := True; // the state we must survive, not record + LogLine('[winstate] resize: minimised'); + Exit; + end; + if FRestoring then + begin + // The restore's own resize: reports whatever FMX decided, not intent. + LogLine('[winstate] resize during restore ignored (zoomed=' + + BoolToStr(IsZoomed(LHwnd), True) + ')'); Exit; end; - if FWasMinimized then Exit; // this resize IS the restore FWantMaximized := IsZoomed(LHwnd); // genuine user-driven resize + LogLine('[winstate] resize: want_max=' + BoolToStr(FWantMaximized, True)); end; // Re-apply the remembered state once the window is back. Runs however the @@ -1536,15 +1548,37 @@ end; // maximised. procedure TMainForm.FormActivateRestoreState(Sender: TObject); var - LHwnd: HWND; + LWant: Boolean; begin - if not FWasMinimized then Exit; - LHwnd := WindowHandleToPlatform(Self.Handle).Wnd; - if (LHwnd = 0) or IsIconic(LHwnd) then Exit; - FWasMinimized := False; - if FWantMaximized = IsZoomed(LHwnd) then Exit; // already right - if FWantMaximized then ShowWindow(LHwnd, SW_SHOWMAXIMIZED) - else ShowWindow(LHwnd, SW_RESTORE); + // Snapshot the intent NOW: FMX's restore-time resize may land before or + // after this activate depending on how the window came back, and if it + // lands first it would already have overwritten FWantMaximized. + LWant := FWantMaximized; + if FRestoring then Exit; // one correction per return + FRestoring := True; + LogLine('[winstate] activate: want_max=' + BoolToStr(LWant, True) + + ' was_min=' + BoolToStr(FWasMinimized, True)); + // Queue the correction so it runs AFTER FMX has finished restoring the + // window — applying it inline loses the race against FMX's own sizing. + TThread.ForceQueue(nil, + procedure + var + LHwnd: HWND; + begin + FRestoring := False; + FWasMinimized := False; + LHwnd := WindowHandleToPlatform(Self.Handle).Wnd; + if (LHwnd = 0) or IsIconic(LHwnd) then Exit; + if LWant <> IsZoomed(LHwnd) then + begin + LogLine('[winstate] correcting to ' + + BoolToStr(LWant, True) + ' (was zoomed=' + + BoolToStr(IsZoomed(LHwnd), True) + ')'); + if LWant then ShowWindow(LHwnd, SW_SHOWMAXIMIZED) + else ShowWindow(LHwnd, SW_RESTORE); + end; + FWantMaximized := LWant; // our own ShowWindow fired a resize too + end); end; procedure TMainForm.AutofillTimerTick(Sender: TObject);