fix(window): stop forcing maximised on a window the user left normal
The previous version over-corrected: a normal window came back maximised after Win+D. Two causes, both fixed. - It read FMX's WindowState, which does not reliably follow a native un-maximise, so FWantMaximized never cleared. Now reads Win32 IsZoomed / IsIconic, which is the actual truth. - The restore fires its own resize, reporting whatever FMX decided — recording that erased the very intent we were preserving. FWasMinimized now gates the restore's resize out of the tracking. Activate then corrects both directions: re-maximise when FMX dropped a maximised window, restore when Windows brought a normal one back maximised. Degrades safely — if the minimise resize never fires, it simply does nothing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -79,6 +79,9 @@ type
|
|||||||
// which happens however the user comes back. FWantMaximized mirrors the
|
// which happens however the user comes back. FWantMaximized mirrors the
|
||||||
// user's LAST deliberate choice, so we never fight a normal-size window.
|
// user's LAST deliberate choice, so we never fight a normal-size window.
|
||||||
FWantMaximized: Boolean;
|
FWantMaximized: Boolean;
|
||||||
|
// True between an external minimise and the following activate, so the
|
||||||
|
// restore's own resize is not mistaken for a user resize.
|
||||||
|
FWasMinimized: Boolean;
|
||||||
FServer: TPMHTTPServer;
|
FServer: TPMHTTPServer;
|
||||||
FBridge: TPMBridge;
|
FBridge: TPMBridge;
|
||||||
// Accumulates base64 chunks for large file saves (attachments too big
|
// Accumulates base64 chunks for large file saves (attachments too big
|
||||||
@@ -174,6 +177,7 @@ begin
|
|||||||
// The .fmx ships WindowState = wsMaximized, so that is the starting intent.
|
// The .fmx ships WindowState = wsMaximized, so that is the starting intent.
|
||||||
// Wired here (not in the .fmx) to keep the designer file untouched.
|
// Wired here (not in the .fmx) to keep the designer file untouched.
|
||||||
FWantMaximized := (WindowState = TWindowState.wsMaximized);
|
FWantMaximized := (WindowState = TWindowState.wsMaximized);
|
||||||
|
FWasMinimized := False;
|
||||||
OnResize := FormResizeTrackState;
|
OnResize := FormResizeTrackState;
|
||||||
OnActivate := FormActivateRestoreState;
|
OnActivate := FormActivateRestoreState;
|
||||||
|
|
||||||
@@ -1503,23 +1507,44 @@ begin
|
|||||||
Application.Terminate;
|
Application.Terminate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Remember the window state the USER settled on. Minimised is skipped on
|
// Remember the state the USER settled on. Reads Win32 (IsZoomed/IsIconic)
|
||||||
// purpose: that is precisely the state we have to survive, not record.
|
// rather than FMX's WindowState, which does not reliably follow a native
|
||||||
|
// un-maximise — that is why the first version never cleared the flag.
|
||||||
|
//
|
||||||
|
// The restore itself fires a resize too, and that one must NOT be recorded:
|
||||||
|
// it reports whatever FMX decided (often "normal"), which would erase the
|
||||||
|
// intent we are trying to preserve. FWasMinimized gates it out.
|
||||||
procedure TMainForm.FormResizeTrackState(Sender: TObject);
|
procedure TMainForm.FormResizeTrackState(Sender: TObject);
|
||||||
|
var
|
||||||
|
LHwnd: HWND;
|
||||||
begin
|
begin
|
||||||
if WindowState = TWindowState.wsMaximized then
|
LHwnd := WindowHandleToPlatform(Self.Handle).Wnd;
|
||||||
FWantMaximized := True
|
if LHwnd = 0 then Exit;
|
||||||
else if WindowState = TWindowState.wsNormal then
|
if IsIconic(LHwnd) then
|
||||||
FWantMaximized := False;
|
begin
|
||||||
|
FWasMinimized := True; // the state we must survive, not record
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
if FWasMinimized then Exit; // this resize IS the restore
|
||||||
|
FWantMaximized := IsZoomed(LHwnd); // genuine user-driven resize
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Re-apply "maximised" when the window comes back from an external minimise.
|
// Re-apply the remembered state once the window is back. Runs however the
|
||||||
// Runs however the user returns (taskbar, tray, Alt+Tab), because none of our
|
// user returns (taskbar, tray, Alt+Tab) — a plain taskbar restore never goes
|
||||||
// own restore paths are involved in a plain taskbar click.
|
// through any of our own restore paths. Corrects BOTH directions: FMX drops
|
||||||
|
// a maximised window to normal, and Windows can restore a normal window
|
||||||
|
// maximised.
|
||||||
procedure TMainForm.FormActivateRestoreState(Sender: TObject);
|
procedure TMainForm.FormActivateRestoreState(Sender: TObject);
|
||||||
|
var
|
||||||
|
LHwnd: HWND;
|
||||||
begin
|
begin
|
||||||
if FWantMaximized and (WindowState = TWindowState.wsNormal) then
|
if not FWasMinimized then Exit;
|
||||||
WindowState := TWindowState.wsMaximized;
|
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);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.AutofillTimerTick(Sender: TObject);
|
procedure TMainForm.AutofillTimerTick(Sender: TObject);
|
||||||
|
|||||||
Reference in New Issue
Block a user