fix(desktop): tray left-click always shows + focuses, never hides

The previous toggle behavior hid the main window when it was already
visible, surprising users who expected the menu bar icon to bring the
app forward. Hiding belongs to the closeToTray pref (PR2); the tray
icon itself should be unambiguously a "bring window to front" affordance.

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
Lambda
2026-05-20 10:59:21 +08:00
parent 417f55029a
commit 2457519b1f
2 changed files with 30 additions and 12 deletions

View File

@@ -252,6 +252,32 @@ describe("setupTray", () => {
}
});
it("tray click on darwin always shows + focuses a visible window, never hides it", () => {
const orig = Object.getOwnPropertyDescriptor(process, "platform");
Object.defineProperty(process, "platform", { value: "darwin" });
try {
const showOrCreateWindow = vi.fn();
const visibleWindow = {
isDestroyed: () => false,
isVisible: () => true,
isMinimized: () => false,
hide: vi.fn(),
show: vi.fn(),
focus: vi.fn(),
restore: vi.fn(),
} as unknown as Electron.BrowserWindow;
setupTray({ getWindow: () => visibleWindow, showOrCreateWindow });
const click = h.trayInstances[0]!.clickListeners[0]!;
click();
click();
click();
expect(showOrCreateWindow).toHaveBeenCalledTimes(3);
expect(visibleWindow.hide).not.toHaveBeenCalled();
} finally {
if (orig) Object.defineProperty(process, "platform", orig);
}
});
it("replays current status on subscribe and renders an initial menu", () => {
h.lastEmit.value = { state: "running", pid: 99, agents: ["a"] };
setupTray({ getWindow: () => null, showOrCreateWindow: vi.fn() });

View File

@@ -154,20 +154,12 @@ export function setupTray(opts: TrayOptions): void {
// Left-click handler is a macOS/Windows nice-to-have only. Linux's
// AppIndicator surface doesn't fire `click`, so all actions must remain
// reachable via the context menu — which they are (see buildMenuTemplate).
// Click always shows + focuses the main window; hiding is reserved for
// the closeToTray pref (PR2). showOrCreateWindow restores from minimized,
// shows if hidden, and focuses an already-visible window.
if (process.platform !== "linux") {
tray.on("click", () => {
const win = opts.getWindow();
// The window may have been closed (mainWindow === null after the
// owner's `closed` handler) or destroyed; in either case recreate.
if (!win || win.isDestroyed()) {
opts.showOrCreateWindow();
return;
}
if (win.isVisible() && !win.isMinimized()) {
win.hide();
} else {
opts.showOrCreateWindow();
}
opts.showOrCreateWindow();
});
}