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 win.setTopBrowserView() so that BrowserViews can be raised #27007

Merged
merged 13 commits into from Feb 10, 2021
Merged
7 changes: 7 additions & 0 deletions docs/api/browser-window.md
Expand Up @@ -1786,6 +1786,13 @@ Replacement API for setBrowserView supporting work with multi browser views.

* `browserView` [BrowserView](browser-view.md)

#### `win.setTopBrowserView(browserView)` _Experimental_

* `browserView` [BrowserView](browser-view.md)

Raises `browserView` above other `BrowserView`s attached to `win`.
Throws an error if `browserView` is not attached to `win`.

#### `win.getBrowserViews()` _Experimental_

Returns `BrowserView[]` - an array of all BrowserViews that have been attached
Expand Down
20 changes: 20 additions & 0 deletions shell/browser/api/electron_api_base_window.cc
Expand Up @@ -786,6 +786,25 @@ void BaseWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
}
}

void BaseWindow::SetTopBrowserView(v8::Local<v8::Value> value,
gin_helper::Arguments* args) {
gin::Handle<BrowserView> browser_view;
if (value->IsObject() &&
gin::ConvertFromV8(isolate(), value, &browser_view)) {
if (!browser_view->web_contents())
return;
auto* owner_window = browser_view->web_contents()->owner_window();
auto get_that_view = browser_views_.find(browser_view->ID());
if (get_that_view == browser_views_.end() ||
(owner_window && owner_window != window_.get())) {
args->ThrowError("Given BrowserView is not attached to the window");
return;
}

window_->SetTopBrowserView(browser_view->view());
}
}

std::string BaseWindow::GetMediaSourceId() const {
return window_->GetDesktopMediaID().ToString();
}
Expand Down Expand Up @@ -1224,6 +1243,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setBrowserView", &BaseWindow::SetBrowserView)
.SetMethod("addBrowserView", &BaseWindow::AddBrowserView)
.SetMethod("removeBrowserView", &BaseWindow::RemoveBrowserView)
.SetMethod("setTopBrowserView", &BaseWindow::SetTopBrowserView)
.SetMethod("getMediaSourceId", &BaseWindow::GetMediaSourceId)
.SetMethod("getNativeWindowHandle", &BaseWindow::GetNativeWindowHandle)
.SetMethod("setProgressBar", &BaseWindow::SetProgressBar)
Expand Down
2 changes: 2 additions & 0 deletions shell/browser/api/electron_api_base_window.h
Expand Up @@ -176,6 +176,8 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
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 void SetTopBrowserView(v8::Local<v8::Value> value,
gin_helper::Arguments* args);
virtual std::vector<v8::Local<v8::Value>> GetBrowserViews() const;
virtual void ResetBrowserViews();
std::string GetMediaSourceId() const;
Expand Down
8 changes: 8 additions & 0 deletions shell/browser/api/electron_api_browser_window.cc
Expand Up @@ -378,6 +378,14 @@ void BrowserWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
#endif
}

void BrowserWindow::SetTopBrowserView(v8::Local<v8::Value> value,
gin_helper::Arguments* args) {
BaseWindow::SetTopBrowserView(value, args);
#if defined(OS_MACOSX)
UpdateDraggableRegions(draggable_regions_);
#endif
}

