From 782d581429d952b3dcce04daf8172f12f627991d Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Fri, 17 Aug 2018 16:56:34 -0300 Subject: [PATCH 01/14] Unset default application menu on startup --- src/background.js | 40 +++++++++++++++++++--------------- src/menu/dev_menu_template.js | 25 --------------------- src/menu/edit_menu_template.js | 14 ------------ 3 files changed, 23 insertions(+), 56 deletions(-) delete mode 100644 src/menu/dev_menu_template.js delete mode 100644 src/menu/edit_menu_template.js diff --git a/src/background.js b/src/background.js index 34cefa9100..a7a4b88dc8 100644 --- a/src/background.js +++ b/src/background.js @@ -1,29 +1,35 @@ -// This is main process of Electron, started as first thing when your -// app starts. This script is running through entire life of your application. -// It doesn't have any windows which you can see on screen, but we can open -// window from here. - import path from 'path'; import url from 'url'; import { app, Menu, BrowserWindow } from 'electron'; -import { devMenuTemplate } from './menu/dev_menu_template'; -import { editMenuTemplate } from './menu/edit_menu_template'; import './background/certificate'; +import { afterMainWindow } from './background.custom'; +import i18n from './i18n/index.js'; +import env from './env'; export { default as remoteServers } from './background/servers'; export { default as certificate } from './background/certificate'; -import { afterMainWindow } from './background.custom'; -// Special module holding environment variables which you declared -// in config/env_xxx.json file. -import env from './env'; +const unsetDefaultApplicationMenu = () => { + const isMacOS = process.platform === 'darwin'; + + if (isMacOS) { + const emptyMenuTemplate = [{ + submenu: [ + { + label: i18n.__('Quit_App', app.getName()), + accelerator: 'CommandOrControl+Q', + click () { + app.quit(); + } + } + ] + }]; + Menu.setApplicationMenu(Menu.buildFromTemplate(emptyMenuTemplate)); -const setApplicationMenu = function () { - const menus = [editMenuTemplate]; - if (env.name !== 'production') { - menus.push(devMenuTemplate); + return; } - Menu.setApplicationMenu(Menu.buildFromTemplate(menus)); + + Menu.setApplicationMenu(null); }; // Save userData in separate folders for each environment. @@ -85,7 +91,7 @@ if (process.platform === 'darwin') { } app.on('ready', function () { - setApplicationMenu(); + unsetDefaultApplicationMenu(); mainWindow = new BrowserWindow({ width: 1000, diff --git a/src/menu/dev_menu_template.js b/src/menu/dev_menu_template.js deleted file mode 100644 index a75b48e384..0000000000 --- a/src/menu/dev_menu_template.js +++ /dev/null @@ -1,25 +0,0 @@ -import { app, BrowserWindow } from 'electron'; -import i18n from '../i18n/index.js'; - -export const devMenuTemplate = { - label: i18n.__('Development'), - submenu: [{ - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click: function () { - BrowserWindow.getFocusedWindow().webContents.reloadIgnoringCache(); - } - }, { - label: i18n.__('Toggle_DevTools'), - accelerator: 'Alt+CmdOrCtrl+I', - click: function () { - BrowserWindow.getFocusedWindow().toggleDevTools(); - } - }, { - label: i18n.__('Quit'), - accelerator: 'CmdOrCtrl+Q', - click: function () { - app.quit(); - } - }] -}; diff --git a/src/menu/edit_menu_template.js b/src/menu/edit_menu_template.js deleted file mode 100644 index a49abb10c2..0000000000 --- a/src/menu/edit_menu_template.js +++ /dev/null @@ -1,14 +0,0 @@ -import i18n from '../i18n/index.js'; - -export const editMenuTemplate = { - label: i18n.__('Edit'), - submenu: [ - { label: i18n.__('Undo'), accelerator: "CmdOrCtrl+Z", selector: "undo:" }, - { label: i18n.__('Redo'), accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" }, - { type: "separator" }, - { label: i18n.__('Cut'), accelerator: "CmdOrCtrl+X", selector: "cut:" }, - { label: i18n.__('Copy'), accelerator: "CmdOrCtrl+C", selector: "copy:" }, - { label: i18n.__('Paste'), accelerator: "CmdOrCtrl+V", selector: "paste:" }, - { label: i18n.__('Select_All'), accelerator: "CmdOrCtrl+A", selector: "selectAll:" } - ] -}; From 33c139885ab23deea931dfd903a5641bc2732792 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Fri, 17 Aug 2018 18:04:56 -0300 Subject: [PATCH 02/14] Add migration of user data from 'Rocket.Chat+' --- src/background.js | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/background.js b/src/background.js index a7a4b88dc8..fab835557e 100644 --- a/src/background.js +++ b/src/background.js @@ -1,5 +1,6 @@ import path from 'path'; import url from 'url'; +import jetpack from 'fs-jetpack'; import { app, Menu, BrowserWindow } from 'electron'; import './background/certificate'; import { afterMainWindow } from './background.custom'; @@ -32,13 +33,25 @@ const unsetDefaultApplicationMenu = () => { Menu.setApplicationMenu(null); }; -// 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 + ')'); -} +const setUserDataPath = () => { + const appName = app.getName(); + const dirName = env.name === 'production' ? appName : `${ appName } (${ env.name })`; + + app.setPath('userData', path.join(app.getPath('appData'), dirName)); +}; + +const migrateOlderVersionUserData = () => { + const olderAppName = 'Rocket.Chat+'; + const dirName = env.name === 'production' ? olderAppName : `${ olderAppName } (${ env.name })`; + const olderUserDataPath = path.join(app.getPath('appData'), dirName); + + try { + jetpack.copy(olderUserDataPath, app.getPath('userData'), { overwrite: true }); + jetpack.remove(olderUserDataPath); + } catch (e) { + return; + } +}; const processProtocolArgv = (argv) => { const protocolURI = argv.find(arg => arg.startsWith('rocketchat://')); @@ -92,6 +105,8 @@ if (process.platform === 'darwin') { app.on('ready', function () { unsetDefaultApplicationMenu(); + setUserDataPath(); + migrateOlderVersionUserData(); mainWindow = new BrowserWindow({ width: 1000, From a239bb0d2e1ab3451bea9618ed581f2b7b213a8a Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Sat, 18 Aug 2018 02:24:02 -0300 Subject: [PATCH 03/14] Refactor code --- src/background.js | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/background.js b/src/background.js index fab835557e..4bd941a4b9 100644 --- a/src/background.js +++ b/src/background.js @@ -10,27 +10,26 @@ import env from './env'; export { default as remoteServers } from './background/servers'; export { default as certificate } from './background/certificate'; -const unsetDefaultApplicationMenu = () => { - const isMacOS = process.platform === 'darwin'; - - if (isMacOS) { - const emptyMenuTemplate = [{ - submenu: [ - { - label: i18n.__('Quit_App', app.getName()), - accelerator: 'CommandOrControl+Q', - click () { - app.quit(); - } - } - ] - }]; - Menu.setApplicationMenu(Menu.buildFromTemplate(emptyMenuTemplate)); +const isMacOS = process.platform === 'darwin'; +const unsetDefaultApplicationMenu = () => { + if (!isMacOS) { + Menu.setApplicationMenu(null); return; } - Menu.setApplicationMenu(null); + const emptyMenuTemplate = [{ + submenu: [ + { + label: i18n.__('Quit_App', app.getName()), + accelerator: 'CommandOrControl+Q', + click () { + app.quit(); + } + } + ] + }]; + Menu.setApplicationMenu(Menu.buildFromTemplate(emptyMenuTemplate)); }; const setUserDataPath = () => { From 5eb64b7be5fda3db07a38c09ac621400c41426e6 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Sat, 18 Aug 2018 03:15:47 -0300 Subject: [PATCH 04/14] Handle multiple URLs from argv --- src/background.js | 81 ++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/src/background.js b/src/background.js index 4bd941a4b9..71f05ef451 100644 --- a/src/background.js +++ b/src/background.js @@ -1,4 +1,5 @@ import path from 'path'; +import querystring from 'querystring'; import url from 'url'; import jetpack from 'fs-jetpack'; import { app, Menu, BrowserWindow } from 'electron'; @@ -52,57 +53,45 @@ const migrateOlderVersionUserData = () => { } }; -const processProtocolArgv = (argv) => { - const protocolURI = argv.find(arg => arg.startsWith('rocketchat://')); - if (protocolURI) { - const site = protocolURI.split(/\/|\?/)[2]; - if (site) { - let scheme = 'https://'; - if (protocolURI.includes('insecure=true')) { - scheme = 'http://'; - } - return scheme + site; - } - } -}; +const parseProtocolUrls = (args) => + args.filter(arg => /^rocketchat:\/\/./.test(arg)) + .map(uri => url.parse(uri)) + .map(({ hostname, pathname, query }) => { + const { insecure } = querystring.parse(query); + return `${ insecure === 'true' ? 'http' : 'https' }://${ hostname }${ pathname || '' }`; + }); let mainWindow = null; -const appIsReady = new Promise(resolve => { - if (app.isReady()) { - resolve(); - } else { - app.on('ready', resolve); + +const addServers = (serverUrls) => { + if (!mainWindow) { + return; } -}); -if (process.platform === 'darwin') { - // Open protocol urls on mac as open-url is not yet implemented on other OS's - app.on('open-url', function (e, url) { - e.preventDefault(); - const site = processProtocolArgv([url]); - if (site) { - appIsReady.then(() => setTimeout(() => mainWindow.send('add-host', site), 750)); - } - }); -} else { - const isSecondInstance = app.makeSingleInstance((argv) => { - // Someone tried to run a second instance, we should focus our window. - const site = processProtocolArgv(argv); - if (site) { - appIsReady.then(() => mainWindow.send('add-host', site)); - } - if (mainWindow) { - if (mainWindow.isMinimized()) { - mainWindow.restore(); - } - mainWindow.show(); - } - }); - if (isSecondInstance) { - app.quit(); + + serverUrls.forEach(serverUrl => mainWindow.send('add-host', serverUrl)); + + if (mainWindow.isMinimized()) { + mainWindow.restore(); } + + mainWindow.show(); +}; + +const isSecondInstance = app.makeSingleInstance((argv) => { + addServers(parseProtocolUrls(argv.slice(2))); +}); + +if (isSecondInstance) { + app.quit(); } -app.on('ready', function () { +// macOS only +app.on('open-url', (event, url) => { + event.preventDefault(); + addServers(parseProtocolUrls([ url ])); +}); + +app.on('ready', () => { unsetDefaultApplicationMenu(); setUserDataPath(); migrateOlderVersionUserData(); @@ -126,6 +115,6 @@ app.on('ready', function () { } }); -app.on('window-all-closed', function () { +app.on('window-all-closed', () => { app.quit(); }); From bb9efd442fe997f59bbefccb15a7a1b64af97de6 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Sat, 18 Aug 2018 03:34:06 -0300 Subject: [PATCH 05/14] Isolate main window creation --- src/background.custom.js | 16 ++++++++++--- src/background.js | 50 ++++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/background.custom.js b/src/background.custom.js index 57998bf4be..ca984c4639 100644 --- a/src/background.custom.js +++ b/src/background.custom.js @@ -46,9 +46,6 @@ ipcMain.on('source-result', (e, sourceId) => { }); export function afterMainWindow (mainWindow) { - if (!app.isDefaultProtocolClient('rocketchat')) { - app.setAsDefaultProtocolClient('rocketchat'); - } // Preserver of the window size and position between app launches. const mainWindowState = windowStateKeeper('main', { width: 1000, @@ -134,3 +131,16 @@ export function afterMainWindow (mainWindow) { checkForUpdates(); } } + +let mainWindow = null; +export const getMainWindow = () => new Promise(resolve => { + if (!mainWindow) { + mainWindow = new BrowserWindow({ + width: 1000, + titleBarStyle: 'hidden', + height: 600 + }); + } + + resolve(mainWindow); +}); diff --git a/src/background.js b/src/background.js index 71f05ef451..fa1df8207a 100644 --- a/src/background.js +++ b/src/background.js @@ -2,9 +2,9 @@ import path from 'path'; import querystring from 'querystring'; import url from 'url'; import jetpack from 'fs-jetpack'; -import { app, Menu, BrowserWindow } from 'electron'; +import { app, Menu } from 'electron'; import './background/certificate'; -import { afterMainWindow } from './background.custom'; +import { getMainWindow, afterMainWindow } from './background.custom'; import i18n from './i18n/index.js'; import env from './env'; @@ -61,20 +61,16 @@ const parseProtocolUrls = (args) => return `${ insecure === 'true' ? 'http' : 'https' }://${ hostname }${ pathname || '' }`; }); -let mainWindow = null; - const addServers = (serverUrls) => { - if (!mainWindow) { - return; - } + getMainWindow().then((mainWindow) => { + serverUrls.forEach(serverUrl => mainWindow.send('add-host', serverUrl)); - serverUrls.forEach(serverUrl => mainWindow.send('add-host', serverUrl)); - - if (mainWindow.isMinimized()) { - mainWindow.restore(); - } + if (mainWindow.isMinimized()) { + mainWindow.restore(); + } - mainWindow.show(); + mainWindow.show(); + }); }; const isSecondInstance = app.makeSingleInstance((argv) => { @@ -96,23 +92,23 @@ app.on('ready', () => { setUserDataPath(); migrateOlderVersionUserData(); - mainWindow = new BrowserWindow({ - width: 1000, - titleBarStyle: 'hidden', - height: 600 - }); + if (!app.isDefaultProtocolClient('rocketchat')) { + app.setAsDefaultProtocolClient('rocketchat'); + } - afterMainWindow(mainWindow); + getMainWindow().then((mainWindow) => { + afterMainWindow(mainWindow); - mainWindow.loadURL(url.format({ - pathname: path.join(__dirname, 'public', 'app.html'), - protocol: 'file:', - slashes: true - })); + mainWindow.loadURL(url.format({ + pathname: path.join(__dirname, 'public', 'app.html'), + protocol: 'file:', + slashes: true + })); - if (env.name === 'development') { - mainWindow.openDevTools(); - } + if (env.name === 'development') { + mainWindow.openDevTools(); + } + }); }); app.on('window-all-closed', () => { From c45301b6dea6a25aaaea1c14325aa2d052a99758 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 20 Aug 2018 18:30:08 -0300 Subject: [PATCH 06/14] Isolate screen share code --- src/background.js | 3 +- .../mainWindow.js} | 40 ++----------------- src/background/screenshare.js | 35 ++++++++++++++++ 3 files changed, 40 insertions(+), 38 deletions(-) rename src/{background.custom.js => background/mainWindow.js} (73%) create mode 100644 src/background/screenshare.js diff --git a/src/background.js b/src/background.js index fa1df8207a..f918460991 100644 --- a/src/background.js +++ b/src/background.js @@ -4,7 +4,8 @@ import url from 'url'; import jetpack from 'fs-jetpack'; import { app, Menu } from 'electron'; import './background/certificate'; -import { getMainWindow, afterMainWindow } from './background.custom'; +import './background/screenshare'; +import { getMainWindow, afterMainWindow } from './background/mainWindow'; import i18n from './i18n/index.js'; import env from './env'; diff --git a/src/background.custom.js b/src/background/mainWindow.js similarity index 73% rename from src/background.custom.js rename to src/background/mainWindow.js index ca984c4639..43a496c8a6 100644 --- a/src/background.custom.js +++ b/src/background/mainWindow.js @@ -4,47 +4,13 @@ // window from here. import { app, BrowserWindow, ipcMain, nativeImage, } from 'electron'; -import windowStateKeeper from './background/windowState'; -import certificate from './background/certificate'; +import windowStateKeeper from './windowState'; +import certificate from './certificate'; import idle from '@paulcbetts/system-idle-time'; -import { canUpdate, checkForUpdates } from './background/autoUpdate'; +import { canUpdate, checkForUpdates } from './autoUpdate'; process.env.GOOGLE_API_KEY = 'AIzaSyADqUh_c1Qhji3Cp1NE43YrcpuPkmhXD-c'; -let screenshareEvent; -ipcMain.on('screenshare', (event, sources) => { - screenshareEvent = event; - let mainWindow = new BrowserWindow({ - width: 776, - height: 600, - show : false, - skipTaskbar: false - }); - - mainWindow.loadURL('file://'+__dirname+'/public/screenshare.html'); - - //window.openDevTools(); - mainWindow.webContents.on('did-finish-load', () => { - mainWindow.webContents.send('sources', sources); - mainWindow.show(); - }); - - mainWindow.on('closed', () => { - mainWindow = null; - if (screenshareEvent) { - screenshareEvent.sender.send('screenshare-result', 'PermissionDeniedError'); - screenshareEvent = null; - } - }); -}); - -ipcMain.on('source-result', (e, sourceId) => { - if (screenshareEvent) { - screenshareEvent.sender.send('screenshare-result', sourceId); - screenshareEvent = null; - } -}); - export function afterMainWindow (mainWindow) { // Preserver of the window size and position between app launches. const mainWindowState = windowStateKeeper('main', { diff --git a/src/background/screenshare.js b/src/background/screenshare.js new file mode 100644 index 0000000000..db99d4d856 --- /dev/null +++ b/src/background/screenshare.js @@ -0,0 +1,35 @@ +import { BrowserWindow, ipcMain } from 'electron'; + +let screenshareEvent; +ipcMain.on('screenshare', (event, sources) => { + screenshareEvent = event; + let mainWindow = new BrowserWindow({ + width: 776, + height: 600, + show : false, + skipTaskbar: false + }); + + mainWindow.loadURL('file://'+__dirname+'/../public/screenshare.html'); + + //window.openDevTools(); + mainWindow.webContents.on('did-finish-load', () => { + mainWindow.webContents.send('sources', sources); + mainWindow.show(); + }); + + mainWindow.on('closed', () => { + mainWindow = null; + if (screenshareEvent) { + screenshareEvent.sender.send('screenshare-result', 'PermissionDeniedError'); + screenshareEvent = null; + } + }); +}); + +ipcMain.on('source-result', (e, sourceId) => { + if (screenshareEvent) { + screenshareEvent.sender.send('screenshare-result', sourceId); + screenshareEvent = null; + } +}); From e0cd4644f50980c7d032599319fedc952a236ddf Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 21 Aug 2018 11:16:27 -0300 Subject: [PATCH 07/14] Move Google API key definition --- src/background.js | 2 ++ src/background/mainWindow.js | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/background.js b/src/background.js index f918460991..84fe8d78e3 100644 --- a/src/background.js +++ b/src/background.js @@ -12,6 +12,8 @@ import env from './env'; export { default as remoteServers } from './background/servers'; export { default as certificate } from './background/certificate'; +process.env.GOOGLE_API_KEY = 'AIzaSyADqUh_c1Qhji3Cp1NE43YrcpuPkmhXD-c'; + const isMacOS = process.platform === 'darwin'; const unsetDefaultApplicationMenu = () => { diff --git a/src/background/mainWindow.js b/src/background/mainWindow.js index 43a496c8a6..07a65d7f29 100644 --- a/src/background/mainWindow.js +++ b/src/background/mainWindow.js @@ -3,14 +3,12 @@ // It doesn't have any windows which you can see on screen, but we can open // window from here. -import { app, BrowserWindow, ipcMain, nativeImage, } from 'electron'; +import { app, BrowserWindow, ipcMain, nativeImage } from 'electron'; import windowStateKeeper from './windowState'; import certificate from './certificate'; import idle from '@paulcbetts/system-idle-time'; import { canUpdate, checkForUpdates } from './autoUpdate'; -process.env.GOOGLE_API_KEY = 'AIzaSyADqUh_c1Qhji3Cp1NE43YrcpuPkmhXD-c'; - export function afterMainWindow (mainWindow) { // Preserver of the window size and position between app launches. const mainWindowState = windowStateKeeper('main', { From 0a5c6596485f5e964f8221eb2453da660f05f0c0 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 21 Aug 2018 12:27:16 -0300 Subject: [PATCH 08/14] Refactor main window module --- src/background.js | 16 ++------- src/background/mainWindow.js | 70 +++++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/background.js b/src/background.js index 84fe8d78e3..8d4116d899 100644 --- a/src/background.js +++ b/src/background.js @@ -5,7 +5,7 @@ import jetpack from 'fs-jetpack'; import { app, Menu } from 'electron'; import './background/certificate'; import './background/screenshare'; -import { getMainWindow, afterMainWindow } from './background/mainWindow'; +import { createMainWindow, getMainWindow } from './background/mainWindow'; import i18n from './i18n/index.js'; import env from './env'; @@ -99,19 +99,7 @@ app.on('ready', () => { app.setAsDefaultProtocolClient('rocketchat'); } - getMainWindow().then((mainWindow) => { - afterMainWindow(mainWindow); - - mainWindow.loadURL(url.format({ - pathname: path.join(__dirname, 'public', 'app.html'), - protocol: 'file:', - slashes: true - })); - - if (env.name === 'development') { - mainWindow.openDevTools(); - } - }); + createMainWindow(); }); app.on('window-all-closed', () => { diff --git a/src/background/mainWindow.js b/src/background/mainWindow.js index 07a65d7f29..8197f07a31 100644 --- a/src/background/mainWindow.js +++ b/src/background/mainWindow.js @@ -4,12 +4,17 @@ // window from here. import { app, BrowserWindow, ipcMain, nativeImage } from 'electron'; +import url from 'url'; +import path from 'path'; import windowStateKeeper from './windowState'; import certificate from './certificate'; import idle from '@paulcbetts/system-idle-time'; import { canUpdate, checkForUpdates } from './autoUpdate'; +import env from '../env'; -export function afterMainWindow (mainWindow) { +let mainWindow = null; + +function afterMainWindow (mainWindow) { // Preserver of the window size and position between app launches. const mainWindowState = windowStateKeeper('main', { width: 1000, @@ -36,6 +41,20 @@ export function afterMainWindow (mainWindow) { mainWindow.hide(); } + app.on('activate', () => { + mainWindowState.saveState(mainWindow); + mainWindow.show(); + }); + + app.on('before-quit', () => { + mainWindowState.saveState(mainWindow); + mainWindow.forceClose = true; + }); + + mainWindow.on('show', () => { + mainWindowState.saveState(mainWindow); + }); + mainWindow.on('close', function (event) { if (mainWindow.forceClose) { mainWindowState.saveState(mainWindow); @@ -53,11 +72,6 @@ export function afterMainWindow (mainWindow) { mainWindowState.saveState(mainWindow); }); - app.on('before-quit', function () { - mainWindowState.saveState(mainWindow); - mainWindow.forceClose = true; - }); - mainWindow.on('resize', function () { mainWindowState.saveState(mainWindow); }); @@ -66,11 +80,6 @@ export function afterMainWindow (mainWindow) { mainWindowState.saveState(mainWindow); }); - app.on('activate', function () { - mainWindow.show(); - mainWindowState.saveState(mainWindow); - }); - mainWindow.webContents.on('will-navigate', function (event) { event.preventDefault(); }); @@ -96,15 +105,36 @@ export function afterMainWindow (mainWindow) { } } -let mainWindow = null; -export const getMainWindow = () => new Promise(resolve => { - if (!mainWindow) { - mainWindow = new BrowserWindow({ - width: 1000, - titleBarStyle: 'hidden', - height: 600 - }); +export const createMainWindow = (cb) => { + if (mainWindow) { + return cb && cb(mainWindow); + } + + mainWindow = new BrowserWindow({ + width: 1000, + height: 600, + titleBarStyle: 'hidden' + }); + + afterMainWindow(mainWindow); + + mainWindow.loadURL(url.format({ + pathname: path.join(__dirname, 'public', 'app.html'), + protocol: 'file:', + slashes: true + })); + + if (env.name === 'development') { + mainWindow.openDevTools(); + } + + return cb && cb(mainWindow); +}; + +export const getMainWindow = () => new Promise((resolve) => { + if (app.isReady()) { + return createMainWindow(resolve); } - resolve(mainWindow); + app.on('ready', () => createMainWindow(resolve)); }); From ee05ea64d603c87029ba798b700490219ae4e5a9 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 21 Aug 2018 12:32:43 -0300 Subject: [PATCH 09/14] Set minimum window size on creation --- src/background/mainWindow.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/background/mainWindow.js b/src/background/mainWindow.js index 8197f07a31..e0025eedba 100644 --- a/src/background/mainWindow.js +++ b/src/background/mainWindow.js @@ -27,7 +27,6 @@ function afterMainWindow (mainWindow) { if (mainWindowState.width !== undefined && mainWindowState.height !== undefined) { mainWindow.setSize(mainWindowState.width, mainWindowState.height, false); } - mainWindow.setMinimumSize(600, 400); if (mainWindowState.isMaximized) { mainWindow.maximize(); @@ -113,6 +112,8 @@ export const createMainWindow = (cb) => { mainWindow = new BrowserWindow({ width: 1000, height: 600, + minWidth: 600, + minHeight: 400, titleBarStyle: 'hidden' }); From 744890690b6bd838cda111763b85cfd79f5b1ae4 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 21 Aug 2018 13:10:17 -0300 Subject: [PATCH 10/14] Refactor window state handling --- src/background/mainWindow.js | 51 ++++++++++++--------------------- src/background/windowState.js | 53 +++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 54 deletions(-) diff --git a/src/background/mainWindow.js b/src/background/mainWindow.js index e0025eedba..094e890983 100644 --- a/src/background/mainWindow.js +++ b/src/background/mainWindow.js @@ -14,32 +14,21 @@ import env from '../env'; let mainWindow = null; -function afterMainWindow (mainWindow) { - // Preserver of the window size and position between app launches. - const mainWindowState = windowStateKeeper('main', { - width: 1000, - height: 600 - }); - - if (mainWindowState.x !== undefined && mainWindowState.y !== undefined) { - mainWindow.setPosition(mainWindowState.x, mainWindowState.y, false); - } - if (mainWindowState.width !== undefined && mainWindowState.height !== undefined) { - mainWindow.setSize(mainWindowState.width, mainWindowState.height, false); - } - - if (mainWindowState.isMaximized) { - mainWindow.maximize(); - } +const mainWindowOptions = { + width: 1000, + height: 600, + minWidth: 600, + minHeight: 400, + titleBarStyle: 'hidden', + show: false +}; - if (mainWindowState.isMinimized) { - mainWindow.minimize(); - } +function afterMainWindow (mainWindow) { + const mainWindowState = windowStateKeeper('main', mainWindowOptions); - if (mainWindowState.isHidden) { - mainWindow.hide(); - } + mainWindow.once('ready-to-show', () => mainWindowState.loadState(mainWindow)); + // macOS only app.on('activate', () => { mainWindowState.saveState(mainWindow); mainWindow.show(); @@ -106,16 +95,11 @@ function afterMainWindow (mainWindow) { export const createMainWindow = (cb) => { if (mainWindow) { - return cb && cb(mainWindow); + cb && cb(mainWindow); + return; } - mainWindow = new BrowserWindow({ - width: 1000, - height: 600, - minWidth: 600, - minHeight: 400, - titleBarStyle: 'hidden' - }); + mainWindow = new BrowserWindow(mainWindowOptions); afterMainWindow(mainWindow); @@ -129,12 +113,13 @@ export const createMainWindow = (cb) => { mainWindow.openDevTools(); } - return cb && cb(mainWindow); + cb && cb(mainWindow); }; export const getMainWindow = () => new Promise((resolve) => { if (app.isReady()) { - return createMainWindow(resolve); + createMainWindow(resolve); + return; } app.on('ready', () => createMainWindow(resolve)); diff --git a/src/background/windowState.js b/src/background/windowState.js index 3b1e5997d2..d0895148b3 100644 --- a/src/background/windowState.js +++ b/src/background/windowState.js @@ -4,42 +4,52 @@ import { app } from 'electron'; import jetpack from 'fs-jetpack'; -import _ from 'lodash'; +import { debounce } from 'lodash'; export default function (name, defaults) { - const userDataDir = jetpack.cwd(app.getPath('userData')); - const stateStoreFile = `window-state-${name}.json`; let state = { width: defaults.width, height: defaults.height }; + const userDataDir = jetpack.cwd(app.getPath('userData')); + const stateStoreFile = `window-state-${name}.json`; + try { - const loadedState = userDataDir.read(stateStoreFile, 'json'); - if (loadedState) { - state = loadedState; - } + state = userDataDir.read(stateStoreFile, 'json') || state; } catch (err) { - // For some reason json can't be read. - // No worries, we have defaults. + console.error(`Failed to load "${ name }" window state`); + console.error(err); } - const saveState = function (win) { - if (!win.isMaximized() && !win.isMinimized() && win.isVisible()) { - const position = win.getPosition(); - const size = win.getSize(); - state.x = position[0]; - state.y = position[1]; - state.width = size[0]; - state.height = size[1]; + const saveState = function (window) { + state.isMaximized = window.isMaximized(); + state.isMinimized = window.isMinimized(); + state.isHidden = !window.isMinimized() && !window.isVisible(); + + if (!state.isMaximized && !state.isHidden) { + [ state.x, state.y ] = window.getPosition(); + [ state.width, state.height ] = window.getSize(); } - state.isMaximized = win.isMaximized(); - state.isMinimized = win.isMinimized(); - state.isHidden = !win.isMinimized() && !win.isVisible(); + userDataDir.write(stateStoreFile, state, { atomic: true }); }; + const loadState = function (window) { + if (this.x !== undefined && this.y !== undefined) { + window.setPosition(this.x, this.y, false); + } + + if (this.width !== undefined && this.height !== undefined) { + window.setSize(this.width, this.height, false); + } + + this.isMaximized ? window.maximize() : window.unmaximize(); + this.isMinimized ? window.minimize() : window.restore(); + this.isHidden ? window.hide() : window.show(); + }; + return { get x () { return state.x && Math.floor(state.x); }, get y () { return state.y && Math.floor(state.y); }, @@ -48,6 +58,7 @@ export default function (name, defaults) { get isMaximized () { return state.isMaximized; }, get isMinimized () { return state.isMinimized; }, get isHidden () { return state.isHidden; }, - saveState: _.debounce(saveState, 1000) + saveState: debounce(saveState, 1000), + loadState }; } From abc298fe55bc3f4ce8910c0446f525b10242ee63 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 21 Aug 2018 13:34:01 -0300 Subject: [PATCH 11/14] Move autoupdate code --- src/background.js | 5 +++++ src/background/mainWindow.js | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/background.js b/src/background.js index 8d4116d899..6b3d3e5eeb 100644 --- a/src/background.js +++ b/src/background.js @@ -6,6 +6,7 @@ import { app, Menu } from 'electron'; import './background/certificate'; import './background/screenshare'; import { createMainWindow, getMainWindow } from './background/mainWindow'; +import { canUpdate, checkForUpdates } from './background/autoUpdate'; import i18n from './i18n/index.js'; import env from './env'; @@ -100,6 +101,10 @@ app.on('ready', () => { } createMainWindow(); + + if (canUpdate()) { + checkForUpdates(); + } }); app.on('window-all-closed', () => { diff --git a/src/background/mainWindow.js b/src/background/mainWindow.js index 094e890983..eecc5aa59e 100644 --- a/src/background/mainWindow.js +++ b/src/background/mainWindow.js @@ -9,7 +9,6 @@ import path from 'path'; import windowStateKeeper from './windowState'; import certificate from './certificate'; import idle from '@paulcbetts/system-idle-time'; -import { canUpdate, checkForUpdates } from './autoUpdate'; import env from '../env'; let mainWindow = null; @@ -87,10 +86,6 @@ function afterMainWindow (mainWindow) { }); certificate.initWindow(mainWindow); - - if (canUpdate()) { - checkForUpdates(); - } } export const createMainWindow = (cb) => { From 2c8aec97e4c128eafe9118ef4d02be98b0aabbd3 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 21 Aug 2018 13:40:24 -0300 Subject: [PATCH 12/14] Move certificate store code --- src/background.js | 10 +++++++--- src/background/mainWindow.js | 3 --- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/background.js b/src/background.js index 6b3d3e5eeb..b4f1d29a14 100644 --- a/src/background.js +++ b/src/background.js @@ -3,10 +3,12 @@ import querystring from 'querystring'; import url from 'url'; import jetpack from 'fs-jetpack'; import { app, Menu } from 'electron'; -import './background/certificate'; -import './background/screenshare'; -import { createMainWindow, getMainWindow } from './background/mainWindow'; + import { canUpdate, checkForUpdates } from './background/autoUpdate'; +import certificate from './background/certificate'; +import { createMainWindow, getMainWindow } from './background/mainWindow'; +import './background/screenshare'; + import i18n from './i18n/index.js'; import env from './env'; @@ -102,6 +104,8 @@ app.on('ready', () => { createMainWindow(); + getMainWindow().then(mainWindow => certificate.initWindow(mainWindow)); + if (canUpdate()) { checkForUpdates(); } diff --git a/src/background/mainWindow.js b/src/background/mainWindow.js index eecc5aa59e..57f6da111a 100644 --- a/src/background/mainWindow.js +++ b/src/background/mainWindow.js @@ -7,7 +7,6 @@ import { app, BrowserWindow, ipcMain, nativeImage } from 'electron'; import url from 'url'; import path from 'path'; import windowStateKeeper from './windowState'; -import certificate from './certificate'; import idle from '@paulcbetts/system-idle-time'; import env from '../env'; @@ -84,8 +83,6 @@ function afterMainWindow (mainWindow) { const img = nativeImage.createFromDataURL(data); mainWindow.setOverlayIcon(img, text); }); - - certificate.initWindow(mainWindow); } export const createMainWindow = (cb) => { From fe79c34afa21a76c42d49cd7b240cc81f9ea3a93 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 21 Aug 2018 13:44:10 -0300 Subject: [PATCH 13/14] Move getSystemIdleTime ipcMain message --- src/background.js | 7 ++++++- src/background/mainWindow.js | 6 +----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/background.js b/src/background.js index b4f1d29a14..e05f87b468 100644 --- a/src/background.js +++ b/src/background.js @@ -2,7 +2,8 @@ import path from 'path'; import querystring from 'querystring'; import url from 'url'; import jetpack from 'fs-jetpack'; -import { app, Menu } from 'electron'; +import idle from '@paulcbetts/system-idle-time'; +import { app, ipcMain, Menu } from 'electron'; import { canUpdate, checkForUpdates } from './background/autoUpdate'; import certificate from './background/certificate'; @@ -114,3 +115,7 @@ app.on('ready', () => { app.on('window-all-closed', () => { app.quit(); }); + +ipcMain.on('getSystemIdleTime', (event) => { + event.returnValue = idle.getIdleTime(); +}); diff --git a/src/background/mainWindow.js b/src/background/mainWindow.js index 57f6da111a..4be85320d6 100644 --- a/src/background/mainWindow.js +++ b/src/background/mainWindow.js @@ -6,8 +6,8 @@ import { app, BrowserWindow, ipcMain, nativeImage } from 'electron'; import url from 'url'; import path from 'path'; + import windowStateKeeper from './windowState'; -import idle from '@paulcbetts/system-idle-time'; import env from '../env'; let mainWindow = null; @@ -75,10 +75,6 @@ function afterMainWindow (mainWindow) { mainWindowState.saveState(mainWindow); }); - ipcMain.on('getSystemIdleTime', (event) => { - event.returnValue = idle.getIdleTime(); - }); - ipcMain.on('update-taskbar-icon', (event, data, text) => { const img = nativeImage.createFromDataURL(data); mainWindow.setOverlayIcon(img, text); From 5317c49c0dac13a877f43b0931b067888271d1dd Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 21 Aug 2018 14:00:40 -0300 Subject: [PATCH 14/14] Refactor background code --- src/background.js | 19 +++++-------------- src/background/mainWindow.js | 33 +++++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/background.js b/src/background.js index e05f87b468..858a24f03f 100644 --- a/src/background.js +++ b/src/background.js @@ -7,7 +7,7 @@ import { app, ipcMain, Menu } from 'electron'; import { canUpdate, checkForUpdates } from './background/autoUpdate'; import certificate from './background/certificate'; -import { createMainWindow, getMainWindow } from './background/mainWindow'; +import { addServer, createMainWindow, getMainWindow } from './background/mainWindow'; import './background/screenshare'; import i18n from './i18n/index.js'; @@ -68,20 +68,11 @@ const parseProtocolUrls = (args) => return `${ insecure === 'true' ? 'http' : 'https' }://${ hostname }${ pathname || '' }`; }); -const addServers = (serverUrls) => { - getMainWindow().then((mainWindow) => { - serverUrls.forEach(serverUrl => mainWindow.send('add-host', serverUrl)); - - if (mainWindow.isMinimized()) { - mainWindow.restore(); - } - - mainWindow.show(); - }); -}; +const addServers = (protocolUrls) => parseProtocolUrls(protocolUrls) + .forEach(serverUrl => addServer(serverUrl)); const isSecondInstance = app.makeSingleInstance((argv) => { - addServers(parseProtocolUrls(argv.slice(2))); + addServers(argv.slice(2)); }); if (isSecondInstance) { @@ -91,7 +82,7 @@ if (isSecondInstance) { // macOS only app.on('open-url', (event, url) => { event.preventDefault(); - addServers(parseProtocolUrls([ url ])); + addServers([ url ]); }); app.on('ready', () => { diff --git a/src/background/mainWindow.js b/src/background/mainWindow.js index 4be85320d6..518db57b1b 100644 --- a/src/background/mainWindow.js +++ b/src/background/mainWindow.js @@ -21,7 +21,7 @@ const mainWindowOptions = { show: false }; -function afterMainWindow (mainWindow) { +const attachWindowStateHandling = (mainWindow) => { const mainWindowState = windowStateKeeper('main', mainWindowOptions); mainWindow.once('ready-to-show', () => mainWindowState.loadState(mainWindow)); @@ -65,21 +65,18 @@ function afterMainWindow (mainWindow) { mainWindow.on('move', function () { mainWindowState.saveState(mainWindow); }); +}; - mainWindow.webContents.on('will-navigate', function (event) { - event.preventDefault(); - }); - +const attachIpcMessageHandling = (mainWindow) => { ipcMain.on('focus', () => { mainWindow.show(); - mainWindowState.saveState(mainWindow); }); ipcMain.on('update-taskbar-icon', (event, data, text) => { const img = nativeImage.createFromDataURL(data); mainWindow.setOverlayIcon(img, text); }); -} +}; export const createMainWindow = (cb) => { if (mainWindow) { @@ -88,14 +85,20 @@ export const createMainWindow = (cb) => { } mainWindow = new BrowserWindow(mainWindowOptions); + attachWindowStateHandling(mainWindow); + attachIpcMessageHandling(mainWindow); - afterMainWindow(mainWindow); + mainWindow.webContents.on('will-navigate', (event) => { + event.preventDefault(); + }); - mainWindow.loadURL(url.format({ + const appUrl = url.format({ pathname: path.join(__dirname, 'public', 'app.html'), protocol: 'file:', slashes: true - })); + }); + + mainWindow.loadURL(appUrl); if (env.name === 'development') { mainWindow.openDevTools(); @@ -112,3 +115,13 @@ export const getMainWindow = () => new Promise((resolve) => { app.on('ready', () => createMainWindow(resolve)); }); + +export const addServer = (serverUrl) => getMainWindow().then((mainWindow) => { + mainWindow.send('add-host', serverUrl); + + mainWindow.show(); + + if (mainWindow.isMinimized()) { + mainWindow.restore(); + } +});