1
- import { desktopCapturer , ipcMain , session } from 'electron' ;
1
+ import {
2
+ BaseWindow ,
3
+ BrowserWindow ,
4
+ desktopCapturer ,
5
+ ipcMain ,
6
+ session ,
7
+ } from 'electron' ;
2
8
import { NOTIFICATION_WINDOW_TITLE } from '../common/api-interface' ;
3
9
import { isDevEnv , isMac } from '../common/env' ;
4
10
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 ;
10
16
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
+ } ) ;
29
35
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
+ ) ;
33
39
34
- const browserWindowOptions : ICustomBrowserWindowConstructorOpts =
35
- windowHandler . getWindowOpts (
40
+ const browserWindowOptions = windowHandler . getWindowOpts (
36
41
{
37
42
alwaysOnTop : true ,
38
43
autoHideMenuBar : true ,
@@ -42,63 +47,79 @@ export const setDisplayMediaRequestHandler = () => {
42
47
width : 580 ,
43
48
show : false ,
44
49
fullscreenable : false ,
50
+ parent : windowHandler . getMainWindow ( ) as BaseWindow ,
45
51
} ,
46
- {
47
- devTools : isDevEnv ,
48
- } ,
52
+ { devTools : isDevEnv } ,
49
53
) ;
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 ( ) ;
61
63
} ) ;
62
- } ) ;
63
64
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 ) ;
69
84
70
- ipcMain . on (
71
- 'screen-source-select' ,
72
- ( _event , source : Electron . DesktopCapturerSource ) => {
85
+ ipcMain . on ( 'screen-source-select' , ( _event , source ) => {
73
86
if ( source ) {
74
87
windowHandler . drawScreenShareIndicatorFrame ( source ) ;
75
88
}
76
89
logger . info ( 'display-media-request-handler: source selected' , source ) ;
77
- } ,
78
- ) ;
90
+ } ) ;
79
91
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 ( ) ;
84
94
logger . info (
85
95
'display-media-request-handler: source to be shared' ,
86
96
source ,
87
97
) ;
88
98
if ( ! source ) {
89
99
windowHandler . closeScreenSharingIndicator ( ) ;
90
- /**
91
- * Passing the empty stream crashes the main process,
92
- * but passing an empty callback throws an AbortError.
93
- */
94
100
// @ts -ignore
95
101
callback ( ) ;
96
102
} else {
97
103
callback ( { video : source } ) ;
98
104
}
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 } ;
0 commit comments