From 1f95d8a4ca3c9dc01489aefbf82c2b7d75f00e6b Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Mon, 13 Apr 2026 15:53:07 +0800 Subject: [PATCH] electron: assign ids to windows --- packages/desktop-electron/src/main/ipc.ts | 8 ++++- packages/desktop-electron/src/main/windows.ts | 32 +++++++++++++++++++ .../desktop-electron/src/preload/index.ts | 1 + .../desktop-electron/src/preload/types.ts | 1 + 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/desktop-electron/src/main/ipc.ts b/packages/desktop-electron/src/main/ipc.ts index 52d87ed7ee..726436df10 100644 --- a/packages/desktop-electron/src/main/ipc.ts +++ b/packages/desktop-electron/src/main/ipc.ts @@ -4,7 +4,7 @@ import type { IpcMainEvent, IpcMainInvokeEvent } from "electron" import type { InitStep, ServerReadyData, SqliteMigrationProgress, TitlebarTheme, WslConfig } from "../preload/types" import { getStore } from "./store" -import { setTitlebar } from "./windows" +import { getWindowId, setTitlebar } from "./windows" const pickerFilters = (ext?: string[]) => { if (!ext || ext.length === 0) return undefined @@ -151,6 +151,12 @@ export function registerIpcHandlers(deps: Deps) { ipcMain.handle("get-window-count", () => BrowserWindow.getAllWindows().length) + ipcMain.handle("get-window-id", (event: IpcMainInvokeEvent) => { + const win = BrowserWindow.fromWebContents(event.sender) + if (!win) return null + return getWindowId(win) ?? null + }) + ipcMain.handle("get-window-focused", (event: IpcMainInvokeEvent) => { const win = BrowserWindow.fromWebContents(event.sender) return win?.isFocused() ?? false diff --git a/packages/desktop-electron/src/main/windows.ts b/packages/desktop-electron/src/main/windows.ts index 95f80c1240..1822884f07 100644 --- a/packages/desktop-electron/src/main/windows.ts +++ b/packages/desktop-electron/src/main/windows.ts @@ -1,3 +1,4 @@ +import { randomInt } from "node:crypto" import windowState from "electron-window-state" import { app, BrowserWindow, nativeImage, nativeTheme } from "electron" import { dirname, join } from "node:path" @@ -12,6 +13,9 @@ type Globals = { const root = dirname(fileURLToPath(import.meta.url)) let backgroundColor: string | undefined +const ids = new WeakMap() +const used = new Set() +let seen = false export function setBackgroundColor(color: string) { backgroundColor = color @@ -21,6 +25,10 @@ export function getBackgroundColor(): string | undefined { return backgroundColor } +export function getWindowId(win: BrowserWindow) { + return ids.get(win) +} + function iconsDir() { return app.isPackaged ? join(process.resourcesPath, "icons") : join(root, "../../resources/icons") } @@ -88,6 +96,7 @@ export function createMainWindow(globals: Globals) { sandbox: false, }, }) + track(win) state.manage(win) loadWindow(win, "index.html") @@ -161,3 +170,26 @@ function wireZoom(win: BrowserWindow) { win.webContents.setZoomFactor(1) }) } + +function track(win: BrowserWindow) { + const id = nextId() + ids.set(win, id) + win.once("closed", () => { + used.delete(id) + }) +} + +function nextId() { + if (!seen) { + seen = true + used.add("main") + return "main" + } + + while (true) { + const id = String(randomInt(100_000, 1_000_000)) + if (used.has(id)) continue + used.add(id) + return id + } +} diff --git a/packages/desktop-electron/src/preload/index.ts b/packages/desktop-electron/src/preload/index.ts index 296fcb2f1c..67eeb20c3e 100644 --- a/packages/desktop-electron/src/preload/index.ts +++ b/packages/desktop-electron/src/preload/index.ts @@ -29,6 +29,7 @@ const api: ElectronAPI = { storeLength: (name) => ipcRenderer.invoke("store-length", name), getWindowCount: () => ipcRenderer.invoke("get-window-count"), + getWindowId: () => ipcRenderer.invoke("get-window-id"), onSqliteMigrationProgress: (cb) => { const handler = (_: unknown, progress: SqliteMigrationProgress) => cb(progress) ipcRenderer.on("sqlite-migration-progress", handler) diff --git a/packages/desktop-electron/src/preload/types.ts b/packages/desktop-electron/src/preload/types.ts index f8e6d52c7d..a60b9a5b6f 100644 --- a/packages/desktop-electron/src/preload/types.ts +++ b/packages/desktop-electron/src/preload/types.ts @@ -37,6 +37,7 @@ export type ElectronAPI = { storeLength: (name: string) => Promise getWindowCount: () => Promise + getWindowId: () => Promise onSqliteMigrationProgress: (cb: (progress: SqliteMigrationProgress) => void) => () => void onMenuCommand: (cb: (id: string) => void) => () => void onDeepLink: (cb: (urls: string[]) => void) => () => void