diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index 8cdd0a681bd..338d66ea19f 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -314,10 +314,20 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s Qt::WindowType type = window->window()->type(); auto *transientParent = window->transientParent(); - if (type == Qt::ToolTip && transientParent) { - setPopup(transientParent); - } else if (type == Qt::Popup && transientParent && display->lastInputDevice()) { - setGrabPopup(transientParent, display->lastInputDevice(), display->lastInputSerial()); + if (type == Qt::ToolTip) { + if (transientParent) { + setPopup(transientParent); + } else { + qCWarning(lcQpaWayland) << "Failed to create popup. Ensure popup " << window->window() << "has a transientParent set."; + QWindowSystemInterface::handleCloseEvent(m_window->window()); + } + } else if (type == Qt::Popup ) { + if (transientParent && display->lastInputDevice()) { + setGrabPopup(transientParent, display->lastInputDevice(), display->lastInputSerial()); + } else { + qCWarning(lcQpaWayland) << "Failed to create grabbing popup. Ensure popup " << window->window() << "has a transientParent set and that parent window has received input."; + QWindowSystemInterface::handleCloseEvent(m_window->window()); + } } else { setToplevel(); } diff --git a/tests/auto/wayland/xdgshell/tst_xdgshell.cpp b/tests/auto/wayland/xdgshell/tst_xdgshell.cpp index 45b78ed003f..e23cc83f5b6 100644 --- a/tests/auto/wayland/xdgshell/tst_xdgshell.cpp +++ b/tests/auto/wayland/xdgshell/tst_xdgshell.cpp @@ -26,6 +26,7 @@ private slots: void tooltipAndSiblingPopup(); void switchPopups(); void hidePopupParent(); + void popupsWithoutParent(); void pongs(); void minMaxSize_data(); void minMaxSize(); @@ -608,6 +609,45 @@ void tst_xdgshell::hidePopupParent() QCOMPOSITOR_TRY_VERIFY(!xdgToplevel()); } +void tst_xdgshell::popupsWithoutParent() +{ + QRasterWindow popup; + QSignalSpy popupDoneSpy(&popup, &QWindow::visibilityChanged); + popup.setFlags(Qt::Popup); + popup.resize(100, 100); + popup.show(); + QVERIFY(popup.isVisible()); + + // popup cannot be created within the spec, so it gets auto-dismissed + QVERIFY(popupDoneSpy.wait()); + QVERIFY(!popup.isVisible()); + + QCOMPOSITOR_VERIFY(!xdgToplevel()); + + // now make a normal window with an input event + QRasterWindow window; + window.setTitle("main window"); + window.resize(200, 200); + window.show(); + + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + exec([&] { xdgToplevel()->sendCompleteConfigure(); }); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial); + exec([&] { + keyboard()->sendEnter(xdgToplevel()->surface()); + keyboard()->sendKey(client(), 72, Keyboard::key_state_pressed); // related with native scan code + keyboard()->sendKey(client(), 72, Keyboard::key_state_released); // related with native scan code + }); + QTRY_COMPARE(qGuiApp->focusWindow(), &window); + + // now re-show our popup, it should be able to guess a transient this time + // and correctly show as a popup + popup.show(); + QCOMPOSITOR_TRY_VERIFY(xdgPopup()); + exec([&] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); }); + QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial); +} + void tst_xdgshell::pongs() { // Create and show a window to trigger shell integration initialzation,