From 8165fd057136572a8de2fcf7c6bf676caba2310a Mon Sep 17 00:00:00 2001 From: George Xu Date: Thu, 30 Apr 2026 22:37:02 -0700 Subject: [PATCH] docs: fix setDisplayMediaRequestHandler migration examples Address review feedback on the desktopCapturer deprecation docs: - Fix broken anchor link in the deprecation banner (was pointing at #sessetdisplaymediarequesthandleropts, now correctly points at #sessetdisplaymediarequesthandlerhandler-opts). - Rewrite the "After (recommended)" migration example to gate useSystemPicker on desktopCapturer.isDisplayMediaSystemPickerAvailable() so the snippet works on Windows, Linux, and macOS < 15 (the previous version called callback({}) unconditionally and rejected getDisplayMedia on every non-macOS-15 platform). - Document desktopCapturer.isDisplayMediaSystemPickerAvailable(), which has been a runtime export since #43581 but was never added to the reference docs. - Update the top-level quickstart comment and prose to match what the example actually does (tab self-capture, not "first screen found"). - Mirror the platform-aware pattern in session.md. - Fill in the real PR URL (#51235) in the getSources deprecated YAML block, drop the unused navigator.mediaDevices.getUserMedia link definition, and normalize migration-guide list markers to asterisks so lint:docs passes after the anchor fix exposes the pre-existing lint failures. Notes: none --- docs/api/desktop-capturer.md | 55 +++++++++++++++++++++--------------- docs/api/session.md | 10 +++---- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index afa0a3cf7f..e5a847723f 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -7,13 +7,13 @@ Process: [Main](../glossary.md#main-process) > [!WARNING] > The `desktopCapturer` module is deprecated. Use -> [`session.setDisplayMediaRequestHandler`](session.md#sessetdisplaymediarequesthandleropts) +> [`session.setDisplayMediaRequestHandler`](session.md#sessetdisplaymediarequesthandlerhandler-opts) > instead, which aligns with the web-standard > [`navigator.mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) > API. See the [migration guide](#migrating-from-getsources-to-setdisplaymediarequesthandler) below. -The following example shows how to capture video from a desktop window whose -title is `Electron`: +The following example shows how to respond to a `getDisplayMedia` request by +letting the requesting tab capture itself: ```js // main.js @@ -23,7 +23,7 @@ app.whenReady().then(() => { const mainWindow = new BrowserWindow() session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { - // Grant access to the first screen found. + // Allow the requesting tab to capture itself. callback({ video: request.frame }) }) @@ -90,7 +90,7 @@ changes: description: "This method now returns a Promise instead of using a callback function." breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis deprecated: - - pr-url: https://github.com/electron/electron/pull/XXXXX + - pr-url: https://github.com/electron/electron/pull/51235 ``` --> @@ -114,8 +114,20 @@ Returns `Promise` - Resolves with an array of [`Desktop > * Capturing audio requires `NSAudioCaptureUsageDescription` Info.plist key on macOS 14.2 Sonoma and higher - [read more](#macos-versions-142-or-higher). > * Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher, which can detected by [`systemPreferences.getMediaAccessStatus`][]. +### `desktopCapturer.isDisplayMediaSystemPickerAvailable()` _macOS_ _Experimental_ + + + +Returns `boolean` - Whether the native macOS [`SCContentSharingPicker`](https://developer.apple.com/documentation/screencapturekit/sccontentsharingpicker) is available. Returns `true` on macOS 15 and later, `false` on earlier macOS versions and all non-macOS platforms. + +Use this to decide whether to pass `useSystemPicker: true` to [`session.setDisplayMediaRequestHandler`](session.md#sessetdisplaymediarequesthandlerhandler-opts) — see the [migration guide](#migrating-from-getsources-to-setdisplaymediarequesthandler) below for an example. + [`navigator.mediaDevices.getDisplayMedia`]: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia -[`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia [`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-windows-macos ## Caveats @@ -173,12 +185,12 @@ which aligns with the web-standard [`navigator.mediaDevices.getDisplayMedia`][] ### Why migrate? -- **Web standards alignment** — `getDisplayMedia()` is the web-standard API for screen +* **Web standards alignment** — `getDisplayMedia()` is the web-standard API for screen capture. Using `setDisplayMediaRequestHandler` lets you integrate with it directly. -- **Platform integration** — On macOS 15+, setting `useSystemPicker: true` invokes the +* **Platform integration** — On macOS 15+, setting `useSystemPicker: true` invokes the native OS screen picker (SCContentSharingPicker), providing a familiar UX and correct permissions handling. -- **Simpler architecture** — The handler receives the request when the renderer calls +* **Simpler architecture** — The handler receives the request when the renderer calls `getDisplayMedia()` and you respond with the chosen source. No need to pre-enumerate sources. @@ -202,29 +214,28 @@ app.whenReady().then(() => { ### After (recommended) -For most apps, using the system picker is the simplest approach: +On macOS 15+, the native OS picker (SCContentSharingPicker) is available. On +other platforms you must provide your own picker UI. A cross-platform handler +typically branches on `desktopCapturer.isDisplayMediaSystemPickerAvailable()`: ```js -const { app, BrowserWindow, session } = require('electron') +const { app, BrowserWindow, desktopCapturer, session } = require('electron') app.whenReady().then(() => { const mainWindow = new BrowserWindow() - // The OS presents its own picker; the handler is not invoked. session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { + // On macOS 15+, useSystemPicker: true causes the OS to present its own + // picker and the handler is not invoked. This branch runs everywhere else + // (Windows, Linux, and macOS < 15) — show your own picker UI here and + // call callback with the selected source, e.g. via desktopCapturer.getSources(). callback({}) - }, { useSystemPicker: true }) + }, { useSystemPicker: desktopCapturer.isDisplayMediaSystemPickerAvailable() }) mainWindow.loadFile('index.html') }) ``` -If you need a custom picker UI, handle the request directly: - -```js -session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { - // request.preferredDisplaySurface is 'monitor', 'window', 'browser', or 'none' - // Show your custom picker UI, then call callback with the selected source. - // For tab capture, pass a WebFrameMain: - callback({ video: request.frame }) -}) +`request.preferredDisplaySurface` (`'monitor'`, `'window'`, `'browser'`, or +`'none'`) indicates what kind of surface the caller asked for, and can be used +to drive the filtering in your custom picker UI. diff --git a/docs/api/session.md b/docs/api/session.md index 3e61cd2c7b..191cc90883 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -1063,14 +1063,14 @@ This option is experimental, and currently available for MacOS 15+ only. If the is set to `true`, the handler will not be invoked. ```js -const { session } = require('electron') +const { desktopCapturer, session } = require('electron') session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { - // Allow the tab to capture itself. + // Runs on Windows, Linux, and macOS < 15. On macOS 15+ (where + // useSystemPicker is effective) the OS presents its own picker and this + // handler is not invoked. callback({ video: request.frame }) - // On macOS 15+, use the native system picker if available. - // When the system picker is used, the handler will not be invoked. -}, { useSystemPicker: true }) +}, { useSystemPicker: desktopCapturer.isDisplayMediaSystemPickerAvailable() }) ``` Passing a [WebFrameMain](web-frame-main.md) object as a video or audio stream