From 0506d757dd79199e5d78c59d990a466633f1a53b Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Mon, 27 Jul 2026 10:47:25 +0100 Subject: [PATCH] fix(startup): hide the taskbar proxy too, and trace the --tray timeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The window still showed, taskbar entry included. Two things. The taskbar button belongs to the FMX proxy window (TFMAppClass), a separate top-level window from the form — hiding the form alone never removed it. FindFMXAppWindow moves from private to public so the activate-hide can drop both. (Guarded on Assigned(FBridge): the handler is installed at line 222, the bridge is created at 268.) And rather than guess a fourth time at FMX's startup order — the same trap as the window-state saga, which only fell to instrumentation — this logs a millisecond timeline: FormCreate begin/end, the activate-hide, and the deferred MinimizeToTray. Whichever gap holds the second will be obvious. Co-Authored-By: Claude Opus 4.8 --- delphi-backend/Source/PM.Bridge.pas | 5 ++++- delphi-backend/UMainForm.pas | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/delphi-backend/Source/PM.Bridge.pas b/delphi-backend/Source/PM.Bridge.pas index 8957cd4..bf7607d 100644 --- a/delphi-backend/Source/PM.Bridge.pas +++ b/delphi-backend/Source/PM.Bridge.pas @@ -140,8 +140,11 @@ type procedure PrepareNid; procedure ShowTrayMenu; procedure ShowFirstTimeBalloon; - function FindFMXAppWindow: HWND; public + // The FMX taskbar proxy (TFMAppClass) — a SEPARATE top-level window from + // the form, and the one that owns the taskbar entry. Public so the host + // can hide it during a --tray launch, before MinimizeToTray gets to run. + function FindFMXAppWindow: HWND; // Tray balloon (caller applies its own gating setting). Used for // messages the user must see while the window is hidden — e.g. an // autofill blocked by an elevated target. diff --git a/delphi-backend/UMainForm.pas b/delphi-backend/UMainForm.pas index 2929977..7078051 100644 --- a/delphi-backend/UMainForm.pas +++ b/delphi-backend/UMainForm.pas @@ -220,6 +220,7 @@ begin begin Visible := False; OnActivate := TrayStartupHideOnce; + LogLine('[tray] FormCreate begin at ' + FormatDateTime('hh:nn:ss.zzz', Now)); end; // The .fmx ships WindowState = wsMaximized, so that is the starting intent. @@ -325,11 +326,13 @@ 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)); TThread.ForceQueue(nil, procedure begin FBridge.MinimizeToTray; - LogLine('Launched with --tray, minimised at startup (balloon suppressed)'); + LogLine('[tray] deferred MinimizeToTray ran at ' + + FormatDateTime('hh:nn:ss.zzz', Now)); end); end; end; @@ -1600,13 +1603,22 @@ end; procedure TMainForm.TrayStartupHideOnce(Sender: TObject); var - LHwnd: HWND; + LHwnd, LAppHwnd: HWND; 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)); end; // Single entry point for every tray restore. ExecuteAutofill really minimises