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 2ccdf40c..ab3a8e1c 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 1466b76a..00c9c47c 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 72ca19f0..204317ba 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 6dd2b988..6072f0ff 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 ab3a8e1c..b0a657a0 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 b0a657a0..75104042 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 75104042..7198356c 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 6072f0ff..7f753927 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 7198356c..98ffb9f4 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 32e305d8..b632708f 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 98ffb9f4..5409194d 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 82ef0b51..5710e66e 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 {