完整提交;

This commit is contained in:
yuantao
2025-09-11 18:32:41 +08:00
parent 731f18c57e
commit 8732d67234
6 changed files with 731 additions and 178 deletions

283
main.js
View File

@@ -1,125 +1,296 @@
const { app, BrowserWindow, Tray, Menu, nativeImage, ipcMain } = require('electron');
const path = require('path');
const AutoLaunch = require('auto-launch');
const { app, BrowserWindow, Tray, Menu, nativeImage, ipcMain } = require('electron')
const path = require('path')
const AutoLaunch = require('auto-launch')
const si = require('systeminformation')
// 保持对窗口对象的全局引用如果不这样做窗口将会在JavaScript垃圾回收时自动关闭
let mainWindow;
let tray = null;
let mainWindow
let tray = null
// 创建开机启动管理器
let autoLauncher = new AutoLaunch({
name: 'Motioner',
path: process.execPath,
});
})
// 跟踪开机启动状态
let isAutoLaunchEnabled = false
// 存储GPU监控定时器
let gpuMonitorInterval = null
// 创建窗口的函数
function createWindow() {
// 创建浏览器窗口
mainWindow = new BrowserWindow({
width: 300,
height: 200,
width: 350,
height: 180,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
contextIsolation: false,
},
resizable: false,
// 创建无边框窗口
frame: false,
// 保持窗口始终在最前面
alwaysOnTop: true,
// 窗口透明
transparent: true
});
transparent: false,
backgroundMaterial: 'mica',
// 隐藏任务栏图标
skipTaskbar: true,
// 隐藏窗口切换时的显示
show: false,
// 隐藏窗口标题栏和任务栏显示
titleBarStyle: 'hidden',
// 隐藏窗口在Alt+Tab切换中显示
hiddenInMissionControl: true
})
// 加载应用的index.html
mainWindow.loadFile('index.html');
mainWindow.loadFile('index.html')
// 处理最小化事件
ipcMain.on('window-minimize', () => {
mainWindow.hide();
});
mainWindow.hide()
})
// 处理关闭事件
ipcMain.on('window-close', () => {
app.quit();
});
app.quit()
})
// 处理开机启动设置事件
ipcMain.on('set-auto-launch', (event, enable) => {
if (enable) {
autoLauncher.enable().then(() => {
console.log('开机启动已启用');
}).catch(err => {
console.error('启用开机启动失败:', err);
});
autoLauncher
.enable()
.then(() => {
console.log('开机启动已启用')
isAutoLaunchEnabled = true
// 重新创建托盘菜单以更新状态
createTray()
})
.catch(err => {
console.error('启用开机启动失败:', err)
})
} else {
autoLauncher.disable().then(() => {
console.log('开机启动已禁用');
}).catch(err => {
console.error('禁用开机启动失败:', err);
});
autoLauncher
.disable()
.then(() => {
console.log('开机启动已禁用')
isAutoLaunchEnabled = false
// 重新创建托盘菜单以更新状态
createTray()
})
.catch(err => {
console.error('禁用开机启动失败:', err)
})
}
});
})
// 当窗口关闭时触发
mainWindow.on('closed', function () {
// 取消对窗口对象的引用,通常会存储窗口在数组中,这是删除相应元素的时候
mainWindow = null;
});
mainWindow = null
// 清除GPU监控定时器
if (gpuMonitorInterval) {
clearInterval(gpuMonitorInterval)
gpuMonitorInterval = null
}
})
}
// 保存窗口原始位置和大小
let originalBounds = { width: 350, height: 150 }
// 当Electron完成初始化并准备创建浏览器窗口时调用此方法
app.whenReady().then(() => {
createWindow();
createWindow()
// 创建系统托盘
createTray();
createTray()
// 启动GPU监控
startGpuMonitoring()
// 显示窗口
mainWindow.show()
// 监听窗口失焦事件
mainWindow.on('blur', () => {
// 2秒后缩小窗口
setTimeout(() => {
if (mainWindow && !mainWindow.isDestroyed()) {
// 保存当前窗口位置和大小
const bounds = mainWindow.getBounds()
originalBounds = { ...bounds }
// 缩小窗口到小球大小,以顶部中心点为基准
const newX = Math.round(bounds.x + bounds.width / 2 - 20)
const newY = bounds.y
try {
mainWindow.setBounds({
x: newX,
y: newY,
width: 150,
height: 210,
})
// 移除backgroundMaterial带来的阴影
mainWindow.setBackgroundMaterial('none')
mainWindow.setOpacity(0.3)
} catch (error) {
console.error('设置窗口边界时出错:', error)
}
}
}, 2000)
// 通知渲染进程窗口已失焦
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('window-blurred')
}
})
// 监听窗口聚焦事件
mainWindow.on('focus', () => {
// 恢复窗口到原始大小和位置
if (mainWindow && !mainWindow.isDestroyed()) {
try {
mainWindow.setBounds({
x: originalBounds.x,
y: originalBounds.y,
width: originalBounds.width,
height: originalBounds.height,
})
// 恢复backgroundMaterial带来的阴影
mainWindow.setBackgroundMaterial('mica')
mainWindow.setOpacity(1)
} catch (error) {
console.error('设置窗口边界时出错:', error)
}
}
// 通知渲染进程窗口已聚焦
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('window-focused')
}
})
app.on('activate', function () {
// 在macOS上当单击dock图标并且没有其他窗口打开时通常在应用程序中重新创建一个窗口
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 当所有窗口都关闭时退出应用
app.on('window-all-closed', function () {
// 在macOS上应用程序及其菜单栏通常会保持活动状态直到用户明确退出
if (process.platform !== 'darwin') app.quit();
});
if (process.platform !== 'darwin') app.quit()
})
// 创建系统托盘
function createTray() {
// 创建托盘图标
const iconPath = path.join(__dirname, 'assets/icon.png');
let icon;
const iconPath = path.join(__dirname, 'assets/icon.png')
let icon
try {
icon = nativeImage.createFromPath(iconPath);
icon = nativeImage.createFromPath(iconPath)
} catch (error) {
// 如果找不到图标文件,使用默认图标
icon = nativeImage.createEmpty();
icon = nativeImage.createEmpty()
}
tray = new Tray(icon);
tray = new Tray(icon)
// 创建上下文菜单
const contextMenu = Menu.buildFromTemplate([
{
label: '显示',
click: () => {
mainWindow.show();
}
mainWindow.show()
},
},
{
label: '开机启动',
type: 'checkbox',
checked: isAutoLaunchEnabled,
click: () => {
if (isAutoLaunchEnabled) {
autoLauncher
.disable()
.then(() => {
console.log('开机启动已禁用')
isAutoLaunchEnabled = false
// 重新创建托盘菜单以更新状态
createTray()
})
.catch(err => {
console.error('禁用开机启动失败:', err)
})
} else {
autoLauncher
.enable()
.then(() => {
console.log('开机启动已启用')
isAutoLaunchEnabled = true
// 重新创建托盘菜单以更新状态
createTray()
})
.catch(err => {
console.error('启用开机启动失败:', err)
})
}
},
},
{
label: '退出',
click: () => {
app.quit();
}
}
]);
tray.setContextMenu(contextMenu);
app.quit()
},
},
])
tray.setContextMenu(contextMenu)
// 点击托盘图标显示窗口
tray.on('click', () => {
mainWindow.show();
});
}
mainWindow.show()
})
}
// 启动GPU监控
function startGpuMonitoring() {
// 每秒获取一次GPU信息
gpuMonitorInterval = setInterval(async () => {
try {
// 获取GPU信息
const graphicsData = await si.graphics()
// 过滤掉虚拟GPU设备如OrayIddDriver等
const physicalGpus = graphicsData.controllers.filter(controller => {
// 忽略虚拟GPU和软件渲染器
const isVirtual = controller.model.includes('Oray') || controller.model.includes('Virtual') || controller.model.includes('Software') || controller.vendor.includes('Oray') || (controller.vram === 0 && !controller.memoryTotal)
return !isVirtual
})
// 提取显存信息
const gpuInfo = physicalGpus.map(controller => ({
name: controller.model,
memoryUsed: controller.memoryUsed,
memoryTotal: controller.memoryTotal,
memoryFree: controller.memoryFree,
utilizationGpu: controller.utilizationGpu,
temperature: controller.temperatureGpu,
vram: controller.vram,
}))
// 发送GPU信息到渲染进程
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('gpu-info', gpuInfo)
}
} catch (error) {
console.error('获取GPU信息时出错:', error)
}
}, 1000) // 每秒更新一次
}