UNPKG

@theia/core

Version:

Theia is a cloud & desktop IDE framework implemented in TypeScript.

185 lines • 8.63 kB
"use strict"; // ***************************************************************************** // Copyright (C) 2022 Ericsson and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 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; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TheiaElectronWindowFactory = exports.TheiaElectronWindow = exports.WindowApplicationConfig = exports.TheiaBrowserWindowOptions = void 0; const electron_messages_1 = require("../electron-common/messaging/electron-messages"); const electron_1 = require("../../electron-shared/electron"); const inversify_1 = require("../../shared/inversify"); const electron_main_constants_1 = require("./electron-main-constants"); const common_1 = require("../common"); const event_utils_1 = require("./event-utils"); const uri_1 = require("../common/uri"); const file_uri_1 = require("../node/file-uri"); exports.TheiaBrowserWindowOptions = Symbol('TheiaBrowserWindowOptions'); exports.WindowApplicationConfig = Symbol('WindowApplicationConfig'); let TheiaElectronWindow = class TheiaElectronWindow { constructor() { this.onDidCloseEmitter = new common_1.Emitter(); this.toDispose = new common_1.DisposableCollection(this.onDidCloseEmitter); this.closeIsConfirmed = false; this.applicationState = 'init'; } get onDidClose() { return this.onDidCloseEmitter.event; } get window() { return this._window; } init() { this._window = new electron_1.BrowserWindow(this.options); this._window.setMenuBarVisibility(false); this.attachReadyToShow(); this.restoreMaximizedState(); this.attachCloseListeners(); this.trackApplicationState(); this.attachReloadListener(); } /** * Only show the window when the content is ready. */ attachReadyToShow() { this._window.once('ready-to-show', () => this._window.show()); } attachCloseListeners() { (0, event_utils_1.createDisposableListener)(this._window, 'closed', () => { this.onDidCloseEmitter.fire(); this.dispose(); }, this.toDispose); (0, event_utils_1.createDisposableListener)(this._window, 'close', async (event) => { // User has already indicated that it is OK to close this window, or the window is being closed before it's ready. if (this.closeIsConfirmed || this.applicationState !== 'ready') { return; } event.preventDefault(); this.handleStopRequest(() => this.doCloseWindow(), electron_messages_1.StopReason.Close); }, this.toDispose); } doCloseWindow() { this.closeIsConfirmed = true; this._window.close(); } close(reason = electron_messages_1.StopReason.Close) { return this.handleStopRequest(() => this.doCloseWindow(), reason); } reload() { this.handleStopRequest(() => { this.applicationState = 'init'; this._window.reload(); }, electron_messages_1.StopReason.Reload); } async handleStopRequest(onSafeCallback, reason) { // Only confirm close to windows that have loaded our frontend. // Both the windows's URL and the FS path of the `index.html` should be converted to the "same" format to be able to compare them. (#11226) // Notes: // - Windows: file:///C:/path/to/somewhere vs file:///c%3A/path/to/somewhere // - macOS: file:///Applications/App%20Name.app/Contents vs /Applications/App Name.app/Contents // This URL string comes from electron, we can expect that this is properly encoded URL. For example, a space is `%20` const currentUrl = new uri_1.URI(this.window.webContents.getURL()).toString(); // THEIA_FRONTEND_HTML_PATH is an FS path, we have to covert to an encoded URI string. const frontendUri = file_uri_1.FileUri.create(this.globals.THEIA_FRONTEND_HTML_PATH).toString(); const safeToClose = !currentUrl.includes(frontendUri) || await this.checkSafeToStop(reason); if (safeToClose) { try { await onSafeCallback(); return true; } catch (e) { console.warn(`Request ${electron_messages_1.StopReason[reason]} failed.`, e); } } return false; } checkSafeToStop(reason) { const confirmChannel = `safe-to-close-${this._window.id}`; const cancelChannel = `notSafeToClose-${this._window.id}`; const temporaryDisposables = new common_1.DisposableCollection(); return new Promise(resolve => { this._window.webContents.send(electron_messages_1.CLOSE_REQUESTED_SIGNAL, { confirmChannel, cancelChannel, reason }); (0, event_utils_1.createDisposableListener)(electron_1.ipcMain, confirmChannel, (e) => { if (this.isSender(e)) { resolve(true); } }, temporaryDisposables); (0, event_utils_1.createDisposableListener)(electron_1.ipcMain, cancelChannel, (e) => { if (this.isSender(e)) { resolve(false); } }, temporaryDisposables); }).finally(() => temporaryDisposables.dispose()); } restoreMaximizedState() { if (this.options.isMaximized) { this._window.maximize(); } else { this._window.unmaximize(); } } trackApplicationState() { (0, event_utils_1.createDisposableListener)(electron_1.ipcMain, electron_messages_1.APPLICATION_STATE_CHANGE_SIGNAL, (e, state) => { if (this.isSender(e)) { this.applicationState = state; } }, this.toDispose); } attachReloadListener() { (0, event_utils_1.createDisposableListener)(electron_1.ipcMain, electron_messages_1.RELOAD_REQUESTED_SIGNAL, (e) => { if (this.isSender(e)) { this.reload(); } }, this.toDispose); } isSender(e) { return electron_1.BrowserWindow.fromId(e.sender.id) === this._window; } dispose() { this.toDispose.dispose(); } }; __decorate([ (0, inversify_1.inject)(exports.TheiaBrowserWindowOptions), __metadata("design:type", Object) ], TheiaElectronWindow.prototype, "options", void 0); __decorate([ (0, inversify_1.inject)(exports.WindowApplicationConfig), __metadata("design:type", Object) ], TheiaElectronWindow.prototype, "config", void 0); __decorate([ (0, inversify_1.inject)(electron_main_constants_1.ElectronMainApplicationGlobals), __metadata("design:type", Object) ], TheiaElectronWindow.prototype, "globals", void 0); __decorate([ (0, inversify_1.postConstruct)(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], TheiaElectronWindow.prototype, "init", null); TheiaElectronWindow = __decorate([ (0, inversify_1.injectable)() ], TheiaElectronWindow); exports.TheiaElectronWindow = TheiaElectronWindow; exports.TheiaElectronWindowFactory = Symbol('TheiaElectronWindowFactory'); //# sourceMappingURL=theia-electron-window.js.map