2026-06-28 03:37:07 +08:00
|
|
|
import electron from 'electron';
|
|
|
|
|
import path from 'path';
|
|
|
|
|
|
2026-07-11 23:33:44 +08:00
|
|
|
const { ipcMain, dialog, shell } = electron;
|
2026-06-28 03:37:07 +08:00
|
|
|
|
|
|
|
|
const isDev = !electron.app.isPackaged;
|
|
|
|
|
|
|
|
|
|
interface WinRef {
|
|
|
|
|
mainWindow: electron.BrowserWindow | null;
|
|
|
|
|
splashWindow: electron.BrowserWindow | null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-11 23:33:44 +08:00
|
|
|
const MIME_MAP: Record<string, string> = {
|
|
|
|
|
png: 'image/png',
|
|
|
|
|
jpg: 'image/jpeg',
|
|
|
|
|
jpeg: 'image/jpeg',
|
|
|
|
|
webp: 'image/webp',
|
|
|
|
|
gif: 'image/gif',
|
|
|
|
|
bmp: 'image/bmp',
|
|
|
|
|
svg: 'image/svg+xml',
|
|
|
|
|
};
|
|
|
|
|
|
2026-06-28 03:37:07 +08:00
|
|
|
function createSplashWindow(): electron.BrowserWindow {
|
|
|
|
|
const splash = new electron.BrowserWindow({
|
|
|
|
|
width: 480,
|
|
|
|
|
height: 320,
|
|
|
|
|
transparent: true,
|
|
|
|
|
frame: false,
|
|
|
|
|
resizable: false,
|
|
|
|
|
skipTaskbar: true,
|
|
|
|
|
alwaysOnTop: true,
|
|
|
|
|
webPreferences: {
|
|
|
|
|
nodeIntegration: false,
|
|
|
|
|
contextIsolation: true,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (isDev) {
|
|
|
|
|
splash.loadURL('http://localhost:1420/splash.html');
|
|
|
|
|
} else {
|
|
|
|
|
splash.loadFile(path.join(__dirname, '../dist/splash.html'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return splash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function registerWindowHandlers(win: WinRef) {
|
|
|
|
|
ipcMain.handle('window:minimize', () => {
|
|
|
|
|
win.mainWindow?.minimize();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('window:maximize', () => {
|
|
|
|
|
if (win.mainWindow?.isMaximized()) {
|
|
|
|
|
win.mainWindow.unmaximize();
|
|
|
|
|
} else {
|
|
|
|
|
win.mainWindow?.maximize();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('window:close', () => {
|
|
|
|
|
win.mainWindow?.close();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('window:isMaximized', () => {
|
|
|
|
|
return win.mainWindow?.isMaximized() ?? false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('window:getTheme', () => {
|
|
|
|
|
return (win.mainWindow as any)?.themeSource ?? null;
|
|
|
|
|
});
|
|
|
|
|
|
2026-08-31 02:20:25 +08:00
|
|
|
// 打开浏览器调试工具(DevTools,开发者工具测试用)
|
|
|
|
|
ipcMain.handle('window:openDevTools', () => {
|
|
|
|
|
win.mainWindow?.webContents.openDevTools({ mode: 'detach' });
|
|
|
|
|
return { success: true };
|
|
|
|
|
});
|
|
|
|
|
|
2026-06-28 03:37:07 +08:00
|
|
|
// Splash window management
|
|
|
|
|
ipcMain.handle('window:openSplash', () => {
|
|
|
|
|
if (win.splashWindow && !win.splashWindow.isDestroyed()) {
|
|
|
|
|
win.splashWindow.focus();
|
|
|
|
|
return { success: true };
|
|
|
|
|
}
|
|
|
|
|
win.splashWindow = createSplashWindow();
|
|
|
|
|
return { success: true };
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('window:closeSplash', () => {
|
|
|
|
|
if (win.splashWindow && !win.splashWindow.isDestroyed()) {
|
|
|
|
|
win.splashWindow.close();
|
|
|
|
|
win.splashWindow = null;
|
|
|
|
|
}
|
|
|
|
|
return { success: true };
|
|
|
|
|
});
|
|
|
|
|
|
2026-07-11 23:33:44 +08:00
|
|
|
// File dialog — returns source path and extension for preload to handle
|
2026-06-28 03:37:07 +08:00
|
|
|
ipcMain.handle('dialog:openFile', async (_event, payload: {
|
|
|
|
|
filters?: { name: string; extensions: string[] }[];
|
|
|
|
|
}) => {
|
|
|
|
|
const result = await dialog.showOpenDialog(win.mainWindow!, {
|
|
|
|
|
properties: ['openFile'],
|
|
|
|
|
filters: payload.filters,
|
|
|
|
|
});
|
|
|
|
|
if (result.canceled || result.filePaths.length === 0) return null;
|
2026-07-11 23:33:44 +08:00
|
|
|
const srcPath = result.filePaths[0];
|
|
|
|
|
const ext = path.extname(srcPath).toLowerCase() || '.png';
|
|
|
|
|
return { srcPath, ext };
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Open external URL in system browser
|
|
|
|
|
ipcMain.handle('shell:openExternal', async (_event, url: string) => {
|
|
|
|
|
await shell.openExternal(url);
|
2026-06-28 03:37:07 +08:00
|
|
|
});
|
2026-08-04 01:28:16 +08:00
|
|
|
|
|
|
|
|
// Folder dialog — select a directory
|
|
|
|
|
ipcMain.handle('dialog:openFolder', async () => {
|
|
|
|
|
const result = await dialog.showOpenDialog(win.mainWindow!, {
|
|
|
|
|
properties: ['openDirectory'],
|
|
|
|
|
});
|
|
|
|
|
if (result.canceled || result.filePaths.length === 0) return null;
|
|
|
|
|
return { folderPath: result.filePaths[0] };
|
|
|
|
|
});
|
2026-06-28 03:37:07 +08:00
|
|
|
}
|