summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Klokkhammer Helsing <johan.helsing@qt.io>2018-12-21 14:31:58 +0100
committerJohan Helsing <johan.helsing@qt.io>2019-02-06 15:30:23 +0000
commit60d6d83ea0c43462d5f8e17aaa654ab6f625dd6e (patch)
tree643f3860052c5ee50b3f9ab53481a4f552c025c4
parent401bdecabb950001ae3294e864ed397d1b76b3f4 (diff)
Client xdg-shell: Add test for tooltips on popupsv5.13.0-alpha1
This used to cause protocol errors. Task-number: QTBUG-71734 Change-Id: Ic937210fc42c93f1d411fb0fb4f269de01f07b5b Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
-rw-r--r--tests/auto/client/shared/coreprotocol.cpp14
-rw-r--r--tests/auto/client/shared/coreprotocol.h3
-rw-r--r--tests/auto/client/shared/xdgshell.cpp36
-rw-r--r--tests/auto/client/shared/xdgshell.h14
-rw-r--r--tests/auto/client/xdgshell/tst_xdgshell.cpp80
5 files changed, 140 insertions, 7 deletions
diff --git a/tests/auto/client/shared/coreprotocol.cpp b/tests/auto/client/shared/coreprotocol.cpp
index 54725e81..6f51a979 100644
--- a/tests/auto/client/shared/coreprotocol.cpp
+++ b/tests/auto/client/shared/coreprotocol.cpp
@@ -263,10 +263,22 @@ uint Pointer::sendEnter(Surface *surface, const QPointF &position)
wl_client *client = surface->resource()->client();
const auto pointerResources = resourceMap().values(client);
for (auto *r : pointerResources)
- send_enter(r->handle, m_enterSerial, surface->resource()->handle, x ,y);
+ wl_pointer::send_enter(r->handle, m_enterSerial, surface->resource()->handle, x ,y);
return m_enterSerial;
}
+uint Pointer::sendLeave(Surface *surface)
+{
+ m_enterSerial = 0;
+ uint serial = m_seat->m_compositor->nextSerial();
+
+ wl_client *client = surface->resource()->client();
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ wl_pointer::send_leave(r->handle, serial, surface->resource()->handle);
+ return serial;
+}
+
// Make sure you call enter, frame etc. first
void Pointer::sendMotion(wl_client *client, const QPointF &position)
{
diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h
index 11b35eb4..249c16f4 100644
--- a/tests/auto/client/shared/coreprotocol.h
+++ b/tests/auto/client/shared/coreprotocol.h
@@ -275,7 +275,10 @@ public:
explicit Pointer(Seat *seat) : m_seat(seat) {}
Surface *cursorSurface();
CursorRole* m_cursorRole = nullptr; //TODO: cleanup
+ void send_enter() = delete;
uint sendEnter(Surface *surface, const QPointF &position);
+ void send_leave() = delete;
+ uint sendLeave(Surface *surface);
void sendMotion(wl_client *client, const QPointF &position);
uint sendButton(wl_client *client, uint button, uint state);
void sendAxis(wl_client *client, axis axis, qreal value);
diff --git a/tests/auto/client/shared/xdgshell.cpp b/tests/auto/client/shared/xdgshell.cpp
index 6bc30302..9437688a 100644
--- a/tests/auto/client/shared/xdgshell.cpp
+++ b/tests/auto/client/shared/xdgshell.cpp
@@ -120,11 +120,11 @@ void XdgSurface::xdg_surface_get_toplevel(Resource *resource, uint32_t id)
void XdgSurface::xdg_surface_get_popup(Resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner)
{
- Q_UNUSED(parent);
Q_UNUSED(positioner);
QVERIFY(!m_toplevel);
QVERIFY(!m_popup);
- m_popup = new XdgPopup(this, id, resource->version());
+ auto *p = fromResource<XdgSurface>(parent);
+ m_popup = new XdgPopup(this, p, id, resource->version());
}
void XdgSurface::xdg_surface_destroy_resource(Resource *resource)
@@ -135,6 +135,12 @@ void XdgSurface::xdg_surface_destroy_resource(Resource *resource)
delete this;
}
+void XdgSurface::xdg_surface_destroy(QtWaylandServer::xdg_surface::Resource *resource)
+{
+ QVERIFY(m_popups.empty());
+ wl_resource_destroy(resource->handle);
+}
+
void XdgSurface::xdg_surface_set_window_geometry(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
{
Q_UNUSED(resource);
@@ -189,10 +195,14 @@ void XdgToplevel::xdg_toplevel_set_min_size(Resource *resource, int32_t width, i
m_pending.minSize = size;
}
-XdgPopup::XdgPopup(XdgSurface *xdgSurface, int id, int version)
+XdgPopup::XdgPopup(XdgSurface *xdgSurface, XdgSurface *parent, int id, int version)
: QtWaylandServer::xdg_popup(xdgSurface->resource()->client(), id, version)
, m_xdgSurface(xdgSurface)
+ , m_parentXdgSurface(parent)
{
+ Q_ASSERT(m_xdgSurface);
+ Q_ASSERT(m_parentXdgSurface);
+ m_parentXdgSurface->m_popups << this;
}
void XdgPopup::sendConfigure(const QRect &geometry)
@@ -200,14 +210,32 @@ void XdgPopup::sendConfigure(const QRect &geometry)
send_configure(geometry.x(), geometry.y(), geometry.width(), geometry.height());
}
+uint XdgPopup::sendCompleteConfigure(const QRect &geometry)
+{
+ sendConfigure(geometry);
+ return m_xdgSurface->sendConfigure();
+}
+
void XdgPopup::xdg_popup_grab(QtWaylandServer::xdg_popup::Resource *resource, wl_resource *seat, uint32_t serial)
{
Q_UNUSED(resource);
Q_UNUSED(seat); // TODO: verify correct seat as well
- //TODO: verify no other popup has grabbed
QVERIFY(!m_grabbed);
+ QVERIFY(m_parentXdgSurface->isValidPopupGrabParent());
+ m_xdgSurface->m_xdgWmBase->m_topmostGrabbingPopup = this;
m_grabbed = true;
m_grabSerial = serial;
}
+void XdgPopup::xdg_popup_destroy(Resource *resource) {
+ Q_UNUSED(resource);
+ if (m_grabbed) {
+ auto *base = m_xdgSurface->m_xdgWmBase;
+ QCOMPARE(base->m_topmostGrabbingPopup, this);
+ base->m_topmostGrabbingPopup = this->m_parentXdgSurface->m_popup;
+ }
+ m_xdgSurface->m_popup = nullptr;
+ m_parentXdgSurface->m_popups.removeAll(this);
+}
+
} // namespace MockCompositor
diff --git a/tests/auto/client/shared/xdgshell.h b/tests/auto/client/shared/xdgshell.h
index 1a01ea1e..ca19c293 100644
--- a/tests/auto/client/shared/xdgshell.h
+++ b/tests/auto/client/shared/xdgshell.h
@@ -51,6 +51,7 @@ public:
QVector<XdgSurface *> m_xdgSurfaces;
XdgToplevel *toplevel(int i = 0);
XdgPopup *popup(int i = 0);
+ XdgPopup *m_topmostGrabbingPopup = nullptr;
CoreCompositor *m_compositor = nullptr;
signals:
@@ -75,8 +76,13 @@ public:
void send_configure(uint serial) = delete; // Use the one below instead, as it tracks state
void sendConfigure(uint serial);
uint sendConfigure();
+ bool isTopmostGrabbingPopup() const { return m_popup && m_xdgWmBase->m_topmostGrabbingPopup == m_popup; }
+ bool isValidPopupGrabParent() const { return isTopmostGrabbingPopup() || (m_toplevel && !m_xdgWmBase->m_topmostGrabbingPopup); }
+
+ // Role objects
XdgToplevel *m_toplevel = nullptr;
XdgPopup *m_popup = nullptr;
+
XdgWmBase *m_xdgWmBase = nullptr;
Surface *m_surface = nullptr;
bool m_configureSent = false;
@@ -86,6 +92,7 @@ public:
struct DoubleBufferedState {
QRect windowGeometry = {0, 0, 0, 0};
} m_pending, m_committed;
+ QVector<XdgPopup *> m_popups;
public slots:
void verifyConfigured() { QVERIFY(m_configureSent); }
@@ -98,7 +105,7 @@ protected:
void xdg_surface_get_toplevel(Resource *resource, uint32_t id) override;
void xdg_surface_get_popup(Resource *resource, uint32_t id, ::wl_resource *parent, ::wl_resource *positioner) override;
void xdg_surface_destroy_resource(Resource *resource) override;
- void xdg_surface_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); }
+ void xdg_surface_destroy(Resource *resource) override;
void xdg_surface_set_window_geometry(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override;
void xdg_surface_ack_configure(Resource *resource, uint32_t serial) override;
};
@@ -126,14 +133,17 @@ protected:
class XdgPopup : public QtWaylandServer::xdg_popup
{
public:
- explicit XdgPopup(XdgSurface *xdgSurface, int id, int version = 1);
+ explicit XdgPopup(XdgSurface *xdgSurface, XdgSurface *parent, int id, int version = 1);
void sendConfigure(const QRect &geometry);
+ uint sendCompleteConfigure(const QRect &geometry);
Surface *surface() { return m_xdgSurface->m_surface; }
XdgSurface *m_xdgSurface = nullptr;
+ XdgSurface *m_parentXdgSurface = nullptr;
bool m_grabbed = false;
uint m_grabSerial = 0;
protected:
void xdg_popup_grab(Resource *resource, ::wl_resource *seat, uint32_t serial) override;
+ void xdg_popup_destroy(Resource *resource) override;
};
} // namespace MockCompositor
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
index de034101..32b62689 100644
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
@@ -42,6 +42,7 @@ private slots:
void configureSize();
void configureStates();
void popup();
+ void tooltipOnPopup();
void pongs();
void minMaxSize();
void windowGeometry();
@@ -252,6 +253,85 @@ void tst_xdgshell::popup()
});
}
+void tst_xdgshell::tooltipOnPopup()
+{
+ class Popup : public QRasterWindow {
+ public:
+ explicit Popup(QWindow *parent) {
+ setTransientParent(parent);
+ setFlags(Qt::Popup);
+ resize(100, 100);
+ show();
+ }
+ void mousePressEvent(QMouseEvent *event) override {
+ QRasterWindow::mousePressEvent(event);
+ m_tooltip = new QRasterWindow;
+ m_tooltip->setTransientParent(this);
+ m_tooltip->setFlags(Qt::ToolTip);
+ m_tooltip->resize(100, 100);
+ m_tooltip->show();
+ }
+ QWindow *m_tooltip = nullptr;
+ };
+
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *event) override {
+ QRasterWindow::mousePressEvent(event);
+ m_popup = new Popup(this);
+ }
+ Popup *m_popup = nullptr;
+ };
+
+ 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);
+
+ exec([=] {
+ auto *surface = xdgPopup()->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();
+ });
+
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
+ exec([=] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_xdgSurface->m_committedConfigureSerial);
+ QCOMPOSITOR_TRY_VERIFY(!xdgPopup(1)->m_grabbed);
+
+ // Close the middle popup (according protocol this should also destroy any nested popups)
+ window.m_popup->close();
+
+ // Close order is verified in XdgSurface::xdg_surface_destroy
+
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
+}
+
void tst_xdgshell::pongs()
{
QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong);