fix(desktop): tray badge — IPC handler died when icon.ico missing from packaged resources
This commit is contained in:
@@ -30,6 +30,17 @@ function resolveIconPathDev(): string {
|
|||||||
return path.join(app.getAppPath(), 'resources', 'icon.ico');
|
return path.join(app.getAppPath(), 'resources', 'icon.ico');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 16×16 grey square — last-ditch fallback when neither the packaged
|
||||||
|
// nor dev icon file resolves. Tray constructor on Windows throws when
|
||||||
|
// handed an empty NativeImage, which would tear down the whole
|
||||||
|
// registrar before `ipcMain.handle(TRAY_UNREAD)` runs — leaving the
|
||||||
|
// taskbar overlay badge wired but the renderer's invoke rejecting
|
||||||
|
// with "No handler registered". A non-empty placeholder keeps the
|
||||||
|
// constructor happy so the IPC handler always gets registered.
|
||||||
|
const FALLBACK_TRAY_PNG_BASE64 =
|
||||||
|
'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAH0lEQVR42mNk' +
|
||||||
|
'YGD4z0ABYBxVOKpwVOGowlGFwwoBAEnYAR9XlIldAAAAAElFTkSuQmCC';
|
||||||
|
|
||||||
function loadTrayIcon(): NativeImage {
|
function loadTrayIcon(): NativeImage {
|
||||||
for (const p of [resolveIconPath(), resolveIconPathDev()]) {
|
for (const p of [resolveIconPath(), resolveIconPathDev()]) {
|
||||||
try {
|
try {
|
||||||
@@ -39,7 +50,7 @@ function loadTrayIcon(): NativeImage {
|
|||||||
/* try next */
|
/* try next */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nativeImage.createEmpty();
|
return nativeImage.createFromBuffer(Buffer.from(FALLBACK_TRAY_PNG_BASE64, 'base64'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildOverlay(): NativeImage {
|
function buildOverlay(): NativeImage {
|
||||||
@@ -53,8 +64,16 @@ function buildOverlay(): NativeImage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function register(mainWindow: BrowserWindow): void {
|
export function register(mainWindow: BrowserWindow): void {
|
||||||
|
// Tray icon is best-effort: if neither the packaged resource nor the
|
||||||
|
// dev path resolves (e.g. icon.ico isn't shipped under resourcesPath
|
||||||
|
// in packaged builds — only the app icon goes into the .exe metadata),
|
||||||
|
// we still want the taskbar overlay badge to work. setOverlayIcon is
|
||||||
|
// a BrowserWindow method, so it functions even when the systray icon
|
||||||
|
// creation fails.
|
||||||
|
try {
|
||||||
const icon = loadTrayIcon();
|
const icon = loadTrayIcon();
|
||||||
trayRef = new Tray(icon.isEmpty() ? nativeImage.createEmpty() : icon);
|
if (!icon.isEmpty()) {
|
||||||
|
trayRef = new Tray(icon);
|
||||||
trayRef.setToolTip('Netralax');
|
trayRef.setToolTip('Netralax');
|
||||||
|
|
||||||
const menu = Menu.buildFromTemplate([
|
const menu = Menu.buildFromTemplate([
|
||||||
@@ -82,6 +101,12 @@ export function register(mainWindow: BrowserWindow): void {
|
|||||||
if (mainWindow.isVisible()) mainWindow.focus();
|
if (mainWindow.isVisible()) mainWindow.focus();
|
||||||
else mainWindow.show();
|
else mainWindow.show();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
} catch (err: unknown) {
|
||||||
|
// Swallow: the overlay badge below is the user-visible bit. A missing
|
||||||
|
// systray icon is cosmetic and shouldn't take the unread handler with it.
|
||||||
|
console.warn('[tray] systray init failed, overlay badge still active', err);
|
||||||
|
}
|
||||||
|
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
CHANNELS.TRAY_UNREAD,
|
CHANNELS.TRAY_UNREAD,
|
||||||
|
|||||||
Reference in New Issue
Block a user