Add LayoutManager/BoxLayout APIs

This commit is contained in:
Cheng Zhao 2018-05-22 17:08:27 +09:00
parent b3edfd7d89
commit 322bde526c
14 changed files with 310 additions and 18 deletions

View file

@ -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)

View file

@ -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_

View file

@ -9,6 +9,7 @@
#include "atom/browser/web_contents_preferences.h" #include "atom/browser/web_contents_preferences.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
#include "atom/common/api/api_messages.h" #include "atom/common/api/api_messages.h"
#include "atom/common/api/constructor.h"
#include "atom/common/color_util.h" #include "atom/common/color_util.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/value_converter.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, v8::Local<v8::Context> context,
void* priv) { void* priv) {
v8::Isolate* isolate = context->GetIsolate(); 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); mate::Dictionary dict(isolate, exports);
dict.Set("BrowserWindow", templ->GetFunction()); dict.Set("BrowserWindow", mate::CreateConstructor<BrowserWindow>(
isolate, base::Bind(&BrowserWindow::New)));
} }
} // namespace } // namespace

View file

@ -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)

View file

@ -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_

View file

@ -23,6 +23,13 @@ View::~View() {
delete 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 // static
mate::WrappableBase* View::New(mate::Arguments* args) { mate::WrappableBase* View::New(mate::Arguments* args) {
auto* view = new View(); auto* view = new View();
@ -32,7 +39,11 @@ mate::WrappableBase* View::New(mate::Arguments* args) {
// static // static
void View::BuildPrototype(v8::Isolate* isolate, 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 } // namespace api

View file

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

View file

@ -5,6 +5,7 @@
#include "atom/browser/api/atom_api_web_contents_view.h" #include "atom/browser/api/atom_api_web_contents_view.h"
#include "atom/browser/api/atom_api_web_contents.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 "brightray/browser/inspectable_web_contents_view.h"
#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_user_data.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
@ -117,13 +118,9 @@ void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Context> context, v8::Local<v8::Context> context,
void* priv) { void* priv) {
v8::Isolate* isolate = context->GetIsolate(); 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); mate::Dictionary dict(isolate, exports);
dict.Set("WebContentsView", constructor); dict.Set("WebContentsView", mate::CreateConstructor<WebContentsView>(
isolate, base::Bind(&WebContentsView::New)));
} }
} // namespace } // namespace

View file

@ -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_

View file

@ -31,6 +31,7 @@
V(atom_browser_app) \ V(atom_browser_app) \
V(atom_browser_auto_updater) \ V(atom_browser_auto_updater) \
V(atom_browser_browser_view) \ V(atom_browser_browser_view) \
V(atom_browser_box_layout) \
V(atom_browser_content_tracing) \ V(atom_browser_content_tracing) \
V(atom_browser_debugger) \ V(atom_browser_debugger) \
V(atom_browser_desktop_capturer) \ V(atom_browser_desktop_capturer) \
@ -38,6 +39,7 @@
V(atom_browser_download_item) \ V(atom_browser_download_item) \
V(atom_browser_global_shortcut) \ V(atom_browser_global_shortcut) \
V(atom_browser_in_app_purchase) \ V(atom_browser_in_app_purchase) \
V(atom_browser_layout_manager) \
V(atom_browser_menu) \ V(atom_browser_menu) \
V(atom_browser_net) \ V(atom_browser_net) \
V(atom_browser_power_monitor) \ V(atom_browser_power_monitor) \

View file

@ -13,6 +13,7 @@
'lib/browser/api/auto-updater/auto-updater-native.js', 'lib/browser/api/auto-updater/auto-updater-native.js',
'lib/browser/api/auto-updater/auto-updater-win.js', 'lib/browser/api/auto-updater/auto-updater-win.js',
'lib/browser/api/auto-updater/squirrel-update-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-view.js',
'lib/browser/api/browser-window.js', 'lib/browser/api/browser-window.js',
'lib/browser/api/content-tracing.js', 'lib/browser/api/content-tracing.js',
@ -21,6 +22,7 @@
'lib/browser/api/global-shortcut.js', 'lib/browser/api/global-shortcut.js',
'lib/browser/api/ipc-main.js', 'lib/browser/api/ipc-main.js',
'lib/browser/api/in-app-purchase.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-roles.js',
'lib/browser/api/menu-item.js', 'lib/browser/api/menu-item.js',
'lib/browser/api/menu-utils.js', 'lib/browser/api/menu-utils.js',
@ -113,6 +115,8 @@
'atom/browser/api/atom_api_app.h', 'atom/browser/api/atom_api_app.h',
'atom/browser/api/atom_api_auto_updater.cc', 'atom/browser/api/atom_api_auto_updater.cc',
'atom/browser/api/atom_api_auto_updater.h', '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.cc',
'atom/browser/api/atom_api_browser_view.h', 'atom/browser/api/atom_api_browser_view.h',
'atom/browser/api/atom_api_content_tracing.cc', '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_global_shortcut.h',
'atom/browser/api/atom_api_in_app_purchase.cc', 'atom/browser/api/atom_api_in_app_purchase.cc',
'atom/browser/api/atom_api_in_app_purchase.h', '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.cc',
'atom/browser/api/atom_api_menu.h', 'atom/browser/api/atom_api_menu.h',
'atom/browser/api/atom_api_menu_mac.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_api_v8_util.cc',
'atom/common/api/atom_bindings.cc', 'atom/common/api/atom_bindings.cc',
'atom/common/api/atom_bindings.h', 'atom/common/api/atom_bindings.h',
'atom/common/api/constructor.h',
'atom/common/api/event_emitter_caller.cc', 'atom/common/api/event_emitter_caller.cc',
'atom/common/api/event_emitter_caller.h', 'atom/common/api/event_emitter_caller.h',
'atom/common/api/features.cc', 'atom/common/api/features.cc',

View file

@ -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

View file

@ -0,0 +1,8 @@
'use strict'
const {LayoutManager} = process.atomBinding('layout_manager')
LayoutManager.prototype._init = function () {
}
module.exports = LayoutManager

View file

@ -2,6 +2,7 @@
module.exports = [ module.exports = [
{name: 'app', file: 'app'}, {name: 'app', file: 'app'},
{name: 'autoUpdater', file: 'auto-updater'}, {name: 'autoUpdater', file: 'auto-updater'},
{name: 'BoxLayout', file: 'box-layout'},
{name: 'BrowserView', file: 'browser-view'}, {name: 'BrowserView', file: 'browser-view'},
{name: 'BrowserWindow', file: 'browser-window'}, {name: 'BrowserWindow', file: 'browser-window'},
{name: 'contentTracing', file: 'content-tracing'}, {name: 'contentTracing', file: 'content-tracing'},
@ -9,6 +10,7 @@ module.exports = [
{name: 'globalShortcut', file: 'global-shortcut'}, {name: 'globalShortcut', file: 'global-shortcut'},
{name: 'ipcMain', file: 'ipc-main'}, {name: 'ipcMain', file: 'ipc-main'},
{name: 'inAppPurchase', file: 'in-app-purchase'}, {name: 'inAppPurchase', file: 'in-app-purchase'},
{name: 'LayoutManager', file: 'layout-manager'},
{name: 'Menu', file: 'menu'}, {name: 'Menu', file: 'menu'},
{name: 'MenuItem', file: 'menu-item'}, {name: 'MenuItem', file: 'menu-item'},
{name: 'net', file: 'net'}, {name: 'net', file: 'net'},