Merge branch 'master' into linux

Conflicts:
	vendor/apm
This commit is contained in:
Cheng Zhao 2014-01-15 11:18:40 +00:00
commit 2f798c5116
43 changed files with 478 additions and 75 deletions

View file

@ -0,0 +1,71 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "common/api/atom_api_event_emitter.h"
#include <vector>
#include "base/logging.h"
#include "browser/api/atom_api_event.h"
#include "common/v8/native_type_conversions.h"
#include "common/v8/node_common.h"
namespace atom {
namespace api {
EventEmitter::EventEmitter(v8::Handle<v8::Object> wrapper) {
Wrap(wrapper);
}
EventEmitter::~EventEmitter() {
// Clear the aligned pointer, it should have been done by ObjectWrap but
// somehow node v0.11.x changed this behaviour.
v8::HandleScope handle_scope(node_isolate);
handle()->SetAlignedPointerInInternalField(0, NULL);
}
bool EventEmitter::Emit(const std::string& name) {
base::ListValue args;
return Emit(name, &args);
}
bool EventEmitter::Emit(const std::string& name, base::ListValue* args) {
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
scoped_ptr<V8ValueConverter> converter(new V8ValueConverter);
v8::Handle<v8::Object> v8_event = Event::CreateV8Object();
Event* event = Event::Unwrap<Event>(v8_event);
// Generate arguments for calling handle.emit.
std::vector<v8::Handle<v8::Value>> v8_args;
v8_args.reserve(args->GetSize() + 2);
v8_args.push_back(ToV8Value(name));
v8_args.push_back(v8_event);
for (size_t i = 0; i < args->GetSize(); i++) {
base::Value* value = NULL;
if (args->Get(i, &value)) {
DCHECK(value);
v8_args.push_back(converter->ToV8Value(value, context));
} else {
NOTREACHED() << "Wrong offset " << i << " for " << *args;
}
}
node::MakeCallback(handle(), "emit", v8_args.size(), &v8_args[0]);
bool prevent_default = event->prevent_default();
// Don't wait for V8 GC, delete it immediately.
delete event;
return prevent_default;
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,43 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_ATOM_API_EVENT_EMITTER_H_
#define ATOM_COMMON_API_ATOM_API_EVENT_EMITTER_H_
#include <string>
#include "base/basictypes.h"
#include "vendor/node/src/node_object_wrap.h"
namespace base {
class ListValue;
}
namespace atom {
namespace api {
// Class interiting EventEmitter should assume it's a javascript object which
// interits require('events').EventEmitter, this class provides many helper
// methods to do event processing in C++.
class EventEmitter : public node::ObjectWrap {
public:
virtual ~EventEmitter();
// Emit an event and returns whether the handler has called preventDefault().
bool Emit(const std::string& name);
bool Emit(const std::string& name, base::ListValue* args);
protected:
explicit EventEmitter(v8::Handle<v8::Object> wrapper);
private:
DISALLOW_COPY_AND_ASSIGN(EventEmitter);
};
} // namespace api
} // namespace atom
#endif // ATOM_COMMON_API_ATOM_API_EVENT_EMITTER_H_

View file

@ -0,0 +1,86 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "common/api/atom_api_screen.h"
#include "common/v8/native_type_conversions.h"
#include "ui/gfx/screen.h"
#include "common/v8/node_common.h"
#define UNWRAP_SCREEN_AND_CHECK \
Screen* self = ObjectWrap::Unwrap<Screen>(args.This()); \
if (self == NULL) \
return node::ThrowError("Screen is already destroyed")
namespace atom {
namespace api {
namespace {
v8::Handle<v8::Object> DisplayToV8Value(const gfx::Display& display) {
v8::Handle<v8::Object> obj = v8::Object::New();
obj->Set(ToV8Value("bounds"), ToV8Value(display.bounds()));
obj->Set(ToV8Value("workArea"), ToV8Value(display.work_area()));
obj->Set(ToV8Value("size"), ToV8Value(display.size()));
obj->Set(ToV8Value("workAreaSize"), ToV8Value(display.work_area_size()));
obj->Set(ToV8Value("scaleFactor"), ToV8Value(display.device_scale_factor()));
return obj;
}
} // namespace
Screen::Screen(v8::Handle<v8::Object> wrapper)
: EventEmitter(wrapper),
screen_(gfx::Screen::GetNativeScreen()) {
}
Screen::~Screen() {
}
// static
void Screen::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope scope(args.GetIsolate());
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
new Screen(args.This());
}
// static
void Screen::GetCursorScreenPoint(
const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_SCREEN_AND_CHECK;
args.GetReturnValue().Set(ToV8Value(self->screen_->GetCursorScreenPoint()));
}
// static
void Screen::GetPrimaryDisplay(
const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_SCREEN_AND_CHECK;
gfx::Display display = self->screen_->GetPrimaryDisplay();
args.GetReturnValue().Set(DisplayToV8Value(display));
}
// static
void Screen::Initialize(v8::Handle<v8::Object> target) {
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(v8::String::NewSymbol("Screen"));
NODE_SET_PROTOTYPE_METHOD(t, "getCursorScreenPoint", GetCursorScreenPoint);
NODE_SET_PROTOTYPE_METHOD(t, "getPrimaryDisplay", GetPrimaryDisplay);
target->Set(v8::String::NewSymbol("Screen"), t->GetFunction());
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_common_screen, atom::api::Screen::Initialize)

View file

@ -0,0 +1,44 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_ATOM_API_SCREEN_H_
#define ATOM_COMMON_API_ATOM_API_SCREEN_H_
#include "common/api/atom_api_event_emitter.h"
namespace gfx {
class Screen;
}
namespace atom {
namespace api {
class Screen : public EventEmitter {
public:
virtual ~Screen();
static void Initialize(v8::Handle<v8::Object> target);
protected:
explicit Screen(v8::Handle<v8::Object> wrapper);
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetCursorScreenPoint(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetPrimaryDisplay(
const v8::FunctionCallbackInfo<v8::Value>& args);
gfx::Screen* screen_;
DISALLOW_COPY_AND_ASSIGN(Screen);
};
} // namespace api
} // namespace atom
#endif // ATOM_COMMON_API_ATOM_API_SCREEN_H_

View file

@ -16,11 +16,41 @@ namespace {
static int kMaxCallStackSize = 200; // Same with WebKit.
static uv_async_t dummy_uv_handle;
// Async handle to wake up uv loop.
static uv_async_t g_next_tick_uv_handle;
// Async handle to execute the stored v8 callback.
static uv_async_t g_callback_uv_handle;
// Stored v8 callback, to be called by the async handler.
RefCountedV8Function g_v8_callback;
// Dummy class type that used for crashing the program.
struct DummyClass { bool crash; };
void UvNoOp(uv_async_t* handle, int status) {
// Async handler to call next process.nextTick callbacks.
void UvCallNextTick(uv_async_t* handle, int status) {
node::Environment* env = node::Environment::GetCurrent(node_isolate);
node::Environment::TickInfo* tick_info = env->tick_info();
if (tick_info->in_tick())
return;
if (tick_info->length() == 0) {
tick_info->set_index(0);
return;
}
tick_info->set_in_tick(true);
env->tick_callback_function()->Call(env->process_object(), 0, NULL);
tick_info->set_in_tick(false);
}
// Async handler to execute the stored v8 callback.
void UvOnCallback(uv_async_t* handle, int status) {
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
g_v8_callback->NewHandle()->Call(global, 0, NULL);
}
v8::Handle<v8::Object> DumpStackFrame(v8::Handle<v8::StackFrame> stack_frame) {
@ -44,7 +74,8 @@ v8::Handle<v8::Object> DumpStackFrame(v8::Handle<v8::StackFrame> stack_frame) {
node::node_module_struct* GetBuiltinModule(const char *name, bool is_browser);
AtomBindings::AtomBindings() {
uv_async_init(uv_default_loop(), &dummy_uv_handle, UvNoOp);
uv_async_init(uv_default_loop(), &g_next_tick_uv_handle, UvCallNextTick);
uv_async_init(uv_default_loop(), &g_callback_uv_handle, UvOnCallback);
}
AtomBindings::~AtomBindings() {
@ -58,6 +89,7 @@ void AtomBindings::BindTo(v8::Handle<v8::Object> process) {
NODE_SET_METHOD(process, "activateUvLoop", ActivateUVLoop);
NODE_SET_METHOD(process, "log", Log);
NODE_SET_METHOD(process, "getCurrentStackTrace", GetCurrentStackTrace);
NODE_SET_METHOD(process, "scheduleCallback", ScheduleCallback);
process->Get(v8::String::New("versions"))->ToObject()->
Set(v8::String::New("atom-shell"), v8::String::New(ATOM_VERSION_STRING));
@ -115,7 +147,7 @@ void AtomBindings::Crash(const v8::FunctionCallbackInfo<v8::Value>& args) {
// static
void AtomBindings::ActivateUVLoop(
const v8::FunctionCallbackInfo<v8::Value>& args) {
uv_async_send(&dummy_uv_handle);
uv_async_send(&g_next_tick_uv_handle);
}
// static
@ -146,4 +178,12 @@ void AtomBindings::GetCurrentStackTrace(
args.GetReturnValue().Set(result);
}
// static
void AtomBindings::ScheduleCallback(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (!FromV8Arguments(args, &g_v8_callback))
return node::ThrowTypeError("Bad arguments");
uv_async_send(&g_callback_uv_handle);
}
} // namespace atom

View file

@ -26,6 +26,7 @@ class AtomBindings {
static void Log(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetCurrentStackTrace(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void ScheduleCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
DISALLOW_COPY_AND_ASSIGN(AtomBindings);
};

View file

@ -27,6 +27,7 @@ NODE_EXT_LIST_ITEM(atom_renderer_ipc)
NODE_EXT_LIST_ITEM(atom_common_clipboard)
NODE_EXT_LIST_ITEM(atom_common_crash_reporter)
NODE_EXT_LIST_ITEM(atom_common_id_weak_map)
NODE_EXT_LIST_ITEM(atom_common_screen)
NODE_EXT_LIST_ITEM(atom_common_shell)
NODE_EXT_LIST_ITEM(atom_common_v8_util)

View file

@ -0,0 +1,3 @@
{Screen} = process.atomBinding 'screen'
module.exports = new Screen

View file

@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 8
#define ATOM_PATCH_VERSION 1
#define ATOM_PATCH_VERSION 5
#define ATOM_VERSION_IS_RELEASE 1

28
common/lib/init.coffee Normal file
View file

@ -0,0 +1,28 @@
path = require 'path'
timers = require 'timers'
Module = require 'module'
# Add common/api/lib to module search paths.
globalPaths = Module.globalPaths
globalPaths.push path.join(process.resourcesPath, 'common', 'api', 'lib')
# setImmediate and process.nextTick makes use of uv_check and uv_prepare to
# run the callbacks, however since we only run uv loop on requests, the
# callbacks wouldn't be called until something else activated the uv loop,
# which would delay the callbacks for arbitrary long time. So we should
# initiatively activate the uv loop once setImmediate and process.nextTick is
# called.
wrapWithActivateUvLoop = (func) ->
->
process.activateUvLoop()
func.apply this, arguments
process.nextTick = wrapWithActivateUvLoop process.nextTick
global.setImmediate = wrapWithActivateUvLoop timers.setImmediate
global.clearImmediate = timers.clearImmediate
# The child_process module also needs to activate the uv loop to make the ipc
# channel setup.
# TODO(zcbenz): Find out why this is needed.
childProcess = require 'child_process'
childProcess.spawn = wrapWithActivateUvLoop childProcess.spawn
childProcess.fork = wrapWithActivateUvLoop childProcess.fork

View file

@ -65,7 +65,9 @@ NodeBindings::NodeBindings(bool is_browser)
: is_browser_(is_browser),
message_loop_(NULL),
uv_loop_(uv_default_loop()),
embed_closed_(false) {
embed_closed_(false),
uv_env_(NULL),
weak_factory_(this) {
}
NodeBindings::~NodeBindings() {
@ -76,7 +78,6 @@ NodeBindings::~NodeBindings() {
// Wait for everything to be done.
uv_thread_join(&embed_thread_);
message_loop_->RunUntilIdle();
// Clear uv.
uv_sem_destroy(&embed_sem_);
@ -193,9 +194,13 @@ void NodeBindings::RunMessageLoop() {
void NodeBindings::UvRunOnce() {
DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI));
// Enter node context while dealing with uv events.
v8::HandleScope handle_scope(node_isolate);
v8::Context::Scope context_scope(global_env->context());
// Enter node context while dealing with uv events, by default the global
// env would be used unless user specified another one (this happens for
// renderer process, which wraps the uv loop with web page context).
node::Environment* env = uv_env() ? uv_env() : global_env;
v8::Context::Scope context_scope(env->context());
// Deal with uv events.
int r = uv_run(uv_loop_, (uv_run_mode)(UV_RUN_ONCE | UV_RUN_NOWAIT));
@ -209,7 +214,7 @@ void NodeBindings::UvRunOnce() {
void NodeBindings::WakeupMainThread() {
DCHECK(message_loop_);
message_loop_->PostTask(FROM_HERE, base::Bind(&NodeBindings::UvRunOnce,
base::Unretained(this)));
weak_factory_.GetWeakPtr()));
}
void NodeBindings::WakeupEmbedThread() {
@ -220,11 +225,20 @@ void NodeBindings::WakeupEmbedThread() {
void NodeBindings::EmbedThreadRunner(void *arg) {
NodeBindings* self = static_cast<NodeBindings*>(arg);
while (!self->embed_closed_) {
while (true) {
// Wait for the main loop to deal with events.
uv_sem_wait(&self->embed_sem_);
if (self->embed_closed_)
break;
// Wait for something to happen in uv loop.
// Note that the PollEvents() is implemented by derived classes, so when
// this class is being destructed the PollEvents() would not be available
// anymore. Because of it we must make sure we only invoke PollEvents()
// when this class is alive.
self->PollEvents();
if (self->embed_closed_)
break;
// Deal with event in main thread.
self->WakeupMainThread();

View file

@ -6,6 +6,7 @@
#define ATOM_COMMON_NODE_BINDINGS_H_
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "v8/include/v8.h"
#include "vendor/node/deps/uv/include/uv.h"
@ -37,6 +38,10 @@ class NodeBindings {
// Do message loop integration.
virtual void RunMessageLoop();
// Gets/sets the environment to wrap uv loop.
void set_uv_env(node::Environment* env) { uv_env_ = env; }
node::Environment* uv_env() const { return uv_env_; }
protected:
explicit NodeBindings(bool is_browser);
@ -83,6 +88,11 @@ class NodeBindings {
// Semaphore to wait for main loop in the embed thread.
uv_sem_t embed_sem_;
// Environment that to wrap the uv loop.
node::Environment* uv_env_;
base::WeakPtrFactory<NodeBindings> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(NodeBindings);
};

View file

@ -17,8 +17,9 @@
#include "common/swap_or_assign.h"
#include "common/v8/scoped_persistent.h"
#include "common/v8/v8_value_converter.h"
#include "content/public/renderer/v8_value_converter.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "url/gurl.h"
// Convert V8 value to arbitrary supported types.
@ -71,8 +72,9 @@ struct FromV8Value {
converter->FromV8Value(value_, v8::Context::GetCurrent()));
}
operator std::vector<std::string>() {
std::vector<std::string> array;
template<class T>
operator std::vector<T>() {
std::vector<T> 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)));
@ -80,14 +82,15 @@ struct FromV8Value {
return array;
}
operator std::map<std::string, std::string>() {
std::map<std::string, std::string> dict;
template<class K, class V>
operator std::map<K, V>() {
std::map<K, V> dict;
v8::Handle<v8::Object> v8_dict = value_->ToObject();
v8::Handle<v8::Array> v8_keys = v8_dict->GetOwnPropertyNames();
for (uint32_t i = 0; i < v8_keys->Length(); ++i) {
v8::Handle<v8::Value> v8_key = v8_keys->Get(i);
std::string key = FromV8Value(v8_key);
dict[key] = std::string(FromV8Value(v8_dict->Get(v8_key)));
K key = FromV8Value(v8_key);
dict[key] = V(FromV8Value(v8_dict->Get(v8_key)));
}
return dict;
@ -121,6 +124,14 @@ inline v8::Handle<v8::Value> ToV8Value(bool b) {
return v8::Boolean::New(b);
}
inline v8::Handle<v8::Value> ToV8Value(float f) {
return v8::Number::New(f);
}
inline v8::Handle<v8::Value> ToV8Value(double f) {
return v8::Number::New(f);
}
inline v8::Handle<v8::Value> ToV8Value(const char* s) {
return v8::String::New(s);
}
@ -146,14 +157,37 @@ 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]));
template<class T> inline
v8::Handle<v8::Value> ToV8Value(const std::vector<T>& arr) {
v8::Handle<v8::Array> result = v8::Array::New(arr.size());
for (size_t i = 0; i < arr.size(); ++i)
result->Set(i, ToV8Value(arr[i]));
return result;
}
inline v8::Handle<v8::Value> ToV8Value(const gfx::Point& point) {
v8::Handle<v8::Object> obj = v8::Object::New();
obj->Set(ToV8Value("x"), ToV8Value(point.x()));
obj->Set(ToV8Value("y"), ToV8Value(point.y()));
return obj;
}
inline v8::Handle<v8::Value> ToV8Value(const gfx::Rect& rect) {
v8::Handle<v8::Object> obj = v8::Object::New();
obj->Set(ToV8Value("x"), ToV8Value(rect.x()));
obj->Set(ToV8Value("y"), ToV8Value(rect.y()));
obj->Set(ToV8Value("width"), ToV8Value(rect.width()));
obj->Set(ToV8Value("height"), ToV8Value(rect.height()));
return obj;
}
inline v8::Handle<v8::Value> ToV8Value(const gfx::Size& size) {
v8::Handle<v8::Object> obj = v8::Object::New();
obj->Set(ToV8Value("width"), ToV8Value(size.width()));
obj->Set(ToV8Value("height"), ToV8Value(size.height()));
return obj;
}
// Check if a V8 Value is of specified type.
template<class T> inline
bool V8ValueCanBeConvertedTo(v8::Handle<v8::Value> value) {

View file

@ -8,6 +8,8 @@
// Include common headers for using node APIs.
#undef CHECK
#undef CHECK_EQ
#undef CHECK_NE
#undef DISALLOW_COPY_AND_ASSIGN
#include "vendor/node/src/env.h"
#include "vendor/node/src/env-inl.h"