123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- import { EventEmitter } from 'events';
- import * as fs from 'fs';
- import * as path from 'path';
- import type * as defaultMenuModule from '@electron/internal/browser/default-menu';
- import type * as url from 'url';
- import type * as v8 from 'v8';
- const Module = require('module') as NodeJS.ModuleInternal;
- // We modified the original process.argv to let node.js load the init.js,
- // we need to restore it here.
- process.argv.splice(1, 1);
- // Import common settings.
- require('@electron/internal/common/init');
- process._linkedBinding('electron_browser_event_emitter').setEventEmitterPrototype(EventEmitter.prototype);
- // Don't quit on fatal error.
- process.on('uncaughtException', function (error) {
- // Do nothing if the user has a custom uncaught exception handler.
- if (process.listenerCount('uncaughtException') > 1) {
- return;
- }
- // Show error in GUI.
- // We can't import { dialog } at the top of this file as this file is
- // responsible for setting up the require hook for the "electron" module
- // so we import it inside the handler down here
- import('electron')
- .then(({ dialog }) => {
- const stack = error.stack ? error.stack : `${error.name}: ${error.message}`;
- const message = 'Uncaught Exception:\n' + stack;
- dialog.showErrorBox('A JavaScript error occurred in the main process', message);
- });
- });
- // Emit 'exit' event on quit.
- const { app } = require('electron');
- app.on('quit', (_event, exitCode) => {
- process.emit('exit', exitCode);
- });
- if (process.platform === 'win32') {
- // If we are a Squirrel.Windows-installed app, set app user model ID
- // so that users don't have to do this.
- //
- // Squirrel packages are always of the form:
- //
- // PACKAGE-NAME
- // - Update.exe
- // - app-VERSION
- // - OUREXE.exe
- //
- // Squirrel itself will always set the shortcut's App User Model ID to the
- // form `com.squirrel.PACKAGE-NAME.OUREXE`. We need to call
- // app.setAppUserModelId with a matching identifier so that renderer processes
- // will inherit this value.
- const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe');
- if (fs.existsSync(updateDotExe)) {
- const packageDir = path.dirname(path.resolve(updateDotExe));
- const packageName = path.basename(packageDir).replaceAll(/\s/g, '');
- const exeName = path.basename(process.execPath).replace(/\.exe$/i, '').replaceAll(/\s/g, '');
- app.setAppUserModelId(`com.squirrel.${packageName}.${exeName}`);
- }
- }
- // Map process.exit to app.exit, which quits gracefully.
- process.exit = app.exit as () => never;
- // Load the RPC server.
- require('@electron/internal/browser/rpc-server');
- // Load the guest view manager.
- require('@electron/internal/browser/guest-view-manager');
- // Now we try to load app's package.json.
- const v8Util = process._linkedBinding('electron_common_v8_util');
- let packagePath = null;
- let packageJson = null;
- const searchPaths: string[] = v8Util.getHiddenValue(global, 'appSearchPaths');
- const searchPathsOnlyLoadASAR: boolean = v8Util.getHiddenValue(global, 'appSearchPathsOnlyLoadASAR');
- // Borrow the _getOrCreateArchive asar helper
- const getOrCreateArchive = process._getOrCreateArchive;
- delete process._getOrCreateArchive;
- if (process.resourcesPath) {
- for (packagePath of searchPaths) {
- try {
- packagePath = path.join(process.resourcesPath, packagePath);
- if (searchPathsOnlyLoadASAR) {
- if (!getOrCreateArchive?.(packagePath)) {
- continue;
- }
- }
- packageJson = Module._load(path.join(packagePath, 'package.json'));
- break;
- } catch {
- continue;
- }
- }
- }
- if (packageJson == null) {
- process.nextTick(function () {
- return process.exit(1);
- });
- throw new Error('Unable to find a valid app');
- }
- // Set application's version.
- if (packageJson.version != null) {
- app.setVersion(packageJson.version);
- }
- // Set application's name.
- if (packageJson.productName != null) {
- app.name = `${packageJson.productName}`.trim();
- } else if (packageJson.name != null) {
- app.name = `${packageJson.name}`.trim();
- }
- // Set application's desktop name.
- if (packageJson.desktopName != null) {
- app.setDesktopName(packageJson.desktopName);
- } else {
- app.setDesktopName(`${app.name}.desktop`);
- }
- // Set v8 flags, deliberately lazy load so that apps that do not use this
- // feature do not pay the price
- if (packageJson.v8Flags != null) {
- (require('v8') as typeof v8).setFlagsFromString(packageJson.v8Flags);
- }
- app.setAppPath(packagePath);
- // Load the chrome devtools support.
- require('@electron/internal/browser/devtools');
- // Load protocol module to ensure it is populated on app ready
- require('@electron/internal/browser/api/protocol');
- // Load web-contents module to ensure it is populated on app ready
- require('@electron/internal/browser/api/web-contents');
- // Load web-frame-main module to ensure it is populated on app ready
- require('@electron/internal/browser/api/web-frame-main');
- // Required because `new BrowserWindow` calls some WebContentsView stuff, so
- // the inheritance needs to be set up before that happens.
- require('@electron/internal/browser/api/web-contents-view');
- // Set main startup script of the app.
- const mainStartupScript = packageJson.main || 'index.js';
- const KNOWN_XDG_DESKTOP_VALUES = new Set(['Pantheon', 'Unity:Unity7', 'pop:GNOME']);
- function currentPlatformSupportsAppIndicator () {
- if (process.platform !== 'linux') return false;
- const currentDesktop = process.env.XDG_CURRENT_DESKTOP;
- if (!currentDesktop) return false;
- if (KNOWN_XDG_DESKTOP_VALUES.has(currentDesktop)) return true;
- // ubuntu based or derived session (default ubuntu one, communitheme…) supports
- // indicator too.
- if (/ubuntu/ig.test(currentDesktop)) return true;
- return false;
- }
- // Workaround for electron/electron#5050 and electron/electron#9046
- process.env.ORIGINAL_XDG_CURRENT_DESKTOP = process.env.XDG_CURRENT_DESKTOP;
- if (currentPlatformSupportsAppIndicator()) {
- process.env.XDG_CURRENT_DESKTOP = 'Unity';
- }
- // Quit when all windows are closed and no other one is listening to this.
- app.on('window-all-closed', () => {
- if (app.listenerCount('window-all-closed') === 1) {
- app.quit();
- }
- });
- const { setDefaultApplicationMenu } = require('@electron/internal/browser/default-menu') as typeof defaultMenuModule;
- // Create default menu.
- //
- // The |will-finish-launching| event is emitted before |ready| event, so default
- // menu is set before any user window is created.
- app.once('will-finish-launching', setDefaultApplicationMenu);
- const { appCodeLoaded } = process;
- delete process.appCodeLoaded;
- if (packagePath) {
- // Finally load app's main.js and transfer control to C++.
- if ((packageJson.type === 'module' && !mainStartupScript.endsWith('.cjs')) || mainStartupScript.endsWith('.mjs')) {
- const { loadESM } = __non_webpack_require__('internal/process/esm_loader');
- const main = (require('url') as typeof url).pathToFileURL(path.join(packagePath, mainStartupScript));
- loadESM(async (esmLoader: any) => {
- try {
- await esmLoader.import(main.toString(), undefined, Object.create(null));
- appCodeLoaded!();
- } catch (err) {
- appCodeLoaded!();
- process.emit('uncaughtException', err as Error);
- }
- });
- } else {
- // Call appCodeLoaded before just for safety, it doesn't matter here as _load is syncronous
- appCodeLoaded!();
- process._firstFileName = Module._resolveFilename(path.join(packagePath, mainStartupScript), null, false);
- Module._load(path.join(packagePath, mainStartupScript), Module, true);
- }
- } else {
- console.error('Failed to locate a valid package to load (app, app.asar or default_app.asar)');
- console.error('This normally means you\'ve damaged the Electron package somehow');
- appCodeLoaded!();
- }
|