From bbda658b7f7e0dd4b173b2b4ed02484ff9eba170 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 13 May 2017 12:37:13 +0100 Subject: [PATCH 1/8] make Electron tray icon mimic the Favico.js one DRY: moved Favicon stuff into the base platform Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- electron_app/src/tray.js | 16 ++++---- src/vector/platform/VectorBasePlatform.js | 47 ++++++++++++++++++++++- src/vector/platform/WebPlatform.js | 44 --------------------- 3 files changed, 55 insertions(+), 52 deletions(-) diff --git a/electron_app/src/tray.js b/electron_app/src/tray.js index 2ccdf40ccc..ab3a8e1c53 100644 --- a/electron_app/src/tray.js +++ b/electron_app/src/tray.js @@ -15,12 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -const path = require('path'); -const electron = require('electron'); - -const app = electron.app; -const Tray = electron.Tray; -const MenuItem = electron.MenuItem; +const {app, Tray, Menu, nativeImage} = require('electron'); let trayIcon = null; @@ -44,7 +39,7 @@ exports.create = function (win, config) { } }; - const contextMenu = electron.Menu.buildFromTemplate([ + const contextMenu = Menu.buildFromTemplate([ { label: 'Show/Hide ' + config.brand, click: toggleWin @@ -64,4 +59,11 @@ exports.create = function (win, config) { trayIcon.setToolTip(config.brand); trayIcon.setContextMenu(contextMenu); trayIcon.on('click', toggleWin); + + win.webContents.on('page-favicon-updated', function(ev, favicons) { + try { + const img = nativeImage.createFromDataURL(favicons[0]); + trayIcon.setImage(img); + } catch (e) {console.error(e);} + }); }; diff --git a/src/vector/platform/VectorBasePlatform.js b/src/vector/platform/VectorBasePlatform.js index 1466b76ae3..00c9c47c30 100644 --- a/src/vector/platform/VectorBasePlatform.js +++ b/src/vector/platform/VectorBasePlatform.js @@ -17,12 +17,57 @@ See the License for the specific language governing permissions and limitations under the License. */ -import BasePlatform from 'matrix-react-sdk/lib/BasePlatform' +import BasePlatform from 'matrix-react-sdk/lib/BasePlatform'; +import Favico from 'favico.js'; /** * Vector-specific extensions to the BasePlatform template */ export default class VectorBasePlatform extends BasePlatform { + constructor() { + super(); + + // The 'animations' are really low framerate and look terrible. + // Also it re-starts the animationb every time you set the badge, + // and we set the state each time, even if the value hasn't changed, + // so we'd need to fix that if enabling the animation. + this.favicon = new Favico({animation: 'none'}); + this._updateFavicon(); + } + + _updateFavicon() { + try { + // This needs to be in in a try block as it will throw + // if there are more than 100 badge count changes in + // its internal queue + let bgColor = "#d00", + notif = this.notificationCount; + + if (this.errorDidOccur) { + notif = notif || "×"; + bgColor = "#f00"; + } + + this.favicon.badge(notif, { + bgColor: bgColor, + }); + } catch (e) { + console.warn(`Failed to set badge count: ${e.message}`); + } + } + + setNotificationCount(count: number) { + if (this.notificationCount === count) return; + super.setNotificationCount(count); + this._updateFavicon(); + } + + setErrorStatus(errorDidOccur: boolean) { + if (this.errorDidOccur === errorDidOccur) return; + super.setErrorStatus(errorDidOccur); + this._updateFavicon(); + } + /** * Check for the availability of an update to the version of the * app that's currently running. diff --git a/src/vector/platform/WebPlatform.js b/src/vector/platform/WebPlatform.js index 72ca19f06c..204317bab3 100644 --- a/src/vector/platform/WebPlatform.js +++ b/src/vector/platform/WebPlatform.js @@ -18,7 +18,6 @@ limitations under the License. */ import VectorBasePlatform from './VectorBasePlatform'; -import Favico from 'favico.js'; import request from 'browser-request'; import dis from 'matrix-react-sdk/lib/dispatcher.js'; import q from 'q'; @@ -27,49 +26,6 @@ import url from 'url'; import UAParser from 'ua-parser-js'; export default class WebPlatform extends VectorBasePlatform { - constructor() { - super(); - this.runningVersion = null; - // The 'animations' are really low framerate and look terrible. - // Also it re-starts the animationb every time you set the badge, - // and we set the state each time, even if the value hasn't changed, - // so we'd need to fix that if enabling the animation. - this.favicon = new Favico({animation: 'none'}); - this._updateFavicon(); - } - - _updateFavicon() { - try { - // This needs to be in in a try block as it will throw - // if there are more than 100 badge count changes in - // its internal queue - let bgColor = "#d00", - notif = this.notificationCount; - - if (this.errorDidOccur) { - notif = notif || "×"; - bgColor = "#f00"; - } - - this.favicon.badge(notif, { - bgColor: bgColor, - }); - } catch (e) { - console.warn(`Failed to set badge count: ${e.message}`); - } - } - - setNotificationCount(count: number) { - if (this.notificationCount === count) return; - super.setNotificationCount(count); - this._updateFavicon(); - } - - setErrorStatus(errorDidOccur: boolean) { - if (this.errorDidOccur === errorDidOccur) return; - super.setErrorStatus(errorDidOccur); - this._updateFavicon(); - } /** * Returns true if the platform supports displaying From 8927afca036cda1f0cc2b1c0cac23f4510fa351d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 13 May 2017 12:37:27 +0100 Subject: [PATCH 2/8] re-add electron node modules to gitignore Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6dd2b988c3..6072f0ff5b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ /key.pem /lib /node_modules -/electron/node_modules +/electron_app/node_modules /packages/ /webapp /.npmrc From 6aae97b81204e20ef463ecbfa903af7658dbd6de Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 13 May 2017 12:39:55 +0100 Subject: [PATCH 3/8] Update tray tooltip based on document.title Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- electron_app/src/tray.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/electron_app/src/tray.js b/electron_app/src/tray.js index ab3a8e1c53..b0a657a08e 100644 --- a/electron_app/src/tray.js +++ b/electron_app/src/tray.js @@ -66,4 +66,8 @@ exports.create = function (win, config) { trayIcon.setImage(img); } catch (e) {console.error(e);} }); + + win.webContents.on('page-title-updated', function(ev, title) { + trayIcon.setToolTip(title); + }); }; From 808240eef9bfef0a4e685933bd986b8347bead1e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 13 May 2017 12:40:17 +0100 Subject: [PATCH 4/8] shouldn't need this try-catch Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- electron_app/src/tray.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/electron_app/src/tray.js b/electron_app/src/tray.js index b0a657a08e..75104042c1 100644 --- a/electron_app/src/tray.js +++ b/electron_app/src/tray.js @@ -61,10 +61,7 @@ exports.create = function (win, config) { trayIcon.on('click', toggleWin); win.webContents.on('page-favicon-updated', function(ev, favicons) { - try { - const img = nativeImage.createFromDataURL(favicons[0]); - trayIcon.setImage(img); - } catch (e) {console.error(e);} + trayIcon.setImage(nativeImage.createFromDataURL(favicons[0])); }); win.webContents.on('page-title-updated', function(ev, title) { From aa7728cad39f388f607cea1eb810eec5ea33a4f2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 13 May 2017 12:41:13 +0100 Subject: [PATCH 5/8] tidy up tray.js - it made my eyes hurt Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- electron_app/src/tray.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/electron_app/src/tray.js b/electron_app/src/tray.js index 75104042c1..7198356ca6 100644 --- a/electron_app/src/tray.js +++ b/electron_app/src/tray.js @@ -21,15 +21,15 @@ let trayIcon = null; exports.hasTray = function hasTray() { return (trayIcon !== null); -} +}; -exports.create = function (win, config) { +exports.create = function(win, config) { // no trays on darwin if (process.platform === 'darwin' || trayIcon) { return; } - const toggleWin = function () { + const toggleWin = function() { if (win.isVisible() && !win.isMinimized()) { win.hide(); } else { @@ -42,17 +42,17 @@ exports.create = function (win, config) { const contextMenu = Menu.buildFromTemplate([ { label: 'Show/Hide ' + config.brand, - click: toggleWin + click: toggleWin, }, { - type: 'separator' + type: 'separator', }, { label: 'Quit', - click: function () { + click: function() { app.quit(); - } - } + }, + }, ]); trayIcon = new Tray(config.icon_path); From 39b6c7c65d08942e197cf5f7c5f110d8f641b774 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 17 May 2017 09:53:33 +0100 Subject: [PATCH 6/8] ignore electron_app subdirs properly, missed these too :L Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 6072f0ff5b..7f753927ce 100644 --- a/.gitignore +++ b/.gitignore @@ -6,12 +6,11 @@ /lib /node_modules /electron_app/node_modules +/electron_app/dist /packages/ /webapp /.npmrc .DS_Store npm-debug.log -electron/dist -electron/pub /config.json /src/component-index.js From 826a571b602783c33e9177d9026147c27c675e91 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 17 May 2017 10:05:50 +0100 Subject: [PATCH 7/8] apply same image to the window/taskbar too; as per request LETS MAKE IT CLEAR WE ARE NEEDY AND WANT ATTENTION Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- electron_app/src/tray.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/electron_app/src/tray.js b/electron_app/src/tray.js index 7198356ca6..98ffb9f40e 100644 --- a/electron_app/src/tray.js +++ b/electron_app/src/tray.js @@ -61,7 +61,14 @@ exports.create = function(win, config) { trayIcon.on('click', toggleWin); win.webContents.on('page-favicon-updated', function(ev, favicons) { - trayIcon.setImage(nativeImage.createFromDataURL(favicons[0])); + if (favicons && favicons.length > 0 && favicons[0].startsWith('data:')) { + const image = nativeImage.createFromDataURL(favicons[0]); + trayIcon.setImage(image); + win.setIcon(image); + } else { + trayIcon.setImage(config.icon_path); + win.setIcon(config.icon_path); + } }); win.webContents.on('page-title-updated', function(ev, title) { From 9352e5d78ea1b003ec74939d4299106f2fa4103b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 17 May 2017 10:39:43 +0100 Subject: [PATCH 8/8] Lets make it abundantly clear that we want attention. FLASH FLASH FLASH also improve favicon updating to not change if we're same as previous not sure how intensive the nativeImage stuff is but cheap efficiency For FLASH FLASH I moved the setBadgeCount stuff RPC -> IPC should be more reliable now, its in electron-main Win only: if mainWindow is set and is not in focus make it FLASH clear flash if notification gets cleared elsewhere debounce focus handler so we don't set a million of them if the app is backgrounded a while Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- electron_app/src/electron-main.js | 21 ++++++++++++++++++++- electron_app/src/tray.js | 21 +++++++++++++++------ src/vector/platform/ElectronPlatform.js | 14 +++----------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/electron_app/src/electron-main.js b/electron_app/src/electron-main.js index 32e305d8d9..b632708f86 100644 --- a/electron_app/src/electron-main.js +++ b/electron_app/src/electron-main.js @@ -155,12 +155,31 @@ function startAutoUpdate(update_base_url) { // no other way to catch this error). // Assuming we generally run from the console when developing, // this is far preferable. -process.on('uncaughtException', function (error) { +process.on('uncaughtException', function(error) { console.log("Unhandled exception", error); }); electron.ipcMain.on('install_update', installUpdate); +let focusHandlerAttached = false; +electron.ipcMain.on('setBadgeCount', function(ev, count) { + electron.app.setBadgeCount(count); + if (process.platform === 'win32' && mainWindow && !mainWindow.isFocused()) { + if (count > 0) { + if (!focusHandlerAttached) { + mainWindow.once('focus', () => { + mainWindow.flashFrame(false); + focusHandlerAttached = false; + }); + focusHandlerAttached = true; + } + mainWindow.flashFrame(true); + } else { + mainWindow.flashFrame(false); + } + } +}); + electron.app.commandLine.appendSwitch('--enable-usermedia-screen-capturing'); const shouldQuit = electron.app.makeSingleInstance((commandLine, workingDirectory) => { diff --git a/electron_app/src/tray.js b/electron_app/src/tray.js index 98ffb9f40e..5409194d8f 100644 --- a/electron_app/src/tray.js +++ b/electron_app/src/tray.js @@ -60,15 +60,24 @@ exports.create = function(win, config) { trayIcon.setContextMenu(contextMenu); trayIcon.on('click', toggleWin); + let lastFavicon = null; win.webContents.on('page-favicon-updated', function(ev, favicons) { + let newFavicon = config.icon_path; if (favicons && favicons.length > 0 && favicons[0].startsWith('data:')) { - const image = nativeImage.createFromDataURL(favicons[0]); - trayIcon.setImage(image); - win.setIcon(image); - } else { - trayIcon.setImage(config.icon_path); - win.setIcon(config.icon_path); + newFavicon = favicons[0]; } + + // No need to change, shortcut + if (newFavicon === lastFavicon) return; + lastFavicon = newFavicon; + + // if its not default we have to construct into nativeImage + if (newFavicon !== config.icon_path) { + newFavicon = nativeImage.createFromDataURL(favicons[0]); + } + + trayIcon.setImage(newFavicon); + win.setIcon(newFavicon); }); win.webContents.on('page-title-updated', function(ev, title) { diff --git a/src/vector/platform/ElectronPlatform.js b/src/vector/platform/ElectronPlatform.js index 82ef0b5168..5710e66e4a 100644 --- a/src/vector/platform/ElectronPlatform.js +++ b/src/vector/platform/ElectronPlatform.js @@ -20,7 +20,7 @@ limitations under the License. import VectorBasePlatform from './VectorBasePlatform'; import dis from 'matrix-react-sdk/lib/dispatcher'; import q from 'q'; -import electron, {remote} from 'electron'; +import electron, {remote, ipcRenderer} from 'electron'; remote.autoUpdater.on('update-downloaded', onUpdateDownloaded); @@ -58,16 +58,8 @@ export default class ElectronPlatform extends VectorBasePlatform { setNotificationCount(count: number) { if (this.notificationCount === count) return; super.setNotificationCount(count); - // this sometimes throws because electron is made of fail: - // https://github.com/electron/electron/issues/7351 - // For now, let's catch the error, but I suspect it may - // continue to fail and we might just have to accept that - // electron's remote RPC is a non-starter for now and use IPC - try { - remote.app.setBadgeCount(count); - } catch (e) { - console.error('Failed to set notification count', e); - } + + ipcRenderer.send('setBadgeCount', count); } supportsNotifications(): boolean {