diff --git a/delphi-backend/UMainForm.pas b/delphi-backend/UMainForm.pas index 5db9d0b..2c6092b 100644 --- a/delphi-backend/UMainForm.pas +++ b/delphi-backend/UMainForm.pas @@ -169,6 +169,9 @@ type public // Called from the WinEvent hook. WINEVENT_OUTOFCONTEXT delivers through // our own message queue, so these already run on the main thread. + // Every tray restore goes through here so the minimise guard cannot get + // stuck raised (see the implementation). + procedure RestoreWindowFromTray; procedure WinStateMinimizeStart; procedure WinStateMinimizeEnd; end; @@ -407,7 +410,7 @@ begin // it vanishes from the taskbar it came from. Restored-from-iconic just // stays open after the modal closes. LWasHidden := not Self.Visible; - FBridge.RestoreFromTray; + RestoreWindowFromTray; LWasHiddenJs := BoolToStr(LWasHidden, True).ToLower; // Second arg forFill=true tells JS to SendInput on pick instead of copy. WebBrowser.ExecuteJavaScript( @@ -431,7 +434,7 @@ begin // can paste into the target app without an extra alt-tab. Iconic-only // (taskbar) does NOT count — see BridgeQuickSearchHotkey. LWasHidden := not Self.Visible; - FBridge.RestoreFromTray; + RestoreWindowFromTray; LWasHiddenJs := BoolToStr(LWasHidden, True).ToLower; WebBrowser.ExecuteJavaScript( 'if(window.Bridge&&typeof Bridge.openQuickSearch==="function")' + @@ -444,7 +447,7 @@ var EscapedTitle: string; begin if not FServer.Active then Exit; - FBridge.RestoreFromTray; + RestoreWindowFromTray; EscapedTitle := StringReplace(AWindowTitle, '\', '\\', [rfReplaceAll]); EscapedTitle := StringReplace(EscapedTitle, '"', '\"', [rfReplaceAll]); WebBrowser.ExecuteJavaScript( @@ -1027,7 +1030,7 @@ begin // restores it later via ForceForegroundWindow. else if ACmd = 'app/focus' then begin - FBridge.RestoreFromTray; + RestoreWindowFromTray; LogLine('App brought to front (autofill picker)'); end @@ -1519,7 +1522,7 @@ end; procedure TMainForm.BridgeTrayRestore; begin - FBridge.RestoreFromTray; + RestoreWindowFromTray; // Notify the JS layer: the UI may want to reset the auto-lock timer, // refresh state, or show a "welcome back" toast. WebBrowser.ExecuteJavaScript( @@ -1545,7 +1548,7 @@ begin // Restore the form first so the tray icon goes away and FormDestroy // executes from a normal (non-hidden) state. RestoreFromTray also // deletes the tray icon. - FBridge.RestoreFromTray; + RestoreWindowFromTray; Application.Terminate; end; @@ -1572,6 +1575,18 @@ begin else if AEvent = EVENT_SYSTEM_MINIMIZEEND then MainForm.WinStateMinimizeEnd; end; +// Single entry point for every tray restore. ExecuteAutofill really minimises +// the window (SW_MINIMIZE) before typing, which raises the guard; if the window +// is then HIDDEN to the tray instead of being un-minimised, MINIMIZEEND may +// never arrive and the guard would stay up forever, silently freezing the +// tracked window state. RestoreFromTray replays its own saved placement, so +// there is nothing left for the guard to protect by then. +procedure TMainForm.RestoreWindowFromTray; +begin + FIgnoreResizes := False; + FBridge.RestoreFromTray; +end; + // The window is going down: from here until the restore settles, every resize // FMX fires is part of that transition, never a user gesture. procedure TMainForm.WinStateMinimizeStart;