From e99356a04bd277ee4fb8e85276365fef318ada1a Mon Sep 17 00:00:00 2001 From: webadderall Date: Sat, 6 Jun 2026 20:01:19 +1000 Subject: [PATCH] fix(linux): preserve portal screen source mapping --- electron/ipc/register/sourceMapping.test.ts | 50 +++++++++++++++++++++ electron/ipc/register/sourceMapping.ts | 35 +++++++++++++++ electron/ipc/register/sources.ts | 8 +++- 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 electron/ipc/register/sourceMapping.test.ts create mode 100644 electron/ipc/register/sourceMapping.ts diff --git a/electron/ipc/register/sourceMapping.test.ts b/electron/ipc/register/sourceMapping.test.ts new file mode 100644 index 00000000..d0b68e75 --- /dev/null +++ b/electron/ipc/register/sourceMapping.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from "vitest"; + +import { + getScreenSourceIdForDisplay, + LINUX_PORTAL_SCREEN_SOURCE_ID, +} from "./sourceMapping"; + +describe("getScreenSourceIdForDisplay", () => { + it("keeps the live Electron screen source when one is available", () => { + expect( + getScreenSourceIdForDisplay({ + displayId: "42", + matchedSourceId: "screen:42:0", + platform: "linux", + }), + ).toBe("screen:42:0"); + }); + + 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({ + displayId: "42", + matchedSourceId: undefined, + platform: "win32", + }), + ).toBe("screen:fallback:42"); + }); +}); \ No newline at end of file diff --git a/electron/ipc/register/sourceMapping.ts b/electron/ipc/register/sourceMapping.ts new file mode 100644 index 00000000..a61b4cf7 --- /dev/null +++ b/electron/ipc/register/sourceMapping.ts @@ -0,0 +1,35 @@ +export const LINUX_PORTAL_SCREEN_SOURCE_ID = "screen:linux-portal"; + +export function isLikelyLinuxWaylandSession(env: NodeJS.ProcessEnv) { + const sessionType = env.XDG_SESSION_TYPE?.trim().toLowerCase(); + if (sessionType === "wayland") { + return true; + } + if (sessionType === "x11") { + return false; + } + + return Boolean(env.WAYLAND_DISPLAY); +} + +export function getScreenSourceIdForDisplay({ + displayId, + env = process.env, + matchedSourceId, + platform, +}: { + displayId: string; + env?: NodeJS.ProcessEnv; + matchedSourceId?: string | null; + platform: NodeJS.Platform | string; +}) { + if (matchedSourceId) { + return matchedSourceId; + } + + if (platform === "linux" && isLikelyLinuxWaylandSession(env)) { + return LINUX_PORTAL_SCREEN_SOURCE_ID; + } + + return `screen:fallback:${displayId}`; +} \ No newline at end of file diff --git a/electron/ipc/register/sources.ts b/electron/ipc/register/sources.ts index 4ba6b35a..33c9ee74 100644 --- a/electron/ipc/register/sources.ts +++ b/electron/ipc/register/sources.ts @@ -6,6 +6,7 @@ import { selectedSource, setSelectedSource } from "../state"; import type { SelectedSource } from "../types"; import { getScreen, parseWindowId } from "../utils"; import { getDisplayBoundsForSource, getDisplayWorkAreaForSource } from "../recording/ffmpeg"; +import { getScreenSourceIdForDisplay } from "./sourceMapping"; import { getNativeMacWindowSources, resolveMacWindowBounds, @@ -125,7 +126,12 @@ export function registerSourceHandlers({ : `Screen ${index + 1}`; return { - id: matchedSource?.id ?? `screen:fallback:${displayId}`, + id: getScreenSourceIdForDisplay({ + displayId, + env: process.env, + matchedSourceId: matchedSource?.id, + platform: process.platform, + }), name: displayName, originalName: matchedSource?.name ?? displayName, display_id: displayId,