void BrowserWindow::ResetBrowserViews() {
BaseWindow::ResetBrowserViews();
#if defined(OS_MAC)
Expand Down
2 changes: 2 additions & 0 deletions shell/browser/api/electron_api_browser_window.h
Expand Up @@ -84,6 +84,8 @@ class BrowserWindow : public BaseWindow,
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 SetTopBrowserView(v8::Local<v8::Value> value,
gin_helper::Arguments* args) override;
void ResetBrowserViews() override;
void SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value) override;
void OnWindowShow() override;
Expand Down
1 change: 1 addition & 0 deletions shell/browser/native_window.h
Expand Up @@ -167,6 +167,7 @@ class NativeWindow : public base::SupportsUserData,
virtual void SetParentWindow(NativeWindow* parent);
virtual void AddBrowserView(NativeBrowserView* browser_view) = 0;
virtual void RemoveBrowserView(NativeBrowserView* browser_view) = 0;
virtual void SetTopBrowserView(NativeBrowserView* browser_view) = 0;
virtual content::DesktopMediaID GetDesktopMediaID() const = 0;
virtual gfx::NativeView GetNativeView() const = 0;
virtual gfx::NativeWindow GetNativeWindow() const = 0;
Expand Down
1 change: 1 addition & 0 deletions shell/browser/native_window_mac.h
Expand Up @@ -103,6 +103,7 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
void SetFocusable(bool focusable) override;
void AddBrowserView(NativeBrowserView* browser_view) override;
void RemoveBrowserView(NativeBrowserView* browser_view) override;
void SetTopBrowserView(NativeBrowserView* browser_view) override;
void SetParentWindow(NativeWindow* parent) override;
content::DesktopMediaID GetDesktopMediaID() const override;
gfx::NativeView GetNativeView() const override;
Expand Down
24 changes: 24 additions & 0 deletions shell/browser/native_window_mac.mm
Expand Up @@ -1095,6 +1095,30 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
[CATransaction commit];
}

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

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

remove_browser_view(view);
add_browser_view(view);
if (view->GetInspectableWebContentsView()) {
auto* native_view = view->GetInspectableWebContentsView()
->GetNativeView()
.GetNativeNSView();
[[window_ contentView] addSubview:native_view
positioned:NSWindowAbove
relativeTo:nil];
native_view.hidden = NO;
}

[CATransaction commit];
}

void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
InternalSetParentWindow(parent, IsVisible());
}
Expand Down
16 changes: 16 additions & 0 deletions shell/browser/native_window_views.cc
Expand Up @@ -1151,6 +1151,22 @@ void NativeWindowViews::RemoveBrowserView(NativeBrowserView* view) {
remove_browser_view(view);
}

void NativeWindowViews::SetTopBrowserView(NativeBrowserView* view) {
if (!content_view())
return;

if (!view) {
return;
}

remove_browser_view(view);
add_browser_view(view);

if (view->GetInspectableWebContentsView())
content_view()->ReorderChildView(
view->GetInspectableWebContentsView()->GetView(), -1);
}

void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
NativeWindow::SetParentWindow(parent);

Expand Down
1 change: 1 addition & 0 deletions shell/browser/native_window_views.h
Expand Up @@ -115,6 +115,7 @@ class NativeWindowViews : public NativeWindow,
void SetMenu(ElectronMenuModel* menu_model) override;
void AddBrowserView(NativeBrowserView* browser_view) override;
void RemoveBrowserView(NativeBrowserView* browser_view) override;
void SetTopBrowserView(NativeBrowserView* browser_view) override;
void SetParentWindow(NativeWindow* parent) override;
gfx::NativeView GetNativeView() const override;
gfx::NativeWindow GetNativeWindow() const override;
Expand Down
26 changes: 26 additions & 0 deletions spec-main/api-browser-view-spec.ts
Expand Up @@ -210,6 +210,32 @@ describe('BrowserView module', () => {
});
});

describe('BrowserWindow.setTopBrowserView()', () => {
it('should throw an error when a BrowserView is not attached to the window', () => {
view = new BrowserView();
expect(() => {
w.setTopBrowserView(view);
}).to.throw(/is not attached/);
});

it('should throw an error when a BrowserView is attached to some other window', () => {
view = new BrowserView();

const win2 = new BrowserWindow();

w.addBrowserView(view);
view.setBounds({ x: 0, y: 0, width: 100, height: 100 });
win2.addBrowserView(view);

expect(() => {
w.setTopBrowserView(view);
}).to.throw(/is not attached/);

win2.close();
win2.destroy();
});
});

describe('BrowserView.webContents.getOwnerBrowserWindow()', () => {
it('points to owning window', () => {
view = new BrowserView();
Expand Down