init.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. 'use strict'
  2. const { Buffer } = require('buffer')
  3. const fs = require('fs')
  4. const path = require('path')
  5. const util = require('util')
  6. const Module = require('module')
  7. const v8 = require('v8')
  8. // We modified the original process.argv to let node.js load the init.js,
  9. // we need to restore it here.
  10. process.argv.splice(1, 1)
  11. // Clear search paths.
  12. require('../common/reset-search-paths')
  13. // Import common settings.
  14. require('@electron/internal/common/init')
  15. const globalPaths = Module.globalPaths
  16. // Expose public APIs.
  17. globalPaths.push(path.join(__dirname, 'api', 'exports'))
  18. if (process.platform === 'win32') {
  19. // Redirect node's console to use our own implementations, since node can not
  20. // handle console output when running as GUI program.
  21. const consoleLog = function (...args) {
  22. return process.log(util.format(...args) + '\n')
  23. }
  24. const streamWrite = function (chunk, encoding, callback) {
  25. if (Buffer.isBuffer(chunk)) {
  26. chunk = chunk.toString(encoding)
  27. }
  28. process.log(chunk)
  29. if (callback) {
  30. callback()
  31. }
  32. return true
  33. }
  34. console.log = console.error = console.warn = consoleLog
  35. process.stdout.write = process.stderr.write = streamWrite
  36. }
  37. // Don't quit on fatal error.
  38. process.on('uncaughtException', function (error) {
  39. // Do nothing if the user has a custom uncaught exception handler.
  40. if (process.listeners('uncaughtException').length > 1) {
  41. return
  42. }
  43. // Show error in GUI.
  44. const dialog = require('electron').dialog
  45. const stack = error.stack ? error.stack : `${error.name}: ${error.message}`
  46. const message = 'Uncaught Exception:\n' + stack
  47. dialog.showErrorBox('A JavaScript error occurred in the main process', message)
  48. })
  49. // Emit 'exit' event on quit.
  50. const { app } = require('electron')
  51. app.on('quit', function (event, exitCode) {
  52. process.emit('exit', exitCode)
  53. })
  54. if (process.platform === 'win32') {
  55. // If we are a Squirrel.Windows-installed app, set app user model ID
  56. // so that users don't have to do this.
  57. //
  58. // Squirrel packages are always of the form:
  59. //
  60. // PACKAGE-NAME
  61. // - Update.exe
  62. // - app-VERSION
  63. // - OUREXE.exe
  64. //
  65. // Squirrel itself will always set the shortcut's App User Model ID to the
  66. // form `com.squirrel.PACKAGE-NAME.OUREXE`. We need to call
  67. // app.setAppUserModelId with a matching identifier so that renderer processes
  68. // will inherit this value.
  69. const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe')
  70. if (fs.existsSync(updateDotExe)) {
  71. const packageDir = path.dirname(path.resolve(updateDotExe))
  72. const packageName = path.basename(packageDir).replace(/\s/g, '')
  73. const exeName = path.basename(process.execPath).replace(/\.exe$/i, '').replace(/\s/g, '')
  74. app.setAppUserModelId(`com.squirrel.${packageName}.${exeName}`)
  75. }
  76. }
  77. // Map process.exit to app.exit, which quits gracefully.
  78. process.exit = app.exit
  79. // Load the RPC server.
  80. require('@electron/internal/browser/rpc-server')
  81. // Load the guest view manager.
  82. require('@electron/internal/browser/guest-view-manager')
  83. require('@electron/internal/browser/guest-window-manager')
  84. // Now we try to load app's package.json.
  85. let packagePath = null
  86. let packageJson = null
  87. const searchPaths = ['app', 'app.asar', 'default_app.asar']
  88. for (packagePath of searchPaths) {
  89. try {
  90. packagePath = path.join(process.resourcesPath, packagePath)
  91. packageJson = require(path.join(packagePath, 'package.json'))
  92. break
  93. } catch (error) {
  94. continue
  95. }
  96. }
  97. if (packageJson == null) {
  98. process.nextTick(function () {
  99. return process.exit(1)
  100. })
  101. throw new Error('Unable to find a valid app')
  102. }
  103. // Set application's version.
  104. if (packageJson.version != null) {
  105. app.setVersion(packageJson.version)
  106. }
  107. // Set application's name.
  108. if (packageJson.productName != null) {
  109. app.setName(`${packageJson.productName}`.trim())
  110. } else if (packageJson.name != null) {
  111. app.setName(`${packageJson.name}`.trim())
  112. }
  113. // Set application's desktop name.
  114. if (packageJson.desktopName != null) {
  115. app.setDesktopName(packageJson.desktopName)
  116. } else {
  117. app.setDesktopName((app.getName()) + '.desktop')
  118. }
  119. // Set v8 flags
  120. if (packageJson.v8Flags != null) {
  121. v8.setFlagsFromString(packageJson.v8Flags)
  122. }
  123. app._setDefaultAppPaths(packagePath)
  124. // Load the chrome extension support.
  125. require('@electron/internal/browser/chrome-extension')
  126. const features = process.atomBinding('features')
  127. if (features.isDesktopCapturerEnabled()) {
  128. // Load internal desktop-capturer module.
  129. require('@electron/internal/browser/desktop-capturer')
  130. }
  131. // Load protocol module to ensure it is populated on app ready
  132. require('@electron/internal/browser/api/protocol')
  133. // Set main startup script of the app.
  134. const mainStartupScript = packageJson.main || 'index.js'
  135. const KNOWN_XDG_DESKTOP_VALUES = ['Pantheon', 'Unity:Unity7', 'pop:GNOME']
  136. function currentPlatformSupportsAppIndicator () {
  137. if (process.platform !== 'linux') return false
  138. const currentDesktop = process.env.XDG_CURRENT_DESKTOP
  139. if (!currentDesktop) return false
  140. if (KNOWN_XDG_DESKTOP_VALUES.includes(currentDesktop)) return true
  141. // ubuntu based or derived session (default ubuntu one, communitheme…) supports
  142. // indicator too.
  143. if (/ubuntu/ig.test(currentDesktop)) return true
  144. return false
  145. }
  146. // Workaround for electron/electron#5050 and electron/electron#9046
  147. if (currentPlatformSupportsAppIndicator()) {
  148. process.env.XDG_CURRENT_DESKTOP = 'Unity'
  149. }
  150. // Quit when all windows are closed and no other one is listening to this.
  151. app.on('window-all-closed', () => {
  152. if (app.listenerCount('window-all-closed') === 1) {
  153. app.quit()
  154. }
  155. })
  156. const { setDefaultApplicationMenu } = require('@electron/internal/browser/default-menu')
  157. // Create default menu.
  158. app.once('ready', setDefaultApplicationMenu)
  159. // Finally load app's main.js and transfer control to C++.
  160. Module._load(path.join(packagePath, mainStartupScript), Module, true)