// SPDX-License-Identifier: AGPL-3.0-or-later import fs from 'node:fs'; import path from 'node:path'; import type {BrowserWindow, NativeImage} from 'electron'; import {nativeImage} from 'electron'; const badgeIcons: Array = []; let hasInit = false; let lastIndex: number | null = null; let lastCount: number | null = null; function isSupported(): boolean { return process.platform === 'win32'; } function ensureInitialized(): void { if (hasInit || !isSupported()) { return; } hasInit = true; const badgeDir = path.join(process.resourcesPath, 'badges'); for (let i = 1; i <= 11; i++) { const iconPath = path.join(badgeDir, `badge-${i}.ico`); if (!fs.existsSync(iconPath)) { badgeIcons.push(null); continue; } const icon = nativeImage.createFromPath(iconPath); badgeIcons.push(icon.isEmpty() ? null : icon); } } function getOverlayIconData(count: number): { index: number | null; description: string; } { if (count === -1) { return { index: 10, description: 'Unread messages', }; } if (count === 0) { return { index: null, description: 'No Notifications', }; } const index = Math.max(1, Math.min(count, 10)) - 1; return { index, description: `${index} notifications`, }; } function applyOverlay(win: BrowserWindow | null, count: number, force: boolean): void { if (!isSupported()) { return; } if (!win || win.isDestroyed()) { return; } const {index, description} = getOverlayIconData(count); if (force || lastIndex !== index) { if (index == null) { win.setOverlayIcon(null, description); } else { const icon = badgeIcons[index]; win.setOverlayIcon(icon ?? null, description); } lastIndex = index; } lastCount = count; } export function setWindowsBadgeOverlay(win: BrowserWindow | null, count: number): void { if (!isSupported()) { return; } ensureInitialized(); applyOverlay(win, count, false); } export function refreshWindowsBadgeOverlay(win: BrowserWindow | null): void { if (!isSupported() || lastCount == null) { return; } ensureInitialized(); applyOverlay(win, lastCount, true); }