diff --git a/electron/main.ts b/electron/main.ts index ed05ffeb..f0ae2092 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -712,39 +712,39 @@ function updateTrayMenu(recording: boolean = false) { const trayToolTip = recording ? `Recording: ${selectedSourceName}` : "Recordly"; const menuTemplate = recording ? [ - { - label: "Show Controls", - click: () => { - if (!showHudOverlayFromTray()) { - focusOrCreateMainWindow(); - } - }, + { + label: "Show Controls", + click: () => { + if (!showHudOverlayFromTray()) { + focusOrCreateMainWindow(); + } }, - { - label: "Stop Recording", - click: () => { - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.webContents.send("stop-recording-from-tray"); - } - }, + }, + { + label: "Stop Recording", + click: () => { + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.webContents.send("stop-recording-from-tray"); + } }, - ] + }, + ] : [ - { - label: "Open", - click: () => { - if (!showHudOverlayFromTray()) { - focusOrCreateMainWindow(); - } - }, + { + label: "Open", + click: () => { + if (!showHudOverlayFromTray()) { + focusOrCreateMainWindow(); + } }, - { - label: "Quit", - click: () => { - app.quit(); - }, + }, + { + label: "Quit", + click: () => { + app.quit(); }, - ]; + }, + ]; const menu = Menu.buildFromTemplate(menuTemplate); trayContextMenu = menu; tray.setImage(trayIcon); @@ -1005,7 +1005,7 @@ app.whenReady().then(async () => { // ignored by the native capture pipeline. session.defaultSession.setDisplayMediaRequestHandler(async (_request, callback) => { try { - const sourceId = getSelectedSourceId(); + let sourceId = getSelectedSourceId(); // On Linux/Wayland, calling desktopCapturer.getSources() itself // invokes the xdg-desktop-portal picker. If we then return one of // those sources, Chromium triggers a SECOND portal because the @@ -1014,27 +1014,37 @@ app.whenReady().then(async () => { // is set we skip getSources entirely and hand back a synthetic // source id; Chromium then opens the portal once to actually // resolve the capture. - // Default to the sentinel on Linux when no source has been - // pre-selected (e.g. fresh session where the renderer skipped the - // source picker entirely). This avoids calling getSources() which - // would itself trigger an extra portal dialog. + const isWayland = + process.env.XDG_SESSION_TYPE === "wayland" || !!process.env.WAYLAND_DISPLAY; + const isLinuxPortalSentinel = - process.platform === "linux" && (sourceId === "screen:linux-portal" || !sourceId); + process.platform === "linux" && isWayland && (sourceId === "screen:linux-portal" || !sourceId); if (isLinuxPortalSentinel) { callback({ video: { id: "screen:0:0", name: "Entire screen" } }); return; } + + // On Linux/X11, "screen:linux-portal" is not a real desktopCapturer + // source id. Resolve the actual X11 source instead, e.g. screen:428:0. + if (process.platform === "linux" && sourceId === "screen:linux-portal") { + sourceId = null; + } + const sources = await desktopCapturer.getSources({ types: ["screen", "window"] }); - const source = sourceId - ? (sources.find((s) => s.id === sourceId) ?? sources[0]) - : sources[0]; - if (source) { - callback({ - video: { id: source.id, name: source.name }, - }); - } else { + + const source = + (sourceId ? sources.find((s) => s.id === sourceId) : undefined) ?? + sources.find((s) => s.id.startsWith("screen:")) ?? + sources[0]; + + if (!source) { callback({}); + return; } + + callback({ + video: { id: source.id, name: source.name, }, + }); } catch (error) { console.error("setDisplayMediaRequestHandler error:", error); callback({}); diff --git a/src/components/video-editor/videoPlayback/zoomRegionUtils.ts b/src/components/video-editor/videoPlayback/zoomRegionUtils.ts index 8e1cc6bf..ab1af945 100644 --- a/src/components/video-editor/videoPlayback/zoomRegionUtils.ts +++ b/src/components/video-editor/videoPlayback/zoomRegionUtils.ts @@ -6,7 +6,7 @@ import { ZOOM_OUT_EARLY_START_MS, } from "./constants"; import { clampFocusToScale } from "./focusUtils"; -import { clamp01, cubicBezier, easeOutZoom } from "./mathUtils"; +import { clamp01, easeOutZoom } from "./mathUtils"; const CHAINED_ZOOM_PAN_GAP_MS = 1350; const CONNECTED_ZOOM_PAN_DURATION_MS = 1000; @@ -34,14 +34,6 @@ type ConnectedPanTransition = { endScale: number; }; -function lerp(start: number, end: number, amount: number) { - return start + (end - start) * amount; -} - -function easeConnectedPan(value: number) { - return cubicBezier(0.1, 0.0, 0.2, 1.0, value); -} - export function computeRegionStrength( region: ZoomRegion, timeMs: number, @@ -79,13 +71,6 @@ export function computeRegionStrength( return 1 - easeOutZoom(progress); } -function getLinearFocus(start: ZoomFocus, end: ZoomFocus, amount: number): ZoomFocus { - return { - cx: lerp(start.cx, end.cx, amount), - cy: lerp(start.cy, end.cy, amount), - }; -} - function getResolvedFocus(region: ZoomRegion, zoomScale: number): ZoomFocus { return clampFocusToScale(region.focus, zoomScale); } @@ -199,44 +184,6 @@ function getConnectedRegionHold(timeMs: number, connectedPairs: ConnectedRegionP return null; } -function getConnectedRegionTransition(connectedPairs: ConnectedRegionPair[], timeMs: number) { - for (const pair of connectedPairs) { - const { currentRegion, nextRegion, transitionStart, transitionEnd } = pair; - - if (timeMs < transitionStart || timeMs > transitionEnd) { - continue; - } - - const transitionProgress = easeConnectedPan( - clamp01((timeMs - transitionStart) / Math.max(1, transitionEnd - transitionStart)), - ); - const currentScale = ZOOM_DEPTH_SCALES[currentRegion.depth]; - const nextScale = ZOOM_DEPTH_SCALES[nextRegion.depth]; - const transitionScale = lerp(currentScale, nextScale, transitionProgress); - const currentFocus = getResolvedFocus(currentRegion, currentScale); - const nextFocus = getResolvedFocus(nextRegion, nextScale); - const transitionFocus = getLinearFocus(currentFocus, nextFocus, transitionProgress); - - return { - region: { - ...nextRegion, - focus: transitionFocus, - }, - strength: 1, - blendedScale: transitionScale, - transition: { - progress: transitionProgress, - startFocus: currentFocus, - endFocus: nextFocus, - startScale: currentScale, - endScale: nextScale, - }, - }; - } - - return null; -} - export function findDominantRegion( regions: ZoomRegion[], timeMs: number,