From 46b9c22f10058521eef2d61fdac7dfb6379e6cb5 Mon Sep 17 00:00:00 2001 From: Evan Simkowitz Date: Fri, 3 May 2024 13:41:53 -0700 Subject: [PATCH] Remove barriers to supporting multiple windows (#647) --- src/electron/emain.ts | 107 ++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/src/electron/emain.ts b/src/electron/emain.ts index 069a9210a..b5b3cea0a 100644 --- a/src/electron/emain.ts +++ b/src/electron/emain.ts @@ -34,7 +34,9 @@ let wasActive = true; let wasInFg = true; let currentGlobalShortcut: string | null = null; let initialClientData: ClientDataType = null; -let MainWindow: Electron.BrowserWindow | null = null; +let windows: Windows = {}; + +interface Windows extends Record {} checkPromptMigrate(); ensureDir(waveHome); @@ -200,14 +202,15 @@ function readAuthKey(): string { } const reloadAcceleratorKey = unamePlatform == "darwin" ? "Option+R" : "Super+R"; const cmdOrAlt = process.platform === "darwin" ? "Cmd" : "Alt"; + let viewSubMenu: Electron.MenuItemConstructorOptions[] = []; viewSubMenu.push({ role: "reload", accelerator: reloadAcceleratorKey }); viewSubMenu.push({ role: "toggleDevTools" }); if (isDev) { viewSubMenu.push({ label: "Toggle Dev UI", - click: () => { - MainWindow?.webContents.send("toggle-devui"); + click: (_, window) => { + window?.webContents.send("toggle-devui"); }, }); } @@ -215,36 +218,33 @@ viewSubMenu.push({ type: "separator" }); viewSubMenu.push({ label: "Actual Size", accelerator: cmdOrAlt + "+0", - click: () => { - if (MainWindow == null) { - return; - } - MainWindow.webContents.setZoomFactor(1); - MainWindow.webContents.send("zoom-changed"); + click: (_, window) => { + window?.webContents.setZoomFactor(1); + window?.webContents.send("zoom-changed"); }, }); viewSubMenu.push({ label: "Zoom In", accelerator: cmdOrAlt + "+Plus", - click: () => { - if (MainWindow == null) { + click: (_, window) => { + if (window == null) { return; } - const zoomFactor = MainWindow.webContents.getZoomFactor(); - MainWindow.webContents.setZoomFactor(zoomFactor * 1.1); - MainWindow.webContents.send("zoom-changed"); + const zoomFactor = window.webContents.getZoomFactor(); + window.webContents.setZoomFactor(zoomFactor * 1.1); + window.webContents.send("zoom-changed"); }, }); viewSubMenu.push({ label: "Zoom Out", accelerator: cmdOrAlt + "+-", - click: () => { - if (MainWindow == null) { + click: (_, window) => { + if (window == null) { return; } - const zoomFactor = MainWindow.webContents.getZoomFactor(); - MainWindow.webContents.setZoomFactor(zoomFactor / 1.1); - MainWindow.webContents.send("zoom-changed"); + const zoomFactor = window.webContents.getZoomFactor(); + window.webContents.setZoomFactor(zoomFactor / 1.1); + window.webContents.send("zoom-changed"); }, }); viewSubMenu.push({ type: "separator" }); @@ -255,8 +255,8 @@ const menuTemplate: Electron.MenuItemConstructorOptions[] = [ submenu: [ { label: "About Wave Terminal", - click: () => { - MainWindow?.webContents.send("menu-item-about"); + click: (_, window) => { + window?.webContents.send("menu-item-about"); }, }, { type: "separator" }, @@ -325,7 +325,10 @@ function shFrameNavHandler(event: Electron.Event { - MainWindow = null; + delete windows[id]; }); win.webContents.on("zoom-changed", (e) => { win.webContents.send("zoom-changed"); }); + windows[id] = win; + return win; +} + +function createMainWindow(clientData: ClientDataType | null) { + const win = createWindow("main", clientData); win.webContents.setWindowOpenHandler(({ url, frameName }) => { if (url.startsWith("https://docs.waveterm.dev/")) { console.log("openExternal docs", url); @@ -399,8 +408,6 @@ function createMainWindow(clientData: ClientDataType | null): Electron.BrowserWi console.log("window-open denied", url); return { action: "deny" }; }); - - return win; } function mainResizeHandler(_: any, win: Electron.BrowserWindow) { @@ -474,8 +481,9 @@ app.on("window-all-closed", () => { }); electron.ipcMain.on("toggle-developer-tools", (event) => { - if (MainWindow != null) { - MainWindow.webContents.toggleDevTools(); + const window = getWindowForEvent(event); + if (window != null) { + window.webContents.toggleDevTools(); } event.returnValue = true; }); @@ -487,8 +495,8 @@ function convertMenuDefArrToMenu(menuDefArr: ElectronContextMenuItem[]): electro role: menuDef.role as any, label: menuDef.label, type: menuDef.type, - click: () => { - MainWindow?.webContents.send("contextmenu-click", menuDef.id); + click: (_, window) => { + window?.webContents.send("contextmenu-click", menuDef.id); }, }; if (menuDef.submenu != null) { @@ -500,6 +508,11 @@ function convertMenuDefArrToMenu(menuDefArr: ElectronContextMenuItem[]): electro return electron.Menu.buildFromTemplate(menuItems); } +function getWindowForEvent(event: Electron.IpcMainEvent): Electron.BrowserWindow { + const windowId = event.sender.id; + return electron.BrowserWindow.fromId(windowId); +} + electron.ipcMain.on("contextmenu-show", (event, menuDefArr: ElectronContextMenuItem[], { x, y }) => { if (menuDefArr == null || menuDefArr.length == 0) { return; @@ -510,8 +523,9 @@ electron.ipcMain.on("contextmenu-show", (event, menuDefArr: ElectronContextMenuI }); electron.ipcMain.on("hide-window", (event) => { - if (MainWindow != null) { - MainWindow.hide(); + const window = getWindowForEvent(event); + if (window) { + window.hide(); } event.returnValue = true; }); @@ -552,8 +566,9 @@ electron.ipcMain.on("restart-server", (event) => { }); electron.ipcMain.on("reload-window", (event) => { - if (MainWindow != null) { - MainWindow.reload(); + const window = getWindowForEvent(event); + if (window) { + window.reload(); } event.returnValue = true; }); @@ -592,9 +607,9 @@ electron.ipcMain.on("set-nativethemesource", (event, themeSource: "system" | "li }); electron.nativeTheme.on("updated", () => { - if (MainWindow != null) { - MainWindow.webContents.send("nativetheme-updated"); - } + electron.BrowserWindow.getAllWindows().forEach((win) => { + win.webContents.send("nativetheme-updated"); + }); }); function readLastLinesOfFile(filePath: string, lineCount: number) { @@ -658,12 +673,12 @@ async function getClientData(willRetry: boolean, retryNum: number): Promise { console.log("global shortcut triggered, showing window"); - MainWindow?.show(); + windows["main"]?.show(); }); console.log("registered global shortcut", shortcut, ok ? "ok" : "failed"); if (!ok) { @@ -814,8 +829,8 @@ let lastUpdateCheck: Date = null; */ function setAppUpdateStatus(status: string) { appUpdateStatus = status; - if (MainWindow != null) { - MainWindow.webContents.send("app-update-status", appUpdateStatus); + if (windows["main"] != null) { + windows["main"].webContents.send("app-update-status", appUpdateStatus); } } @@ -900,7 +915,7 @@ async function installAppUpdate() { detail: "A new version has been downloaded. Restart the application to apply the updates.", }; - await electron.dialog.showMessageBox(MainWindow, dialogOpts).then(({ response }) => { + await electron.dialog.showMessageBox(windows["main"], dialogOpts).then(({ response }) => { if (response === 0) autoUpdater.quitAndInstall(); }); }