67 lines
2.2 KiB
TypeScript
67 lines
2.2 KiB
TypeScript
/**
|
||
* 系统托盘:应用常驻入口
|
||
* Windows:关闭窗口后靠托盘活着,单击托盘还原窗口
|
||
* mac:托盘(菜单栏图标)仅提供快捷菜单,窗口恢复主要靠 Dock 的 activate 事件
|
||
*/
|
||
import { app, Menu, nativeImage, Tray } from 'electron';
|
||
|
||
import { PRODUCT_NAME } from './config';
|
||
import { appState } from './state';
|
||
import { checkUpdateManually } from './updater';
|
||
import { getAutoLaunchEnabled, getResourcePath, setAutoLaunchEnabled } from './utils';
|
||
import { showMainWindow } from './window';
|
||
|
||
/** 托盘单例(必须持有引用,否则会被 GC 导致图标消失) */
|
||
let tray: null | Tray = null;
|
||
|
||
/**
|
||
* 创建托盘图标与菜单
|
||
* 托盘直接用品牌应用图标缩小(resources/icon.png,年糕猫+奶酪)
|
||
*/
|
||
export function createTray(): Tray {
|
||
// TODO(待确认):mac 后续可换 Template 单色托盘图(setTemplateImage 随菜单栏深浅色自动反色)
|
||
const icon = nativeImage
|
||
.createFromPath(getResourcePath('icon.png'))
|
||
.resize({ height: 16, width: 16 });
|
||
tray = new Tray(icon);
|
||
tray.setToolTip(PRODUCT_NAME);
|
||
refreshTrayMenu();
|
||
// Windows 惯例:单击托盘直接还原主窗口;mac 惯例是单击弹菜单,不抢行为
|
||
if (process.platform !== 'darwin') {
|
||
tray.on('click', () => showMainWindow());
|
||
}
|
||
return tray;
|
||
}
|
||
|
||
/**
|
||
* 重建托盘右键菜单
|
||
* 单独导出是因为「开机自启」勾选状态可能被渲染层(desktopAPI.setAutoLaunch)改掉,
|
||
* 改完需要同步刷新菜单勾选态
|
||
*/
|
||
export function refreshTrayMenu(): void {
|
||
if (!tray) return;
|
||
const menu = Menu.buildFromTemplate([
|
||
{ click: () => showMainWindow(), label: '显示主窗口' },
|
||
{ type: 'separator' },
|
||
{
|
||
checked: getAutoLaunchEnabled(),
|
||
click: (item) => {
|
||
setAutoLaunchEnabled(item.checked);
|
||
},
|
||
label: '开机自启',
|
||
type: 'checkbox',
|
||
},
|
||
{ click: () => checkUpdateManually(), label: '检查更新' },
|
||
{ type: 'separator' },
|
||
{
|
||
click: () => {
|
||
// 标记真正退出,绕过窗口 close 事件里的「隐藏到托盘」拦截
|
||
appState.quitting = true;
|
||
app.quit();
|
||
},
|
||
label: '退出',
|
||
},
|
||
]);
|
||
tray.setContextMenu(menu);
|
||
}
|