Handle IPC messages in webContents instead of BrowserWindow.

This commit is contained in:
Cheng Zhao 2014-04-25 16:13:16 +08:00
parent 1815f8b40d
commit c0875864dc
21 changed files with 138 additions and 421 deletions

View file

@ -48,7 +48,6 @@
'atom/browser/api/atom_api_app.h', 'atom/browser/api/atom_api_app.h',
'atom/browser/api/atom_api_auto_updater.cc', 'atom/browser/api/atom_api_auto_updater.cc',
'atom/browser/api/atom_api_auto_updater.h', 'atom/browser/api/atom_api_auto_updater.h',
'atom/browser/api/atom_api_browser_ipc.cc',
'atom/browser/api/atom_api_dialog.cc', 'atom/browser/api/atom_api_dialog.cc',
'atom/browser/api/atom_api_menu.cc', 'atom/browser/api/atom_api_menu.cc',
'atom/browser/api/atom_api_menu.h', 'atom/browser/api/atom_api_menu.h',
@ -66,8 +65,6 @@
'atom/browser/api/atom_api_web_contents.h', 'atom/browser/api/atom_api_web_contents.h',
'atom/browser/api/atom_api_window.cc', 'atom/browser/api/atom_api_window.cc',
'atom/browser/api/atom_api_window.h', 'atom/browser/api/atom_api_window.h',
'atom/browser/api/atom_browser_bindings.cc',
'atom/browser/api/atom_browser_bindings.h',
'atom/browser/api/event.cc', 'atom/browser/api/event.cc',
'atom/browser/api/event.h', 'atom/browser/api/event.h',
'atom/browser/api/event_emitter.cc', 'atom/browser/api/event_emitter.cc',
@ -95,8 +92,6 @@
'atom/browser/browser_observer.h', 'atom/browser/browser_observer.h',
'atom/browser/devtools_delegate.cc', 'atom/browser/devtools_delegate.cc',
'atom/browser/devtools_delegate.h', 'atom/browser/devtools_delegate.h',
'atom/browser/devtools_web_contents_observer.cc',
'atom/browser/devtools_web_contents_observer.h',
'atom/browser/mac/atom_application.h', 'atom/browser/mac/atom_application.h',
'atom/browser/mac/atom_application.mm', 'atom/browser/mac/atom_application.mm',
'atom/browser/mac/atom_application_delegate.h', 'atom/browser/mac/atom_application_delegate.h',

View file

@ -1,37 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "atom/common/api/api_messages.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "content/public/browser/render_view_host.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
using content::RenderViewHost;
namespace {
bool Send(const string16& channel, int process_id, int routing_id,
const base::ListValue& arguments) {
RenderViewHost* render_view_host(RenderViewHost::FromID(
process_id, routing_id));
if (!render_view_host) {
node::ThrowError("Invalid render view host");
return false;
}
return render_view_host->Send(new AtomViewMsg_Message(routing_id, channel,
arguments));
}
void Initialize(v8::Handle<v8::Object> exports) {
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
dict.SetMethod("send", &Send);
}
} // namespace
NODE_MODULE(atom_browser_ipc, Initialize)

View file

@ -8,6 +8,7 @@
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/native_mate_converters/value_converter.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
@ -48,6 +49,18 @@ void WebContents::DidStopLoading(content::RenderViewHost* render_view_host) {
Emit("did-stop-loading"); Emit("did-stop-loading");
} }
bool WebContents::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebContents, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void WebContents::WebContentsDestroyed(content::WebContents*) { void WebContents::WebContentsDestroyed(content::WebContents*) {
// The RenderViewDeleted was not called when the WebContents is destroyed. // The RenderViewDeleted was not called when the WebContents is destroyed.
RenderViewDeleted(web_contents_->GetRenderViewHost()); RenderViewDeleted(web_contents_->GetRenderViewHost());
@ -166,7 +179,20 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("getProcessId", &WebContents::GetProcessID) .SetMethod("getProcessId", &WebContents::GetProcessID)
.SetMethod("isCrashed", &WebContents::IsCrashed) .SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("executeJavaScript", &WebContents::ExecuteJavaScript) .SetMethod("executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("send", &WebContents::SendIPCMessage); .SetMethod("_send", &WebContents::SendIPCMessage);
}
void WebContents::OnRendererMessage(const string16& channel,
const base::ListValue& args) {
// webContents.emit(channel, new Event(), args...);
Emit(UTF16ToUTF8(channel), args, web_contents(), NULL);
}
void WebContents::OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* message) {
// webContents.emit(channel, new Event(sender, message), args...);
Emit(UTF16ToUTF8(channel), args, web_contents(), message);
} }
// static // static

