diff --git a/src/displayMediaCallback.ts b/src/displayMediaCallback.ts new file mode 100644 index 000000000..be96340ce --- /dev/null +++ b/src/displayMediaCallback.ts @@ -0,0 +1,29 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Streams } from "electron"; + +type DisplayMediaCallback = (streams: Streams) => void; + +let displayMediaCallback: DisplayMediaCallback | null; + +export const getDisplayMediaCallback = (): DisplayMediaCallback | null => { + return displayMediaCallback; +}; + +export const setDisplayMediaCallback = (callback: DisplayMediaCallback | null): void => { + displayMediaCallback = callback; +}; diff --git a/src/electron-main.ts b/src/electron-main.ts index e7259c3e3..4b7a592ff 100644 --- a/src/electron-main.ts +++ b/src/electron-main.ts @@ -19,7 +19,7 @@ limitations under the License. // Squirrel on windows starts the app with various flags as hooks to tell us when we've been installed/uninstalled etc. import "./squirrelhooks"; -import { app, BrowserWindow, Menu, autoUpdater, protocol, dialog, Input, Event } from "electron"; +import { app, BrowserWindow, Menu, autoUpdater, protocol, dialog, Input, Event, session } from "electron"; import * as Sentry from "@sentry/electron/main"; import AutoLaunch from "auto-launch"; import path from "path"; @@ -39,6 +39,7 @@ import webContentsHandler from "./webcontents-handler"; import * as updater from "./updater"; import { getProfileFromDeeplink, protocolInit } from "./protocol"; import { _t, AppLocalization } from "./language-helper"; +import { setDisplayMediaCallback } from "./displayMediaCallback"; const argv = minimist(process.argv, { alias: { help: "h" }, @@ -532,6 +533,11 @@ app.on("ready", async () => { store: global.store, components: [(): void => tray.initApplicationMenu(), (): void => Menu.setApplicationMenu(buildMenuTemplate())], }); + + session.defaultSession.setDisplayMediaRequestHandler((_, callback) => { + global.mainWindow?.webContents.send("openDesktopCapturerSourcePicker"); + setDisplayMediaCallback(callback); + }); }); app.on("window-all-closed", () => { diff --git a/src/ipc.ts b/src/ipc.ts index 3845827f2..b84fb9514 100644 --- a/src/ipc.ts +++ b/src/ipc.ts @@ -22,6 +22,7 @@ import { recordSSOSession } from "./protocol"; import { randomArray } from "./utils"; import { Settings } from "./settings"; import { keytar } from "./keytar"; +import { getDisplayMediaCallback, setDisplayMediaCallback } from "./displayMediaCallback"; ipcMain.on("setBadgeCount", function (_ev: IpcMainEvent, count: number): void { if (process.platform !== "win32") { @@ -186,6 +187,11 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) { thumbnailURL: source.thumbnail.toDataURL(), })); break; + case "callDisplayMediaCallback": + await getDisplayMediaCallback()?.({ video: args[0] }); + setDisplayMediaCallback(null); + ret = null; + break; case "clearStorage": global.store.clear(); diff --git a/src/preload.ts b/src/preload.ts index a761fba6f..4f9384ebb 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -34,6 +34,7 @@ const CHANNELS = [ "update-downloaded", "userDownloadCompleted", "userDownloadAction", + "openDesktopCapturerSourcePicker", ]; contextBridge.exposeInMainWorld("electron", {