[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.
This commit is contained in:
parent
211f08446c
commit
50ba61f027
2 changed files with 245 additions and 98 deletions
|
@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <QtTest/QtTest>
|
||||
// KWin
|
||||
#include "../../wayland_client/connection_thread.h"
|
||||
#include "../../wayland_server/display.h"
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
|
@ -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<KWin::Wayland::ConnectionThread> 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<KWin::Wayland::ConnectionThread> 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<KWin::Wayland::ConnectionThread> 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<KWin::Wayland::ConnectionThread> 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());
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#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 <wayland-client-protocol.h>
|
||||
|
||||
|
@ -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<quint32>(), announced.first().last().value<quint32>()));
|
||||
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<quint32>(), announced.first().last().value<quint32>()));
|
||||
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<quint32>(), announced.first().last().value<quint32>()));
|
||||
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<KWin::Wayland::Output::SubPixel>("expected");
|
||||
QTest::addColumn<KWin::WaylandServer::OutputInterface::SubPixel>("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<quint32>(), announced.first().last().value<quint32>()));
|
||||
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<KWin::Wayland::Output::Transform>("expected");
|
||||
QTest::addColumn<KWin::WaylandServer::OutputInterface::Transform>("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<quint32>(), announced.first().last().value<quint32>()));
|
||||
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"
|
||||
|
|
Loading…
Reference in a new issue