From 532d194e27adb7d3a43286159d3f3be585455f91 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Fri, 29 May 2026 01:05:21 +0700 Subject: [PATCH] fix(linux): tighten portal source fallback routing --- electron/ipc/register/sourceMapping.test.ts | 24 ++++++++++++++++++++- electron/ipc/register/sourceMapping.ts | 10 +++++++-- electron/ipc/register/sources.ts | 1 + src/hooks/useScreenRecorder.test.ts | 11 +++++++++- src/hooks/useScreenRecorder.ts | 4 ++++ 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/electron/ipc/register/sourceMapping.test.ts b/electron/ipc/register/sourceMapping.test.ts index c5823e64..a4c67c16 100644 --- a/electron/ipc/register/sourceMapping.test.ts +++ b/electron/ipc/register/sourceMapping.test.ts @@ -17,16 +17,28 @@ describe("getScreenSourceIdForDisplay", () => { ).toBe("screen:42:0"); }); - it("routes unmatched Linux screens through the portal sentinel", () => { + it("routes unmatched Linux Wayland screens through the portal sentinel", () => { expect( getScreenSourceIdForDisplay({ displayId: "42", + env: { XDG_SESSION_TYPE: "wayland", WAYLAND_DISPLAY: "wayland-0" }, matchedSourceId: null, platform: "linux", }), ).toBe(LINUX_PORTAL_SCREEN_SOURCE_ID); }); + it("keeps unmatched Linux X11 screens on the explicit fallback id", () => { + expect( + getScreenSourceIdForDisplay({ + displayId: "42", + env: { XDG_SESSION_TYPE: "x11", DISPLAY: ":0" }, + matchedSourceId: null, + platform: "linux", + }), + ).toBe("screen:fallback:42"); + }); + it("keeps non-Linux unmatched screens on the explicit fallback id", () => { expect( getScreenSourceIdForDisplay({ @@ -59,6 +71,16 @@ describe("shouldUseSyntheticLinuxPortalSource", () => { ).toBe(false); }); + it("recovers stale fallback ids through the synthetic path on Wayland", () => { + expect( + shouldUseSyntheticLinuxPortalSource({ + env: { WAYLAND_DISPLAY: "wayland-0" }, + platform: "linux", + sourceId: "screen:fallback:0", + }), + ).toBe(true); + }); + it("defaults unknown Linux sessions with WAYLAND_DISPLAY to the synthetic path", () => { expect( shouldUseSyntheticLinuxPortalSource({ diff --git a/electron/ipc/register/sourceMapping.ts b/electron/ipc/register/sourceMapping.ts index c779c380..b6a4366d 100644 --- a/electron/ipc/register/sourceMapping.ts +++ b/electron/ipc/register/sourceMapping.ts @@ -14,10 +14,12 @@ export function isLikelyLinuxWaylandSession(env: NodeJS.ProcessEnv) { export function getScreenSourceIdForDisplay({ displayId, + env = process.env, matchedSourceId, platform, }: { displayId: string; + env?: NodeJS.ProcessEnv; matchedSourceId?: string | null; platform: NodeJS.Platform | string; }) { @@ -25,7 +27,7 @@ export function getScreenSourceIdForDisplay({ return matchedSourceId; } - if (platform === "linux") { + if (platform === "linux" && isLikelyLinuxWaylandSession(env)) { return LINUX_PORTAL_SCREEN_SOURCE_ID; } @@ -45,7 +47,11 @@ export function shouldUseSyntheticLinuxPortalSource({ return false; } - if (sourceId && sourceId !== LINUX_PORTAL_SCREEN_SOURCE_ID) { + if ( + sourceId && + sourceId !== LINUX_PORTAL_SCREEN_SOURCE_ID && + !sourceId.startsWith("screen:fallback:") + ) { return false; } diff --git a/electron/ipc/register/sources.ts b/electron/ipc/register/sources.ts index 141a335f..b59d9ead 100644 --- a/electron/ipc/register/sources.ts +++ b/electron/ipc/register/sources.ts @@ -128,6 +128,7 @@ export function registerSourceHandlers({ return { id: getScreenSourceIdForDisplay({ displayId, + env: process.env, matchedSourceId: matchedSource?.id, platform: process.platform, }), diff --git a/src/hooks/useScreenRecorder.test.ts b/src/hooks/useScreenRecorder.test.ts index 8f6d8b58..ae27d1c1 100644 --- a/src/hooks/useScreenRecorder.test.ts +++ b/src/hooks/useScreenRecorder.test.ts @@ -212,7 +212,7 @@ describe("shouldUseLinuxPortalCapture", () => { it("uses the portal when the selected source is the Linux sentinel", () => { expect( shouldUseLinuxPortalCapture({ - browserCaptureSourceId: "screen:0:0", + browserCaptureSourceId: "screen:linux-portal", selectedSourceId: "screen:linux-portal", }), ).toBe(true); @@ -235,6 +235,15 @@ describe("shouldUseLinuxPortalCapture", () => { }), ).toBe(false); }); + + it("prefers a live Electron source over stale portal selection state", () => { + expect( + shouldUseLinuxPortalCapture({ + browserCaptureSourceId: "screen:42:0", + selectedSourceId: "screen:linux-portal", + }), + ).toBe(false); + }); }); describe("getScreenCaptureCursorSetting", () => { diff --git a/src/hooks/useScreenRecorder.ts b/src/hooks/useScreenRecorder.ts index 2e71b2cc..8455a0bf 100644 --- a/src/hooks/useScreenRecorder.ts +++ b/src/hooks/useScreenRecorder.ts @@ -135,6 +135,10 @@ export function shouldUseLinuxPortalCapture({ browserCaptureSourceId?: string; selectedSourceId?: string; }) { + if (browserCaptureSourceId && browserCaptureSourceId !== LINUX_PORTAL_SOURCE.id) { + return false; + } + return ( selectedSourceId === LINUX_PORTAL_SOURCE.id || browserCaptureSourceId === LINUX_PORTAL_SOURCE.id