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 2ccdf40ccc7..ab3a8e1c530 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 1466b76ae37..00c9c47c306 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 72ca19f06c2..204317bab38 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 6dd2b988c36..6072f0ff5b5 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 ab3a8e1c530..b0a657a08e9 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 b0a657a08e9..75104042c17 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 75104042c17..7198356ca61 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 6072f0ff5b5..7f753927ce5 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 7198356ca61..98ffb9f40e3 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 32e305d8d98..b632708f865 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 98ffb9f40e3..5409194d8fc 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 82ef0b51684..5710e66e4a7 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 {