From 96d2ca9e5c26f37a2117842117db8ad04fb476c9 Mon Sep 17 00:00:00 2001 From: webadderall <131426131+webadderall@users.noreply.github.com> Date: Mon, 6 Apr 2026 15:22:58 +1000 Subject: [PATCH] Improve tray and packaged editor restore paths --- electron/main.ts | 49 ++++++++++++++++----- electron/windows.ts | 103 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 128 insertions(+), 24 deletions(-) diff --git a/electron/main.ts b/electron/main.ts index 8e5ee927..1cdeb575 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -22,6 +22,7 @@ import { killWindowsCaptureProcess, registerIpcHandlers, } from "./ipc/handlers"; +import { ensurePackagedRendererServer } from "./rendererServer"; import type { UpdateToastPayload } from "./updater"; import { checkForAppUpdates, @@ -46,30 +47,25 @@ import { isHudOverlayMousePassthroughSupported, showUpdateToastWindow, } from "./windows"; -import { ensurePackagedRendererServer } from "./rendererServer"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const IS_SMOKE_EXPORT = process.env.RECORDLY_SMOKE_EXPORT === "1"; function configureGpuAccelerationSwitches() { - app.commandLine.appendSwitch("ignore-gpu-blocklist"); - app.commandLine.appendSwitch("enable-gpu-rasterization"); - if (process.platform === "darwin") { + app.commandLine.appendSwitch("ignore-gpu-blocklist"); + app.commandLine.appendSwitch("enable-gpu-rasterization"); app.commandLine.appendSwitch("use-angle", "metal"); app.commandLine.appendSwitch("disable-features", "MacCatapLoopbackAudioForScreenShare"); return; } if (process.platform === "win32") { + app.commandLine.appendSwitch("ignore-gpu-blocklist"); + app.commandLine.appendSwitch("enable-gpu-rasterization"); app.commandLine.appendSwitch("use-angle", "d3d11"); return; } - - if (process.platform === "linux") { - app.commandLine.appendSwitch("use-angle", "vulkan"); - app.commandLine.appendSwitch("enable-features", "Vulkan"); - } } async function logSmokeExportGpuDiagnostics() { @@ -121,6 +117,7 @@ process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL let mainWindow: BrowserWindow | null = null; let sourceSelectorWindow: BrowserWindow | null = null; let tray: Tray | null = null; +let trayContextMenu: Menu | null = null; let selectedSourceName = ""; let editorHasUnsavedChanges = false; let isForceClosing = false; @@ -392,9 +389,35 @@ function setupApplicationMenu() { Menu.setApplicationMenu(menu); } +function isPrimaryTrayClick(event: unknown) { + const button = + event && typeof event === "object" && "button" in event + ? (event as { button?: number | string }).button + : undefined; + return button === undefined || button === 0 || button === "left"; +} + function createTray() { tray = new Tray(getDefaultTrayIcon()); - tray.on("click", () => focusOrCreateMainWindow()); + tray.on("click", (event) => { + if (process.platform === "win32" && !isPrimaryTrayClick(event)) { + return; + } + + focusOrCreateMainWindow(); + }); + + if (process.platform === "win32") { + tray.on("right-click", () => { + if (!tray || !trayContextMenu) { + return; + } + + tray.popUpContextMenu(trayContextMenu); + }); + return; + } + tray.on("double-click", () => focusOrCreateMainWindow()); } @@ -640,9 +663,13 @@ function updateTrayMenu(recording: boolean = false) { }, }, ]; + const menu = Menu.buildFromTemplate(menuTemplate); + trayContextMenu = menu; tray.setImage(trayIcon); tray.setToolTip(trayToolTip); - tray.setContextMenu(Menu.buildFromTemplate(menuTemplate)); + if (process.platform !== "win32") { + tray.setContextMenu(menu); + } } function createEditorWindowWrapper() { diff --git a/electron/windows.ts b/electron/windows.ts index 3ab5e3de..0bfbf309 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -571,6 +571,95 @@ export function hideUpdateToastWindow(): void { updateToastWindow.hide(); } +function loadPackagedEditorWindow(win: BrowserWindow) { + const query = getEditorWindowQuery(); + const queryString = new URLSearchParams(query).toString(); + const indexHtmlPath = path.join(RENDERER_DIST, "index.html"); + const packagedRendererBaseUrl = getPackagedRendererBaseUrl(); + + const loadFromFile = () => { + console.log("[editor-window] load-file", indexHtmlPath); + void win.loadFile(indexHtmlPath, { query }); + }; + + if (!packagedRendererBaseUrl) { + loadFromFile(); + return; + } + + const targetUrl = `${packagedRendererBaseUrl}/?${queryString}`; + let settled = false; + let timeoutId: NodeJS.Timeout | null = setTimeout(() => { + fallbackToFile("load-timeout"); + }, 5000); + + const clearTimeoutIfNeeded = () => { + if (timeoutId) { + clearTimeout(timeoutId); + timeoutId = null; + } + }; + + const cleanup = () => { + clearTimeoutIfNeeded(); + win.webContents.removeListener("did-fail-load", handleDidFailLoad); + win.webContents.removeListener("did-finish-load", handleDidFinishLoad); + }; + + const fallbackToFile = (reason: string, details?: Record) => { + if (settled || win.isDestroyed()) { + return; + } + + settled = true; + cleanup(); + console.warn("[editor-window] packaged renderer URL failed, falling back to file", { + reason, + targetUrl, + ...details, + }); + loadFromFile(); + }; + + const handleDidFailLoad = ( + _event: Electron.Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean, + ) => { + if (!isMainFrame || validatedURL !== targetUrl) { + return; + } + + fallbackToFile("did-fail-load", { + errorCode, + errorDescription, + validatedURL, + }); + }; + + const handleDidFinishLoad = () => { + if (win.webContents.getURL() !== targetUrl) { + return; + } + + settled = true; + cleanup(); + }; + + win.webContents.on("did-fail-load", handleDidFailLoad); + win.webContents.on("did-finish-load", handleDidFinishLoad); + win.once("closed", cleanup); + + console.log("[editor-window] load-url", targetUrl); + void win.loadURL(targetUrl).catch((error) => { + fallbackToFile("load-url-rejected", { + error: error instanceof Error ? error.message : String(error), + }); + }); +} + export function createEditorWindow(): BrowserWindow { const isMac = process.platform === "darwin"; const { workArea, workAreaSize } = getScreen().getPrimaryDisplay(); @@ -644,19 +733,7 @@ export function createEditorWindow(): BrowserWindow { const query = new URLSearchParams(getEditorWindowQuery()); win.loadURL(`${VITE_DEV_SERVER_URL}?${query.toString()}`); } else { - const query = new URLSearchParams(getEditorWindowQuery()); - const packagedRendererBaseUrl = getPackagedRendererBaseUrl(); - - if (packagedRendererBaseUrl) { - const targetUrl = `${packagedRendererBaseUrl}/?${query.toString()}`; - console.log("[editor-window] load-url", targetUrl); - win.loadURL(targetUrl); - } else { - console.log("[editor-window] load-file", path.join(RENDERER_DIST, "index.html")); - win.loadFile(path.join(RENDERER_DIST, "index.html"), { - query: getEditorWindowQuery(), - }); - } + loadPackagedEditorWindow(win); } return win;