From 2007b0c2cc850b058241f5a568ff4edbdb31c85f Mon Sep 17 00:00:00 2001 From: EtienneLescot Date: Fri, 19 Jun 2026 13:03:42 +0200 Subject: [PATCH 1/2] Fix issue 3 app launch and UI bugs --- electron/main.ts | 14 ++++++- src/components/launch/LaunchWindow.tsx | 42 ++++++++++++++++++- src/components/video-editor/SettingsPanel.tsx | 8 ++-- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/electron/main.ts b/electron/main.ts index bfb949ed..f32673c2 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -108,6 +108,16 @@ function showMainWindow() { createWindow(); } +const hasSingleInstanceLock = app.requestSingleInstanceLock(); + +if (hasSingleInstanceLock) { + app.on("second-instance", () => { + showMainWindow(); + }); +} else { + app.quit(); +} + function isEditorWindow(window: BrowserWindow) { return window.webContents.getURL().includes("windowType=editor"); } @@ -453,7 +463,9 @@ app.on("will-quit", () => { unregisterAllGlobalShortcuts(); }); -app.whenReady().then(async () => { +const appReady = hasSingleInstanceLock ? app.whenReady() : null; + +appReady?.then(async () => { // Force "regular" activation policy so the Dock icon appears. The HUD overlay // (transparent, frameless, skipTaskbar) is the first window, and AppKit would // otherwise classify us as an accessory app. diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index a93514c5..dbe84311 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -476,6 +476,45 @@ export function LaunchWindow() { } }; const dragLastPositionRef = useRef<{ x: number; y: number } | null>(null); + const dragAnimationFrameRef = useRef(null); + const pendingDragDeltaRef = useRef({ x: 0, y: 0 }); + const flushHudDragMove = useCallback(() => { + dragAnimationFrameRef.current = null; + const { x, y } = pendingDragDeltaRef.current; + pendingDragDeltaRef.current = { x: 0, y: 0 }; + if (x === 0 && y === 0) return; + window.electronAPI?.moveHudOverlayBy?.(x, y); + }, []); + const scheduleHudDragMove = useCallback( + (deltaX: number, deltaY: number) => { + pendingDragDeltaRef.current = { + x: pendingDragDeltaRef.current.x + deltaX, + y: pendingDragDeltaRef.current.y + deltaY, + }; + + if (dragAnimationFrameRef.current === null) { + dragAnimationFrameRef.current = window.requestAnimationFrame(flushHudDragMove); + } + }, + [flushHudDragMove], + ); + const flushPendingHudDragMove = useCallback(() => { + if (dragAnimationFrameRef.current !== null) { + window.cancelAnimationFrame(dragAnimationFrameRef.current); + dragAnimationFrameRef.current = null; + } + const { x, y } = pendingDragDeltaRef.current; + pendingDragDeltaRef.current = { x: 0, y: 0 }; + if (x === 0 && y === 0) return; + window.electronAPI?.moveHudOverlayBy?.(x, y); + }, []); + useEffect(() => { + return () => { + if (dragAnimationFrameRef.current !== null) { + window.cancelAnimationFrame(dragAnimationFrameRef.current); + } + }; + }, []); const handleHudDragPointerDown = (event: React.PointerEvent) => { event.preventDefault(); event.stopPropagation(); @@ -489,10 +528,11 @@ export function LaunchWindow() { const deltaX = event.screenX - lastPosition.x; const deltaY = event.screenY - lastPosition.y; dragLastPositionRef.current = { x: event.screenX, y: event.screenY }; - window.electronAPI?.moveHudOverlayBy?.(deltaX, deltaY); + scheduleHudDragMove(deltaX, deltaY); }; const handleHudDragPointerEnd = (event: React.PointerEvent) => { dragLastPositionRef.current = null; + flushPendingHudDragMove(); if (event.currentTarget.hasPointerCapture(event.pointerId)) { event.currentTarget.releasePointerCapture(event.pointerId); } diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx index a2c5d401..5e0cc806 100644 --- a/src/components/video-editor/SettingsPanel.tsx +++ b/src/components/video-editor/SettingsPanel.tsx @@ -1705,22 +1705,22 @@ export function SettingsPanel({ - + {t("background.image")} {t("background.color")} {t("background.gradient")} From 59521204200459cbad256e5f600f2aa4ea389449 Mon Sep 17 00:00:00 2001 From: EtienneLescot Date: Fri, 19 Jun 2026 13:27:37 +0200 Subject: [PATCH 2/2] Guard duplicate HUD creation --- electron/main.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/electron/main.ts b/electron/main.ts index 16473e6f..57e489f3 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -92,6 +92,10 @@ const defaultTrayIcon = getTrayIcon("openscreen.png", trayIconSize); const recordingTrayIcon = getTrayIcon("rec-button.png", trayIconSize); function createWindow() { + if (mainWindow && !mainWindow.isDestroyed()) { + return; + } + mainWindow = createHudOverlayWindow(); }