From 283676224f803f9c68d53f119eff15a5dfeda190 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Mon, 27 Jul 2026 10:53:22 +0100 Subject: [PATCH] fix(startup): hide at three points during FormCreate, and prove when it shows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- delphi-backend/UMainForm.pas | 38 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/delphi-backend/UMainForm.pas b/delphi-backend/UMainForm.pas index 7078051..d6ce83a 100644 --- a/delphi-backend/UMainForm.pas +++ b/delphi-backend/UMainForm.pas @@ -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