diff --git a/atom/browser/api/atom_api_browser_view.cc b/atom/browser/api/atom_api_browser_view.cc new file mode 100644 index 00000000000..67533e645d3 --- /dev/null +++ b/atom/browser/api/atom_api_browser_view.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2017 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_browser_view.h" + +#include "atom/browser/api/atom_api_web_contents.h" +#include "atom/browser/browser.h" +#include "atom/browser/native_browser_view.h" +#include "atom/common/color_util.h" +#include "atom/common/native_mate_converters/gfx_converter.h" +#include "atom/common/native_mate_converters/value_converter.h" +#include "atom/common/node_includes.h" +#include "atom/common/options_switches.h" +#include "native_mate/constructor.h" +#include "native_mate/dictionary.h" +#include "ui/gfx/geometry/rect.h" + +namespace atom { + +namespace api { + +BrowserView::BrowserView(v8::Isolate* isolate, + v8::Local wrapper, + const mate::Dictionary& options) + : api_web_contents_(nullptr) { + Init(isolate, wrapper, options); +} + +void BrowserView::Init(v8::Isolate* isolate, + v8::Local wrapper, + const mate::Dictionary& options) { + mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate); + options.Get(options::kWebPreferences, &web_preferences); + web_preferences.Set("isBrowserView", true); + mate::Handle web_contents = + WebContents::Create(isolate, web_preferences); + + web_contents_.Reset(isolate, web_contents.ToV8()); + api_web_contents_ = web_contents.get(); + + view_.reset(NativeBrowserView::Create( + api_web_contents_->managed_web_contents()->GetView())); + + InitWith(isolate, wrapper); +} + +BrowserView::~BrowserView() { + api_web_contents_->DestroyWebContents(); +} + +// static +mate::WrappableBase* BrowserView::New(mate::Arguments* args) { + if (!Browser::Get()->is_ready()) { + args->ThrowError("Cannot create BrowserView before app is ready"); + return nullptr; + } + + if (args->Length() > 1) { + args->ThrowError("Too many arguments"); + return nullptr; + } + + mate::Dictionary options; + if (!(args->Length() == 1 && args->GetNext(&options))) { + options = mate::Dictionary::CreateEmpty(args->isolate()); + } + + return new BrowserView(args->isolate(), args->GetThis(), options); +} + +int32_t BrowserView::ID() const { + return weak_map_id(); +} + +void BrowserView::SetBounds(const gfx::Rect& bounds) { + view_->SetBounds(bounds); +} + +void BrowserView::SetBackgroundColor(const std::string& color_name) { + view_->SetBackgroundColor(ParseHexColor(color_name)); +} + +v8::Local BrowserView::WebContents() { + if (web_contents_.IsEmpty()) { + return v8::Null(isolate()); + } + + return v8::Local::New(isolate(), web_contents_); +} + +// static +void BrowserView::BuildPrototype(v8::Isolate* isolate, + v8::Local prototype) { + prototype->SetClassName(mate::StringToV8(isolate, "BrowserView")); + mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) + .MakeDestroyable() + .SetMethod("setBounds", &BrowserView::SetBounds) + .SetMethod("setBackgroundColor", &BrowserView::SetBackgroundColor) + .SetProperty("webContents", &BrowserView::WebContents) + .SetProperty("id", &BrowserView::ID); +} + +} // namespace api + +} // namespace atom + +namespace { + +using atom::api::BrowserView; + +void Initialize(v8::Local exports, + v8::Local unused, + v8::Local context, + void* priv) { + v8::Isolate* isolate = context->GetIsolate(); + BrowserView::SetConstructor(isolate, base::Bind(&BrowserView::New)); + + mate::Dictionary browser_view( + isolate, BrowserView::GetConstructor(isolate)->GetFunction()); + + mate::Dictionary dict(isolate, exports); + dict.Set("BrowserView", browser_view); +} + +} // namespace + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_browser_view, Initialize) diff --git a/atom/browser/api/atom_api_browser_view.h b/atom/browser/api/atom_api_browser_view.h new file mode 100644 index 00000000000..875d8428982 --- /dev/null +++ b/atom/browser/api/atom_api_browser_view.h @@ -0,0 +1,70 @@ +// Copyright (c) 2017 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_BROWSER_VIEW_H_ +#define ATOM_BROWSER_API_ATOM_API_BROWSER_VIEW_H_ + +#include +#include + +#include "atom/browser/api/trackable_object.h" +#include "native_mate/handle.h" + +namespace gfx { +class Rect; +} + +namespace mate { +class Arguments; +class Dictionary; +} // namespace mate + +namespace atom { + +class NativeBrowserView; + +namespace api { + +class WebContents; + +class BrowserView : public mate::TrackableObject { + public: + static mate::WrappableBase* New(mate::Arguments* args); + + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + + NativeBrowserView* view() const { return view_.get(); } + + int32_t ID() const; + + protected: + BrowserView(v8::Isolate* isolate, + v8::Local wrapper, + const mate::Dictionary& options); + ~BrowserView() override; + + private: + void Init(v8::Isolate* isolate, + v8::Local wrapper, + const mate::Dictionary& options); + + void SetBounds(const gfx::Rect& bounds); + void SetBackgroundColor(const std::string& color_name); + + v8::Local WebContents(); + + v8::Global web_contents_; + class WebContents* api_web_contents_; + + std::unique_ptr view_; + + DISALLOW_COPY_AND_ASSIGN(BrowserView); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_BROWSER_VIEW_H_ diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 9390777f9c5..d3e7bae2e41 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -188,6 +188,7 @@ struct Converter { switch (val) { case Type::BACKGROUND_PAGE: type = "backgroundPage"; break; case Type::BROWSER_WINDOW: type = "window"; break; + case Type::BROWSER_VIEW: type = "browserView"; break; case Type::REMOTE: type = "remote"; break; case Type::WEB_VIEW: type = "webview"; break; case Type::OFF_SCREEN: type = "offscreen"; break; @@ -202,10 +203,12 @@ struct Converter { std::string type; if (!ConvertFromV8(isolate, val, &type)) return false; - if (type == "webview") { - *out = Type::WEB_VIEW; - } else if (type == "backgroundPage") { + if (type == "backgroundPage") { *out = Type::BACKGROUND_PAGE; + } else if (type == "browserView") { + *out = Type::BROWSER_VIEW; + } else if (type == "webview") { + *out = Type::WEB_VIEW; } else if (type == "offscreen") { *out = Type::OFF_SCREEN; } else { @@ -306,6 +309,8 @@ WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options) type_ = WEB_VIEW; else if (options.Get("isBackgroundPage", &b) && b) type_ = BACKGROUND_PAGE; + else if (options.Get("isBrowserView", &b) && b) + type_ = BROWSER_VIEW; else if (options.Get("offscreen", &b) && b) type_ = OFF_SCREEN; diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index c289503b43c..1301ed15f7f 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -53,10 +53,11 @@ class WebContents : public mate::TrackableObject, public: enum Type { BACKGROUND_PAGE, // A DevTools extension background page. - BROWSER_WINDOW, // Used by BrowserWindow. - REMOTE, // Thin wrap around an existing WebContents. - WEB_VIEW, // Used by . - OFF_SCREEN, // Used for offscreen rendering + BROWSER_WINDOW, // Used by BrowserWindow. + BROWSER_VIEW, // Used by BrowserView. + REMOTE, // Thin wrap around an existing WebContents. + WEB_VIEW, // Used by . + OFF_SCREEN, // Used for offscreen rendering }; // For node.js callback function type: function(error, buffer) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 9a4ae5850dc..c6707624913 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -5,6 +5,7 @@ #include "atom/browser/api/atom_api_window.h" #include "atom/common/native_mate_converters/value_converter.h" +#include "atom/browser/api/atom_api_browser_view.h" #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/browser.h" @@ -816,6 +817,25 @@ std::vector> Window::GetChildWindows() const { return child_windows_.Values(isolate()); } +v8::Local Window::GetBrowserView() const { + if (browser_view_.IsEmpty()) { + return v8::Null(isolate()); + } + + return v8::Local::New(isolate(), browser_view_); +} + +void Window::SetBrowserView(v8::Local value) { + mate::Handle browser_view; + if (value->IsNull()) { + window_->SetBrowserView(nullptr); + browser_view_.Reset(); + } else if (mate::ConvertFromV8(isolate(), value, &browser_view)) { + window_->SetBrowserView(browser_view->view()); + browser_view_.Reset(isolate(), value); + } +} + bool Window::IsModal() const { return window_->is_modal(); } @@ -862,10 +882,11 @@ int32_t Window::ID() const { } v8::Local Window::WebContents(v8::Isolate* isolate) { - if (web_contents_.IsEmpty()) + if (web_contents_.IsEmpty()) { return v8::Null(isolate); - else - return v8::Local::New(isolate, web_contents_); + } + + return v8::Local::New(isolate, web_contents_); } void Window::RemoveFromParentChildWindows() { @@ -910,6 +931,8 @@ void Window::BuildPrototype(v8::Isolate* isolate, #endif .SetMethod("getParentWindow", &Window::GetParentWindow) .SetMethod("getChildWindows", &Window::GetChildWindows) + .SetMethod("getBrowserView", &Window::GetBrowserView) + .SetMethod("setBrowserView", &Window::SetBrowserView) .SetMethod("isModal", &Window::IsModal) .SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle) .SetMethod("getBounds", &Window::GetBounds) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 24afec354df..d464af58ea9 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -180,6 +180,8 @@ class Window : public mate::TrackableObject, void SetParentWindow(v8::Local value, mate::Arguments* args); v8::Local GetParentWindow() const; std::vector> GetChildWindows() const; + v8::Local GetBrowserView() const; + void SetBrowserView(v8::Local value); bool IsModal() const; v8::Local GetNativeWindowHandle(); @@ -220,6 +222,7 @@ class Window : public mate::TrackableObject, MessageCallbackMap messages_callback_map_; #endif + v8::Global browser_view_; v8::Global web_contents_; v8::Global menu_; v8::Global parent_window_; diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index f7f9e46250e..a10f959dce9 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -178,9 +178,14 @@ void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) { void CommonWebContentsDelegate::SetOwnerWindow( content::WebContents* web_contents, NativeWindow* owner_window) { - owner_window_ = owner_window->GetWeakPtr(); + owner_window_ = owner_window ? owner_window->GetWeakPtr() : nullptr; NativeWindowRelay* relay = new NativeWindowRelay(owner_window_); - web_contents->SetUserData(relay->key, relay); + if (owner_window) { + web_contents->SetUserData(relay->key, relay); + } else { + web_contents->RemoveUserData(relay->key); + delete relay; + } } void CommonWebContentsDelegate::ResetManagedWebContents() { diff --git a/atom/browser/native_browser_view.cc b/atom/browser/native_browser_view.cc new file mode 100644 index 00000000000..949e5e9ec96 --- /dev/null +++ b/atom/browser/native_browser_view.cc @@ -0,0 +1,18 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/native_browser_view.h" + +#include "atom/browser/api/atom_api_web_contents.h" +#include "brightray/browser/inspectable_web_contents_view.h" + +namespace atom { + +NativeBrowserView::NativeBrowserView( + brightray::InspectableWebContentsView* web_contents_view) + : web_contents_view_(web_contents_view) {} + +NativeBrowserView::~NativeBrowserView() {} + +} // namespace atom diff --git a/atom/browser/native_browser_view.h b/atom/browser/native_browser_view.h new file mode 100644 index 00000000000..f9af80f65ed --- /dev/null +++ b/atom/browser/native_browser_view.h @@ -0,0 +1,51 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_ +#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_ + +#include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace brightray { +class InspectableWebContentsView; +} + +namespace gfx { +class Rect; +} + +namespace atom { + +namespace api { +class WebContents; +} + +class NativeBrowserView { + public: + virtual ~NativeBrowserView(); + + static NativeBrowserView* Create( + brightray::InspectableWebContentsView* web_contents_view); + + brightray::InspectableWebContentsView* GetInspectableWebContentsView() { + return web_contents_view_; + } + + virtual void SetBounds(const gfx::Rect& bounds) = 0; + virtual void SetBackgroundColor(SkColor color) = 0; + + protected: + explicit NativeBrowserView( + brightray::InspectableWebContentsView* web_contents_view); + + brightray::InspectableWebContentsView* web_contents_view_; + + private: + DISALLOW_COPY_AND_ASSIGN(NativeBrowserView); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_ diff --git a/atom/browser/native_browser_view_mac.h b/atom/browser/native_browser_view_mac.h new file mode 100644 index 00000000000..3053a098fca --- /dev/null +++ b/atom/browser/native_browser_view_mac.h @@ -0,0 +1,29 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_ +#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_ + +#import + +#include "atom/browser/native_browser_view.h" + +namespace atom { + +class NativeBrowserViewMac : public NativeBrowserView { + public: + explicit NativeBrowserViewMac( + brightray::InspectableWebContentsView* web_contents_view); + ~NativeBrowserViewMac() override; + + void SetBounds(const gfx::Rect& bounds) override; + void SetBackgroundColor(SkColor color) override; + + private: + DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewMac); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_ diff --git a/atom/browser/native_browser_view_mac.mm b/atom/browser/native_browser_view_mac.mm new file mode 100644 index 00000000000..73a36cd347e --- /dev/null +++ b/atom/browser/native_browser_view_mac.mm @@ -0,0 +1,40 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/native_browser_view_mac.h" + +#include "brightray/browser/inspectable_web_contents_view.h" +#include "skia/ext/skia_utils_mac.h" +#include "ui/gfx/geometry/rect.h" + +namespace atom { + +NativeBrowserViewMac::NativeBrowserViewMac( + brightray::InspectableWebContentsView* web_contents_view) + : NativeBrowserView(web_contents_view) {} + +NativeBrowserViewMac::~NativeBrowserViewMac() {} + +void NativeBrowserViewMac::SetBounds(const gfx::Rect& bounds) { + auto* view = GetInspectableWebContentsView()->GetNativeView(); + auto* superview = view.superview; + const auto superview_height = superview ? superview.frame.size.height : 0; + view.frame = + NSMakeRect(bounds.x(), superview_height - bounds.y() - bounds.height(), + bounds.width(), bounds.height()); +} + +void NativeBrowserViewMac::SetBackgroundColor(SkColor color) { + auto* view = GetInspectableWebContentsView()->GetNativeView(); + view.wantsLayer = YES; + view.layer.backgroundColor = skia::CGColorCreateFromSkColor(color); +} + +// static +NativeBrowserView* NativeBrowserView::Create( + brightray::InspectableWebContentsView* web_contents_view) { + return new NativeBrowserViewMac(web_contents_view); +} + +} // namespace atom diff --git a/atom/browser/native_browser_view_views.cc b/atom/browser/native_browser_view_views.cc new file mode 100644 index 00000000000..08a8123bcae --- /dev/null +++ b/atom/browser/native_browser_view_views.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/native_browser_view_views.h" + +#include "brightray/browser/inspectable_web_contents_view.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/background.h" +#include "ui/views/view.h" + +namespace atom { + +NativeBrowserViewViews::NativeBrowserViewViews( + brightray::InspectableWebContentsView* web_contents_view) + : NativeBrowserView(web_contents_view) {} + +NativeBrowserViewViews::~NativeBrowserViewViews() {} + +void NativeBrowserViewViews::SetBounds(const gfx::Rect& bounds) { + auto* view = GetInspectableWebContentsView()->GetView(); + view->SetBoundsRect(bounds); +} + +void NativeBrowserViewViews::SetBackgroundColor(SkColor color) { + auto* view = GetInspectableWebContentsView()->GetView(); + view->set_background(views::Background::CreateSolidBackground(color)); +} + +// static +NativeBrowserView* NativeBrowserView::Create( + brightray::InspectableWebContentsView* web_contents_view) { + return new NativeBrowserViewViews(web_contents_view); +} + +} // namespace atom diff --git a/atom/browser/native_browser_view_views.h b/atom/browser/native_browser_view_views.h new file mode 100644 index 00000000000..ecfc6989df8 --- /dev/null +++ b/atom/browser/native_browser_view_views.h @@ -0,0 +1,27 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_ +#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_ + +#include "atom/browser/native_browser_view.h" + +namespace atom { + +class NativeBrowserViewViews : public NativeBrowserView { + public: + explicit NativeBrowserViewViews( + brightray::InspectableWebContentsView* web_contents_view); + ~NativeBrowserViewViews() override; + + void SetBounds(const gfx::Rect& bounds) override; + void SetBackgroundColor(SkColor color) override; + + private: + DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewViews); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_ diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 227e28c1e46..56702daef63 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -47,6 +47,8 @@ class Dictionary; namespace atom { +class NativeBrowserView; + struct DraggableRegion; class NativeWindow : public base::SupportsUserData, @@ -144,6 +146,7 @@ class NativeWindow : public base::SupportsUserData, virtual void SetFocusable(bool focusable); virtual void SetMenu(AtomMenuModel* menu); virtual void SetParentWindow(NativeWindow* parent); + virtual void SetBrowserView(NativeBrowserView* browser_view) = 0; virtual gfx::NativeWindow GetNativeWindow() = 0; virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index a535cdb4bef..af0f157ecae 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -87,6 +87,7 @@ class NativeWindowMac : public NativeWindow, bool IsDocumentEdited() override; void SetIgnoreMouseEvents(bool ignore) override; void SetContentProtection(bool enable) override; + void SetBrowserView(NativeBrowserView* browser_view) override; void SetParentWindow(NativeWindow* parent) override; gfx::NativeWindow GetNativeWindow() override; gfx::AcceleratedWidget GetAcceleratedWidget() override; @@ -164,6 +165,8 @@ class NativeWindowMac : public NativeWindow, // The view that will fill the whole frameless window. base::scoped_nsobject content_view_; + NativeBrowserView* browser_view_; + std::vector draggable_regions_; bool is_kiosk_; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index c3ca24a3d41..b695f8eafa8 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -7,6 +7,7 @@ #include #include +#include "atom/browser/native_browser_view_mac.h" #include "atom/browser/ui/cocoa/atom_touch_bar.h" #include "atom/browser/window_list.h" #include "atom/common/color_util.h" @@ -19,9 +20,9 @@ #include "brightray/browser/inspectable_web_contents_view.h" #include "brightray/browser/mac/event_dispatching_window.h" #include "content/public/browser/browser_accessibility_state.h" -#include "content/public/browser/web_contents.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" #include "native_mate/dictionary.h" #include "skia/ext/skia_utils_mac.h" #include "third_party/skia/include/core/SkRegion.h" @@ -671,6 +672,7 @@ NativeWindowMac::NativeWindowMac( const mate::Dictionary& options, NativeWindow* parent) : NativeWindow(web_contents, options, parent), + browser_view_(nullptr), is_kiosk_(false), was_fullscreen_(false), zoom_to_page_width_(false), @@ -1269,6 +1271,26 @@ void NativeWindowMac::SetContentProtection(bool enable) { : NSWindowSharingReadOnly]; } +void NativeWindowMac::SetBrowserView(NativeBrowserView* browser_view) { + if (browser_view_) { + [browser_view_->GetInspectableWebContentsView()->GetNativeView() + removeFromSuperview]; + browser_view_ = nullptr; + } + + if (!browser_view) { + return; + } + + browser_view_ = browser_view; + auto* native_view = + browser_view->GetInspectableWebContentsView()->GetNativeView(); + [[window_ contentView] addSubview:native_view + positioned:NSWindowAbove + relativeTo:nil]; + native_view.hidden = NO; +} + void NativeWindowMac::SetParentWindow(NativeWindow* parent) { if (is_modal()) return; diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index b0722cbc4af..68e210a6256 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -7,6 +7,7 @@ #include #include +#include "atom/browser/native_browser_view.h" #include "atom/browser/ui/views/menu_bar.h" #include "atom/browser/ui/views/menu_layout.h" #include "atom/browser/window_list.h" @@ -135,6 +136,7 @@ NativeWindowViews::NativeWindowViews( : NativeWindow(web_contents, options, parent), window_(new views::Widget), web_view_(inspectable_web_contents()->GetView()->GetView()), + browser_view_(nullptr), menu_bar_autohide_(false), menu_bar_visible_(false), menu_bar_alt_pressed_(false), @@ -881,6 +883,20 @@ void NativeWindowViews::SetMenu(AtomMenuModel* menu_model) { Layout(); } +void NativeWindowViews::SetBrowserView(NativeBrowserView* browser_view) { + if (browser_view_) { + RemoveChildView(browser_view_->GetInspectableWebContentsView()->GetView()); + browser_view_ = nullptr; + } + + if (!browser_view) { + return; + } + + browser_view_ = browser_view; + AddChildView(browser_view->GetInspectableWebContentsView()->GetView()); +} + void NativeWindowViews::SetParentWindow(NativeWindow* parent) { NativeWindow::SetParentWindow(parent); diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index a7f02fb2727..cf605a0231b 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -104,6 +104,7 @@ class NativeWindowViews : public NativeWindow, void SetContentProtection(bool enable) override; void SetFocusable(bool focusable) override; void SetMenu(AtomMenuModel* menu_model) override; + void SetBrowserView(NativeBrowserView* browser_view) override; void SetParentWindow(NativeWindow* parent) override; gfx::NativeWindow GetNativeWindow() override; void SetOverlayIcon(const gfx::Image& overlay, @@ -189,6 +190,8 @@ class NativeWindowViews : public NativeWindow, std::unique_ptr window_; views::View* web_view_; // Managed by inspectable_web_contents_. + NativeBrowserView* browser_view_; + std::unique_ptr menu_bar_; bool menu_bar_autohide_; bool menu_bar_visible_; diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index f4696773dad..ae757b1da88 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -33,17 +33,18 @@ // Electron's builtin modules. REFERENCE_MODULE(atom_browser_app); REFERENCE_MODULE(atom_browser_auto_updater); +REFERENCE_MODULE(atom_browser_browser_view); REFERENCE_MODULE(atom_browser_content_tracing); -REFERENCE_MODULE(atom_browser_dialog); REFERENCE_MODULE(atom_browser_debugger); REFERENCE_MODULE(atom_browser_desktop_capturer); +REFERENCE_MODULE(atom_browser_dialog); REFERENCE_MODULE(atom_browser_download_item); +REFERENCE_MODULE(atom_browser_global_shortcut); REFERENCE_MODULE(atom_browser_menu); REFERENCE_MODULE(atom_browser_net); REFERENCE_MODULE(atom_browser_power_monitor); REFERENCE_MODULE(atom_browser_power_save_blocker); REFERENCE_MODULE(atom_browser_protocol); -REFERENCE_MODULE(atom_browser_global_shortcut); REFERENCE_MODULE(atom_browser_render_process_preferences); REFERENCE_MODULE(atom_browser_session); REFERENCE_MODULE(atom_browser_system_preferences); diff --git a/docs/api/browser-view.md b/docs/api/browser-view.md new file mode 100644 index 00000000000..1fa518fdd77 --- /dev/null +++ b/docs/api/browser-view.md @@ -0,0 +1,62 @@ +## Class: BrowserView + +> Create and control views. + +**Note:** The BrowserView API is currently experimental and may change or be +removed in future Electron releases. + +Process: [Main](../glossary.md#main-process) + +A `BrowserView` can be used to embed additional web content into a +`BrowserWindow`. It is like a child window, except that it is positioned +relative to its owning window. It is meant to be an alternative to the +`webview` tag. + +## Example + +```javascript +// In the main process. +const {BrowserView, BrowserWindow} = require('electron') + +let win = new BrowserWindow({width: 800, height: 600}) +win.on('closed', () => { + win = null +}) + +let view = new BrowserView() +win.addChildView(view) +view.setBounds(0, 0, 300, 300) +view.webContents.loadURL('https://electron.atom.io') +``` + +### `new BrowserView([options])` _Experimental_ + +* `options` Object (optional) + * `webPreferences` Object (optional) - See [BrowserWindow](browser-window.md). + +### Instance Properties + +Objects created with `new BrowserView` have the following properties: + +#### `view.webContents` _Experimental_ + +A [`webContents`](web-contents.md) object owned by this view. + +#### `win.id` _Experimental_ + +A `Integer` representing the unique ID of the view. + +### Instance Methods + +Objects created with `new BrowserWindow` have the following instance methods: + +#### `win.setBounds(bounds)` _Experimental_ + +* `bounds` [Rectangle](structures/rectangle.md) + +Resizes and moves the view to the supplied bounds relative to the window. + +#### `win.setBackgroundColor(color)` _Experimental_ + +* `color` String - Color in `#aarrggbb` or `#argb` form. The alpha channel is + optional. diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index ee46a3fa03e..2c720fdfac1 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -1289,6 +1289,13 @@ machine has a touch bar and is running on macOS 10.12.1+. **Note:** The TouchBar API is currently experimental and may change or be removed in future Electron releases. +#### `win.setBrowserView(browserView)` _Experimental_ + +* `browserView` [BrowserView](browser-view.md) + +**Note:** The BrowserView API is currently experimental and may change or be +removed in future Electron releases. + [blink-feature-string]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5?l=62 [quick-look]: https://en.wikipedia.org/wiki/Quick_Look [vibrancy-docs]: https://developer.apple.com/reference/appkit/nsvisualeffectview?language=objc diff --git a/filenames.gypi b/filenames.gypi index ec9c68241c2..f9fa4227ea1 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -13,23 +13,24 @@ '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/browser-view.js', 'lib/browser/api/browser-window.js', 'lib/browser/api/content-tracing.js', 'lib/browser/api/dialog.js', 'lib/browser/api/exports/electron.js', 'lib/browser/api/global-shortcut.js', 'lib/browser/api/ipc-main.js', - 'lib/browser/api/menu.js', - 'lib/browser/api/menu-item.js', 'lib/browser/api/menu-item-roles.js', + 'lib/browser/api/menu-item.js', + 'lib/browser/api/menu.js', 'lib/browser/api/module-list.js', 'lib/browser/api/navigation-controller.js', 'lib/browser/api/net.js', 'lib/browser/api/power-monitor.js', 'lib/browser/api/power-save-blocker.js', 'lib/browser/api/protocol.js', - 'lib/browser/api/session.js', 'lib/browser/api/screen.js', + 'lib/browser/api/session.js', 'lib/browser/api/system-preferences.js', 'lib/browser/api/touch-bar.js', 'lib/browser/api/tray.js', @@ -103,6 +104,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_browser_view.cc', + 'atom/browser/api/atom_api_browser_view.h', 'atom/browser/api/atom_api_content_tracing.cc', 'atom/browser/api/atom_api_cookies.cc', 'atom/browser/api/atom_api_cookies.h', @@ -110,27 +113,27 @@ 'atom/browser/api/atom_api_debugger.h', 'atom/browser/api/atom_api_desktop_capturer.cc', 'atom/browser/api/atom_api_desktop_capturer.h', + 'atom/browser/api/atom_api_dialog.cc', 'atom/browser/api/atom_api_download_item.cc', 'atom/browser/api/atom_api_download_item.h', - 'atom/browser/api/atom_api_dialog.cc', 'atom/browser/api/atom_api_global_shortcut.cc', 'atom/browser/api/atom_api_global_shortcut.h', 'atom/browser/api/atom_api_menu.cc', 'atom/browser/api/atom_api_menu.h', - 'atom/browser/api/atom_api_menu_views.cc', - 'atom/browser/api/atom_api_menu_views.h', 'atom/browser/api/atom_api_menu_mac.h', 'atom/browser/api/atom_api_menu_mac.mm', + 'atom/browser/api/atom_api_menu_views.cc', + 'atom/browser/api/atom_api_menu_views.h', 'atom/browser/api/atom_api_net.cc', 'atom/browser/api/atom_api_net.h', 'atom/browser/api/atom_api_power_monitor.cc', 'atom/browser/api/atom_api_power_monitor.h', 'atom/browser/api/atom_api_power_save_blocker.cc', 'atom/browser/api/atom_api_power_save_blocker.h', - 'atom/browser/api/atom_api_render_process_preferences.cc', - 'atom/browser/api/atom_api_render_process_preferences.h', 'atom/browser/api/atom_api_protocol.cc', 'atom/browser/api/atom_api_protocol.h', + 'atom/browser/api/atom_api_render_process_preferences.cc', + 'atom/browser/api/atom_api_render_process_preferences.h', 'atom/browser/api/atom_api_screen.cc', 'atom/browser/api/atom_api_screen.h', 'atom/browser/api/atom_api_session.cc', @@ -216,6 +219,12 @@ 'atom/browser/mac/atom_application_delegate.mm', 'atom/browser/mac/dict_util.h', 'atom/browser/mac/dict_util.mm', + 'atom/browser/native_browser_view.cc', + 'atom/browser/native_browser_view.h', + 'atom/browser/native_browser_view_mac.h', + 'atom/browser/native_browser_view_mac.mm', + 'atom/browser/native_browser_view_views.h', + 'atom/browser/native_browser_view_views.cc', 'atom/browser/native_window.cc', 'atom/browser/native_window.h', 'atom/browser/native_window_views_win.cc', diff --git a/lib/browser/api/browser-view.js b/lib/browser/api/browser-view.js new file mode 100644 index 00000000000..60023fef92b --- /dev/null +++ b/lib/browser/api/browser-view.js @@ -0,0 +1,8 @@ +'use strict' + +const {EventEmitter} = require('events') +const {BrowserView} = process.atomBinding('browser_view') + +Object.setPrototypeOf(BrowserView.prototype, EventEmitter.prototype) + +module.exports = BrowserView diff --git a/lib/browser/api/module-list.js b/lib/browser/api/module-list.js index 3274f0b6d4f..64b2829064b 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: 'BrowserView', file: 'browser-view'}, {name: 'BrowserWindow', file: 'browser-window'}, {name: 'contentTracing', file: 'content-tracing'}, {name: 'dialog', file: 'dialog'}, diff --git a/spec/api-browser-view-spec.js b/spec/api-browser-view-spec.js new file mode 100644 index 00000000000..d4ab02a4178 --- /dev/null +++ b/spec/api-browser-view-spec.js @@ -0,0 +1,71 @@ +'use strict' + +const assert = require('assert') +const {closeWindow} = require('./window-helpers') + +const {remote} = require('electron') +const {BrowserView, BrowserWindow} = remote + +describe('View module', function () { + var w = null + + beforeEach(function () { + w = new BrowserWindow({ + show: false, + width: 400, + height: 400, + webPreferences: { + backgroundThrottling: false + } + }) + }) + + afterEach(function () { + return closeWindow(w).then(function () { w = null }) + }) + + describe('BrowserView.setBackgroundColor()', function () { + it('does not throw for valid args', function () { + const view = new BrowserView() + view.setBackgroundColor('#000') + }) + + it('throws for invalid args', function () { + const view = new BrowserView() + assert.throws(function () { + view.setBackgroundColor(null) + }, /conversion failure/) + }) + }) + + describe('BrowserView.setBounds()', function () { + it('does not throw for valid args', function () { + const view = new BrowserView() + view.setBounds({ x: 0, y: 0, width: 1, height: 1 }) + }) + + it('throws for invalid args', function () { + const view = new BrowserView() + assert.throws(function () { + view.setBounds(null) + }, /conversion failure/) + assert.throws(function () { + view.setBounds({}) + }, /conversion failure/) + }) + }) + + describe('BrowserWindow.setBrowserView()', function () { + it('does not throw for valid args', function () { + const view = new BrowserView() + w.setBrowserView(view) + }) + + it('does not throw if called multiple times with same view', function () { + const view = new BrowserView() + w.setBrowserView(view) + w.setBrowserView(view) + w.setBrowserView(view) + }) + }) +})