fix(startup): hide at three points during FormCreate, and prove when it shows

The timeline says FormCreate itself runs for 1.02 s (45.509 → 46.532) while
the hide only landed at 46.663 — so if the window is visible during that
stretch, it accounts for exactly the second being reported.

TrayHideNow() hides the form AND the FMX taskbar proxy, and is now called at
three points: top of FormCreate, right after the browser is parented (which
forces the handle to exist, the likely moment FMX shows it), and at the end of
FormCreate — plus the existing on-activate one-shot.

It also logs whether the window WAS visible each time, which pins down exactly
where FMX turns it on instead of another guess.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-07-27 10:53:22 +01:00
parent 0506d757dd
commit 283676224f
+24 -14
View File
@@ -173,6 +173,9 @@ type
// stuck raised (see the implementation).
// One-shot: hides the window the first time FMX shows it on a --tray
// launch, then unhooks itself.
// Hides the form AND the FMX taskbar proxy right now, logging whether the
// window was actually visible — that is what pins down when FMX shows it.
procedure TrayHideNow(const ATag: string);
procedure TrayStartupHideOnce(Sender: TObject);
procedure RestoreWindowFromTray;
procedure WinStateMinimizeStart;
@@ -221,6 +224,7 @@ begin
Visible := False;
OnActivate := TrayStartupHideOnce;
LogLine('[tray] FormCreate begin at ' + FormatDateTime('hh:nn:ss.zzz', Now));
TrayHideNow('hide#1 top-of-FormCreate');
end;
// The .fmx ships WindowState = wsMaximized, so that is the starting intent.
@@ -261,6 +265,9 @@ begin
{$ENDIF}
WebBrowser.Parent := Self;
WebBrowser.Align := TAlignLayout.Client;
// Parenting forces the form's window handle to exist, and that is the point
// FMX may show it — hide again right away.
if FindCmdLineSwitch('tray', True) then TrayHideNow('hide#2 after-browser-parent');
FServer := TPMHTTPServer.Create;
FServer.OnLog := LogLine;
@@ -326,7 +333,7 @@ begin
// it's noise when Windows itself put us in the tray (the user
// didn't actively minimise). Manual launches still see it once.
FBridge.BalloonShown := True;
LogLine('[tray] FormCreate end at ' + FormatDateTime('hh:nn:ss.zzz', Now));
TrayHideNow('hide#3 end-of-FormCreate');
TThread.ForceQueue(nil,
procedure
begin
@@ -1601,24 +1608,27 @@ begin
else if AEvent = EVENT_SYSTEM_MINIMIZEEND then MainForm.WinStateMinimizeEnd;
end;
procedure TMainForm.TrayStartupHideOnce(Sender: TObject);
procedure TMainForm.TrayHideNow(const ATag: string);
var
LHwnd, LAppHwnd: HWND;
LWasVisible: Boolean;
begin
LHwnd := WindowHandleToPlatform(Self.Handle).Wnd;
LWasVisible := (LHwnd <> 0) and IsWindowVisible(LHwnd);
if LHwnd <> 0 then ShowWindow(LHwnd, SW_HIDE);
LAppHwnd := 0;
if Assigned(FBridge) then LAppHwnd := FBridge.FindFMXAppWindow;
if LAppHwnd <> 0 then ShowWindow(LAppHwnd, SW_HIDE);
LogLine(Format('[tray] %s at %s — form_visible_was=%s hwnd=%d app=%d',
[ATag, FormatDateTime('hh:nn:ss.zzz', Now),
BoolToStr(LWasVisible, True), LHwnd, LAppHwnd]));
end;
procedure TMainForm.TrayStartupHideOnce(Sender: TObject);
begin
OnActivate := nil; // one shot — never fight the user afterwards
Visible := False;
LHwnd := WindowHandleToPlatform(Self.Handle).Wnd;
if LHwnd <> 0 then
ShowWindow(LHwnd, SW_HIDE);
// The taskbar entry belongs to the FMX proxy window, not the form — hiding
// the form alone leaves the button on the taskbar.
if Assigned(FBridge) then
begin
LAppHwnd := FBridge.FindFMXAppWindow;
if LAppHwnd <> 0 then ShowWindow(LAppHwnd, SW_HIDE);
end;
LogLine('[tray] activate-hide fired at ' +
FormatDateTime('hh:nn:ss.zzz', Now));
TrayHideNow('hide#4 on-activate');
end;
// Single entry point for every tray restore. ExecuteAutofill really minimises