View file

@ -60,9 +60,18 @@ class WebContents : public mate::EventEmitter,
content::RenderViewHost* render_view_host) OVERRIDE; content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidStopLoading( virtual void DidStopLoading(
content::RenderViewHost* render_view_host) OVERRIDE; content::RenderViewHost* render_view_host) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void WebContentsDestroyed(content::WebContents*) OVERRIDE; virtual void WebContentsDestroyed(content::WebContents*) OVERRIDE;
private: private:
// Called when received a message from renderer.
void OnRendererMessage(const string16& channel, const base::ListValue& args);
// Called when received a synchronous message from renderer.
void OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* message);
content::WebContents* web_contents_; // Weak. content::WebContents* web_contents_; // Weak.
DISALLOW_COPY_AND_ASSIGN(WebContents); DISALLOW_COPY_AND_ASSIGN(WebContents);

View file

@ -1,93 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_browser_bindings.h"
#include <vector>
#include "atom/browser/api/event.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/v8_value_converter.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "atom/common/node_includes.h"
namespace atom {
AtomBrowserBindings::AtomBrowserBindings() {
}
void AtomBrowserBindings::OnRendererMessage(int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
scoped_ptr<V8ValueConverter> converter(new V8ValueConverter);
// process.emit(channel, 'message', process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize());
arguments.push_back(mate::ConvertToV8(node_isolate, channel));
const base::Value* value;
if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
arguments.push_back(v8::Integer::New(process_id));
arguments.push_back(v8::Integer::New(routing_id));
for (size_t i = 1; i < args.GetSize(); i++) {
const base::Value* value;
if (args.Get(i, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
}
node::MakeCallback(global_env->process_object(),
"emit",
arguments.size(),
&arguments[0]);
}
void AtomBrowserBindings::OnRendererMessageSync(
int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args,
content::WebContents* sender,
IPC::Message* message) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
scoped_ptr<V8ValueConverter> converter(new V8ValueConverter);
// Create the event object.
mate::Handle<mate::Event> event = mate::Event::Create(node_isolate);
event->SetSenderAndMessage(sender, message);
// process.emit(channel, 'sync-message', event, process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize());
arguments.push_back(mate::ConvertToV8(node_isolate, channel));
const base::Value* value;
if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
arguments.push_back(event.ToV8());
arguments.push_back(v8::Integer::New(process_id));
arguments.push_back(v8::Integer::New(routing_id));
for (size_t i = 1; i < args.GetSize(); i++) {
const base::Value* value;
if (args.Get(i, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
}
node::MakeCallback(global_env->process_object(),
"emit",
arguments.size(),
&arguments[0]);
}
} // namespace atom

View file

@ -1,49 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_H_
#define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_H_
#include "atom/common/api/atom_bindings.h"
#include "base/strings/string16.h"
namespace base {
class ListValue;
}
namespace content {
class WebContents;
}
namespace IPC {
class Message;
}
namespace atom {
class AtomBrowserBindings : public AtomBindings {
public:
AtomBrowserBindings();
// Called when received a message from renderer.
void OnRendererMessage(int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args);
// Called when received a synchronous message from renderer.
void OnRendererMessageSync(int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args,
content::WebContents* sender,
IPC::Message* message);
private:
DISALLOW_COPY_AND_ASSIGN(AtomBrowserBindings);
};
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_H_

View file

@ -24,6 +24,13 @@ bool EventEmitter::Emit(const base::StringPiece& name) {
bool EventEmitter::Emit(const base::StringPiece& name, bool EventEmitter::Emit(const base::StringPiece& name,
const base::ListValue& args) { const base::ListValue& args) {
return Emit(name, args, NULL, NULL);
}
bool EventEmitter::Emit(const base::StringPiece& name,
const base::ListValue& args,
content::WebContents* sender,
IPC::Message* message) {
v8::Locker locker(node_isolate); v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate); v8::HandleScope handle_scope(node_isolate);
@ -31,6 +38,8 @@ bool EventEmitter::Emit(const base::StringPiece& name,
scoped_ptr<atom::V8ValueConverter> converter(new atom::V8ValueConverter); scoped_ptr<atom::V8ValueConverter> converter(new atom::V8ValueConverter);
mate::Handle<mate::Event> event = mate::Event::Create(node_isolate); mate::Handle<mate::Event> event = mate::Event::Create(node_isolate);
if (sender && message)
event->SetSenderAndMessage(sender, message);
// v8_args = [name, event, args...]; // v8_args = [name, event, args...];
std::vector<v8::Handle<v8::Value>> v8_args; std::vector<v8::Handle<v8::Value>> v8_args;

View file

@ -11,6 +11,14 @@ namespace base {
class ListValue; class ListValue;
} }
namespace content {
class WebContents;
}
namespace IPC {
class Message;
}
namespace mate { namespace mate {
// Provide helperers to emit event in JavaScript. // Provide helperers to emit event in JavaScript.
@ -18,12 +26,16 @@ class EventEmitter : public Wrappable {
protected: protected:
EventEmitter(); EventEmitter();
// this.emit(name); // this.emit(name, new Event());
bool Emit(const base::StringPiece& name); bool Emit(const base::StringPiece& name);
// this.emit(name, args...); // this.emit(name, new Event(), args...);
bool Emit(const base::StringPiece& name, const base::ListValue& args); bool Emit(const base::StringPiece& name, const base::ListValue& args);
// this.emit(name, new Event(sender, message), args...);
bool Emit(const base::StringPiece& name, const base::ListValue& args,
content::WebContents* sender, IPC::Message* message);
private: private:
DISALLOW_COPY_AND_ASSIGN(EventEmitter); DISALLOW_COPY_AND_ASSIGN(EventEmitter);
}; };

View file

@ -1,10 +1,32 @@
EventEmitter = require('events').EventEmitter EventEmitter = require('events').EventEmitter
IDWeakMap = require 'id-weak-map' IDWeakMap = require 'id-weak-map'
app = require 'app' app = require 'app'
ipc = require 'ipc'
BrowserWindow = process.atomBinding('window').BrowserWindow BrowserWindow = process.atomBinding('window').BrowserWindow
BrowserWindow::__proto__ = EventEmitter.prototype BrowserWindow::__proto__ = EventEmitter.prototype
wrapWebContents = (webContents) ->
return null unless webContents.isAlive()
# webContents is an EventEmitter.
webContents.__proto__ = EventEmitter.prototype
# Wrap around the send method.
webContents.send = (args...) ->
@_send 'ATOM_INTERNAL_MESSAGE', [args...]
# Dispatch the ipc messages.
webContents.on 'ipc-message', (event, channel, args...) =>
Object.defineProperty event, 'sender', value: webContents
ipc.emit channel, event, args...
webContents.on 'ipc-message-sync', (event, channel, args...) =>
set = (value) -> event.sendReply JSON.stringify(value)
Object.defineProperty event, 'returnValue', {set}
Object.defineProperty event, 'sender', value: webContents
ipc.emit channel, event, args...
webContents
# Store all created windows in the weak map. # Store all created windows in the weak map.
BrowserWindow.windows = new IDWeakMap BrowserWindow.windows = new IDWeakMap
@ -45,15 +67,10 @@ BrowserWindow::toggleDevTools = ->
if @isDevToolsOpened() then @closeDevTools() else @openDevTools() if @isDevToolsOpened() then @closeDevTools() else @openDevTools()
BrowserWindow::getWebContents = -> BrowserWindow::getWebContents = ->
webContents = @_getWebContents() wrapWebContents @_getWebContents()
webContents.__proto__ = EventEmitter.prototype
webContents
BrowserWindow::getDevToolsWebContents = -> BrowserWindow::getDevToolsWebContents = ->
webContents = @_getDevToolsWebContents() wrapWebContents @_getDevToolsWebContents()
webContents.__proto__ = EventEmitter.prototype
webContents = null unless webContents.isAlive()
webContents
BrowserWindow::restart = -> BrowserWindow::restart = ->
@loadUrl(@getUrl()) @loadUrl(@getUrl())

View file

@ -1,32 +1,3 @@
EventEmitter = require('events').EventEmitter EventEmitter = require('events').EventEmitter
send = process.atomBinding('ipc').send
sendWrap = (channel, processId, routingId, args...) -> module.exports = new EventEmitter
BrowserWindow = require 'browser-window'
if processId?.constructor is BrowserWindow
window = processId
args = [routingId, args...]
processId = window.getProcessId()
routingId = window.getRoutingId()
send channel, processId, routingId, [args...]
class Ipc extends EventEmitter
constructor: ->
process.on 'ATOM_INTERNAL_MESSAGE', (args...) =>
@emit(args...)
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (channel, event, args...) =>
set = (value) -> event.sendReply JSON.stringify(value)
Object.defineProperty event, 'returnValue', {set}
Object.defineProperty event, 'result', {set}
@emit(channel, event, args...)
send: (processId, routingId, args...) ->
@sendChannel(processId, routingId, 'message', args...)
sendChannel: (args...) ->
sendWrap('ATOM_INTERNAL_MESSAGE', args...)
module.exports = new Ipc

View file

@ -4,10 +4,10 @@
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/api/atom_browser_bindings.h"
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/node_bindings.h" #include "atom/common/node_bindings.h"
#include "net/proxy/proxy_resolver_v8.h" #include "net/proxy/proxy_resolver_v8.h"
@ -23,7 +23,7 @@ namespace atom {
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL; AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
AtomBrowserMainParts::AtomBrowserMainParts() AtomBrowserMainParts::AtomBrowserMainParts()
: atom_bindings_(new AtomBrowserBindings), : atom_bindings_(new AtomBindings),
browser_(new Browser), browser_(new Browser),
node_bindings_(NodeBindings::Create(true)) { node_bindings_(NodeBindings::Create(true)) {
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts"; DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";

View file

@ -9,7 +9,7 @@
namespace atom { namespace atom {
class AtomBrowserBindings; class AtomBindings;
class Browser; class Browser;
class NodeBindings; class NodeBindings;
@ -20,7 +20,6 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
static AtomBrowserMainParts* Get(); static AtomBrowserMainParts* Get();
AtomBrowserBindings* atom_bindings() { return atom_bindings_.get(); }
Browser* browser() { return browser_.get(); } Browser* browser() { return browser_.get(); }
protected: protected:
@ -37,7 +36,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
#endif #endif
private: private:
scoped_ptr<AtomBrowserBindings> atom_bindings_; scoped_ptr<AtomBindings> atom_bindings_;
scoped_ptr<Browser> browser_; scoped_ptr<Browser> browser_;
scoped_ptr<NodeBindings> node_bindings_; scoped_ptr<NodeBindings> node_bindings_;

View file

@ -1,64 +0,0 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "atom/browser/devtools_web_contents_observer.h"
#include "atom/browser/api/atom_browser_bindings.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/native_window.h"
#include "atom/common/api/api_messages.h"
#include "base/logging.h"
#include "content/public/browser/render_process_host.h"
#include "ipc/ipc_message_macros.h"
namespace atom {
DevToolsWebContentsObserver::DevToolsWebContentsObserver(
NativeWindow* native_window,
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
inspected_window_(native_window) {
DCHECK(native_window);
}
DevToolsWebContentsObserver::~DevToolsWebContentsObserver() {
}
bool DevToolsWebContentsObserver::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DevToolsWebContentsObserver, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void DevToolsWebContentsObserver::OnRendererMessage(
const string16& channel,
const base::ListValue& args) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
web_contents()->GetRenderProcessHost()->GetID(),
web_contents()->GetRoutingID(),
channel,
args);
}
void DevToolsWebContentsObserver::OnRendererMessageSync(
const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync(
web_contents()->GetRenderProcessHost()->GetID(),
web_contents()->GetRoutingID(),
channel,
args,
web_contents(),
reply_msg);
}
} // namespace atom

View file

@ -1,41 +0,0 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_DEVTOOLS_WEB_CONTENTS_OBSERVER_H_
#define ATOM_BROWSER_DEVTOOLS_WEB_CONTENTS_OBSERVER_H_
#include "content/public/browser/web_contents_observer.h"
namespace base {
class ListValue;
}
namespace atom {
class NativeWindow;
class DevToolsWebContentsObserver : public content::WebContentsObserver {
public:
DevToolsWebContentsObserver(NativeWindow* native_window,
content::WebContents* web_contents);
virtual ~DevToolsWebContentsObserver();
protected:
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
void OnRendererMessage(const string16& channel,
const base::ListValue& args);
void OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg);
private:
NativeWindow* inspected_window_;
DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
};
} // namespace atom
#endif // ATOM_BROWSER_DEVTOOLS_WEB_CONTENTS_OBSERVER_H_

View file

@ -4,7 +4,7 @@ objectsRegistry = require './objects-registry.js'
v8Util = process.atomBinding 'v8_util' v8Util = process.atomBinding 'v8_util'
# Convert a real value into meta data. # Convert a real value into meta data.
valueToMeta = (processId, routingId, value) -> valueToMeta = (sender, value) ->
meta = type: typeof value meta = type: typeof value
meta.type = 'value' if value is null meta.type = 'value' if value is null
@ -15,13 +15,15 @@ valueToMeta = (processId, routingId, value) ->
if meta.type is 'array' if meta.type is 'array'
meta.members = [] meta.members = []
meta.members.push valueToMeta(processId, routingId, el) for el in value meta.members.push valueToMeta(sender, el) for el in value
else if meta.type is 'object' or meta.type is 'function' else if meta.type is 'object' or meta.type is 'function'
meta.name = value.constructor.name meta.name = value.constructor.name
# Reference the original value if it's an object, because when it's # 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 # passed to renderer we would assume the renderer keeps a reference of
# it. # it.
processId = sender.getProcessId()
routingId = sender.getRoutingId()
[meta.id, meta.storeId] = objectsRegistry.add processId, routingId, value [meta.id, meta.storeId] = objectsRegistry.add processId, routingId, value
meta.members = [] meta.members = []
@ -37,12 +39,14 @@ errorToMeta = (error) ->
type: 'error', message: error.message, stack: (error.stack || error) type: 'error', 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 = (processId, routingId, args) -> unwrapArgs = (sender, args) ->
processId = sender.getProcessId()
routingId = sender.getRoutingId()
metaToValue = (meta) -> metaToValue = (meta) ->
switch meta.type switch meta.type
when 'value' then meta.value when 'value' then meta.value
when 'remote-object' then objectsRegistry.get meta.id when 'remote-object' then objectsRegistry.get meta.id
when 'array' then unwrapArgs processId, routingId, meta.value when 'array' then unwrapArgs sender, meta.value
when 'object' when 'object'
ret = v8Util.createObjectWithName meta.name ret = v8Util.createObjectWithName meta.name
for member in meta.members for member in meta.members
@ -58,10 +62,10 @@ unwrapArgs = (processId, routingId, args) ->
ret = -> ret = ->
throw new Error('Calling a callback of released renderer view') if rendererReleased throw new Error('Calling a callback of released renderer view') if rendererReleased
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(processId, routingId, arguments) sender.send 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments)
v8Util.setDestructor ret, -> v8Util.setDestructor ret, ->
return if rendererReleased return if rendererReleased
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id sender.send 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id
ret ret
else throw new TypeError("Unknown type: #{meta.type}") else throw new TypeError("Unknown type: #{meta.type}")
@ -69,78 +73,80 @@ unwrapArgs = (processId, routingId, args) ->
# Call a function and send reply asynchronously if it's a an asynchronous # Call a function and send reply asynchronously if it's a an asynchronous
# style function and the caller didn't pass a callback. # style function and the caller didn't pass a callback.
callFunction = (event, processId, routingId, func, caller, args) -> callFunction = (event, func, caller, args) ->
if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function' if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function'
args.push (ret) -> args.push (ret) ->
event.returnValue = valueToMeta processId, routingId, ret event.returnValue = valueToMeta event.sender, ret
func.apply caller, args func.apply caller, args
else else
ret = func.apply caller, args ret = func.apply caller, args
event.returnValue = valueToMeta processId, routingId, ret event.returnValue = valueToMeta event.sender, ret
# 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', (processId, routingId) -> process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (processId, routingId) ->
objectsRegistry.clear processId, routingId objectsRegistry.clear processId, routingId
ipc.on 'ATOM_BROWSER_REQUIRE', (event, processId, routingId, module) -> ipc.on 'ATOM_BROWSER_REQUIRE', (event, module) ->
try try
event.returnValue = valueToMeta processId, routingId, require(module) event.returnValue = valueToMeta event.sender, require(module)
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_GLOBAL', (event, processId, routingId, name) -> ipc.on 'ATOM_BROWSER_GLOBAL', (event, name) ->
try try
event.returnValue = valueToMeta processId, routingId, global[name] event.returnValue = valueToMeta event.sender, global[name]
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, processId, routingId) -> ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) ->
try try
BrowserWindow = require 'browser-window' BrowserWindow = require 'browser-window'
processId = event.sender.getProcessId()
routingId = event.sender.getRoutingId()
window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId
window = BrowserWindow.fromDevTools processId, routingId unless window? window = BrowserWindow.fromDevTools processId, routingId unless window?
event.returnValue = valueToMeta processId, routingId, window event.returnValue = valueToMeta event.sender, window
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) -> ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs event.sender, args
constructor = objectsRegistry.get id constructor = objectsRegistry.get id
# Call new with array of arguments. # Call new with array of arguments.
# http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible # http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
obj = new (Function::bind.apply(constructor, [null].concat(args))) obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta processId, routingId, obj event.returnValue = valueToMeta event.sender, obj
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, processId, routingId, id, args) -> ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs event.sender, args
func = objectsRegistry.get id func = objectsRegistry.get id
callFunction event, processId, routingId, func, global, args callFunction event, func, global, args
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, processId, routingId, id, method, args) -> ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs event.sender, args
constructor = objectsRegistry.get(id)[method] 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))) obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta processId, routingId, obj event.returnValue = valueToMeta event.sender, obj
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, processId, routingId, id, method, args) -> ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs event.sender, args
obj = objectsRegistry.get id obj = objectsRegistry.get id
callFunction event, processId, routingId, obj[method], obj, args callFunction event, obj[method], obj, args
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, processId, routingId, id, name, value) -> ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
try try
obj = objectsRegistry.get id obj = objectsRegistry.get id
obj[name] = value obj[name] = value
@ -148,12 +154,14 @@ ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, processId, routingId, id, name, value)
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, processId, routingId, id, name) -> ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) ->
try try
obj = objectsRegistry.get id obj = objectsRegistry.get id
event.returnValue = valueToMeta processId, routingId, obj[name] event.returnValue = valueToMeta event.sender, obj[name]
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_DEREFERENCE', (processId, routingId, storeId) -> ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, storeId) ->
processId = event.sender.getProcessId()
routingId = event.sender.getRoutingId()
objectsRegistry.remove processId, routingId, storeId objectsRegistry.remove processId, routingId, storeId

