From 166ebe04e6aa78d04ba595e3706044f45bd2c516 Mon Sep 17 00:00:00 2001 From: Chris Knepper Date: Wed, 27 Jun 2018 22:14:27 -0400 Subject: [PATCH] -Prevent multiple instances of the app launching which was a potentially large problem on Windows -True minimizing "to" the Windows Tray --- src/background.js | 218 +++++++++++++++++++++++++--------------------- 1 file changed, 118 insertions(+), 100 deletions(-) diff --git a/src/background.js b/src/background.js index 5d307e2b..56eac3ee 100644 --- a/src/background.js +++ b/src/background.js @@ -17,116 +17,134 @@ import { IS_MAC, IS_WINDOWS, IS_LINUX, IS_DEV } from './constants'; // in config/env_xxx.json file. import env from 'env'; -let tray; // Must declare reference to instance of Tray as a variable, not a const, or bad/weird things happen +let mainWindow = null; + +// Prevent multiple instances of the app which causes many problems with an app like ours +// Without this, if an instance were minimized to the tray in Windows, clicking a shortcut would launch another instance, icky +// Adapted from https://github.com/electron/electron/blob/v2.0.2/docs/api/app.md#appmakesingleinstancecallback +const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory) => { + // Someone tried to run a second instance, let's show our existing instance instead + if (mainWindow) { + if (!mainWindow.isVisible()) { + mainWindow.show(); + } + } +}); -const setApplicationMenu = () => { - const menus = baseMenuTemplate; +if (isSecondInstance) { + app.quit() +} else { + let tray; // Must declare reference to instance of Tray as a variable, not a const, or bad/weird things happen + + const setApplicationMenu = () => { + const menus = baseMenuTemplate; + if (env.name !== 'production') { + menus.push(devMenuTemplate); + } + menus.push(helpMenuTemplate); + Menu.setApplicationMenu(Menu.buildFromTemplate(menus)); + }; + + // Save userData in separate folders for each environment. + // Thanks to this you can use production and development versions of the app + // on same machine like those are two separate apps. if (env.name !== 'production') { - menus.push(devMenuTemplate); + const userDataPath = app.getPath('userData'); + app.setPath('userData', `${userDataPath} (${env.name})`); } - menus.push(helpMenuTemplate); - Menu.setApplicationMenu(Menu.buildFromTemplate(menus)); -}; - -// Save userData in separate folders for each environment. -// Thanks to this you can use production and development versions of the app -// on same machine like those are two separate apps. -if (env.name !== 'production') { - const userDataPath = app.getPath('userData'); - app.setPath('userData', `${userDataPath} (${env.name})`); -} - -if (IS_WINDOWS) { - // Stupid, DUMB calls that have to be made to let notifications come through on Windows (only Windows 10?) - // See: https://github.com/electron/electron/issues/10864#issuecomment-382519150 - app.setAppUserModelId('com.knepper.android-messages-desktop'); - app.setAsDefaultProtocolClient('android-messages-desktop'); -} - -app.on('ready', () => { - setApplicationMenu(); - autoUpdater.checkForUpdatesAndNotify(); - - const mainWindow = createWindow('main', { - width: 1100, - height: 800 - }); - - mainWindow.loadURL( - url.format({ - pathname: path.join(__dirname, 'app.html'), - protocol: 'file:', - slashes: true - }) - ); - app.mainWindow = mainWindow; // Quick and dirty way for renderer process to access mainWindow for communication - - if (IS_MAC) { - let quitViaContext = false; - app.on('before-quit', () => { - quitViaContext = true; - }); - - mainWindow.on('close', (event) => { - if (!quitViaContext) { - event.preventDefault(); - mainWindow.hide(); - } - }); - - app.on('activate', () => { - mainWindow.show(); - }); + if (IS_WINDOWS) { + // Stupid, DUMB calls that have to be made to let notifications come through on Windows (only Windows 10?) + // See: https://github.com/electron/electron/issues/10864#issuecomment-382519150 + app.setAppUserModelId('com.knepper.android-messages-desktop'); + app.setAsDefaultProtocolClient('android-messages-desktop'); } - if (IS_WINDOWS) { - mainWindow.on('close', (event) => { - app.quit(); - }); + app.on('ready', () => { + setApplicationMenu(); + autoUpdater.checkForUpdatesAndNotify(); - tray = new Tray(__dirname + '../../resources/icon.ico'); + mainWindow = createWindow('main', { + width: 1100, + height: 800 + }); - let contextMenu = Menu.buildFromTemplate([ - { - label: 'Show', - click: () => { - mainWindow.show(); + mainWindow.loadURL( + url.format({ + pathname: path.join(__dirname, 'app.html'), + protocol: 'file:', + slashes: true + }) + ); + + app.mainWindow = mainWindow; // Quick and dirty way for renderer process to access mainWindow for communication + + if (IS_MAC) { + let quitViaContext = false; + app.on('before-quit', () => { + quitViaContext = true; + }); + + mainWindow.on('close', (event) => { + if (!quitViaContext) { + event.preventDefault(); + mainWindow.hide(); } - }, - { - label: 'Quit', - click: () => { - app.quit(); + }); + + app.on('activate', () => { + mainWindow.show(); + }); + } + + if (IS_WINDOWS) { + mainWindow.on('close', (event) => { + app.quit(); + }); + + tray = new Tray(__dirname + '../../resources/icon.ico'); + + let contextMenu = Menu.buildFromTemplate([ + { + label: 'Show', + click: () => { + mainWindow.show(); + } + }, + { + label: 'Quit', + click: () => { + app.quit(); + } } - } - ]); - - tray.setContextMenu(contextMenu); + ]); - tray.on('double-click', (event) => { - event.preventDefault(); - mainWindow.show(); - }); - - mainWindow.on('minimize', (event) => { - event.preventDefault(); - // TODO: Hide the window via mainWindow.hide() instead of minimizing? - // Hiding would allow the icon to disappear from the taskbar if it's not pinned, - // but if it's pinned, hidden, then clicked, results in a duplicate instance of the app... - // Possible solution: https://github.com/electron/electron/blob/v0.36.10/docs/api/app.md#appmakesingleinstancecallback - mainWindow.minimize(); - }); - } + tray.setContextMenu(contextMenu); - // TODO: Better UX for Linux...likely similar to Windows as far as tray behavior - if (IS_LINUX) { - app.on('window-all-closed', (event) => { - app.quit(); - }); - } + tray.on('double-click', (event) => { + event.preventDefault(); + mainWindow.show(); + }); - if (IS_DEV) { - mainWindow.openDevTools(); - } -}); + mainWindow.on('minimize', (event) => { + event.preventDefault(); + // TODO: Hide the window via mainWindow.hide() instead of minimizing? + // Hiding would allow the icon to disappear from the taskbar if it's not pinned, + // but if it's pinned, hidden, then clicked, results in a duplicate instance of the app... + // Possible solution: https://github.com/electron/electron/blob/v0.36.10/docs/api/app.md#appmakesingleinstancecallback + mainWindow.hide(); + }); + } + + // TODO: Better UX for Linux...likely similar to Windows as far as tray behavior + if (IS_LINUX) { + app.on('window-all-closed', (event) => { + app.quit(); + }); + } + + if (IS_DEV) { + mainWindow.openDevTools(); + } + }); +}