diff --git a/browser/api/atom_api_event_emitter.cc b/browser/api/atom_api_event_emitter.cc index 48f27cdd2094..13acafe0b037 100644 --- a/browser/api/atom_api_event_emitter.cc +++ b/browser/api/atom_api_event_emitter.cc @@ -71,6 +71,26 @@ bool EventEmitter::Emit(const std::string& name, base::ListValue* args) { return prevent_default; } +// static +v8::Handle EventEmitter::FromConstructorTemplate( + v8::Persistent t, + const v8::Arguments& args) { + v8::Handle new_object = node::FromConstructorTemplate(t, args); + args.This()->SetHiddenValue(v8::String::New("native_object"), new_object); + return new_object; +} + +// static +v8::Handle EventEmitter::SearchNativeObject( + v8::Handle handle) { + if (handle->InternalFieldCount() > 0) + return handle; + + // If the object is not a native object, we assume the native object is + // stored in it. + return handle->GetHiddenValue(v8::String::New("native_object"))->ToObject(); +} + } // namespace api } // namespace atom diff --git a/browser/api/atom_api_event_emitter.h b/browser/api/atom_api_event_emitter.h index af514503dca1..fc3853f9faab 100644 --- a/browser/api/atom_api_event_emitter.h +++ b/browser/api/atom_api_event_emitter.h @@ -29,12 +29,37 @@ class EventEmitter : public node::ObjectWrap { bool Emit(const std::string& name); bool Emit(const std::string& name, base::ListValue* args); + // Same with Unwrap but if the handle is not a native object, which happened + // when user inherits a native class, we would search for the native object, + // otherwise we won't get the correct C++ object. + template + static inline bool SafeUnwrap(v8::Handle handle, T** pointer) { + v8::Handle real_handle = SearchNativeObject(handle); + if (real_handle->InternalFieldCount() == 0) + return false; + + *pointer = Unwrap(real_handle); + return true; + } + + // Helper function to call "new" when constructor is called as normal + // function, this usually happens when inheriting native class. + // + // This function also does some special hacks to make sure the inheritance + // would work, because normal inheritance would not inherit internal fields. + static v8::Handle FromConstructorTemplate( + v8::Persistent t, + const v8::Arguments& args); + // Small accessor to return handle_, this follows Google C++ Style. v8::Persistent handle() const { return handle_; } protected: explicit EventEmitter(v8::Handle wrapper); + static v8::Handle SearchNativeObject( + v8::Handle handle); + private: DISALLOW_COPY_AND_ASSIGN(EventEmitter); }; diff --git a/browser/api/atom_api_window.cc b/browser/api/atom_api_window.cc index 0f4f870fde47..1c89a7722c20 100644 --- a/browser/api/atom_api_window.cc +++ b/browser/api/atom_api_window.cc @@ -19,9 +19,13 @@ using content::NavigationController; using node::ObjectWrap; #define UNWRAP_WINDOW_AND_CHECK \ - Window* self = ObjectWrap::Unwrap(args.This()); \ - if (self == NULL) \ - return node::ThrowError("Window is already destroyed") + Window* self; \ + if (SafeUnwrap(args.This(), &self)) { \ + if (self == NULL) \ + return node::ThrowError("Window is already destroyed"); \ + } else { \ + return node::ThrowTypeError("Window methods are not generic");\ + } namespace atom { @@ -36,6 +40,9 @@ v8::Handle UTF16ToV8String(const string16& s) { } // namespace +// static +v8::Persistent Window::constructor_template_; + Window::Window(v8::Handle wrapper, base::DictionaryValue* options) : EventEmitter(wrapper), window_(NativeWindow::Create(options)) { @@ -85,10 +92,10 @@ void Window::OnRendererCrashed() { // static v8::Handle Window::New(const v8::Arguments &args) { - v8::HandleScope scope; - if (!args.IsConstructCall()) - return node::ThrowError("Require constructor call"); + return FromConstructorTemplate(constructor_template_, args); + + v8::HandleScope scope; if (!args[0]->IsObject()) return node::ThrowTypeError("Need options creating Window"); @@ -643,7 +650,10 @@ void Window::Initialize(v8::Handle target) { v8::Local t = v8::FunctionTemplate::New(Window::New); t->InstanceTemplate()->SetInternalFieldCount(1); - t->SetClassName(v8::String::NewSymbol("BrowserWindow")); + t->SetClassName(v8::String::NewSymbol("Window")); + + constructor_template_ = v8::Persistent::New( + node::node_isolate, t); NODE_SET_PROTOTYPE_METHOD(t, "destroy", Destroy); NODE_SET_PROTOTYPE_METHOD(t, "close", Close); @@ -703,7 +713,7 @@ void Window::Initialize(v8::Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "reload", Reload); NODE_SET_PROTOTYPE_METHOD(t, "reloadIgnoringCache", ReloadIgnoringCache); - target->Set(v8::String::NewSymbol("BrowserWindow"), t->GetFunction()); + target->Set(v8::String::NewSymbol("Window"), t->GetFunction()); } } // namespace api diff --git a/browser/api/atom_api_window.h b/browser/api/atom_api_window.h index c9ffec213526..01c4f7ad8569 100644 --- a/browser/api/atom_api_window.h +++ b/browser/api/atom_api_window.h @@ -105,6 +105,8 @@ class Window : public EventEmitter, static v8::Handle Reload(const v8::Arguments &args); static v8::Handle ReloadIgnoringCache(const v8::Arguments &args); + static v8::Persistent constructor_template_; + scoped_ptr window_; DISALLOW_COPY_AND_ASSIGN(Window); diff --git a/browser/api/lib/browser-window.coffee b/browser/api/lib/browser-window.coffee index 452151c7bcd7..9c96add7a52f 100644 --- a/browser/api/lib/browser-window.coffee +++ b/browser/api/lib/browser-window.coffee @@ -2,28 +2,30 @@ EventEmitter = require('events').EventEmitter v8Util = process.atomBinding 'v8_util' objectsRegistry = require '../../atom/objects-registry.js' -BrowserWindow = process.atomBinding('window').BrowserWindow -BrowserWindow::__proto__ = EventEmitter.prototype +Window = process.atomBinding('window').Window +Window::__proto__ = EventEmitter.prototype -BrowserWindow::toggleDevTools = -> - opened = v8Util.getHiddenValue this, 'devtoolsOpened' - if opened - @closeDevTools() - v8Util.setHiddenValue this, 'devtoolsOpened', false - else - @openDevTools() - v8Util.setHiddenValue this, 'devtoolsOpened', true +module.exports = class BrowserWindow extends Window + constructor: -> + super -BrowserWindow::restart = -> - @loadUrl(@getUrl()) + toggleDevTools: -> + opened = v8Util.getHiddenValue this, 'devtoolsOpened' + if opened + @closeDevTools() + v8Util.setHiddenValue this, 'devtoolsOpened', false + else + @openDevTools() + v8Util.setHiddenValue this, 'devtoolsOpened', true -BrowserWindow.getFocusedWindow = -> - windows = objectsRegistry.getAllWindows() - return window for window in windows when window.isFocused() + restart: -> + @loadUrl @getUrl() -BrowserWindow.fromProcessIdAndRoutingId = (processId, routingId) -> - windows = objectsRegistry.getAllWindows() - return window for window in windows when window.getProcessId() == processId and - window.getRoutingId() == routingId + @getFocusedWindow: -> + windows = objectsRegistry.getAllWindows() + return window for window in windows when window.isFocused() -module.exports = BrowserWindow + @fromProcessIdAndRoutingId = (processId, routingId) -> + windows = objectsRegistry.getAllWindows() + return window for window in windows when window.getProcessId() == processId and + window.getRoutingId() == routingId