From 09e0345cccb9098ef29ed544ef3dd5d5134bfa07 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 9 Jul 2024 09:50:08 +0300 Subject: [PATCH] wayland: Dismiss XdgPopupWindow when the parent window is closed XdgPopupWindow can't exist on its own. BUG: 472013 --- autotests/integration/xdgshellwindow_test.cpp | 25 +++++++++++++++++++ src/workspace.cpp | 11 +++----- src/xdgshellwindow.cpp | 3 +++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/autotests/integration/xdgshellwindow_test.cpp b/autotests/integration/xdgshellwindow_test.cpp index fb321b66cf..922ff4599d 100644 --- a/autotests/integration/xdgshellwindow_test.cpp +++ b/autotests/integration/xdgshellwindow_test.cpp @@ -107,6 +107,7 @@ private Q_SLOTS: void testModal(); void testCloseModal(); void testCloseInactiveModal(); + void testClosePopupOnParentUnmapped(); }; void TestXdgShellWindow::testXdgPopupReactive_data() @@ -2322,5 +2323,29 @@ void TestXdgShellWindow::testCloseInactiveModal() QCOMPARE(workspace()->activeWindow(), otherWindow); } +void TestXdgShellWindow::testClosePopupOnParentUnmapped() +{ + // This test verifies that a popup window will be closed when the parent window is closed. + + std::unique_ptr parentSurface = Test::createSurface(); + std::unique_ptr parentToplevel = Test::createXdgToplevelSurface(parentSurface.get()); + Window *parent = Test::renderAndWaitForShown(parentSurface.get(), QSize(200, 200), Qt::cyan); + QVERIFY(parent); + + std::unique_ptr positioner = Test::createXdgPositioner(); + positioner->set_size(10, 10); + positioner->set_anchor_rect(10, 10, 10, 10); + + std::unique_ptr childSurface = Test::createSurface(); + std::unique_ptr popup = Test::createXdgPopupSurface(childSurface.get(), parentToplevel->xdgSurface(), positioner.get()); + Window *child = Test::renderAndWaitForShown(childSurface.get(), QSize(10, 10), Qt::cyan); + QVERIFY(child); + + QSignalSpy childClosedSpy(child, &Window::closed); + parentToplevel.reset(); + parentSurface.reset(); + QVERIFY(childClosedSpy.wait()); +} + WAYLANDTEST_MAIN(TestXdgShellWindow) #include "xdgshellwindow_test.moc" diff --git a/src/workspace.cpp b/src/workspace.cpp index 397e59ba73..2fe745875d 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -464,16 +464,13 @@ Workspace::~Workspace() #endif if (waylandServer()) { - const QList waylandWindows = waylandServer()->windows(); - for (Window *window : waylandWindows) { - window->destroyWindow(); + while (!waylandServer()->windows().isEmpty()) { + waylandServer()->windows()[0]->destroyWindow(); } } - // We need a shadow copy because windows get removed as we go through them. - const QList windows = m_windows; - for (Window *window : windows) { - window->destroyWindow(); + while (!m_windows.isEmpty()) { + m_windows[0]->destroyWindow(); } m_rulebook.reset(); diff --git a/src/xdgshellwindow.cpp b/src/xdgshellwindow.cpp index b64abc5936..8dac0246ef 100644 --- a/src/xdgshellwindow.cpp +++ b/src/xdgshellwindow.cpp @@ -1672,6 +1672,8 @@ void XdgPopupWindow::handleRoleDestroyed() { disconnect(transientFor(), &Window::frameGeometryChanged, this, &XdgPopupWindow::relayout); + disconnect(transientFor(), &Window::closed, + this, &XdgPopupWindow::destroyWindow); m_shellSurface->disconnect(this); XdgSurfaceWindow::handleRoleDestroyed(); @@ -1815,6 +1817,7 @@ void XdgPopupWindow::initialize() updateRelativePlacement(); connect(parent, &Window::frameGeometryChanged, this, &XdgPopupWindow::relayout); + connect(parent, &Window::closed, this, &XdgPopupWindow::destroyWindow); workspace()->placement()->place(this, QRectF()); scheduleConfigure();