From bbd514efbafde7f9348c24851216996ce0480d9a Mon Sep 17 00:00:00 2001 From: webadderall <131426131+webadderall@users.noreply.github.com> Date: Sun, 22 Mar 2026 20:44:28 +1100 Subject: [PATCH] perf: remove launch source polling Push selected-source changes from Electron to the launch window instead of polling every 500ms, reducing constant renderer and IPC churn. Also restore the TimelineEditor audio path narrowing fix so the current tree stays type-safe. --- electron/electron-env.d.ts | 1 + electron/ipc/handlers.ts | 9 +++++ electron/preload.ts | 5 +++ src/components/launch/LaunchWindow.tsx | 35 +++++++++++++------ .../video-editor/timeline/TimelineEditor.tsx | 4 ++- 5 files changed, 43 insertions(+), 11 deletions(-) diff --git a/electron/electron-env.d.ts b/electron/electron-env.d.ts index f06f73d1..2b723af7 100644 --- a/electron/electron-env.d.ts +++ b/electron/electron-env.d.ts @@ -39,6 +39,7 @@ interface Window { selectSource: (source: any) => Promise; showSourceHighlight: (source: any) => Promise<{ success: boolean }>; getSelectedSource: () => Promise; + onSelectedSourceChanged: (callback: (source: any) => void) => () => void; startNativeScreenRecording: ( source: any, options?: { diff --git a/electron/ipc/handlers.ts b/electron/ipc/handlers.ts index 846299e3..ccb25c3f 100644 --- a/electron/ipc/handlers.ts +++ b/electron/ipc/handlers.ts @@ -43,6 +43,14 @@ function getScreen() { return nodeRequire('electron').screen as typeof import('electron').screen } +function broadcastSelectedSourceChange() { + for (const window of BrowserWindow.getAllWindows()) { + if (!window.isDestroyed()) { + window.webContents.send('selected-source-changed', selectedSource) + } + } +} + type SelectedSource = { id?: string name: string @@ -2575,6 +2583,7 @@ export function registerIpcHandlers( ipcMain.handle('select-source', (_, source: SelectedSource) => { selectedSource = source + broadcastSelectedSourceChange() stopWindowBoundsCapture() const sourceSelectorWin = getSourceSelectorWindow() if (sourceSelectorWin) { diff --git a/electron/preload.ts b/electron/preload.ts index f5c8fa53..bdf00e46 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -49,6 +49,11 @@ contextBridge.exposeInMainWorld("electronAPI", { getSelectedSource: () => { return ipcRenderer.invoke("get-selected-source"); }, + onSelectedSourceChanged: (callback: (source: any) => void) => { + const listener = (_event: Electron.IpcRendererEvent, payload: any) => callback(payload); + ipcRenderer.on("selected-source-changed", listener); + return () => ipcRenderer.removeListener("selected-source-changed", listener); + }, startNativeScreenRecording: ( source: any, options?: { diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index 36f5438a..02e011a9 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -297,20 +297,35 @@ export function LaunchWindow() { }; useEffect(() => { - const checkSelectedSource = async () => { - if (!window.electronAPI) return; - const source = await window.electronAPI.getSelectedSource(); - if (source) { + let mounted = true; + + const applySelectedSource = (source: { name?: string } | null | undefined) => { + if (!mounted) { + return; + } + + if (source?.name) { setSelectedSource(source.name); setHasSelectedSource(true); - } else { - setSelectedSource("Screen"); - setHasSelectedSource(false); + return; } + + setSelectedSource("Screen"); + setHasSelectedSource(false); + }; + + void window.electronAPI.getSelectedSource().then((source) => { + applySelectedSource(source); + }); + + const cleanup = window.electronAPI.onSelectedSourceChanged((source) => { + applySelectedSource(source); + }); + + return () => { + mounted = false; + cleanup?.(); }; - void checkSelectedSource(); - const interval = setInterval(checkSelectedSource, 500); - return () => clearInterval(interval); }, []); useEffect(() => { diff --git a/src/components/video-editor/timeline/TimelineEditor.tsx b/src/components/video-editor/timeline/TimelineEditor.tsx index 07c7a70a..ee0080e0 100644 --- a/src/components/video-editor/timeline/TimelineEditor.tsx +++ b/src/components/video-editor/timeline/TimelineEditor.tsx @@ -1179,9 +1179,11 @@ export default function TimelineEditor({ return; } + const audioPath = result.path; + // Load the audio file to get its full duration const audioDurationMs = await new Promise((resolve) => { - const audio = new Audio(toFileUrl(result.path)); + const audio = new Audio(toFileUrl(audioPath)); audio.addEventListener('loadedmetadata', () => { resolve(Math.round(audio.duration * 1000)); });