Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add multi BrowserView support to BrowserWindow #16148

Merged
24 changes: 23 additions & 1 deletion atom/browser/api/atom_api_browser_window.cc
Expand Up @@ -304,7 +304,29 @@ void BrowserWindow::SetBackgroundColor(const std::string& color_name) {
}

void BrowserWindow::SetBrowserView(v8::Local<v8::Value> value) {
TopLevelWindow::SetBrowserView(value);
TopLevelWindow::ResetBrowserViews();
TopLevelWindow::AddBrowserView(value);
#if defined(OS_MACOSX)
UpdateDraggableRegions(nullptr, draggable_regions_);
#endif
}

void BrowserWindow::AddBrowserView(v8::Local<v8::Value> value) {
TopLevelWindow::AddBrowserView(value);
#if defined(OS_MACOSX)
UpdateDraggableRegions(nullptr, draggable_regions_);
#endif
}

void BrowserWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
TopLevelWindow::RemoveBrowserView(value);
#if defined(OS_MACOSX)
UpdateDraggableRegions(nullptr, draggable_regions_);
#endif
}

void BrowserWindow::ResetBrowserViews() {
TopLevelWindow::ResetBrowserViews();
#if defined(OS_MACOSX)
UpdateDraggableRegions(nullptr, draggable_regions_);
#endif
Expand Down
3 changes: 3 additions & 0 deletions atom/browser/api/atom_api_browser_window.h
Expand Up @@ -72,6 +72,9 @@ class BrowserWindow : public TopLevelWindow,
void Blur() override;
void SetBackgroundColor(const std::string& color_name) override;
void SetBrowserView(v8::Local<v8::Value> value) override;
void AddBrowserView(v8::Local<v8::Value> value) override;
void RemoveBrowserView(v8::Local<v8::Value> value) override;
void ResetBrowserViews() override;
void SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value) override;

// BrowserWindow APIs.
Expand Down
6 changes: 4 additions & 2 deletions atom/browser/api/atom_api_browser_window_mac.mm
Expand Up @@ -108,8 +108,10 @@ - (NSView*)hitTest:(NSPoint)aPoint {
DraggableRegionsToSkRegion(regions), webViewWidth, webViewHeight);
}

if (window_->browser_view())
window_->browser_view()->UpdateDraggableRegions(drag_exclude_rects);
auto browser_views = window_->browser_views();
for (NativeBrowserView* view : browser_views) {
(view)->UpdateDraggableRegions(drag_exclude_rects);
}

