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)
|
||||
|
||||
#### `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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1095,6 +1095,30 @@ void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) {
|
|||
[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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue