UNPKG

27.9 kBJavaScriptView Raw
1"use strict";
2// *****************************************************************************
3// Copyright (C) 2020 Ericsson and others.
4//
5// This program and the accompanying materials are made available under the
6// terms of the Eclipse Public License v. 2.0 which is available at
7// http://www.eclipse.org/legal/epl-2.0.
8//
9// This Source Code may also be made available under the following Secondary
10// Licenses when the conditions for such availability set forth in the Eclipse
11// Public License v. 2.0 are satisfied: GNU General Public License, version 2
12// with the GNU Classpath Exception which is available at
13// https://www.gnu.org/software/classpath/license.html.
14//
15// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16// *****************************************************************************
17var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
18 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21 return c > 3 && r && Object.defineProperty(target, key, r), r;
22};
23var __metadata = (this && this.__metadata) || function (k, v) {
24 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25};
26Object.defineProperty(exports, "__esModule", { value: true });
27exports.ElectronMainApplication = exports.ElectronMainProcessArgv = exports.ElectronMainApplicationContribution = exports.ElectronMainApplicationGlobals = void 0;
28const inversify_1 = require("inversify");
29const electron_1 = require("../../electron-shared/electron");
30const path = require("path");
31const fs_1 = require("fs");
32const child_process_1 = require("child_process");
33const application_props_1 = require("@theia/application-package/lib/application-props");
34const file_uri_1 = require("../node/file-uri");
35const promise_util_1 = require("../common/promise-util");
36const contribution_provider_1 = require("../common/contribution-provider");
37const electron_security_token_service_1 = require("./electron-security-token-service");
38const electron_token_1 = require("../electron-common/electron-token");
39const Storage = require("electron-store");
40const common_1 = require("../common");
41const window_1 = require("../common/window");
42const theia_electron_window_1 = require("./theia-electron-window");
43const electron_main_constants_1 = require("./electron-main-constants");
44Object.defineProperty(exports, "ElectronMainApplicationGlobals", { enumerable: true, get: function () { return electron_main_constants_1.ElectronMainApplicationGlobals; } });
45const event_utils_1 = require("./event-utils");
46const electron_api_main_1 = require("./electron-api-main");
47const frontend_application_state_1 = require("../common/frontend-application-state");
48const dynamic_require_1 = require("../node/dynamic-require");
49const createYargs = require('yargs/yargs');
50/**
51 * The default entrypoint will handle a very rudimentary CLI to open workspaces by doing `app path/to/workspace`. To override this behavior, you can extend and rebind the
52 * `ElectronMainApplication` class and overriding the `launch` method.
53 * A JSON-RPC communication between the Electron Main Process and the Renderer Processes is available: You can bind services using the `ElectronConnectionHandler` and
54 * `ElectronIpcConnectionProvider` APIs, example:
55 *
56 * From an `electron-main` module:
57 *
58 * bind(ElectronConnectionHandler).toDynamicValue(context =>
59 * new RpcConnectionHandler(electronMainWindowServicePath,
60 * () => context.container.get(ElectronMainWindowService))
61 * ).inSingletonScope();
62 *
63 * And from the `electron-browser` module:
64 *
65 * bind(ElectronMainWindowService).toDynamicValue(context =>
66 * ElectronIpcConnectionProvider.createProxy(context.container, electronMainWindowServicePath)
67 * ).inSingletonScope();
68 */
69exports.ElectronMainApplicationContribution = Symbol('ElectronMainApplicationContribution');
70// Extracted and modified the functionality from `yargs@15.4.0-beta.0`.
71// Based on https://github.com/yargs/yargs/blob/522b019c9a50924605986a1e6e0cb716d47bcbca/lib/process-argv.ts
72let ElectronMainProcessArgv = class ElectronMainProcessArgv {
73 get processArgvBinIndex() {
74 // The binary name is the first command line argument for:
75 // - bundled Electron apps: bin argv1 argv2 ... argvn
76 if (this.isBundledElectronApp) {
77 return 0;
78 }
79 // or the second one (default) for:
80 // - standard node apps: node bin.js argv1 argv2 ... argvn
81 // - unbundled Electron apps: electron bin.js argv1 arg2 ... argvn
82 return 1;
83 }
84 get isBundledElectronApp() {
85 // process.defaultApp is either set by electron in an electron unbundled app, or undefined
86 // see https://github.com/electron/electron/blob/master/docs/api/process.md#processdefaultapp-readonly
87 return this.isElectronApp && !process.defaultApp;
88 }
89 get isElectronApp() {
90 // process.versions.electron is either set by electron, or undefined
91 // see https://github.com/electron/electron/blob/master/docs/api/process.md#processversionselectron-readonly
92 return !!process.versions.electron;
93 }
94 getProcessArgvWithoutBin(argv = process.argv) {
95 return argv.slice(this.processArgvBinIndex + 1);
96 }
97 getProcessArgvBin(argv = process.argv) {
98 return argv[this.processArgvBinIndex];
99 }
100};
101ElectronMainProcessArgv = __decorate([
102 (0, inversify_1.injectable)()
103], ElectronMainProcessArgv);
104exports.ElectronMainProcessArgv = ElectronMainProcessArgv;
105let ElectronMainApplication = class ElectronMainApplication {
106 constructor() {
107 this.electronStore = new Storage();
108 this._backendPort = new promise_util_1.Deferred();
109 this.backendPort = this._backendPort.promise;
110 this.useNativeWindowFrame = true;
111 this.didUseNativeWindowFrameOnStart = new Map();
112 this.windows = new Map();
113 this.restarting = false;
114 }
115 get config() {
116 if (!this._config) {
117 throw new Error('You have to start the application first.');
118 }
119 return this._config;
120 }
121 async start(config) {
122 this.useNativeWindowFrame = this.getTitleBarStyle(config) === 'native';
123 this._config = config;
124 this.hookApplicationEvents();
125 this.showInitialWindow();
126 const port = await this.startBackend();
127 this._backendPort.resolve(port);
128 await electron_1.app.whenReady();
129 await this.attachElectronSecurityToken(port);
130 await this.startContributions();
131 await this.launch({
132 secondInstance: false,
133 argv: this.processArgv.getProcessArgvWithoutBin(process.argv),
134 cwd: process.cwd()
135 });
136 }
137 getTitleBarStyle(config) {
138 var _a;
139 if (common_1.isOSX) {
140 return 'native';
141 }
142 const storedFrame = (_a = this.electronStore.get('windowstate')) === null || _a === void 0 ? void 0 : _a.frame;
143 if (storedFrame !== undefined) {
144 return !!storedFrame ? 'native' : 'custom';
145 }
146 if (config.preferences && config.preferences['window.titleBarStyle']) {
147 const titleBarStyle = config.preferences['window.titleBarStyle'];
148 if (titleBarStyle === 'native' || titleBarStyle === 'custom') {
149 return titleBarStyle;
150 }
151 }
152 return common_1.isWindows ? 'custom' : 'native';
153 }
154 setTitleBarStyle(webContents, style) {
155 this.useNativeWindowFrame = common_1.isOSX || style === 'native';
156 this.saveState(webContents);
157 }
158 setBackgroundColor(webContents, backgroundColor) {
159 this.customBackgroundColor = backgroundColor;
160 this.saveState(webContents);
161 }
162 saveState(webContents) {
163 const browserWindow = electron_1.BrowserWindow.fromWebContents(webContents);
164 if (browserWindow) {
165 this.saveWindowState(browserWindow);
166 }
167 else {
168 console.warn(`no BrowserWindow with id: ${webContents.id}`);
169 }
170 }
171 /**
172 * @param id the id of the WebContents of the BrowserWindow in question
173 * @returns 'native' or 'custom'
174 */
175 getTitleBarStyleAtStartup(webContents) {
176 return this.didUseNativeWindowFrameOnStart.get(webContents.id) ? 'native' : 'custom';
177 }
178 showInitialWindow() {
179 if (this.config.electron.showWindowEarly) {
180 electron_1.app.whenReady().then(async () => {
181 const options = await this.getLastWindowOptions();
182 this.initialWindow = await this.createWindow({ ...options });
183 this.initialWindow.show();
184 });
185 }
186 }
187 async launch(params) {
188 createYargs(params.argv, params.cwd)
189 .command('$0 [file]', false, cmd => cmd
190 .positional('file', { type: 'string' }), args => this.handleMainCommand(params, { file: args.file })).parse();
191 }
192 /**
193 * Use this rather than creating `BrowserWindow` instances from scratch, since some security parameters need to be set, this method will do it.
194 *
195 * @param options
196 */
197 async createWindow(asyncOptions = this.getDefaultTheiaWindowOptions()) {
198 let options = await asyncOptions;
199 options = this.avoidOverlap(options);
200 const electronWindow = this.windowFactory(options, this.config);
201 const id = electronWindow.window.webContents.id;
202 this.windows.set(id, electronWindow);
203 electronWindow.onDidClose(() => this.windows.delete(id));
204 electronWindow.window.on('maximize', () => electron_api_main_1.TheiaRendererAPI.sendWindowEvent(electronWindow.window.webContents, 'maximize'));
205 electronWindow.window.on('unmaximize', () => electron_api_main_1.TheiaRendererAPI.sendWindowEvent(electronWindow.window.webContents, 'unmaximize'));
206 electronWindow.window.on('focus', () => electron_api_main_1.TheiaRendererAPI.sendWindowEvent(electronWindow.window.webContents, 'focus'));
207 this.attachSaveWindowState(electronWindow.window);
208 this.configureNativeSecondaryWindowCreation(electronWindow.window);
209 return electronWindow.window;
210 }
211 async getLastWindowOptions() {
212 const previousWindowState = this.electronStore.get('windowstate');
213 const windowState = (previousWindowState === null || previousWindowState === void 0 ? void 0 : previousWindowState.screenLayout) === this.getCurrentScreenLayout()
214 ? previousWindowState
215 : this.getDefaultTheiaWindowOptions();
216 return {
217 frame: this.useNativeWindowFrame,
218 ...this.getDefaultOptions(),
219 ...windowState
220 };
221 }
222 avoidOverlap(options) {
223 const existingWindowsBounds = electron_1.BrowserWindow.getAllWindows().map(window => window.getBounds());
224 if (existingWindowsBounds.length > 0) {
225 while (existingWindowsBounds.some(window => window.x === options.x || window.y === options.y)) {
226 // if the window is maximized or in fullscreen, use the default window options.
227 if (options.isMaximized || options.isFullScreen) {
228 options = this.getDefaultTheiaWindowOptions();
229 }
230 options.x = options.x + 30;
231 options.y = options.y + 30;
232 }
233 }
234 return options;
235 }
236 getDefaultOptions() {
237 var _a, _b;
238 return {
239 show: false,
240 title: this.config.applicationName,
241 backgroundColor: application_props_1.DefaultTheme.defaultBackgroundColor(((_a = this.config.electron.windowOptions) === null || _a === void 0 ? void 0 : _a.darkTheme) || electron_1.nativeTheme.shouldUseDarkColors),
242 minWidth: 200,
243 minHeight: 120,
244 webPreferences: {
245 // `global` is undefined when `true`.
246 contextIsolation: true,
247 sandbox: false,
248 nodeIntegration: false,
249 // Setting the following option to `true` causes some features to break, somehow.
250 // Issue: https://github.com/eclipse-theia/theia/issues/8577
251 nodeIntegrationInWorker: false,
252 preload: path.resolve(this.globals.THEIA_APP_PROJECT_PATH, 'lib', 'frontend', 'preload.js').toString()
253 },
254 ...((_b = this.config.electron) === null || _b === void 0 ? void 0 : _b.windowOptions) || {},
255 };
256 }
257 async openDefaultWindow(params) {
258 const options = this.getDefaultTheiaWindowOptions();
259 const [uri, electronWindow] = await Promise.all([this.createWindowUri(params), this.reuseOrCreateWindow(options)]);
260 electronWindow.loadURL(uri.withFragment(window_1.DEFAULT_WINDOW_HASH).toString(true));
261 return electronWindow;
262 }
263 async openWindowWithWorkspace(workspacePath) {
264 const options = await this.getLastWindowOptions();
265 const [uri, electronWindow] = await Promise.all([this.createWindowUri(), this.reuseOrCreateWindow(options)]);
266 electronWindow.loadURL(uri.withFragment(encodeURI(workspacePath)).toString(true));
267 return electronWindow;
268 }
269 async reuseOrCreateWindow(asyncOptions) {
270 if (!this.initialWindow) {
271 return this.createWindow(asyncOptions);
272 }
273 // reset initial window after having it re-used once
274 const window = this.initialWindow;
275 this.initialWindow = undefined;
276 return window;
277 }
278 /** Configures native window creation, i.e. using window.open or links with target "_blank" in the frontend. */
279 configureNativeSecondaryWindowCreation(electronWindow) {
280 electronWindow.webContents.setWindowOpenHandler(() => {
281 const { minWidth, minHeight } = this.getDefaultOptions();
282 const options = {
283 ...this.getDefaultTheiaWindowBounds(),
284 // We always need the native window frame for now because the secondary window does not have Theia's title bar by default.
285 // In 'custom' title bar mode this would leave the window without any window controls (close, min, max)
286 // TODO set to this.useNativeWindowFrame when secondary windows support a custom title bar.
287 frame: true,
288 minWidth,
289 minHeight
290 };
291 if (!this.useNativeWindowFrame) {
292 // If the main window does not have a native window frame, do not show an icon in the secondary window's native title bar.
293 // The data url is a 1x1 transparent png
294 options.icon = electron_1.nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQI12P4DwQACfsD/WMmxY8AAAAASUVORK5CYII=');
295 }
296 return {
297 action: 'allow',
298 overrideBrowserWindowOptions: options,
299 };
300 });
301 }
302 /**
303 * "Gently" close all windows, application will not stop if a `beforeunload` handler returns `false`.
304 */
305 requestStop() {
306 electron_1.app.quit();
307 }
308 async handleMainCommand(params, options) {
309 if (params.secondInstance === false) {
310 await this.openWindowWithWorkspace(''); // restore previous workspace.
311 }
312 else if (options.file === undefined) {
313 await this.openDefaultWindow();
314 }
315 else {
316 let workspacePath;
317 try {
318 workspacePath = await fs_1.promises.realpath(path.resolve(params.cwd, options.file));
319 }
320 catch {
321 console.error(`Could not resolve the workspace path. "${options.file}" is not a valid 'file' option. Falling back to the default workspace location.`);
322 }
323 if (workspacePath === undefined) {
324 await this.openDefaultWindow();
325 }
326 else {
327 await this.openWindowWithWorkspace(workspacePath);
328 }
329 }
330 }
331 async createWindowUri(params = {}) {
332 if (!('port' in params)) {
333 params.port = (await this.backendPort).toString();
334 }
335 const query = Object.entries(params).map(([name, value]) => `${name}=${value}`).join('&');
336 return file_uri_1.FileUri.create(this.globals.THEIA_FRONTEND_HTML_PATH)
337 .withQuery(query);
338 }
339 getDefaultTheiaWindowOptions() {
340 return {
341 frame: this.useNativeWindowFrame,
342 isFullScreen: false,
343 isMaximized: false,
344 ...this.getDefaultTheiaWindowBounds(),
345 ...this.getDefaultOptions()
346 };
347 }
348 getDefaultTheiaWindowBounds() {
349 // The `screen` API must be required when the application is ready.
350 // See: https://electronjs.org/docs/api/screen#screen
351 // We must center by hand because `browserWindow.center()` fails on multi-screen setups
352 // See: https://github.com/electron/electron/issues/3490
353 const { bounds } = electron_1.screen.getDisplayNearestPoint(electron_1.screen.getCursorScreenPoint());
354 const height = Math.round(bounds.height * (2 / 3));
355 const width = Math.round(bounds.width * (2 / 3));
356 const y = Math.round(bounds.y + (bounds.height - height) / 2);
357 const x = Math.round(bounds.x + (bounds.width - width) / 2);
358 return {
359 width,
360 height,
361 x,
362 y
363 };
364 }
365 /**
366 * Save the window geometry state on every change.
367 */
368 attachSaveWindowState(electronWindow) {
369 const windowStateListeners = new common_1.DisposableCollection();
370 let delayedSaveTimeout;
371 const saveWindowStateDelayed = () => {
372 if (delayedSaveTimeout) {
373 clearTimeout(delayedSaveTimeout);
374 }
375 delayedSaveTimeout = setTimeout(() => this.saveWindowState(electronWindow), 1000);
376 };
377 (0, event_utils_1.createDisposableListener)(electronWindow, 'close', () => {
378 this.saveWindowState(electronWindow);
379 }, windowStateListeners);
380 (0, event_utils_1.createDisposableListener)(electronWindow, 'resize', saveWindowStateDelayed, windowStateListeners);
381 (0, event_utils_1.createDisposableListener)(electronWindow, 'move', saveWindowStateDelayed, windowStateListeners);
382 windowStateListeners.push(common_1.Disposable.create(() => { try {
383 this.didUseNativeWindowFrameOnStart.delete(electronWindow.webContents.id);
384 }
385 catch { } }));
386 this.didUseNativeWindowFrameOnStart.set(electronWindow.webContents.id, this.useNativeWindowFrame);
387 electronWindow.once('closed', () => windowStateListeners.dispose());
388 }
389 saveWindowState(electronWindow) {
390 // In some circumstances the `electronWindow` can be `null`
391 if (!electronWindow) {
392 return;
393 }
394 try {
395 const bounds = electronWindow.getBounds();
396 const options = {
397 isFullScreen: electronWindow.isFullScreen(),
398 isMaximized: electronWindow.isMaximized(),
399 width: bounds.width,
400 height: bounds.height,
401 x: bounds.x,
402 y: bounds.y,
403 frame: this.useNativeWindowFrame,
404 screenLayout: this.getCurrentScreenLayout(),
405 backgroundColor: this.customBackgroundColor
406 };
407 this.electronStore.set('windowstate', options);
408 }
409 catch (e) {
410 console.error('Error while saving window state:', e);
411 }
412 }
413 /**
414 * Return a string unique to the current display layout.
415 */
416 getCurrentScreenLayout() {
417 return electron_1.screen.getAllDisplays().map(display => `${display.bounds.x}:${display.bounds.y}:${display.bounds.width}:${display.bounds.height}`).sort().join('-');
418 }
419 /**
420 * Start the NodeJS backend server.
421 *
422 * @return Running server's port promise.
423 */
424 async startBackend() {
425 // Check if we should run everything as one process.
426 const noBackendFork = process.argv.indexOf('--no-cluster') !== -1;
427 // We cannot use the `process.cwd()` as the application project path (the location of the `package.json` in other words)
428 // in a bundled electron application because it depends on the way we start it. For instance, on OS X, these are a differences:
429 // https://github.com/eclipse-theia/theia/issues/3297#issuecomment-439172274
430 process.env.THEIA_APP_PROJECT_PATH = this.globals.THEIA_APP_PROJECT_PATH;
431 // Set the electron version for both the dev and the production mode. (https://github.com/eclipse-theia/theia/issues/3254)
432 // Otherwise, the forked backend processes will not know that they're serving the electron frontend.
433 process.env.THEIA_ELECTRON_VERSION = process.versions.electron;
434 if (noBackendFork) {
435 process.env[electron_token_1.ElectronSecurityToken] = JSON.stringify(this.electronSecurityToken);
436 // The backend server main file is supposed to export a promise resolving with the port used by the http(s) server.
437 (0, dynamic_require_1.dynamicRequire)(this.globals.THEIA_BACKEND_MAIN_PATH);
438 // @ts-expect-error
439 const address = await globalThis.serverAddress;
440 return address.port;
441 }
442 else {
443 const backendProcess = (0, child_process_1.fork)(this.globals.THEIA_BACKEND_MAIN_PATH, this.processArgv.getProcessArgvWithoutBin(), await this.getForkOptions());
444 return new Promise((resolve, reject) => {
445 // The backend server main file is also supposed to send the resolved http(s) server port via IPC.
446 backendProcess.on('message', (address) => {
447 resolve(address.port);
448 });
449 backendProcess.on('error', error => {
450 reject(error);
451 });
452 backendProcess.on('exit', () => {
453 reject(new Error('backend process exited'));
454 });
455 electron_1.app.on('quit', () => {
456 // Only issue a kill signal if the backend process is running.
457 // eslint-disable-next-line no-null/no-null
458 if (backendProcess.exitCode === null && backendProcess.signalCode === null) {
459 try {
460 // If we forked the process for the clusters, we need to manually terminate it.
461 // See: https://github.com/eclipse-theia/theia/issues/835
462 if (backendProcess.pid) {
463 process.kill(backendProcess.pid);
464 }
465 }
466 catch (error) {
467 // See https://man7.org/linux/man-pages/man2/kill.2.html#ERRORS
468 if (error.code === 'ESRCH') {
469 return;
470 }
471 throw error;
472 }
473 }
474 });
475 });
476 }
477 }
478 async getForkOptions() {
479 return {
480 // The backend must be a process group leader on UNIX in order to kill the tree later.
481 // See https://nodejs.org/api/child_process.html#child_process_options_detached
482 detached: process.platform !== 'win32',
483 env: {
484 ...process.env,
485 [electron_token_1.ElectronSecurityToken]: JSON.stringify(this.electronSecurityToken),
486 },
487 };
488 }
489 async attachElectronSecurityToken(port) {
490 await this.electronSecurityTokenService.setElectronSecurityTokenCookie(`http://localhost:${port}`);
491 }
492 hookApplicationEvents() {
493 electron_1.app.on('will-quit', this.onWillQuit.bind(this));
494 electron_1.app.on('second-instance', this.onSecondInstance.bind(this));
495 electron_1.app.on('window-all-closed', this.onWindowAllClosed.bind(this));
496 }
497 onWillQuit(event) {
498 this.stopContributions();
499 }
500 async onSecondInstance(event, argv, cwd) {
501 const electronWindows = electron_1.BrowserWindow.getAllWindows();
502 if (electronWindows.length > 0) {
503 const electronWindow = electronWindows[0];
504 if (electronWindow.isMinimized()) {
505 electronWindow.restore();
506 }
507 electronWindow.focus();
508 }
509 }
510 onWindowAllClosed(event) {
511 if (!this.restarting) {
512 this.requestStop();
513 }
514 }
515 async restart(webContents) {
516 this.restarting = true;
517 const wrapper = this.windows.get(webContents.id);
518 if (wrapper) {
519 const listener = wrapper.onDidClose(async () => {
520 listener.dispose();
521 await this.launch({
522 secondInstance: false,
523 argv: this.processArgv.getProcessArgvWithoutBin(process.argv),
524 cwd: process.cwd()
525 });
526 this.restarting = false;
527 });
528 // If close failed or was cancelled on this occasion, don't keep listening for it.
529 if (!await wrapper.close(frontend_application_state_1.StopReason.Restart)) {
530 listener.dispose();
531 }
532 }
533 }
534 async startContributions() {
535 const promises = [];
536 for (const contribution of this.contributions.getContributions()) {
537 if (contribution.onStart) {
538 promises.push(contribution.onStart(this));
539 }
540 }
541 await Promise.all(promises);
542 }
543 stopContributions() {
544 for (const contribution of this.contributions.getContributions()) {
545 if (contribution.onStop) {
546 contribution.onStop(this);
547 }
548 }
549 }
550};
551__decorate([
552 (0, inversify_1.inject)(contribution_provider_1.ContributionProvider),
553 (0, inversify_1.named)(exports.ElectronMainApplicationContribution),
554 __metadata("design:type", Object)
555], ElectronMainApplication.prototype, "contributions", void 0);
556__decorate([
557 (0, inversify_1.inject)(electron_main_constants_1.ElectronMainApplicationGlobals),
558 __metadata("design:type", Object)
559], ElectronMainApplication.prototype, "globals", void 0);
560__decorate([
561 (0, inversify_1.inject)(ElectronMainProcessArgv),
562 __metadata("design:type", ElectronMainProcessArgv)
563], ElectronMainApplication.prototype, "processArgv", void 0);
564__decorate([
565 (0, inversify_1.inject)(electron_security_token_service_1.ElectronSecurityTokenService),
566 __metadata("design:type", electron_security_token_service_1.ElectronSecurityTokenService)
567], ElectronMainApplication.prototype, "electronSecurityTokenService", void 0);
568__decorate([
569 (0, inversify_1.inject)(electron_token_1.ElectronSecurityToken),
570 __metadata("design:type", Object)
571], ElectronMainApplication.prototype, "electronSecurityToken", void 0);
572__decorate([
573 (0, inversify_1.inject)(theia_electron_window_1.TheiaElectronWindowFactory),
574 __metadata("design:type", Function)
575], ElectronMainApplication.prototype, "windowFactory", void 0);
576ElectronMainApplication = __decorate([
577 (0, inversify_1.injectable)()
578], ElectronMainApplication);
579exports.ElectronMainApplication = ElectronMainApplication;
580//# sourceMappingURL=electron-main-application.js.map
\No newline at end of file