diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index e4c6e422..0eb96ab9 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -113,6 +113,9 @@ }, { "frontend": "lib/browser/boards/quick-open/boards-quick-open-module" + }, + { + "electronMain": "lib/electron-main/arduino-electron-main-module" } ] } diff --git a/arduino-ide-extension/scripts/download-examples.js b/arduino-ide-extension/scripts/download-examples.js index b58877ad..52005a1f 100644 --- a/arduino-ide-extension/scripts/download-examples.js +++ b/arduino-ide-extension/scripts/download-examples.js @@ -1,5 +1,8 @@ // @ts-check +// The version to use. +const version = '1.9.0'; + (async () => { const os = require('os'); @@ -10,14 +13,21 @@ const repository = path.join(os.tmpdir(), `${v4()}-arduino-examples`); if (shell.mkdir('-p', repository).code !== 0) { shell.exit(1); + process.exit(1); } - if (shell.exec(`git clone https://github.com/arduino/arduino.git --depth 1 ${repository}`).code !== 0) { + if (shell.exec(`git clone https://github.com/arduino/arduino-examples.git ${repository}`).code !== 0) { shell.exit(1); + process.exit(1); + } + + if (shell.exec(`git -C ${repository} checkout tags/${version} -b ${version}`).code !== 0) { + shell.exit(1); + process.exit(1); } const destination = path.join(__dirname, '..', 'Examples'); shell.mkdir('-p', destination); - shell.cp('-fR', path.join(repository, 'build', 'shared', 'examples', '*'), destination); + shell.cp('-fR', path.join(repository, 'examples', '*'), destination); })(); diff --git a/arduino-ide-extension/src/browser/contributions/contribution.ts b/arduino-ide-extension/src/browser/contributions/contribution.ts index b247798e..751bf2a8 100644 --- a/arduino-ide-extension/src/browser/contributions/contribution.ts +++ b/arduino-ide-extension/src/browser/contributions/contribution.ts @@ -1,7 +1,7 @@ import { inject, injectable, interfaces } from 'inversify'; import URI from '@theia/core/lib/common/uri'; import { ILogger } from '@theia/core/lib/common/logger'; -import { FileSystem } from '@theia/filesystem/lib/common'; +import { FileService } from '@theia/filesystem/lib/browser/file-service'; import { MaybePromise } from '@theia/core/lib/common/types'; import { LabelProvider } from '@theia/core/lib/browser/label-provider'; import { MessageService } from '@theia/core/lib/common/message-service'; @@ -59,8 +59,8 @@ export abstract class Contribution implements CommandContribution, MenuContribut @injectable() export abstract class SketchContribution extends Contribution { - @inject(FileSystem) - protected readonly fileSystem: FileSystem; + @inject(FileService) + protected readonly fileService: FileService; @inject(FileSystemExt) protected readonly fileSystemExt: FileSystemExt; diff --git a/arduino-ide-extension/src/browser/contributions/open-sketch-external.ts b/arduino-ide-extension/src/browser/contributions/open-sketch-external.ts index 10fb7290..b2711e96 100644 --- a/arduino-ide-extension/src/browser/contributions/open-sketch-external.ts +++ b/arduino-ide-extension/src/browser/contributions/open-sketch-external.ts @@ -1,5 +1,6 @@ import { injectable } from 'inversify'; import { remote } from 'electron'; +import URI from '@theia/core/lib/common/uri'; import { ArduinoMenus } from '../menu/arduino-menus'; import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry } from './contribution'; @@ -30,9 +31,9 @@ export class OpenSketchExternal extends SketchContribution { protected async openExternal(): Promise { const uri = await this.sketchServiceClient.currentSketchFile(); if (uri) { - const exists = this.fileSystem.exists(uri); + const exists = this.fileService.exists(new URI(uri)); if (exists) { - const fsPath = await this.fileSystem.getFsPath(uri); + const fsPath = await this.fileService.fsPath(new URI(uri)); if (fsPath) { remote.shell.showItemInFolder(fsPath); } diff --git a/arduino-ide-extension/src/browser/contributions/open-sketch.ts b/arduino-ide-extension/src/browser/contributions/open-sketch.ts index 4df217db..fd242ec1 100644 --- a/arduino-ide-extension/src/browser/contributions/open-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/open-sketch.ts @@ -115,7 +115,7 @@ export class OpenSketch extends SketchContribution { protected async selectSketch(): Promise { const config = await this.configService.getConfiguration(); - const defaultPath = await this.fileSystem.getFsPath(config.sketchDirUri); + const defaultPath = await this.fileService.fsPath(new URI(config.sketchDirUri)); const { filePaths } = await remote.dialog.showOpenDialog({ defaultPath, properties: ['createDirectory', 'openFile'], @@ -149,7 +149,7 @@ export class OpenSketch extends SketchContribution { }); if (response === 1) { // OK const newSketchUri = new URI(sketchFileUri).parent.resolve(name); - const exists = await this.fileSystem.exists(newSketchUri.toString()); + const exists = await this.fileService.exists(newSketchUri); if (exists) { await remote.dialog.showMessageBox({ type: 'error', @@ -158,8 +158,8 @@ export class OpenSketch extends SketchContribution { }); return undefined; } - await this.fileSystem.createFolder(newSketchUri.toString()); - await this.fileSystem.move(sketchFileUri, newSketchUri.resolve(nameWithExt).toString()); + await this.fileService.createFolder(newSketchUri); + await this.fileService.move(new URI(sketchFileUri), new URI(newSketchUri.resolve(nameWithExt).toString())); return this.sketchService.getSketchFolder(newSketchUri.toString()); } } diff --git a/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts b/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts index 26428b76..07bd5b98 100644 --- a/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts @@ -45,11 +45,11 @@ export class SaveAsSketch extends SketchContribution { // If target does not exist, propose a `directories.user`/${sketch.name} path // If target exists, propose `directories.user`/${sketch.name}_copy_${yyyymmddHHMMss} const sketchDirUri = new URI((await this.configService.getConfiguration()).sketchDirUri); - const exists = await this.fileSystem.exists(sketchDirUri.resolve(sketch.name).toString()); + const exists = await this.fileService.exists(sketchDirUri.resolve(sketch.name)); const defaultUri = exists ? sketchDirUri.resolve(sketchDirUri.resolve(`${sketch.name}_copy_${dateFormat(new Date(), 'yyyymmddHHMMss')}`).toString()) : sketchDirUri.resolve(sketch.name); - const defaultPath = await this.fileSystem.getFsPath(defaultUri.toString())!; + const defaultPath = await this.fileService.fsPath(defaultUri); const { filePath, canceled } = await remote.dialog.showSaveDialog({ title: 'Save sketch folder as...', defaultPath }); if (!filePath || canceled) { return false; @@ -61,7 +61,7 @@ export class SaveAsSketch extends SketchContribution { const workspaceUri = await this.sketchService.copy(sketch, { destinationUri }); if (workspaceUri && openAfterMove) { if (wipeOriginal) { - await this.fileSystem.delete(sketch.uri); + await this.fileService.delete(new URI(sketch.uri)); } this.workspaceService.open(new URI(workspaceUri), { preserveWindow: true }); } diff --git a/arduino-ide-extension/src/electron-main/arduino-electron-main-module.ts b/arduino-ide-extension/src/electron-main/arduino-electron-main-module.ts new file mode 100644 index 00000000..f8d37ed4 --- /dev/null +++ b/arduino-ide-extension/src/electron-main/arduino-electron-main-module.ts @@ -0,0 +1,8 @@ +import { ContainerModule } from 'inversify'; +import { ElectronMainApplication as TheiaElectronMainApplication } from '@theia/core/lib/electron-main/electron-main-application'; +import { ElectronMainApplication } from './theia/electron-main-application'; + +export default new ContainerModule((bind, unbind, isBound, rebind) => { + bind(ElectronMainApplication).toSelf().inSingletonScope(); + rebind(TheiaElectronMainApplication).toService(ElectronMainApplication); +}); diff --git a/arduino-ide-extension/src/electron-main/theia/electron-main-application.ts b/arduino-ide-extension/src/electron-main/theia/electron-main-application.ts new file mode 100644 index 00000000..746ca585 --- /dev/null +++ b/arduino-ide-extension/src/electron-main/theia/electron-main-application.ts @@ -0,0 +1,76 @@ +import { injectable } from 'inversify'; +import { app } from 'electron'; +import { fork } from 'child_process'; +import { AddressInfo } from 'net'; +import { ElectronSecurityToken } from '@theia/core/lib/electron-common/electron-token'; +import { ElectronMainApplication as TheiaElectronMainApplication, TheiaBrowserWindowOptions } from '@theia/core/lib/electron-main/electron-main-application'; + +@injectable() +export class ElectronMainApplication extends TheiaElectronMainApplication { + + protected async getDefaultBrowserWindowOptions(): Promise { + const options = await super.getDefaultBrowserWindowOptions(); + return { + ...options, + // Set and use a custom minimum window size: https://github.com/arduino/arduino-pro-ide/issues/337#issuecomment-687017281 + minWidth: 900, + minHeight: 800 + }; + } + + protected async startBackend(): Promise { + // Check if we should run everything as one process. + const noBackendFork = process.argv.indexOf('--no-cluster') !== -1; + // We cannot use the `process.cwd()` as the application project path (the location of the `package.json` in other words) + // in a bundled electron application because it depends on the way we start it. For instance, on OS X, these are a differences: + // https://github.com/eclipse-theia/theia/issues/3297#issuecomment-439172274 + process.env.THEIA_APP_PROJECT_PATH = this.globals.THEIA_APP_PROJECT_PATH; + // Set the electron version for both the dev and the production mode. (https://github.com/eclipse-theia/theia/issues/3254) + // Otherwise, the forked backend processes will not know that they're serving the electron frontend. + process.env.THEIA_ELECTRON_VERSION = process.versions.electron; + if (noBackendFork) { + process.env[ElectronSecurityToken] = JSON.stringify(this.electronSecurityToken); + // The backend server main file is supposed to export a promise resolving with the port used by the http(s) server. + const address: AddressInfo = await require(this.globals.THEIA_BACKEND_MAIN_PATH); + return address.port; + } else { + let args = this.processArgv.getProcessArgvWithoutBin(); + // https://github.com/eclipse-theia/theia/issues/8227 + if (process.platform === 'darwin') { + // https://github.com/electron/electron/issues/3657 + // https://stackoverflow.com/questions/10242115/os-x-strange-psn-command-line-parameter-when-launched-from-finder#comment102377986_10242200 + // macOS appends an extra `-psn_0_someNumber` arg if a file is opened from Finder after downloading from the Internet. + // "AppName" is an app downloaded from the Internet. Are you sure you want to open it? + args = args.filter(arg => !arg.startsWith('-psn')); + } + const backendProcess = fork( + this.globals.THEIA_BACKEND_MAIN_PATH, + args, + await this.getForkOptions(), + ); + return new Promise((resolve, reject) => { + // The backend server main file is also supposed to send the resolved http(s) server port via IPC. + backendProcess.on('message', (address: AddressInfo) => { + resolve(address.port); + }); + backendProcess.on('error', error => { + reject(error); + }); + app.on('quit', () => { + try { + // If we forked the process for the clusters, we need to manually terminate it. + // See: https://github.com/eclipse-theia/theia/issues/835 + process.kill(backendProcess.pid); + } catch (e) { + if (e.code === 'ESRCH') { + console.log('Could not terminate the backend process. It was not running.'); + return; + } + throw e; + } + }); + }); + } + } + +} diff --git a/arduino-ide-extension/src/node/sketches-service-impl.ts b/arduino-ide-extension/src/node/sketches-service-impl.ts index e97a39b1..c3d801b1 100644 --- a/arduino-ide-extension/src/node/sketches-service-impl.ts +++ b/arduino-ide-extension/src/node/sketches-service-impl.ts @@ -6,8 +6,8 @@ import { ncp } from 'ncp'; import { Stats } from 'fs'; import * as fs from './fs-extra'; import URI from '@theia/core/lib/common/uri'; +import { FileUri } from '@theia/core/lib/node'; import { isWindows } from '@theia/core/lib/common/os'; -import { FileUri, BackendApplicationContribution } from '@theia/core/lib/node'; import { ConfigService } from '../common/protocol/config-service'; import { SketchesService, Sketch } from '../common/protocol/sketches-service'; import { firstToLowerCase } from '../common/utils'; @@ -23,17 +23,11 @@ const prefix = '.arduinoProIDE-unsaved'; // TODO: `fs`: use async API @injectable() -export class SketchesServiceImpl implements SketchesService, BackendApplicationContribution { - - protected readonly temp = temp.track(); +export class SketchesServiceImpl implements SketchesService { @inject(ConfigService) protected readonly configService: ConfigService; - onStop(): void { - this.temp.cleanupSync(); - } - async getSketches(uri?: string): Promise { const sketches: Array = []; let fsPath: undefined | string; @@ -210,7 +204,7 @@ export class SketchesServiceImpl implements SketchesService, BackendApplicationC async cloneExample(uri: string): Promise { const sketch = await this.loadSketch(uri); const parentPath = await new Promise((resolve, reject) => { - this.temp.mkdir({ prefix }, (err, dirPath) => { + temp.mkdir({ prefix }, (err, dirPath) => { if (err) { reject(err); return; @@ -277,7 +271,7 @@ export class SketchesServiceImpl implements SketchesService, BackendApplicationC const monthNames = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']; const today = new Date(); const parentPath = await new Promise((resolve, reject) => { - this.temp.mkdir({ prefix }, (err, dirPath) => { + temp.mkdir({ prefix }, (err, dirPath) => { if (err) { reject(err); return; @@ -373,6 +367,11 @@ void loop() { if (!exists) { throw new Error(`Sketch does not exist: ${sketch}`); } + // Nothing to do when source and destination are the same. + if (sketch.uri === destinationUri) { + await this.loadSketch(sketch.uri); // Sanity check. + return sketch.uri; + } const destination = FileUri.fsPath(destinationUri); await new Promise((resolve, reject) => { ncp.ncp(source, destination, async error => { @@ -384,9 +383,7 @@ void loop() { try { const oldPath = path.join(destination, new URI(sketch.mainFileUri).path.base); const newPath = path.join(destination, `${newName}.ino`); - if (oldPath !== newPath) { - await fs.rename(oldPath, newPath); - } + await fs.rename(oldPath, newPath); await this.loadSketch(destinationUri); // Sanity check. resolve(); } catch (e) { diff --git a/electron/build/patch/electron-main.js b/electron/build/patch/electron-main.js deleted file mode 100644 index aab6623e..00000000 --- a/electron/build/patch/electron-main.js +++ /dev/null @@ -1,301 +0,0 @@ -// @ts-check - -// Useful for Electron/NW.js apps as GUI apps on macOS doesn't inherit the `$PATH` define -// in your dotfiles (.bashrc/.bash_profile/.zshrc/etc). -// https://github.com/electron/electron/issues/550#issuecomment-162037357 -// https://github.com/eclipse-theia/theia/pull/3534#issuecomment-439689082 -require('fix-path')(); - -// Workaround for https://github.com/electron/electron/issues/9225. Chrome has an issue where -// in certain locales (e.g. PL), image metrics are wrongly computed. We explicitly set the -// LC_NUMERIC to prevent this from happening (selects the numeric formatting category of the -// C locale, http://en.cppreference.com/w/cpp/locale/LC_categories). -if (process.env.LC_ALL) { - process.env.LC_ALL = 'C'; -} -process.env.LC_NUMERIC = 'C'; - -const { v4 } = require('uuid'); -const electron = require('electron'); -const { join, resolve } = require('path'); -const { fork } = require('child_process'); -const { app, dialog, shell, BrowserWindow, ipcMain, Menu, globalShortcut } = electron; -const { ElectronSecurityToken } = require('@theia/core/lib/electron-common/electron-token'); - -// Fix the window reloading issue, see: https://github.com/electron/electron/issues/22119 -app.allowRendererProcessReuse = false; - -const applicationName = `Arduino Pro IDE`; -const isSingleInstance = false; -const disallowReloadKeybinding = false; -const defaultWindowOptionsAdditions = {}; - - -if (isSingleInstance && !app.requestSingleInstanceLock()) { - // There is another instance running, exit now. The other instance will request focus. - app.quit(); - return; -} - -const nativeKeymap = require('native-keymap'); -const Storage = require('electron-store'); -const electronStore = new Storage(); - -const electronSecurityToken = { - value: v4(), -}; - -// Make it easy for renderer process to fetch the ElectronSecurityToken: -global[ElectronSecurityToken] = electronSecurityToken; - -app.on('ready', () => { - - // Explicitly set the app name to have better menu items on macOS. ("About", "Hide", and "Quit") - // See: https://github.com/electron-userland/electron-builder/issues/2468 - app.setName(applicationName); - - const { screen } = electron; - - // Remove the default electron menus, waiting for the application to set its own. - Menu.setApplicationMenu(Menu.buildFromTemplate([{ - role: 'help', submenu: [{ role: 'toggleDevTools' }] - }])); - - function createNewWindow(theUrl) { - - // We must center by hand because `browserWindow.center()` fails on multi-screen setups - // See: https://github.com/electron/electron/issues/3490 - const { bounds } = screen.getDisplayNearestPoint(screen.getCursorScreenPoint()); - const height = Math.floor(bounds.height * (2 / 3)); - const width = Math.floor(bounds.width * (2 / 3)); - - const y = Math.floor(bounds.y + (bounds.height - height) / 2); - const x = Math.floor(bounds.x + (bounds.width - width) / 2); - - const WINDOW_STATE = 'windowstate'; - const windowState = electronStore.get(WINDOW_STATE, { - width, height, x, y - }); - - const persistedWindowOptionsAdditions = electronStore.get('windowOptions', {}); - - const windowOptionsAdditions = { - ...defaultWindowOptionsAdditions, - ...persistedWindowOptionsAdditions - }; - - let windowOptions = { - show: false, - title: applicationName, - width: windowState.width, - height: windowState.height, - // Set and use a custom minimum window size: https://github.com/arduino/arduino-pro-ide/issues/337#issuecomment-687017281 - minWidth: 900, - minHeight: 800, - x: windowState.x, - y: windowState.y, - isMaximized: windowState.isMaximized, - ...windowOptionsAdditions, - webPreferences: { - nodeIntegration: true - } - }; - - // Always hide the window, we will show the window when it is ready to be shown in any case. - const newWindow = new BrowserWindow(windowOptions); - if (windowOptions.isMaximized) { - newWindow.maximize(); - } - newWindow.on('ready-to-show', () => newWindow.show()); - if (disallowReloadKeybinding) { - newWindow.on('focus', event => { - for (const accelerator of ['CmdOrCtrl+R', 'F5']) { - globalShortcut.register(accelerator, () => { }); - } - }); - newWindow.on('blur', event => globalShortcut.unregisterAll()); - } - - // Prevent calls to "window.open" from opening an ElectronBrowser window, - // and rather open in the OS default web browser. - newWindow.webContents.on('new-window', (event, url) => { - event.preventDefault(); - shell.openExternal(url); - }); - - // Save the window geometry state on every change - const saveWindowState = () => { - try { - let bounds; - if (newWindow.isMaximized()) { - bounds = electronStore.get(WINDOW_STATE, {}); - } else { - bounds = newWindow.getBounds(); - } - electronStore.set(WINDOW_STATE, { - isMaximized: newWindow.isMaximized(), - width: bounds.width, - height: bounds.height, - x: bounds.x, - y: bounds.y - }); - } catch (e) { - console.error("Error while saving window state.", e); - } - }; - let delayedSaveTimeout; - const saveWindowStateDelayed = () => { - if (delayedSaveTimeout) { - clearTimeout(delayedSaveTimeout); - } - delayedSaveTimeout = setTimeout(saveWindowState, 1000); - }; - newWindow.on('close', saveWindowState); - newWindow.on('resize', saveWindowStateDelayed); - newWindow.on('move', saveWindowStateDelayed); - - // Fired when a beforeunload handler tries to prevent the page unloading - newWindow.webContents.on('will-prevent-unload', async event => { - const { response } = await dialog.showMessageBox(newWindow, { - type: 'question', - buttons: ['Yes', 'No'], - title: 'Confirm', - message: 'Are you sure you want to quit?', - detail: 'Any unsaved changes will not be saved.' - }); - if (response === 0) { // 'Yes' - // This ignores the beforeunload callback, allowing the page to unload - event.preventDefault(); - } - }); - - // Notify the renderer process on keyboard layout change - nativeKeymap.onDidChangeKeyboardLayout(() => { - if (!newWindow.isDestroyed()) { - const newLayout = { - info: nativeKeymap.getCurrentKeyboardLayout(), - mapping: nativeKeymap.getKeyMap() - }; - newWindow.webContents.send('keyboardLayoutChanged', newLayout); - } - }); - - if (!!theUrl) { - newWindow.loadURL(theUrl); - } - return newWindow; - } - - app.on('window-all-closed', () => { - app.quit(); - }); - ipcMain.on('create-new-window', (event, url) => { - createNewWindow(url); - }); - ipcMain.on('open-external', (event, url) => { - shell.openExternal(url); - }); - ipcMain.on('set-window-options', (event, options) => { - electronStore.set('windowOptions', options); - }); - ipcMain.on('get-persisted-window-options-additions', event => { - event.returnValue = electronStore.get('windowOptions', {}); - }); - - // Check whether we are in bundled application or development mode. - // @ts-ignore - const devMode = process.defaultApp || /node_modules[/]electron[/]/.test(process.execPath); - // Check if we should run everything as one process. - const noBackendFork = process.argv.includes('--no-cluster'); - const mainWindow = createNewWindow(); - - if (isSingleInstance) { - app.on('second-instance', (event, commandLine, workingDirectory) => { - // Someone tried to run a second instance, we should focus our window. - if (mainWindow && !mainWindow.isDestroyed()) { - if (mainWindow.isMinimized()) { - mainWindow.restore(); - } - mainWindow.focus() - } - }) - } - - const setElectronSecurityToken = async port => { - await electron.session.defaultSession.cookies.set({ - url: `http://localhost:${port}/`, - name: ElectronSecurityToken, - value: JSON.stringify(electronSecurityToken), - httpOnly: true - }); - }; - - const loadMainWindow = port => { - if (!mainWindow.isDestroyed()) { - mainWindow.loadURL('file://' + join(__dirname, '../../lib/index.html') + '?port=' + port); - } - }; - - // We cannot use the `process.cwd()` as the application project path (the location of the `package.json` in other words) - // in a bundled electron application because it depends on the way we start it. For instance, on OS X, these are a differences: - // https://github.com/eclipse-theia/theia/issues/3297#issuecomment-439172274 - process.env.THEIA_APP_PROJECT_PATH = resolve(__dirname, '..', '..'); - - // Set the electron version for both the dev and the production mode. (https://github.com/eclipse-theia/theia/issues/3254) - // Otherwise, the forked backend processes will not know that they're serving the electron frontend. - // The forked backend should patch its `process.versions.electron` with this value if it is missing. - process.env.THEIA_ELECTRON_VERSION = process.versions.electron; - - const mainPath = join(__dirname, '..', 'backend', 'main'); - // We spawn a separate process for the backend for Express to not run in the Electron main process. - // See: https://github.com/eclipse-theia/theia/pull/7361#issuecomment-601272212 - // But when in debugging we want to run everything in the same process to make things easier. - if (noBackendFork) { - process.env[ElectronSecurityToken] = JSON.stringify(electronSecurityToken); - require(mainPath).then(async (address) => { - await setElectronSecurityToken(address.port); - loadMainWindow(address.port); - }).catch((error) => { - console.error(error); - app.exit(1); - }); - } else { - // We want to pass flags passed to the Electron app to the backend process. - // Quirk: When developing from sources, we execute Electron as `electron.exe electron-main.js ...args`, but when bundled, - // the command looks like `bundled-application.exe ...args`. - let args = process.argv.slice(devMode ? 2 : 1); - if (process.platform === 'darwin') { - // https://github.com/electron/electron/issues/3657 - // https://stackoverflow.com/questions/10242115/os-x-strange-psn-command-line-parameter-when-launched-from-finder#comment102377986_10242200 - // macOS appends an extra `-psn_0_someNumber` arg if a file is opened from Finder after downloading from the Internet. - // "AppName" is an app downloaded from the Internet. Are you sure you want to open it? - args = args.filter(arg => !arg.startsWith('-psn')); - } - const cp = fork(mainPath, args, { - env: Object.assign({ - [ElectronSecurityToken]: JSON.stringify(electronSecurityToken), - }, process.env) - }); - cp.on('message', async (address) => { - await setElectronSecurityToken(address.port); - loadMainWindow(address.port); - }); - cp.on('error', (error) => { - console.error(error); - app.exit(1); - }); - app.on('quit', () => { - // If we forked the process for the clusters, we need to manually terminate it. - // See: https://github.com/eclipse-theia/theia/issues/835 - try { - process.kill(cp.pid); - } catch (e) { - if (e.code === 'ESRCH') { - console.log('Could not terminate the backend process. It was not running.'); - return; - } - throw e; - } - }); - } -}); diff --git a/electron/build/template-package.json b/electron/build/template-package.json index a5e5deee..27b8cbf0 100644 --- a/electron/build/template-package.json +++ b/electron/build/template-package.json @@ -22,7 +22,7 @@ "package": "cross-env DEBUG=* && electron-builder --publish=never", "package:publish": "cross-env DEBUG=* && electron-builder --publish=always", "download:plugins": "theia download:plugins", - "patch": "ncp ./patch/electron-main.js ./src-gen/frontend/electron-main.js && ncp ./patch/main.js ./src-gen/backend/main.js" + "patch": "ncp ./patch/main.js ./src-gen/backend/main.js" }, "engines": { "node": ">=12.14.1 <13"