View file

@ -8,13 +8,10 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "atom/browser/api/atom_browser_bindings.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_javascript_dialog_manager.h" #include "atom/browser/atom_javascript_dialog_manager.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/devtools_delegate.h" #include "atom/browser/devtools_delegate.h"
#include "atom/browser/devtools_web_contents_observer.h"
#include "atom/browser/ui/file_dialog.h" #include "atom/browser/ui/file_dialog.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
#include "atom/common/api/api_messages.h" #include "atom/common/api/api_messages.h"
@ -195,12 +192,8 @@ bool NativeWindow::HasModalDialog() {
void NativeWindow::OpenDevTools() { void NativeWindow::OpenDevTools() {
if (devtools_window_) { if (devtools_window_) {
devtools_window_->Focus(true); devtools_window_->Focus(true);
devtools_web_contents_observer_.reset(new DevToolsWebContentsObserver(
this, devtools_window_->GetWebContents()));
} else { } else {
inspectable_web_contents()->ShowDevTools(); inspectable_web_contents()->ShowDevTools();
devtools_web_contents_observer_.reset(new DevToolsWebContentsObserver(
this, GetDevToolsWebContents()));
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Temporary fix for flashing devtools, try removing this after upgraded to // Temporary fix for flashing devtools, try removing this after upgraded to
// Chrome 32. // Chrome 32.
@ -470,9 +463,6 @@ void NativeWindow::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
bool NativeWindow::OnMessageReceived(const IPC::Message& message) { bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
bool handled = true; bool handled = true;
IPC_BEGIN_MESSAGE_MAP(NativeWindow, message) IPC_BEGIN_MESSAGE_MAP(NativeWindow, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_UpdateDraggableRegions, IPC_MESSAGE_HANDLER(AtomViewHostMsg_UpdateDraggableRegions,
UpdateDraggableRegions) UpdateDraggableRegions)
IPC_MESSAGE_UNHANDLED(handled = false) IPC_MESSAGE_UNHANDLED(handled = false)
@ -602,25 +592,4 @@ void NativeWindow::CallDevToolsFunction(const std::string& function_name,
string16(), base::UTF8ToUTF16(function_name + "(" + params + ");")); string16(), base::UTF8ToUTF16(function_name + "(" + params + ");"));
} }
void NativeWindow::OnRendererMessage(const string16& channel,
const base::ListValue& args) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID(),
channel,
args);
}
void NativeWindow::OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID(),
channel,
args,
GetWebContents(),
reply_msg);
}
} // namespace atom } // namespace atom

View file

@ -46,7 +46,6 @@ namespace atom {
class AtomJavaScriptDialogManager; class AtomJavaScriptDialogManager;
class DevToolsDelegate; class DevToolsDelegate;
class DevToolsWebContentsObserver;
struct DraggableRegion; struct DraggableRegion;
class NativeWindow : public brightray::DefaultWebContentsDelegate, class NativeWindow : public brightray::DefaultWebContentsDelegate,
@ -270,13 +269,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
bool succeed, bool succeed,
const SkBitmap& bitmap); const SkBitmap& bitmap);
void OnRendererMessage(const string16& channel,
const base::ListValue& args);
void OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg);
// Notification manager. // Notification manager.
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
@ -301,9 +293,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
base::WeakPtr<NativeWindow> devtools_window_; base::WeakPtr<NativeWindow> devtools_window_;
scoped_ptr<DevToolsDelegate> devtools_delegate_; scoped_ptr<DevToolsDelegate> devtools_delegate_;
// WebContentsObserver for the WebContents of devtools.
scoped_ptr<DevToolsWebContentsObserver> devtools_web_contents_observer_;
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_; scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
// Notice that inspectable_web_contents_ must be placed after dialog_manager_, // Notice that inspectable_web_contents_ must be placed after dialog_manager_,

