From 50ba61f027a7b3bf7f168cc11f2f291b523f60a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Tue, 26 Aug 2014 16:07:39 +0200 Subject: [PATCH] [kwin_wayland] Initial addition of the WaylandServer module So far this new module contains: * Display * OutputInterface Display manages the server socket and server event loop. In general it's the entry point to any part of the server. OutputInterface is the abstraction for the wl_output interface on server side. An OutputInterface is created through the Display. The auto tests for ConnectionThread and Output are adjusted to use the internal server instead of starting Weston. Especially the Output test could be extended to test much more as we have absolute control over the server now. --- .../test_wayland_connection_thread.cpp | 70 ++--- src/wayland/test_wayland_output.cpp | 273 +++++++++++++++--- 2 files changed, 245 insertions(+), 98 deletions(-) diff --git a/src/wayland/test_wayland_connection_thread.cpp b/src/wayland/test_wayland_connection_thread.cpp index c045e5cfcd..c60b63c282 100644 --- a/src/wayland/test_wayland_connection_thread.cpp +++ b/src/wayland/test_wayland_connection_thread.cpp @@ -21,6 +21,7 @@ along with this program. If not, see . #include // KWin #include "../../wayland_client/connection_thread.h" +#include "../../wayland_server/display.h" // Wayland #include @@ -39,60 +40,36 @@ private Q_SLOTS: void testConnectionThread(); private: - QProcess *m_westonProcess; + KWin::WaylandServer::Display *m_display; }; static const QString s_socketName = QStringLiteral("kwin-test-wayland-connection-0"); TestWaylandConnectionThread::TestWaylandConnectionThread(QObject *parent) : QObject(parent) - , m_westonProcess(nullptr) + , m_display(nullptr) { } void TestWaylandConnectionThread::init() { - QVERIFY(!m_westonProcess); - // starts weston - m_westonProcess = new QProcess(this); - m_westonProcess->setProgram(QStringLiteral("weston")); - - m_westonProcess->setArguments(QStringList({QStringLiteral("--socket=%1").arg(s_socketName), QStringLiteral("--use-pixman")})); - m_westonProcess->start(); - QVERIFY(m_westonProcess->waitForStarted()); - - // wait for the socket to appear - QDir runtimeDir(qgetenv("XDG_RUNTIME_DIR")); - if (runtimeDir.exists(s_socketName)) { - return; - } - QFileSystemWatcher *socketWatcher = new QFileSystemWatcher(QStringList({runtimeDir.absolutePath()}), this); - QSignalSpy socketSpy(socketWatcher, SIGNAL(directoryChanged(QString))); - - // limit to maximum of 10 waits - for (int i = 0; i < 10; ++i) { - QVERIFY(socketSpy.wait()); - if (runtimeDir.exists(s_socketName)) { - delete socketWatcher; - return; - } - } + using namespace KWin::WaylandServer; + delete m_display; + m_display = new Display(this); + QSignalSpy displayRunning(m_display, SIGNAL(runningChanged(bool))); + m_display->setSocketName(s_socketName); + m_display->start(); + QVERIFY(m_display->isRunning()); } void TestWaylandConnectionThread::cleanup() { - // terminates weston - m_westonProcess->terminate(); - QVERIFY(m_westonProcess->waitForFinished()); - delete m_westonProcess; - m_westonProcess = nullptr; + delete m_display; + m_display = nullptr; } void TestWaylandConnectionThread::testInitConnectionNoThread() { - if (m_westonProcess->state() != QProcess::Running) { - QSKIP("This test requires a running wayland server"); - } QScopedPointer connection(new KWin::Wayland::ConnectionThread); QCOMPARE(connection->socketName(), QStringLiteral("wayland-0")); connection->setSocketName(s_socketName); @@ -109,9 +86,6 @@ void TestWaylandConnectionThread::testInitConnectionNoThread() void TestWaylandConnectionThread::testConnectionFailure() { - if (m_westonProcess->state() != QProcess::Running) { - QSKIP("This test requires a running wayland server"); - } QScopedPointer connection(new KWin::Wayland::ConnectionThread); connection->setSocketName(QStringLiteral("kwin-test-socket-does-not-exist")); @@ -148,9 +122,6 @@ static const struct wl_registry_listener s_registryListener = { void TestWaylandConnectionThread::testConnectionThread() { - if (m_westonProcess->state() != QProcess::Running) { - QSKIP("This test requires a running wayland server"); - } QScopedPointer connection(new KWin::Wayland::ConnectionThread); connection->setSocketName(s_socketName); @@ -177,7 +148,10 @@ void TestWaylandConnectionThread::testConnectionThread() wl_registry_add_listener(registry, &s_registryListener, this); wl_display_flush(display); - QVERIFY(eventsSpy.wait()); + if (eventsSpy.isEmpty()) { + QVERIFY(eventsSpy.wait()); + } + QVERIFY(!eventsSpy.isEmpty()); wl_registry_destroy(registry); wl_event_queue_destroy(queue); @@ -189,9 +163,6 @@ void TestWaylandConnectionThread::testConnectionThread() void TestWaylandConnectionThread::testConnectionDieing() { - if (m_westonProcess->state() != QProcess::Running) { - QSKIP("This test requires a running wayland server"); - } QScopedPointer connection(new KWin::Wayland::ConnectionThread); QSignalSpy connectedSpy(connection.data(), SIGNAL(connected())); connection->setSocketName(s_socketName); @@ -200,8 +171,8 @@ void TestWaylandConnectionThread::testConnectionDieing() QVERIFY(connection->display()); QSignalSpy diedSpy(connection.data(), SIGNAL(connectionDied())); - m_westonProcess->terminate(); - QVERIFY(m_westonProcess->waitForFinished()); + m_display->terminate(); + QVERIFY(!m_display->isRunning()); QVERIFY(diedSpy.wait()); QCOMPARE(diedSpy.count(), 1); QVERIFY(!connection->display()); @@ -209,9 +180,8 @@ void TestWaylandConnectionThread::testConnectionDieing() connectedSpy.clear(); QVERIFY(connectedSpy.isEmpty()); // restarts the server - delete m_westonProcess; - m_westonProcess = nullptr; - init(); + m_display->start(); + QVERIFY(m_display->isRunning()); if (connectedSpy.count() == 0) { QVERIFY(connectedSpy.wait()); } diff --git a/src/wayland/test_wayland_output.cpp b/src/wayland/test_wayland_output.cpp index 1f9fe959b4..854512bbcc 100644 --- a/src/wayland/test_wayland_output.cpp +++ b/src/wayland/test_wayland_output.cpp @@ -23,6 +23,8 @@ along with this program. If not, see . #include "../../wayland_client/connection_thread.h" #include "../../wayland_client/output.h" #include "../../wayland_client/registry.h" +#include "../../wayland_server/display.h" +#include "../../wayland_server/output_interface.h" // Wayland #include @@ -36,79 +38,91 @@ private Q_SLOTS: void cleanup(); void testRegistry(); + void testModeChanges(); + void testScaleChange(); - // TODO: add tests for removal - requires more control over the compositor + void testSubPixel_data(); + void testSubPixel(); + + void testTransform_data(); + void testTransform(); private: - QProcess *m_westonProcess; + KWin::WaylandServer::Display *m_display; + KWin::WaylandServer::OutputInterface *m_serverOutput; + KWin::Wayland::ConnectionThread *m_connection; + QThread *m_thread; }; static const QString s_socketName = QStringLiteral("kwin-test-wayland-output-0"); TestWaylandOutput::TestWaylandOutput(QObject *parent) : QObject(parent) - , m_westonProcess(nullptr) + , m_display(nullptr) + , m_serverOutput(nullptr) + , m_connection(nullptr) + , m_thread(nullptr) { } void TestWaylandOutput::init() { - QVERIFY(!m_westonProcess); - // starts weston - m_westonProcess = new QProcess(this); - m_westonProcess->setProgram(QStringLiteral("weston")); + using namespace KWin::WaylandServer; + delete m_display; + m_display = new Display(this); + m_display->setSocketName(s_socketName); + m_display->start(); + QVERIFY(m_display->isRunning()); - m_westonProcess->setArguments(QStringList({QStringLiteral("--socket=%1").arg(s_socketName), - QStringLiteral("--use-pixman"), - QStringLiteral("--width=1024"), - QStringLiteral("--height=768")})); - m_westonProcess->start(); - QVERIFY(m_westonProcess->waitForStarted()); + m_serverOutput = m_display->createOutput(this); + m_serverOutput->addMode(QSize(800, 600)); + m_serverOutput->addMode(QSize(1024, 768)); + m_serverOutput->addMode(QSize(1280, 1024)); + m_serverOutput->setCurrentMode(QSize(1024, 768)); + m_serverOutput->create(); - // wait for the socket to appear - QDir runtimeDir(qgetenv("XDG_RUNTIME_DIR")); - if (runtimeDir.exists(s_socketName)) { - return; - } - QFileSystemWatcher *socketWatcher = new QFileSystemWatcher(QStringList({runtimeDir.absolutePath()}), this); - QSignalSpy socketSpy(socketWatcher, SIGNAL(directoryChanged(QString))); + // setup connection + m_connection = new KWin::Wayland::ConnectionThread; + QSignalSpy connectedSpy(m_connection, SIGNAL(connected())); + m_connection->setSocketName(s_socketName); - // limit to maximum of 10 waits - for (int i = 0; i < 10; ++i) { - QVERIFY(socketSpy.wait()); - if (runtimeDir.exists(s_socketName)) { - delete socketWatcher; - return; - } - } + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait()); } void TestWaylandOutput::cleanup() { - // terminates weston - m_westonProcess->terminate(); - QVERIFY(m_westonProcess->waitForFinished()); - delete m_westonProcess; - m_westonProcess = nullptr; + if (m_thread) { + m_thread->quit(); + m_thread->wait(); + delete m_thread; + m_thread = nullptr; + } + delete m_connection; + m_connection = nullptr; + + delete m_serverOutput; + m_serverOutput = nullptr; + + delete m_display; + m_display = nullptr; } void TestWaylandOutput::testRegistry() { - if (m_westonProcess->state() != QProcess::Running) { - QSKIP("This test requires a running wayland server"); - } - KWin::Wayland::ConnectionThread connection; - QSignalSpy connectedSpy(&connection, SIGNAL(connected())); - connection.setSocketName(s_socketName); - connection.initConnection(); - QVERIFY(connectedSpy.wait()); + m_serverOutput->setGlobalPosition(QPoint(100, 50)); + m_serverOutput->setPhysicalSize(QSize(200, 100)); KWin::Wayland::Registry registry; QSignalSpy announced(®istry, SIGNAL(outputAnnounced(quint32,quint32))); - registry.create(connection.display()); + registry.create(m_connection->display()); QVERIFY(registry.isValid()); registry.setup(); - wl_display_flush(connection.display()); + wl_display_flush(m_connection->display()); QVERIFY(announced.wait()); KWin::Wayland::Output output; @@ -128,14 +142,14 @@ void TestWaylandOutput::testRegistry() QVERIFY(outputChanged.isValid()); output.setup(registry.bindOutput(announced.first().first().value(), announced.first().last().value())); - wl_display_flush(connection.display()); + wl_display_flush(m_connection->display()); QVERIFY(outputChanged.wait()); - QCOMPARE(output.geometry(), QRect(0, 0, 1024, 768)); - QCOMPARE(output.globalPosition(), QPoint(0, 0)); - QCOMPARE(output.manufacturer(), QStringLiteral("xwayland")); + QCOMPARE(output.geometry(), QRect(100, 50, 1024, 768)); + QCOMPARE(output.globalPosition(), QPoint(100, 50)); + QCOMPARE(output.manufacturer(), QStringLiteral("org.kde.kwin")); QCOMPARE(output.model(), QStringLiteral("none")); - // TODO: add test for physicalSize + QCOMPARE(output.physicalSize(), QSize(200, 100)); QCOMPARE(output.pixelSize(), QSize(1024, 768)); QCOMPARE(output.refreshRate(), 60000); QCOMPARE(output.scale(), 1); @@ -145,5 +159,168 @@ void TestWaylandOutput::testRegistry() QCOMPARE(output.transform(), KWin::Wayland::Output::Transform::Normal); } +void TestWaylandOutput::testModeChanges() +{ + KWin::Wayland::Registry registry; + QSignalSpy announced(®istry, SIGNAL(outputAnnounced(quint32,quint32))); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + registry.setup(); + wl_display_flush(m_connection->display()); + QVERIFY(announced.wait()); + + KWin::Wayland::Output output; + QSignalSpy outputChanged(&output, SIGNAL(changed())); + QVERIFY(outputChanged.isValid()); + output.setup(registry.bindOutput(announced.first().first().value(), announced.first().last().value())); + wl_display_flush(m_connection->display()); + QVERIFY(outputChanged.wait()); + + QCOMPARE(output.pixelSize(), QSize(1024, 768)); + + // change the current mode + outputChanged.clear(); + m_serverOutput->setCurrentMode(QSize(800, 600)); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.pixelSize(), QSize(800, 600)); + + // change once more + outputChanged.clear(); + m_serverOutput->setCurrentMode(QSize(1280, 1024)); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.pixelSize(), QSize(1280, 1024)); +} + +void TestWaylandOutput::testScaleChange() +{ + KWin::Wayland::Registry registry; + QSignalSpy announced(®istry, SIGNAL(outputAnnounced(quint32,quint32))); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + registry.setup(); + wl_display_flush(m_connection->display()); + QVERIFY(announced.wait()); + + KWin::Wayland::Output output; + QSignalSpy outputChanged(&output, SIGNAL(changed())); + QVERIFY(outputChanged.isValid()); + output.setup(registry.bindOutput(announced.first().first().value(), announced.first().last().value())); + wl_display_flush(m_connection->display()); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.scale(), 1); + + // change the scale + outputChanged.clear(); + m_serverOutput->setScale(2); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.scale(), 2); + + // change once more + outputChanged.clear(); + m_serverOutput->setScale(4); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.scale(), 4); +} + +void TestWaylandOutput::testSubPixel_data() +{ + using namespace KWin::Wayland; + using namespace KWin::WaylandServer; + QTest::addColumn("expected"); + QTest::addColumn("actual"); + + QTest::newRow("none") << Output::SubPixel::None << OutputInterface::SubPixel::None; + QTest::newRow("horizontal/rgb") << Output::SubPixel::HorizontalRGB << OutputInterface::SubPixel::HorizontalRGB; + QTest::newRow("horizontal/bgr") << Output::SubPixel::HorizontalBGR << OutputInterface::SubPixel::HorizontalBGR; + QTest::newRow("vertical/rgb") << Output::SubPixel::VerticalRGB << OutputInterface::SubPixel::VerticalRGB; + QTest::newRow("vertical/bgr") << Output::SubPixel::VerticalBGR << OutputInterface::SubPixel::VerticalBGR; +} + +void TestWaylandOutput::testSubPixel() +{ + using namespace KWin::Wayland; + using namespace KWin::WaylandServer; + QFETCH(OutputInterface::SubPixel, actual); + m_serverOutput->setSubPixel(actual); + + KWin::Wayland::Registry registry; + QSignalSpy announced(®istry, SIGNAL(outputAnnounced(quint32,quint32))); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + registry.setup(); + wl_display_flush(m_connection->display()); + QVERIFY(announced.wait()); + + KWin::Wayland::Output output; + QSignalSpy outputChanged(&output, SIGNAL(changed())); + QVERIFY(outputChanged.isValid()); + output.setup(registry.bindOutput(announced.first().first().value(), announced.first().last().value())); + wl_display_flush(m_connection->display()); + if (outputChanged.isEmpty()) { + QVERIFY(outputChanged.wait()); + } + + QTEST(output.subPixel(), "expected"); + + // change back to unknown + outputChanged.clear(); + m_serverOutput->setSubPixel(OutputInterface::SubPixel::Unknown); + if (outputChanged.isEmpty()) { + QVERIFY(outputChanged.wait()); + } + QCOMPARE(output.subPixel(), Output::SubPixel::Unknown); +} + +void TestWaylandOutput::testTransform_data() +{ + using namespace KWin::Wayland; + using namespace KWin::WaylandServer; + QTest::addColumn("expected"); + QTest::addColumn("actual"); + + QTest::newRow("90") << Output::Transform::Rotated90 << OutputInterface::Transform::Rotated90; + QTest::newRow("180") << Output::Transform::Rotated180 << OutputInterface::Transform::Rotated180; + QTest::newRow("270") << Output::Transform::Rotated270 << OutputInterface::Transform::Rotated270; + QTest::newRow("Flipped") << Output::Transform::Flipped << OutputInterface::Transform::Flipped; + QTest::newRow("Flipped 90") << Output::Transform::Flipped90 << OutputInterface::Transform::Flipped90; + QTest::newRow("Flipped 180") << Output::Transform::Flipped180 << OutputInterface::Transform::Flipped180; + QTest::newRow("Flipped 280") << Output::Transform::Flipped270 << OutputInterface::Transform::Flipped270; +} + +void TestWaylandOutput::testTransform() +{ + using namespace KWin::Wayland; + using namespace KWin::WaylandServer; + QFETCH(OutputInterface::Transform, actual); + m_serverOutput->setTransform(actual); + + KWin::Wayland::Registry registry; + QSignalSpy announced(®istry, SIGNAL(outputAnnounced(quint32,quint32))); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + registry.setup(); + wl_display_flush(m_connection->display()); + QVERIFY(announced.wait()); + + KWin::Wayland::Output output; + QSignalSpy outputChanged(&output, SIGNAL(changed())); + QVERIFY(outputChanged.isValid()); + output.setup(registry.bindOutput(announced.first().first().value(), announced.first().last().value())); + wl_display_flush(m_connection->display()); + if (outputChanged.isEmpty()) { + QVERIFY(outputChanged.wait()); + } + + QTEST(output.transform(), "expected"); + + // change back to normal + outputChanged.clear(); + m_serverOutput->setTransform(OutputInterface::Transform::Normal); + if (outputChanged.isEmpty()) { + QVERIFY(outputChanged.wait()); + } + QCOMPARE(output.transform(), Output::Transform::Normal); +} + QTEST_MAIN(TestWaylandOutput) #include "test_wayland_output.moc"