You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
8.7 KiB
C++

/*
SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
// Qt
#include <QSignalSpy>
#include <QTest>
// KWin
#include "wayland/compositor.h"
#include "wayland/display.h"
#include "wayland/xdgdecoration_v1.h"
#include "wayland/xdgshell.h"
#include "KWayland/Client/compositor.h"
#include "KWayland/Client/connection_thread.h"
#include "KWayland/Client/event_queue.h"
#include "KWayland/Client/registry.h"
#include "KWayland/Client/surface.h"
#include "KWayland/Client/xdgdecoration.h"
#include "KWayland/Client/xdgshell.h"
class TestXdgDecoration : public QObject
{
Q_OBJECT
public:
explicit TestXdgDecoration(QObject *parent = nullptr);
private Q_SLOTS:
void init();
void cleanup();
void testDecoration_data();
void testDecoration();
private:
KWin::Display *m_display = nullptr;
KWin::CompositorInterface *m_compositorInterface = nullptr;
KWin::XdgShellInterface *m_xdgShellInterface = nullptr;
KWin::XdgDecorationManagerV1Interface *m_xdgDecorationManagerInterface = nullptr;
KWayland::Client::ConnectionThread *m_connection = nullptr;
KWayland::Client::Compositor *m_compositor = nullptr;
KWayland::Client::EventQueue *m_queue = nullptr;
KWayland::Client::XdgShell *m_xdgShell = nullptr;
KWayland::Client::XdgDecorationManager *m_xdgDecorationManager = nullptr;
QThread *m_thread = nullptr;
KWayland::Client::Registry *m_registry = nullptr;
};
static const QString s_socketName = QStringLiteral("kwayland-test-wayland-server-side-decoration-0");
TestXdgDecoration::TestXdgDecoration(QObject *parent)
: QObject(parent)
{
}
void TestXdgDecoration::init()
{
using namespace KWin;
qRegisterMetaType<KWayland::Client::XdgDecoration::Mode>();
qRegisterMetaType<XdgToplevelDecorationV1Interface::Mode>();
delete m_display;
m_display = new KWin::Display(this);
m_display->addSocketName(s_socketName);
m_display->start();
QVERIFY(m_display->isRunning());
// setup connection
m_connection = new KWayland::Client::ConnectionThread;
QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
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 KWayland::Client::EventQueue(this);
QVERIFY(!m_queue->isValid());
m_queue->setup(m_connection);
QVERIFY(m_queue->isValid());
m_registry = new KWayland::Client::Registry();
QSignalSpy compositorSpy(m_registry, &KWayland::Client::Registry::compositorAnnounced);
QSignalSpy xdgShellSpy(m_registry, &KWayland::Client::Registry::xdgShellStableAnnounced);
QSignalSpy xdgDecorationManagerSpy(m_registry, &KWayland::Client::Registry::xdgDecorationAnnounced);
QVERIFY(!m_registry->eventQueue());
m_registry->setEventQueue(m_queue);
QCOMPARE(m_registry->eventQueue(), m_queue);
m_registry->create(m_connection);
QVERIFY(m_registry->isValid());
m_registry->setup();
m_compositorInterface = new CompositorInterface(m_display, m_display);
QVERIFY(compositorSpy.wait());
m_compositor = m_registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
m_xdgShellInterface = new XdgShellInterface(m_display, m_display);
QVERIFY(xdgShellSpy.wait());
m_xdgShell = m_registry->createXdgShell(xdgShellSpy.first().first().value<quint32>(), xdgShellSpy.first().last().value<quint32>(), this);
m_xdgDecorationManagerInterface = new XdgDecorationManagerV1Interface(m_display, m_display);
QVERIFY(xdgDecorationManagerSpy.wait());
m_xdgDecorationManager = m_registry->createXdgDecorationManager(xdgDecorationManagerSpy.first().first().value<quint32>(),
xdgDecorationManagerSpy.first().last().value<quint32>(),
this);
}
void TestXdgDecoration::cleanup()
{
if (m_compositor) {
delete m_compositor;
m_compositor = nullptr;
}
if (m_xdgShell) {
delete m_xdgShell;
m_xdgShell = nullptr;
}
if (m_xdgDecorationManager) {
delete m_xdgDecorationManager;
m_xdgDecorationManager = nullptr;
}
if (m_queue) {
delete m_queue;
m_queue = nullptr;
}
if (m_registry) {
delete m_registry;
m_registry = nullptr;
}
if (m_thread) {
m_thread->quit();
m_thread->wait();
delete m_thread;
m_thread = nullptr;
}
delete m_connection;
m_connection = nullptr;
delete m_display;
m_display = nullptr;
}
void TestXdgDecoration::testDecoration_data()
{
using namespace KWin;
QTest::addColumn<KWin::XdgToplevelDecorationV1Interface::Mode>("configuredMode");
QTest::addColumn<KWayland::Client::XdgDecoration::Mode>("configuredModeExp");
QTest::addColumn<KWayland::Client::XdgDecoration::Mode>("setMode");
QTest::addColumn<KWin::XdgToplevelDecorationV1Interface::Mode>("setModeExp");
const auto serverClient = XdgToplevelDecorationV1Interface::Mode::Client;
const auto serverServer = XdgToplevelDecorationV1Interface::Mode::Server;
const auto clientClient = KWayland::Client::XdgDecoration::Mode::ClientSide;
const auto clientServer = KWayland::Client::XdgDecoration::Mode::ServerSide;
QTest::newRow("client->client") << serverClient << clientClient << clientClient << serverClient;
QTest::newRow("client->server") << serverClient << clientClient << clientServer << serverServer;
QTest::newRow("server->client") << serverServer << clientServer << clientClient << serverClient;
QTest::newRow("server->server") << serverServer << clientServer << clientServer << serverServer;
}
void TestXdgDecoration::testDecoration()
{
using namespace KWin;
QFETCH(KWin::XdgToplevelDecorationV1Interface::Mode, configuredMode);
QFETCH(KWayland::Client::XdgDecoration::Mode, configuredModeExp);
QFETCH(KWayland::Client::XdgDecoration::Mode, setMode);
QFETCH(KWin::XdgToplevelDecorationV1Interface::Mode, setModeExp);
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
QSignalSpy shellSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::toplevelCreated);
QSignalSpy decorationCreatedSpy(m_xdgDecorationManagerInterface, &XdgDecorationManagerV1Interface::decorationCreated);
// create shell surface and deco object
std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
std::unique_ptr<KWayland::Client::XdgShellSurface> shellSurface(m_xdgShell->createSurface(surface.get()));
std::unique_ptr<KWayland::Client::XdgDecoration> decoration(m_xdgDecorationManager->getToplevelDecoration(shellSurface.get()));
// and receive all these on the "server"
QVERIFY(surfaceCreatedSpy.count() || surfaceCreatedSpy.wait());
QVERIFY(shellSurfaceCreatedSpy.count() || shellSurfaceCreatedSpy.wait());
QVERIFY(decorationCreatedSpy.count() || decorationCreatedSpy.wait());
auto shellSurfaceIface = shellSurfaceCreatedSpy.first().first().value<XdgToplevelInterface *>();
auto decorationIface = decorationCreatedSpy.first().first().value<XdgToplevelDecorationV1Interface *>();
QVERIFY(decorationIface);
QVERIFY(shellSurfaceIface);
QCOMPARE(decorationIface->toplevel(), shellSurfaceIface);
QCOMPARE(decorationIface->preferredMode(), XdgToplevelDecorationV1Interface::Mode::Undefined);
QSignalSpy clientConfiguredSpy(decoration.get(), &KWayland::Client::XdgDecoration::modeChanged);
QSignalSpy modeRequestedSpy(decorationIface, &XdgToplevelDecorationV1Interface::preferredModeChanged);
// server configuring a client
decorationIface->sendConfigure(configuredMode);
quint32 serial = shellSurfaceIface->sendConfigure(QSize(0, 0), {});
QVERIFY(clientConfiguredSpy.wait());
QCOMPARE(clientConfiguredSpy.first().first().value<KWayland::Client::XdgDecoration::Mode>(), configuredModeExp);
shellSurface->ackConfigure(serial);
// client requesting another mode
decoration->setMode(setMode);
QVERIFY(modeRequestedSpy.wait());
QCOMPARE(modeRequestedSpy.first().first().value<XdgToplevelDecorationV1Interface::Mode>(), setModeExp);
QCOMPARE(decorationIface->preferredMode(), setModeExp);
modeRequestedSpy.clear();
decoration->unsetMode();
QVERIFY(modeRequestedSpy.wait());
QCOMPARE(modeRequestedSpy.first().first().value<XdgToplevelDecorationV1Interface::Mode>(), XdgToplevelDecorationV1Interface::Mode::Undefined);
}
QTEST_GUILESS_MAIN(TestXdgDecoration)
#include "test_xdg_decoration.moc"