View file

@ -12,7 +12,6 @@ NODE_EXT_LIST_START
NODE_EXT_LIST_ITEM(atom_browser_app) NODE_EXT_LIST_ITEM(atom_browser_app)
NODE_EXT_LIST_ITEM(atom_browser_auto_updater) NODE_EXT_LIST_ITEM(atom_browser_auto_updater)
NODE_EXT_LIST_ITEM(atom_browser_dialog) NODE_EXT_LIST_ITEM(atom_browser_dialog)
NODE_EXT_LIST_ITEM(atom_browser_ipc)
NODE_EXT_LIST_ITEM(atom_browser_menu) NODE_EXT_LIST_ITEM(atom_browser_menu)
NODE_EXT_LIST_ITEM(atom_browser_power_monitor) NODE_EXT_LIST_ITEM(atom_browser_power_monitor)
NODE_EXT_LIST_ITEM(atom_browser_protocol) NODE_EXT_LIST_ITEM(atom_browser_protocol)

View file

@ -10,15 +10,13 @@ class Ipc extends EventEmitter
process.removeAllListeners 'ATOM_INTERNAL_MESSAGE' process.removeAllListeners 'ATOM_INTERNAL_MESSAGE'
send: (args...) -> send: (args...) ->
@sendChannel 'message', args... ipc.send 'ipc-message', [args...]
sendChannel: (args...) ->
ipc.send 'ATOM_INTERNAL_MESSAGE', [args...]
sendSync: (args...) -> sendSync: (args...) ->
@sendSync 'sync-message', args... JSON.parse ipc.sendSync('ipc-message-sync', [args...])
sendChannelSync: (args...) -> # Discarded
JSON.parse ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', [args...]) sendChannel: -> @send.apply this, arguments
sendChannelSync: -> @sendSync.apply this, arguments
module.exports = new Ipc module.exports = new Ipc

