mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
fix: reparenting after BrowserWindow.destroy() (#39307)
fix: reparenting after BrowserWindow.destroy() Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
@@ -148,6 +148,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual std::string GetAlwaysOnTopLevel() = 0;
|
||||
virtual void SetActive(bool is_key) = 0;
|
||||
virtual bool IsActive() const = 0;
|
||||
virtual void RemoveChildFromParentWindow() = 0;
|
||||
virtual void RemoveChildWindow(NativeWindow* child) = 0;
|
||||
virtual void AttachChildren() = 0;
|
||||
virtual void DetachChildren() = 0;
|
||||
|
||||
@@ -157,7 +157,7 @@ class NativeWindowMac : public NativeWindow,
|
||||
bool IsActive() const override;
|
||||
// Remove the specified child window without closing it.
|
||||
void RemoveChildWindow(NativeWindow* child) override;
|
||||
void RemoveChildFromParentWindow(NativeWindow* child);
|
||||
void RemoveChildFromParentWindow() override;
|
||||
// Attach child windows, if the window is visible.
|
||||
void AttachChildren() override;
|
||||
// Detach window from parent without destroying it.
|
||||
|
||||
@@ -431,7 +431,12 @@ void NativeWindowMac::Close() {
|
||||
}
|
||||
|
||||
// Ensure we're detached from the parent window before closing.
|
||||
RemoveChildFromParentWindow(this);
|
||||
RemoveChildFromParentWindow();
|
||||
|
||||
while (!child_windows_.empty()) {
|
||||
auto* child = child_windows_.back();
|
||||
child->RemoveChildFromParentWindow();
|
||||
}
|
||||
|
||||
// If a sheet is attached to the window when we call
|
||||
// [window_ performClose:nil], the window won't close properly
|
||||
@@ -450,13 +455,20 @@ void NativeWindowMac::Close() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::CloseImmediately() {
|
||||
RemoveChildFromParentWindow(this);
|
||||
// Ensure we're detached from the parent window before closing.
|
||||
RemoveChildFromParentWindow();
|
||||
|
||||
// Retain the child window before closing it. If the last reference to the
|
||||
// NSWindow goes away inside -[NSWindow close], then bad stuff can happen.
|
||||
// See e.g. http://crbug.com/616701.
|
||||
base::scoped_nsobject<NSWindow> child_window(window_,
|
||||
base::scoped_policy::RETAIN);
|
||||
|
||||
while (!child_windows_.empty()) {
|
||||
auto* child = child_windows_.back();
|
||||
child->RemoveChildFromParentWindow();
|
||||
}
|
||||
|
||||
[window_ close];
|
||||
}
|
||||
|
||||
@@ -645,9 +657,11 @@ void NativeWindowMac::RemoveChildWindow(NativeWindow* child) {
|
||||
[window_ removeChildWindow:child->GetNativeWindow().GetNativeNSWindow()];
|
||||
}
|
||||
|
||||
void NativeWindowMac::RemoveChildFromParentWindow(NativeWindow* child) {
|
||||
if (parent())
|
||||
parent()->RemoveChildWindow(child);
|
||||
void NativeWindowMac::RemoveChildFromParentWindow() {
|
||||
if (parent() && !is_modal()) {
|
||||
parent()->RemoveChildWindow(this);
|
||||
NativeWindow::SetParentWindow(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::AttachChildren() {
|
||||
@@ -1867,12 +1881,13 @@ void NativeWindowMac::InternalSetParentWindow(NativeWindow* new_parent,
|
||||
return;
|
||||
|
||||
// Remove current parent window.
|
||||
RemoveChildFromParentWindow(this);
|
||||
RemoveChildFromParentWindow();
|
||||
|
||||
// Set new parent window.
|
||||
if (new_parent && attach) {
|
||||
if (new_parent) {
|
||||
new_parent->add_child_window(this);
|
||||
new_parent->AttachChildren();
|
||||
if (attach)
|
||||
new_parent->AttachChildren();
|
||||
}
|
||||
|
||||
NativeWindow::SetParentWindow(new_parent);
|
||||
|
||||
@@ -4376,6 +4376,7 @@ describe('BrowserWindow module', () => {
|
||||
c.setParentWindow(null);
|
||||
expect(c.getParentWindow()).to.be.null('c.parent');
|
||||
});
|
||||
|
||||
it('adds window to child windows of parent', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const c = new BrowserWindow({ show: false });
|
||||
@@ -4385,6 +4386,7 @@ describe('BrowserWindow module', () => {
|
||||
c.setParentWindow(null);
|
||||
expect(w.getChildWindows()).to.deep.equal([]);
|
||||
});
|
||||
|
||||
it('removes from child windows of parent when window is closed', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const c = new BrowserWindow({ show: false });
|
||||
@@ -4396,6 +4398,25 @@ describe('BrowserWindow module', () => {
|
||||
await delay();
|
||||
expect(w.getChildWindows().length).to.equal(0);
|
||||
});
|
||||
|
||||
ifit(process.platform === 'darwin')('can reparent when the first parent is destroyed', async () => {
|
||||
const w1 = new BrowserWindow({ show: false });
|
||||
const w2 = new BrowserWindow({ show: false });
|
||||
const c = new BrowserWindow({ show: false });
|
||||
|
||||
c.setParentWindow(w1);
|
||||
expect(w1.getChildWindows().length).to.equal(1);
|
||||
|
||||
const closed = emittedOnce(w1, 'closed');
|
||||
w1.destroy();
|
||||
await closed;
|
||||
|
||||
c.setParentWindow(w2);
|
||||
await delay(1000);
|
||||
|
||||
const children = w2.getChildWindows();
|
||||
expect(children[0]).to.equal(c);
|
||||
});
|
||||
});
|
||||
|
||||
describe('modal option', () => {
|
||||
|
||||
Reference in New Issue
Block a user