diff options
Diffstat (limited to 'src/index.js')
-rw-r--r-- | src/index.js | 161 |
1 files changed, 120 insertions, 41 deletions
diff --git a/src/index.js b/src/index.js index f34df8c17..3fe996aa7 100644 --- a/src/index.js +++ b/src/index.js | |||
@@ -4,25 +4,23 @@ import { | |||
4 | shell, | 4 | shell, |
5 | ipcMain, | 5 | ipcMain, |
6 | } from 'electron'; | 6 | } from 'electron'; |
7 | 7 | import isDevMode from 'electron-is-dev'; | |
8 | import fs from 'fs-extra'; | 8 | import fs from 'fs-extra'; |
9 | import path from 'path'; | 9 | import path from 'path'; |
10 | import windowStateKeeper from 'electron-window-state'; | 10 | import windowStateKeeper from 'electron-window-state'; |
11 | 11 | ||
12 | // Set app directory before loading user modules | ||
13 | if (isDevMode) { | ||
14 | app.setPath('userData', path.join(app.getPath('appData'), 'FranzDev')); | ||
15 | } | ||
16 | |||
17 | /* eslint-disable import/first */ | ||
12 | import { | 18 | import { |
13 | isDevMode, | ||
14 | isMac, | 19 | isMac, |
15 | isWindows, | 20 | isWindows, |
16 | isLinux, | 21 | isLinux, |
17 | } from './environment'; | 22 | } from './environment'; |
18 | |||
19 | import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; | 23 | import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; |
20 | |||
21 | // DEV MODE: Save user data into FranzDev | ||
22 | if (isDevMode) { | ||
23 | app.setPath('userData', path.join(app.getPath('appData'), 'FranzDev')); | ||
24 | } | ||
25 | /* eslint-disable import/first */ | ||
26 | import ipcApi from './electron/ipc-api'; | 24 | import ipcApi from './electron/ipc-api'; |
27 | import Tray from './lib/Tray'; | 25 | import Tray from './lib/Tray'; |
28 | import Settings from './electron/Settings'; | 26 | import Settings from './electron/Settings'; |
@@ -35,6 +33,8 @@ import { | |||
35 | DEFAULT_APP_SETTINGS, | 33 | DEFAULT_APP_SETTINGS, |
36 | DEFAULT_WINDOW_OPTIONS, | 34 | DEFAULT_WINDOW_OPTIONS, |
37 | } from './config'; | 35 | } from './config'; |
36 | import { asarPath } from './helpers/asar-helpers'; | ||
37 | import { isValidExternalURL } from './helpers/url-helpers'; | ||
38 | /* eslint-enable import/first */ | 38 | /* eslint-enable import/first */ |
39 | 39 | ||
40 | const debug = require('debug')('Franz:App'); | 40 | const debug = require('debug')('Franz:App'); |
@@ -44,6 +44,17 @@ const debug = require('debug')('Franz:App'); | |||
44 | let mainWindow; | 44 | let mainWindow; |
45 | let willQuitApp = false; | 45 | let willQuitApp = false; |
46 | 46 | ||
47 | // Register methods to be called once the window has been loaded. | ||
48 | let onDidLoadFns = []; | ||
49 | |||
50 | function onDidLoad(fn) { | ||
51 | if (onDidLoadFns) { | ||
52 | onDidLoadFns.push(fn); | ||
53 | } else if (mainWindow) { | ||
54 | fn(mainWindow); | ||
55 | } | ||
56 | } | ||
57 | |||
47 | // Ensure that the recipe directory exists | 58 | // Ensure that the recipe directory exists |
48 | fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); | 59 | fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); |
49 | fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json')); | 60 | fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json')); |
@@ -61,32 +72,38 @@ if (!gotTheLock) { | |||
61 | app.on('second-instance', (event, argv) => { | 72 | app.on('second-instance', (event, argv) => { |
62 | // Someone tried to run a second instance, we should focus our window. | 73 | // Someone tried to run a second instance, we should focus our window. |
63 | if (mainWindow) { | 74 | if (mainWindow) { |
64 | if (mainWindow.isMinimized()) mainWindow.restore(); | 75 | mainWindow.show(); |
76 | if (mainWindow.isMinimized()) { | ||
77 | mainWindow.restore(); | ||
78 | } | ||
65 | mainWindow.focus(); | 79 | mainWindow.focus(); |
66 | 80 | ||
67 | if (isWindows) { | 81 | if (isWindows) { |
68 | // Keep only command line / deep linked arguments | 82 | onDidLoad((window) => { |
69 | const url = argv.slice(1); | 83 | // Keep only command line / deep linked arguments |
70 | 84 | const url = argv.slice(1); | |
71 | if (url) { | 85 | if (url) { |
72 | handleDeepLink(mainWindow, url.toString()); | 86 | handleDeepLink(window, url.toString()); |
73 | } | 87 | } |
74 | } | 88 | |
75 | 89 | if (argv.includes('--reset-window')) { | |
76 | if (argv.includes('--reset-window')) { | 90 | // Needs to be delayed to not interfere with mainWindow.restore(); |
77 | // Needs to be delayed to not interfere with mainWindow.restore(); | 91 | setTimeout(() => { |
78 | setTimeout(() => { | 92 | debug('Resetting windows via Task'); |
79 | debug('Resetting windows via Task'); | 93 | window.setPosition(DEFAULT_WINDOW_OPTIONS.x + 100, DEFAULT_WINDOW_OPTIONS.y + 100); |
80 | mainWindow.setPosition(DEFAULT_WINDOW_OPTIONS.x + 100, DEFAULT_WINDOW_OPTIONS.y + 100); | 94 | window.setSize(DEFAULT_WINDOW_OPTIONS.width, DEFAULT_WINDOW_OPTIONS.height); |
81 | mainWindow.setSize(DEFAULT_WINDOW_OPTIONS.width, DEFAULT_WINDOW_OPTIONS.height); | 95 | }, 1); |
82 | }, 1); | 96 | } else if (argv.includes('--quit')) { |
97 | // Needs to be delayed to not interfere with mainWindow.restore(); | ||
98 | setTimeout(() => { | ||
99 | debug('Quitting Franz via Task'); | ||
100 | app.quit(); | ||
101 | }, 1); | ||
102 | } | ||
103 | }); | ||
83 | } | 104 | } |
84 | } | 105 | } |
85 | }); | 106 | }); |
86 | |||
87 | // Create myWindow, load the rest of the app, etc... | ||
88 | app.on('ready', () => { | ||
89 | }); | ||
90 | } | 107 | } |
91 | // const isSecondInstance = app.makeSingleInstance((argv) => { | 108 | // const isSecondInstance = app.makeSingleInstance((argv) => { |
92 | // if (mainWindow) { | 109 | // if (mainWindow) { |
@@ -166,6 +183,14 @@ const createWindow = () => { | |||
166 | }, | 183 | }, |
167 | }); | 184 | }); |
168 | 185 | ||
186 | mainWindow.webContents.on('did-finish-load', () => { | ||
187 | const fns = onDidLoadFns; | ||
188 | onDidLoadFns = null; | ||
189 | for (const fn of fns) { | ||
190 | fn(mainWindow); | ||
191 | } | ||
192 | }); | ||
193 | |||
169 | // Initialize System Tray | 194 | // Initialize System Tray |
170 | const trayIcon = new Tray(); | 195 | const trayIcon = new Tray(); |
171 | 196 | ||
@@ -190,22 +215,36 @@ const createWindow = () => { | |||
190 | mainWindow.webContents.openDevTools(); | 215 | mainWindow.webContents.openDevTools(); |
191 | } | 216 | } |
192 | 217 | ||
218 | // Windows deep linking handling on app launch | ||
219 | if (isWindows) { | ||
220 | onDidLoad((window) => { | ||
221 | const url = process.argv.slice(1); | ||
222 | if (url) { | ||
223 | handleDeepLink(window, url.toString()); | ||
224 | } | ||
225 | }); | ||
226 | } | ||
227 | |||
193 | // Emitted when the window is closed. | 228 | // Emitted when the window is closed. |
194 | mainWindow.on('close', (e) => { | 229 | mainWindow.on('close', (e) => { |
230 | debug('Window: close window'); | ||
195 | // Dereference the window object, usually you would store windows | 231 | // Dereference the window object, usually you would store windows |
196 | // in an array if your app supports multi windows, this is the time | 232 | // in an array if your app supports multi windows, this is the time |
197 | // when you should delete the corresponding element. | 233 | // when you should delete the corresponding element. |
198 | if (!willQuitApp && (settings.get('runInBackground') === undefined || settings.get('runInBackground'))) { | 234 | if (!willQuitApp && (settings.get('runInBackground') === undefined || settings.get('runInBackground'))) { |
199 | e.preventDefault(); | 235 | e.preventDefault(); |
200 | if (isWindows) { | 236 | if (isWindows) { |
237 | debug('Window: minimize'); | ||
201 | mainWindow.minimize(); | 238 | mainWindow.minimize(); |
239 | |||
240 | if (settings.get('minimizeToSystemTray')) { | ||
241 | debug('Skip taskbar: true'); | ||
242 | mainWindow.setSkipTaskbar(true); | ||
243 | } | ||
202 | } else { | 244 | } else { |
245 | debug('Window: hide'); | ||
203 | mainWindow.hide(); | 246 | mainWindow.hide(); |
204 | } | 247 | } |
205 | |||
206 | if (isWindows) { | ||
207 | mainWindow.setSkipTaskbar(true); | ||
208 | } | ||
209 | } else { | 248 | } else { |
210 | app.quit(); | 249 | app.quit(); |
211 | } | 250 | } |
@@ -217,32 +256,39 @@ const createWindow = () => { | |||
217 | app.wasMaximized = app.isMaximized; | 256 | app.wasMaximized = app.isMaximized; |
218 | 257 | ||
219 | if (settings.get('minimizeToSystemTray')) { | 258 | if (settings.get('minimizeToSystemTray')) { |
259 | debug('Skip taskbar: true'); | ||
220 | mainWindow.setSkipTaskbar(true); | 260 | mainWindow.setSkipTaskbar(true); |
221 | trayIcon.show(); | 261 | trayIcon.show(); |
222 | } | 262 | } |
223 | }); | 263 | }); |
224 | 264 | ||
225 | mainWindow.on('maximize', () => { | 265 | mainWindow.on('maximize', () => { |
266 | debug('Window: maximize'); | ||
226 | app.isMaximized = true; | 267 | app.isMaximized = true; |
227 | }); | 268 | }); |
228 | 269 | ||
229 | mainWindow.on('unmaximize', () => { | 270 | mainWindow.on('unmaximize', () => { |
271 | debug('Window: unmaximize'); | ||
230 | app.isMaximized = false; | 272 | app.isMaximized = false; |
231 | }); | 273 | }); |
232 | 274 | ||
233 | mainWindow.on('restore', () => { | 275 | mainWindow.on('restore', () => { |
276 | debug('Window: restore'); | ||
234 | mainWindow.setSkipTaskbar(false); | 277 | mainWindow.setSkipTaskbar(false); |
235 | 278 | ||
236 | if (app.wasMaximized) { | 279 | if (app.wasMaximized) { |
280 | debug('Window: was maximized before, maximize window'); | ||
237 | mainWindow.maximize(); | 281 | mainWindow.maximize(); |
238 | } | 282 | } |
239 | 283 | ||
240 | if (!settings.get('enableSystemTray')) { | 284 | if (!settings.get('enableSystemTray')) { |
285 | debug('Tray: hiding tray icon'); | ||
241 | trayIcon.hide(); | 286 | trayIcon.hide(); |
242 | } | 287 | } |
243 | }); | 288 | }); |
244 | 289 | ||
245 | mainWindow.on('show', () => { | 290 | mainWindow.on('show', () => { |
291 | debug('Skip taskbar: false'); | ||
246 | mainWindow.setSkipTaskbar(false); | 292 | mainWindow.setSkipTaskbar(false); |
247 | }); | 293 | }); |
248 | 294 | ||
@@ -250,23 +296,53 @@ const createWindow = () => { | |||
250 | app.isMaximized = mainWindow.isMaximized(); | 296 | app.isMaximized = mainWindow.isMaximized(); |
251 | 297 | ||
252 | mainWindow.webContents.on('new-window', (e, url) => { | 298 | mainWindow.webContents.on('new-window', (e, url) => { |
299 | debug('Open url', url); | ||
253 | e.preventDefault(); | 300 | e.preventDefault(); |
254 | shell.openExternal(url); | 301 | |
302 | if (isValidExternalURL(url)) { | ||
303 | shell.openExternal(url); | ||
304 | } | ||
255 | }); | 305 | }); |
256 | }; | 306 | }; |
257 | 307 | ||
308 | // Allow passing command line parameters/switches to electron | ||
309 | // https://electronjs.org/docs/api/chrome-command-line-switches | ||
310 | // used for Kerberos support | ||
311 | // Usage e.g. MACOS | ||
312 | // $ Franz.app/Contents/MacOS/Franz --auth-server-whitelist *.mydomain.com --auth-negotiate-delegate-whitelist *.mydomain.com | ||
313 | const argv = require('minimist')(process.argv.slice(1)); | ||
314 | |||
315 | if (argv['auth-server-whitelist']) { | ||
316 | app.commandLine.appendSwitch('auth-server-whitelist', argv['auth-server-whitelist']); | ||
317 | } | ||
318 | if (argv['auth-negotiate-delegate-whitelist']) { | ||
319 | app.commandLine.appendSwitch('auth-negotiate-delegate-whitelist', argv['auth-negotiate-delegate-whitelist']); | ||
320 | } | ||
321 | |||
258 | // This method will be called when Electron has finished | 322 | // This method will be called when Electron has finished |
259 | // initialization and is ready to create browser windows. | 323 | // initialization and is ready to create browser windows. |
260 | // Some APIs can only be used after this event occurs. | 324 | // Some APIs can only be used after this event occurs. |
261 | app.on('ready', () => { | 325 | app.on('ready', () => { |
326 | // Register App URL | ||
327 | app.setAsDefaultProtocolClient('franz'); | ||
328 | |||
329 | if (isDevMode) { | ||
330 | app.setAsDefaultProtocolClient('franz-dev'); | ||
331 | } | ||
332 | |||
262 | if (process.platform === 'win32') { | 333 | if (process.platform === 'win32') { |
263 | app.setUserTasks([{ | 334 | app.setUserTasks([{ |
264 | program: process.execPath, | 335 | program: process.execPath, |
265 | arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`, | 336 | arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`, |
266 | iconPath: path.join(`${__dirname}`, '../src/assets/images/taskbar/win32/display.ico'), | 337 | iconPath: asarPath(path.join(isDevMode ? `${__dirname}../src/` : __dirname, 'assets/images/taskbar/win32/display.ico')), |
267 | iconIndex: 0, | 338 | iconIndex: 0, |
268 | title: 'Move Franz to Current Display', | 339 | title: 'Move Franz to Current Display', |
269 | description: 'Restore the position and size of Franz', | 340 | description: 'Restore the position and size of Franz', |
341 | }, { | ||
342 | program: process.execPath, | ||
343 | arguments: `${isDevMode ? `${__dirname} ` : ''}--quit`, | ||
344 | iconIndex: 0, | ||
345 | title: 'Quit Franz', | ||
270 | }]); | 346 | }]); |
271 | } | 347 | } |
272 | 348 | ||
@@ -317,7 +393,10 @@ app.on('window-all-closed', () => { | |||
317 | // to stay active until the user quits explicitly with Cmd + Q | 393 | // to stay active until the user quits explicitly with Cmd + Q |
318 | if (settings.get('runInBackground') === undefined | 394 | if (settings.get('runInBackground') === undefined |
319 | || settings.get('runInBackground')) { | 395 | || settings.get('runInBackground')) { |
396 | debug('Window: all windows closed, quit app'); | ||
320 | app.quit(); | 397 | app.quit(); |
398 | } else { | ||
399 | debug('Window: don\'t quit app'); | ||
321 | } | 400 | } |
322 | }); | 401 | }); |
323 | 402 | ||
@@ -336,13 +415,13 @@ app.on('activate', () => { | |||
336 | }); | 415 | }); |
337 | 416 | ||
338 | app.on('will-finish-launching', () => { | 417 | app.on('will-finish-launching', () => { |
339 | // Protocol handler for osx | 418 | // Protocol handler for macOS |
340 | app.on('open-url', (event, url) => { | 419 | app.on('open-url', (event, url) => { |
341 | event.preventDefault(); | 420 | event.preventDefault(); |
342 | console.log(`open-url event: ${url}`); | 421 | |
343 | handleDeepLink(mainWindow, url); | 422 | onDidLoad((window) => { |
423 | debug('open-url event', url); | ||
424 | handleDeepLink(window, url); | ||
425 | }); | ||
344 | }); | 426 | }); |
345 | }); | 427 | }); |
346 | |||
347 | // Register App URL | ||
348 | app.setAsDefaultProtocolClient('franz'); | ||