diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/client/client/tst_client.cpp | 20 | ||||
-rw-r--r-- | tests/auto/client/shared/mockcompositor.cpp | 5 | ||||
-rw-r--r-- | tests/auto/client/shared/mockcompositor.h | 14 | ||||
-rw-r--r-- | tests/auto/client/shared/mockxdgshellv6.cpp | 35 | ||||
-rw-r--r-- | tests/auto/client/shared/mockxdgshellv6.h | 5 | ||||
-rw-r--r-- | tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp | 189 |
6 files changed, 261 insertions, 7 deletions
diff --git a/tests/auto/client/client/tst_client.cpp b/tests/auto/client/client/tst_client.cpp index 05b8bac1a..7a7c7fa85 100644 --- a/tests/auto/client/client/tst_client.cpp +++ b/tests/auto/client/client/tst_client.cpp @@ -172,6 +172,7 @@ private slots: void windowScreens(); void removePrimaryScreen(); void createDestroyWindow(); + void activeWindowFollowsKeyboardFocus(); void events(); void backingStore(); void touchDrag(); @@ -313,7 +314,7 @@ void tst_WaylandClient::createDestroyWindow() QTRY_VERIFY(!compositor->surface()); } -void tst_WaylandClient::events() +void tst_WaylandClient::activeWindowFollowsKeyboardFocus() { TestWindow window; window.show(); @@ -324,6 +325,9 @@ void tst_WaylandClient::events() QTRY_VERIFY(window.isExposed()); + if (compositor->xdgToplevelV6()) + QSKIP("On xdg-shell v6 focus is handled by configure events"); + QCOMPARE(window.focusInEventCount, 0); compositor->setKeyboardFocus(surface); QTRY_COMPARE(window.focusInEventCount, 1); @@ -333,9 +337,21 @@ void tst_WaylandClient::events() compositor->setKeyboardFocus(QSharedPointer<MockSurface>(nullptr)); QTRY_COMPARE(window.focusOutEventCount, 1); QTRY_COMPARE(QGuiApplication::focusWindow(), static_cast<QWindow *>(nullptr)); +} + +void tst_WaylandClient::events() +{ + TestWindow window; + window.show(); + + QSharedPointer<MockSurface> surface; + QTRY_VERIFY(surface = compositor->surface()); + compositor->sendShellSurfaceConfigure(surface); + + QTRY_VERIFY(window.isExposed()); compositor->setKeyboardFocus(surface); - QTRY_COMPARE(window.focusInEventCount, 2); + QTRY_COMPARE(window.focusInEventCount, 1); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); uint keyCode = 80; // arbitrarily chosen diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp index 9ef08ad95..11b40d9fc 100644 --- a/tests/auto/client/shared/mockcompositor.cpp +++ b/tests/auto/client/shared/mockcompositor.cpp @@ -236,11 +236,14 @@ void MockCompositor::sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface processCommand(command); } -void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size) +void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size, const QVector<uint> &states) { Command command = makeCommand(Impl::Compositor::sendXdgToplevelV6Configure, m_compositor); command.parameters << QVariant::fromValue(toplevel); command.parameters << QVariant::fromValue(size); + auto statesBytes = QByteArray::fromRawData(reinterpret_cast<const char *>(states.data()), + states.size() * static_cast<int>(sizeof(uint))); + command.parameters << statesBytes; processCommand(command); } diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h index 34c20943a..d3568c165 100644 --- a/tests/auto/client/shared/mockcompositor.h +++ b/tests/auto/client/shared/mockcompositor.h @@ -175,12 +175,21 @@ private: Q_DECLARE_METATYPE(QSharedPointer<MockIviSurface>) -class MockXdgToplevelV6 +class MockXdgToplevelV6 : public QObject { + Q_OBJECT public: Impl::XdgToplevelV6 *handle() const { return m_toplevel; } void sendConfigure(const QSharedPointer<MockXdgToplevelV6> toplevel); + +signals: + uint setMinimizedRequested(); + uint setMaximizedRequested(); + uint unsetMaximizedRequested(); + uint setFullscreenRequested(); + uint unsetFullscreenRequested(); + private: MockXdgToplevelV6(Impl::XdgToplevelV6 *toplevel) : m_toplevel(toplevel) {} friend class Impl::Compositor; @@ -234,7 +243,8 @@ public: void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output); void sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size = QSize(0, 0)); void sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface> iviSurface, const QSize &size); - void sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size = QSize(0, 0)); + void sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size = QSize(0, 0), + const QVector<uint> &states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED }); void waitForStartDrag(); QSharedPointer<MockSurface> surface(); diff --git a/tests/auto/client/shared/mockxdgshellv6.cpp b/tests/auto/client/shared/mockxdgshellv6.cpp index 39e03296d..6f6f0b905 100644 --- a/tests/auto/client/shared/mockxdgshellv6.cpp +++ b/tests/auto/client/shared/mockxdgshellv6.cpp @@ -39,8 +39,8 @@ void Compositor::sendXdgToplevelV6Configure(void *data, const QList<QVariant> &p Q_ASSERT(toplevel && toplevel->resource()); QSize size = parameters.at(1).toSize(); Q_ASSERT(size.isValid()); - QByteArray states; - toplevel->send_configure(size.width(), size.height(), states); + auto statesBytes = parameters.at(2).toByteArray(); + toplevel->send_configure(size.width(), size.height(), statesBytes); toplevel->xdgSurface()->send_configure(compositor->nextSerial()); } @@ -87,6 +87,37 @@ void XdgToplevelV6::zxdg_toplevel_v6_destroy(QtWaylandServer::zxdg_toplevel_v6:: wl_resource_destroy(resource->handle); } +void XdgToplevelV6::zxdg_toplevel_v6_set_minimized(QtWaylandServer::zxdg_toplevel_v6::Resource *resource) +{ + Q_UNUSED(resource); + emit m_mockToplevel->setMinimizedRequested(); +} + +void XdgToplevelV6::zxdg_toplevel_v6_set_maximized(QtWaylandServer::zxdg_toplevel_v6::Resource *resource) +{ + Q_UNUSED(resource); + emit m_mockToplevel->setMaximizedRequested(); +} + +void XdgToplevelV6::zxdg_toplevel_v6_unset_maximized(QtWaylandServer::zxdg_toplevel_v6::Resource *resource) +{ + Q_UNUSED(resource); + emit m_mockToplevel->unsetMaximizedRequested(); +} + +void XdgToplevelV6::zxdg_toplevel_v6_set_fullscreen(QtWaylandServer::zxdg_toplevel_v6::Resource *resource, wl_resource *output) +{ + Q_UNUSED(resource); + Q_UNUSED(output); + emit m_mockToplevel->setFullscreenRequested(); +} + +void XdgToplevelV6::zxdg_toplevel_v6_unset_fullscreen(QtWaylandServer::zxdg_toplevel_v6::Resource *resource) +{ + Q_UNUSED(resource); + emit m_mockToplevel->unsetFullscreenRequested(); +} + void Impl::XdgShellV6::zxdg_shell_v6_get_xdg_surface(QtWaylandServer::zxdg_shell_v6::Resource *resource, uint32_t id, wl_resource *surface) { new XdgSurfaceV6(this, Surface::fromResource(surface), resource->client(), id); diff --git a/tests/auto/client/shared/mockxdgshellv6.h b/tests/auto/client/shared/mockxdgshellv6.h index 92b808ba8..faadb785a 100644 --- a/tests/auto/client/shared/mockxdgshellv6.h +++ b/tests/auto/client/shared/mockxdgshellv6.h @@ -74,6 +74,11 @@ public: protected: void zxdg_toplevel_v6_destroy_resource(Resource *) override { delete this; } void zxdg_toplevel_v6_destroy(Resource *resource) override; + void zxdg_toplevel_v6_set_minimized(Resource *resource) override; + void zxdg_toplevel_v6_set_maximized(Resource *resource) override; + void zxdg_toplevel_v6_unset_maximized(Resource *resource) override; + void zxdg_toplevel_v6_set_fullscreen(Resource *resource, struct ::wl_resource *output) override; + void zxdg_toplevel_v6_unset_fullscreen(Resource *resource) override; private: XdgSurfaceV6 *m_xdgSurface = nullptr; diff --git a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp index 364cd1099..0f72f58a9 100644 --- a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp +++ b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp @@ -42,6 +42,7 @@ static const QSize screenSize(1600, 1200); class TestWindow : public QWindow { + Q_OBJECT public: TestWindow() { @@ -49,6 +50,16 @@ public: setGeometry(0, 0, 32, 32); create(); } + + bool event(QEvent *event) override + { + if (event->type() == QEvent::WindowStateChange) + emit windowStateChangeEventReceived(static_cast<QWindowStateChangeEvent *>(event)->oldState()); + return QWindow::event(event); + } + +signals: + void windowStateChangeEventReceived(uint oldState); }; class tst_WaylandClientXdgShellV6 : public QObject @@ -58,6 +69,7 @@ public: tst_WaylandClientXdgShellV6(MockCompositor *c) : m_compositor(c) { + qRegisterMetaType<Qt::WindowState>(); QSocketNotifier *notifier = new QSocketNotifier(m_compositor->waylandFileDescriptor(), QSocketNotifier::Read, this); connect(notifier, &QSocketNotifier::activated, this, &tst_WaylandClientXdgShellV6::processWaylandEvents); // connect to the event dispatcher to make sure to flush out the outgoing message queue @@ -82,6 +94,11 @@ public slots: private slots: void createDestroyWindow(); void configure(); + void showMinimized(); + void setMinimized(); + void unsetMaximized(); + void focusWindowFollowsConfigure(); + void windowStateChangedEvents(); private: MockCompositor *m_compositor = nullptr; @@ -118,10 +135,182 @@ void tst_WaylandClientXdgShellV6::configure() QSharedPointer<MockXdgToplevelV6> toplevel; QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6()); + const QSize newSize(123, 456); m_compositor->sendXdgToplevelV6Configure(toplevel, newSize); QTRY_VERIFY(window.isExposed()); + QTRY_COMPARE(window.visibility(), QWindow::Windowed); + QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), newSize)); + + m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED }); + QTRY_COMPARE(window.visibility(), QWindow::Maximized); + QTRY_COMPARE(window.windowStates(), Qt::WindowMaximized); + QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), screenSize)); + + m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN }); + QTRY_COMPARE(window.visibility(), QWindow::FullScreen); + QTRY_COMPARE(window.windowStates(), Qt::WindowFullScreen); + QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), screenSize)); + + //The window should remember it's original size + m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED }); + QTRY_COMPARE(window.visibility(), QWindow::Windowed); + QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); + QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), newSize)); +} + +void tst_WaylandClientXdgShellV6::showMinimized() +{ + // On xdg-shell v6 there's really no way for the compositor to tell the window if it's minimized + // There are wl_surface.enter events and so on, but there's really no way to differentiate + // between a window preview and an unminimized window. + TestWindow window; + window.showMinimized(); + QCOMPARE(window.windowStates(), Qt::WindowMinimized); // should return minimized until + QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); // rejected by handleWindowStateChanged +} + +void tst_WaylandClientXdgShellV6::setMinimized() +{ + TestWindow window; + window.show(); + + QSharedPointer<MockXdgToplevelV6> toplevel; + QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6()); + + m_compositor->sendXdgToplevelV6Configure(toplevel); + QTRY_COMPARE(window.visibility(), QWindow::Windowed); + QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); + + QSignalSpy setMinimizedSpy(toplevel.data(), SIGNAL(setMinimizedRequested())); + QSignalSpy windowStateChangeSpy(&window, SIGNAL(windowStateChangeEventReceived(uint))); + + window.setVisibility(QWindow::Minimized); + QCOMPARE(window.visibility(), QWindow::Minimized); + QCOMPARE(window.windowStates(), Qt::WindowMinimized); + QTRY_COMPARE(setMinimizedSpy.count(), 1); + { + QTRY_VERIFY(windowStateChangeSpy.count() > 0); + Qt::WindowStates oldStates(windowStateChangeSpy.takeFirst().at(0).toUInt()); + QCOMPARE(oldStates, Qt::WindowNoState); + } + + // In the meantime the compositor may minimize, do nothing or reshow the window without + // telling us. + + QTRY_COMPARE(window.visibility(), QWindow::Windowed); // verify that we don't know anything + QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); + { + QTRY_COMPARE(windowStateChangeSpy.count(), 1); + Qt::WindowStates oldStates(windowStateChangeSpy.takeFirst().at(0).toUInt()); + QCOMPARE(oldStates, Qt::WindowNoState); // because the window never was minimized + } + + // Setting visibility again should send another set_minimized request + window.setVisibility(QWindow::Minimized); + QTRY_COMPARE(setMinimizedSpy.count(), 2); +} + +void tst_WaylandClientXdgShellV6::unsetMaximized() +{ + TestWindow window; + window.show(); + + QSharedPointer<MockXdgToplevelV6> toplevel; + QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6()); + + QSignalSpy unsetMaximizedSpy(toplevel.data(), SIGNAL(unsetMaximizedRequested())); + + QSignalSpy windowStateChangedSpy(&window, SIGNAL(windowStateChanged(Qt::WindowState))); + + m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED }); + + QTRY_COMPARE(windowStateChangedSpy.count(), 1); + QCOMPARE(windowStateChangedSpy.takeFirst().at(0).toUInt(), Qt::WindowMaximized); + + window.setWindowStates(Qt::WindowNoState); + + QTRY_COMPARE(unsetMaximizedSpy.count(), 1); + QTRY_COMPARE(windowStateChangedSpy.count(), 1); + QCOMPARE(windowStateChangedSpy.takeFirst().at(0).toUInt(), Qt::WindowNoState); + + m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), {}); + + QTRY_COMPARE(windowStateChangedSpy.count(), 1); + QCOMPARE(windowStateChangedSpy.takeFirst().at(0).toUInt(), Qt::WindowNoState); +} + +void tst_WaylandClientXdgShellV6::focusWindowFollowsConfigure() +{ + TestWindow window; + window.show(); + + QSharedPointer<MockXdgToplevelV6> toplevel; + QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6()); + QTRY_VERIFY(!window.isActive()); + + QSignalSpy windowStateChangeSpy(&window, SIGNAL(windowStateChangeEventReceived(uint))); + + m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED }); + QTRY_VERIFY(window.isActive()); + + m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), {}); + QTRY_VERIFY(!window.isActive()); +} + +void tst_WaylandClientXdgShellV6::windowStateChangedEvents() +{ + TestWindow window; + window.show(); + + QSharedPointer<MockXdgToplevelV6> toplevel; + QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6()); + + QSignalSpy eventSpy(&window, SIGNAL(windowStateChangeEventReceived(uint))); + QSignalSpy signalSpy(&window, SIGNAL(windowStateChanged(Qt::WindowState))); + + m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED }); + + QTRY_COMPARE(window.windowStates(), Qt::WindowMaximized); + QTRY_COMPARE(window.windowState(), Qt::WindowMaximized); + { + QTRY_COMPARE(eventSpy.count(), 1); + Qt::WindowStates oldStates(eventSpy.takeFirst().at(0).toUInt()); + QCOMPARE(oldStates, Qt::WindowNoState); + + QTRY_COMPARE(signalSpy.count(), 1); + uint newState = signalSpy.takeFirst().at(0).toUInt(); + QCOMPARE(newState, Qt::WindowMaximized); + } + + m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN }); + + QTRY_COMPARE(window.windowStates(), Qt::WindowFullScreen); + QTRY_COMPARE(window.windowState(), Qt::WindowFullScreen); + { + QTRY_COMPARE(eventSpy.count(), 1); + Qt::WindowStates oldStates(eventSpy.takeFirst().at(0).toUInt()); + QCOMPARE(oldStates, Qt::WindowMaximized); + + QTRY_COMPARE(signalSpy.count(), 1); + uint newState = signalSpy.takeFirst().at(0).toUInt(); + QCOMPARE(newState, Qt::WindowFullScreen); + } + + m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), {}); + + QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); + QTRY_COMPARE(window.windowState(), Qt::WindowNoState); + { + QTRY_COMPARE(eventSpy.count(), 1); + Qt::WindowStates oldStates(eventSpy.takeFirst().at(0).toUInt()); + QCOMPARE(oldStates, Qt::WindowFullScreen); + + QTRY_COMPARE(signalSpy.count(), 1); + uint newState = signalSpy.takeFirst().at(0).toUInt(); + QCOMPARE(newState, Qt::WindowNoState); + } } int main(int argc, char **argv) |