diff --git a/atom/browser/api/atom_api_box_layout.cc b/atom/browser/api/atom_api_box_layout.cc new file mode 100644 index 0000000000..b37430b6eb --- /dev/null +++ b/atom/browser/api/atom_api_box_layout.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2018 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/api/atom_api_box_layout.h" + +#include + +#include "atom/common/api/constructor.h" +#include "native_mate/dictionary.h" + +#include "atom/common/node_includes.h" + +namespace mate { + +template <> +struct Converter { + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + views::BoxLayout::Orientation* out) { + std::string orientation; + if (!ConvertFromV8(isolate, val, &orientation)) + return false; + if (orientation == "horizontal") + *out = views::BoxLayout::kHorizontal; + else if (orientation == "vertical") + *out = views::BoxLayout::kVertical; + else + return false; + return true; + } +}; + +} // namespace mate + +namespace atom { + +namespace api { + +BoxLayout::BoxLayout(views::BoxLayout::Orientation orientation) + : LayoutManager(new views::BoxLayout(orientation)) {} + +BoxLayout::~BoxLayout() {} + +// static +mate::WrappableBase* BoxLayout::New(mate::Arguments* args, + views::BoxLayout::Orientation orientation) { + auto* layout = new BoxLayout(orientation); + layout->InitWith(args->isolate(), args->GetThis()); + return layout; +} + +// static +void BoxLayout::BuildPrototype(v8::Isolate* isolate, + v8::Local prototype) {} + +} // namespace api + +} // namespace atom + +namespace { + +using atom::api::BoxLayout; + +void Initialize(v8::Local exports, + v8::Local unused, + v8::Local context, + void* priv) { + v8::Isolate* isolate = context->GetIsolate(); + mate::Dictionary dict(isolate, exports); + dict.Set("BoxLayout", mate::CreateConstructor( + isolate, base::Bind(&BoxLayout::New))); +} + +} // namespace + +NODE_BUILTIN_MODULE_CONTEXT_AWARE(atom_browser_box_layout, Initialize) diff --git a/atom/browser/api/atom_api_box_layout.h b/atom/browser/api/atom_api_box_layout.h new file mode 100644 index 0000000000..804cc244c1 --- /dev/null +++ b/atom/browser/api/atom_api_box_layout.h @@ -0,0 +1,35 @@ +// Copyright (c) 2018 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_API_ATOM_API_BOX_LAYOUT_H_ +#define ATOM_BROWSER_API_ATOM_API_BOX_LAYOUT_H_ + +#include "atom/browser/api/atom_api_layout_manager.h" +#include "ui/views/layout/box_layout.h" + +namespace atom { + +namespace api { + +class BoxLayout : public LayoutManager { + public: + static mate::WrappableBase* New(mate::Arguments* args, + views::BoxLayout::Orientation orientation); + + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + + protected: + explicit BoxLayout(views::BoxLayout::Orientation orientation); + ~BoxLayout() override; + + private: + DISALLOW_COPY_AND_ASSIGN(BoxLayout); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_BOX_LAYOUT_H_ diff --git a/atom/browser/api/atom_api_browser_window.cc b/atom/browser/api/atom_api_browser_window.cc index ce85e52d43..a987828be5 100644 --- a/atom/browser/api/atom_api_browser_window.cc +++ b/atom/browser/api/atom_api_browser_window.cc @@ -9,6 +9,7 @@ #include "atom/browser/web_contents_preferences.h" #include "atom/browser/window_list.h" #include "atom/common/api/api_messages.h" +#include "atom/common/api/constructor.h" #include "atom/common/color_util.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/value_converter.h" @@ -428,17 +429,9 @@ void Initialize(v8::Local exports, v8::Local context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); - // Calling SetConstructor would only use TopLevelWindow's prototype. - v8::Local templ = CreateFunctionTemplate( - isolate, - base::Bind( - &mate::internal::InvokeNew, - base::Bind(&BrowserWindow::New))); - templ->InstanceTemplate()->SetInternalFieldCount(1); - BrowserWindow::BuildPrototype(isolate, templ); - mate::Dictionary dict(isolate, exports); - dict.Set("BrowserWindow", templ->GetFunction()); + dict.Set("BrowserWindow", mate::CreateConstructor( + isolate, base::Bind(&BrowserWindow::New))); } } // namespace diff --git a/atom/browser/api/atom_api_layout_manager.cc b/atom/browser/api/atom_api_layout_manager.cc new file mode 100644 index 0000000000..49c8cea5e7 --- /dev/null +++ b/atom/browser/api/atom_api_layout_manager.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2018 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/api/atom_api_layout_manager.h" + +#include "atom/common/api/constructor.h" +#include "native_mate/dictionary.h" + +#include "atom/common/node_includes.h" + +namespace atom { + +namespace api { + +LayoutManager::LayoutManager(views::LayoutManager* layout_manager) + : layout_manager_(layout_manager) { + DCHECK(layout_manager_); +} + +LayoutManager::~LayoutManager() { + if (managed_by_us_) + delete layout_manager_; +} + +std::unique_ptr LayoutManager::TakeOver() { + if (!managed_by_us_) // already taken over. + return nullptr; + managed_by_us_ = false; + return std::unique_ptr(layout_manager_); +} + +// static +mate::WrappableBase* LayoutManager::New(mate::Arguments* args) { + args->ThrowError("LayoutManager can not be created directly"); + return nullptr; +} + +// static +void LayoutManager::BuildPrototype(v8::Isolate* isolate, + v8::Local prototype) {} + +} // namespace api + +} // namespace atom + +namespace { + +using atom::api::LayoutManager; + +void Initialize(v8::Local exports, + v8::Local unused, + v8::Local context, + void* priv) { + v8::Isolate* isolate = context->GetIsolate(); + mate::Dictionary dict(isolate, exports); + dict.Set("LayoutManager", mate::CreateConstructor( + isolate, base::Bind(&LayoutManager::New))); +} + +} // namespace + +NODE_BUILTIN_MODULE_CONTEXT_AWARE(atom_browser_layout_manager, Initialize) diff --git a/atom/browser/api/atom_api_layout_manager.h b/atom/browser/api/atom_api_layout_manager.h new file mode 100644 index 0000000000..4e893b746b --- /dev/null +++ b/atom/browser/api/atom_api_layout_manager.h @@ -0,0 +1,44 @@ +// Copyright (c) 2018 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_API_ATOM_API_LAYOUT_MANAGER_H_ +#define ATOM_BROWSER_API_ATOM_API_LAYOUT_MANAGER_H_ + +#include + +#include "atom/browser/api/trackable_object.h" +#include "ui/views/layout/layout_manager.h" + +namespace atom { + +namespace api { + +class LayoutManager : public mate::TrackableObject { + public: + static mate::WrappableBase* New(mate::Arguments* args); + + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + + // Take over the ownership of the LayoutManager, and leave weak ref here. + std::unique_ptr TakeOver(); + + views::LayoutManager* layout_manager() const { return layout_manager_; } + + protected: + explicit LayoutManager(views::LayoutManager* layout_manager); + ~LayoutManager() override; + + private: + bool managed_by_us_ = true; + views::LayoutManager* layout_manager_; + + DISALLOW_COPY_AND_ASSIGN(LayoutManager); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_LAYOUT_MANAGER_H_ diff --git a/atom/browser/api/atom_api_view.cc b/atom/browser/api/atom_api_view.cc index 07db4bfca1..650ad18cde 100644 --- a/atom/browser/api/atom_api_view.cc +++ b/atom/browser/api/atom_api_view.cc @@ -23,6 +23,13 @@ View::~View() { delete view_; } +void View::SetLayoutManager(mate::Handle layout_manager) { + layout_manager_.Reset(isolate(), layout_manager->GetWrapper()); + // TODO(zcbenz): New versions of Chrome takes std::unique_ptr instead of raw + // pointer, remove the "release()" call when we upgraded to it. + view()->SetLayoutManager(layout_manager->TakeOver().release()); +} + // static mate::WrappableBase* View::New(mate::Arguments* args) { auto* view = new View(); @@ -32,7 +39,11 @@ mate::WrappableBase* View::New(mate::Arguments* args) { // static void View::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) {} + v8::Local prototype) { + prototype->SetClassName(mate::StringToV8(isolate, "View")); + mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) + .SetMethod("setLayoutManager", &View::SetLayoutManager); +} } // namespace api diff --git a/atom/browser/api/atom_api_view.h b/atom/browser/api/atom_api_view.h index 4e851ef289..37f7ae4e1c 100644 --- a/atom/browser/api/atom_api_view.h +++ b/atom/browser/api/atom_api_view.h @@ -7,7 +7,8 @@ #include -#include "atom/browser/api/trackable_object.h" +#include "atom/browser/api/atom_api_layout_manager.h" +#include "native_mate/handle.h" #include "ui/views/view.h" namespace atom { @@ -21,6 +22,8 @@ class View : public mate::TrackableObject { static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); + void SetLayoutManager(mate::Handle layout_manager); + views::View* view() const { return view_; } protected: @@ -32,6 +35,8 @@ class View : public mate::TrackableObject { void set_delete_view(bool should) { delete_view_ = should; } private: + v8::Global layout_manager_; + bool delete_view_ = true; views::View* view_ = nullptr; diff --git a/atom/browser/api/atom_api_web_contents_view.cc b/atom/browser/api/atom_api_web_contents_view.cc index de27f8eeed..60d04ff936 100644 --- a/atom/browser/api/atom_api_web_contents_view.cc +++ b/atom/browser/api/atom_api_web_contents_view.cc @@ -5,6 +5,7 @@ #include "atom/browser/api/atom_api_web_contents_view.h" #include "atom/browser/api/atom_api_web_contents.h" +#include "atom/common/api/constructor.h" #include "brightray/browser/inspectable_web_contents_view.h" #include "content/public/browser/web_contents_user_data.h" #include "native_mate/dictionary.h" @@ -117,13 +118,9 @@ void Initialize(v8::Local exports, v8::Local context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); - WebContentsView::SetConstructor(isolate, base::Bind(&WebContentsView::New)); - - mate::Dictionary constructor( - isolate, WebContentsView::GetConstructor(isolate)->GetFunction()); - mate::Dictionary dict(isolate, exports); - dict.Set("WebContentsView", constructor); + dict.Set("WebContentsView", mate::CreateConstructor( + isolate, base::Bind(&WebContentsView::New))); } } // namespace diff --git a/atom/common/api/constructor.h b/atom/common/api/constructor.h new file mode 100644 index 0000000000..a4e4332f0a --- /dev/null +++ b/atom/common/api/constructor.h @@ -0,0 +1,33 @@ +// Copyright (c) 2018 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_COMMON_API_CONSTRUCTOR_H_ +#define ATOM_COMMON_API_CONSTRUCTOR_H_ + +#include "native_mate/constructor.h" + +namespace mate { + +// Create a FunctionTemplate that can be "new"ed in JavaScript. +// It is user's responsibility to ensure this function is called for one type +// only ONCE in the program's whole lifetime, otherwise we would have memory +// leak. +template +v8::Local CreateConstructor(v8::Isolate* isolate, + const base::Callback& func) { +#ifndef NDEBUG + static bool called = false; + CHECK(!called) << "CreateConstructor can only be called for one type once"; + called = true; +#endif + v8::Local templ = CreateFunctionTemplate( + isolate, base::Bind(&mate::internal::InvokeNew, func)); + templ->InstanceTemplate()->SetInternalFieldCount(1); + T::BuildPrototype(isolate, templ); + return templ->GetFunction(); +} + +} // namespace mate + +#endif // ATOM_COMMON_API_CONSTRUCTOR_H_ diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index d50327934c..8af9114de8 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -31,6 +31,7 @@ V(atom_browser_app) \ V(atom_browser_auto_updater) \ V(atom_browser_browser_view) \ + V(atom_browser_box_layout) \ V(atom_browser_content_tracing) \ V(atom_browser_debugger) \ V(atom_browser_desktop_capturer) \ @@ -38,6 +39,7 @@ V(atom_browser_download_item) \ V(atom_browser_global_shortcut) \ V(atom_browser_in_app_purchase) \ + V(atom_browser_layout_manager) \ V(atom_browser_menu) \ V(atom_browser_net) \ V(atom_browser_power_monitor) \ diff --git a/filenames.gypi b/filenames.gypi index ec0c59f0a0..9da6d9cdff 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -13,6 +13,7 @@ 'lib/browser/api/auto-updater/auto-updater-native.js', 'lib/browser/api/auto-updater/auto-updater-win.js', 'lib/browser/api/auto-updater/squirrel-update-win.js', + 'lib/browser/api/box-layout.js', 'lib/browser/api/browser-view.js', 'lib/browser/api/browser-window.js', 'lib/browser/api/content-tracing.js', @@ -21,6 +22,7 @@ 'lib/browser/api/global-shortcut.js', 'lib/browser/api/ipc-main.js', 'lib/browser/api/in-app-purchase.js', + 'lib/browser/api/layout-manager.js', 'lib/browser/api/menu-item-roles.js', 'lib/browser/api/menu-item.js', 'lib/browser/api/menu-utils.js', @@ -113,6 +115,8 @@ 'atom/browser/api/atom_api_app.h', 'atom/browser/api/atom_api_auto_updater.cc', 'atom/browser/api/atom_api_auto_updater.h', + 'atom/browser/api/atom_api_box_layout.cc', + 'atom/browser/api/atom_api_box_layout.h', 'atom/browser/api/atom_api_browser_view.cc', 'atom/browser/api/atom_api_browser_view.h', 'atom/browser/api/atom_api_content_tracing.cc', @@ -129,6 +133,8 @@ 'atom/browser/api/atom_api_global_shortcut.h', 'atom/browser/api/atom_api_in_app_purchase.cc', 'atom/browser/api/atom_api_in_app_purchase.h', + 'atom/browser/api/atom_api_layout_manager.cc', + 'atom/browser/api/atom_api_layout_manager.h', 'atom/browser/api/atom_api_menu.cc', 'atom/browser/api/atom_api_menu.h', 'atom/browser/api/atom_api_menu_mac.h', @@ -436,6 +442,7 @@ 'atom/common/api/atom_api_v8_util.cc', 'atom/common/api/atom_bindings.cc', 'atom/common/api/atom_bindings.h', + 'atom/common/api/constructor.h', 'atom/common/api/event_emitter_caller.cc', 'atom/common/api/event_emitter_caller.h', 'atom/common/api/features.cc', diff --git a/lib/browser/api/box-layout.js b/lib/browser/api/box-layout.js new file mode 100644 index 0000000000..4dc77f3194 --- /dev/null +++ b/lib/browser/api/box-layout.js @@ -0,0 +1,15 @@ +'use strict' + +const electron = require('electron') + +const {LayoutManager} = electron +const {BoxLayout} = process.atomBinding('box_layout') + +Object.setPrototypeOf(BoxLayout.prototype, LayoutManager.prototype) + +BoxLayout.prototype._init = function () { + // Call parent class's _init. + LayoutManager.prototype._init.call(this) +} + +module.exports = BoxLayout diff --git a/lib/browser/api/layout-manager.js b/lib/browser/api/layout-manager.js new file mode 100644 index 0000000000..1a850a5345 --- /dev/null +++ b/lib/browser/api/layout-manager.js @@ -0,0 +1,8 @@ +'use strict' + +const {LayoutManager} = process.atomBinding('layout_manager') + +LayoutManager.prototype._init = function () { +} + +module.exports = LayoutManager diff --git a/lib/browser/api/module-list.js b/lib/browser/api/module-list.js index 5b218838ac..663da97c3e 100644 --- a/lib/browser/api/module-list.js +++ b/lib/browser/api/module-list.js @@ -2,6 +2,7 @@ module.exports = [ {name: 'app', file: 'app'}, {name: 'autoUpdater', file: 'auto-updater'}, + {name: 'BoxLayout', file: 'box-layout'}, {name: 'BrowserView', file: 'browser-view'}, {name: 'BrowserWindow', file: 'browser-window'}, {name: 'contentTracing', file: 'content-tracing'}, @@ -9,6 +10,7 @@ module.exports = [ {name: 'globalShortcut', file: 'global-shortcut'}, {name: 'ipcMain', file: 'ipc-main'}, {name: 'inAppPurchase', file: 'in-app-purchase'}, + {name: 'LayoutManager', file: 'layout-manager'}, {name: 'Menu', file: 'menu'}, {name: 'MenuItem', file: 'menu-item'}, {name: 'net', file: 'net'},