Browse Source

Add LayoutManager/BoxLayout APIs

Cheng Zhao 7 years ago
parent
commit
322bde526c

+ 77 - 0
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 <string>
+
+#include "atom/common/api/constructor.h"
+#include "native_mate/dictionary.h"
+
+#include "atom/common/node_includes.h"
+
+namespace mate {
+
+template <>
+struct Converter<views::BoxLayout::Orientation> {
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Handle<v8::Value> 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<v8::FunctionTemplate> prototype) {}
+
+}  // namespace api
+
+}  // namespace atom
+
+namespace {
+
+using atom::api::BoxLayout;
+
+void Initialize(v8::Local<v8::Object> exports,
+                v8::Local<v8::Value> unused,
+                v8::Local<v8::Context> context,
+                void* priv) {
+  v8::Isolate* isolate = context->GetIsolate();
+  mate::Dictionary dict(isolate, exports);
+  dict.Set("BoxLayout", mate::CreateConstructor<BoxLayout>(
+                            isolate, base::Bind(&BoxLayout::New)));
+}
+
+}  // namespace
+
+NODE_BUILTIN_MODULE_CONTEXT_AWARE(atom_browser_box_layout, Initialize)

+ 35 - 0
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<v8::FunctionTemplate> 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_

+ 3 - 10
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<v8::Object> exports,
                 v8::Local<v8::Context> context,
                 void* priv) {
   v8::Isolate* isolate = context->GetIsolate();
-  // Calling SetConstructor would only use TopLevelWindow's prototype.
-  v8::Local<v8::FunctionTemplate> templ = CreateFunctionTemplate(
-      isolate,
-      base::Bind(
-          &mate::internal::InvokeNew<mate::WrappableBase*(mate::Arguments*)>,
-          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<BrowserWindow>(
+                                isolate, base::Bind(&BrowserWindow::New)));
 }
 
 }  // namespace

+ 63 - 0
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<views::LayoutManager> LayoutManager::TakeOver() {
+  if (!managed_by_us_)  // already taken over.
+    return nullptr;
+  managed_by_us_ = false;
+  return std::unique_ptr<views::LayoutManager>(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<v8::FunctionTemplate> prototype) {}
+
+}  // namespace api
+
+}  // namespace atom
+
+namespace {
+
+using atom::api::LayoutManager;
+
+void Initialize(v8::Local<v8::Object> exports,
+                v8::Local<v8::Value> unused,
+                v8::Local<v8::Context> context,
+                void* priv) {
+  v8::Isolate* isolate = context->GetIsolate();
+  mate::Dictionary dict(isolate, exports);
+  dict.Set("LayoutManager", mate::CreateConstructor<LayoutManager>(
+                                isolate, base::Bind(&LayoutManager::New)));
+}
+
+}  // namespace
+
+NODE_BUILTIN_MODULE_CONTEXT_AWARE(atom_browser_layout_manager, Initialize)

+ 44 - 0
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 <memory>
+
+#include "atom/browser/api/trackable_object.h"
+#include "ui/views/layout/layout_manager.h"
+
+namespace atom {
+
+namespace api {
+
+class LayoutManager : public mate::TrackableObject<LayoutManager> {
+ public:
+  static mate::WrappableBase* New(mate::Arguments* args);
+
+  static void BuildPrototype(v8::Isolate* isolate,
+                             v8::Local<v8::FunctionTemplate> prototype);
+
+  // Take over the ownership of the LayoutManager, and leave weak ref here.
+  std::unique_ptr<views::LayoutManager> 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_

+ 12 - 1
atom/browser/api/atom_api_view.cc

@@ -23,6 +23,13 @@ View::~View() {
     delete view_;
 }
 
+void View::SetLayoutManager(mate::Handle<LayoutManager> 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<v8::FunctionTemplate> prototype) {}
+                          v8::Local<v8::FunctionTemplate> prototype) {
+  prototype->SetClassName(mate::StringToV8(isolate, "View"));
+  mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
+      .SetMethod("setLayoutManager", &View::SetLayoutManager);
+}
 
 }  // namespace api
 

+ 6 - 1
atom/browser/api/atom_api_view.h

@@ -7,7 +7,8 @@
 
 #include <memory>
 
-#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<View> {
   static void BuildPrototype(v8::Isolate* isolate,
                              v8::Local<v8::FunctionTemplate> prototype);
 
+  void SetLayoutManager(mate::Handle<LayoutManager> layout_manager);
+
   views::View* view() const { return view_; }
 
  protected:
@@ -32,6 +35,8 @@ class View : public mate::TrackableObject<View> {
   void set_delete_view(bool should) { delete_view_ = should; }
 
  private:
+  v8::Global<v8::Object> layout_manager_;
+
   bool delete_view_ = true;
   views::View* view_ = nullptr;
 

+ 3 - 6
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<v8::Object> exports,
                 v8::Local<v8::Context> 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<WebContentsView>(
+                                  isolate, base::Bind(&WebContentsView::New)));
 }
 
 }  // namespace

+ 33 - 0
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 <typename T, typename Sig>
+v8::Local<v8::Function> CreateConstructor(v8::Isolate* isolate,
+                                          const base::Callback<Sig>& func) {
+#ifndef NDEBUG
+  static bool called = false;
+  CHECK(!called) << "CreateConstructor can only be called for one type once";
+  called = true;
+#endif
+  v8::Local<v8::FunctionTemplate> templ = CreateFunctionTemplate(
+      isolate, base::Bind(&mate::internal::InvokeNew<Sig>, func));
+  templ->InstanceTemplate()->SetInternalFieldCount(1);
+  T::BuildPrototype(isolate, templ);
+  return templ->GetFunction();
+}
+
+}  // namespace mate
+
+#endif  // ATOM_COMMON_API_CONSTRUCTOR_H_

+ 2 - 0
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)              \

+ 7 - 0
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',

+ 15 - 0
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

+ 8 - 0
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

+ 2 - 0
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'},