feat: tray quick-search + privacy hardening + race fixes
Quick search from tray - New "Quick search…" entry in the tray context menu (between Open and Lock vault). - Compact modal with live-filtered top-8 entries, arrow keys / Enter to copy the password (Shift+Enter copies the username instead), Esc to dismiss. Each row shows the favicon when cached. - Locked vault → focus the master password input instead of opening the modal (same pattern as the locked-autofill-hotkey path). - Window-state restore: Delphi remembers whether the window was hidden before the menu was opened and tells JS via the Bridge.openQuickSearch(wasHidden) arg. After the copy (or cancel) we hide back to the tray so the previously-foreground app comes back and Ctrl+V drops the password in. Tray notifications toggle - New Settings → Security "Show tray notifications" toggle. Gates Shell_NotifyIcon NIF_INFO balloons (currently only the "still running in the tray" first-time popup). Default ON, synced via settings_json so it follows the user across devices. - PM.Bridge.ShowNotifications exposed as a public property; JS pushes the value on every settings sync. Privacy: WebView2 phone-home killed - WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS set in the unit initialization section (before the TMS WebBrowser instantiates its CoreWebView2Environment). Disables: background networking, sync, component updates, breakpad/crashpad, domain reliability, client-side phishing detection, experiments, UMA upload, MediaRouter, OptimizationHints, SafeBrowsing enhanced, autofill server, privacy sandbox APIs. Verified via Resource Monitor: only 127.0.0.1 connections remain (plus DDG when favicons are on). Fixes - Blank-window-on-launch race: the 1.5 s navigation timer assumes WebView2 finishes init in time, but on slow machines Edge Chromium needs 2-3 s and the Navigate() call is silently dropped. WebBrowserInitialized now also navigates if a URL is still pending — first to run wins. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,10 @@ type
|
||||
FPowerNotify: THandle; // registration handle from PowerRegisterSuspendResumeNotification
|
||||
FSecureClipboard: TSecureClipboard;
|
||||
FBalloonShown: Boolean;
|
||||
// User setting: gates Shell_NotifyIcon NIF_INFO balloons (currently
|
||||
// only the "running in the tray" first-time popup, future tray
|
||||
// notifications would honour the same flag).
|
||||
FShowNotifications: Boolean;
|
||||
// Window placement captured at MinimizeToTray time. Replayed on
|
||||
// RestoreFromTray so the window comes back in the same state
|
||||
// (maximised / normal + position + size) as before hiding.
|
||||
@@ -91,6 +95,7 @@ type
|
||||
FOnTrayRestore: TProc;
|
||||
FOnLockRequest: TProc;
|
||||
FOnQuit: TProc;
|
||||
FOnQuickSearchRequest: TProc;
|
||||
// Autofill: global hotkeys → inject credentials into browser. Combos
|
||||
// are user-configurable from Settings; defaults are Ctrl+Shift+L /
|
||||
// Ctrl+Shift+P. We track which IDs are actually live so unregister
|
||||
@@ -157,6 +162,16 @@ type
|
||||
// bridge does not call it itself, so the host stays in control of
|
||||
// shutdown order (server stop, save state, etc.).
|
||||
property OnQuit: TProc read FOnQuit write FOnQuit;
|
||||
// Fired when the user picks "Quick search…" from the tray menu.
|
||||
// Handler typically restores the window and pops a JS-side modal
|
||||
// (Bridge.openQuickSearch) so the user can type to find an entry
|
||||
// and copy its password without restoring the whole vault UI.
|
||||
property OnQuickSearchRequest: TProc
|
||||
read FOnQuickSearchRequest write FOnQuickSearchRequest;
|
||||
// True (default) = show tray balloon notifications. Set False to keep
|
||||
// the tray icon mute. Configured from the JS settings panel.
|
||||
property ShowNotifications: Boolean
|
||||
read FShowNotifications write FShowNotifications;
|
||||
// Fired on main thread when the autofill hotkey fires.
|
||||
// Args: (ATargetHWND, AWindowTitle). Handler calls ExecuteJavaScript
|
||||
// to let JS match the title against vault entries.
|
||||
@@ -374,6 +389,7 @@ begin
|
||||
FSecureClipboard := TSecureClipboard.Create;
|
||||
FTrayAdded := False;
|
||||
FBalloonShown := False;
|
||||
FShowNotifications := True; // default on; JS pushes user pref on load
|
||||
|
||||
// Dedicated message-only window for tray + WTS notifications.
|
||||
FMsgWindow := AllocateHWnd(MsgWindowHandler);
|
||||
@@ -538,8 +554,9 @@ begin
|
||||
ShowWindow(LAppHwnd, SW_HIDE);
|
||||
|
||||
// 3. First-time only: pop a balloon notification so the user knows the
|
||||
// app is still running in the tray (and didn't crash).
|
||||
if not FBalloonShown then
|
||||
// app is still running in the tray (and didn't crash). Skipped when
|
||||
// the user opted out via Settings.
|
||||
if (not FBalloonShown) and FShowNotifications then
|
||||
begin
|
||||
ShowFirstTimeBalloon;
|
||||
FBalloonShown := True;
|
||||
@@ -612,9 +629,10 @@ end;
|
||||
|
||||
procedure TPMBridge.ShowTrayMenu;
|
||||
const
|
||||
ID_OPEN = 1;
|
||||
ID_LOCK = 2;
|
||||
ID_QUIT = 3;
|
||||
ID_OPEN = 1;
|
||||
ID_LOCK = 2;
|
||||
ID_QUIT = 3;
|
||||
ID_QUICKSEARCH = 4;
|
||||
var
|
||||
LMenu: HMENU;
|
||||
LPt: TPoint;
|
||||
@@ -624,6 +642,7 @@ begin
|
||||
if LMenu = 0 then Exit;
|
||||
try
|
||||
AppendMenu(LMenu, MF_STRING, ID_OPEN, 'Open');
|
||||
AppendMenu(LMenu, MF_STRING, ID_QUICKSEARCH, 'Quick search…');
|
||||
AppendMenu(LMenu, MF_STRING, ID_LOCK, 'Lock vault');
|
||||
AppendMenu(LMenu, MF_SEPARATOR, 0, nil);
|
||||
AppendMenu(LMenu, MF_STRING, ID_QUIT, 'Quit');
|
||||
@@ -642,9 +661,10 @@ begin
|
||||
PostMessage(FMsgWindow, WM_NULL, 0, 0);
|
||||
|
||||
case LCmd of
|
||||
ID_OPEN: if Assigned(FOnTrayRestore) then FOnTrayRestore();
|
||||
ID_LOCK: if Assigned(FOnLockRequest) then FOnLockRequest();
|
||||
ID_QUIT: if Assigned(FOnQuit) then FOnQuit();
|
||||
ID_OPEN: if Assigned(FOnTrayRestore) then FOnTrayRestore();
|
||||
ID_QUICKSEARCH: if Assigned(FOnQuickSearchRequest) then FOnQuickSearchRequest();
|
||||
ID_LOCK: if Assigned(FOnLockRequest) then FOnLockRequest();
|
||||
ID_QUIT: if Assigned(FOnQuit) then FOnQuit();
|
||||
end;
|
||||
finally
|
||||
DestroyMenu(LMenu);
|
||||
|
||||
Reference in New Issue
Block a user