Skip to content

Commit dfdc370

Browse files
authored
SDA-4850 Screen share indicator listener unsubscription (#2335)
* SDA-4850 Screen share indicator listener unsubscription, close screen picker when the meeting ends and keep it in the foregro SDA-4850 Close screen picker when the meeting ends and keep it in the foreground * SDA-4850 Remove all listeners related to screen source selection
1 parent a48996b commit dfdc370

File tree

3 files changed

+96
-73
lines changed

3 files changed

+96
-73
lines changed
+89-68
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,43 @@
1-
import { desktopCapturer, ipcMain, session } from 'electron';
1+
import {
2+
BaseWindow,
3+
BrowserWindow,
4+
desktopCapturer,
5+
ipcMain,
6+
session,
7+
} from 'electron';
28
import { NOTIFICATION_WINDOW_TITLE } from '../common/api-interface';
39
import { isDevEnv, isMac } from '../common/env';
410
import { logger } from '../common/logger';
5-
import {
6-
ICustomBrowserWindowConstructorOpts,
7-
windowHandler,
8-
} from './window-handler';
9-
import { createComponentWindow, windowExists } from './window-utils';
11+
import { windowHandler } from './window-handler';
12+
import { createComponentWindow } from './window-utils';
13+
14+
class DisplayMediaRequestHandler {
15+
private screenPickerWindow: BrowserWindow | null = null;
1016

11-
/**
12-
* For MacOS 15+ the { useSystemPicker: true } overrides the code set in the handler,
13-
* and uses the native implementation.
14-
*
15-
* But for other versions and OSes, the code is executed.
16-
*/
17-
export const setDisplayMediaRequestHandler = () => {
18-
const { defaultSession } = session;
19-
defaultSession.setDisplayMediaRequestHandler(
20-
async (_request, callback) => {
21-
logger.info('display-media-request-handler: getting sources');
22-
const sources = await desktopCapturer.getSources({
23-
types: ['screen', 'window'],
24-
thumbnailSize: {
25-
height: 150,
26-
width: 150,
27-
},
28-
});
17+
/**
18+
* Display media request handler initialization
19+
*/
20+
public init() {
21+
const { defaultSession } = session;
22+
/**
23+
* For MacOS 15+ the { useSystemPicker: true } overrides the code set in the handler,
24+
* and uses the native implementation.
25+
*
26+
* But for other versions and OSes, the code is executed.
27+
*/
28+
defaultSession.setDisplayMediaRequestHandler(
29+
async (_request, callback) => {
30+
logger.info('display-media-request-handler: getting sources');
31+
const sources = await desktopCapturer.getSources({
32+
types: ['screen', 'window'],
33+
thumbnailSize: { height: 150, width: 150 },
34+
});
2935

30-
const updatedSources = sources.filter(
31-
(source) => source.name !== NOTIFICATION_WINDOW_TITLE,
32-
);
36+
const updatedSources = sources.filter(
37+
(source) => source.name !== NOTIFICATION_WINDOW_TITLE,
38+
);
3339

34-
const browserWindowOptions: ICustomBrowserWindowConstructorOpts =
35-
windowHandler.getWindowOpts(
40+
const browserWindowOptions = windowHandler.getWindowOpts(
3641
{
3742
alwaysOnTop: true,
3843
autoHideMenuBar: true,
@@ -42,63 +47,79 @@ export const setDisplayMediaRequestHandler = () => {
4247
width: 580,
4348
show: false,
4449
fullscreenable: false,
50+
parent: windowHandler.getMainWindow() as BaseWindow,
4551
},
46-
{
47-
devTools: isDevEnv,
48-
},
52+
{ devTools: isDevEnv },
4953
);
50-
const screenPickerWindow = createComponentWindow(
51-
'screen-picker',
52-
browserWindowOptions,
53-
);
54-
windowHandler.moveWindow(screenPickerWindow);
55-
screenPickerWindow.webContents.once('did-finish-load', () => {
56-
if (!screenPickerWindow || !windowExists(screenPickerWindow)) {
57-
return;
58-
}
59-
screenPickerWindow.webContents.send('screen-picker-data', {
60-
sources: updatedSources,
54+
55+
this.screenPickerWindow = createComponentWindow(
56+
'screen-picker',
57+
browserWindowOptions,
58+
);
59+
60+
this.screenPickerWindow.on('blur', () => {
61+
this.screenPickerWindow?.setAlwaysOnTop(true);
62+
this.screenPickerWindow?.focus();
6163
});
62-
});
6364

64-
const mainWebContents = windowHandler.getMainWebContents();
65-
if (!mainWebContents) {
66-
return;
67-
}
68-
mainWebContents.send('screen-picker-data', updatedSources);
65+
this.screenPickerWindow.on('closed', () => {
66+
this.screenPickerWindow = null;
67+
ipcMain.removeAllListeners('screen-source-select');
68+
});
69+
70+
this.screenPickerWindow.webContents.once('did-finish-load', () => {
71+
if (!this.screenPickerWindow) {
72+
return;
73+
}
74+
this.screenPickerWindow.webContents.send('screen-picker-data', {
75+
sources: updatedSources,
76+
});
77+
});
78+
79+
const mainWebContents = windowHandler.getMainWebContents();
80+
if (!mainWebContents) {
81+
return;
82+
}
83+
mainWebContents.send('screen-picker-data', updatedSources);
6984

70-
ipcMain.on(
71-
'screen-source-select',
72-
(_event, source: Electron.DesktopCapturerSource) => {
85+
ipcMain.on('screen-source-select', (_event, source) => {
7386
if (source) {
7487
windowHandler.drawScreenShareIndicatorFrame(source);
7588
}
7689
logger.info('display-media-request-handler: source selected', source);
77-
},
78-
);
90+
});
7991

80-
ipcMain.once(
81-
'screen-source-selected',
82-
(_event, source: Electron.DesktopCapturerSource) => {
83-
screenPickerWindow.close();
92+
ipcMain.once('screen-source-selected', (_event, source) => {
93+
this.screenPickerWindow?.close();
8494
logger.info(
8595
'display-media-request-handler: source to be shared',
8696
source,
8797
);
8898
if (!source) {
8999
windowHandler.closeScreenSharingIndicator();
90-
/**
91-
* Passing the empty stream crashes the main process,
92-
* but passing an empty callback throws an AbortError.
93-
*/
94100
// @ts-ignore
95101
callback();
96102
} else {
97103
callback({ video: source });
98104
}
99-
},
100-
);
101-
},
102-
{ useSystemPicker: true },
103-
);
104-
};
105+
});
106+
},
107+
{ useSystemPicker: true },
108+
);
109+
}
110+
111+
/**
112+
* Closes screen picker if still open
113+
*/
114+
public closeScreenPickerWindow() {
115+
logger.info(
116+
'display-media-request-handler: close screen picker if it exists',
117+
);
118+
this.screenPickerWindow?.close();
119+
this.screenPickerWindow = null;
120+
}
121+
}
122+
123+
const displayMediaRequestHandler = new DisplayMediaRequestHandler();
124+
125+
export { displayMediaRequestHandler };

src/app/main-api-handler.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import callNotificationHelper from '../renderer/call-notification-helper';
6464
import { autoUpdate, AutoUpdateTrigger } from './auto-update-handler';
6565
import { SDAUserSessionActionTypes } from './bi/interface';
6666
import { miniViewHandler } from './mini-view-handler';
67+
import { displayMediaRequestHandler } from './display-media-request-handler';
6768
import { openfinHandler } from './openfin-handler';
6869
import { presenceStatus } from './presence-status-handler';
6970
import { appStats } from './stats';
@@ -307,6 +308,7 @@ ipcMain.on(
307308
memoryMonitor.setMeetingStatus(arg.isInMeeting);
308309
appStateHandler.preventDisplaySleep(arg.isInMeeting);
309310
if (!arg.isInMeeting) {
311+
displayMediaRequestHandler.closeScreenPickerWindow();
310312
windowHandler.closeScreenPickerWindow();
311313
windowHandler.closeScreenSharingIndicator();
312314
}
@@ -397,7 +399,7 @@ ipcMain.on(
397399
(win) =>
398400
(win as ICustomBrowserWindow).winName &&
399401
(win as ICustomBrowserWindow).winName ===
400-
apiName.notificationWindowName,
402+
apiName.notificationWindowName,
401403
);
402404
notificationWindows.map((notificationWindow) => {
403405
const notificationWebContents = notificationWindow?.webContents;
@@ -466,8 +468,8 @@ ipcMain.on(
466468
const podUrl = urlFromCmd
467469
? urlFromCmd.substr(6)
468470
: userConfigURL
469-
? userConfigURL
470-
: globalConfigURL;
471+
? userConfigURL
472+
: globalConfigURL;
471473
const { subdomain, domain, tld } = whitelistHandler.parseDomain(podUrl);
472474
const localConfig = config.getConfigFields([
473475
'enableBrowserLogin',

src/app/main.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { cleanUpAppCache, createAppCacheFile } from './app-cache-handler';
88
import { setChromeFlags, setSessionProperties } from './chrome-flags';
99
import { config } from './config-handler';
1010
import './dialog-handler';
11-
import { setDisplayMediaRequestHandler } from './display-media-request-handler';
11+
import { displayMediaRequestHandler } from './display-media-request-handler';
1212
import './main-api-handler';
1313
import { handlePerformanceSettings } from './perf-handler';
1414
import { protocolHandler } from './protocol-handler';
@@ -109,7 +109,7 @@ const startApplication = async () => {
109109
// Picks global config values and updates them in the user config
110110
await config.updateUserConfigOnStart();
111111
setSessionProperties();
112-
setDisplayMediaRequestHandler();
112+
displayMediaRequestHandler.init();
113113
await autoUpdate.init();
114114
await windowHandler.createApplication();
115115
logger.info(`main: created application`);

0 commit comments

Comments
 (0)