Migrate to block comments
This commit is contained in:
parent
630cd091a0
commit
403870a27e
44 changed files with 538 additions and 437 deletions
|
@ -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