Migrate to block comments
This commit is contained in:
parent
630cd091a0
commit
403870a27e
44 changed files with 538 additions and 437 deletions
|
@ -34,13 +34,13 @@ app.setAppPath = (path) ->
|
|||
app.getAppPath = ->
|
||||
appPath
|
||||
|
||||
# Routes the events to webContents.
|
||||
### Routes the events to webContents. ###
|
||||
for name in ['login', 'certificate-error', 'select-client-certificate']
|
||||
do (name) ->
|
||||
app.on name, (event, webContents, args...) ->
|
||||
webContents.emit name, event, args...
|
||||
|
||||
# Deprecated.
|
||||
### Deprecated. ###
|
||||
app.getHomeDir = deprecate 'app.getHomeDir', 'app.getPath', ->
|
||||
@getPath 'home'
|
||||
app.getDataPath = deprecate 'app.getDataPath', 'app.getPath', ->
|
||||
|
@ -51,22 +51,23 @@ app.resolveProxy = deprecate 'app.resolveProxy', 'session.defaultSession.resolve
|
|||
session.defaultSession.resolveProxy url, callback
|
||||
deprecate.rename app, 'terminate', 'quit'
|
||||
deprecate.event app, 'finish-launching', 'ready', ->
|
||||
setImmediate => # give default app a chance to setup default menu.
|
||||
### give default app a chance to setup default menu. ###
|
||||
setImmediate =>
|
||||
@emit 'finish-launching'
|
||||
deprecate.event app, 'activate-with-no-open-windows', 'activate', (event, hasVisibleWindows) ->
|
||||
@emit 'activate-with-no-open-windows', event if not hasVisibleWindows
|
||||
deprecate.event app, 'select-certificate', 'select-client-certificate'
|
||||
|
||||
# Wrappers for native classes.
|
||||
### Wrappers for native classes. ###
|
||||
wrapDownloadItem = (downloadItem) ->
|
||||
# downloadItem is an EventEmitter.
|
||||
### downloadItem is an EventEmitter. ###
|
||||
downloadItem.__proto__ = EventEmitter.prototype
|
||||
# Deprecated.
|
||||
### Deprecated. ###
|
||||
deprecate.property downloadItem, 'url', 'getURL'
|
||||
deprecate.property downloadItem, 'filename', 'getFilename'
|
||||
deprecate.property downloadItem, 'mimeType', 'getMimeType'
|
||||
deprecate.rename downloadItem, 'getUrl', 'getURL'
|
||||
downloadItemBindings._setWrapDownloadItem wrapDownloadItem
|
||||
|
||||
# Only one App object pemitted.
|
||||
### Only one App object pemitted. ###
|
||||
module.exports = app
|
||||
|
|
|
@ -6,7 +6,7 @@ autoUpdater =
|
|||
else
|
||||
require './auto-updater/auto-updater-native'
|
||||
|
||||
# Deprecated.
|
||||
### Deprecated. ###
|
||||
deprecate.rename autoUpdater, 'setFeedUrl', 'setFeedURL'
|
||||
|
||||
module.exports = autoUpdater
|
||||
|
|
|
@ -28,14 +28,16 @@ class AutoUpdater extends EventEmitter
|
|||
return @emitError error if error?
|
||||
|
||||
{releaseNotes, version} = update
|
||||
# Following information is not available on Windows, so fake them.
|
||||
### Following information is not available on Windows, so fake them. ###
|
||||
date = new Date
|
||||
url = @updateURL
|
||||
|
||||
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
|
||||
|
||||
# Private: Emit both error object and message, this is to keep compatibility
|
||||
# with Old APIs.
|
||||
###
|
||||
Private: Emit both error object and message, this is to keep compatibility
|
||||
with Old APIs.
|
||||
###
|
||||
emitError: (message) ->
|
||||
@emit 'error', new Error(message), message
|
||||
|
||||
|
|
|
@ -2,17 +2,21 @@ fs = require 'fs'
|
|||
path = require 'path'
|
||||
{spawn} = require 'child_process'
|
||||
|
||||
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
|
||||
updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe
|
||||
### i.e. my-app/app-0.1.13/ ###
|
||||
appFolder = path.dirname process.execPath
|
||||
### i.e. my-app/Update.exe ###
|
||||
updateExe = path.resolve appFolder, '..', 'Update.exe'
|
||||
exeName = path.basename process.execPath
|
||||
|
||||
# Spawn a command and invoke the callback when it completes with an error
|
||||
# and the output from standard out.
|
||||
###
|
||||
Spawn a command and invoke the callback when it completes with an error
|
||||
and the output from standard out.
|
||||
###
|
||||
spawnUpdate = (args, detached, callback) ->
|
||||
try
|
||||
spawnedProcess = spawn updateExe, args, {detached}
|
||||
catch error
|
||||
# Shouldn't happen, but still guard it.
|
||||
### Shouldn't happen, but still guard it. ###
|
||||
process.nextTick -> callback error
|
||||
return
|
||||
|
||||
|
@ -26,27 +30,27 @@ spawnUpdate = (args, detached, callback) ->
|
|||
errorEmitted = true
|
||||
callback error
|
||||
spawnedProcess.on 'exit', (code, signal) ->
|
||||
# We may have already emitted an error.
|
||||
### We may have already emitted an error. ###
|
||||
return if errorEmitted
|
||||
|
||||
# Process terminated with error.
|
||||
### Process terminated with error. ###
|
||||
if code isnt 0
|
||||
return callback "Command failed: #{signal ? code}\n#{stderr}"
|
||||
|
||||
# Success.
|
||||
### Success. ###
|
||||
callback null, stdout
|
||||
|
||||
# Start an instance of the installed app.
|
||||
### Start an instance of the installed app. ###
|
||||
exports.processStart = (callback) ->
|
||||
spawnUpdate ['--processStart', exeName], true, ->
|
||||
|
||||
# Download the releases specified by the URL and write new results to stdout.
|
||||
### Download the releases specified by the URL and write new results to stdout. ###
|
||||
exports.download = (updateURL, callback) ->
|
||||
spawnUpdate ['--download', updateURL], false, (error, stdout) ->
|
||||
return callback(error) if error?
|
||||
|
||||
try
|
||||
# Last line of output is the JSON details about the releases
|
||||
### Last line of output is the JSON details about the releases ###
|
||||
json = stdout.trim().split('\n').pop()
|
||||
update = JSON.parse(json)?.releasesToApply?.pop?()
|
||||
catch
|
||||
|
@ -54,11 +58,11 @@ exports.download = (updateURL, callback) ->
|
|||
|
||||
callback null, update
|
||||
|
||||
# Update the application to the latest remote version specified by URL.
|
||||
### Update the application to the latest remote version specified by URL. ###
|
||||
exports.update = (updateURL, callback) ->
|
||||
spawnUpdate ['--update', updateURL], false, callback
|
||||
|
||||
# Is the Update.exe installed with the current application?
|
||||
### Is the Update.exe installed with the current application? ###
|
||||
exports.supported = ->
|
||||
try
|
||||
fs.accessSync updateExe, fs.R_OK
|
||||
|
|
|
@ -5,56 +5,61 @@
|
|||
BrowserWindow::__proto__ = EventEmitter.prototype
|
||||
|
||||
BrowserWindow::_init = ->
|
||||
{app} = require 'electron' # avoid recursive require.
|
||||
### avoid recursive require. ###
|
||||
{app} = require 'electron'
|
||||
|
||||
# Simulate the application menu on platforms other than OS X.
|
||||
### Simulate the application menu on platforms other than OS X. ###
|
||||
if process.platform isnt 'darwin'
|
||||
menu = app.getApplicationMenu()
|
||||
@setMenu menu if menu?
|
||||
|
||||
# Make new windows requested by links behave like "window.open"
|
||||
### Make new windows requested by links behave like "window.open" ###
|
||||
@webContents.on '-new-window', (event, url, frameName) ->
|
||||
options = show: true, width: 800, height: 600
|
||||
ipcMain.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
|
||||
|
||||
# window.resizeTo(...)
|
||||
# window.moveTo(...)
|
||||
###
|
||||
window.resizeTo(...)
|
||||
window.moveTo(...)
|
||||
###
|
||||
@webContents.on 'move', (event, size) =>
|
||||
@setBounds size
|
||||
|
||||
# Hide the auto-hide menu when webContents is focused.
|
||||
### Hide the auto-hide menu when webContents is focused. ###
|
||||
@webContents.on 'activate', =>
|
||||
if process.platform isnt 'darwin' and @isMenuBarAutoHide() and @isMenuBarVisible()
|
||||
@setMenuBarVisibility false
|
||||
|
||||
# Forward the crashed event.
|
||||
### Forward the crashed event. ###
|
||||
@webContents.on 'crashed', =>
|
||||
@emit 'crashed'
|
||||
|
||||
# Change window title to page title.
|
||||
### Change window title to page title. ###
|
||||
@webContents.on 'page-title-updated', (event, title, explicitSet) =>
|
||||
@emit 'page-title-updated', event, title
|
||||
@setTitle title unless event.defaultPrevented
|
||||
|
||||
# Sometimes the webContents doesn't get focus when window is shown, so we have
|
||||
# to force focusing on webContents in this case. The safest way is to focus it
|
||||
# when we first start to load URL, if we do it earlier it won't have effect,
|
||||
# if we do it later we might move focus in the page.
|
||||
# Though this hack is only needed on OS X when the app is launched from
|
||||
# Finder, we still do it on all platforms in case of other bugs we don't know.
|
||||
###
|
||||
Sometimes the webContents doesn't get focus when window is shown, so we have
|
||||
to force focusing on webContents in this case. The safest way is to focus it
|
||||
when we first start to load URL, if we do it earlier it won't have effect,
|
||||
if we do it later we might move focus in the page.
|
||||
Though this hack is only needed on OS X when the app is launched from
|
||||
Finder, we still do it on all platforms in case of other bugs we don't know.
|
||||
###
|
||||
@webContents.once 'load-url', ->
|
||||
@focus()
|
||||
|
||||
# Redirect focus/blur event to app instance too.
|
||||
### Redirect focus/blur event to app instance too. ###
|
||||
@on 'blur', (event) =>
|
||||
app.emit 'browser-window-blur', event, this
|
||||
@on 'focus', (event) =>
|
||||
app.emit 'browser-window-focus', event, this
|
||||
|
||||
# Notify the creation of the window.
|
||||
### Notify the creation of the window. ###
|
||||
app.emit 'browser-window-created', {}, this
|
||||
|
||||
# Be compatible with old APIs.
|
||||
### Be compatible with old APIs. ###
|
||||
@webContents.on 'devtools-focused', => @emit 'devtools-focused'
|
||||
@webContents.on 'devtools-opened', => @emit 'devtools-opened'
|
||||
@webContents.on 'devtools-closed', => @emit 'devtools-closed'
|
||||
|
@ -76,7 +81,7 @@ BrowserWindow.fromDevToolsWebContents = (webContents) ->
|
|||
windows = BrowserWindow.getAllWindows()
|
||||
return window for window in windows when window.devToolsWebContents?.equal webContents
|
||||
|
||||
# Helpers.
|
||||
### Helpers. ###
|
||||
BrowserWindow::loadURL = -> @webContents.loadURL.apply @webContents, arguments
|
||||
BrowserWindow::getURL = -> @webContents.getURL()
|
||||
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
|
||||
|
@ -89,7 +94,7 @@ BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools()
|
|||
BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments
|
||||
BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker()
|
||||
|
||||
# Deprecated.
|
||||
### Deprecated. ###
|
||||
deprecate.member BrowserWindow, 'undo', 'webContents'
|
||||
deprecate.member BrowserWindow, 'redo', 'webContents'
|
||||
deprecate.member BrowserWindow, 'cut', 'webContents'
|
||||
|
|
|
@ -16,12 +16,12 @@ messageBoxOptions =
|
|||
|
||||
parseArgs = (window, options, callback) ->
|
||||
unless window is null or window?.constructor is BrowserWindow
|
||||
# Shift.
|
||||
### Shift. ###
|
||||
callback = options
|
||||
options = window
|
||||
window = null
|
||||
if not callback? and typeof options is 'function'
|
||||
# Shift.
|
||||
### Shift. ###
|
||||
callback = options
|
||||
options = null
|
||||
[window, options, callback]
|
||||
|
@ -97,7 +97,7 @@ module.exports =
|
|||
options.icon ?= null
|
||||
options.defaultId ?= -1
|
||||
|
||||
# Choose a default button to get selected when dialog is cancelled.
|
||||
### Choose a default button to get selected when dialog is cancelled. ###
|
||||
unless options.cancelId?
|
||||
options.cancelId = 0
|
||||
for text, i in options.buttons
|
||||
|
@ -122,6 +122,6 @@ module.exports =
|
|||
showErrorBox: (args...) ->
|
||||
binding.showErrorBox args...
|
||||
|
||||
# Mark standard asynchronous functions.
|
||||
### Mark standard asynchronous functions. ###
|
||||
for api in ['showMessageBox', 'showOpenDialog', 'showSaveDialog']
|
||||
v8Util.setHiddenValue module.exports[api], 'asynchronous', true
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
common = require '../../../../common/api/lib/exports/electron'
|
||||
|
||||
# Import common modules.
|
||||
### Import common modules. ###
|
||||
common.defineProperties exports
|
||||
|
||||
Object.defineProperties exports,
|
||||
# Browser side modules, please sort with alphabet order.
|
||||
### Browser side modules, please sort with alphabet order. ###
|
||||
app:
|
||||
enumerable: true
|
||||
get: -> require '../app'
|
||||
|
@ -50,7 +50,7 @@ Object.defineProperties exports,
|
|||
Tray:
|
||||
enumerable: true
|
||||
get: -> require '../tray'
|
||||
# The internal modules, invisible unless you know their names.
|
||||
### The internal modules, invisible unless you know their names. ###
|
||||
NavigationController:
|
||||
get: -> require '../navigation-controller'
|
||||
webContents:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{deprecate, ipcMain} = require 'electron'
|
||||
|
||||
# This module is deprecated, we mirror everything from ipcMain.
|
||||
### This module is deprecated, we mirror everything from ipcMain. ###
|
||||
deprecate.warn 'ipc module', 'require("electron").ipcMain'
|
||||
|
||||
module.exports = ipcMain
|
||||
|
|
|
@ -2,7 +2,7 @@ v8Util = process.atomBinding 'v8_util'
|
|||
|
||||
nextCommandId = 0
|
||||
|
||||
# Maps role to methods of webContents
|
||||
### Maps role to methods of webContents ###
|
||||
rolesMap =
|
||||
undo: 'undo'
|
||||
redo: 'redo'
|
||||
|
@ -13,7 +13,7 @@ rolesMap =
|
|||
minimize: 'minimize'
|
||||
close: 'close'
|
||||
|
||||
# Maps methods that should be called directly on the BrowserWindow instance
|
||||
### Maps methods that should be called directly on the BrowserWindow instance ###
|
||||
methodInBrowserWindow =
|
||||
minimize: true
|
||||
close: true
|
||||
|
@ -46,7 +46,7 @@ class MenuItem
|
|||
|
||||
@commandId = ++nextCommandId
|
||||
@click = (focusedWindow) =>
|
||||
# Manually flip the checked flags when clicked.
|
||||
### Manually flip the checked flags when clicked. ###
|
||||
@checked = !@checked if @type in ['checkbox', 'radio']
|
||||
|
||||
if @role and rolesMap[@role] and process.platform isnt 'darwin' and focusedWindow?
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
v8Util = process.atomBinding 'v8_util'
|
||||
bindings = process.atomBinding 'menu'
|
||||
|
||||
# Automatically generated radio menu item's group id.
|
||||
### Automatically generated radio menu item's group id. ###
|
||||
nextGroupId = 0
|
||||
|
||||
# Search between seperators to find a radio menu item and return its group id,
|
||||
# otherwise generate a group id.
|
||||
### Search between seperators to find a radio menu item and return its group id, ###
|
||||
### otherwise generate a group id. ###
|
||||
generateGroupId = (items, pos) ->
|
||||
if pos > 0
|
||||
for i in [pos - 1..0]
|
||||
|
@ -22,12 +22,12 @@ generateGroupId = (items, pos) ->
|
|||
break if item.type is 'separator'
|
||||
++nextGroupId
|
||||
|
||||
# Returns the index of item according to |id|.
|
||||
### Returns the index of item according to |id|. ###
|
||||
indexOfItemById = (items, id) ->
|
||||
return i for item, i in items when item.id is id
|
||||
-1
|
||||
|
||||
# Returns the index of where to insert the item according to |position|.
|
||||
### Returns the index of where to insert the item according to |position|. ###
|
||||
indexToInsertByPosition = (items, position) ->
|
||||
return items.length unless position
|
||||
|
||||
|
@ -41,12 +41,12 @@ indexToInsertByPosition = (items, position) ->
|
|||
when 'after'
|
||||
insertIndex++
|
||||
when 'endof'
|
||||
# If the |id| doesn't exist, then create a new group with the |id|.
|
||||
### If the |id| doesn't exist, then create a new group with the |id|. ###
|
||||
if insertIndex is -1
|
||||
items.push id: id, type: 'separator'
|
||||
insertIndex = items.length - 1
|
||||
|
||||
# Find the end of the group.
|
||||
### Find the end of the group. ###
|
||||
insertIndex++
|
||||
while insertIndex < items.length and items[insertIndex].type isnt 'separator'
|
||||
insertIndex++
|
||||
|
@ -69,7 +69,7 @@ Menu::_init = ->
|
|||
executeCommand: (commandId) =>
|
||||
@commandsMap[commandId]?.click BrowserWindow.getFocusedWindow()
|
||||
menuWillShow: =>
|
||||
# Make sure radio groups have at least one menu item seleted.
|
||||
### Make sure radio groups have at least one menu item seleted. ###
|
||||
for id, group of @groupsMap
|
||||
checked = false
|
||||
for radioItem in group when radioItem.checked
|
||||
|
@ -79,7 +79,7 @@ Menu::_init = ->
|
|||
|
||||
Menu::popup = (window, x, y) ->
|
||||
unless window?.constructor is BrowserWindow
|
||||
# Shift.
|
||||
### Shift. ###
|
||||
y = x
|
||||
x = window
|
||||
window = BrowserWindow.getFocusedWindow()
|
||||
|
@ -100,12 +100,12 @@ Menu::insert = (pos, item) ->
|
|||
when 'separator' then @insertSeparator pos
|
||||
when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu
|
||||
when 'radio'
|
||||
# Grouping radio menu items.
|
||||
### Grouping radio menu items. ###
|
||||
item.overrideReadOnlyProperty 'groupId', generateGroupId(@items, pos)
|
||||
@groupsMap[item.groupId] ?= []
|
||||
@groupsMap[item.groupId].push item
|
||||
|
||||
# Setting a radio menu item should flip other items in the group.
|
||||
### Setting a radio menu item should flip other items in the group. ###
|
||||
v8Util.setHiddenValue item, 'checked', item.checked
|
||||
Object.defineProperty item, 'checked',
|
||||
enumerable: true
|
||||
|
@ -121,14 +121,14 @@ Menu::insert = (pos, item) ->
|
|||
@setIcon pos, item.icon if item.icon?
|
||||
@setRole pos, item.role if item.role?
|
||||
|
||||
# Make menu accessable to items.
|
||||
### Make menu accessable to items. ###
|
||||
item.overrideReadOnlyProperty 'menu', this
|
||||
|
||||
# Remember the items.
|
||||
### Remember the items. ###
|
||||
@items.splice pos, 0, item
|
||||
@commandsMap[item.commandId] = item
|
||||
|
||||
# Force menuWillShow to be called
|
||||
### Force menuWillShow to be called ###
|
||||
Menu::_callMenuWillShow = ->
|
||||
@delegate?.menuWillShow()
|
||||
item.submenu._callMenuWillShow() for item in @items when item.submenu?
|
||||
|
@ -136,7 +136,8 @@ Menu::_callMenuWillShow = ->
|
|||
applicationMenu = null
|
||||
Menu.setApplicationMenu = (menu) ->
|
||||
throw new TypeError('Invalid menu') unless menu is null or menu.constructor is Menu
|
||||
applicationMenu = menu # Keep a reference.
|
||||
### Keep a reference. ###
|
||||
applicationMenu = menu
|
||||
|
||||
if process.platform is 'darwin'
|
||||
return if menu is null
|
||||
|
@ -160,7 +161,7 @@ Menu.buildFromTemplate = (template) ->
|
|||
if item.position
|
||||
insertIndex = indexToInsertByPosition positionedTemplate, item.position
|
||||
else
|
||||
# If no |position| is specified, insert after last item.
|
||||
### If no |position| is specified, insert after last item. ###
|
||||
insertIndex++
|
||||
positionedTemplate.splice insertIndex, 0, item
|
||||
|
||||
|
|
|
@ -1,42 +1,47 @@
|
|||
{ipcMain} = require 'electron'
|
||||
|
||||
# The history operation in renderer is redirected to browser.
|
||||
### The history operation in renderer is redirected to browser. ###
|
||||
ipcMain.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) ->
|
||||
event.sender[method] args...
|
||||
|
||||
ipcMain.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) ->
|
||||
event.returnValue = event.sender[method] args...
|
||||
|
||||
# JavaScript implementation of Chromium's NavigationController.
|
||||
# Instead of relying on Chromium for history control, we compeletely do history
|
||||
# control on user land, and only rely on WebContents.loadURL for navigation.
|
||||
# This helps us avoid Chromium's various optimizations so we can ensure renderer
|
||||
# process is restarted everytime.
|
||||
###
|
||||
JavaScript implementation of Chromium's NavigationController.
|
||||
Instead of relying on Chromium for history control, we compeletely do history
|
||||
control on user land, and only rely on WebContents.loadURL for navigation.
|
||||
This helps us avoid Chromium's various optimizations so we can ensure renderer
|
||||
process is restarted everytime.
|
||||
###
|
||||
class NavigationController
|
||||
constructor: (@webContents) ->
|
||||
@clearHistory()
|
||||
|
||||
# webContents may have already navigated to a page.
|
||||
### webContents may have already navigated to a page. ###
|
||||
if @webContents._getURL()
|
||||
@currentIndex++
|
||||
@history.push @webContents._getURL()
|
||||
|
||||
@webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) =>
|
||||
if @inPageIndex > -1 and not inPage
|
||||
# Navigated to a new page, clear in-page mark.
|
||||
### Navigated to a new page, clear in-page mark. ###
|
||||
@inPageIndex = -1
|
||||
else if @inPageIndex is -1 and inPage
|
||||
# Started in-page navigations.
|
||||
### Started in-page navigations. ###
|
||||
@inPageIndex = @currentIndex
|
||||
|
||||
if @pendingIndex >= 0 # Go to index.
|
||||
if @pendingIndex >= 0
|
||||
### Go to index. ###
|
||||
@currentIndex = @pendingIndex
|
||||
@pendingIndex = -1
|
||||
@history[@currentIndex] = url
|
||||
else if replaceEntry # Non-user initialized navigation.
|
||||
else if replaceEntry
|
||||
### Non-user initialized navigation. ###
|
||||
@history[@currentIndex] = url
|
||||
else # Normal navigation.
|
||||
@history = @history.slice 0, @currentIndex + 1 # Clear history.
|
||||
else
|
||||
### Normal navigation. Clear history. ###
|
||||
@history = @history.slice 0, @currentIndex + 1
|
||||
currentEntry = @history[@currentIndex]
|
||||
if currentEntry?.url isnt url
|
||||
@currentIndex++
|
||||
|
|
|
@ -4,7 +4,7 @@ throw new Error('Can not initialize protocol module before app is ready') unless
|
|||
|
||||
{protocol} = process.atomBinding 'protocol'
|
||||
|
||||
# Warn about removed APIs.
|
||||
### Warn about removed APIs. ###
|
||||
logAndThrow = (callback, message) ->
|
||||
console.error message
|
||||
if callback then callback(new Error(message)) else throw new Error(message)
|
||||
|
|
|
@ -4,7 +4,7 @@ bindings = process.atomBinding 'session'
|
|||
|
||||
PERSIST_PERFIX = 'persist:'
|
||||
|
||||
# Returns the Session from |partition| string.
|
||||
### Returns the Session from |partition| string. ###
|
||||
exports.fromPartition = (partition='') ->
|
||||
return exports.defaultSession if partition is ''
|
||||
if partition.startsWith PERSIST_PERFIX
|
||||
|
@ -12,13 +12,13 @@ exports.fromPartition = (partition='') ->
|
|||
else
|
||||
bindings.fromPartition partition, true
|
||||
|
||||
# Returns the default session.
|
||||
### Returns the default session. ###
|
||||
Object.defineProperty exports, 'defaultSession',
|
||||
enumerable: true
|
||||
get: -> bindings.fromPartition '', false
|
||||
|
||||
wrapSession = (session) ->
|
||||
# session is an EventEmitter.
|
||||
### session is an EventEmitter. ###
|
||||
session.__proto__ = EventEmitter.prototype
|
||||
|
||||
bindings._setWrapSession wrapSession
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
Tray::__proto__ = EventEmitter.prototype
|
||||
|
||||
Tray::_init = ->
|
||||
# Deprecated.
|
||||
### Deprecated. ###
|
||||
deprecate.rename this, 'popContextMenu', 'popUpContextMenu'
|
||||
deprecate.event this, 'clicked', 'click'
|
||||
deprecate.event this, 'double-clicked', 'double-click'
|
||||
|
@ -14,6 +14,7 @@ Tray::_init = ->
|
|||
|
||||
Tray::setContextMenu = (menu) ->
|
||||
@_setContextMenu menu
|
||||
@menu = menu # Keep a strong reference of menu.
|
||||
### Keep a strong reference of menu. ###
|
||||
@menu = menu
|
||||
|
||||
module.exports = Tray
|
||||
|
|
|
@ -40,28 +40,30 @@ PDFPageSize =
|
|||
custom_display_name: "Tabloid"
|
||||
|
||||
wrapWebContents = (webContents) ->
|
||||
# webContents is an EventEmitter.
|
||||
### webContents is an EventEmitter. ###
|
||||
webContents.__proto__ = EventEmitter.prototype
|
||||
|
||||
# WebContents::send(channel, args..)
|
||||
### WebContents::send(channel, args..) ###
|
||||
webContents.send = (channel, args...) ->
|
||||
@_send channel, [args...]
|
||||
|
||||
# Make sure webContents.executeJavaScript would run the code only when the
|
||||
# web contents has been loaded.
|
||||
###
|
||||
Make sure webContents.executeJavaScript would run the code only when the
|
||||
web contents has been loaded.
|
||||
###
|
||||
webContents.executeJavaScript = (code, hasUserGesture=false) ->
|
||||
if @getURL() and not @isLoading()
|
||||
@_executeJavaScript code, hasUserGesture
|
||||
else
|
||||
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
|
||||
|
||||
# The navigation controller.
|
||||
### The navigation controller. ###
|
||||
controller = new NavigationController(webContents)
|
||||
for name, method of NavigationController.prototype when method instanceof Function
|
||||
do (name, method) ->
|
||||
webContents[name] = -> method.apply controller, arguments
|
||||
|
||||
# Dispatch IPC messages to the ipc module.
|
||||
### Dispatch IPC messages to the ipc module. ###
|
||||
webContents.on 'ipc-message', (event, packed) ->
|
||||
[channel, args...] = packed
|
||||
ipcMain.emit channel, event, args...
|
||||
|
@ -70,22 +72,24 @@ wrapWebContents = (webContents) ->
|
|||
Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value)
|
||||
ipcMain.emit channel, event, args...
|
||||
|
||||
# Handle context menu action request from pepper plugin.
|
||||
### Handle context menu action request from pepper plugin. ###
|
||||
webContents.on 'pepper-context-menu', (event, params) ->
|
||||
menu = Menu.buildFromTemplate params.menu
|
||||
menu.popup params.x, params.y
|
||||
|
||||
# This error occurs when host could not be found.
|
||||
### This error occurs when host could not be found. ###
|
||||
webContents.on 'did-fail-provisional-load', (args...) ->
|
||||
# Calling loadURL during this event might cause crash, so delay the event
|
||||
# until next tick.
|
||||
###
|
||||
Calling loadURL during this event might cause crash, so delay the event
|
||||
until next tick.
|
||||
###
|
||||
setImmediate => @emit 'did-fail-load', args...
|
||||
|
||||
# Delays the page-title-updated event to next tick.
|
||||
### Delays the page-title-updated event to next tick. ###
|
||||
webContents.on '-page-title-updated', (args...) ->
|
||||
setImmediate => @emit 'page-title-updated', args...
|
||||
|
||||
# Deprecated.
|
||||
### Deprecated. ###
|
||||
deprecate.rename webContents, 'loadUrl', 'loadURL'
|
||||
deprecate.rename webContents, 'getUrl', 'getURL'
|
||||
deprecate.event webContents, 'page-title-set', 'page-title-updated', (args...) ->
|
||||
|
|
|
@ -3,7 +3,7 @@ fs = require 'fs'
|
|||
path = require 'path'
|
||||
url = require 'url'
|
||||
|
||||
# Mapping between hostname and file path.
|
||||
### Mapping between hostname and file path. ###
|
||||
hostPathMap = {}
|
||||
hostPathMapNextKey = 0
|
||||
|
||||
|
@ -15,14 +15,16 @@ getHostForPath = (path) ->
|
|||
getPathForHost = (host) ->
|
||||
hostPathMap[host]
|
||||
|
||||
# Cache extensionInfo.
|
||||
### Cache extensionInfo. ###
|
||||
extensionInfoMap = {}
|
||||
|
||||
getExtensionInfoFromPath = (srcDirectory) ->
|
||||
manifest = JSON.parse fs.readFileSync(path.join(srcDirectory, 'manifest.json'))
|
||||
unless extensionInfoMap[manifest.name]?
|
||||
# We can not use 'file://' directly because all resources in the extension
|
||||
# will be treated as relative to the root in Chrome.
|
||||
###
|
||||
We can not use 'file://' directly because all resources in the extension
|
||||
will be treated as relative to the root in Chrome.
|
||||
###
|
||||
page = url.format
|
||||
protocol: 'chrome-extension'
|
||||
slashes: true
|
||||
|
@ -35,11 +37,11 @@ getExtensionInfoFromPath = (srcDirectory) ->
|
|||
exposeExperimentalAPIs: true
|
||||
extensionInfoMap[manifest.name]
|
||||
|
||||
# The loaded extensions cache and its persistent path.
|
||||
### The loaded extensions cache and its persistent path. ###
|
||||
loadedExtensions = null
|
||||
loadedExtensionsPath = null
|
||||
|
||||
# Persistent loaded extensions.
|
||||
### Persistent loaded extensions. ###
|
||||
{app} = electron
|
||||
app.on 'will-quit', ->
|
||||
try
|
||||
|
@ -50,21 +52,21 @@ app.on 'will-quit', ->
|
|||
fs.writeFileSync loadedExtensionsPath, JSON.stringify(loadedExtensions)
|
||||
catch e
|
||||
|
||||
# We can not use protocol or BrowserWindow until app is ready.
|
||||
### We can not use protocol or BrowserWindow until app is ready. ###
|
||||
app.once 'ready', ->
|
||||
{protocol, BrowserWindow} = electron
|
||||
|
||||
# Load persistented extensions.
|
||||
### Load persistented extensions. ###
|
||||
loadedExtensionsPath = path.join app.getPath('userData'), 'DevTools Extensions'
|
||||
|
||||
try
|
||||
loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath)
|
||||
loadedExtensions = [] unless Array.isArray loadedExtensions
|
||||
# Preheat the extensionInfo cache.
|
||||
### Preheat the extensionInfo cache. ###
|
||||
getExtensionInfoFromPath srcDirectory for srcDirectory in loadedExtensions
|
||||
catch e
|
||||
|
||||
# The chrome-extension: can map a extension URL request to real file path.
|
||||
### The chrome-extension: can map a extension URL request to real file path. ###
|
||||
chromeExtensionHandler = (request, callback) ->
|
||||
parsed = url.parse request.url
|
||||
return callback() unless parsed.hostname and parsed.path?
|
||||
|
@ -88,7 +90,7 @@ app.once 'ready', ->
|
|||
BrowserWindow.removeDevToolsExtension = (name) ->
|
||||
delete extensionInfoMap[name]
|
||||
|
||||
# Load persistented extensions when devtools is opened.
|
||||
### Load persistented extensions when devtools is opened. ###
|
||||
init = BrowserWindow::_init
|
||||
BrowserWindow::_init = ->
|
||||
init.call this
|
||||
|
|
|
@ -4,26 +4,30 @@
|
|||
deepEqual = (opt1, opt2) ->
|
||||
return JSON.stringify(opt1) is JSON.stringify(opt2)
|
||||
|
||||
# A queue for holding all requests from renderer process.
|
||||
### A queue for holding all requests from renderer process. ###
|
||||
requestsQueue = []
|
||||
|
||||
ipcMain.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, captureWindow, captureScreen, thumbnailSize, id) ->
|
||||
request = id: id, options: {captureWindow, captureScreen, thumbnailSize}, webContents: event.sender
|
||||
requestsQueue.push request
|
||||
desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize if requestsQueue.length is 1
|
||||
# If the WebContents is destroyed before receiving result, just remove the
|
||||
# reference from requestsQueue to make the module not send the result to it.
|
||||
###
|
||||
If the WebContents is destroyed before receiving result, just remove the
|
||||
reference from requestsQueue to make the module not send the result to it.
|
||||
###
|
||||
event.sender.once 'destroyed', ->
|
||||
request.webContents = null
|
||||
|
||||
desktopCapturer.emit = (event, name, sources) ->
|
||||
# Receiving sources result from main process, now send them back to renderer.
|
||||
### Receiving sources result from main process, now send them back to renderer. ###
|
||||
handledRequest = requestsQueue.shift 0
|
||||
result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources)
|
||||
handledRequest.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{handledRequest.id}", result
|
||||
|
||||
# Check the queue to see whether there is other same request. If has, handle
|
||||
# it for reducing redunplicated `desktopCaptuer.startHandling` calls.
|
||||
###
|
||||
Check the queue to see whether there is other same request. If has, handle
|
||||
it for reducing redunplicated `desktopCaptuer.startHandling` calls.
|
||||
###
|
||||
unhandledRequestsQueue = []
|
||||
for request in requestsQueue
|
||||
if deepEqual handledRequest.options, request.options
|
||||
|
@ -31,7 +35,7 @@ desktopCapturer.emit = (event, name, sources) ->
|
|||
else
|
||||
unhandledRequestsQueue.push request
|
||||
requestsQueue = unhandledRequestsQueue
|
||||
# If the requestsQueue is not empty, start a new request handling.
|
||||
### If the requestsQueue is not empty, start a new request handling. ###
|
||||
if requestsQueue.length > 0
|
||||
{captureWindow, captureScreen, thumbnailSize} = requestsQueue[0].options
|
||||
desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{ipcMain, webContents} = require 'electron'
|
||||
|
||||
webViewManager = null # Doesn't exist in early initialization.
|
||||
### Doesn't exist in early initialization. ###
|
||||
webViewManager = null
|
||||
|
||||
supportedWebViewEvents = [
|
||||
'load-commit'
|
||||
|
@ -40,15 +41,15 @@ guestInstances = {}
|
|||
embedderElementsMap = {}
|
||||
reverseEmbedderElementsMap = {}
|
||||
|
||||
# Moves the last element of array to the first one.
|
||||
### Moves the last element of array to the first one. ###
|
||||
moveLastToFirst = (list) ->
|
||||
list.unshift list.pop()
|
||||
|
||||
# Generate guestInstanceId.
|
||||
### Generate guestInstanceId. ###
|
||||
getNextInstanceId = (webContents) ->
|
||||
++nextInstanceId
|
||||
|
||||
# Create a new guest instance.
|
||||
### Create a new guest instance. ###
|
||||
createGuest = (embedder, params) ->
|
||||
webViewManager ?= process.atomBinding 'web_view_manager'
|
||||
|
||||
|
@ -56,21 +57,23 @@ createGuest = (embedder, params) ->
|
|||
guest = webContents.create {isGuest: true, partition: params.partition, embedder}
|
||||
guestInstances[id] = {guest, embedder}
|
||||
|
||||
# Destroy guest when the embedder is gone or navigated.
|
||||
### Destroy guest when the embedder is gone or navigated. ###
|
||||
destroyEvents = ['destroyed', 'crashed', 'did-navigate']
|
||||
destroy = ->
|
||||
destroyGuest embedder, id if guestInstances[id]?
|
||||
for event in destroyEvents
|
||||
embedder.once event, destroy
|
||||
# Users might also listen to the crashed event, so We must ensure the guest
|
||||
# is destroyed before users' listener gets called. It is done by moving our
|
||||
# listener to the first one in queue.
|
||||
###
|
||||
Users might also listen to the crashed event, so We must ensure the guest
|
||||
is destroyed before users' listener gets called. It is done by moving our
|
||||
listener to the first one in queue.
|
||||
###
|
||||
listeners = embedder._events[event]
|
||||
moveLastToFirst listeners if Array.isArray listeners
|
||||
guest.once 'destroyed', ->
|
||||
embedder.removeListener event, destroy for event in destroyEvents
|
||||
|
||||
# Init guest web view after attached.
|
||||
### Init guest web view after attached. ###
|
||||
guest.once 'did-attach', ->
|
||||
params = @attachParams
|
||||
delete @attachParams
|
||||
|
@ -96,32 +99,32 @@ createGuest = (embedder, params) ->
|
|||
|
||||
guest.allowPopups = params.allowpopups
|
||||
|
||||
# Dispatch events to embedder.
|
||||
### Dispatch events to embedder. ###
|
||||
for event in supportedWebViewEvents
|
||||
do (event) ->
|
||||
guest.on event, (_, args...) ->
|
||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{guest.viewInstanceId}", event, args...
|
||||
|
||||
# Dispatch guest's IPC messages to embedder.
|
||||
### Dispatch guest's IPC messages to embedder. ###
|
||||
guest.on 'ipc-message-host', (_, packed) ->
|
||||
[channel, args...] = packed
|
||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{guest.viewInstanceId}", channel, args...
|
||||
|
||||
# Autosize.
|
||||
### Autosize. ###
|
||||
guest.on 'size-changed', (_, args...) ->
|
||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{guest.viewInstanceId}", args...
|
||||
|
||||
id
|
||||
|
||||
# Attach the guest to an element of embedder.
|
||||
### Attach the guest to an element of embedder. ###
|
||||
attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
|
||||
guest = guestInstances[guestInstanceId].guest
|
||||
|
||||
# Destroy the old guest when attaching.
|
||||
### Destroy the old guest when attaching. ###
|
||||
key = "#{embedder.getId()}-#{elementInstanceId}"
|
||||
oldGuestInstanceId = embedderElementsMap[key]
|
||||
if oldGuestInstanceId?
|
||||
# Reattachment to the same guest is not currently supported.
|
||||
### Reattachment to the same guest is not currently supported. ###
|
||||
return unless oldGuestInstanceId != guestInstanceId
|
||||
|
||||
return unless guestInstances[oldGuestInstanceId]?
|
||||
|
@ -139,7 +142,7 @@ attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
|
|||
embedderElementsMap[key] = guestInstanceId
|
||||
reverseEmbedderElementsMap[guestInstanceId] = key
|
||||
|
||||
# Destroy an existing guest instance.
|
||||
### Destroy an existing guest instance. ###
|
||||
destroyGuest = (embedder, id) ->
|
||||
webViewManager.removeGuest embedder, id
|
||||
guestInstances[id].guest.destroy()
|
||||
|
@ -165,10 +168,10 @@ ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', (event, id, params) ->
|
|||
ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', (event, id, allowtransparency) ->
|
||||
guestInstances[id]?.guest.setAllowTransparency allowtransparency
|
||||
|
||||
# Returns WebContents from its guest id.
|
||||
### Returns WebContents from its guest id. ###
|
||||
exports.getGuest = (id) ->
|
||||
guestInstances[id]?.guest
|
||||
|
||||
# Returns the embedder of the guest.
|
||||
### Returns the embedder of the guest. ###
|
||||
exports.getEmbedder = (id) ->
|
||||
guestInstances[id]?.embedder
|
||||
|
|
|
@ -3,7 +3,7 @@ v8Util = process.atomBinding 'v8_util'
|
|||
|
||||
frameToGuest = {}
|
||||
|
||||
# Copy attribute of |parent| to |child| if it is not defined in |child|.
|
||||
### Copy attribute of |parent| to |child| if it is not defined in |child|. ###
|
||||
mergeOptions = (child, parent) ->
|
||||
for own key, value of parent when key not of child
|
||||
if typeof value is 'object'
|
||||
|
@ -12,34 +12,36 @@ mergeOptions = (child, parent) ->
|
|||
child[key] = value
|
||||
child
|
||||
|
||||
# Merge |options| with the |embedder|'s window's options.
|
||||
### Merge |options| with the |embedder|'s window's options. ###
|
||||
mergeBrowserWindowOptions = (embedder, options) ->
|
||||
if embedder.browserWindowOptions?
|
||||
# Inherit the original options if it is a BrowserWindow.
|
||||
### Inherit the original options if it is a BrowserWindow. ###
|
||||
mergeOptions options, embedder.browserWindowOptions
|
||||
else
|
||||
# Or only inherit web-preferences if it is a webview.
|
||||
### Or only inherit web-preferences if it is a webview. ###
|
||||
options.webPreferences ?= {}
|
||||
mergeOptions options.webPreferences, embedder.getWebPreferences()
|
||||
options
|
||||
|
||||
# Create a new guest created by |embedder| with |options|.
|
||||
### Create a new guest created by |embedder| with |options|. ###
|
||||
createGuest = (embedder, url, frameName, options) ->
|
||||
guest = frameToGuest[frameName]
|
||||
if frameName and guest?
|
||||
guest.loadURL url
|
||||
return guest.id
|
||||
|
||||
# Remember the embedder window's id.
|
||||
### Remember the embedder window's id. ###
|
||||
options.webPreferences ?= {}
|
||||
options.webPreferences.openerId = BrowserWindow.fromWebContents(embedder)?.id
|
||||
|
||||
guest = new BrowserWindow(options)
|
||||
guest.loadURL url
|
||||
|
||||
# When |embedder| is destroyed we should also destroy attached guest, and if
|
||||
# guest is closed by user then we should prevent |embedder| from double
|
||||
# closing guest.
|
||||
###
|
||||
When |embedder| is destroyed we should also destroy attached guest, and if
|
||||
guest is closed by user then we should prevent |embedder| from double
|
||||
closing guest.
|
||||
###
|
||||
guestId = guest.id
|
||||
closedByEmbedder = ->
|
||||
guest.removeListener 'closed', closedByUser
|
||||
|
@ -58,7 +60,7 @@ createGuest = (embedder, url, frameName, options) ->
|
|||
|
||||
guest.id
|
||||
|
||||
# Routed window.open messages.
|
||||
### Routed window.open messages. ###
|
||||
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) ->
|
||||
[url, frameName, options] = args
|
||||
options = mergeBrowserWindowOptions event.sender, options
|
||||
|
|
|
@ -3,26 +3,28 @@ path = require 'path'
|
|||
util = require 'util'
|
||||
Module = require 'module'
|
||||
|
||||
# We modified the original process.argv to let node.js load the atom.js,
|
||||
# we need to restore it here.
|
||||
### We modified the original process.argv to let node.js load the atom.js, ###
|
||||
### we need to restore it here. ###
|
||||
process.argv.splice 1, 1
|
||||
|
||||
# Clear search paths.
|
||||
### Clear search paths. ###
|
||||
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')
|
||||
|
||||
# Import common settings.
|
||||
### Import common settings. ###
|
||||
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
|
||||
|
||||
globalPaths = Module.globalPaths
|
||||
unless process.env.ELECTRON_HIDE_INTERNAL_MODULES
|
||||
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
||||
|
||||
# Expose public APIs.
|
||||
### Expose public APIs. ###
|
||||
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib', 'exports')
|
||||
|
||||
if process.platform is 'win32'
|
||||
# Redirect node's console to use our own implementations, since node can not
|
||||
# handle console output when running as GUI program.
|
||||
###
|
||||
Redirect node's console to use our own implementations, since node can not
|
||||
handle console output when running as GUI program.
|
||||
###
|
||||
consoleLog = (args...) ->
|
||||
process.log util.format(args...) + "\n"
|
||||
streamWrite = (chunk, encoding, callback) ->
|
||||
|
@ -33,40 +35,40 @@ if process.platform is 'win32'
|
|||
console.log = console.error = console.warn = consoleLog
|
||||
process.stdout.write = process.stderr.write = streamWrite
|
||||
|
||||
# Always returns EOF for stdin stream.
|
||||
### Always returns EOF for stdin stream. ###
|
||||
Readable = require('stream').Readable
|
||||
stdin = new Readable
|
||||
stdin.push null
|
||||
process.__defineGetter__ 'stdin', -> stdin
|
||||
|
||||
# Don't quit on fatal error.
|
||||
### Don't quit on fatal error. ###
|
||||
process.on 'uncaughtException', (error) ->
|
||||
# Do nothing if the user has a custom uncaught exception handler.
|
||||
### Do nothing if the user has a custom uncaught exception handler. ###
|
||||
if process.listeners('uncaughtException').length > 1
|
||||
return
|
||||
|
||||
# Show error in GUI.
|
||||
### Show error in GUI. ###
|
||||
{dialog} = require 'electron'
|
||||
stack = error.stack ? "#{error.name}: #{error.message}"
|
||||
message = "Uncaught Exception:\n#{stack}"
|
||||
dialog.showErrorBox 'A JavaScript error occurred in the main process', message
|
||||
|
||||
# Emit 'exit' event on quit.
|
||||
### Emit 'exit' event on quit. ###
|
||||
{app} = require 'electron'
|
||||
app.on 'quit', (event, exitCode) ->
|
||||
process.emit 'exit', exitCode
|
||||
|
||||
# Map process.exit to app.exit, which quits gracefully.
|
||||
### Map process.exit to app.exit, which quits gracefully. ###
|
||||
process.exit = app.exit
|
||||
|
||||
# Load the RPC server.
|
||||
### Load the RPC server. ###
|
||||
require './rpc-server'
|
||||
|
||||
# Load the guest view manager.
|
||||
### Load the guest view manager. ###
|
||||
require './guest-view-manager'
|
||||
require './guest-window-manager'
|
||||
|
||||
# Now we try to load app's package.json.
|
||||
### Now we try to load app's package.json. ###
|
||||
packageJson = null
|
||||
|
||||
searchPaths = [ 'app', 'app.asar', 'default_app' ]
|
||||
|
@ -82,37 +84,37 @@ unless packageJson?
|
|||
process.nextTick -> process.exit 1
|
||||
throw new Error("Unable to find a valid app")
|
||||
|
||||
# Set application's version.
|
||||
### Set application's version. ###
|
||||
app.setVersion packageJson.version if packageJson.version?
|
||||
|
||||
# Set application's name.
|
||||
### Set application's name. ###
|
||||
if packageJson.productName?
|
||||
app.setName packageJson.productName
|
||||
else if packageJson.name?
|
||||
app.setName packageJson.name
|
||||
|
||||
# Set application's desktop name.
|
||||
### Set application's desktop name. ###
|
||||
if packageJson.desktopName?
|
||||
app.setDesktopName packageJson.desktopName
|
||||
else
|
||||
app.setDesktopName "#{app.getName()}.desktop"
|
||||
|
||||
# Chrome 42 disables NPAPI plugins by default, reenable them here
|
||||
### Chrome 42 disables NPAPI plugins by default, reenable them here ###
|
||||
app.commandLine.appendSwitch 'enable-npapi'
|
||||
|
||||
# Set the user path according to application's name.
|
||||
### Set the user path according to application's name. ###
|
||||
app.setPath 'userData', path.join(app.getPath('appData'), app.getName())
|
||||
app.setPath 'userCache', path.join(app.getPath('cache'), app.getName())
|
||||
app.setAppPath packagePath
|
||||
|
||||
# Load the chrome extension support.
|
||||
### Load the chrome extension support. ###
|
||||
require './chrome-extension'
|
||||
|
||||
# Load internal desktop-capturer module.
|
||||
### Load internal desktop-capturer module. ###
|
||||
require './desktop-capturer'
|
||||
|
||||
# Set main startup script of the app.
|
||||
### Set main startup script of the app. ###
|
||||
mainStartupScript = packageJson.main or 'index.js'
|
||||
|
||||
# Finally load app's main.js and transfer control to C++.
|
||||
### Finally load app's main.js and transfer control to C++. ###
|
||||
Module._load path.join(packagePath, mainStartupScript), Module, true
|
||||
|
|
|
@ -6,46 +6,52 @@ class ObjectsRegistry extends EventEmitter
|
|||
@setMaxListeners Number.MAX_VALUE
|
||||
@nextId = 0
|
||||
|
||||
# Stores all objects by ref-counting.
|
||||
# (id) => {object, count}
|
||||
###
|
||||
Stores all objects by ref-counting.
|
||||
(id) => {object, count}
|
||||
###
|
||||
@storage = {}
|
||||
|
||||
# Stores the IDs of objects referenced by WebContents.
|
||||
# (webContentsId) => {(id) => (count)}
|
||||
###
|
||||
Stores the IDs of objects referenced by WebContents.
|
||||
(webContentsId) => {(id) => (count)}
|
||||
###
|
||||
@owners = {}
|
||||
|
||||
# Register a new object, the object would be kept referenced until you release
|
||||
# it explicitly.
|
||||
###
|
||||
Register a new object, the object would be kept referenced until you release
|
||||
it explicitly.
|
||||
###
|
||||
add: (webContentsId, obj) ->
|
||||
id = @saveToStorage obj
|
||||
# Remember the owner.
|
||||
### Remember the owner. ###
|
||||
@owners[webContentsId] ?= {}
|
||||
@owners[webContentsId][id] ?= 0
|
||||
@owners[webContentsId][id]++
|
||||
# Returns object's id
|
||||
### Returns object's id ###
|
||||
id
|
||||
|
||||
# Get an object according to its ID.
|
||||
### Get an object according to its ID. ###
|
||||
get: (id) ->
|
||||
@storage[id]?.object
|
||||
|
||||
# Dereference an object according to its ID.
|
||||
### Dereference an object according to its ID. ###
|
||||
remove: (webContentsId, id) ->
|
||||
@dereference id, 1
|
||||
# Also reduce the count in owner.
|
||||
### Also reduce the count in owner. ###
|
||||
pointer = @owners[webContentsId]
|
||||
return unless pointer?
|
||||
--pointer[id]
|
||||
delete pointer[id] if pointer[id] is 0
|
||||
|
||||
# Clear all references to objects refrenced by the WebContents.
|
||||
### Clear all references to objects refrenced by the WebContents. ###
|
||||
clear: (webContentsId) ->
|
||||
@emit "clear-#{webContentsId}"
|
||||
return unless @owners[webContentsId]?
|
||||
@dereference id, count for id, count of @owners[webContentsId]
|
||||
delete @owners[webContentsId]
|
||||
|
||||
# Private: Saves the object into storage and assigns an ID for it.
|
||||
### Private: Saves the object into storage and assigns an ID for it. ###
|
||||
saveToStorage: (object) ->
|
||||
id = v8Util.getHiddenValue object, 'atomId'
|
||||
unless id
|
||||
|
@ -55,7 +61,7 @@ class ObjectsRegistry extends EventEmitter
|
|||
++@storage[id].count
|
||||
id
|
||||
|
||||
# Private: Dereference the object from store.
|
||||
### Private: Dereference the object from store. ###
|
||||
dereference: (id, count) ->
|
||||
pointer = @storage[id]
|
||||
return unless pointer?
|
||||
|
|
|
@ -7,7 +7,7 @@ objectsRegistry = require './objects-registry'
|
|||
v8Util = process.atomBinding 'v8_util'
|
||||
{IDWeakMap} = process.atomBinding 'id_weak_map'
|
||||
|
||||
# Convert a real value into meta data.
|
||||
### Convert a real value into meta data. ###
|
||||
valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||
meta = type: typeof value
|
||||
|
||||
|
@ -18,11 +18,11 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
meta.type = 'date' if value instanceof Date
|
||||
meta.type = 'promise' if value?.constructor.name is 'Promise'
|
||||
|
||||
# Treat simple objects as value.
|
||||
### Treat simple objects as value. ###
|
||||
if optimizeSimpleObject and meta.type is 'object' and v8Util.getHiddenValue value, 'simple'
|
||||
meta.type = 'value'
|
||||
|
||||
# Treat the arguments object as array.
|
||||
### Treat the arguments object as array. ###
|
||||
meta.type = 'array' if meta.type is 'object' and value.callee? and value.length?
|
||||
|
||||
if meta.type is 'array'
|
||||
|
@ -31,9 +31,11 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
else if meta.type is 'object' or meta.type is 'function'
|
||||
meta.name = value.constructor.name
|
||||
|
||||
# Reference the original value if it's an object, because when it's
|
||||
# passed to renderer we would assume the renderer keeps a reference of
|
||||
# it.
|
||||
###
|
||||
Reference the original value if it's an object, because when it's
|
||||
passed to renderer we would assume the renderer keeps a reference of
|
||||
it.
|
||||
###
|
||||
meta.id = objectsRegistry.add sender.getId(), value
|
||||
|
||||
meta.members = ({name, type: typeof field} for name, field of value)
|
||||
|
@ -43,7 +45,7 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
meta.then = valueToMeta sender, value.then.bind(value)
|
||||
else if meta.type is 'error'
|
||||
meta.members = plainObjectToMeta value
|
||||
# Error.name is not part of own properties.
|
||||
### Error.name is not part of own properties. ###
|
||||
meta.members.push {name: 'name', value: value.name}
|
||||
else if meta.type is 'date'
|
||||
meta.value = value.getTime()
|
||||
|
@ -53,15 +55,15 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
|
||||
meta
|
||||
|
||||
# Convert object to meta by value.
|
||||
### Convert object to meta by value. ###
|
||||
plainObjectToMeta = (obj) ->
|
||||
Object.getOwnPropertyNames(obj).map (name) -> {name, value: obj[name]}
|
||||
|
||||
# Convert Error into meta data.
|
||||
### Convert Error into meta data. ###
|
||||
exceptionToMeta = (error) ->
|
||||
type: 'exception', message: error.message, stack: (error.stack || error)
|
||||
|
||||
# Convert array of meta data from renderer into array of real values.
|
||||
### Convert array of meta data from renderer into array of real values. ###
|
||||
unwrapArgs = (sender, args) ->
|
||||
metaToValue = (meta) ->
|
||||
switch meta.type
|
||||
|
@ -80,7 +82,7 @@ unwrapArgs = (sender, args) ->
|
|||
returnValue = metaToValue meta.value
|
||||
-> returnValue
|
||||
when 'function'
|
||||
# Cache the callbacks in renderer.
|
||||
### Cache the callbacks in renderer. ###
|
||||
unless sender.callbacks
|
||||
sender.callbacks = new IDWeakMap
|
||||
sender.on 'render-view-deleted', ->
|
||||
|
@ -106,8 +108,10 @@ unwrapArgs = (sender, args) ->
|
|||
|
||||
args.map metaToValue
|
||||
|
||||
# Call a function and send reply asynchronously if it's a an asynchronous
|
||||
# style function and the caller didn't pass a callback.
|
||||
###
|
||||
Call a function and send reply asynchronously if it's a an asynchronous
|
||||
style function and the caller didn't pass a callback.
|
||||
###
|
||||
callFunction = (event, func, caller, args) ->
|
||||
funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous')
|
||||
funcPassedCallback = typeof args[args.length - 1] is 'function'
|
||||
|
@ -121,15 +125,17 @@ callFunction = (event, func, caller, args) ->
|
|||
ret = func.apply caller, args
|
||||
event.returnValue = valueToMeta event.sender, ret, true
|
||||
catch e
|
||||
# Catch functions thrown further down in function invocation and wrap
|
||||
# them with the function name so it's easier to trace things like
|
||||
# `Error processing argument -1.`
|
||||
###
|
||||
Catch functions thrown further down in function invocation and wrap
|
||||
them with the function name so it's easier to trace things like
|
||||
`Error processing argument -1.`
|
||||
###
|
||||
funcName = func.name ? "anonymous"
|
||||
throw new Error("Could not call remote function `#{funcName}`.
|
||||
Check that the function signature is correct.
|
||||
Underlying error: #{e.message}")
|
||||
|
||||
# Send by BrowserWindow when its render view is deleted.
|
||||
### Send by BrowserWindow when its render view is deleted. ###
|
||||
process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) ->
|
||||
objectsRegistry.clear id
|
||||
|
||||
|
@ -164,8 +170,10 @@ ipcMain.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
|
|||
try
|
||||
args = unwrapArgs event.sender, args
|
||||
constructor = objectsRegistry.get id
|
||||
# Call new with array of arguments.
|
||||
# http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
|
||||
###
|
||||
Call new with array of arguments.
|
||||
http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
|
||||
###
|
||||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.returnValue = valueToMeta event.sender, obj
|
||||
catch e
|
||||
|
@ -183,7 +191,7 @@ ipcMain.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
|
|||
try
|
||||
args = unwrapArgs event.sender, args
|
||||
constructor = objectsRegistry.get(id)[method]
|
||||
# Call new with array of arguments.
|
||||
### Call new with array of arguments. ###
|
||||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.returnValue = valueToMeta event.sender, obj
|
||||
catch e
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue