import { app, BrowserWindow } from 'electron' import { join } from 'path' import { createWindow, setupSingleInstanceLock, getFilePathFromArgs } from './window-manager' import { FileWatcher, SidebarWatcher } from './file-watcher' import { registerIpcHandlers } from './ipc-handlers' import { readFileContent } from './file-system' let mainWindow: BrowserWindow | null = null const state = { activeFilePath: null as string | null, pendingFilePath: null as string | null, isClosing: false, closeTimeout: null as NodeJS.Timeout | null } const fileWatcher = new FileWatcher(() => mainWindow) const sidebarWatcher = new SidebarWatcher(() => mainWindow) function openFileInTab(filePath: string): void { if (!mainWindow || mainWindow.isDestroyed()) return readFileContent(filePath).then(result => { if (result.success && mainWindow && !mainWindow.isDestroyed()) { state.activeFilePath = filePath fileWatcher.start(filePath) mainWindow.setTitle(`MarkLite - ${filePath.split(/[/\\]/).pop()}`) mainWindow.webContents.send('file:openInTab', { filePath, content: result.content }) } }).catch((err) => { console.error('openFileInTab failed:', err) }) } const lockOk = setupSingleInstanceLock((filePath) => { if (mainWindow && !mainWindow.isDestroyed()) { if (mainWindow.isMinimized()) mainWindow.restore() mainWindow.focus() if (filePath) openFileInTab(filePath) } }) if (!lockOk) { app.quit() } else { function setupCloseHandler(): void { if (!mainWindow) return mainWindow.on('close', (e) => { if (state.isClosing) return state.isClosing = true e.preventDefault() try { if (mainWindow && !mainWindow.webContents.isDestroyed()) { mainWindow.webContents.send('window:confirmClose') } else { mainWindow?.removeAllListeners('close') mainWindow?.close() return } } catch { mainWindow?.removeAllListeners('close') mainWindow?.close() return } state.closeTimeout = setTimeout(() => { state.closeTimeout = null if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.removeAllListeners('close') mainWindow.close() } }, 5000) }) } // C-05: 窗口重建时重置状态 function initWindow(): void { state.isClosing = false if (state.closeTimeout) { clearTimeout(state.closeTimeout) state.closeTimeout = null } mainWindow = createWindow() if (process.env.ELECTRON_RENDERER_URL) { mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL) } else { mainWindow.loadFile(join(__dirname, '../renderer/index.html')) } mainWindow.webContents.on('did-finish-load', () => { if (state.pendingFilePath) { openFileInTab(state.pendingFilePath) state.pendingFilePath = null } }) setupCloseHandler() mainWindow.on('closed', () => { fileWatcher.stop() sidebarWatcher.stop() mainWindow = null }) } app.whenReady().then(() => { app.on('open-file', (event, filePath) => { event.preventDefault() if (mainWindow && !mainWindow.isDestroyed() && mainWindow.webContents.isLoading()) { state.pendingFilePath = filePath } else if (mainWindow && !mainWindow.isDestroyed()) { openFileInTab(filePath) } else { state.pendingFilePath = filePath } }) // C-03: IPC 处理器只注册一次 registerIpcHandlers(() => mainWindow, fileWatcher, sidebarWatcher, state) initWindow() const cmdFile = getFilePathFromArgs(process.argv) if (cmdFile) { state.pendingFilePath = cmdFile } }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit() }) // C-03: activate 只重建窗口,不重复注册 IPC app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { initWindow() } }) }