View file

@ -48,13 +48,13 @@ describe 'ipc module', ->
print_name = remote.require path.join(fixtures, 'module', 'print_name.js') print_name = remote.require path.join(fixtures, 'module', 'print_name.js')
assert.equal print_name.print(buf), 'Buffer' assert.equal print_name.print(buf), 'Buffer'
describe 'ipc.send', -> describe 'ipc.sender.send', ->
it 'should work when sending an object containing id property', (done) -> it 'should work when sending an object containing id property', (done) ->
obj = id: 1, name: 'ly' obj = id: 1, name: 'ly'
ipc.once 'message', (message) -> ipc.once 'message', (message) ->
assert.deepEqual message, obj assert.deepEqual message, obj
done() done()
ipc.send obj ipc.send 'message', obj
describe 'ipc.sendSync', -> describe 'ipc.sendSync', ->
it 'can be replied by setting event.returnValue', -> it 'can be replied by setting event.returnValue', ->

View file

@ -8,8 +8,8 @@ var window = null;
app.commandLine.appendSwitch('js-flags', '--expose_gc'); app.commandLine.appendSwitch('js-flags', '--expose_gc');
ipc.on('message', function() { ipc.on('message', function(event, arg) {
ipc.send.apply(this, arguments); event.sender.send('message', arg);
}); });
ipc.on('console.log', function(pid, rid, args) { ipc.on('console.log', function(pid, rid, args) {
@ -24,11 +24,11 @@ ipc.on('process.exit', function(pid, rid, code) {
process.exit(code); process.exit(code);
}); });
ipc.on('eval', function(ev, pid, rid, script) { ipc.on('eval', function(ev, script) {
ev.returnValue = eval(script); ev.returnValue = eval(script);
}); });
ipc.on('echo', function(ev, pid, rid, msg) { ipc.on('echo', function(ev, msg) {
ev.returnValue = msg; ev.returnValue = msg;
}); });