summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/auto/client/shared/xdgshell.cpp1
-rw-r--r--tests/auto/client/shared/xdgshell.h5
-rw-r--r--tests/auto/client/xdgshell/tst_xdgshell.cpp89
3 files changed, 94 insertions, 1 deletions
diff --git a/tests/auto/client/shared/xdgshell.cpp b/tests/auto/client/shared/xdgshell.cpp
index 9437688a..13acc01e 100644
--- a/tests/auto/client/shared/xdgshell.cpp
+++ b/tests/auto/client/shared/xdgshell.cpp
@@ -236,6 +236,7 @@ void XdgPopup::xdg_popup_destroy(Resource *resource) {
}
m_xdgSurface->m_popup = nullptr;
m_parentXdgSurface->m_popups.removeAll(this);
+ emit destroyRequested();
}
} // namespace MockCompositor
diff --git a/tests/auto/client/shared/xdgshell.h b/tests/auto/client/shared/xdgshell.h
index ca19c293..618babde 100644
--- a/tests/auto/client/shared/xdgshell.h
+++ b/tests/auto/client/shared/xdgshell.h
@@ -130,8 +130,9 @@ protected:
void xdg_toplevel_set_min_size(Resource *resource, int32_t width, int32_t height) override;
};
-class XdgPopup : public QtWaylandServer::xdg_popup
+class XdgPopup : public QObject, public QtWaylandServer::xdg_popup
{
+ Q_OBJECT
public:
explicit XdgPopup(XdgSurface *xdgSurface, XdgSurface *parent, int id, int version = 1);
void sendConfigure(const QRect &geometry);
@@ -141,6 +142,8 @@ public:
XdgSurface *m_parentXdgSurface = nullptr;
bool m_grabbed = false;
uint m_grabSerial = 0;
+signals:
+ void destroyRequested();
protected:
void xdg_popup_grab(Resource *resource, ::wl_resource *seat, uint32_t serial) override;
void xdg_popup_destroy(Resource *resource) override;
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
index 32b62689..6efffc8a 100644
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
@@ -43,6 +43,7 @@ private slots:
void configureStates();
void popup();
void tooltipOnPopup();
+ void switchPopups();
void pongs();
void minMaxSize();
void windowGeometry();
@@ -332,6 +333,94 @@ void tst_xdgshell::tooltipOnPopup()
QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
}
+// QTBUG-65680
+void tst_xdgshell::switchPopups()
+{
+ class Popup : public QRasterWindow {
+ public:
+ explicit Popup(QWindow *parent) {
+ setTransientParent(parent);
+ setFlags(Qt::Popup);
+ resize(10, 10);
+ show();
+ }
+ };
+
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *event) override {
+ QRasterWindow::mousePressEvent(event);
+ if (!m_popups.empty())
+ m_popups.last()->setVisible(false);
+ }
+ // The bug this checks for, is the case where there is a flushWindowSystemEvents() call
+ // somewhere within setVisible(false) before the grab has been released.
+ // This leads to the the release event below—including its show() call—to be handled
+ // At a time where there is still an active grab, making it illegal for the new popup to
+ // grab.
+ void mouseReleaseEvent(QMouseEvent *event) override {
+ QRasterWindow::mouseReleaseEvent(event);
+ m_popups << new Popup(this);
+ }
+ ~Window() override { qDeleteAll(m_popups); }
+ QVector<Popup *> m_popups;
+ };
+
+ Window window;
+ window.resize(200, 200);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *surface = xdgToplevel()->surface();
+ auto *p = pointer();
+ p->sendEnter(surface, {100, 100});
+// p->sendFrame(); //TODO: uncomment when we support seat v5
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
+// p->sendFrame();
+ p->sendLeave(surface);
+// p->sendFrame();
+ });
+
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup());
+ exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed);
+
+ QSignalSpy firstDestroyed(exec([=] { return xdgPopup(); }), &XdgPopup::destroyRequested);
+
+ exec([=] {
+ auto *surface = xdgToplevel()->surface();
+ auto *p = pointer();
+ p->sendEnter(surface, {100, 100});
+// p->sendFrame();
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
+// p->sendFrame();
+ });
+
+ // The client will now hide one popup and then show another
+ firstDestroyed.wait();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup());
+ QCOMPOSITOR_TRY_VERIFY(!xdgPopup(1));
+
+ // Verify we still grabbed in case the client has checks to avoid illegal grabs
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed);
+
+ // Sometimes the popup will select another parent if one is illegal at the time it tries to
+ // grab. So we verify we got the intended parent on the compositor side.
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_parentXdgSurface == xdgToplevel()->m_xdgSurface);
+
+ // For good measure just check that configuring works as usual
+ exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
+}
+
void tst_xdgshell::pongs()
{
QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong);