aboutsummaryrefslogtreecommitdiffstats
path: root/src/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/index.js')
-rw-r--r--src/index.js161
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 7import isDevMode from 'electron-is-dev';
8import fs from 'fs-extra'; 8import fs from 'fs-extra';
9import path from 'path'; 9import path from 'path';
10import windowStateKeeper from 'electron-window-state'; 10import windowStateKeeper from 'electron-window-state';
11 11
12// Set app directory before loading user modules
13if (isDevMode) {
14 app.setPath('userData', path.join(app.getPath('appData'), 'FranzDev'));
15}
16
17/* eslint-disable import/first */
12import { 18import {
13 isDevMode,
14 isMac, 19 isMac,
15 isWindows, 20 isWindows,
16 isLinux, 21 isLinux,
17} from './environment'; 22} from './environment';
18
19import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; 23import { mainIpcHandler as basicAuthHandler } from './features/basicAuth';
20
21// DEV MODE: Save user data into FranzDev
22if (isDevMode) {
23 app.setPath('userData', path.join(app.getPath('appData'), 'FranzDev'));
24}
25/* eslint-disable import/first */
26import ipcApi from './electron/ipc-api'; 24import ipcApi from './electron/ipc-api';
27import Tray from './lib/Tray'; 25import Tray from './lib/Tray';
28import Settings from './electron/Settings'; 26import 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';
36import { asarPath } from './helpers/asar-helpers';
37import { isValidExternalURL } from './helpers/url-helpers';
38/* eslint-enable import/first */ 38/* eslint-enable import/first */
39 39
40const debug = require('debug')('Franz:App'); 40const debug = require('debug')('Franz:App');
@@ -44,6 +44,17 @@ const debug = require('debug')('Franz:App');
44let mainWindow; 44let mainWindow;
45let willQuitApp = false; 45let willQuitApp = false;
46 46
47// Register methods to be called once the window has been loaded.
48let onDidLoadFns = [];
49
50function 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
48fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); 59fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp'));
49fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json')); 60fs.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
313const argv = require('minimist')(process.argv.slice(1));
314
315if (argv['auth-server-whitelist']) {
316 app.commandLine.appendSwitch('auth-server-whitelist', argv['auth-server-whitelist']);
317}
318if (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.
261app.on('ready', () => { 325app.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
338app.on('will-finish-launching', () => { 417app.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
348app.setAsDefaultProtocolClient('franz');