wayland: Dismiss XdgPopupWindow when the parent window is closed

XdgPopupWindow can't exist on its own.

BUG: 472013
This commit is contained in:
Vlad Zahorodnii 2024-07-09 09:50:08 +03:00
parent fef5791290
commit 09e0345ccc
3 changed files with 32 additions and 7 deletions

View file

@ -107,6 +107,7 @@ private Q_SLOTS:
void testModal(); void testModal();
void testCloseModal(); void testCloseModal();
void testCloseInactiveModal(); void testCloseInactiveModal();
void testClosePopupOnParentUnmapped();
}; };
void TestXdgShellWindow::testXdgPopupReactive_data() void TestXdgShellWindow::testXdgPopupReactive_data()
@ -2322,5 +2323,29 @@ void TestXdgShellWindow::testCloseInactiveModal()
QCOMPARE(workspace()->activeWindow(), otherWindow); 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<KWayland::Client::Surface> parentSurface = Test::createSurface();
std::unique_ptr<Test::XdgToplevel> parentToplevel = Test::createXdgToplevelSurface(parentSurface.get());
Window *parent = Test::renderAndWaitForShown(parentSurface.get(), QSize(200, 200), Qt::cyan);
QVERIFY(parent);
std::unique_ptr<Test::XdgPositioner> positioner = Test::createXdgPositioner();
positioner->set_size(10, 10);
positioner->set_anchor_rect(10, 10, 10, 10);
std::unique_ptr<KWayland::Client::Surface> childSurface = Test::createSurface();
std::unique_ptr<Test::XdgPopup> 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) WAYLANDTEST_MAIN(TestXdgShellWindow)
#include "xdgshellwindow_test.moc" #include "xdgshellwindow_test.moc"

View file

@ -464,16 +464,13 @@ Workspace::~Workspace()
#endif #endif
if (waylandServer()) { if (waylandServer()) {
const QList<Window *> waylandWindows = waylandServer()->windows(); while (!waylandServer()->windows().isEmpty()) {
for (Window *window : waylandWindows) { waylandServer()->windows()[0]->destroyWindow();
window->destroyWindow();
} }
} }
// We need a shadow copy because windows get removed as we go through them. while (!m_windows.isEmpty()) {
const QList<Window *> windows = m_windows; m_windows[0]->destroyWindow();
for (Window *window : windows) {
window->destroyWindow();
} }
m_rulebook.reset(); m_rulebook.reset();

View file

@ -1672,6 +1672,8 @@ void XdgPopupWindow::handleRoleDestroyed()
{ {
disconnect(transientFor(), &Window::frameGeometryChanged, disconnect(transientFor(), &Window::frameGeometryChanged,
this, &XdgPopupWindow::relayout); this, &XdgPopupWindow::relayout);
disconnect(transientFor(), &Window::closed,
this, &XdgPopupWindow::destroyWindow);
m_shellSurface->disconnect(this); m_shellSurface->disconnect(this);
XdgSurfaceWindow::handleRoleDestroyed(); XdgSurfaceWindow::handleRoleDestroyed();
@ -1815,6 +1817,7 @@ void XdgPopupWindow::initialize()
updateRelativePlacement(); updateRelativePlacement();
connect(parent, &Window::frameGeometryChanged, this, &XdgPopupWindow::relayout); connect(parent, &Window::frameGeometryChanged, this, &XdgPopupWindow::relayout);
connect(parent, &Window::closed, this, &XdgPopupWindow::destroyWindow);
workspace()->placement()->place(this, QRectF()); workspace()->placement()->place(this, QRectF());
scheduleConfigure(); scheduleConfigure();