// Create and add a ControlRegionView for each region that needs to be
// excluded from the dragging.
Expand Down
82 changes: 63 additions & 19 deletions atom/browser/api/atom_api_top_level_window.cc
Expand Up @@ -159,7 +159,7 @@ void TopLevelWindow::OnWindowClosed() {
Emit("closed");

RemoveFromParentChildWindows();
ResetBrowserView();
TopLevelWindow::ResetBrowserViews();

// Destroy the native class when window is closed.
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, GetDestroyClosure());
Expand Down Expand Up @@ -294,6 +294,7 @@ void TopLevelWindow::OnWindowMessage(UINT message,
#endif

void TopLevelWindow::SetContentView(mate::Handle<View> view) {
ResetBrowserViews();
content_view_.Reset(isolate(), view.ToV8());
window_->SetContentView(view->view());
}
Expand Down Expand Up @@ -681,18 +682,37 @@ void TopLevelWindow::SetParentWindow(v8::Local<v8::Value> value,
}

void TopLevelWindow::SetBrowserView(v8::Local<v8::Value> value) {
ResetBrowserView();
ResetBrowserViews();
AddBrowserView(value);
}

void TopLevelWindow::AddBrowserView(v8::Local<v8::Value> value) {
mate::Handle<BrowserView> browser_view;
if (value->IsNull() || value->IsUndefined()) {
window_->SetBrowserView(nullptr);
} else if (mate::ConvertFromV8(isolate(), value, &browser_view)) {
window_->SetBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(window_.get());
browser_view_.Reset(isolate(), value);
if (value->IsObject() &&
mate::ConvertFromV8(isolate(), value, &browser_view)) {
auto get_that_view = browser_views_.find(browser_view->weak_map_id());
if (get_that_view == browser_views_.end()) {
window_->AddBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(window_.get());
browser_views_[browser_view->weak_map_id()].Reset(isolate(), value);
}
}
}

void TopLevelWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
mate::Handle<BrowserView> browser_view;
if (value->IsObject() &&
mate::ConvertFromV8(isolate(), value, &browser_view)) {
auto get_that_view = browser_views_.find(browser_view->weak_map_id());
if (get_that_view != browser_views_.end()) {
window_->RemoveBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(nullptr);

(*get_that_view).second.Reset(isolate(), value);
browser_views_.erase(get_that_view);
}
}
}
v8::Local<v8::Value> TopLevelWindow::GetNativeWindowHandle() {
// TODO(MarshallOfSound): Replace once
// https://chromium-review.googlesource.com/c/chromium/src/+/1253094/ has
Expand Down Expand Up @@ -847,12 +867,29 @@ std::vector<v8::Local<v8::Object>> TopLevelWindow::GetChildWindows() const {
return child_windows_.Values(isolate());
}

v8::Local<v8::Value> TopLevelWindow::GetBrowserView() const {
if (browser_view_.IsEmpty()) {
v8::Local<v8::Value> TopLevelWindow::GetBrowserView(
mate::Arguments* args) const {
if (browser_views_.size() == 0) {
return v8::Null(isolate());
} else if (browser_views_.size() == 1) {
auto first_view = browser_views_.begin();
return v8::Local<v8::Value>::New(isolate(), (*first_view).second);
} else {
args->ThrowError(
"BrowserWindow have multiple BrowserViews, "
"Use getBrowserViews() instead");
return v8::Null(isolate());
}
}

return v8::Local<v8::Value>::New(isolate(), browser_view_);
std::vector<v8::Local<v8::Value>> TopLevelWindow::GetBrowserViews() const {
std::vector<v8::Local<v8::Value>> ret;

for (auto const& views_iter : browser_views_) {
ret.push_back(v8::Local<v8::Value>::New(isolate(), views_iter.second));
}

return ret;
}

bool TopLevelWindow::IsModal() const {
Expand Down Expand Up @@ -944,17 +981,21 @@ int32_t TopLevelWindow::GetID() const {
return weak_map_id();
}

void TopLevelWindow::ResetBrowserView() {
if (browser_view_.IsEmpty())
return;
void TopLevelWindow::ResetBrowserViews() {
for (auto& item : browser_views_) {
mate::Handle<BrowserView> browser_view;
if (mate::ConvertFromV8(isolate(),
v8::Local<v8::Value>::New(isolate(), item.second),
&browser_view) &&
!browser_view.IsEmpty()) {
window_->RemoveBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(nullptr);
}

mate::Handle<BrowserView> browser_view;
if (mate::ConvertFromV8(isolate(), GetBrowserView(), &browser_view) &&
!browser_view.IsEmpty()) {
browser_view->web_contents()->SetOwnerWindow(nullptr);
item.second.Reset();
}

browser_view_.Reset();
browser_views_.clear();
}

void TopLevelWindow::RemoveFromParentChildWindows() {
Expand Down Expand Up @@ -1064,6 +1105,8 @@ void TopLevelWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setMenu", &TopLevelWindow::SetMenu)
.SetMethod("setParentWindow", &TopLevelWindow::SetParentWindow)
.SetMethod("setBrowserView", &TopLevelWindow::SetBrowserView)
.SetMethod("addBrowserView", &TopLevelWindow::AddBrowserView)
.SetMethod("removeBrowserView", &TopLevelWindow::RemoveBrowserView)
.SetMethod("getNativeWindowHandle",
&TopLevelWindow::GetNativeWindowHandle)
.SetMethod("setProgressBar", &TopLevelWindow::SetProgressBar)
Expand Down Expand Up @@ -1101,6 +1144,7 @@ void TopLevelWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("getParentWindow", &TopLevelWindow::GetParentWindow)
.SetMethod("getChildWindows", &TopLevelWindow::GetChildWindows)
.SetMethod("getBrowserView", &TopLevelWindow::GetBrowserView)
.SetMethod("getBrowserViews", &TopLevelWindow::GetBrowserViews)
.SetMethod("isModal", &TopLevelWindow::IsModal)
.SetMethod("setThumbarButtons", &TopLevelWindow::SetThumbarButtons)
#if defined(TOOLKIT_VIEWS)
Expand Down
8 changes: 6 additions & 2 deletions atom/browser/api/atom_api_top_level_window.h
Expand Up @@ -165,6 +165,10 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
void SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> menu);
void SetParentWindow(v8::Local<v8::Value> value, mate::Arguments* args);
virtual void SetBrowserView(v8::Local<v8::Value> value);
virtual void AddBrowserView(v8::Local<v8::Value> value);
virtual void RemoveBrowserView(v8::Local<v8::Value> value);
virtual std::vector<v8::Local<v8::Value>> GetBrowserViews() const;
virtual void ResetBrowserViews();
v8::Local<v8::Value> GetNativeWindowHandle();
void SetProgressBar(double progress, mate::Arguments* args);
void SetOverlayIcon(const gfx::Image& overlay,
Expand Down Expand Up @@ -195,7 +199,7 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
v8::Local<v8::Value> GetContentView() const;
v8::Local<v8::Value> GetParentWindow() const;
std::vector<v8::Local<v8::Object>> GetChildWindows() const;
v8::Local<v8::Value> GetBrowserView() const;
v8::Local<v8::Value> GetBrowserView(mate::Arguments* args) const;
bool IsModal() const;

// Extra APIs added in JS.
Expand Down Expand Up @@ -238,7 +242,7 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
#endif

v8::Global<v8::Value> content_view_;
v8::Global<v8::Value> browser_view_;
std::map<int32_t, v8::Global<v8::Value>> browser_views_;
v8::Global<v8::Value> menu_;
v8::Global<v8::Value> parent_window_;
KeyWeakMap<int> child_windows_;
Expand Down
18 changes: 13 additions & 5 deletions atom/browser/native_window.h
Expand Up @@ -5,6 +5,7 @@
#ifndef ATOM_BROWSER_NATIVE_WINDOW_H_
#define ATOM_BROWSER_NATIVE_WINDOW_H_

#include <list>
#include <map>
#include <memory>
#include <string>
Expand Down Expand Up @@ -155,7 +156,8 @@ 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 void AddBrowserView(NativeBrowserView* browser_view) = 0;
virtual void RemoveBrowserView(NativeBrowserView* browser_view) = 0;
virtual gfx::NativeView GetNativeView() const = 0;
virtual gfx::NativeWindow GetNativeWindow() const = 0;
virtual gfx::AcceleratedWidget GetAcceleratedWidget() const = 0;
Expand Down Expand Up @@ -286,10 +288,11 @@ class NativeWindow : public base::SupportsUserData,
bool transparent() const { return transparent_; }
bool enable_larger_than_screen() const { return enable_larger_than_screen_; }

NativeBrowserView* browser_view() const { return browser_view_; }
NativeWindow* parent() const { return parent_; }
bool is_modal() const { return is_modal_; }

std::list<NativeBrowserView*> browser_views() const { return browser_views_; }

protected:
NativeWindow(const mate::Dictionary& options, NativeWindow* parent);

Expand All @@ -298,8 +301,13 @@ class NativeWindow : public base::SupportsUserData,
const views::Widget* GetWidget() const override;

void set_content_view(views::View* view) { content_view_ = view; }
void set_browser_view(NativeBrowserView* browser_view) {
browser_view_ = browser_view;

void add_browser_view(NativeBrowserView* browser_view) {
browser_views_.push_back(browser_view);
}
void remove_browser_view(NativeBrowserView* browser_view) {
browser_views_.remove_if(
[&browser_view](NativeBrowserView* n) { return (n == browser_view); });
}

private:
Expand Down Expand Up @@ -340,7 +348,7 @@ class NativeWindow : public base::SupportsUserData,
bool is_modal_ = false;

// The browser view layer.
NativeBrowserView* browser_view_ = nullptr;
std::list<NativeBrowserView*> browser_views_;

// Observers of this window.
base::ObserverList<NativeWindowObserver> observers_;
Expand Down
3 changes: 2 additions & 1 deletion atom/browser/native_window_mac.h
Expand Up @@ -102,7 +102,8 @@ class NativeWindowMac : public NativeWindow {
bool IsDocumentEdited() override;
void SetIgnoreMouseEvents(bool ignore, bool forward) override;
void SetContentProtection(bool enable) override;
void SetBrowserView(NativeBrowserView* browser_view) override;
void AddBrowserView(NativeBrowserView* browser_view) override;
void RemoveBrowserView(NativeBrowserView* browser_view) override;
void SetParentWindow(NativeWindow* parent) override;
gfx::NativeView GetNativeView() const override;
gfx::NativeWindow GetNativeWindow() const override;
Expand Down
25 changes: 17 additions & 8 deletions atom/browser/native_window_mac.mm
Expand Up @@ -1069,22 +1069,16 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
setSharingType:enable ? NSWindowSharingNone : NSWindowSharingReadOnly];
}

void NativeWindowMac::SetBrowserView(NativeBrowserView* view) {
void NativeWindowMac::AddBrowserView(NativeBrowserView* view) {
[CATransaction begin];
[CATransaction setDisableActions:YES];

if (browser_view()) {
[browser_view()->GetInspectableWebContentsView()->GetNativeView()
removeFromSuperview];
set_browser_view(nullptr);
}

if (!view) {
[CATransaction commit];
return;
}

set_browser_view(view);
add_browser_view(view);
auto* native_view = view->GetInspectableWebContentsView()->GetNativeView();
[[window_ contentView] addSubview:native_view
positioned:NSWindowAbove
Expand All @@ -1094,6 +1088,21 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
[CATransaction commit];
}

void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) {
[CATransaction begin];
[CATransaction setDisableActions:YES];

if (!view) {
[CATransaction commit];
return;
}

[view->GetInspectableWebContentsView()->GetNativeView() removeFromSuperview];
remove_browser_view(view);

[CATransaction commit];
}

void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
InternalSetParentWindow(parent, IsVisible());
}
Expand Down