From 996c828da3f32fe3c6f4c36191c778b0a3b19822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 14 Oct 2015 09:58:16 +0200 Subject: [PATCH] [autotest/wayland] Add a test for quick tiling Wayland clients Base test verifies the quick tile positions. No maximization or direct state changes tested yet. Required to have Toplevel and AbstractClient exported. Otherwise we cannot use the SignalSpy. --- abstract_client.h | 2 +- autotests/wayland/CMakeLists.txt | 9 + autotests/wayland/quick_tiling_test.cpp | 222 ++++++++++++++++++++++++ toplevel.h | 2 +- 4 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 autotests/wayland/quick_tiling_test.cpp diff --git a/abstract_client.h b/abstract_client.h index 95c53b482c..96b62b0469 100644 --- a/abstract_client.h +++ b/abstract_client.h @@ -49,7 +49,7 @@ namespace Decoration class DecorationPalette; } -class AbstractClient : public Toplevel +class KWIN_EXPORT AbstractClient : public Toplevel { Q_OBJECT /** diff --git a/autotests/wayland/CMakeLists.txt b/autotests/wayland/CMakeLists.txt index ac3c1fe5a1..a7343e58aa 100644 --- a/autotests/wayland/CMakeLists.txt +++ b/autotests/wayland/CMakeLists.txt @@ -17,3 +17,12 @@ add_executable(testTransientNoInput ${testTransientNoInput_SRCS}) target_link_libraries( testTransientNoInput kwin Qt5::Test) add_test(kwin-testTransientNoInput testTransientNoInput) ecm_mark_as_test(testTransientNoInput) + +######################################################## +# Quick Tiling test +######################################################## +set( testQuickTiling_SRCS quick_tiling_test.cpp kwin_wayland_test.cpp ) +add_executable(testQuickTiling ${testQuickTiling_SRCS}) +target_link_libraries( testQuickTiling kwin Qt5::Test) +add_test(kwin-testQuickTiling testQuickTiling) +ecm_mark_as_test(testQuickTiling) diff --git a/autotests/wayland/quick_tiling_test.cpp b/autotests/wayland/quick_tiling_test.cpp new file mode 100644 index 0000000000..fde6d90172 --- /dev/null +++ b/autotests/wayland/quick_tiling_test.cpp @@ -0,0 +1,222 @@ +/******************************************************************** +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "kwin_wayland_test.h" +#include "abstract_backend.h" +#include "abstract_client.h" +#include "screens.h" +#include "wayland_server.h" +#include "workspace.h" +#include "shell_client.h" + +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(KWin::AbstractClient::QuickTileMode) + +namespace KWin +{ + +static const QString s_socketName = QStringLiteral("wayland_test_kwin_quick_tiling-0"); + +class QuickTilingTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void init(); + void cleanup(); + void testQuickTiling_data(); + void testQuickTiling(); + +private: + KWayland::Client::ConnectionThread *m_connection = nullptr; + KWayland::Client::Compositor *m_compositor = nullptr; + KWayland::Client::ShmPool *m_shm = nullptr; + KWayland::Client::Shell *m_shell = nullptr; + KWayland::Client::EventQueue *m_queue = nullptr; + QThread *m_thread = nullptr; +}; + +void QuickTilingTest::initTestCase() +{ + qRegisterMetaType(); + QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); + QVERIFY(workspaceCreatedSpy.isValid()); + waylandServer()->backend()->setInitialWindowSize(QSize(1280, 1024)); + waylandServer()->init(s_socketName.toLocal8Bit()); + kwinApp()->start(); + QVERIFY(workspaceCreatedSpy.wait()); +} + +void QuickTilingTest::init() +{ + using namespace KWayland::Client; + // setup connection + m_connection = new ConnectionThread; + QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected); + QVERIFY(connectedSpy.isValid()); + m_connection->setSocketName(s_socketName); + + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait()); + + m_queue = new EventQueue(this); + QVERIFY(!m_queue->isValid()); + m_queue->setup(m_connection); + QVERIFY(m_queue->isValid()); + + Registry registry; + registry.setEventQueue(m_queue); + QSignalSpy compositorSpy(®istry, &Registry::compositorAnnounced); + QSignalSpy shmSpy(®istry, &Registry::shmAnnounced); + QSignalSpy shellSpy(®istry, &Registry::shellAnnounced); + QSignalSpy allAnnounced(®istry, &Registry::interfacesAnnounced); + QVERIFY(allAnnounced.isValid()); + QVERIFY(shmSpy.isValid()); + QVERIFY(shellSpy.isValid()); + QVERIFY(compositorSpy.isValid()); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + registry.setup(); + QVERIFY(allAnnounced.wait()); + QVERIFY(!compositorSpy.isEmpty()); + QVERIFY(!shmSpy.isEmpty()); + QVERIFY(!shellSpy.isEmpty()); + + m_compositor = registry.createCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value(), this); + QVERIFY(m_compositor->isValid()); + m_shm = registry.createShmPool(shmSpy.first().first().value(), shmSpy.first().last().value(), this); + QVERIFY(m_shm->isValid()); + m_shell = registry.createShell(shellSpy.first().first().value(), shellSpy.first().last().value(), this); + QVERIFY(m_shell->isValid()); +} + +void QuickTilingTest::cleanup() +{ + delete m_compositor; + m_compositor = nullptr; + delete m_shm; + m_shm = nullptr; + delete m_shell; + m_shell = nullptr; + delete m_queue; + m_queue = nullptr; + if (m_thread) { + m_thread->quit(); + m_thread->wait(); + delete m_thread; + m_thread = nullptr; + } + +} + +void QuickTilingTest::testQuickTiling_data() +{ + QTest::addColumn("mode"); + QTest::addColumn("expectedGeometry"); + +#define FLAG(name) AbstractClient::QuickTileMode(AbstractClient::QuickTile##name) + + QTest::newRow("left") << FLAG(Left) << QRect(0, 0, 640, 1024); + QTest::newRow("top") << FLAG(Top) << QRect(0, 0, 1280, 512); + QTest::newRow("right") << FLAG(Right) << QRect(640, 0, 640, 1024); + QTest::newRow("bottom") << FLAG(Bottom) << QRect(0, 512, 1280, 512); + + QTest::newRow("top left") << (FLAG(Left) | FLAG(Top)) << QRect(0, 0, 640, 512); + QTest::newRow("top right") << (FLAG(Right) | FLAG(Top)) << QRect(640, 0, 640, 512); + QTest::newRow("bottom left") << (FLAG(Left) | FLAG(Bottom)) << QRect(0, 512, 640, 512); + QTest::newRow("bottom right") << (FLAG(Right) | FLAG(Bottom)) << QRect(640, 512, 640, 512); + +#undef FLAG +} + +void QuickTilingTest::testQuickTiling() +{ + using namespace KWayland::Client; + + QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded); + QVERIFY(clientAddedSpy.isValid()); + + QScopedPointer surface(m_compositor->createSurface()); + QVERIFY(!surface.isNull()); + + QScopedPointer shellSurface(m_shell->createSurface(surface.data())); + QVERIFY(!shellSurface.isNull()); + QSignalSpy sizeChangeSpy(shellSurface.data(), &ShellSurface::sizeChanged); + QVERIFY(sizeChangeSpy.isValid()); + // let's render + QImage img(QSize(100, 50), QImage::Format_ARGB32); + img.fill(Qt::blue); + surface->attachBuffer(m_shm->createBuffer(img)); + surface->damage(QRect(0, 0, 100, 50)); + surface->commit(Surface::CommitFlag::None); + + m_connection->flush(); + QVERIFY(clientAddedSpy.wait()); + AbstractClient *c = workspace()->activeClient(); + QVERIFY(c); + QCOMPARE(clientAddedSpy.first().first().value(), c); + QCOMPARE(c->geometry(), QRect(0, 0, 100, 50)); + QCOMPARE(c->quickTileMode(), AbstractClient::QuickTileNone); + QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged); + QVERIFY(quickTileChangedSpy.isValid()); + QSignalSpy geometryChangedSpy(c, &AbstractClient::geometryChanged); + QVERIFY(geometryChangedSpy.isValid()); + + QFETCH(AbstractClient::QuickTileMode, mode); + QFETCH(QRect, expectedGeometry); + c->setQuickTileMode(mode, true); + QCOMPARE(quickTileChangedSpy.count(), 1); + // at this point the geometry did not yet change + QCOMPARE(c->geometry(), QRect(0, 0, 100, 50)); + // but quick tile mode already changed + QCOMPARE(c->quickTileMode(), mode); + + // but we got requested a new geometry + QVERIFY(sizeChangeSpy.wait()); + QCOMPARE(sizeChangeSpy.count(), 1); + QCOMPARE(sizeChangeSpy.first().first().toSize(), expectedGeometry.size()); + + // attach a new image + img = QImage(expectedGeometry.size(), QImage::Format_ARGB32); + img.fill(Qt::red); + surface->attachBuffer(m_shm->createBuffer(img)); + surface->damage(QRect(QPoint(0, 0), expectedGeometry.size())); + surface->commit(Surface::CommitFlag::None); + m_connection->flush(); + + QVERIFY(geometryChangedSpy.wait()); + QCOMPARE(geometryChangedSpy.count(), 1); + QCOMPARE(c->geometry(), expectedGeometry); +} + +} + +WAYLANTEST_MAIN(KWin::QuickTilingTest) +#include "quick_tiling_test.moc" diff --git a/toplevel.h b/toplevel.h index 9b372c1194..1af3274445 100644 --- a/toplevel.h +++ b/toplevel.h @@ -67,7 +67,7 @@ enum class ReleaseReason { KWinShutsDown ///< Release on KWin Shutdown (window still valid) }; -class Toplevel +class KWIN_EXPORT Toplevel : public QObject { Q_OBJECT