diff --git a/electron/main.ts b/electron/main.ts
index f00f264d..636c29ff 100644
--- a/electron/main.ts
+++ b/electron/main.ts
@@ -900,8 +900,13 @@ 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 isLinuxPortalSentinel =
- process.platform === "linux" && sourceId === "screen:linux-portal";
+ process.platform === "linux" &&
+ (sourceId === "screen:linux-portal" || !sourceId);
if (isLinuxPortalSentinel) {
callback({ video: { id: "screen:0:0", name: "Entire screen" } });
return;
diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx
index 9bbcd2f0..2c4e6146 100644
--- a/src/components/launch/LaunchWindow.tsx
+++ b/src/components/launch/LaunchWindow.tsx
@@ -1093,23 +1093,27 @@ export function LaunchWindow() {
const idleControls = (
<>
-
+ {platform !== "linux" && (
+ <>
+
-
+
+ >
+ )}
+ mediaDevices.getDisplayMedia({
+ audio: withAudio,
+ video: {
+ displaySurface: "monitor",
+ width: { ideal: TARGET_WIDTH, max: TARGET_WIDTH },
+ height: { ideal: TARGET_HEIGHT, max: TARGET_HEIGHT },
+ frameRate: { ideal: TARGET_FRAME_RATE, max: TARGET_FRAME_RATE },
+ cursor: "never",
+ },
+ selfBrowserSurface: "exclude",
+ surfaceSwitching: "exclude",
+ });
if (systemAudioEnabled) {
try {
screenMediaStream = useLinuxPortal
- ? await mediaDevices.getDisplayMedia({
- audio: true,
- video: {
- displaySurface: "monitor",
- width: { ideal: TARGET_WIDTH, max: TARGET_WIDTH },
- height: { ideal: TARGET_HEIGHT, max: TARGET_HEIGHT },
- frameRate: { ideal: TARGET_FRAME_RATE, max: TARGET_FRAME_RATE },
- cursor: "never",
- },
- selfBrowserSurface: "exclude",
- surfaceSwitching: "exclude",
- })
+ ? await acquireLinuxPortalStream(true)
: await mediaDevices.getUserMedia({
audio: {
mandatory: {
@@ -1065,18 +1077,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
"System audio is not available for this source. Recording will continue without system audio.",
);
screenMediaStream = useLinuxPortal
- ? await mediaDevices.getDisplayMedia({
- audio: false,
- video: {
- displaySurface: "monitor",
- width: { ideal: TARGET_WIDTH, max: TARGET_WIDTH },
- height: { ideal: TARGET_HEIGHT, max: TARGET_HEIGHT },
- frameRate: { ideal: TARGET_FRAME_RATE, max: TARGET_FRAME_RATE },
- cursor: "never",
- },
- selfBrowserSurface: "exclude",
- surfaceSwitching: "exclude",
- })
+ ? await acquireLinuxPortalStream(false)
: await mediaDevices.getUserMedia({
audio: false,
video: browserScreenVideoConstraints,
@@ -1084,18 +1085,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
}
} else {
screenMediaStream = useLinuxPortal
- ? await mediaDevices.getDisplayMedia({
- audio: false,
- video: {
- displaySurface: "monitor",
- width: { ideal: TARGET_WIDTH, max: TARGET_WIDTH },
- height: { ideal: TARGET_HEIGHT, max: TARGET_HEIGHT },
- frameRate: { ideal: TARGET_FRAME_RATE, max: TARGET_FRAME_RATE },
- cursor: "never",
- },
- selfBrowserSurface: "exclude",
- surfaceSwitching: "exclude",
- })
+ ? await acquireLinuxPortalStream(false)
: await mediaDevices.getUserMedia({
audio: false,
video: browserScreenVideoConstraints,