Skip to content

Commit

Permalink
feat(alwaysontop): Add visibility monitoring for meeting frame
Browse files Browse the repository at this point in the history
  • Loading branch information
Gabriel-Tiberiu Imre-Lucaci authored and hristoterezov committed Feb 8, 2019
1 parent 1972c3b commit 6c6de83
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 10 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,5 @@ typings/
# dotenv environment variables file
.env

build/
.jshint*
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,17 @@ const {
} = require("jitsi-meet-electron-utils");

const api = new JitsiMeetExternalAPI(...);
setupAlwaysOnTopRender(api);
const alwaysOnTop = setupAlwaysOnTopRender(api);

alwaysOnTop.on('will-close', handleAlwaysOnTopClose);
```

`setupAlwaysOnTopRender` return an instance of EventEmitter with the following events:

* _will-close_ - emitted right before the always on top window is going to close

#### WiFi Stats
Provides a function to query for wifi stats on the host computer. Returns information like interface name, addresses, signal quality, noise (not available on all OS).
Provides a function to query for wifi stats on the host computer. Returns information like interface name, addresses, signal quality, noise (not available on all OS).

**WiFi Stats:**

Expand Down
3 changes: 3 additions & 0 deletions alwaysontop/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
ALWAYSONTOP_WILL_CLOSE: 'will-close'
};
57 changes: 49 additions & 8 deletions alwaysontop/render.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
/* global __dirname */
const { ipcRenderer, remote } = require('electron');

const { EventEmitter } = require('events');
const os = require('os');
const path = require('path');
const url = require('url');

const { ALWAYSONTOP_WILL_CLOSE } = require('./constants');

/**
* URL for index.html which will be our entry point.
*/
Expand Down Expand Up @@ -43,22 +46,25 @@ function getNumberFromLocalStorage(localStorageKey) {
/**
* Implements the always on top functionality for the render process.
*/
class AlwaysOnTop {
class AlwaysOnTop extends EventEmitter {
/**
* Creates new instance.
*
* @param {JitsiIFrameApi} api - the Jitsi Meet iframe api object.
*/
constructor(api) {
super();
this._updateLargeVideoSrc = this._updateLargeVideoSrc.bind(this);
this._openAlwaysOnTopWindow = this._openAlwaysOnTopWindow.bind(this);
this._closeAlwaysOnTopWindow = this._closeAlwaysOnTopWindow.bind(this);
this._onMessageReceived = this._onMessageReceived.bind(this);
this._onConferenceJoined = this._onConferenceJoined.bind(this);
this._onConferenceLeft = this._onConferenceLeft.bind(this);
this._onIntersection = this._onIntersection.bind(this);

this._api = api;
this._jitsiMeetElectronWindow = remote.getCurrentWindow();
this._intersectionObserver = new IntersectionObserver(this._onIntersection);

if (!api) {
throw new Error('Wrong arguments!');
Expand Down Expand Up @@ -158,6 +164,7 @@ class AlwaysOnTop {
this._jitsiMeetElectronWindow.on('blur', this._openAlwaysOnTopWindow);
this._jitsiMeetElectronWindow.on('focus', this._closeAlwaysOnTopWindow);
this._jitsiMeetElectronWindow.on('close', this._closeAlwaysOnTopWindow);
this._intersectionObserver.observe(this._api.getIFrame());
}

/**
Expand All @@ -166,6 +173,7 @@ class AlwaysOnTop {
* @returns {void}
*/
_onConferenceLeft() {
this._intersectionObserver.unobserve(this._api.getIFrame());
this._jitsiMeetElectronWindow.removeListener(
'blur',
this._openAlwaysOnTopWindow
Expand All @@ -181,6 +189,30 @@ class AlwaysOnTop {
this._closeAlwaysOnTopWindow();
}

/**
* Handles intersection events for the instance's IntersectionObserver
*
* @param {IntersectionObserverEntry[]} entries
* @param {IntersectionObserver} observer
*/
_onIntersection(entries) {
const singleEntry = entries.pop();
this._jitsiMeetElectronWindow.removeListener(
'focus',
this._closeAlwaysOnTopWindow
);

if (singleEntry.isIntersecting) {
this._closeAlwaysOnTopWindow();
this._jitsiMeetElectronWindow.on(
'focus',
this._closeAlwaysOnTopWindow
);
} else {
this._openAlwaysOnTopWindow();
}
}

/**
* Handles IPC messages from the main process.
*
Expand Down Expand Up @@ -214,6 +246,7 @@ class AlwaysOnTop {
api: this._api,
onload: this._updateLargeVideoSrc,
onbeforeunload: () => {
this.emit(ALWAYSONTOP_WILL_CLOSE);
this._api.removeListener(
'largeVideoChanged',
this._updateLargeVideoSrc
Expand Down Expand Up @@ -243,21 +276,29 @@ class AlwaysOnTop {
* @returns {void}
*/
_closeAlwaysOnTopWindow() {
if (this._alwaysOnTopBrowserWindow) {
const position
= this._alwaysOnTopBrowserWindow.getPosition();
this._alwaysOnTopBrowserWindow = undefined;
if (this._alwaysOnTopBrowserWindow && !this._alwaysOnTopBrowserWindow.isDestroyed()) {
const position =
this._alwaysOnTopBrowserWindow.getPosition();

this._position = {
x: position[0],
y: position[1]
};
}

if(this._alwaysOnTopWindow) {
this._alwaysOnTopWindow.close();
this._alwaysOnTopWindow = undefined;
// we need to check the BrowserWindow reference here because
// window.closed is not reliable due to Electron quirkiness
if(this._alwaysOnTopBrowserWindow &&!this._alwaysOnTopBrowserWindow.isDestroyed()) {
this._alwaysOnTopWindow.close();
}

ipcRenderer.removeListener('jitsi-always-on-top',
this._onMessageReceived);
}

this._alwaysOnTopBrowserWindow = undefined;
this._alwaysOnTopWindow = undefined;
}

/**
Expand Down Expand Up @@ -292,5 +333,5 @@ class AlwaysOnTop {
* @param {JitsiIFrameApi} api - the Jitsi Meet iframe api object.
*/
module.exports = function setupAlwaysOnTopRender(api) {
new AlwaysOnTop(api);
return new AlwaysOnTop(api);
};

0 comments on commit 6c6de83

Please sign in to comment.