Merge pull request #101 from atom/no-blocking-browser

Make the browser non-blocking
This commit is contained in:
Cheng Zhao 2013-09-24 16:48:29 -07:00
commit 6aefb0f76f
38 changed files with 999 additions and 412 deletions

View file

@ -157,6 +157,7 @@
'common/platform_util.h', 'common/platform_util.h',
'common/platform_util_mac.mm', 'common/platform_util_mac.mm',
'common/platform_util_win.cc', 'common/platform_util_win.cc',
'common/v8_conversions.h',
'common/v8_value_converter_impl.cc', 'common/v8_value_converter_impl.cc',
'common/v8_value_converter_impl.h', 'common/v8_value_converter_impl.h',
'renderer/api/atom_api_renderer_ipc.cc', 'renderer/api/atom_api_renderer_ipc.cc',

View file

@ -7,6 +7,7 @@
#include "base/values.h" #include "base/values.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "browser/browser.h" #include "browser/browser.h"
#include "common/v8_conversions.h"
#include "vendor/node/src/node.h" #include "vendor/node/src/node.h"
namespace atom { namespace atom {
@ -111,14 +112,14 @@ v8::Handle<v8::Value> App::GetVersion(const v8::Arguments &args) {
v8::Handle<v8::Value> App::AppendSwitch(const v8::Arguments &args) { v8::Handle<v8::Value> App::AppendSwitch(const v8::Arguments &args) {
v8::HandleScope scope; v8::HandleScope scope;
if (!args[0]->IsString()) std::string switch_string;
if (!FromV8Arguments(args, &switch_string))
return node::ThrowError("Bad argument"); return node::ThrowError("Bad argument");
std::string switch_string(*v8::String::Utf8Value(args[0]));
if (args.Length() == 1) { if (args.Length() == 1) {
CommandLine::ForCurrentProcess()->AppendSwitch(switch_string); CommandLine::ForCurrentProcess()->AppendSwitch(switch_string);
} else { } else {
std::string value(*v8::String::Utf8Value(args[1])); std::string value = FromV8Value(args[1]);
CommandLine::ForCurrentProcess()->AppendSwitchASCII( CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switch_string, value); switch_string, value);
} }
@ -130,10 +131,10 @@ v8::Handle<v8::Value> App::AppendSwitch(const v8::Arguments &args) {
v8::Handle<v8::Value> App::AppendArgument(const v8::Arguments &args) { v8::Handle<v8::Value> App::AppendArgument(const v8::Arguments &args) {
v8::HandleScope scope; v8::HandleScope scope;
if (!args[0]->IsString()) std::string value;
if (!FromV8Arguments(args, &value))
return node::ThrowError("Bad argument"); return node::ThrowError("Bad argument");
std::string value(*v8::String::Utf8Value(args[0]));
CommandLine::ForCurrentProcess()->AppendArg(value); CommandLine::ForCurrentProcess()->AppendArg(value);
return v8::Undefined(); return v8::Undefined();
@ -143,7 +144,7 @@ v8::Handle<v8::Value> App::AppendArgument(const v8::Arguments &args) {
// static // static
v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) { v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) {
std::string type(*v8::String::Utf8Value(args[0])); std::string type = FromV8Value(args[0]);
int request_id = -1; int request_id = -1;
if (type == "critical") if (type == "critical")
@ -158,21 +159,20 @@ v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) {
// static // static
v8::Handle<v8::Value> App::DockCancelBounce(const v8::Arguments& args) { v8::Handle<v8::Value> App::DockCancelBounce(const v8::Arguments& args) {
Browser::Get()->DockCancelBounce(args[0]->IntegerValue()); Browser::Get()->DockCancelBounce(FromV8Value(args[0]));
return v8::Undefined(); return v8::Undefined();
} }
// static // static
v8::Handle<v8::Value> App::DockSetBadgeText(const v8::Arguments& args) { v8::Handle<v8::Value> App::DockSetBadgeText(const v8::Arguments& args) {
std::string label(*v8::String::Utf8Value(args[0])); Browser::Get()->DockSetBadgeText(FromV8Value(args[0]));
Browser::Get()->DockSetBadgeText(label);
return v8::Undefined(); return v8::Undefined();
} }
// static // static
v8::Handle<v8::Value> App::DockGetBadgeText(const v8::Arguments& args) { v8::Handle<v8::Value> App::DockGetBadgeText(const v8::Arguments& args) {
std::string text(Browser::Get()->DockGetBadgeText()); std::string text(Browser::Get()->DockGetBadgeText());
return v8::String::New(text.data(), text.size()); return ToV8Value(text);
} }
#endif // defined(OS_MACOSX) #endif // defined(OS_MACOSX)

View file

@ -6,6 +6,7 @@
#include "base/values.h" #include "base/values.h"
#include "browser/auto_updater.h" #include "browser/auto_updater.h"
#include "common/v8_conversions.h"
namespace atom { namespace atom {
@ -56,7 +57,7 @@ v8::Handle<v8::Value> AutoUpdater::New(const v8::Arguments &args) {
// static // static
v8::Handle<v8::Value> AutoUpdater::SetFeedURL(const v8::Arguments &args) { v8::Handle<v8::Value> AutoUpdater::SetFeedURL(const v8::Arguments &args) {
auto_updater::AutoUpdater::SetFeedURL(*v8::String::Utf8Value(args[0])); auto_updater::AutoUpdater::SetFeedURL(FromV8Value(args[0]));
return v8::Undefined(); return v8::Undefined();
} }

View file

@ -6,6 +6,7 @@
#include "base/values.h" #include "base/values.h"
#include "common/api/api_messages.h" #include "common/api/api_messages.h"
#include "common/v8_conversions.h"
#include "common/v8_value_converter_impl.h" #include "common/v8_value_converter_impl.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "vendor/node/src/node.h" #include "vendor/node/src/node.h"
@ -22,13 +23,11 @@ namespace api {
v8::Handle<v8::Value> BrowserIPC::Send(const v8::Arguments &args) { v8::Handle<v8::Value> BrowserIPC::Send(const v8::Arguments &args) {
v8::HandleScope scope; v8::HandleScope scope;
if (!args[0]->IsString() || !args[1]->IsNumber() || !args[2]->IsNumber()) string16 channel;
int process_id, routing_id;
if (!FromV8Arguments(args, &channel, &process_id, &routing_id))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
std::string channel(*v8::String::Utf8Value(args[0]));
int process_id = args[1]->IntegerValue();
int routing_id = args[2]->IntegerValue();
RenderViewHost* render_view_host(RenderViewHost::FromID( RenderViewHost* render_view_host(RenderViewHost::FromID(
process_id, routing_id)); process_id, routing_id));
if (!render_view_host) if (!render_view_host)

View file

@ -5,6 +5,7 @@
#include "browser/api/atom_api_crash_reporter.h" #include "browser/api/atom_api_crash_reporter.h"
#include "browser/crash_reporter.h" #include "browser/crash_reporter.h"
#include "common/v8_conversions.h"
#include "vendor/node/src/node.h" #include "vendor/node/src/node.h"
#include "vendor/node/src/node_internals.h" #include "vendor/node/src/node_internals.h"
@ -14,22 +15,20 @@ namespace api {
// static // static
v8::Handle<v8::Value> CrashReporter::SetCompanyName(const v8::Arguments &args) { v8::Handle<v8::Value> CrashReporter::SetCompanyName(const v8::Arguments &args) {
std::string name(*v8::String::Utf8Value(args[0])); crash_reporter::CrashReporter::SetCompanyName(FromV8Value(args[0]));
crash_reporter::CrashReporter::SetCompanyName(name);
return v8::Undefined(); return v8::Undefined();
} }
// static // static
v8::Handle<v8::Value> CrashReporter::SetSubmissionURL( v8::Handle<v8::Value> CrashReporter::SetSubmissionURL(
const v8::Arguments &args) { const v8::Arguments &args) {
std::string url(*v8::String::Utf8Value(args[0])); crash_reporter::CrashReporter::SetSubmissionURL(FromV8Value(args[0]));
crash_reporter::CrashReporter::SetSubmissionURL(url);
return v8::Undefined(); return v8::Undefined();
} }
// static // static
v8::Handle<v8::Value> CrashReporter::SetAutoSubmit(const v8::Arguments &args) { v8::Handle<v8::Value> CrashReporter::SetAutoSubmit(const v8::Arguments &args) {
crash_reporter::CrashReporter::SetAutoSubmit(args[0]->BooleanValue()); crash_reporter::CrashReporter::SetAutoSubmit(FromV8Value(args[0]));
return v8::Undefined(); return v8::Undefined();
} }

View file

@ -4,14 +4,14 @@
#include "browser/api/atom_api_dialog.h" #include "browser/api/atom_api_dialog.h"
#include <string> #include "base/bind.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "browser/api/atom_api_window.h"
#include "browser/native_window.h" #include "browser/native_window.h"
#include "browser/ui/file_dialog.h" #include "browser/ui/file_dialog.h"
#include "browser/ui/message_box.h" #include "browser/ui/message_box.h"
#include "common/v8_conversions.h"
#include "vendor/node/src/node_internals.h"
using node::node_isolate;
namespace atom { namespace atom {
@ -19,14 +19,24 @@ namespace api {
namespace { namespace {
base::FilePath V8ValueToFilePath(v8::Handle<v8::Value> path) { template<typename T>
std::string path_string(*v8::String::Utf8Value(path)); void CallV8Function(v8::Persistent<v8::Function> callback, T arg) {
return base::FilePath::FromUTF8Unsafe(path_string); DCHECK(!callback.IsEmpty());
v8::HandleScope scope;
v8::Handle<v8::Value> value = ToV8Value(arg);
callback->Call(callback, 1, &value);
callback.Dispose(node_isolate);
} }
v8::Handle<v8::Value> FilePathToV8Value(const base::FilePath path) { template<typename T>
std::string path_string(path.AsUTF8Unsafe()); void CallV8Function2(v8::Persistent<v8::Function> callback,
return v8::String::New(path_string.data(), path_string.size()); bool result,
T arg) {
if (result)
return CallV8Function<T>(callback, arg);
else
return CallV8Function<void*>(callback, NULL);
} }
void Initialize(v8::Handle<v8::Object> target) { void Initialize(v8::Handle<v8::Object> target) {
@ -42,84 +52,103 @@ void Initialize(v8::Handle<v8::Object> target) {
v8::Handle<v8::Value> ShowMessageBox(const v8::Arguments &args) { v8::Handle<v8::Value> ShowMessageBox(const v8::Arguments &args) {
v8::HandleScope scope; v8::HandleScope scope;
if (!args[0]->IsNumber() || // type int type;
!args[1]->IsArray() || // buttons std::vector<std::string> buttons;
!args[2]->IsString() || // title std::string title, message, detail;
!args[3]->IsString() || // message if (!FromV8Arguments(args, &type, &buttons, &title, &message, &detail))
!args[4]->IsString()) // detail
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
NativeWindow* native_window = NULL; NativeWindow* native_window = FromV8Value(args[5]);
if (args[5]->IsObject()) { v8::Persistent<v8::Function> callback = FromV8Value(args[6]);
Window* window = Window::Unwrap<Window>(args[5]->ToObject());
if (!window || !window->window())
return node::ThrowError("Invalid window");
native_window = window->window();
}
MessageBoxType type = (MessageBoxType)(args[0]->IntegerValue());
std::vector<std::string> buttons;
v8::Handle<v8::Array> v8_buttons = v8::Handle<v8::Array>::Cast(args[1]);
for (uint32_t i = 0; i < v8_buttons->Length(); ++i)
buttons.push_back(*v8::String::Utf8Value(v8_buttons->Get(i)));
std::string title(*v8::String::Utf8Value(args[2]));
std::string message(*v8::String::Utf8Value(args[3]));
std::string detail(*v8::String::Utf8Value(args[4]));
if (callback.IsEmpty()) {
int chosen = atom::ShowMessageBox( int chosen = atom::ShowMessageBox(
native_window, type, buttons, title, message, detail); native_window,
(MessageBoxType)type,
buttons,
title,
message,
detail);
return scope.Close(v8::Integer::New(chosen)); return scope.Close(v8::Integer::New(chosen));
} else {
atom::ShowMessageBox(
native_window,
(MessageBoxType)type,
buttons,
title,
message,
detail,
base::Bind(&CallV8Function<int>, callback));
return v8::Undefined();
}
} }
v8::Handle<v8::Value> ShowOpenDialog(const v8::Arguments &args) { v8::Handle<v8::Value> ShowOpenDialog(const v8::Arguments &args) {
v8::HandleScope scope; v8::HandleScope scope;
if (!args[0]->IsString() || // title std::string title;
!args[1]->IsString() || // default_path base::FilePath default_path;
!args[2]->IsNumber()) // properties int properties;
if (!FromV8Arguments(args, &title, &default_path, &properties))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
std::string title(*v8::String::Utf8Value(args[0])); NativeWindow* native_window = FromV8Value(args[3]);
base::FilePath default_path(V8ValueToFilePath(args[1])); v8::Persistent<v8::Function> callback = FromV8Value(args[4]);
int properties = args[2]->IntegerValue();
if (callback.IsEmpty()) {
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
if (!file_dialog::ShowOpenDialog(title, default_path, properties, &paths)) if (!file_dialog::ShowOpenDialog(native_window,
title,
default_path,
properties,
&paths))
return v8::Undefined(); return v8::Undefined();
v8::Handle<v8::Array> result = v8::Array::New(paths.size()); v8::Handle<v8::Array> result = v8::Array::New(paths.size());
for (size_t i = 0; i < paths.size(); ++i) for (size_t i = 0; i < paths.size(); ++i)
result->Set(i, FilePathToV8Value(paths[i])); result->Set(i, ToV8Value(paths[i]));
return scope.Close(result); return scope.Close(result);
} else {
file_dialog::ShowOpenDialog(
native_window,
title,
default_path,
properties,
base::Bind(&CallV8Function2<const std::vector<base::FilePath>&>,
callback));
return v8::Undefined();
}
} }
v8::Handle<v8::Value> ShowSaveDialog(const v8::Arguments &args) { v8::Handle<v8::Value> ShowSaveDialog(const v8::Arguments &args) {
v8::HandleScope scope; v8::HandleScope scope;
if (!args[0]->IsObject() || // window std::string title;
!args[1]->IsString() || // title base::FilePath default_path;
!args[2]->IsString()) // default_path if (!FromV8Arguments(args, &title, &default_path))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
Window* window = Window::Unwrap<Window>(args[0]->ToObject()); NativeWindow* native_window = FromV8Value(args[2]);
if (!window || !window->window()) v8::Persistent<v8::Function> callback = FromV8Value(args[3]);
return node::ThrowError("Invalid window");
std::string title(*v8::String::Utf8Value(args[1]));
base::FilePath default_path(V8ValueToFilePath(args[2]));
if (callback.IsEmpty()) {
base::FilePath path; base::FilePath path;
if (!file_dialog::ShowSaveDialog(window->window(), if (!file_dialog::ShowSaveDialog(native_window,
title, title,
default_path, default_path,
&path)) &path))
return v8::Undefined(); return v8::Undefined();
return scope.Close(FilePathToV8Value(path)); return scope.Close(ToV8Value(path));
} else {
file_dialog::ShowSaveDialog(
native_window,
title,
default_path,
base::Bind(&CallV8Function2<const base::FilePath&>, callback));
return v8::Undefined();
}
} }
} // namespace api } // namespace api

View file

@ -4,6 +4,10 @@
#include "browser/api/atom_api_event.h" #include "browser/api/atom_api_event.h"
#include "browser/native_window.h"
#include "common/api/api_messages.h"
#include "common/v8_conversions.h"
using node::node_isolate; using node::node_isolate;
namespace atom { namespace atom {
@ -13,10 +17,14 @@ namespace api {
v8::Persistent<v8::FunctionTemplate> Event::constructor_template_; v8::Persistent<v8::FunctionTemplate> Event::constructor_template_;
Event::Event() Event::Event()
: prevent_default_(false) { : sender_(NULL),
message_(NULL),
prevent_default_(false) {
} }
Event::~Event() { Event::~Event() {
if (sender_)
sender_->RemoveObserver(this);
} }
// static // static
@ -31,6 +39,7 @@ v8::Handle<v8::Object> Event::CreateV8Object() {
constructor_template_->SetClassName(v8::String::NewSymbol("Event")); constructor_template_->SetClassName(v8::String::NewSymbol("Event"));
NODE_SET_PROTOTYPE_METHOD(t, "preventDefault", PreventDefault); NODE_SET_PROTOTYPE_METHOD(t, "preventDefault", PreventDefault);
NODE_SET_PROTOTYPE_METHOD(t, "sendReply", SendReply);
} }
v8::Handle<v8::Object> v8_event = v8::Handle<v8::Object> v8_event =
@ -39,14 +48,30 @@ v8::Handle<v8::Object> Event::CreateV8Object() {
return scope.Close(v8_event); return scope.Close(v8_event);
} }
v8::Handle<v8::Value> Event::New(const v8::Arguments &args) { void Event::SetSenderAndMessage(NativeWindow* sender, IPC::Message* message) {
DCHECK(!sender_);
DCHECK(!message_);
sender_ = sender;
message_ = message;
sender_->AddObserver(this);
}
void Event::OnWindowClosed() {
sender_ = NULL;
message_ = NULL;
}
// static
v8::Handle<v8::Value> Event::New(const v8::Arguments& args) {
Event* event = new Event; Event* event = new Event;
event->Wrap(args.This()); event->Wrap(args.This());
return args.This(); return args.This();
} }
v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments &args) { // static
v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments& args) {
Event* event = Unwrap<Event>(args.This()); Event* event = Unwrap<Event>(args.This());
if (event == NULL) if (event == NULL)
return node::ThrowError("Event is already destroyed"); return node::ThrowError("Event is already destroyed");
@ -56,6 +81,24 @@ v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments &args) {
return v8::Undefined(); return v8::Undefined();
} }
// static
v8::Handle<v8::Value> Event::SendReply(const v8::Arguments& args) {
Event* event = Unwrap<Event>(args.This());
if (event == NULL)
return node::ThrowError("Event is already destroyed");
if (event->message_ == NULL)
return node::ThrowError("Can only send reply to synchronous events once");
string16 json = FromV8Value(args[0]);
AtomViewHostMsg_Message_Sync::WriteReplyParams(event->message_, json);
event->sender_->Send(event->message_);
event->message_ = NULL;
return v8::Undefined();
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom

View file

@ -6,19 +6,32 @@
#define ATOM_BROWSER_ATOM_API_EVENT_H_ #define ATOM_BROWSER_ATOM_API_EVENT_H_
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/string16.h"
#include "browser/native_window_observer.h"
#include "vendor/node/src/node_object_wrap.h" #include "vendor/node/src/node_object_wrap.h"
namespace IPC {
class Message;
}
namespace atom { namespace atom {
class NativeWindow;
namespace api { namespace api {
class Event : public node::ObjectWrap { class Event : public node::ObjectWrap,
public NativeWindowObserver {
public: public:
virtual ~Event(); virtual ~Event();
// Create a V8 Event object. // Create a V8 Event object.
static v8::Handle<v8::Object> CreateV8Object(); static v8::Handle<v8::Object> CreateV8Object();
// Pass the sender and message to be replied.
void SetSenderAndMessage(NativeWindow* sender, IPC::Message* message);
// Accessor to return handle_, this follows Google C++ Style. // Accessor to return handle_, this follows Google C++ Style.
v8::Persistent<v8::Object>& handle() { return handle_; } v8::Persistent<v8::Object>& handle() { return handle_; }
@ -28,12 +41,21 @@ class Event : public node::ObjectWrap {
protected: protected:
Event(); Event();
// NativeWindowObserver implementations:
virtual void OnWindowClosed() OVERRIDE;
private: private:
static v8::Handle<v8::Value> New(const v8::Arguments &args); static v8::Handle<v8::Value> New(const v8::Arguments& args);
static v8::Handle<v8::Value> PreventDefault(const v8::Arguments &args);
static v8::Handle<v8::Value> PreventDefault(const v8::Arguments& args);
static v8::Handle<v8::Value> SendReply(const v8::Arguments& args);
static v8::Persistent<v8::FunctionTemplate> constructor_template_; static v8::Persistent<v8::FunctionTemplate> constructor_template_;
// Replyer for the synchronous messages.
NativeWindow* sender_;
IPC::Message* message_;
bool prevent_default_; bool prevent_default_;
DISALLOW_COPY_AND_ASSIGN(Event); DISALLOW_COPY_AND_ASSIGN(Event);

View file

@ -4,8 +4,8 @@
#include "browser/api/atom_api_menu.h" #include "browser/api/atom_api_menu.h"
#include "browser/api/atom_api_window.h"
#include "browser/ui/accelerator_util.h" #include "browser/ui/accelerator_util.h"
#include "common/v8_conversions.h"
#define UNWRAP_MEMNU_AND_CHECK \ #define UNWRAP_MEMNU_AND_CHECK \
Menu* self = ObjectWrap::Unwrap<Menu>(args.This()); \ Menu* self = ObjectWrap::Unwrap<Menu>(args.This()); \
@ -18,17 +18,6 @@ namespace api {
namespace { namespace {
// Converts a V8 value to a string16.
string16 V8ValueToUTF16(v8::Handle<v8::Value> value) {
v8::String::Value s(value);
return string16(reinterpret_cast<const char16*>(*s), s.length());
}
// Converts string16 to V8 String.
v8::Handle<v8::Value> UTF16ToV8Value(const string16& s) {
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
}
// Call method of delegate object. // Call method of delegate object.
v8::Handle<v8::Value> CallDelegate(v8::Handle<v8::Value> default_value, v8::Handle<v8::Value> CallDelegate(v8::Handle<v8::Value> default_value,
v8::Handle<v8::Object> menu, v8::Handle<v8::Object> menu,
@ -93,7 +82,7 @@ bool Menu::GetAcceleratorForCommandId(int command_id,
"getAcceleratorForCommandId", "getAcceleratorForCommandId",
command_id); command_id);
if (shortcut->IsString()) { if (shortcut->IsString()) {
std::string shortcut_str(*v8::String::Utf8Value(shortcut)); std::string shortcut_str = FromV8Value(shortcut);
return accelerator_util::StringToAccelerator(shortcut_str, accelerator); return accelerator_util::StringToAccelerator(shortcut_str, accelerator);
} }
@ -110,7 +99,7 @@ bool Menu::IsItemForCommandIdDynamic(int command_id) const {
string16 Menu::GetLabelForCommandId(int command_id) const { string16 Menu::GetLabelForCommandId(int command_id) const {
v8::HandleScope scope; v8::HandleScope scope;
return V8ValueToUTF16(CallDelegate(v8::False(), return FromV8Value(CallDelegate(v8::False(),
handle(), handle(),
"getLabelForCommandId", "getLabelForCommandId",
command_id)); command_id));
@ -118,7 +107,7 @@ string16 Menu::GetLabelForCommandId(int command_id) const {
string16 Menu::GetSublabelForCommandId(int command_id) const { string16 Menu::GetSublabelForCommandId(int command_id) const {
v8::HandleScope scope; v8::HandleScope scope;
return V8ValueToUTF16(CallDelegate(v8::False(), return FromV8Value(CallDelegate(v8::False(),
handle(), handle(),
"getSubLabelForCommandId", "getSubLabelForCommandId",
command_id)); command_id));
@ -145,16 +134,15 @@ v8::Handle<v8::Value> Menu::New(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertItem(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::InsertItem(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsString()) int index, command_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
int index = args[0]->IntegerValue();
if (index < 0) if (index < 0)
self->model_->AddItem(args[1]->IntegerValue(), V8ValueToUTF16(args[2])); self->model_->AddItem(command_id, label);
else else
self->model_->InsertItemAt( self->model_->InsertItemAt(index, command_id, label);
index, args[1]->IntegerValue(), V8ValueToUTF16(args[2]));
return v8::Undefined(); return v8::Undefined();
} }
@ -163,16 +151,15 @@ v8::Handle<v8::Value> Menu::InsertItem(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertCheckItem(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::InsertCheckItem(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsString()) int index, command_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
int index = args[0]->IntegerValue();
int command_id = args[1]->IntegerValue();
if (index < 0) if (index < 0)
self->model_->AddCheckItem(command_id, V8ValueToUTF16(args[2])); self->model_->AddCheckItem(command_id, label);
else else
self->model_->InsertCheckItemAt(index, command_id, V8ValueToUTF16(args[2])); self->model_->InsertCheckItemAt(index, command_id, label);
return v8::Undefined(); return v8::Undefined();
} }
@ -181,21 +168,15 @@ v8::Handle<v8::Value> Menu::InsertCheckItem(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertRadioItem(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::InsertRadioItem(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || int index, command_id, group_id;
!args[1]->IsNumber() || string16 label;
!args[2]->IsString() || if (!FromV8Arguments(args, &index, &command_id, &label, &group_id))
!args[3]->IsNumber())
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
int index = args[0]->IntegerValue();
int command_id = args[1]->IntegerValue();
int group_id = args[3]->IntegerValue();
if (index < 0) if (index < 0)
self->model_->AddRadioItem(command_id, V8ValueToUTF16(args[2]), group_id); self->model_->AddRadioItem(command_id, label, group_id);
else else
self->model_->InsertRadioItemAt( self->model_->InsertRadioItemAt(index, command_id, label, group_id);
index, command_id, V8ValueToUTF16(args[2]), group_id);
return v8::Undefined(); return v8::Undefined();
} }
@ -204,11 +185,10 @@ v8::Handle<v8::Value> Menu::InsertRadioItem(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertSeparator(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::InsertSeparator(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber()) int index;
if (!FromV8Arguments(args, &index))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
int index = args[0]->IntegerValue();
if (index < 0) if (index < 0)
self->model_->AddSeparator(ui::NORMAL_SEPARATOR); self->model_->AddSeparator(ui::NORMAL_SEPARATOR);
else else
@ -221,25 +201,20 @@ v8::Handle<v8::Value> Menu::InsertSeparator(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertSubMenu(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::InsertSubMenu(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || int index, command_id;
!args[1]->IsNumber() || string16 label;
!args[2]->IsString() || if (!FromV8Arguments(args, &index, &command_id, &label))
!args[3]->IsObject())
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
Menu* submenu = ObjectWrap::Unwrap<Menu>(args[3]->ToObject()); Menu* submenu = ObjectWrap::Unwrap<Menu>(args[3]->ToObject());
if (!submenu) if (!submenu)
return node::ThrowTypeError("The submenu is already destroyed"); return node::ThrowTypeError("The submenu is already destroyed");
int index = args[0]->IntegerValue();
int command_id = args[1]->IntegerValue();
if (index < 0) if (index < 0)
self->model_->AddSubMenu( self->model_->AddSubMenu(command_id, label, submenu->model_.get());
command_id, V8ValueToUTF16(args[2]), submenu->model_.get());
else else
self->model_->InsertSubMenuAt( self->model_->InsertSubMenuAt(
index, command_id, V8ValueToUTF16(args[2]), submenu->model_.get()); index, command_id, label, submenu->model_.get());
return v8::Undefined(); return v8::Undefined();
} }
@ -248,7 +223,9 @@ v8::Handle<v8::Value> Menu::InsertSubMenu(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::SetIcon(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::SetIcon(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || !args[1]->IsString()) int index;
base::FilePath path;
if (!FromV8Arguments(args, &index, &path))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
// FIXME use webkit_glue's image decoder here. // FIXME use webkit_glue's image decoder here.
@ -260,10 +237,12 @@ v8::Handle<v8::Value> Menu::SetIcon(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::SetSublabel(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::SetSublabel(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || !args[1]->IsString()) int index;
string16 label;
if (!FromV8Arguments(args, &index, &label))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
self->model_->SetSublabel(args[0]->IntegerValue(), V8ValueToUTF16(args[1])); self->model_->SetSublabel(index, label);
return v8::Undefined(); return v8::Undefined();
} }
@ -301,14 +280,14 @@ v8::Handle<v8::Value> Menu::GetCommandIdAt(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::GetLabelAt(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::GetLabelAt(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
int index = args[0]->IntegerValue(); int index = args[0]->IntegerValue();
return UTF16ToV8Value(self->model_->GetLabelAt(index)); return ToV8Value(self->model_->GetLabelAt(index));
} }
// static // static
v8::Handle<v8::Value> Menu::GetSublabelAt(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::GetSublabelAt(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
int index = args[0]->IntegerValue(); int index = args[0]->IntegerValue();
return UTF16ToV8Value(self->model_->GetSublabelAt(index)); return ToV8Value(self->model_->GetSublabelAt(index));
} }
// static // static
@ -334,11 +313,11 @@ v8::Handle<v8::Value> Menu::IsVisibleAt(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::Popup(const v8::Arguments &args) { v8::Handle<v8::Value> Menu::Popup(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK; UNWRAP_MEMNU_AND_CHECK;
Window* window = Window::Unwrap<Window>(args[0]->ToObject()); atom::NativeWindow* window;
if (!window) if (!FromV8Arguments(args, &window))
return node::ThrowTypeError("Invalid window"); return node::ThrowTypeError("Bad argument");
self->Popup(window->window()); self->Popup(window);
return v8::Undefined(); return v8::Undefined();
} }

View file

@ -8,6 +8,7 @@
#include "base/mac/scoped_sending_event.h" #include "base/mac/scoped_sending_event.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "browser/native_window.h" #include "browser/native_window.h"
#include "common/v8_conversions.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h" #include "content/public/browser/web_contents_view.h"
@ -95,10 +96,10 @@ v8::Handle<v8::Value> Menu::SendActionToFirstResponder(
const v8::Arguments &args) { const v8::Arguments &args) {
v8::HandleScope scope; v8::HandleScope scope;
if (!args[0]->IsString()) std::string action;
if (!FromV8Arguments(args, &action))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
std::string action(*v8::String::Utf8Value(args[0]));
MenuMac::SendActionToFirstResponder(action); MenuMac::SendActionToFirstResponder(action);
return v8::Undefined(); return v8::Undefined();

View file

@ -9,6 +9,7 @@
#include "browser/net/adapter_request_job.h" #include "browser/net/adapter_request_job.h"
#include "browser/net/atom_url_request_context_getter.h" #include "browser/net/atom_url_request_context_getter.h"
#include "browser/net/atom_url_request_job_factory.h" #include "browser/net/atom_url_request_job_factory.h"
#include "common/v8_conversions.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "vendor/node/src/node.h" #include "vendor/node/src/node.h"
@ -36,9 +37,9 @@ static const char* kEarlyUseProtocolError = "This method can only be used"
void EmitEventInUI(const std::string& event, const std::string& parameter) { void EmitEventInUI(const std::string& event, const std::string& parameter) {
v8::HandleScope scope; v8::HandleScope scope;
v8::Local<v8::Value> argv[] = { v8::Handle<v8::Value> argv[] = {
v8::String::New(event.data(), event.size()), ToV8Value(event),
v8::String::New(parameter.data(), parameter.size()), ToV8Value(parameter),
}; };
node::MakeCallback(g_protocol_object, "emit", arraysize(argv), argv); node::MakeCallback(g_protocol_object, "emit", arraysize(argv), argv);
} }
@ -83,7 +84,7 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
// Determine the type of the job we are going to create. // Determine the type of the job we are going to create.
if (result->IsString()) { if (result->IsString()) {
std::string data = *v8::String::Utf8Value(result); std::string data = FromV8Value(result);
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, content::BrowserThread::IO,
FROM_HERE, FROM_HERE,
@ -95,14 +96,12 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
return; return;
} else if (result->IsObject()) { } else if (result->IsObject()) {
v8::Handle<v8::Object> obj = result->ToObject(); v8::Handle<v8::Object> obj = result->ToObject();
std::string name = *v8::String::Utf8Value(obj->GetConstructorName()); std::string name = FromV8Value(obj->GetConstructorName());
if (name == "RequestStringJob") { if (name == "RequestStringJob") {
std::string mime_type = *v8::String::Utf8Value(obj->Get( std::string mime_type = FromV8Value(obj->Get(
v8::String::New("mimeType"))); v8::String::New("mimeType")));
std::string charset = *v8::String::Utf8Value(obj->Get( std::string charset = FromV8Value(obj->Get(v8::String::New("charset")));
v8::String::New("charset"))); std::string data = FromV8Value(obj->Get(v8::String::New("data")));
std::string data = *v8::String::Utf8Value(obj->Get(
v8::String::New("data")));
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, content::BrowserThread::IO,
@ -114,8 +113,7 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
data)); data));
return; return;
} else if (name == "RequestFileJob") { } else if (name == "RequestFileJob") {
base::FilePath path = base::FilePath::FromUTF8Unsafe( base::FilePath path = FromV8Value(obj->Get(v8::String::New("path")));
*v8::String::Utf8Value(obj->Get(v8::String::New("path"))));
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, content::BrowserThread::IO,
@ -183,7 +181,11 @@ class CustomProtocolHandler : public ProtocolHandler {
// static // static
v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) { v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
std::string scheme(*v8::String::Utf8Value(args[0])); std::string scheme;
v8::Persistent<v8::Function> callback;
if (!FromV8Arguments(args, &scheme, &callback))
return node::ThrowTypeError("Bad argument");
if (g_handlers.find(scheme) != g_handlers.end() || if (g_handlers.find(scheme) != g_handlers.end() ||
net::URLRequest::IsHandledProtocol(scheme)) net::URLRequest::IsHandledProtocol(scheme))
return node::ThrowError("The scheme is already registered"); return node::ThrowError("The scheme is already registered");
@ -192,10 +194,7 @@ v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
return node::ThrowError(kEarlyUseProtocolError); return node::ThrowError(kEarlyUseProtocolError);
// Store the handler in a map. // Store the handler in a map.
if (!args[1]->IsFunction()) g_handlers[scheme] = callback;
return node::ThrowError("Handler must be a function");
g_handlers[scheme] = v8::Persistent<v8::Function>::New(
node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));
content::BrowserThread::PostTask(content::BrowserThread::IO, content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE, FROM_HERE,
@ -206,7 +205,9 @@ v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
// static // static
v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) { v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
std::string scheme(*v8::String::Utf8Value(args[0])); std::string scheme;
if (!FromV8Arguments(args, &scheme))
return node::ThrowTypeError("Bad argument");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL) if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError); return node::ThrowError(kEarlyUseProtocolError);
@ -226,13 +227,16 @@ v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
// static // static
v8::Handle<v8::Value> Protocol::IsHandledProtocol(const v8::Arguments& args) { v8::Handle<v8::Value> Protocol::IsHandledProtocol(const v8::Arguments& args) {
return v8::Boolean::New(net::URLRequest::IsHandledProtocol( return ToV8Value(net::URLRequest::IsHandledProtocol(FromV8Value(args[0])));
*v8::String::Utf8Value(args[0])));
} }
// static // static
v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) { v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) {
std::string scheme(*v8::String::Utf8Value(args[0])); std::string scheme;
v8::Persistent<v8::Function> callback;
if (!FromV8Arguments(args, &scheme, &callback))
return node::ThrowTypeError("Bad argument");
if (!GetRequestJobFactory()->HasProtocolHandler(scheme)) if (!GetRequestJobFactory()->HasProtocolHandler(scheme))
return node::ThrowError("Cannot intercept procotol"); return node::ThrowError("Cannot intercept procotol");
@ -243,10 +247,7 @@ v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) {
return node::ThrowError(kEarlyUseProtocolError); return node::ThrowError(kEarlyUseProtocolError);
// Store the handler in a map. // Store the handler in a map.
if (!args[1]->IsFunction()) g_handlers[scheme] = callback;
return node::ThrowError("Handler must be a function");
g_handlers[scheme] = v8::Persistent<v8::Function>::New(
node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));
content::BrowserThread::PostTask(content::BrowserThread::IO, content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE, FROM_HERE,
@ -256,7 +257,9 @@ v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) {
// static // static
v8::Handle<v8::Value> Protocol::UninterceptProtocol(const v8::Arguments& args) { v8::Handle<v8::Value> Protocol::UninterceptProtocol(const v8::Arguments& args) {
std::string scheme(*v8::String::Utf8Value(args[0])); std::string scheme;
if (!FromV8Arguments(args, &scheme))
return node::ThrowTypeError("Bad argument");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL) if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError); return node::ThrowError(kEarlyUseProtocolError);

View file

@ -6,6 +6,7 @@
#include "base/values.h" #include "base/values.h"
#include "browser/native_window.h" #include "browser/native_window.h"
#include "common/v8_conversions.h"
#include "common/v8_value_converter_impl.h" #include "common/v8_value_converter_impl.h"
#include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
@ -27,15 +28,6 @@ namespace atom {
namespace api { namespace api {
namespace {
// Converts string16 to V8 String.
v8::Handle<v8::String> UTF16ToV8String(const string16& s) {
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
}
} // namespace
Window::Window(v8::Handle<v8::Object> wrapper, base::DictionaryValue* options) Window::Window(v8::Handle<v8::Object> wrapper, base::DictionaryValue* options)
: EventEmitter(wrapper), : EventEmitter(wrapper),
window_(NativeWindow::Create(options)) { window_(NativeWindow::Create(options)) {
@ -141,7 +133,7 @@ v8::Handle<v8::Value> Window::Focus(const v8::Arguments &args) {
// static // static
v8::Handle<v8::Value> Window::IsFocused(const v8::Arguments &args) { v8::Handle<v8::Value> Window::IsFocused(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsFocused()); return ToV8Value(self->window_->IsFocused());
} }
// static // static
@ -202,10 +194,11 @@ v8::Handle<v8::Value> Window::Restore(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &args) { v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsBoolean()) bool fs;
if (!FromV8Arguments(args, &fs))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
self->window_->SetFullscreen(args[0]->BooleanValue());
self->window_->SetFullscreen(fs);
return v8::Undefined(); return v8::Undefined();
} }
@ -213,18 +206,18 @@ v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsFullscreen(const v8::Arguments &args) { v8::Handle<v8::Value> Window::IsFullscreen(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsFullscreen()); return ToV8Value(self->window_->IsFullscreen());
} }
// static // static
v8::Handle<v8::Value> Window::SetSize(const v8::Arguments &args) { v8::Handle<v8::Value> Window::SetSize(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 2) int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
self->window_->SetSize(
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
self->window_->SetSize(gfx::Size(width, height));
return v8::Undefined(); return v8::Undefined();
} }
@ -234,8 +227,8 @@ v8::Handle<v8::Value> Window::GetSize(const v8::Arguments &args) {
gfx::Size size = self->window_->GetSize(); gfx::Size size = self->window_->GetSize();
v8::Handle<v8::Array> ret = v8::Array::New(2); v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, v8::Integer::New(size.width())); ret->Set(0, ToV8Value(size.width()));
ret->Set(1, v8::Integer::New(size.height())); ret->Set(1, ToV8Value(size.height()));
return ret; return ret;
} }
@ -244,11 +237,11 @@ v8::Handle<v8::Value> Window::GetSize(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetMinimumSize(const v8::Arguments &args) { v8::Handle<v8::Value> Window::SetMinimumSize(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 2) int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
self->window_->SetMinimumSize(
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
self->window_->SetMinimumSize(gfx::Size(width, height));
return v8::Undefined(); return v8::Undefined();
} }
@ -258,8 +251,8 @@ v8::Handle<v8::Value> Window::GetMinimumSize(const v8::Arguments &args) {
gfx::Size size = self->window_->GetMinimumSize(); gfx::Size size = self->window_->GetMinimumSize();
v8::Handle<v8::Array> ret = v8::Array::New(2); v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, v8::Integer::New(size.width())); ret->Set(0, ToV8Value(size.width()));
ret->Set(1, v8::Integer::New(size.height())); ret->Set(1, ToV8Value(size.height()));
return ret; return ret;
} }
@ -268,11 +261,12 @@ v8::Handle<v8::Value> Window::GetMinimumSize(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetMaximumSize(const v8::Arguments &args) { v8::Handle<v8::Value> Window::SetMaximumSize(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 2)
return node::ThrowTypeError("Bad argument");
self->window_->SetMaximumSize(
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument");
self->window_->SetMaximumSize(gfx::Size(width, height));
return v8::Undefined(); return v8::Undefined();
} }
@ -282,8 +276,8 @@ v8::Handle<v8::Value> Window::GetMaximumSize(const v8::Arguments &args) {
gfx::Size size = self->window_->GetMaximumSize(); gfx::Size size = self->window_->GetMaximumSize();
v8::Handle<v8::Array> ret = v8::Array::New(2); v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, v8::Integer::New(size.width())); ret->Set(0, ToV8Value(size.width()));
ret->Set(1, v8::Integer::New(size.height())); ret->Set(1, ToV8Value(size.height()));
return ret; return ret;
} }
@ -292,10 +286,11 @@ v8::Handle<v8::Value> Window::GetMaximumSize(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &args) { v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsBoolean()) bool resizable;
if (!FromV8Arguments(args, &resizable))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
self->window_->SetResizable(args[0]->BooleanValue());
self->window_->SetResizable(resizable);
return v8::Undefined(); return v8::Undefined();
} }
@ -303,17 +298,18 @@ v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsResizable(const v8::Arguments &args) { v8::Handle<v8::Value> Window::IsResizable(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsResizable()); return ToV8Value(self->window_->IsResizable());
} }
// static // static
v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &args) { v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsBoolean()) bool top;
if (!FromV8Arguments(args, &top))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
self->window_->SetAlwaysOnTop(args[0]->BooleanValue());
self->window_->SetAlwaysOnTop(top);
return v8::Undefined(); return v8::Undefined();
} }
@ -321,7 +317,7 @@ v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsAlwaysOnTop(const v8::Arguments &args) { v8::Handle<v8::Value> Window::IsAlwaysOnTop(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsAlwaysOnTop()); return ToV8Value(self->window_->IsAlwaysOnTop());
} }
// static // static
@ -337,11 +333,11 @@ v8::Handle<v8::Value> Window::Center(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetPosition(const v8::Arguments &args) { v8::Handle<v8::Value> Window::SetPosition(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 2) int x, y;
if (!FromV8Arguments(args, &x, &y))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
self->window_->SetPosition(
gfx::Point(args[0]->IntegerValue(), args[1]->IntegerValue()));
self->window_->SetPosition(gfx::Point(x, y));
return v8::Undefined(); return v8::Undefined();
} }
@ -351,8 +347,8 @@ v8::Handle<v8::Value> Window::GetPosition(const v8::Arguments &args) {
gfx::Point pos = self->window_->GetPosition(); gfx::Point pos = self->window_->GetPosition();
v8::Handle<v8::Array> ret = v8::Array::New(2); v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, v8::Integer::New(pos.x())); ret->Set(0, ToV8Value(pos.x()));
ret->Set(1, v8::Integer::New(pos.y())); ret->Set(1, ToV8Value(pos.y()));
return ret; return ret;
} }
@ -361,20 +357,18 @@ v8::Handle<v8::Value> Window::GetPosition(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetTitle(const v8::Arguments &args) { v8::Handle<v8::Value> Window::SetTitle(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsString()) std::string title;
if (!FromV8Arguments(args, &title))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
self->window_->SetTitle(*v8::String::Utf8Value(args[0]));
self->window_->SetTitle(title);
return v8::Undefined(); return v8::Undefined();
} }
// static // static
v8::Handle<v8::Value> Window::GetTitle(const v8::Arguments &args) { v8::Handle<v8::Value> Window::GetTitle(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return ToV8Value(self->window_->GetTitle());
std::string title = self->window_->GetTitle();
return v8::String::New(title.c_str(), title.size());
} }
// static // static
@ -391,10 +385,11 @@ v8::Handle<v8::Value> Window::FlashFrame(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &args) { v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsBoolean()) bool kiosk;
if (!FromV8Arguments(args, &kiosk))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
self->window_->SetKiosk(args[0]->BooleanValue());
self->window_->SetKiosk(kiosk);
return v8::Undefined(); return v8::Undefined();
} }
@ -402,7 +397,7 @@ v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsKiosk(const v8::Arguments &args) { v8::Handle<v8::Value> Window::IsKiosk(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsKiosk()); return ToV8Value(self->window_->IsKiosk());
} }
// static // static
@ -427,9 +422,11 @@ v8::Handle<v8::Value> Window::CloseDevTools(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::InspectElement(const v8::Arguments& args) { v8::Handle<v8::Value> Window::InspectElement(const v8::Arguments& args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
self->window_->InspectElement(args[0]->IntegerValue(), int x, y;
args[1]->IntegerValue()); if (!FromV8Arguments(args, &x, &y))
return node::ThrowTypeError("Bad argument");
self->window_->InspectElement(x, y);
return v8::Undefined(); return v8::Undefined();
} }
@ -454,7 +451,7 @@ v8::Handle<v8::Value> Window::BlurWebView(const v8::Arguments &args) {
// static // static
v8::Handle<v8::Value> Window::IsWebViewFocused(const v8::Arguments& args) { v8::Handle<v8::Value> Window::IsWebViewFocused(const v8::Arguments& args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsWebViewFocused()); return ToV8Value(self->window_->IsWebViewFocused());
} }
// static // static
@ -471,24 +468,21 @@ v8::Handle<v8::Value> Window::RestartHangMonitorTimeout(
v8::Handle<v8::Value> Window::GetPageTitle(const v8::Arguments &args) { v8::Handle<v8::Value> Window::GetPageTitle(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
string16 title = self->window_->GetWebContents()->GetTitle(); return ToV8Value(self->window_->GetWebContents()->GetTitle());
return UTF16ToV8String(title);
} }
// static // static
v8::Handle<v8::Value> Window::IsLoading(const v8::Arguments &args) { v8::Handle<v8::Value> Window::IsLoading(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->GetWebContents()->IsLoading()); return ToV8Value(self->window_->GetWebContents()->IsLoading());
} }
// static // static
v8::Handle<v8::Value> Window::IsWaitingForResponse(const v8::Arguments &args) { v8::Handle<v8::Value> Window::IsWaitingForResponse(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New( return ToV8Value(self->window_->GetWebContents()->IsWaitingForResponse());
self->window_->GetWebContents()->IsWaitingForResponse());
} }
// static // static
@ -504,14 +498,14 @@ v8::Handle<v8::Value> Window::Stop(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::GetRoutingID(const v8::Arguments &args) { v8::Handle<v8::Value> Window::GetRoutingID(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Integer::New(self->window_->GetWebContents()->GetRoutingID()); return ToV8Value(self->window_->GetWebContents()->GetRoutingID());
} }
// static // static
v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) { v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Integer::New( return ToV8Value(
self->window_->GetWebContents()->GetRenderProcessHost()->GetID()); self->window_->GetWebContents()->GetRenderProcessHost()->GetID());
} }
@ -519,19 +513,20 @@ v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsCrashed(const v8::Arguments &args) { v8::Handle<v8::Value> Window::IsCrashed(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->GetWebContents()->IsCrashed()); return ToV8Value(self->window_->GetWebContents()->IsCrashed());
} }
// static // static
v8::Handle<v8::Value> Window::LoadURL(const v8::Arguments &args) { v8::Handle<v8::Value> Window::LoadURL(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsString()) std::string url;
if (!FromV8Arguments(args, &url))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
NavigationController& controller = NavigationController& controller =
self->window_->GetWebContents()->GetController(); self->window_->GetWebContents()->GetController();
controller.LoadURL(GURL(*v8::String::Utf8Value(args[0])), controller.LoadURL(GURL(url),
content::Referrer(), content::Referrer(),
content::PAGE_TRANSITION_AUTO_TOPLEVEL, content::PAGE_TRANSITION_AUTO_TOPLEVEL,
std::string()); std::string());
@ -549,7 +544,7 @@ v8::Handle<v8::Value> Window::GetURL(const v8::Arguments &args) {
if (controller.GetActiveEntry()) if (controller.GetActiveEntry())
url = controller.GetActiveEntry()->GetVirtualURL().spec(); url = controller.GetActiveEntry()->GetVirtualURL().spec();
return v8::String::New(url.c_str(), url.size()); return ToV8Value(url);
} }
// static // static
@ -559,7 +554,7 @@ v8::Handle<v8::Value> Window::CanGoBack(const v8::Arguments &args) {
NavigationController& controller = NavigationController& controller =
self->window_->GetWebContents()->GetController(); self->window_->GetWebContents()->GetController();
return v8::Boolean::New(controller.CanGoBack()); return ToV8Value(controller.CanGoBack());
} }
// static // static
@ -569,21 +564,21 @@ v8::Handle<v8::Value> Window::CanGoForward(const v8::Arguments &args) {
NavigationController& controller = NavigationController& controller =
self->window_->GetWebContents()->GetController(); self->window_->GetWebContents()->GetController();
return v8::Boolean::New(controller.CanGoForward()); return ToV8Value(controller.CanGoForward());
} }
// static // static
v8::Handle<v8::Value> Window::CanGoToOffset(const v8::Arguments &args) { v8::Handle<v8::Value> Window::CanGoToOffset(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1) int offset;
if (!FromV8Arguments(args, &offset))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
NavigationController& controller = NavigationController& controller =
self->window_->GetWebContents()->GetController(); self->window_->GetWebContents()->GetController();
int offset = args[0]->IntegerValue();
return v8::Boolean::New(controller.CanGoToOffset(offset)); return ToV8Value(controller.CanGoToOffset(offset));
} }
// static // static
@ -612,12 +607,13 @@ v8::Handle<v8::Value> Window::GoForward(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &args) { v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1) int index;
if (!FromV8Arguments(args, &index))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
NavigationController& controller = NavigationController& controller =
self->window_->GetWebContents()->GetController(); self->window_->GetWebContents()->GetController();
controller.GoToIndex(args[0]->IntegerValue()); controller.GoToIndex(index);
return v8::Undefined(); return v8::Undefined();
} }
@ -626,12 +622,13 @@ v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::GoToOffset(const v8::Arguments &args) { v8::Handle<v8::Value> Window::GoToOffset(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1) int offset;
if (!FromV8Arguments(args, &offset))
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
NavigationController& controller = NavigationController& controller =
self->window_->GetWebContents()->GetController(); self->window_->GetWebContents()->GetController();
controller.GoToOffset(args[0]->IntegerValue()); controller.GoToOffset(offset);
return v8::Undefined(); return v8::Undefined();
} }

View file

@ -8,6 +8,8 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/values.h" #include "base/values.h"
#include "browser/api/atom_api_event.h"
#include "common/v8_conversions.h"
#include "common/v8_value_converter_impl.h" #include "common/v8_value_converter_impl.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "vendor/node/src/node.h" #include "vendor/node/src/node.h"
@ -42,7 +44,7 @@ void AtomBrowserBindings::AfterLoad() {
void AtomBrowserBindings::OnRendererMessage(int process_id, void AtomBrowserBindings::OnRendererMessage(int process_id,
int routing_id, int routing_id,
const std::string& channel, const string16& channel,
const base::ListValue& args) { const base::ListValue& args) {
v8::HandleScope scope; v8::HandleScope scope;
@ -53,7 +55,7 @@ void AtomBrowserBindings::OnRendererMessage(int process_id,
// process.emit(channel, 'message', process_id, routing_id); // process.emit(channel, 'message', process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments; std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize()); arguments.reserve(3 + args.GetSize());
arguments.push_back(v8::String::New(channel.c_str(), channel.size())); arguments.push_back(ToV8Value(channel));
const base::Value* value; const base::Value* value;
if (args.Get(0, &value)) if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, context)); arguments.push_back(converter->ToV8Value(value, context));
@ -72,21 +74,24 @@ void AtomBrowserBindings::OnRendererMessage(int process_id,
void AtomBrowserBindings::OnRendererMessageSync( void AtomBrowserBindings::OnRendererMessageSync(
int process_id, int process_id,
int routing_id, int routing_id,
const std::string& channel, const string16& channel,
const base::ListValue& args, const base::ListValue& args,
base::DictionaryValue* result) { NativeWindow* sender,
IPC::Message* message) {
v8::HandleScope scope; v8::HandleScope scope;
v8::Handle<v8::Context> context = v8::Context::GetCurrent(); v8::Handle<v8::Context> context = v8::Context::GetCurrent();
scoped_ptr<V8ValueConverter> converter(new V8ValueConverterImpl()); scoped_ptr<V8ValueConverter> converter(new V8ValueConverterImpl());
v8::Handle<v8::Object> event = v8::Object::New(); // Create the event object.
v8::Handle<v8::Object> event = api::Event::CreateV8Object();
api::Event::Unwrap<api::Event>(event)->SetSenderAndMessage(sender, message);
// process.emit(channel, 'sync-message', event, process_id, routing_id); // process.emit(channel, 'sync-message', event, process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments; std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize()); arguments.reserve(3 + args.GetSize());
arguments.push_back(v8::String::New(channel.c_str(), channel.size())); arguments.push_back(ToV8Value(channel));
const base::Value* value; const base::Value* value;
if (args.Get(0, &value)) if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, context)); arguments.push_back(converter->ToV8Value(value, context));
@ -101,11 +106,6 @@ void AtomBrowserBindings::OnRendererMessageSync(
} }
node::MakeCallback(node::process, "emit", arguments.size(), &arguments[0]); node::MakeCallback(node::process, "emit", arguments.size(), &arguments[0]);
scoped_ptr<base::Value> base_event(converter->FromV8Value(event, context));
DCHECK(base_event && base_event->IsType(base::Value::TYPE_DICTIONARY));
result->Swap(static_cast<base::DictionaryValue*>(base_event.get()));
} }
} // namespace atom } // namespace atom

View file

@ -5,17 +5,21 @@
#ifndef ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_ #ifndef ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
#define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_ #define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
#include <string> #include "base/string16.h"
#include "common/api/atom_bindings.h" #include "common/api/atom_bindings.h"
namespace base { namespace base {
class DictionaryValue;
class ListValue; class ListValue;
} }
namespace IPC {
class Message;
}
namespace atom { namespace atom {
class NativeWindow;
class AtomBrowserBindings : public AtomBindings { class AtomBrowserBindings : public AtomBindings {
public: public:
AtomBrowserBindings(); AtomBrowserBindings();
@ -27,15 +31,16 @@ class AtomBrowserBindings : public AtomBindings {
// Called when received a message from renderer. // Called when received a message from renderer.
void OnRendererMessage(int process_id, void OnRendererMessage(int process_id,
int routing_id, int routing_id,
const std::string& channel, const string16& channel,
const base::ListValue& args); const base::ListValue& args);
// Called when received a synchronous message from renderer. // Called when received a synchronous message from renderer.
void OnRendererMessageSync(int process_id, void OnRendererMessageSync(int process_id,
int routing_id, int routing_id,
const std::string& channel, const string16& channel,
const base::ListValue& args, const base::ListValue& args,
base::DictionaryValue* result); NativeWindow* sender,
IPC::Message* message);
// The require('atom').browserMainParts object. // The require('atom').browserMainParts object.
v8::Handle<v8::Object> browser_main_parts() { v8::Handle<v8::Object> browser_main_parts() {

View file

@ -1,4 +1,5 @@
binding = process.atomBinding 'dialog' binding = process.atomBinding 'dialog'
v8Util = process.atomBinding 'v8_util'
BrowserWindow = require 'browser-window' BrowserWindow = require 'browser-window'
fileDialogProperties = fileDialogProperties =
@ -7,48 +8,71 @@ fileDialogProperties =
messageBoxTypes = ['none', 'info', 'warning'] messageBoxTypes = ['none', 'info', 'warning']
module.exports = module.exports =
showOpenDialog: (options) -> showOpenDialog: (window, options, callback) ->
options = title: 'Open', properties: ['openFile'] unless options? unless window?.constructor is BrowserWindow
options.properties = options.properties ? ['openFile'] # Shift.
callback = options
options = window
window = null
options ?= title: 'Open', properties: ['openFile']
options.properties ?= ['openFile']
throw new TypeError('Properties need to be array') unless Array.isArray options.properties throw new TypeError('Properties need to be array') unless Array.isArray options.properties
properties = 0 properties = 0
for prop, value of fileDialogProperties for prop, value of fileDialogProperties
properties |= value if prop in options.properties properties |= value if prop in options.properties
options.title = options.title ? '' options.title ?= ''
options.defaultPath = options.defaultPath ? '' options.defaultPath ?= ''
binding.showOpenDialog options.title, options.defaultPath, properties binding.showOpenDialog String(options.title),
String(options.defaultPath),
properties,
window,
callback
showSaveDialog: (window, options) -> showSaveDialog: (window, options, callback) ->
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow unless window?.constructor is BrowserWindow
options = title: 'Save' unless options? # Shift.
callback = options
options.title = options.title ? ''
options.defaultPath = options.defaultPath ? ''
binding.showSaveDialog window, options.title, options.defaultPath
showMessageBox: (window, options) ->
if window? and window.constructor isnt BrowserWindow
options = window options = window
window = null window = null
options = type: 'none' unless options? options ?= title: 'Save'
options.type = options.type ? 'none' options.title ?= ''
options.defaultPath ?= ''
binding.showSaveDialog String(options.title),
String(options.defaultPath),
window,
callback
showMessageBox: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
options ?= type: 'none'
options.type ?= 'none'
options.type = messageBoxTypes.indexOf options.type options.type = messageBoxTypes.indexOf options.type
throw new TypeError('Invalid message box type') unless options.type > -1 throw new TypeError('Invalid message box type') unless options.type > -1
throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons
options.title = options.title ? '' options.title ?= ''
options.message = options.message ? '' options.message ?= ''
options.detail = options.detail ? '' options.detail ?= ''
binding.showMessageBox options.type, binding.showMessageBox options.type,
options.buttons, options.buttons,
String(options.title), String(options.title),
String(options.message), String(options.message),
String(options.detail), String(options.detail),
window window,
callback
# Mark standard asynchronous functions.
v8Util.setHiddenValue f, 'asynchronous', true for k, f of module.exports

View file

@ -14,8 +14,13 @@ class Ipc extends EventEmitter
constructor: -> constructor: ->
process.on 'ATOM_INTERNAL_MESSAGE', (args...) => process.on 'ATOM_INTERNAL_MESSAGE', (args...) =>
@emit(args...) @emit(args...)
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (args...) => process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (channel, event, args...) =>
@emit(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...) -> send: (processId, routingId, args...) ->
@sendChannel(processId, routingId, 'message', args...) @sendChannel(processId, routingId, 'message', args...)

View file

@ -61,28 +61,40 @@ unwrapArgs = (processId, routingId, args) ->
args.map metaToValue 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.
callFunction = (event, processId, routingId, func, caller, args) ->
if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function'
args.push (ret) ->
event.returnValue = valueToMeta processId, routingId, ret
func.apply caller, args
else
ret = func.apply caller, args
event.returnValue = valueToMeta processId, routingId, ret
ipc.on 'ATOM_BROWSER_REQUIRE', (event, processId, routingId, module) -> ipc.on 'ATOM_BROWSER_REQUIRE', (event, processId, routingId, module) ->
try try
event.result = valueToMeta processId, routingId, require(module) event.returnValue = valueToMeta processId, routingId, require(module)
catch e catch e
event.result = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_GLOBAL', (event, processId, routingId, name) -> ipc.on 'ATOM_BROWSER_GLOBAL', (event, processId, routingId, name) ->
try try
event.result = valueToMeta processId, routingId, global[name] event.returnValue = valueToMeta processId, routingId, global[name]
catch e catch e
event.result = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (event, processId, routingId) -> ipc.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (event, processId, routingId) ->
objectsRegistry.clear processId, routingId objectsRegistry.clear processId, routingId
event.returnValue = null
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, processId, routingId) -> ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, processId, routingId) ->
try try
BrowserWindow = require 'browser-window' BrowserWindow = require 'browser-window'
window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId
event.result = valueToMeta processId, routingId, window event.returnValue = valueToMeta processId, routingId, window
catch e catch e
event.result = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) -> ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) ->
try try
@ -91,18 +103,17 @@ ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) ->
# 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.result = valueToMeta processId, routingId, obj event.returnValue = valueToMeta processId, routingId, obj
catch e catch e
event.result = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, processId, routingId, id, args) -> ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, processId, routingId, id, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs processId, routingId, args
func = objectsRegistry.get id func = objectsRegistry.get id
ret = func.apply global, args callFunction event, processId, routingId, func, global, args
event.result = valueToMeta processId, routingId, ret
catch e catch e
event.result = 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, processId, routingId, id, method, args) ->
try try
@ -110,32 +121,32 @@ ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, processId, routingId, id, meth
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.result = valueToMeta processId, routingId, obj event.returnValue = valueToMeta processId, routingId, obj
catch e catch e
event.result = 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, processId, routingId, id, method, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs processId, routingId, args
obj = objectsRegistry.get id obj = objectsRegistry.get id
ret = obj[method].apply(obj, args) callFunction event, processId, routingId, obj[method], obj, args
event.result = valueToMeta processId, routingId, ret
catch e catch e
event.result = 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, processId, routingId, id, name, value) ->
try try
obj = objectsRegistry.get id obj = objectsRegistry.get id
obj[name] = value obj[name] = value
event.returnValue = null
catch e catch e
event.result = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, processId, routingId, id, name) -> ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, processId, routingId, id, name) ->
try try
obj = objectsRegistry.get id obj = objectsRegistry.get id
event.result = valueToMeta processId, routingId, obj[name] event.returnValue = valueToMeta processId, routingId, obj[name]
catch e catch e
event.result = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_DEREFERENCE', (processId, routingId, storeId) -> ipc.on 'ATOM_BROWSER_DEREFERENCE', (processId, routingId, storeId) ->
objectsRegistry.remove processId, routingId, storeId objectsRegistry.remove processId, routingId, storeId

View file

@ -300,7 +300,8 @@ 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(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message_Sync, OnRendererMessageSync) 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)
@ -340,7 +341,7 @@ void NativeWindow::Observe(int type,
} }
} }
void NativeWindow::OnRendererMessage(const std::string& channel, void NativeWindow::OnRendererMessage(const string16& channel,
const base::ListValue& args) { const base::ListValue& args) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage( AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
GetWebContents()->GetRenderProcessHost()->GetID(), GetWebContents()->GetRenderProcessHost()->GetID(),
@ -349,15 +350,16 @@ void NativeWindow::OnRendererMessage(const std::string& channel,
args); args);
} }
void NativeWindow::OnRendererMessageSync(const std::string& channel, void NativeWindow::OnRendererMessageSync(const string16& channel,
const base::ListValue& args, const base::ListValue& args,
base::DictionaryValue* result) { IPC::Message* reply_msg) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync( AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync(
GetWebContents()->GetRenderProcessHost()->GetID(), GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID(), GetWebContents()->GetRoutingID(),
channel, channel,
args, args,
result); this,
reply_msg);
} }
} // namespace atom } // namespace atom

View file

@ -35,6 +35,10 @@ class Rect;
class Size; class Size;
} }
namespace IPC {
class Message;
}
namespace atom { namespace atom {
class AtomJavaScriptDialogManager; class AtomJavaScriptDialogManager;
@ -173,12 +177,12 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
private: private:
void RendererUnresponsiveDelayed(); void RendererUnresponsiveDelayed();
void OnRendererMessage(const std::string& channel, void OnRendererMessage(const string16& channel,
const base::ListValue& args); const base::ListValue& args);
void OnRendererMessageSync(const std::string& channel, void OnRendererMessageSync(const string16& channel,
const base::ListValue& args, const base::ListValue& args,
base::DictionaryValue* result); IPC::Message* reply_msg);
// Notification manager. // Notification manager.
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;

View file

@ -8,6 +8,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/callback_forward.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
namespace atom { namespace atom {
@ -23,16 +24,34 @@ enum FileDialogProperty {
FILE_DIALOG_CREATE_DIRECTORY = 8, FILE_DIALOG_CREATE_DIRECTORY = 8,
}; };
bool ShowOpenDialog(const std::string& title, typedef base::Callback<void(
bool result, const std::vector<base::FilePath>& paths)> OpenDialogCallback;
typedef base::Callback<void(
bool result, const base::FilePath& path)> SaveDialogCallback;
bool ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path, const base::FilePath& default_path,
int properties, int properties,
std::vector<base::FilePath>* paths); std::vector<base::FilePath>* paths);
bool ShowSaveDialog(atom::NativeWindow* window, void ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
const OpenDialogCallback& callback);
bool ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title, const std::string& title,
const base::FilePath& default_path, const base::FilePath& default_path,
base::FilePath* path); base::FilePath* path);
void ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
const SaveDialogCallback& callback);
} // namespace file_dialog } // namespace file_dialog
#endif // BROWSER_UI_FILE_DIALOG_H_ #endif // BROWSER_UI_FILE_DIALOG_H_

View file

@ -38,20 +38,11 @@ void SetupDialog(NSSavePanel* dialog,
if (default_filename) if (default_filename)
[dialog setNameFieldStringValue:default_filename]; [dialog setNameFieldStringValue:default_filename];
[dialog setCanSelectHiddenExtension:YES];
[dialog setAllowsOtherFileTypes:YES]; [dialog setAllowsOtherFileTypes:YES];
} }
} // namespace void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
bool ShowOpenDialog(const std::string& title,
const base::FilePath& default_path,
int properties,
std::vector<base::FilePath>* paths) {
DCHECK(paths);
NSOpenPanel* dialog = [NSOpenPanel openPanel];
SetupDialog(dialog, title, default_path);
[dialog setCanChooseFiles:(properties & FILE_DIALOG_OPEN_FILE)]; [dialog setCanChooseFiles:(properties & FILE_DIALOG_OPEN_FILE)];
if (properties & FILE_DIALOG_OPEN_DIRECTORY) if (properties & FILE_DIALOG_OPEN_DIRECTORY)
[dialog setCanChooseDirectories:YES]; [dialog setCanChooseDirectories:YES];
@ -59,49 +50,119 @@ bool ShowOpenDialog(const std::string& title,
[dialog setCanCreateDirectories:YES]; [dialog setCanCreateDirectories:YES];
if (properties & FILE_DIALOG_MULTI_SELECTIONS) if (properties & FILE_DIALOG_MULTI_SELECTIONS)
[dialog setAllowsMultipleSelection:YES]; [dialog setAllowsMultipleSelection:YES];
}
if ([dialog runModal] == NSFileHandlingPanelCancelButton) // Run modal dialog with parent window and return user's choice.
return false; int RunModalDialog(NSSavePanel* dialog, atom::NativeWindow* parent_window) {
__block int chosen = NSFileHandlingPanelCancelButton;
if (parent_window == NULL) {
chosen = [dialog runModal];
} else {
NSWindow* window = parent_window->GetNativeWindow();
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger c) {
chosen = c;
[NSApp stopModal];
}];
[NSApp runModalForWindow:window];
}
return chosen;
}
void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
NSArray* urls = [dialog URLs]; NSArray* urls = [dialog URLs];
for (NSURL* url in urls) for (NSURL* url in urls)
if ([url isFileURL]) if ([url isFileURL])
paths->push_back(base::FilePath(base::SysNSStringToUTF8([url path]))); paths->push_back(base::FilePath(base::SysNSStringToUTF8([url path])));
}
} // namespace
bool ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
std::vector<base::FilePath>* paths) {
DCHECK(paths);
NSOpenPanel* dialog = [NSOpenPanel openPanel];
SetupDialog(dialog, title, default_path);
SetupDialogForProperties(dialog, properties);
int chosen = RunModalDialog(dialog, parent_window);
if (chosen == NSFileHandlingPanelCancelButton)
return false;
ReadDialogPaths(dialog, paths);
return true; return true;
} }
bool ShowSaveDialog(atom::NativeWindow* window, void ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
const OpenDialogCallback& c) {
NSOpenPanel* dialog = [NSOpenPanel openPanel];
SetupDialog(dialog, title, default_path);
SetupDialogForProperties(dialog, properties);
// Duplicate the callback object here since c is a reference and gcd would
// only store the pointer, by duplication we can force gcd to store a copy.
__block OpenDialogCallback callback = c;
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton) {
callback.Run(false, std::vector<base::FilePath>());
} else {
std::vector<base::FilePath> paths;
ReadDialogPaths(dialog, &paths);
callback.Run(true, paths);
}
}];
}
bool ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title, const std::string& title,
const base::FilePath& default_path, const base::FilePath& default_path,
base::FilePath* path) { base::FilePath* path) {
DCHECK(window);
DCHECK(path); DCHECK(path);
NSSavePanel* dialog = [NSSavePanel savePanel]; NSSavePanel* dialog = [NSSavePanel savePanel];
SetupDialog(dialog, title, default_path); SetupDialog(dialog, title, default_path);
[dialog setCanSelectHiddenExtension:YES]; int chosen = RunModalDialog(dialog, parent_window);
if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL])
return false;
__block bool result = false; *path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path]));
__block base::FilePath ret_path; return true;
[dialog beginSheetModalForWindow:window->GetNativeWindow() }
void ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
const SaveDialogCallback& c) {
NSSavePanel* dialog = [NSSavePanel savePanel];
SetupDialog(dialog, title, default_path);
__block SaveDialogCallback callback = c;
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) { completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton || if (chosen == NSFileHandlingPanelCancelButton) {
![[dialog URL] isFileURL]) { callback.Run(false, base::FilePath());
result = false;
} else { } else {
result = true; std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
ret_path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path])); callback.Run(true, base::FilePath(path));
} }
[NSApp stopModal];
}]; }];
[NSApp runModalForWindow:window->GetNativeWindow()];
*path = ret_path;
return result;
} }
} // namespace file_dialog } // namespace file_dialog

