feat: browserWindow.getBrowserViews() to return sorted by z-index array (#38943)

This commit is contained in:
Mikhail Leliakin 2023-07-11 19:01:30 +10:00 committed by GitHub
parent 905e41bbdd
commit f959fb0c96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 13 deletions

View file

@ -1651,8 +1651,8 @@ 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[]` - a sorted by z-index array of all BrowserViews that have been attached
with `addBrowserView` or `setBrowserView`. with `addBrowserView` or `setBrowserView`. The top-most BrowserView is the last element of the array.
**Note:** The BrowserView API is currently experimental and may change or be **Note:** The BrowserView API is currently experimental and may change or be
removed in future Electron releases. removed in future Electron releases.

View file

@ -4,6 +4,7 @@
#include "shell/browser/api/electron_api_base_window.h" #include "shell/browser/api/electron_api_base_window.h"
#include <algorithm>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -756,7 +757,7 @@ void BaseWindow::SetBrowserView(
} }
void BaseWindow::AddBrowserView(gin::Handle<BrowserView> browser_view) { void BaseWindow::AddBrowserView(gin::Handle<BrowserView> browser_view) {
if (!base::Contains(browser_views_, browser_view->ID())) { if (!base::Contains(browser_views_, browser_view.ToV8())) {
// If we're reparenting a BrowserView, ensure that it's detached from // If we're reparenting a BrowserView, ensure that it's detached from
// its previous owner window. // its previous owner window.
BaseWindow* owner_window = browser_view->owner_window(); BaseWindow* owner_window = browser_view->owner_window();
@ -770,17 +771,19 @@ void BaseWindow::AddBrowserView(gin::Handle<BrowserView> browser_view) {
window_->AddBrowserView(browser_view->view()); window_->AddBrowserView(browser_view->view());
window_->AddDraggableRegionProvider(browser_view.get()); window_->AddDraggableRegionProvider(browser_view.get());
browser_view->SetOwnerWindow(this); browser_view->SetOwnerWindow(this);
browser_views_[browser_view->ID()].Reset(isolate(), browser_view.ToV8()); browser_views_.emplace_back().Reset(isolate(), browser_view.ToV8());
} }
} }
void BaseWindow::RemoveBrowserView(gin::Handle<BrowserView> browser_view) { void BaseWindow::RemoveBrowserView(gin::Handle<BrowserView> browser_view) {
auto iter = browser_views_.find(browser_view->ID()); auto iter = std::find(browser_views_.begin(), browser_views_.end(),
browser_view.ToV8());
if (iter != browser_views_.end()) { if (iter != browser_views_.end()) {
window_->RemoveBrowserView(browser_view->view()); window_->RemoveBrowserView(browser_view->view());
window_->RemoveDraggableRegionProvider(browser_view.get()); window_->RemoveDraggableRegionProvider(browser_view.get());
browser_view->SetOwnerWindow(nullptr); browser_view->SetOwnerWindow(nullptr);
iter->second.Reset(); iter->Reset();
browser_views_.erase(iter); browser_views_.erase(iter);
} }
} }
@ -788,12 +791,15 @@ void BaseWindow::RemoveBrowserView(gin::Handle<BrowserView> browser_view) {
void BaseWindow::SetTopBrowserView(gin::Handle<BrowserView> browser_view, void BaseWindow::SetTopBrowserView(gin::Handle<BrowserView> browser_view,
gin_helper::Arguments* args) { gin_helper::Arguments* args) {
BaseWindow* owner_window = browser_view->owner_window(); BaseWindow* owner_window = browser_view->owner_window();
auto iter = browser_views_.find(browser_view->ID()); auto iter = std::find(browser_views_.begin(), browser_views_.end(),
browser_view.ToV8());
if (iter == browser_views_.end() || (owner_window && owner_window != this)) { if (iter == browser_views_.end() || (owner_window && owner_window != this)) {
args->ThrowError("Given BrowserView is not attached to the window"); args->ThrowError("Given BrowserView is not attached to the window");
return; return;
} }
browser_views_.erase(iter);
browser_views_.emplace_back().Reset(isolate(), browser_view.ToV8());
window_->SetTopBrowserView(browser_view->view()); window_->SetTopBrowserView(browser_view->view());
} }
@ -1000,7 +1006,7 @@ v8::Local<v8::Value> BaseWindow::GetBrowserView(
return v8::Null(isolate()); return v8::Null(isolate());
} else if (browser_views_.size() == 1) { } else if (browser_views_.size() == 1) {
auto first_view = browser_views_.begin(); auto first_view = browser_views_.begin();
return v8::Local<v8::Value>::New(isolate(), (*first_view).second); return v8::Local<v8::Value>::New(isolate(), *first_view);
} else { } else {
args->ThrowError( args->ThrowError(
"BrowserWindow have multiple BrowserViews, " "BrowserWindow have multiple BrowserViews, "
@ -1012,8 +1018,8 @@ v8::Local<v8::Value> BaseWindow::GetBrowserView(
std::vector<v8::Local<v8::Value>> BaseWindow::GetBrowserViews() const { std::vector<v8::Local<v8::Value>> BaseWindow::GetBrowserViews() const {
std::vector<v8::Local<v8::Value>> ret; std::vector<v8::Local<v8::Value>> ret;
for (auto const& views_iter : browser_views_) { for (auto const& browser_view : browser_views_) {
ret.push_back(v8::Local<v8::Value>::New(isolate(), views_iter.second)); ret.push_back(v8::Local<v8::Value>::New(isolate(), browser_view));
} }
return ret; return ret;
@ -1122,7 +1128,7 @@ void BaseWindow::ResetBrowserViews() {
for (auto& item : browser_views_) { for (auto& item : browser_views_) {
gin::Handle<BrowserView> browser_view; gin::Handle<BrowserView> browser_view;
if (gin::ConvertFromV8(isolate(), if (gin::ConvertFromV8(isolate(),
v8::Local<v8::Value>::New(isolate(), item.second), v8::Local<v8::Value>::New(isolate(), item),
&browser_view) && &browser_view) &&
!browser_view.IsEmpty()) { !browser_view.IsEmpty()) {
// There's a chance that the BrowserView may have been reparented - only // There's a chance that the BrowserView may have been reparented - only
@ -1135,7 +1141,7 @@ void BaseWindow::ResetBrowserViews() {
browser_view->SetOwnerWindow(nullptr); browser_view->SetOwnerWindow(nullptr);
} }
item.second.Reset(); item.Reset();
} }
browser_views_.clear(); browser_views_.clear();

View file

@ -275,7 +275,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
#endif #endif
v8::Global<v8::Value> content_view_; v8::Global<v8::Value> content_view_;
std::map<int32_t, v8::Global<v8::Value>> browser_views_; std::vector<v8::Global<v8::Value>> browser_views_;
v8::Global<v8::Value> menu_; v8::Global<v8::Value> menu_;
v8::Global<v8::Value> parent_window_; v8::Global<v8::Value> parent_window_;
KeyWeakMap<int> child_windows_; KeyWeakMap<int> child_windows_;

View file

@ -286,6 +286,23 @@ describe('BrowserView module', () => {
expect(views[0].webContents.id).to.equal(view1.webContents.id); expect(views[0].webContents.id).to.equal(view1.webContents.id);
expect(views[1].webContents.id).to.equal(view2.webContents.id); expect(views[1].webContents.id).to.equal(view2.webContents.id);
}); });
it('persists ordering by z-index', () => {
const view1 = new BrowserView();
defer(() => view1.webContents.destroy());
w.addBrowserView(view1);
defer(() => w.removeBrowserView(view1));
const view2 = new BrowserView();
defer(() => view2.webContents.destroy());
w.addBrowserView(view2);
defer(() => w.removeBrowserView(view2));
w.setTopBrowserView(view1);
const views = w.getBrowserViews();
expect(views).to.have.lengthOf(2);
expect(views[0].webContents.id).to.equal(view2.webContents.id);
expect(views[1].webContents.id).to.equal(view1.webContents.id);
});
}); });
describe('BrowserWindow.setTopBrowserView()', () => { describe('BrowserWindow.setTopBrowserView()', () => {