From c43507c71611d5508354824a82b4278a84df9609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20T=C5=AFma?= <35496927+Olbrasoft@users.noreply.github.com> Date: Mon, 19 Jan 2026 09:11:48 +0100 Subject: [PATCH] Fix: Linux tray quit and zombie icons (#24) * Fix: Linux tray quit and zombie icons (#23) - Add before-quit handler to set isQuitting flag - Change pgrep -x to pgrep -xi for case-insensitive matching on Linux - Add antigravity-manager to self-kill exclusion filter - Destroy existing tray before creating new one in initTray() - Destroy tray in will-quit handler - Export destroyTray function for cleanup Fixes #23 Co-Authored-By: Claude Opus 4.5 * Fix: Address code review feedback - Add icon validation before creating tray (isEmpty check) - Add try/catch around tray.destroy() calls for error handling - Add try/catch around destroyTray() in will-quit handler - Add explicit !manager check in Linux process filter for defensive coding Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Jirka Co-authored-by: Claude Opus 4.5 --- src/ipc/process/handler.ts | 14 +++++++++----- src/ipc/tray/handler.ts | 31 +++++++++++++++++++++++++++++++ src/main.ts | 12 +++++++++++- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/ipc/process/handler.ts b/src/ipc/process/handler.ts index 62befad..7697c0b 100644 --- a/src/ipc/process/handler.ts +++ b/src/ipc/process/handler.ts @@ -25,7 +25,7 @@ export async function isProcessRunning(): Promise { command = `${cmd} /FI "IMAGENAME eq Antigravity.exe" /NH`; } else { // macOS and Linux (native) - command = 'pgrep -x Antigravity'; + command = 'pgrep -xi Antigravity'; } logger.debug(`Checking process with command: ${command}`); @@ -189,18 +189,22 @@ export async function closeAntigravity(): Promise { if (p.pid === currentPid) { return false; } - // Exclude this electron app (if named Antigravity Manager) - if (p.cmd.includes('Antigravity Manager')) { + // Exclude this electron app (if named Antigravity Manager or antigravity-manager) + if (p.cmd.includes('Antigravity Manager') || p.cmd.includes('antigravity-manager')) { return false; } - // Match Antigravity + // Match Antigravity (but not manager) if (platform === 'win32') { return ( p.cmd.includes('Antigravity.exe') || (p.cmd.includes('antigravity') && !p.cmd.includes('manager')) ); } else { - return p.cmd.includes('Antigravity') || p.cmd.includes('antigravity'); + // Explicit !manager check for Linux/macOS to be defensive + return ( + (p.cmd.includes('Antigravity') || p.cmd.includes('antigravity')) && + !p.cmd.includes('manager') + ); } }); diff --git a/src/ipc/tray/handler.ts b/src/ipc/tray/handler.ts index 4ad8b22..b282108 100644 --- a/src/ipc/tray/handler.ts +++ b/src/ipc/tray/handler.ts @@ -38,12 +38,31 @@ function getQuotaText(account: CloudAccount | null, texts: any): string[] { export function initTray(mainWindow: BrowserWindow) { globalMainWindow = mainWindow; + + // PATCH 3: Destroy existing tray before creating new one (prevents zombie tray icons) + if (tray) { + try { + tray.destroy(); + } catch (e) { + logger.error('Failed to destroy existing tray', e); + } + tray = null; + logger.info('Destroyed existing tray before creating new one'); + } + const inDevelopment = process.env.NODE_ENV === 'development'; const iconPath = inDevelopment ? path.join(process.cwd(), 'src/assets/tray.png') : path.join(process.resourcesPath, 'assets/tray.png'); const icon = nativeImage.createFromPath(iconPath); + + // Verify icon is valid before creating tray + if (icon.isEmpty()) { + logger.error(`Tray icon not found or invalid at path: ${iconPath}`); + return; + } + tray = new Tray(icon); tray.setToolTip('Antigravity Manager'); @@ -158,3 +177,15 @@ export function updateTrayMenu(account: CloudAccount | null, language?: string) export function setTrayLanguage(lang: string) { updateTrayMenu(lastAccount, lang); } + +export function destroyTray() { + if (tray) { + try { + tray.destroy(); + } catch (e) { + logger.error('Failed to destroy tray', e); + } + tray = null; + logger.info('Tray destroyed'); + } +} diff --git a/src/main.ts b/src/main.ts index aa448f4..40c4667 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,7 +14,7 @@ import { CloudMonitorService } from './services/CloudMonitorService'; // Static Imports to fix Bundle Resolution Errors import { AuthServer } from './ipc/cloud/authServer'; import { bootstrapNestServer, stopNestServer } from './server/main'; -import { initTray, setTrayLanguage } from './ipc/tray/handler'; +import { initTray, setTrayLanguage, destroyTray } from './ipc/tray/handler'; import { rpcHandler } from './ipc/handler'; import { ConfigManager } from './ipc/config/manager'; @@ -149,8 +149,18 @@ app.on('child-process-gone', (event, details) => { logger.error('Child process gone:', details); }); +app.on('before-quit', () => { + isQuitting = true; + logger.info('App before-quit event triggered - isQuitting set to true'); +}); + app.on('will-quit', (event) => { logger.info('App will quit event triggered'); + try { + destroyTray(); + } catch (err) { + logger.error('Failed to destroy tray during will-quit', err); + } }); app.on('quit', (event, exitCode) => {