From a6cd0af1eff38a64e77c5dc16279a6405da5aded Mon Sep 17 00:00:00 2001 From: EtienneLescot <215859519+EtienneLescot@users.noreply.github.com> Date: Mon, 22 Jun 2026 09:14:49 +0000 Subject: [PATCH] Keep HUD interactive on Linux so the drag handle can receive pointer events Fixes #12 --- src/components/launch/LaunchWindow.test.tsx | 15 +++++++++++++- src/components/launch/LaunchWindow.tsx | 23 ++++++++++++++------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/components/launch/LaunchWindow.test.tsx b/src/components/launch/LaunchWindow.test.tsx index 6440f1d41..29a67374b 100644 --- a/src/components/launch/LaunchWindow.test.tsx +++ b/src/components/launch/LaunchWindow.test.tsx @@ -8,6 +8,8 @@ type SelectedSourceChangedListener = Parameters< Window["electronAPI"]["onSelectedSourceChanged"] >[0]; +const platformState = vi.hoisted(() => ({ value: "darwin" })); + const recorderState = vi.hoisted(() => ({ value: { recording: false, @@ -71,7 +73,7 @@ vi.mock("../../lib/requestCameraAccess", () => ({ vi.mock("@/native", () => ({ nativeBridgeClient: { system: { - getPlatform: vi.fn(async () => "darwin"), + getPlatform: vi.fn(async () => platformState.value), }, }, })); @@ -190,6 +192,7 @@ function emitSourceSelectorClosed() { describe("LaunchWindow record button", () => { beforeEach(() => { + platformState.value = "darwin"; class ResizeObserver { observe() { return undefined; @@ -327,4 +330,14 @@ describe("LaunchWindow record button", () => { expect(recorderState.value.toggleRecording).toHaveBeenCalledTimes(1); expect(window.electronAPI.openSourceSelector).not.toHaveBeenCalled(); }); + + it("keeps the HUD interactive on Linux so the drag handle can receive pointer events", async () => { + platformState.value = "linux"; + + renderLaunchWindow(); + + await waitFor(() => { + expect(window.electronAPI.setHudOverlayIgnoreMouseEvents).toHaveBeenLastCalledWith(false); + }); + }); }); diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index 511ab8e5c..6b614caae 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -143,6 +143,7 @@ export function LaunchWindow() { () => loadUserPreferences().trayLayout, ); const [supportsCursorModeToggle, setSupportsCursorModeToggle] = useState(false); + const [isLinuxHud, setIsLinuxHud] = useState(false); const languageTriggerRef = useRef(null); const languageMenuPanelRef = useRef(null); const hudBarRef = useRef(null); @@ -212,11 +213,13 @@ export function LaunchWindow() { .then((platform) => { if (!cancelled) { setSupportsCursorModeToggle(platform === "win32" || platform === "darwin"); + setIsLinuxHud(platform === "linux"); } }) .catch(() => { if (!cancelled) { setSupportsCursorModeToggle(false); + setIsLinuxHud(false); } }); @@ -400,14 +403,18 @@ export function LaunchWindow() { [observeHudElement], ); - const hudMouseEventsEnabledRef = useRef(undefined); - const setHudMouseEventsEnabled = useCallback((enabled: boolean) => { - if (hudMouseEventsEnabledRef.current === enabled) { - return; - } - hudMouseEventsEnabledRef.current = enabled; - window.electronAPI?.setHudOverlayIgnoreMouseEvents?.(!enabled); - }, []); + const hudIgnoreMouseEventsRef = useRef(undefined); + const setHudMouseEventsEnabled = useCallback( + (enabled: boolean) => { + const shouldIgnoreMouseEvents = !enabled && !isLinuxHud; + if (hudIgnoreMouseEventsRef.current === shouldIgnoreMouseEvents) { + return; + } + hudIgnoreMouseEventsRef.current = shouldIgnoreMouseEvents; + window.electronAPI?.setHudOverlayIgnoreMouseEvents?.(shouldIgnoreMouseEvents); + }, + [isLinuxHud], + ); useEffect(() => { setHudMouseEventsEnabled(false);