View file

@ -162,7 +162,8 @@ class FileDialog {
SetDefaultFolder(default_path); SetDefaultFolder(default_path);
} }
bool Show(HWND window) { bool Show(atom::NativeWindow* parent_window) {
HWND window = parent_window ? parent_window->GetNativeWindow() : NULL;
return dialog_->DoModal(window) == IDOK; return dialog_->DoModal(window) == IDOK;
} }
@ -198,7 +199,8 @@ class FileDialog {
} // namespace } // namespace
bool ShowOpenDialog(const std::string& title, bool ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path, const base::FilePath& default_path,
int properties, int properties,
std::vector<base::FilePath>* paths) { std::vector<base::FilePath>* paths) {
@ -214,7 +216,7 @@ bool ShowOpenDialog(const std::string& title,
options, options,
std::vector<std::wstring>(), std::vector<std::wstring>(),
std::vector<std::wstring>()); std::vector<std::wstring>());
if (!open_dialog.Show(::GetActiveWindow())) if (!open_dialog.Show(parent_window))
return false; return false;
ATL::CComPtr<IShellItemArray> items; ATL::CComPtr<IShellItemArray> items;
@ -247,7 +249,21 @@ bool ShowOpenDialog(const std::string& title,
return true; return true;
} }
bool ShowSaveDialog(atom::NativeWindow* window, void ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
const OpenDialogCallback& callback) {
std::vector<base::FilePath> paths;
bool result = ShowOpenDialog(parent_window,
title,
default_path,
properties,
&paths);
callback.Run(result, paths);
}
bool ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title, const std::string& title,
const base::FilePath& default_path, const base::FilePath& default_path,
base::FilePath* path) { base::FilePath* path) {
@ -263,7 +279,7 @@ bool ShowSaveDialog(atom::NativeWindow* window,
FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT,
file_ext, file_ext,
std::vector<std::wstring>()); std::vector<std::wstring>());
if (!save_dialog.Show(window->GetNativeWindow())) if (!save_dialog.Show(parent_window))
return false; return false;
wchar_t file_name[MAX_PATH]; wchar_t file_name[MAX_PATH];
@ -290,4 +306,13 @@ bool ShowSaveDialog(atom::NativeWindow* window,
return true; return true;
} }
void ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
const SaveDialogCallback& callback) {
base::FilePath path;
bool result = ShowSaveDialog(parent_window, title, default_path, &path);
callback.Run(result, path);
}
} // namespace file_dialog } // namespace file_dialog

