11/* global __dirname */
22const { ipcRenderer, remote } = require ( 'electron' ) ;
33
4+ const { EventEmitter } = require ( 'events' ) ;
45const os = require ( 'os' ) ;
56const path = require ( 'path' ) ;
67const url = require ( 'url' ) ;
78
9+ const { ALWAYSONTOP_WILL_CLOSE } = require ( './constants' ) ;
10+
811/**
912 * URL for index.html which will be our entry point.
1013 */
@@ -43,22 +46,25 @@ function getNumberFromLocalStorage(localStorageKey) {
4346/**
4447 * Implements the always on top functionality for the render process.
4548 */
46- class AlwaysOnTop {
49+ class AlwaysOnTop extends EventEmitter {
4750 /**
4851 * Creates new instance.
4952 *
5053 * @param {JitsiIFrameApi } api - the Jitsi Meet iframe api object.
5154 */
5255 constructor ( api ) {
56+ super ( ) ;
5357 this . _updateLargeVideoSrc = this . _updateLargeVideoSrc . bind ( this ) ;
5458 this . _openAlwaysOnTopWindow = this . _openAlwaysOnTopWindow . bind ( this ) ;
5559 this . _closeAlwaysOnTopWindow = this . _closeAlwaysOnTopWindow . bind ( this ) ;
5660 this . _onMessageReceived = this . _onMessageReceived . bind ( this ) ;
5761 this . _onConferenceJoined = this . _onConferenceJoined . bind ( this ) ;
5862 this . _onConferenceLeft = this . _onConferenceLeft . bind ( this ) ;
63+ this . _onIntersection = this . _onIntersection . bind ( this ) ;
5964
6065 this . _api = api ;
6166 this . _jitsiMeetElectronWindow = remote . getCurrentWindow ( ) ;
67+ this . _intersectionObserver = new IntersectionObserver ( this . _onIntersection ) ;
6268
6369 if ( ! api ) {
6470 throw new Error ( 'Wrong arguments!' ) ;
@@ -158,6 +164,7 @@ class AlwaysOnTop {
158164 this . _jitsiMeetElectronWindow . on ( 'blur' , this . _openAlwaysOnTopWindow ) ;
159165 this . _jitsiMeetElectronWindow . on ( 'focus' , this . _closeAlwaysOnTopWindow ) ;
160166 this . _jitsiMeetElectronWindow . on ( 'close' , this . _closeAlwaysOnTopWindow ) ;
167+ this . _intersectionObserver . observe ( this . _api . getIFrame ( ) ) ;
161168 }
162169
163170 /**
@@ -166,6 +173,7 @@ class AlwaysOnTop {
166173 * @returns {void }
167174 */
168175 _onConferenceLeft ( ) {
176+ this . _intersectionObserver . unobserve ( this . _api . getIFrame ( ) ) ;
169177 this . _jitsiMeetElectronWindow . removeListener (
170178 'blur' ,
171179 this . _openAlwaysOnTopWindow
@@ -181,6 +189,30 @@ class AlwaysOnTop {
181189 this . _closeAlwaysOnTopWindow ( ) ;
182190 }
183191
192+ /**
193+ * Handles intersection events for the instance's IntersectionObserver
194+ *
195+ * @param {IntersectionObserverEntry[] } entries
196+ * @param {IntersectionObserver } observer
197+ */
198+ _onIntersection ( entries ) {
199+ const singleEntry = entries . pop ( ) ;
200+ this . _jitsiMeetElectronWindow . removeListener (
201+ 'focus' ,
202+ this . _closeAlwaysOnTopWindow
203+ ) ;
204+
205+ if ( singleEntry . isIntersecting ) {
206+ this . _closeAlwaysOnTopWindow ( ) ;
207+ this . _jitsiMeetElectronWindow . on (
208+ 'focus' ,
209+ this . _closeAlwaysOnTopWindow
210+ ) ;
211+ } else {
212+ this . _openAlwaysOnTopWindow ( ) ;
213+ }
214+ }
215+
184216 /**
185217 * Handles IPC messages from the main process.
186218 *
@@ -214,6 +246,7 @@ class AlwaysOnTop {
214246 api : this . _api ,
215247 onload : this . _updateLargeVideoSrc ,
216248 onbeforeunload : ( ) => {
249+ this . emit ( ALWAYSONTOP_WILL_CLOSE ) ;
217250 this . _api . removeListener (
218251 'largeVideoChanged' ,
219252 this . _updateLargeVideoSrc
@@ -243,21 +276,29 @@ class AlwaysOnTop {
243276 * @returns {void }
244277 */
245278 _closeAlwaysOnTopWindow ( ) {
246- if ( this . _alwaysOnTopBrowserWindow ) {
247- const position
248- = this . _alwaysOnTopBrowserWindow . getPosition ( ) ;
249- this . _alwaysOnTopBrowserWindow = undefined ;
279+ if ( this . _alwaysOnTopBrowserWindow && ! this . _alwaysOnTopBrowserWindow . isDestroyed ( ) ) {
280+ const position =
281+ this . _alwaysOnTopBrowserWindow . getPosition ( ) ;
282+
250283 this . _position = {
251284 x : position [ 0 ] ,
252285 y : position [ 1 ]
253286 } ;
254287 }
288+
255289 if ( this . _alwaysOnTopWindow ) {
256- this . _alwaysOnTopWindow . close ( ) ;
257- this . _alwaysOnTopWindow = undefined ;
290+ // we need to check the BrowserWindow reference here because
291+ // window.closed is not reliable due to Electron quirkiness
292+ if ( this . _alwaysOnTopBrowserWindow && ! this . _alwaysOnTopBrowserWindow . isDestroyed ( ) ) {
293+ this . _alwaysOnTopWindow . close ( ) ;
294+ }
295+
258296 ipcRenderer . removeListener ( 'jitsi-always-on-top' ,
259297 this . _onMessageReceived ) ;
260298 }
299+
300+ this . _alwaysOnTopBrowserWindow = undefined ;
301+ this . _alwaysOnTopWindow = undefined ;
261302 }
262303
263304 /**
@@ -292,5 +333,5 @@ class AlwaysOnTop {
292333* @param {JitsiIFrameApi } api - the Jitsi Meet iframe api object.
293334*/
294335module . exports = function setupAlwaysOnTopRender ( api ) {
295- new AlwaysOnTop ( api ) ;
336+ return new AlwaysOnTop ( api ) ;
296337} ;
0 commit comments