diff --git a/src/wayland/test_wayland_shell.cpp b/src/wayland/test_wayland_shell.cpp
index 7dcb95b198..e35f2b5ec5 100644
--- a/src/wayland/test_wayland_shell.cpp
+++ b/src/wayland/test_wayland_shell.cpp
@@ -25,6 +25,11 @@ along with this program. If not, see .
#include "../../wayland_client/shell.h"
#include "../../wayland_client/surface.h"
#include "../../wayland_client/registry.h"
+#include "../../wayland_server/buffer_interface.h"
+#include "../../wayland_server/compositor_interface.h"
+#include "../../wayland_server/display.h"
+#include "../../wayland_server/shell_interface.h"
+#include "../../wayland_server/surface_interface.h"
// Wayland
#include
@@ -37,143 +42,252 @@ private Q_SLOTS:
void init();
void cleanup();
- void testRegistry();
- void testShell();
-
- // TODO: add tests for removal - requires more control over the compositor
+ void testFullscreen();
+ void testPing();
+ void testTitle();
+ void testWindowClass();
private:
- QProcess *m_westonProcess;
+ KWin::WaylandServer::Display *m_display;
+ KWin::WaylandServer::CompositorInterface *m_compositorInterface;
+ KWin::WaylandServer::ShellInterface *m_shellInterface;
+ KWin::Wayland::ConnectionThread *m_connection;
+ KWin::Wayland::Compositor *m_compositor;
+ KWin::Wayland::Shell *m_shell;
+ QThread *m_thread;
};
static const QString s_socketName = QStringLiteral("kwin-test-wayland-shell-0");
TestWaylandShell::TestWaylandShell(QObject *parent)
: QObject(parent)
- , m_westonProcess(nullptr)
+ , m_display(nullptr)
+ , m_compositorInterface(nullptr)
+ , m_shellInterface(nullptr)
+ , m_connection(nullptr)
+ , m_compositor(nullptr)
+ , m_shell(nullptr)
+ , m_thread(nullptr)
{
}
void TestWaylandShell::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_compositorInterface = m_display->createCompositor(m_display);
+ QVERIFY(m_compositorInterface);
+ m_compositorInterface->create();
+ QVERIFY(m_compositorInterface->isValid());
- // 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)));
+ m_shellInterface = m_display->createShell(m_display);
+ QVERIFY(m_shellInterface);
+ m_shellInterface->create();
+ QVERIFY(m_shellInterface->isValid());
- // limit to maximum of 10 waits
- for (int i = 0; i < 10; ++i) {
- QVERIFY(socketSpy.wait());
- if (runtimeDir.exists(s_socketName)) {
- delete socketWatcher;
- return;
+ // setup connection
+ m_connection = new KWin::Wayland::ConnectionThread;
+ QSignalSpy connectedSpy(m_connection, SIGNAL(connected()));
+ m_connection->setSocketName(s_socketName);
+
+ m_thread = new QThread(this);
+ m_connection->moveToThread(m_thread);
+ m_thread->start();
+
+ connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, m_connection,
+ [this]() {
+ if (m_connection->display()) {
+ wl_display_flush(m_connection->display());
+ }
}
- }
-}
+ );
-void TestWaylandShell::cleanup()
-{
- // terminates weston
- m_westonProcess->terminate();
- QVERIFY(m_westonProcess->waitForFinished());
- delete m_westonProcess;
- m_westonProcess = nullptr;
-}
-
-void TestWaylandShell::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());
-
- KWin::Wayland::Registry registry;
- QSignalSpy announced(®istry, SIGNAL(shellAnnounced(quint32,quint32)));
- registry.create(connection.display());
- QVERIFY(registry.isValid());
- registry.setup();
- wl_display_flush(connection.display());
- QVERIFY(announced.wait());
-
- KWin::Wayland::Shell shell;
- QVERIFY(!shell.isValid());
-
- shell.setup(registry.bindShell(announced.first().first().value(), announced.first().last().value()));
- wl_display_flush(connection.display());
- QVERIFY(shell.isValid());
-
- shell.release();
- QVERIFY(!shell.isValid());
-}
-
-void TestWaylandShell::testShell()
-{
- 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();
+ m_connection->initConnection();
QVERIFY(connectedSpy.wait());
KWin::Wayland::Registry registry;
QSignalSpy compositorSpy(®istry, SIGNAL(compositorAnnounced(quint32,quint32)));
- QSignalSpy announced(®istry, SIGNAL(shellAnnounced(quint32,quint32)));
- registry.create(connection.display());
+ QSignalSpy shellSpy(®istry, SIGNAL(shellAnnounced(quint32,quint32)));
+ registry.create(m_connection->display());
QVERIFY(registry.isValid());
registry.setup();
- wl_display_flush(connection.display());
- QVERIFY(announced.wait());
+ QVERIFY(compositorSpy.wait());
- if (compositorSpy.isEmpty()) {
- QVERIFY(compositorSpy.wait());
+ m_compositor = new KWin::Wayland::Compositor(this);
+ m_compositor->setup(registry.bindCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value()));
+ QVERIFY(m_compositor->isValid());
+
+ if (shellSpy.isEmpty()) {
+ QVERIFY(shellSpy.wait());
}
- KWin::Wayland::Compositor compositor;
- compositor.setup(registry.bindCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value()));
+ m_shell = new KWin::Wayland::Shell(this);
+ m_shell->setup(registry.bindShell(shellSpy.first().first().value(), shellSpy.first().last().value()));
+ QVERIFY(m_shell->isValid());
+}
- KWin::Wayland::Shell shell;
- shell.setup(registry.bindShell(announced.first().first().value(), announced.first().last().value()));
- wl_display_flush(connection.display());
- QScopedPointer s(compositor.createSurface());
+void TestWaylandShell::cleanup()
+{
+ if (m_shell) {
+ delete m_shell;
+ m_shell = nullptr;
+ }
+ if (m_compositor) {
+ delete m_compositor;
+ m_compositor = nullptr;
+ }
+ if (m_thread) {
+ m_thread->quit();
+ m_thread->wait();
+ delete m_thread;
+ m_thread = nullptr;
+ }
+ delete m_connection;
+ m_connection = nullptr;
+
+ delete m_shellInterface;
+ m_shellInterface = nullptr;
+
+ delete m_compositorInterface;
+ m_compositorInterface = nullptr;
+
+ delete m_display;
+ m_display = nullptr;
+}
+
+void TestWaylandShell::testFullscreen()
+{
+ using namespace KWin::WaylandServer;
+ QScopedPointer s(m_compositor->createSurface());
QVERIFY(!s.isNull());
QVERIFY(s->isValid());
- KWin::Wayland::ShellSurface *surface = shell.createSurface(s.data(), &shell);
+ KWin::Wayland::ShellSurface *surface = m_shell->createSurface(s.data(), m_shell);
QSignalSpy sizeSpy(surface, SIGNAL(sizeChanged(QSize)));
QVERIFY(sizeSpy.isValid());
QCOMPARE(surface->size(), QSize());
+ QSignalSpy serverSurfaceSpy(m_shellInterface, SIGNAL(surfaceCreated(KWin::WaylandServer::ShellSurfaceInterface*)));
+ QVERIFY(serverSurfaceSpy.isValid());
+ QVERIFY(serverSurfaceSpy.wait());
+ ShellSurfaceInterface *serverSurface = serverSurfaceSpy.first().first().value();
+ QVERIFY(serverSurface);
+
+ QSignalSpy fullscreenSpy(serverSurface, SIGNAL(fullscreenChanged(bool)));
+ QVERIFY(fullscreenSpy.isValid());
+
surface->setFullscreen();
- wl_display_flush(connection.display());
+ QVERIFY(fullscreenSpy.wait());
+ QCOMPARE(fullscreenSpy.count(), 1);
+ QVERIFY(fullscreenSpy.first().first().toBool());
+ serverSurface->requestSize(QSize(1024, 768));
+
QVERIFY(sizeSpy.wait());
QCOMPARE(sizeSpy.count(), 1);
QCOMPARE(sizeSpy.first().first().toSize(), QSize(1024, 768));
QCOMPARE(surface->size(), QSize(1024, 768));
- QVERIFY(surface->isValid());
- shell.release();
- QVERIFY(!surface->isValid());
+ // set back to toplevel
+ fullscreenSpy.clear();
+ wl_shell_surface_set_toplevel(*surface);
+ QVERIFY(fullscreenSpy.wait());
+ QCOMPARE(fullscreenSpy.count(), 1);
+ QVERIFY(!fullscreenSpy.first().first().toBool());
+}
- compositor.release();
+void TestWaylandShell::testPing()
+{
+ using namespace KWin::WaylandServer;
+ QScopedPointer s(m_compositor->createSurface());
+ QVERIFY(!s.isNull());
+ QVERIFY(s->isValid());
+ KWin::Wayland::ShellSurface *surface = m_shell->createSurface(s.data(), m_shell);
+ QSignalSpy pingSpy(surface, SIGNAL(pinged()));
+
+ QSignalSpy serverSurfaceSpy(m_shellInterface, SIGNAL(surfaceCreated(KWin::WaylandServer::ShellSurfaceInterface*)));
+ QVERIFY(serverSurfaceSpy.isValid());
+ QVERIFY(serverSurfaceSpy.wait());
+ ShellSurfaceInterface *serverSurface = serverSurfaceSpy.first().first().value();
+ QVERIFY(serverSurface);
+
+ QSignalSpy pingTimeoutSpy(serverSurface, SIGNAL(pingTimeout()));
+ QVERIFY(pingTimeoutSpy.isValid());
+ QSignalSpy pongSpy(serverSurface, SIGNAL(pongReceived()));
+ QVERIFY(pongSpy.isValid());
+
+ serverSurface->ping();
+ QVERIFY(pingSpy.wait());
+ wl_display_flush(m_connection->display());
+
+ if (pongSpy.isEmpty()) {
+ QVERIFY(pongSpy.wait());
+ }
+ QVERIFY(!pongSpy.isEmpty());
+ QVERIFY(pingTimeoutSpy.isEmpty());
+
+ // evil trick - timeout of zero will make it not get the pong
+ serverSurface->setPingTimeout(0);
+ pongSpy.clear();
+ pingTimeoutSpy.clear();
+ serverSurface->ping();
+ if (pingTimeoutSpy.isEmpty()) {
+ QVERIFY(pingTimeoutSpy.wait());
+ }
+ QCOMPARE(pingTimeoutSpy.count(), 1);
+ QVERIFY(pongSpy.isEmpty());
+}
+
+void TestWaylandShell::testTitle()
+{
+ using namespace KWin::WaylandServer;
+ QScopedPointer s(m_compositor->createSurface());
+ QVERIFY(!s.isNull());
+ QVERIFY(s->isValid());
+ KWin::Wayland::ShellSurface *surface = m_shell->createSurface(s.data(), m_shell);
+
+ QSignalSpy serverSurfaceSpy(m_shellInterface, SIGNAL(surfaceCreated(KWin::WaylandServer::ShellSurfaceInterface*)));
+ QVERIFY(serverSurfaceSpy.isValid());
+ QVERIFY(serverSurfaceSpy.wait());
+ ShellSurfaceInterface *serverSurface = serverSurfaceSpy.first().first().value();
+ QVERIFY(serverSurface);
+
+ QSignalSpy titleSpy(serverSurface, SIGNAL(titleChanged(QString)));
+ QVERIFY(titleSpy.isValid());
+ QString testTitle = QStringLiteral("fooBar");
+ QVERIFY(serverSurface->title().isNull());
+
+ wl_shell_surface_set_title(*surface, testTitle.toUtf8().constData());
+ QVERIFY(titleSpy.wait());
+ QCOMPARE(serverSurface->title(), testTitle);
+ QCOMPARE(titleSpy.first().first().toString(), testTitle);
+}
+
+void TestWaylandShell::testWindowClass()
+{
+ using namespace KWin::WaylandServer;
+ QScopedPointer s(m_compositor->createSurface());
+ QVERIFY(!s.isNull());
+ QVERIFY(s->isValid());
+ KWin::Wayland::ShellSurface *surface = m_shell->createSurface(s.data(), m_shell);
+
+ QSignalSpy serverSurfaceSpy(m_shellInterface, SIGNAL(surfaceCreated(KWin::WaylandServer::ShellSurfaceInterface*)));
+ QVERIFY(serverSurfaceSpy.isValid());
+ QVERIFY(serverSurfaceSpy.wait());
+ ShellSurfaceInterface *serverSurface = serverSurfaceSpy.first().first().value();
+ QVERIFY(serverSurface);
+
+ QSignalSpy windowClassSpy(serverSurface, SIGNAL(windowClassChanged(QByteArray)));
+ QVERIFY(windowClassSpy.isValid());
+ QByteArray testClass = QByteArrayLiteral("fooBar");
+ QVERIFY(serverSurface->windowClass().isNull());
+
+ wl_shell_surface_set_class(*surface, testClass.constData());
+ QVERIFY(windowClassSpy.wait());
+ QCOMPARE(serverSurface->windowClass(), testClass);
+ QCOMPARE(windowClassSpy.first().first().toByteArray(), testClass);
}
QTEST_MAIN(TestWaylandShell)