Client xdg-shell: Add test for switching popups
Task-number: QTBUG-73524 Change-Id: Ie9a13aeae52a7576699147e5515e2ed32a3a4d1c Reviewed-by: Giulio Camuffo <giulio.camuffo@kdab.com>
This commit is contained in:
parent
7fa16ebff6
commit
c104decfdd
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user