fix(window): use foreground ownership to tell a user resize from a restore
The log settled the previous attempt: WPF_RESTORETOMAXIMIZED (flags=2) is set for ANY maximised window, not just one on its way back from minimised, and showCmd is already 1/3 by the time the resize fires. Testing those classified the user's own Maximize click as a restore, so the intent was never recorded (want stayed False) and nothing could be re-applied afterwards. Windows exposes no restore marker here. What does separate the two: a user gesture happens while the window OWNS THE FOREGROUND; FMX's re-layout during a restore (and during the startup burst) runs before it does. Resizes that arrive without foreground ownership are no longer recorded as intent, and re-apply a maximised state the user had left. Placement is still read, for the log only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1520,24 +1520,27 @@ begin
|
|||||||
if LHwnd = 0 then Exit;
|
if LHwnd = 0 then Exit;
|
||||||
if IsIconic(LHwnd) then Exit; // nothing to learn while minimised
|
if IsIconic(LHwnd) then Exit; // nothing to learn while minimised
|
||||||
|
|
||||||
// OnActivate turned out to be useless as a "the window came back" signal —
|
// Windows offers no usable "this resize is a restore" signal: the log showed
|
||||||
// it also fires on plain focus churn with the WebView2 child, and even right
|
// WPF_RESTORETOMAXIMIZED (flags=2) is set for ANY maximised window, and
|
||||||
// after the user clicks Maximize. Ask Windows instead: WPF_RESTORETOMAXIMIZED
|
// showCmd is already 1/3 by then — testing those classified the user's own
|
||||||
// means "this window is on its way back from minimised and belongs
|
// Maximize click as a restore and dropped the intent.
|
||||||
// maximised", which is exactly the resize we must not mistake for the user
|
//
|
||||||
// un-maximising.
|
// What does separate them: a user gesture happens while the window is the
|
||||||
FillChar(LPlace, SizeOf(LPlace), 0);
|
// FOREGROUND window. FMX's re-layout during a restore (and during startup)
|
||||||
|
// runs before the window owns the foreground.
|
||||||
|
LIsRestore := GetForegroundWindow <> LHwnd;
|
||||||
|
FillChar(LPlace, SizeOf(LPlace), 0); // diagnostics only
|
||||||
LPlace.length := SizeOf(LPlace);
|
LPlace.length := SizeOf(LPlace);
|
||||||
LIsRestore := GetWindowPlacement(LHwnd, @LPlace) and
|
GetWindowPlacement(LHwnd, @LPlace);
|
||||||
(((LPlace.flags and WPF_RESTORETOMAXIMIZED) <> 0) or
|
LogLine(Format('[winstate] resize zoomed=%s showCmd=%d flags=%d fg=%s want=%s',
|
||||||
(LPlace.showCmd = SW_SHOWMINIMIZED));
|
|
||||||
LogLine(Format('[winstate] resize zoomed=%s showCmd=%d flags=%d restore=%s want=%s',
|
|
||||||
[BoolToStr(IsZoomed(LHwnd), True), LPlace.showCmd, LPlace.flags,
|
[BoolToStr(IsZoomed(LHwnd), True), LPlace.showCmd, LPlace.flags,
|
||||||
BoolToStr(LIsRestore, True), BoolToStr(FWantMaximized, True)]));
|
BoolToStr(not LIsRestore, True), BoolToStr(FWantMaximized, True)]));
|
||||||
|
|
||||||
if LIsRestore then
|
if LIsRestore then
|
||||||
begin
|
begin
|
||||||
// Re-apply after FMX has finished sizing; doing it inline loses the race.
|
// Not a user gesture — never record it as intent. If it dropped a window
|
||||||
|
// the user had left maximised, put it back (queued: inline loses the race
|
||||||
|
// against FMX's own sizing).
|
||||||
if FWantMaximized and (not IsZoomed(LHwnd)) and (not FRestoring) then
|
if FWantMaximized and (not IsZoomed(LHwnd)) and (not FRestoring) then
|
||||||
begin
|
begin
|
||||||
FRestoring := True;
|
FRestoring := True;
|
||||||
@@ -1552,7 +1555,7 @@ begin
|
|||||||
ShowWindow(LH, SW_SHOWMAXIMIZED);
|
ShowWindow(LH, SW_SHOWMAXIMIZED);
|
||||||
end);
|
end);
|
||||||
end;
|
end;
|
||||||
Exit; // never record a restore as intent
|
Exit;
|
||||||
end;
|
end;
|
||||||
if FRestoring then Exit; // our own ShowWindow's resize
|
if FRestoring then Exit; // our own ShowWindow's resize
|
||||||
FWantMaximized := IsZoomed(LHwnd); // genuine user gesture
|
FWantMaximized := IsZoomed(LHwnd); // genuine user gesture
|
||||||
|
|||||||
Reference in New Issue
Block a user