diff --git a/atom.gyp b/atom.gyp index 8182e82e73cf..832e3e56323b 100644 --- a/atom.gyp +++ b/atom.gyp @@ -7,12 +7,16 @@ ], 'coffee_sources': [ 'browser/api/lib/atom.coffee', + 'browser/api/lib/ipc.coffee', 'browser/api/lib/window.coffee', 'browser/atom/atom.coffee', + 'renderer/api/lib/ipc.coffee', ], 'lib_sources': [ 'app/atom_main_delegate.cc', 'app/atom_main_delegate.h', + 'browser/api/atom_api_browser_ipc.cc', + 'browser/api/atom_api_browser_ipc.h', 'browser/api/atom_api_event.cc', 'browser/api/atom_api_event.h', 'browser/api/atom_api_event_emitter.cc', @@ -52,6 +56,8 @@ 'common/options_switches.h', 'common/v8_value_converter_impl.cc', 'common/v8_value_converter_impl.h', + 'renderer/api/atom_api_renderer_ipc.cc', + 'renderer/api/atom_api_renderer_ipc.h', 'renderer/api/atom_renderer_bindings.cc', 'renderer/api/atom_renderer_bindings.h', 'renderer/atom_render_view_observer.cc', diff --git a/browser/api/atom_api_browser_ipc.cc b/browser/api/atom_api_browser_ipc.cc new file mode 100644 index 000000000000..0173edcfdc75 --- /dev/null +++ b/browser/api/atom_api_browser_ipc.cc @@ -0,0 +1,66 @@ +// 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 "browser/api/atom_api_browser_ipc.h" + +#include "base/values.h" +#include "common/api/api_messages.h" +#include "common/v8_value_converter_impl.h" +#include "content/public/browser/render_view_host.h" +#include "vendor/node/src/node.h" +#include "vendor/node/src/node_internals.h" + +using content::RenderViewHost; +using content::V8ValueConverter; + +namespace atom { + +namespace api { + +// static +v8::Handle BrowserIPC::Send(const v8::Arguments &args) { + v8::HandleScope scope; + + if (!args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsString()) + return node::ThrowTypeError("Bad argument"); + + int process_id = args[0]->IntegerValue(); + int routing_id = args[1]->IntegerValue(); + std::string channel(*v8::String::Utf8Value(args[2])); + + RenderViewHost* render_view_host(RenderViewHost::FromID( + process_id, routing_id)); + if (!render_view_host) + return node::ThrowError("Invalid render view host"); + + // Convert Arguments to Array, so we can use V8ValueConverter to convert it + // to ListValue. + v8::Local v8_args = v8::Array::New(args.Length() - 3); + for (int i = 0; i < args.Length() - 3; ++i) + v8_args->Set(i, args[i + 3]); + + scoped_ptr converter(new V8ValueConverterImpl()); + scoped_ptr arguments( + converter->FromV8Value(v8_args, v8::Context::GetCurrent())); + + DCHECK(arguments && arguments->IsType(base::Value::TYPE_LIST)); + + render_view_host->Send(new AtomViewMsg_Message( + routing_id, + channel, + *static_cast(arguments.get()))); + + return v8::Undefined(); +} + +// static +void BrowserIPC::Initialize(v8::Handle target) { + node::SetMethod(target, "send", Send); +} + +} // namespace api + +} // namespace atom + +NODE_MODULE(atom_browser_ipc, atom::api::BrowserIPC::Initialize) diff --git a/browser/api/atom_api_browser_ipc.h b/browser/api/atom_api_browser_ipc.h new file mode 100644 index 000000000000..5411daf38ab2 --- /dev/null +++ b/browser/api/atom_api_browser_ipc.h @@ -0,0 +1,29 @@ +// 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_API_BROWSER_IPC_H_ +#define ATOM_BROWSER_API_ATOM_API_BROWSER_IPC_H_ + +#include "base/basictypes.h" +#include "v8/include/v8.h" + +namespace atom { + +namespace api { + +class BrowserIPC { + public: + static void Initialize(v8::Handle target); + + private: + static v8::Handle Send(const v8::Arguments &args); + + DISALLOW_IMPLICIT_CONSTRUCTORS(BrowserIPC); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_BROWSER_IPC_H_ diff --git a/browser/api/atom_browser_bindings.cc b/browser/api/atom_browser_bindings.cc index e6be1db6026a..fb9089d9412f 100644 --- a/browser/api/atom_browser_bindings.cc +++ b/browser/api/atom_browser_bindings.cc @@ -40,8 +40,10 @@ void AtomBrowserBindings::AfterLoad() { DCHECK(!browser_main_parts_.IsEmpty()); } -void AtomBrowserBindings::OnRendererMessage( - int routing_id, const base::ListValue& args) { +void AtomBrowserBindings::OnRendererMessage(int process_id, + int routing_id, + const std::string& channel, + const base::ListValue& args) { v8::HandleScope scope; v8::Handle context = v8::Context::GetCurrent(); @@ -49,8 +51,9 @@ void AtomBrowserBindings::OnRendererMessage( scoped_ptr converter(new V8ValueConverterImpl()); std::vector> arguments; - arguments.reserve(2 + args.GetSize()); - arguments.push_back(v8::String::New("message")); + arguments.reserve(3 + args.GetSize()); + arguments.push_back(v8::String::New(channel.c_str(), channel.size())); + arguments.push_back(v8::Integer::New(process_id)); arguments.push_back(v8::Integer::New(routing_id)); for (size_t i = 0; i < args.GetSize(); i++) { diff --git a/browser/api/atom_browser_bindings.h b/browser/api/atom_browser_bindings.h index aa2831ee9937..32b1786b3d95 100644 --- a/browser/api/atom_browser_bindings.h +++ b/browser/api/atom_browser_bindings.h @@ -5,6 +5,8 @@ #ifndef ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_ #define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_ +#include + #include "common/api/atom_bindings.h" namespace base { @@ -22,7 +24,10 @@ class AtomBrowserBindings : public AtomBindings { virtual void AfterLoad(); // Called when received a message from renderer. - void OnRendererMessage(int routing_id, const base::ListValue& args); + void OnRendererMessage(int process_id, + int routing_id, + const std::string& channel, + const base::ListValue& args); // The require('atom').browserMainParts object. v8::Handle browser_main_parts() { diff --git a/browser/api/lib/ipc.coffee b/browser/api/lib/ipc.coffee new file mode 100644 index 000000000000..5f3b3a469478 --- /dev/null +++ b/browser/api/lib/ipc.coffee @@ -0,0 +1,12 @@ +EventEmitter = require('events').EventEmitter +send = process.atom_binding('ipc').send + +class Ipc extends EventEmitter + constructor: -> + process.on 'ATOM_INTERNAL_MESSAGE', (args...) => + @emit('message', args...) + + send: (process_id, routing_id, args...) -> + send(process_id, routing_id, 'ATOM_INTERNAL_MESSAGE', args...) + +module.exports = new Ipc diff --git a/browser/default_app/main.js b/browser/default_app/main.js index ebbd4ca4bab0..12873bf95a15 100644 --- a/browser/default_app/main.js +++ b/browser/default_app/main.js @@ -1,10 +1,12 @@ var atom = require('atom'); +var ipc = require('ipc'); var Window = require('window'); var mainWindow = null; -process.on('message', function() { - console.log.apply(this, arguments); +ipc.on('message', function(process_id, routing_id) { + console.log('message from', process_id, routing_id); + ipc.send.apply(ipc, arguments); }); atom.browserMainParts.preMainMessageLoopRun = function() { diff --git a/browser/native_window.cc b/browser/native_window.cc index be29cdbe6a89..d5665119cd35 100644 --- a/browser/native_window.cc +++ b/browser/native_window.cc @@ -17,6 +17,7 @@ #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" +#include "content/public/browser/render_process_host.h" #include "common/api/api_messages.h" #include "common/options_switches.h" #include "ipc/ipc_message_macros.h" @@ -159,9 +160,13 @@ void NativeWindow::Observe(int type, } } -void NativeWindow::OnRendererMessage(const base::ListValue& args) { +void NativeWindow::OnRendererMessage(const std::string& channel, + const base::ListValue& args) { AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage( - GetWebContents()->GetRoutingID(), args); + GetWebContents()->GetRenderProcessHost()->GetID(), + GetWebContents()->GetRoutingID(), + channel, + args); } } // namespace atom diff --git a/browser/native_window.h b/browser/native_window.h index b65ff17f6d75..0bc1ed35f840 100644 --- a/browser/native_window.h +++ b/browser/native_window.h @@ -120,7 +120,8 @@ class NativeWindow : public content::WebContentsDelegate, const content::NotificationDetails& details) OVERRIDE; private: - void OnRendererMessage(const base::ListValue& args); + void OnRendererMessage(const std::string& channel, + const base::ListValue& args); // Notification manager. content::NotificationRegistrar registrar_; diff --git a/common/api/api_messages.h b/common/api/api_messages.h index 8a3083a862f2..34d47405f6d7 100644 --- a/common/api/api_messages.h +++ b/common/api/api_messages.h @@ -15,8 +15,10 @@ #define IPC_MESSAGE_START ShellMsgStart -IPC_MESSAGE_ROUTED1(AtomViewHostMsg_Message, +IPC_MESSAGE_ROUTED2(AtomViewHostMsg_Message, + std::string /* channel */, ListValue /* arguments */) -IPC_MESSAGE_ROUTED1(AtomViewMsg_Message, +IPC_MESSAGE_ROUTED2(AtomViewMsg_Message, + std::string /* channel */, ListValue /* arguments */) diff --git a/common/api/atom_extensions.h b/common/api/atom_extensions.h index 47bdd3789c33..2a985e5946d9 100644 --- a/common/api/atom_extensions.h +++ b/common/api/atom_extensions.h @@ -8,6 +8,9 @@ NODE_EXT_LIST_START +NODE_EXT_LIST_ITEM(atom_browser_ipc) NODE_EXT_LIST_ITEM(atom_browser_window) +NODE_EXT_LIST_ITEM(atom_renderer_ipc) + NODE_EXT_LIST_END diff --git a/renderer/api/atom_api_renderer_ipc.cc b/renderer/api/atom_api_renderer_ipc.cc new file mode 100644 index 000000000000..4bd27751d3c5 --- /dev/null +++ b/renderer/api/atom_api_renderer_ipc.cc @@ -0,0 +1,83 @@ +// 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 "renderer/api/atom_api_renderer_ipc.h" + +#include "base/values.h" +#include "common/api/api_messages.h" +#include "content/public/renderer/render_view.h" +#include "content/public/renderer/v8_value_converter.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#include "vendor/node/src/node.h" + +using content::RenderView; +using content::V8ValueConverter; +using WebKit::WebFrame; +using WebKit::WebView; + +namespace atom { + +namespace api { + +namespace { + +RenderView* GetCurrentRenderView() { + WebFrame* frame = WebFrame::frameForCurrentContext(); + DCHECK(frame); + if (!frame) + return NULL; + + WebView* view = frame->view(); + if (!view) + return NULL; // can happen during closing. + + RenderView* render_view = RenderView::FromWebView(view); + DCHECK(render_view); + return render_view; +} + +} // namespace + +// static +v8::Handle RendererIPC::Send(const v8::Arguments &args) { + v8::HandleScope scope; + + if (!args[0]->IsString()) + return node::ThrowTypeError("Bad argument"); + + std::string channel(*v8::String::Utf8Value(args[0])); + + RenderView* render_view = GetCurrentRenderView(); + + // Convert Arguments to Array, so we can use V8ValueConverter to convert it + // to ListValue. + v8::Local v8_args = v8::Array::New(args.Length() - 1); + for (int i = 0; i < args.Length() - 1; ++i) + v8_args->Set(i, args[i + 1]); + + scoped_ptr converter(V8ValueConverter::create()); + scoped_ptr arguments( + converter->FromV8Value(v8_args, v8::Context::GetCurrent())); + + DCHECK(arguments && arguments->IsType(base::Value::TYPE_LIST)); + + render_view->Send(new AtomViewHostMsg_Message( + render_view->GetRoutingID(), + channel, + *static_cast(arguments.get()))); + + return v8::Undefined(); +} + +// static +void RendererIPC::Initialize(v8::Handle target) { + node::SetMethod(target, "send", Send); +} + +} // namespace api + +} // namespace atom + +NODE_MODULE(atom_renderer_ipc, atom::api::RendererIPC::Initialize) diff --git a/renderer/api/atom_api_renderer_ipc.h b/renderer/api/atom_api_renderer_ipc.h new file mode 100644 index 000000000000..30affee076ae --- /dev/null +++ b/renderer/api/atom_api_renderer_ipc.h @@ -0,0 +1,29 @@ +// 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_RENDERER_API_ATOM_API_RENDERER_IPC_H_ +#define ATOM_RENDERER_API_ATOM_API_RENDERER_IPC_H_ + +#include "base/basictypes.h" +#include "v8/include/v8.h" + +namespace atom { + +namespace api { + +class RendererIPC { + public: + static void Initialize(v8::Handle target); + + private: + static v8::Handle Send(const v8::Arguments &args); + + DISALLOW_IMPLICIT_CONSTRUCTORS(RendererIPC); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_RENDERER_API_ATOM_API_RENDERER_IPC_H_ diff --git a/renderer/api/atom_renderer_bindings.cc b/renderer/api/atom_renderer_bindings.cc index 15276dd3aaf4..702690c0c5a8 100644 --- a/renderer/api/atom_renderer_bindings.cc +++ b/renderer/api/atom_renderer_bindings.cc @@ -4,9 +4,10 @@ #include "renderer/api/atom_renderer_bindings.h" +#include + #include "base/logging.h" #include "base/values.h" -#include "common/api/api_messages.h" #include "content/public/renderer/render_view.h" #include "content/public/renderer/v8_value_converter.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" @@ -16,7 +17,6 @@ using content::RenderView; using content::V8ValueConverter; using WebKit::WebFrame; -using WebKit::WebView; namespace atom { @@ -30,21 +30,6 @@ v8::Handle GetProcessObject(v8::Handle context) { return process; } -RenderView* GetCurrentRenderView() { - WebFrame* frame = WebFrame::frameForCurrentContext(); - DCHECK(frame); - if (!frame) - return NULL; - - WebView* view = frame->view(); - if (!view) - return NULL; // can happen during closing. - - RenderView* render_view = RenderView::FromWebView(view); - DCHECK(render_view); - return render_view; -} - } // namespace AtomRendererBindings::AtomRendererBindings(RenderView* render_view) @@ -66,43 +51,34 @@ void AtomRendererBindings::BindToFrame(WebFrame* frame) { AtomBindings::BindTo(GetProcessObject(context)); } -void AtomRendererBindings::AddIPCBindings(WebFrame* frame) { - v8::HandleScope handle_scope; +void AtomRendererBindings::OnRendererMessage(const std::string& channel, + const base::ListValue& args) { + if (!render_view_->GetWebView()) + return; - v8::Handle context = frame->mainWorldScriptContext(); + v8::HandleScope scope; + + v8::Local context = + render_view_->GetWebView()->mainFrame()->mainWorldScriptContext(); if (context.IsEmpty()) return; - v8::Context::Scope scope(context); + v8::Context::Scope context_scope(context); v8::Handle process = GetProcessObject(context); - - node::SetMethod(process, "send", Send); -} - -// static -v8::Handle AtomRendererBindings::Send(const v8::Arguments &args) { - v8::HandleScope scope; - - RenderView* render_view = GetCurrentRenderView(); - - // Convert Arguments to Array, so we can use V8ValueConverter to convert it - // to ListValue. - v8::Local v8_args = v8::Array::New(args.Length()); - for (int i = 0; i < args.Length(); ++i) - v8_args->Set(i, args[i]); - scoped_ptr converter(V8ValueConverter::create()); - scoped_ptr arguments( - converter->FromV8Value(v8_args, v8::Context::GetCurrent())); - DCHECK(arguments && arguments->IsType(base::Value::TYPE_LIST)); + std::vector> arguments; + arguments.reserve(1 + args.GetSize()); + arguments.push_back(v8::String::New(channel.c_str(), channel.size())); - render_view->Send(new AtomViewHostMsg_Message( - render_view->GetRoutingID(), - *static_cast(arguments.get()))); + for (size_t i = 0; i < args.GetSize(); i++) { + const base::Value* value; + if (args.Get(i, &value)) + arguments.push_back(converter->ToV8Value(value, context)); + } - return v8::Undefined(); + node::MakeCallback(process, "emit", arguments.size(), &arguments[0]); } } // namespace atom diff --git a/renderer/api/atom_renderer_bindings.h b/renderer/api/atom_renderer_bindings.h index 4be2a642029b..17bc1a0dbe6c 100644 --- a/renderer/api/atom_renderer_bindings.h +++ b/renderer/api/atom_renderer_bindings.h @@ -2,11 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_ -#define ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_ +#ifndef ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_ +#define ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_ + +#include #include "common/api/atom_bindings.h" +namespace base { +class ListValue; +} + namespace content { class RenderView; } @@ -25,12 +31,11 @@ class AtomRendererBindings : public AtomBindings { // Call BindTo for process object of the frame. void BindToFrame(WebKit::WebFrame* frame); - // Add process.send and make process.on accept IPC message. - void AddIPCBindings(WebKit::WebFrame* frame); + // Dispatch messages from browser. + void OnRendererMessage(const std::string& channel, + const base::ListValue& args); private: - static v8::Handle Send(const v8::Arguments &args); - content::RenderView* render_view_; DISALLOW_COPY_AND_ASSIGN(AtomRendererBindings); @@ -38,4 +43,4 @@ class AtomRendererBindings : public AtomBindings { } // namespace atom -#endif // ATOM_RENDERER_API_ATOM_BINDINGS_ +#endif // ATOM_RENDERER_API_ATOM_BINDINGS_H_ diff --git a/renderer/api/lib/ipc.coffee b/renderer/api/lib/ipc.coffee new file mode 100644 index 000000000000..c36dd0312a6e --- /dev/null +++ b/renderer/api/lib/ipc.coffee @@ -0,0 +1,12 @@ +EventEmitter = require('events').EventEmitter +send = process.atom_binding('ipc').send + +class Ipc extends EventEmitter + constructor: -> + process.on 'ATOM_INTERNAL_MESSAGE', (args...) => + @emit('message', args...) + + send: (args...) -> + send('ATOM_INTERNAL_MESSAGE', args...) + +module.exports = new Ipc diff --git a/renderer/api/lib/remote_object.coffee b/renderer/api/lib/remote_object.coffee deleted file mode 100644 index d1d39a29eb5a..000000000000 --- a/renderer/api/lib/remote_object.coffee +++ /dev/null @@ -1,3 +0,0 @@ -RemoteObject = process.atom_binding('remote_object').RemoteObject - -module.exports = RemoteObject diff --git a/renderer/atom_render_view_observer.cc b/renderer/atom_render_view_observer.cc index cd025050aa98..30007cce3137 100644 --- a/renderer/atom_render_view_observer.cc +++ b/renderer/atom_render_view_observer.cc @@ -7,7 +7,9 @@ #include #include +#include "common/api/api_messages.h" #include "common/node_bindings.h" +#include "ipc/ipc_message_macros.h" #include "renderer/api/atom_renderer_bindings.h" #include "renderer/atom_renderer_client.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" @@ -70,7 +72,6 @@ void AtomRenderViewObserver::DidClearWindowObject(WebFrame* frame) { renderer_client_->node_bindings()->BindTo(frame); atom_bindings()->BindToFrame(frame); - atom_bindings()->AddIPCBindings(frame); } void AtomRenderViewObserver::FrameWillClose(WebFrame* frame) { @@ -78,4 +79,19 @@ void AtomRenderViewObserver::FrameWillClose(WebFrame* frame) { vec.erase(std::remove(vec.begin(), vec.end(), frame), vec.end()); } +bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(AtomRenderViewObserver, message) + IPC_MESSAGE_HANDLER(AtomViewMsg_Message, OnRendererMessage) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; +} + +void AtomRenderViewObserver::OnRendererMessage(const std::string& channel, + const base::ListValue& args) { + atom_bindings()->OnRendererMessage(channel, args); +} + } // namespace atom diff --git a/renderer/atom_render_view_observer.h b/renderer/atom_render_view_observer.h index 23c23eb9641c..82715f81b25b 100644 --- a/renderer/atom_render_view_observer.h +++ b/renderer/atom_render_view_observer.h @@ -8,6 +8,10 @@ #include "base/memory/scoped_ptr.h" #include "content/public/renderer/render_view_observer.h" +namespace base { +class ListValue; +} + namespace atom { class AtomRendererBindings; @@ -27,6 +31,12 @@ class AtomRenderViewObserver : content::RenderViewObserver { virtual void FrameWillClose(WebKit::WebFrame*) OVERRIDE; private: + // content::RenderViewObserver implementation. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + void OnRendererMessage(const std::string& channel, + const base::ListValue& args); + scoped_ptr atom_bindings_; // Weak reference to renderer client.