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 <[email protected]> * 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 <[email protected]> --------- Co-authored-by: Jirka <[email protected]> Co-authored-by: Claude Opus 4.5 <[email protected]>
This commit is contained in:
3 files changed
+51
-6
No files matched your search
@@ -25,7 +25,7 @@ export async function isProcessRunning(): Promise<boolean> {
|
|||||||
command = `${cmd} /FI "IMAGENAME eq Antigravity.exe" /NH`;
|
command = `${cmd} /FI "IMAGENAME eq Antigravity.exe" /NH`;
|
||||||
} else {
|
} else {
|
||||||
// macOS and Linux (native)
|
// macOS and Linux (native)
|
||||||
command = 'pgrep -x Antigravity';
|
command = 'pgrep -xi Antigravity';
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Checking process with command: ${command}`);
|
logger.debug(`Checking process with command: ${command}`);
|
||||||
@@ -189,18 +189,22 @@ export async function closeAntigravity(): Promise<void> {
|
|||||||
if (p.pid === currentPid) {
|
if (p.pid === currentPid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Exclude this electron app (if named Antigravity Manager)
|
// Exclude this electron app (if named Antigravity Manager or antigravity-manager)
|
||||||
if (p.cmd.includes('Antigravity Manager')) {
|
if (p.cmd.includes('Antigravity Manager') || p.cmd.includes('antigravity-manager')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Match Antigravity
|
// Match Antigravity (but not manager)
|
||||||
if (platform === 'win32') {
|
if (platform === 'win32') {
|
||||||
return (
|
return (
|
||||||
p.cmd.includes('Antigravity.exe') ||
|
p.cmd.includes('Antigravity.exe') ||
|
||||||
(p.cmd.includes('antigravity') && !p.cmd.includes('manager'))
|
(p.cmd.includes('antigravity') && !p.cmd.includes('manager'))
|
||||||
);
|
);
|
||||||
} else {
|
} 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')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -38,12 +38,31 @@ function getQuotaText(account: CloudAccount | null, texts: any): string[] {
|
|||||||
|
|
||||||
export function initTray(mainWindow: BrowserWindow) {
|
export function initTray(mainWindow: BrowserWindow) {
|
||||||
globalMainWindow = mainWindow;
|
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 inDevelopment = process.env.NODE_ENV === 'development';
|
||||||
const iconPath = inDevelopment
|
const iconPath = inDevelopment
|
||||||
? path.join(process.cwd(), 'src/assets/tray.png')
|
? path.join(process.cwd(), 'src/assets/tray.png')
|
||||||
: path.join(process.resourcesPath, 'assets/tray.png');
|
: path.join(process.resourcesPath, 'assets/tray.png');
|
||||||
|
|
||||||
const icon = nativeImage.createFromPath(iconPath);
|
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 = new Tray(icon);
|
||||||
tray.setToolTip('Antigravity Manager');
|
tray.setToolTip('Antigravity Manager');
|
||||||
|
|
||||||
@@ -158,3 +177,15 @@ export function updateTrayMenu(account: CloudAccount | null, language?: string)
|
|||||||
export function setTrayLanguage(lang: string) {
|
export function setTrayLanguage(lang: string) {
|
||||||
updateTrayMenu(lastAccount, lang);
|
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-1
@@ -14,7 +14,7 @@ import { CloudMonitorService } from './services/CloudMonitorService';
|
|||||||
// Static Imports to fix Bundle Resolution Errors
|
// Static Imports to fix Bundle Resolution Errors
|
||||||
import { AuthServer } from './ipc/cloud/authServer';
|
import { AuthServer } from './ipc/cloud/authServer';
|
||||||
import { bootstrapNestServer, stopNestServer } from './server/main';
|
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 { rpcHandler } from './ipc/handler';
|
||||||
import { ConfigManager } from './ipc/config/manager';
|
import { ConfigManager } from './ipc/config/manager';
|
||||||
|
|
||||||
@@ -149,8 +149,18 @@ app.on('child-process-gone', (event, details) => {
|
|||||||
logger.error('Child process gone:', 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) => {
|
app.on('will-quit', (event) => {
|
||||||
logger.info('App will quit event triggered');
|
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) => {
|
app.on('quit', (event, exitCode) => {
|
||||||
|
|||||||
Reference in new issue
Block a user