View file

@ -8,6 +8,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/callback_forward.h"
namespace atom { namespace atom {
class NativeWindow; class NativeWindow;
@ -18,6 +20,8 @@ enum MessageBoxType {
MESSAGE_BOX_TYPE_WARNING MESSAGE_BOX_TYPE_WARNING
}; };
typedef base::Callback<void(int code)> MessageBoxCallback;
int ShowMessageBox(NativeWindow* parent_window, int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
@ -25,6 +29,14 @@ int ShowMessageBox(NativeWindow* parent_window,
const std::string& message, const std::string& message,
const std::string& detail); const std::string& detail);
void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail,
const MessageBoxCallback& callback);
} // namespace atom } // namespace atom
#endif // BROWSER_UI_MESSAGE_BOX_H_ #endif // BROWSER_UI_MESSAGE_BOX_H_

View file

@ -6,20 +6,53 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include "base/callback.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "browser/native_window.h" #include "browser/native_window.h"
#include "browser/ui/nsalert_synchronous_sheet_mac.h" #include "browser/ui/nsalert_synchronous_sheet_mac.h"
@interface ModalDelegate : NSObject {
@private
atom::MessageBoxCallback callback_;
NSAlert* alert_;
}
- (id)initWithCallback:(const atom::MessageBoxCallback&)callback
andAlert:(NSAlert*)alert;
@end
@implementation ModalDelegate
- (id)initWithCallback:(const atom::MessageBoxCallback&)callback
andAlert:(NSAlert*)alert {
if ((self = [super init])) {
callback_ = callback;
alert_ = alert;
}
return self;
}
- (void)alertDidEnd:(NSAlert*)alert
returnCode:(NSInteger)returnCode
contextInfo:(void*)contextInfo {
callback_.Run(returnCode);
[alert_ release];
[self release];
}
@end
namespace atom { namespace atom {
int ShowMessageBox(NativeWindow* parent_window, namespace {
NSAlert* CreateNSAlert(NativeWindow* parent_window,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail) { const std::string& detail) {
// Ignore the title; it's the window title on other platforms and ignorable. // Ignore the title; it's the window title on other platforms and ignorable.
NSAlert* alert = [[[NSAlert alloc] init] autorelease]; NSAlert* alert = [[NSAlert alloc] init];
[alert setMessageText:base::SysUTF8ToNSString(message)]; [alert setMessageText:base::SysUTF8ToNSString(message)];
[alert setInformativeText:base::SysUTF8ToNSString(detail)]; [alert setInformativeText:base::SysUTF8ToNSString(detail)];
@ -40,10 +73,44 @@ int ShowMessageBox(NativeWindow* parent_window,
[button setTag:i]; [button setTag:i];
} }
return alert;
}
} // namespace
int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail) {
NSAlert* alert = CreateNSAlert(
parent_window, type, buttons, title, message, detail);
[alert autorelease];
if (parent_window) if (parent_window)
return [alert runModalSheetForWindow:parent_window->GetNativeWindow()]; return [alert runModalSheetForWindow:parent_window->GetNativeWindow()];
else else
return [alert runModal]; return [alert runModal];
} }
void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail,
const MessageBoxCallback& callback) {
NSAlert* alert = CreateNSAlert(
parent_window, type, buttons, title, message, detail);
ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback
andAlert:alert];
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : nil;
[alert beginSheetModalForWindow:window
modalDelegate:delegate
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
contextInfo:nil];
}
} // namespace atom } // namespace atom

