From 5a9d56210ecec82b638ef787573cce7f845e9ceb Mon Sep 17 00:00:00 2001 From: bernardopg Date: Fri, 26 Jun 2026 18:11:35 -0300 Subject: [PATCH 1/2] fix(linux): make the recording HUD usable on Wayland/Hyprland The recording control HUD is a transparent, always-on-top overlay. On Linux, mouse pass-through (setIgnoreMouseEvents(true, { forward: true })) was disabled, so every transparent pixel of the overlay captured the cursor. On Wayland compositors with focus-follows-mouse (e.g. Hyprland) this made the bar flicker and disappear on hover, prevented its buttons from being clicked, and blocked clicks on the windows underneath it (#638, #657, #687). Enable pass-through on Linux so the HUD behaves like it does on Windows 11: click-through everywhere except over the interactive controls. While recording, other platforms shrink the HUD to a compact bar and reposition it. Wayland ignores programmatic window placement (BrowserWindow.setBounds x/y is silently dropped), so a shrunken bar cannot move back to the bottom-centre and ends up stranded (top-left on Hyprland). On Linux, keep the full-work-area, click-through window while recording and honour the renderer-driven pass-through so the controls stay clickable without moving the window. All changes are gated to Linux; Windows and macOS behaviour is unchanged. --- electron/windows.ts | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/electron/windows.ts b/electron/windows.ts index 478584b55..9e9241645 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -123,8 +123,14 @@ function getWindowsBuildNumber(): number | null { } export function isHudOverlayMousePassthroughSupported(): boolean { + // On Linux (X11 and Wayland), Electron's setIgnoreMouseEvents(true, { forward: true }) + // is supported and is required for the HUD to behave correctly. The HUD is a + // transparent, always-on-top overlay; without mouse pass-through every transparent + // pixel captures the cursor, which on Wayland compositors with focus-follows-mouse + // (e.g. Hyprland) makes the control bar flicker/disappear on hover and blocks clicks + // on the windows underneath it. See #638, #657, #687. if (process.platform === "linux") { - return false; + return true; } const build = getWindowsBuildNumber(); @@ -190,9 +196,18 @@ function getHudOverlayDisplay() { function getHudOverlayBounds() { const { workArea } = getHudOverlayDisplay(); + // On platforms with mouse pass-through the HUD spans the whole work area and stays + // click-through except over the interactive controls. On Linux/Wayland the compositor + // ignores programmatic window placement (BrowserWindow.setBounds x/y is silently + // dropped), so a window that shrinks to a compact bar while recording cannot move + // itself back to the bottom-centre and ends up stranded (e.g. top-left on Hyprland). + // Keep the full-work-area, click-through window while recording on Linux so the bar + // stays put; other platforms keep the compact recording bar they can reposition. + const keepFullBoundsWhileRecording = process.platform === "linux"; return getHudOverlayWindowBounds( workArea, - isHudOverlayMousePassthroughSupported() && !hudOverlayRecordingActive, + isHudOverlayMousePassthroughSupported() && + (keepFullBoundsWhileRecording || !hudOverlayRecordingActive), hudOverlayFallbackExpanded, ); } @@ -277,10 +292,15 @@ function setHudOverlayFallbackExpanded(expanded: boolean) { } function setHudOverlayMousePassthrough(ignore: boolean) { + // While recording, non-Linux platforms shrink the HUD to a compact bar that always + // captures the mouse. On Linux the window stays full-work-area and click-through, so + // the renderer-driven `ignore` value is honoured (see getHudOverlayBounds / the + // recording branch below). + const recordingForcesCapture = hudOverlayRecordingActive && process.platform !== "linux"; hudOverlayIgnoringMouse = hudOverlaySourceSelectionActive && !hudOverlayRecordingActive ? true - : hudOverlayRecordingActive + : recordingForcesCapture ? false : ignore; @@ -296,7 +316,19 @@ function setHudOverlayMousePassthrough(ignore: boolean) { if (hudOverlayRecordingActive) { hudOverlayFallbackExpanded = false; applyHudOverlayBounds(); - hudOverlayWindow.setIgnoreMouseEvents(false); + if (process.platform === "linux" && isHudOverlayMousePassthroughSupported()) { + // Linux keeps the full-work-area, always-on-top window while recording. + // Honour the renderer-driven pass-through so the controls stay clickable + // while clicks fall through everywhere else (the compositor cannot move a + // shrunken bar back into place, so we never shrink it here). + if (ignore) { + hudOverlayWindow.setIgnoreMouseEvents(true, { forward: true }); + } else { + hudOverlayWindow.setIgnoreMouseEvents(false); + } + } else { + hudOverlayWindow.setIgnoreMouseEvents(false); + } return; } From 03e1701ff24ad87dd15fdb49d67ccbf70be8d9a5 Mon Sep 17 00:00:00 2001 From: bernardopg Date: Fri, 26 Jun 2026 18:29:51 -0300 Subject: [PATCH 2/2] fix(linux): start recording HUD click-through and maximize the editor Two Linux/Wayland follow-ups to the HUD pass-through work: - setHudOverlayRecordingActive started the full-work-area recording HUD in the capturing state (setIgnoreMouseEvents(false)), so the click-through overlay captured every click and blocked the content being recorded. Start it in pass-through on Linux and let the renderer re-assert capture over the controls. - The editor window requests an explicit position, but Wayland ignores programmatic placement, so it could land under reserved areas (panels/bars). Maximize it on Linux so the compositor fits it to the available work area. --- electron/windows.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/electron/windows.ts b/electron/windows.ts index 9e9241645..def7e40b9 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -670,7 +670,15 @@ export function setHudOverlayRecordingActive(recording: boolean): void { hudOverlayRecordingActive = Boolean(recording); hudOverlayFallbackExpanded = false; applyHudOverlayBounds(); - setHudOverlayMousePassthrough(!hudOverlayRecordingActive); + // On Linux the recording HUD keeps the full work area and stays click-through, so it + // must start in pass-through (otherwise the full-screen window would capture every + // click and block the content being recorded). The renderer's hover logic re-asserts + // capture over the controls. Other platforms shrink to a compact, always-capturing bar. + const startIgnoringMouse = + process.platform === "linux" && isHudOverlayMousePassthroughSupported() + ? true + : !hudOverlayRecordingActive; + setHudOverlayMousePassthrough(startIgnoringMouse); } export function createUpdateToastWindow(): BrowserWindow { @@ -899,6 +907,12 @@ export function createEditorWindow(): BrowserWindow { win.once("ready-to-show", () => { console.log(`[PERF:MAIN] Editor Window: ready-to-show in ${Date.now() - perfStart}ms`); win.show(); + // On Linux/Wayland the compositor ignores the requested x/y, so the editor can + // land partly under reserved areas (panels/bars). Maximizing lets the compositor + // fit it to the available work area instead. + if (process.platform === "linux") { + win.maximize(); + } }); win.webContents.on("did-finish-load", () => { @@ -908,6 +922,9 @@ export function createEditorWindow(): BrowserWindow { if (!win.isDestroyed() && !win.isVisible()) { console.log("[editor-window] forcing show after did-finish-load"); win.show(); + if (process.platform === "linux") { + win.maximize(); + } } });