feat: add win.setTopBrowserView()
so that BrowserViews can be raised (#27007)
* feat: Raise a browser view via `BrowserWindow.setTopBrowserView()`. This is similar to removing and re-adding a browser view, but avoids a visible flicker as the browser view is not removed from the window when using `setTopBrowserView`. Note: if the given browser view is not attached to the window, it will be added. This commit contains the macOS implementation. * feat: setTopBrowserView support for Windows and Linux * docs: add info about setTopBrowserView * docs: Clarify behavior when browserView is not yet attached. * fix: throw en error when browserView is not attached to the window * fix: build error * fix: test * fix: add test case * fix: tests * fix: reparenting * fix: close second window in tests Co-authored-by: sentialx <sentialx@gmail.com>
This commit is contained in:
parent
706d9ede9b
commit
5f5afaae27
11 changed files with 108 additions and 0 deletions
|
@ -1786,6 +1786,13 @@ Replacement API for setBrowserView supporting work with multi browser views.
|
||||||
|
|
||||||
* `browserView` [BrowserView](browser-view.md)
|
* `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_
|
#### `win.getBrowserViews()` _Experimental_
|
||||||
|
|
||||||
Returns `BrowserView[]` - an array of all BrowserViews that have been attached
|
Returns `BrowserView[]` - an array of all BrowserViews that have been attached
|
||||||
|
|
|
@ -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 {
|
std::string BaseWindow::GetMediaSourceId() const {
|
||||||
return window_->GetDesktopMediaID().ToString();
|
return window_->GetDesktopMediaID().ToString();
|
||||||
}
|
}
|
||||||
|
@ -1224,6 +1243,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("setBrowserView", &BaseWindow::SetBrowserView)
|
.SetMethod("setBrowserView", &BaseWindow::SetBrowserView)
|
||||||
.SetMethod("addBrowserView", &BaseWindow::AddBrowserView)
|
.SetMethod("addBrowserView", &BaseWindow::AddBrowserView)
|
||||||
.SetMethod("removeBrowserView", &BaseWindow::RemoveBrowserView)
|
.SetMethod("removeBrowserView", &BaseWindow::RemoveBrowserView)
|
||||||
|
.SetMethod("setTopBrowserView", &BaseWindow::SetTopBrowserView)
|
||||||
.SetMethod("getMediaSourceId", &BaseWindow::GetMediaSourceId)
|
.SetMethod("getMediaSourceId", &BaseWindow::GetMediaSourceId)
|
||||||
.SetMethod("getNativeWindowHandle", &BaseWindow::GetNativeWindowHandle)
|
.SetMethod("getNativeWindowHandle", &BaseWindow::GetNativeWindowHandle)
|
||||||
.SetMethod("setProgressBar", &BaseWindow::SetProgressBar)
|
.SetMethod("setProgressBar", &BaseWindow::SetProgressBar)
|
||||||
|
|
|
@ -176,6 +176,8 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
|
||||||
virtual void SetBrowserView(v8::Local<v8::Value> value);
|
virtual void SetBrowserView(v8::Local<v8::Value> value);
|
||||||
virtual void AddBrowserView(v8::Local<v8::Value> value);
|
virtual void AddBrowserView(v8::Local<v8::Value> value);
|
||||||
virtual void RemoveBrowserView(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 std::vector<v8::Local<v8::Value>> GetBrowserViews() const;
|
||||||
virtual void ResetBrowserViews();
|
virtual void ResetBrowserViews();
|
||||||
std::string GetMediaSourceId() const;
|
std::string GetMediaSourceId() const;
|
||||||
|
|
|
@ -378,6 +378,14 @@ void BrowserWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
|
||||||
#endif
|
#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() {
|
void BrowserWindow::ResetBrowserViews() {
|
||||||
BaseWindow::ResetBrowserViews();
|
BaseWindow::ResetBrowserViews();
|
||||||
#if defined(OS_MAC)
|
#if defined(OS_MAC)
|
||||||
|
|
|
@ -84,6 +84,8 @@ class BrowserWindow : public BaseWindow,
|
||||||
void SetBrowserView(v8::Local<v8::Value> value) override;
|
void SetBrowserView(v8::Local<v8::Value> value) override;
|
||||||
void AddBrowserView(v8::Local<v8::Value> value) override;
|
void AddBrowserView(v8::Local<v8::Value> value) override;
|
||||||
void RemoveBrowserView(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 ResetBrowserViews() override;
|
||||||
void SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value) override;
|
void SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value) override;
|
||||||
void OnWindowShow() override;
|
void OnWindowShow() override;
|
||||||
|
|
|
@ -167,6 +167,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||||
virtual void SetParentWindow(NativeWindow* parent);
|
virtual void SetParentWindow(NativeWindow* parent);
|
||||||
virtual void AddBrowserView(NativeBrowserView* browser_view) = 0;
|
virtual void AddBrowserView(NativeBrowserView* browser_view) = 0;
|
||||||
virtual void RemoveBrowserView(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 content::DesktopMediaID GetDesktopMediaID() const = 0;
|
||||||
virtual gfx::NativeView GetNativeView() const = 0;
|
virtual gfx::NativeView GetNativeView() const = 0;
|
||||||
virtual gfx::NativeWindow GetNativeWindow() const = 0;
|
virtual gfx::NativeWindow GetNativeWindow() const = 0;
|
||||||
|
|
|
@ -103,6 +103,7 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
|
||||||
void SetFocusable(bool focusable) override;
|
void SetFocusable(bool focusable) override;
|
||||||
void AddBrowserView(NativeBrowserView* browser_view) override;
|
void AddBrowserView(NativeBrowserView* browser_view) override;
|
||||||
void RemoveBrowserView(NativeBrowserView* browser_view) override;
|
void RemoveBrowserView(NativeBrowserView* browser_view) override;
|
||||||
|
void SetTopBrowserView(NativeBrowserView* browser_view) override;
|
||||||
void SetParentWindow(NativeWindow* parent) override;
|
void SetParentWindow(NativeWindow* parent) override;
|
||||||
content::DesktopMediaID GetDesktopMediaID() const override;
|
content::DesktopMediaID GetDesktopMediaID() const override;
|
||||||
gfx::NativeView GetNativeView() const override;
|
gfx::NativeView GetNativeView() const override;
|
||||||
|
|
|
@ -1095,6 +1095,30 @@ void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) {
|
||||||
[CATransaction commit];
|
[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) {
|
void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
|
||||||
InternalSetParentWindow(parent, IsVisible());
|
InternalSetParentWindow(parent, IsVisible());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1151,6 +1151,22 @@ void NativeWindowViews::RemoveBrowserView(NativeBrowserView* view) {
|
||||||
remove_browser_view(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) {
|
void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
|
||||||
NativeWindow::SetParentWindow(parent);
|
NativeWindow::SetParentWindow(parent);
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,7 @@ class NativeWindowViews : public NativeWindow,
|
||||||
void SetMenu(ElectronMenuModel* menu_model) override;
|
void SetMenu(ElectronMenuModel* menu_model) override;
|
||||||
void AddBrowserView(NativeBrowserView* browser_view) override;
|
void AddBrowserView(NativeBrowserView* browser_view) override;
|
||||||
void RemoveBrowserView(NativeBrowserView* browser_view) override;
|
void RemoveBrowserView(NativeBrowserView* browser_view) override;
|
||||||
|
void SetTopBrowserView(NativeBrowserView* browser_view) override;
|
||||||
void SetParentWindow(NativeWindow* parent) override;
|
void SetParentWindow(NativeWindow* parent) override;
|
||||||
gfx::NativeView GetNativeView() const override;
|
gfx::NativeView GetNativeView() const override;
|
||||||
gfx::NativeWindow GetNativeWindow() const override;
|
gfx::NativeWindow GetNativeWindow() const override;
|
||||||
|
|
|
@ -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()', () => {
|
describe('BrowserView.webContents.getOwnerBrowserWindow()', () => {
|
||||||
it('points to owning window', () => {
|
it('points to owning window', () => {
|
||||||
view = new BrowserView();
|
view = new BrowserView();
|
||||||
|
|
Loading…
Reference in a new issue