View file

@ -4,6 +4,7 @@
#include "browser/ui/message_box.h" #include "browser/ui/message_box.h"
#include "base/callback.h"
#include "base/message_loop.h" #include "base/message_loop.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/string_util.h" #include "base/string_util.h"
@ -38,7 +39,14 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
const std::string& detail); const std::string& detail);
virtual ~MessageDialog(); virtual ~MessageDialog();
int result() const { return result_; } void Show();
int GetResult() const;
void set_callback(const MessageBoxCallback& callback) {
delete_on_close_ = true;
callback_ = callback;
}
private: private:
// Overridden from MessageLoop::Dispatcher: // Overridden from MessageLoop::Dispatcher:
@ -63,11 +71,13 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
const ui::Event& event) OVERRIDE; const ui::Event& event) OVERRIDE;
bool should_close_; bool should_close_;
bool delete_on_close_;
int result_; int result_;
string16 title_; string16 title_;
views::Widget* widget_; views::Widget* widget_;
views::MessageBoxView* message_box_view_; views::MessageBoxView* message_box_view_;
std::vector<views::LabelButton*> buttons_; std::vector<views::LabelButton*> buttons_;
MessageBoxCallback callback_;
DISALLOW_COPY_AND_ASSIGN(MessageDialog); DISALLOW_COPY_AND_ASSIGN(MessageDialog);
}; };
@ -82,6 +92,7 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
const std::string& message, const std::string& message,
const std::string& detail) const std::string& detail)
: should_close_(false), : should_close_(false),
delete_on_close_(false),
result_(-1), result_(-1),
title_(UTF8ToUTF16(title)), title_(UTF8ToUTF16(title)),
widget_(NULL), widget_(NULL),
@ -124,12 +135,30 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
set_background(views::Background::CreateSolidBackground( set_background(views::Background::CreateSolidBackground(
skia::COLORREFToSkColor(GetSysColor(COLOR_WINDOW)))); skia::COLORREFToSkColor(GetSysColor(COLOR_WINDOW))));
widget_->Show();
} }
MessageDialog::~MessageDialog() { MessageDialog::~MessageDialog() {
} }
void MessageDialog::Show() {
widget_->Show();
}
int MessageDialog::GetResult() const {
// When the dialog is closed without choosing anything, we think the user
// chose 'Cancel', otherwise we think the default behavior is chosen.
if (result_ == -1) {
for (size_t i = 0; i < buttons_.size(); ++i)
if (LowerCaseEqualsASCII(buttons_[i]->GetText(), "cancel")) {
return i;
}
return 0;
} else {
return result_;
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// MessageDialog, private: // MessageDialog, private:
@ -145,6 +174,11 @@ string16 MessageDialog::GetWindowTitle() const {
void MessageDialog::WindowClosing() { void MessageDialog::WindowClosing() {
should_close_ = true; should_close_ = true;
if (delete_on_close_) {
callback_.Run(GetResult());
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
} }
views::Widget* MessageDialog::GetWidget() { views::Widget* MessageDialog::GetWidget() {
@ -232,6 +266,7 @@ int ShowMessageBox(NativeWindow* parent_window,
const std::string& message, const std::string& message,
const std::string& detail) { const std::string& detail) {
MessageDialog dialog(parent_window, type, buttons, title, message, detail); MessageDialog dialog(parent_window, type, buttons, title, message, detail);
dialog.Show();
{ {
base::MessageLoop::ScopedNestableTaskAllower allow( base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoopForUI::current()); base::MessageLoopForUI::current());
@ -239,18 +274,21 @@ int ShowMessageBox(NativeWindow* parent_window,
run_loop.Run(); run_loop.Run();
} }
// When the dialog is closed without choosing anything, we think the user return dialog.GetResult();
// chose 'Cancel', otherwise we think the default behavior is chosen. }
if (dialog.result() == -1) {
for (size_t i = 0; i < buttons.size(); ++i)
if (LowerCaseEqualsASCII(buttons[i], "cancel")) {
return i;
}
return 0; void ShowMessageBox(NativeWindow* parent_window,
} else { MessageBoxType type,
return dialog.result(); const std::vector<std::string>& buttons,
} const std::string& title,
const std::string& message,
const std::string& detail,
const MessageBoxCallback& callback) {
// The dialog would be deleted when the dialog is closed.
MessageDialog* dialog = new MessageDialog(
parent_window, type, buttons, title, message, detail);
dialog->set_callback(callback);
dialog->Show();
} }
} // namespace atom } // namespace atom

View file

@ -4,8 +4,7 @@
// Multiply-included file, no traditional include guard. // Multiply-included file, no traditional include guard.
#include <string> #include "base/string16.h"
#include "base/values.h" #include "base/values.h"
#include "common/draggable_region.h" #include "common/draggable_region.h"
#include "content/public/common/common_param_traits.h" #include "content/public/common/common_param_traits.h"
@ -22,16 +21,16 @@ IPC_STRUCT_TRAITS_BEGIN(atom::DraggableRegion)
IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_END()
IPC_MESSAGE_ROUTED2(AtomViewHostMsg_Message, IPC_MESSAGE_ROUTED2(AtomViewHostMsg_Message,
std::string /* channel */, string16 /* channel */,
ListValue /* arguments */) ListValue /* arguments */)
IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync, IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync,
std::string /* channel */, string16 /* channel */,
ListValue /* arguments */, ListValue /* arguments */,
DictionaryValue /* result */) string16 /* result (in JSON) */)
IPC_MESSAGE_ROUTED2(AtomViewMsg_Message, IPC_MESSAGE_ROUTED2(AtomViewMsg_Message,
std::string /* channel */, string16 /* channel */,
ListValue /* arguments */) ListValue /* arguments */)
// Sent by the renderer when the draggable regions are updated. // Sent by the renderer when the draggable regions are updated.

228
common/v8_conversions.h Normal file
View file

@ -0,0 +1,228 @@
// 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 COMMON_V8_CONVERSIONS_H_
#define COMMON_V8_CONVERSIONS_H_
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/string16.h"
#include "browser/api/atom_api_window.h"
#include "v8/include/v8.h"
// Convert V8 value to arbitrary supported types.
struct FromV8Value {
explicit FromV8Value(v8::Handle<v8::Value> value) : value_(value) {}
operator int() {
return value_->IntegerValue();
}
operator bool() {
return value_->BooleanValue();
}
operator std::string() {
return *v8::String::Utf8Value(value_);
}
operator string16() {
v8::String::Value s(value_);
return string16(reinterpret_cast<const char16*>(*s), s.length());
}
operator base::FilePath() {
return base::FilePath::FromUTF8Unsafe(FromV8Value(value_));
}
operator std::vector<std::string>() {
std::vector<std::string> array;
v8::Handle<v8::Array> v8_array = v8::Handle<v8::Array>::Cast(value_);
for (uint32_t i = 0; i < v8_array->Length(); ++i)
array.push_back(FromV8Value(v8_array->Get(i)));
return array;
}
operator atom::NativeWindow*() {
using atom::api::Window;
if (value_->IsObject()) {
Window* window = Window::Unwrap<Window>(value_->ToObject());
if (window && window->window())
return window->window();
}
return NULL;
}
operator v8::Persistent<v8::Function>() {
return value_->IsFunction() ?
v8::Persistent<v8::Function>::New(
node::node_isolate,
v8::Handle<v8::Function>::Cast(value_)) :
v8::Persistent<v8::Function>();
}
v8::Handle<v8::Value> value_;
};
// Convert arbitrary supported native type to V8 value.
inline v8::Handle<v8::Value> ToV8Value(int i) {
return v8::Integer::New(i);
}
inline v8::Handle<v8::Value> ToV8Value(bool b) {
return v8::Boolean::New(b);
}
inline v8::Handle<v8::Value> ToV8Value(const std::string& s) {
return v8::String::New(s.data(), s.size());
}
inline v8::Handle<v8::Value> ToV8Value(const string16& s) {
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
}
inline v8::Handle<v8::Value> ToV8Value(const base::FilePath& path) {
std::string path_string(path.AsUTF8Unsafe());
return v8::String::New(path_string.data(), path_string.size());
}
inline v8::Handle<v8::Value> ToV8Value(void* whatever) {
return v8::Undefined();
}
inline
v8::Handle<v8::Value> ToV8Value(const std::vector<base::FilePath>& paths) {
v8::Handle<v8::Array> result = v8::Array::New(paths.size());
for (size_t i = 0; i < paths.size(); ++i)
result->Set(i, ToV8Value(paths[i]));
return result;
}
// Check if a V8 Value is of specified type.
template<class T> inline
bool V8ValueCanBeConvertedTo(v8::Handle<v8::Value> value) {
return false;
}
template<> inline
bool V8ValueCanBeConvertedTo<int>(v8::Handle<v8::Value> value) {
return value->IsNumber();
}
template<> inline
bool V8ValueCanBeConvertedTo<bool>(v8::Handle<v8::Value> value) {
return value->IsBoolean();
}
template<> inline
bool V8ValueCanBeConvertedTo<std::string>(v8::Handle<v8::Value> value) {
return value->IsString();
}
template<> inline
bool V8ValueCanBeConvertedTo<string16>(v8::Handle<v8::Value> value) {
return V8ValueCanBeConvertedTo<std::string>(value);
}
template<> inline
bool V8ValueCanBeConvertedTo<base::FilePath>(v8::Handle<v8::Value> value) {
return V8ValueCanBeConvertedTo<std::string>(value);
}
template<> inline
bool V8ValueCanBeConvertedTo<std::vector<std::string>>(
v8::Handle<v8::Value> value) {
return value->IsArray();
}
template<> inline
bool V8ValueCanBeConvertedTo<atom::NativeWindow*>(v8::Handle<v8::Value> value) {
using atom::api::Window;
if (value->IsObject()) {
Window* window = Window::Unwrap<Window>(value->ToObject());
if (window && window->window())
return true;
}
return false;
}
template<> inline
bool V8ValueCanBeConvertedTo<v8::Persistent<v8::Function>>(
v8::Handle<v8::Value> value) {
return value->IsFunction();
}
// Check and convert V8's Arguments to native types.
template<typename T1> inline
bool FromV8Arguments(const v8::Arguments& args, T1* value, int index = 0) {
if (!V8ValueCanBeConvertedTo<T1>(args[index]))
return false;
*value = static_cast<const T1&>(FromV8Value(args[index]));
return true;
}
template<typename T1, typename T2> inline
bool FromV8Arguments(const v8::Arguments& args, T1* a1, T2* a2) {
return FromV8Arguments<T1>(args, a1) && FromV8Arguments<T2>(args, a2, 1);
}
template<typename T1, typename T2, typename T3> inline
bool FromV8Arguments(const v8::Arguments& args, T1* a1, T2* a2, T3* a3) {
return FromV8Arguments<T1, T2>(args, a1, a2) &&
FromV8Arguments<T3>(args, a3, 2);
}
template<typename T1, typename T2, typename T3, typename T4> inline
bool FromV8Arguments(const v8::Arguments& args,
T1* a1,
T2* a2,
T3* a3,
T4* a4) {
return FromV8Arguments<T1, T2, T3>(args, a1, a2, a3) &&
FromV8Arguments<T4>(args, a4, 3);
}
template<typename T1, typename T2, typename T3, typename T4, typename T5> inline
bool FromV8Arguments(const v8::Arguments& args,
T1* a1,
T2* a2,
T3* a3,
T4* a4,
T5* a5) {
return FromV8Arguments<T1, T2, T3, T4>(args, a1, a2, a3, a4) &&
FromV8Arguments<T5>(args, a5, 4);
}
template<typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6> inline
bool FromV8Arguments(const v8::Arguments& args,
T1* a1,
T2* a2,
T3* a3,
T4* a4,
T5* a5,
T6* a6) {
return FromV8Arguments<T1, T2, T3, T4, T5>(args, a1, a2, a3, a4, a5) &&
FromV8Arguments<T6>(args, a6, 5);
}
template<typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7> inline
bool FromV8Arguments(const v8::Arguments& args,
T1* a1,
T2* a2,
T3* a3,
T4* a4,
T5* a5,
T6* a6,
T7* a7) {
return
FromV8Arguments<T1, T2, T3, T4, T5, T6>(args, a1, a2, a3, a4, a5, a6) &&
FromV8Arguments<T7>(args, a7, 6);
}
#endif // COMMON_V8_CONVERSIONS_H_

View file

@ -18,7 +18,7 @@ Emitted when renderer sent a message to the browser.
* `routingId` Integer * `routingId` Integer
Emitted when renderer sent a synchronous message to the browser. The receiver Emitted when renderer sent a synchronous message to the browser. The receiver
should store the result in `event.result`. should store the result in `event.returnValue`.
**Note:** Due to the limitation of `EventEmitter`, returning value in the **Note:** Due to the limitation of `EventEmitter`, returning value in the
event handler has no effect, so we have to store the result by using the event handler has no effect, so we have to store the result by using the

View file

@ -30,7 +30,7 @@ An example of sending synchronous message from renderer to browser:
// In browser: // In browser:
var ipc = require('ipc'); var ipc = require('ipc');
ipc.on('browser-data-request', function(event, processId, routingId, message) { ipc.on('browser-data-request', function(event, processId, routingId, message) {
event.result = 'THIS SOME DATA FROM THE BROWSER'; event.returnValue = 'THIS SOME DATA FROM THE BROWSER';
}); });
``` ```

View file

@ -6,6 +6,7 @@
#include "base/values.h" #include "base/values.h"
#include "common/api/api_messages.h" #include "common/api/api_messages.h"
#include "common/v8_conversions.h"
#include "content/public/renderer/render_view.h" #include "content/public/renderer/render_view.h"
#include "content/public/renderer/v8_value_converter.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/WebFrame.h"
@ -47,8 +48,7 @@ v8::Handle<v8::Value> RendererIPC::Send(const v8::Arguments &args) {
if (!args[0]->IsString()) if (!args[0]->IsString())
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
std::string channel(*v8::String::Utf8Value(args[0])); string16 channel = FromV8Value(args[0]);
RenderView* render_view = GetCurrentRenderView(); RenderView* render_view = GetCurrentRenderView();
// Convert Arguments to Array, so we can use V8ValueConverter to convert it // Convert Arguments to Array, so we can use V8ValueConverter to convert it
@ -82,7 +82,7 @@ v8::Handle<v8::Value> RendererIPC::SendSync(const v8::Arguments &args) {
return node::ThrowTypeError("Bad argument"); return node::ThrowTypeError("Bad argument");
v8::Handle<v8::Context> context = v8::Context::GetCurrent(); v8::Handle<v8::Context> context = v8::Context::GetCurrent();
std::string channel(*v8::String::Utf8Value(args[0])); string16 channel = FromV8Value(args[0]);
// Convert Arguments to Array, so we can use V8ValueConverter to convert it // Convert Arguments to Array, so we can use V8ValueConverter to convert it
// to ListValue. // to ListValue.
@ -97,12 +97,12 @@ v8::Handle<v8::Value> RendererIPC::SendSync(const v8::Arguments &args) {
RenderView* render_view = GetCurrentRenderView(); RenderView* render_view = GetCurrentRenderView();
base::DictionaryValue result; string16 json;
IPC::SyncMessage* message = new AtomViewHostMsg_Message_Sync( IPC::SyncMessage* message = new AtomViewHostMsg_Message_Sync(
render_view->GetRoutingID(), render_view->GetRoutingID(),
channel, channel,
*static_cast<base::ListValue*>(arguments.get()), *static_cast<base::ListValue*>(arguments.get()),
&result); &json);
// Enable the UI thread in browser to receive messages. // Enable the UI thread in browser to receive messages.
message->EnableMessagePumping(); message->EnableMessagePumping();
bool success = render_view->Send(message); bool success = render_view->Send(message);
@ -110,7 +110,7 @@ v8::Handle<v8::Value> RendererIPC::SendSync(const v8::Arguments &args) {
if (!success) if (!success)
return node::ThrowError("Unable to send AtomViewHostMsg_Message_Sync"); return node::ThrowError("Unable to send AtomViewHostMsg_Message_Sync");
return scope.Close(converter->ToV8Value(&result, context)); return scope.Close(ToV8Value(json));
} }
// static // static

View file

@ -8,6 +8,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/values.h" #include "base/values.h"
#include "common/v8_conversions.h"
#include "content/public/renderer/render_view.h" #include "content/public/renderer/render_view.h"
#include "content/public/renderer/v8_value_converter.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/WebFrame.h"
@ -51,7 +52,7 @@ void AtomRendererBindings::BindToFrame(WebFrame* frame) {
AtomBindings::BindTo(GetProcessObject(context)); AtomBindings::BindTo(GetProcessObject(context));
} }
void AtomRendererBindings::OnBrowserMessage(const std::string& channel, void AtomRendererBindings::OnBrowserMessage(const string16& channel,
const base::ListValue& args) { const base::ListValue& args) {
if (!render_view_->GetWebView()) if (!render_view_->GetWebView())
return; return;
@ -70,7 +71,7 @@ void AtomRendererBindings::OnBrowserMessage(const std::string& channel,
std::vector<v8::Handle<v8::Value>> arguments; std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(1 + args.GetSize()); arguments.reserve(1 + args.GetSize());
arguments.push_back(v8::String::New(channel.c_str(), channel.size())); arguments.push_back(ToV8Value(channel));
for (size_t i = 0; i < args.GetSize(); i++) { for (size_t i = 0; i < args.GetSize(); i++) {
const base::Value* value; const base::Value* value;

View file

@ -5,10 +5,10 @@
#ifndef ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_ #ifndef ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_
#define ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_ #define ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_
#include <string>
#include "common/api/atom_bindings.h" #include "common/api/atom_bindings.h"
#include "base/string16.h"
namespace base { namespace base {
class ListValue; class ListValue;
} }
@ -32,7 +32,7 @@ class AtomRendererBindings : public AtomBindings {
void BindToFrame(WebKit::WebFrame* frame); void BindToFrame(WebKit::WebFrame* frame);
// Dispatch messages from browser. // Dispatch messages from browser.
void OnBrowserMessage(const std::string& channel, void OnBrowserMessage(const string16& channel,
const base::ListValue& args); const base::ListValue& args);
private: private:

View file

@ -16,9 +16,11 @@ class Ipc extends EventEmitter
ipc.send('ATOM_INTERNAL_MESSAGE', args...) ipc.send('ATOM_INTERNAL_MESSAGE', args...)
sendSync: (args...) -> sendSync: (args...) ->
ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', 'sync-message', args...).result msg = ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', 'sync-message', args...)
JSON.parse(msg)
sendChannelSync: (args...) -> sendChannelSync: (args...) ->
ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', args...).result msg = ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', args...)
JSON.parse(msg)
module.exports = new Ipc module.exports = new Ipc

View file

@ -72,6 +72,7 @@ metaToValue = (meta) ->
ret.__defineSetter__ member.name, (value) -> ret.__defineSetter__ member.name, (value) ->
# Set member data. # Set member data.
ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value
value
ret.__defineGetter__ member.name, -> ret.__defineGetter__ member.name, ->
# Get member data. # Get member data.

View file

@ -101,7 +101,7 @@ bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) {
return handled; return handled;
} }
void AtomRenderViewObserver::OnBrowserMessage(const std::string& channel, void AtomRenderViewObserver::OnBrowserMessage(const string16& channel,
const base::ListValue& args) { const base::ListValue& args) {
atom_bindings()->OnBrowserMessage(channel, args); atom_bindings()->OnBrowserMessage(channel, args);
} }

View file

@ -35,7 +35,7 @@ class AtomRenderViewObserver : content::RenderViewObserver {
virtual void DraggableRegionsChanged(WebKit::WebFrame* frame) OVERRIDE; virtual void DraggableRegionsChanged(WebKit::WebFrame* frame) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
void OnBrowserMessage(const std::string& channel, void OnBrowserMessage(const string16& channel,
const base::ListValue& args); const base::ListValue& args);
scoped_ptr<AtomRendererBindings> atom_bindings_; scoped_ptr<AtomRendererBindings> atom_bindings_;

View file

@ -49,7 +49,12 @@ describe 'ipc', ->
describe 'ipc.send', -> describe 'ipc.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.on 'message', (message) -> ipc.once 'message', (message) ->
assert.deepEqual message, obj assert.deepEqual message, obj
done() done()
ipc.send obj ipc.send obj
describe 'ipc.sendSync', ->
it 'can be replied by setting event.returnValue', ->
msg = ipc.sendChannelSync 'echo', 'test'
assert.equal msg, 'test'

View file

@ -23,7 +23,11 @@ ipc.on('process.exit', function(pid, rid, code) {
}); });
ipc.on('eval', function(ev, pid, rid, script) { ipc.on('eval', function(ev, pid, rid, script) {
ev.result = eval(script); ev.returnValue = eval(script);
});
ipc.on('echo', function(ev, pid, rid, msg) {
ev.returnValue = msg;
}); });
process.on('uncaughtException', function() { process.on('uncaughtException', function() {