diff --git a/browser/api/atom_browser_bindings.cc b/browser/api/atom_browser_bindings.cc index 1d6c795498a2..fb102ff1c753 100644 --- a/browser/api/atom_browser_bindings.cc +++ b/browser/api/atom_browser_bindings.cc @@ -50,7 +50,7 @@ void AtomBrowserBindings::OnRendererMessage(int process_id, scoped_ptr converter(new V8ValueConverterImpl()); - // process.emit('ATOM_INTERNAL_MESSAGE', 'message', process_id, routing_id); + // process.emit(channel, 'message', process_id, routing_id); std::vector> arguments; arguments.reserve(3 + args.GetSize()); arguments.push_back(v8::String::New(channel.c_str(), channel.size())); @@ -69,4 +69,43 @@ void AtomBrowserBindings::OnRendererMessage(int process_id, node::MakeCallback(node::process, "emit", arguments.size(), &arguments[0]); } +void AtomBrowserBindings::OnRendererMessageSync( + int process_id, + int routing_id, + const std::string& channel, + const base::ListValue& args, + base::DictionaryValue* result) { + v8::HandleScope scope; + + v8::Handle context = v8::Context::GetCurrent(); + + scoped_ptr converter(new V8ValueConverterImpl()); + + v8::Handle event = v8::Object::New(); + + // process.emit(channel, 'sync-message', event, process_id, routing_id); + std::vector> arguments; + arguments.reserve(3 + args.GetSize()); + arguments.push_back(v8::String::New(channel.c_str(), channel.size())); + const base::Value* value; + if (args.Get(0, &value)) + arguments.push_back(converter->ToV8Value(value, context)); + arguments.push_back(event); + 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, context)); + } + + node::MakeCallback(node::process, "emit", arguments.size(), &arguments[0]); + + scoped_ptr base_event(converter->FromV8Value(event, context)); + DCHECK(base_event && base_event->IsType(base::Value::TYPE_DICTIONARY)); + + result->Swap(static_cast(base_event.get())); +} + } // namespace atom diff --git a/browser/api/atom_browser_bindings.h b/browser/api/atom_browser_bindings.h index 32b1786b3d95..1b05131a1b27 100644 --- a/browser/api/atom_browser_bindings.h +++ b/browser/api/atom_browser_bindings.h @@ -10,6 +10,7 @@ #include "common/api/atom_bindings.h" namespace base { +class DictionaryValue; class ListValue; } @@ -29,6 +30,13 @@ class AtomBrowserBindings : public AtomBindings { const std::string& channel, const base::ListValue& args); + // Called when received a synchronous message from renderer. + void OnRendererMessageSync(int process_id, + int routing_id, + const std::string& channel, + const base::ListValue& args, + base::DictionaryValue* result); + // The require('atom').browserMainParts object. v8::Handle browser_main_parts() { return browser_main_parts_; diff --git a/browser/api/lib/ipc.coffee b/browser/api/lib/ipc.coffee index 80d56b123099..eea279c27b4d 100644 --- a/browser/api/lib/ipc.coffee +++ b/browser/api/lib/ipc.coffee @@ -5,6 +5,8 @@ class Ipc extends EventEmitter constructor: -> process.on 'ATOM_INTERNAL_MESSAGE', (args...) => @emit(args...) + process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (args...) => + @emit(args...) send: (process_id, routing_id, args...) -> @sendChannel(process_id, routing_id, 'message', args...) diff --git a/browser/default_app/main.js b/browser/default_app/main.js index f5e43abda1b4..a0c14fe162d5 100644 --- a/browser/default_app/main.js +++ b/browser/default_app/main.js @@ -9,6 +9,10 @@ ipc.on('message', function(process_id, routing_id) { ipc.send.apply(ipc, arguments); }); +ipc.on('sync-message', function(event, process_id, routing_id) { + event.result = arguments; +}); + atom.browserMainParts.preMainMessageLoopRun = function() { mainWindow = new Window({ width: 800, height: 600 }); mainWindow.url = 'file://' + __dirname + '/index.html'; diff --git a/browser/native_window.cc b/browser/native_window.cc index d5665119cd35..092d3a9085e9 100644 --- a/browser/native_window.cc +++ b/browser/native_window.cc @@ -134,6 +134,7 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(NativeWindow, message) IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage) + IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message_Sync, OnRendererMessageSync) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -169,4 +170,15 @@ void NativeWindow::OnRendererMessage(const std::string& channel, args); } +void NativeWindow::OnRendererMessageSync(const std::string& channel, + const base::ListValue& args, + base::DictionaryValue* result) { + AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync( + GetWebContents()->GetRenderProcessHost()->GetID(), + GetWebContents()->GetRoutingID(), + channel, + args, + result); +} + } // namespace atom diff --git a/browser/native_window.h b/browser/native_window.h index 0bc1ed35f840..b42f26d4fc98 100644 --- a/browser/native_window.h +++ b/browser/native_window.h @@ -123,6 +123,10 @@ class NativeWindow : public content::WebContentsDelegate, void OnRendererMessage(const std::string& channel, const base::ListValue& args); + void OnRendererMessageSync(const std::string& channel, + const base::ListValue& args, + base::DictionaryValue* result); + // Notification manager. content::NotificationRegistrar registrar_; diff --git a/common/api/api_messages.h b/common/api/api_messages.h index 34d47405f6d7..cc6d5f681f33 100644 --- a/common/api/api_messages.h +++ b/common/api/api_messages.h @@ -19,6 +19,16 @@ IPC_MESSAGE_ROUTED2(AtomViewHostMsg_Message, std::string /* channel */, ListValue /* arguments */) +IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync, + std::string /* channel */, + ListValue /* arguments */, + DictionaryValue /* result */) + IPC_MESSAGE_ROUTED2(AtomViewMsg_Message, std::string /* channel */, ListValue /* arguments */) + +IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewMsg_Message_Sync, + std::string /* channel */, + ListValue /* arguments */, + DictionaryValue /* result */) diff --git a/renderer/api/atom_api_renderer_ipc.cc b/renderer/api/atom_api_renderer_ipc.cc index 4bd27751d3c5..cc2cc7cfc908 100644 --- a/renderer/api/atom_api_renderer_ipc.cc +++ b/renderer/api/atom_api_renderer_ipc.cc @@ -63,17 +63,57 @@ v8::Handle RendererIPC::Send(const v8::Arguments &args) { DCHECK(arguments && arguments->IsType(base::Value::TYPE_LIST)); - render_view->Send(new AtomViewHostMsg_Message( + bool success = render_view->Send(new AtomViewHostMsg_Message( render_view->GetRoutingID(), channel, *static_cast(arguments.get()))); + if (!success) + return node::ThrowError("Unable to send AtomViewHostMsg_Message"); + return v8::Undefined(); } +// static +v8::Handle RendererIPC::SendSync(const v8::Arguments &args) { + v8::HandleScope scope; + + if (!args[0]->IsString()) + return node::ThrowTypeError("Bad argument"); + + v8::Handle context = v8::Context::GetCurrent(); + std::string channel(*v8::String::Utf8Value(args[0])); + + // 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, context)); + + DCHECK(arguments && arguments->IsType(base::Value::TYPE_LIST)); + + RenderView* render_view = GetCurrentRenderView(); + + base::DictionaryValue result; + bool success = render_view->Send(new AtomViewHostMsg_Message_Sync( + render_view->GetRoutingID(), + channel, + *static_cast(arguments.get()), + &result)); + + if (!success) + return node::ThrowError("Unable to send AtomViewHostMsg_Message_Sync"); + + return scope.Close(converter->ToV8Value(&result, context)); +} + // static void RendererIPC::Initialize(v8::Handle target) { node::SetMethod(target, "send", Send); + node::SetMethod(target, "sendSync", SendSync); } } // namespace api diff --git a/renderer/api/atom_api_renderer_ipc.h b/renderer/api/atom_api_renderer_ipc.h index 30affee076ae..9e880e370e65 100644 --- a/renderer/api/atom_api_renderer_ipc.h +++ b/renderer/api/atom_api_renderer_ipc.h @@ -18,6 +18,7 @@ class RendererIPC { private: static v8::Handle Send(const v8::Arguments &args); + static v8::Handle SendSync(const v8::Arguments &args); DISALLOW_IMPLICIT_CONSTRUCTORS(RendererIPC); }; diff --git a/renderer/api/lib/ipc.coffee b/renderer/api/lib/ipc.coffee index cafb25bf5ac6..4c21c48b2db0 100644 --- a/renderer/api/lib/ipc.coffee +++ b/renderer/api/lib/ipc.coffee @@ -1,15 +1,23 @@ EventEmitter = require('events').EventEmitter -send = process.atom_binding('ipc').send +ipc = process.atom_binding('ipc') class Ipc extends EventEmitter constructor: -> process.on 'ATOM_INTERNAL_MESSAGE', (args...) => @emit(args...) + process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (args...) => + @emit(args...) send: (args...) -> @sendChannel('message', args...) sendChannel: (args...) -> - send('ATOM_INTERNAL_MESSAGE', args...) + ipc.send('ATOM_INTERNAL_MESSAGE', args...) + + sendSync: (args...) -> + ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', 'sync-message', args...).result + + sendChannelSync: (args...) -> + ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', args...).result module.exports = new Ipc