File indexing completed on 2024-11-10 04:56:16
0001 /* 0002 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 // Qt 0007 #include <QSignalSpy> 0008 #include <QTest> 0009 // KWin 0010 #include "wayland/compositor.h" 0011 #include "wayland/display.h" 0012 #include "wayland/server_decoration.h" 0013 0014 #include "qwayland-server-decoration.h" 0015 0016 #include "KWayland/Client/compositor.h" 0017 #include "KWayland/Client/connection_thread.h" 0018 #include "KWayland/Client/event_queue.h" 0019 #include "KWayland/Client/registry.h" 0020 #include "KWayland/Client/surface.h" 0021 0022 class ServerSideDecorationManager : public QtWayland::org_kde_kwin_server_decoration_manager 0023 { 0024 }; 0025 0026 class ServerSideDecoration : public QObject, public QtWayland::org_kde_kwin_server_decoration 0027 { 0028 Q_OBJECT 0029 0030 public: 0031 ~ServerSideDecoration() override 0032 { 0033 release(); 0034 } 0035 0036 Q_SIGNALS: 0037 void modeChanged(ServerSideDecorationManager::mode mode); 0038 0039 protected: 0040 void org_kde_kwin_server_decoration_mode(uint32_t mode) override 0041 { 0042 Q_EMIT modeChanged(ServerSideDecorationManager::mode(mode)); 0043 } 0044 }; 0045 0046 class TestServerSideDecoration : public QObject 0047 { 0048 Q_OBJECT 0049 public: 0050 explicit TestServerSideDecoration(QObject *parent = nullptr); 0051 private Q_SLOTS: 0052 void init(); 0053 void cleanup(); 0054 0055 void testCreate_data(); 0056 void testCreate(); 0057 0058 void testRequest_data(); 0059 void testRequest(); 0060 0061 void testSurfaceDestroy(); 0062 0063 private: 0064 KWin::Display *m_display = nullptr; 0065 KWin::CompositorInterface *m_compositorInterface = nullptr; 0066 KWin::ServerSideDecorationManagerInterface *m_serverSideDecorationManagerInterface = nullptr; 0067 KWayland::Client::ConnectionThread *m_connection = nullptr; 0068 KWayland::Client::Compositor *m_compositor = nullptr; 0069 KWayland::Client::EventQueue *m_queue = nullptr; 0070 ServerSideDecorationManager *m_serverSideDecorationManager = nullptr; 0071 QThread *m_thread = nullptr; 0072 KWayland::Client::Registry *m_registry = nullptr; 0073 }; 0074 0075 static const QString s_socketName = QStringLiteral("kwayland-test-wayland-server-side-decoration-0"); 0076 0077 TestServerSideDecoration::TestServerSideDecoration(QObject *parent) 0078 : QObject(parent) 0079 { 0080 } 0081 0082 void TestServerSideDecoration::init() 0083 { 0084 using namespace KWin; 0085 delete m_display; 0086 m_display = new KWin::Display(this); 0087 m_display->addSocketName(s_socketName); 0088 m_display->start(); 0089 QVERIFY(m_display->isRunning()); 0090 0091 // setup connection 0092 m_connection = new KWayland::Client::ConnectionThread; 0093 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected); 0094 m_connection->setSocketName(s_socketName); 0095 0096 m_thread = new QThread(this); 0097 m_connection->moveToThread(m_thread); 0098 m_thread->start(); 0099 0100 m_connection->initConnection(); 0101 QVERIFY(connectedSpy.wait()); 0102 0103 m_queue = new KWayland::Client::EventQueue(this); 0104 QVERIFY(!m_queue->isValid()); 0105 m_queue->setup(m_connection); 0106 QVERIFY(m_queue->isValid()); 0107 0108 m_compositorInterface = new CompositorInterface(m_display, m_display); 0109 m_serverSideDecorationManagerInterface = new ServerSideDecorationManagerInterface(m_display, m_display); 0110 0111 m_registry = new KWayland::Client::Registry(); 0112 connect(m_registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this](const QByteArray &interfaceName, quint32 name, quint32 version) { 0113 if (interfaceName == org_kde_kwin_server_decoration_manager_interface.name) { 0114 m_serverSideDecorationManager = new ServerSideDecorationManager(); 0115 m_serverSideDecorationManager->init(*m_registry, name, version); 0116 } 0117 }); 0118 0119 QSignalSpy interfacesAnnouncedSpy(m_registry, &KWayland::Client::Registry::interfacesAnnounced); 0120 QSignalSpy compositorSpy(m_registry, &KWayland::Client::Registry::compositorAnnounced); 0121 0122 QVERIFY(!m_registry->eventQueue()); 0123 m_registry->setEventQueue(m_queue); 0124 QCOMPARE(m_registry->eventQueue(), m_queue); 0125 m_registry->create(m_connection); 0126 QVERIFY(m_registry->isValid()); 0127 m_registry->setup(); 0128 QVERIFY(interfacesAnnouncedSpy.wait()); 0129 0130 m_compositor = m_registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this); 0131 0132 QVERIFY(m_compositor); 0133 QVERIFY(m_serverSideDecorationManager); 0134 } 0135 0136 void TestServerSideDecoration::cleanup() 0137 { 0138 if (m_compositor) { 0139 delete m_compositor; 0140 m_compositor = nullptr; 0141 } 0142 if (m_serverSideDecorationManager) { 0143 delete m_serverSideDecorationManager; 0144 m_serverSideDecorationManager = nullptr; 0145 } 0146 if (m_registry) { 0147 delete m_registry; 0148 m_registry = nullptr; 0149 } 0150 0151 if (m_queue) { 0152 delete m_queue; 0153 m_queue = nullptr; 0154 } 0155 0156 if (m_thread) { 0157 m_thread->quit(); 0158 m_thread->wait(); 0159 delete m_thread; 0160 m_thread = nullptr; 0161 } 0162 delete m_connection; 0163 m_connection = nullptr; 0164 0165 delete m_display; 0166 m_display = nullptr; 0167 } 0168 0169 void TestServerSideDecoration::testCreate_data() 0170 { 0171 using namespace KWin; 0172 QTest::addColumn<ServerSideDecorationManagerInterface::Mode>("serverMode"); 0173 QTest::addColumn<ServerSideDecorationManager::mode>("clientMode"); 0174 0175 QTest::newRow("none") << ServerSideDecorationManagerInterface::Mode::None << ServerSideDecorationManager::mode_None; 0176 QTest::newRow("client") << ServerSideDecorationManagerInterface::Mode::Client << ServerSideDecorationManager::mode_Client; 0177 QTest::newRow("server") << ServerSideDecorationManagerInterface::Mode::Server << ServerSideDecorationManager::mode_Server; 0178 } 0179 0180 void TestServerSideDecoration::testCreate() 0181 { 0182 using namespace KWin; 0183 QFETCH(KWin::ServerSideDecorationManagerInterface::Mode, serverMode); 0184 m_serverSideDecorationManagerInterface->setDefaultMode(serverMode); 0185 QCOMPARE(m_serverSideDecorationManagerInterface->defaultMode(), serverMode); 0186 0187 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); 0188 QSignalSpy decorationCreated(m_serverSideDecorationManagerInterface, &ServerSideDecorationManagerInterface::decorationCreated); 0189 0190 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0191 QVERIFY(serverSurfaceCreated.wait()); 0192 0193 auto serverSurface = serverSurfaceCreated.first().first().value<SurfaceInterface *>(); 0194 QVERIFY(!ServerSideDecorationInterface::get(serverSurface)); 0195 0196 // create server side deco 0197 auto serverSideDecoration = std::make_unique<ServerSideDecoration>(); 0198 serverSideDecoration->init(m_serverSideDecorationManager->create(*surface.get())); 0199 QSignalSpy modeChangedSpy(serverSideDecoration.get(), &ServerSideDecoration::modeChanged); 0200 0201 QVERIFY(decorationCreated.wait()); 0202 0203 auto serverDeco = decorationCreated.first().first().value<ServerSideDecorationInterface *>(); 0204 QVERIFY(serverDeco); 0205 QCOMPARE(serverDeco, ServerSideDecorationInterface::get(serverSurface)); 0206 QCOMPARE(serverDeco->surface(), serverSurface); 0207 0208 // after binding the client should get the default mode 0209 QVERIFY(modeChangedSpy.wait()); 0210 QCOMPARE(modeChangedSpy.count(), 1); 0211 QTEST(modeChangedSpy.last().at(0).value<ServerSideDecorationManager::mode>(), "clientMode"); 0212 0213 // and destroy 0214 QSignalSpy destroyedSpy(serverDeco, &QObject::destroyed); 0215 serverSideDecoration.reset(); 0216 QVERIFY(destroyedSpy.wait()); 0217 } 0218 0219 void TestServerSideDecoration::testRequest_data() 0220 { 0221 using namespace KWin; 0222 QTest::addColumn<ServerSideDecorationManagerInterface::Mode>("defaultMode"); 0223 QTest::addColumn<ServerSideDecorationManager::mode>("clientMode"); 0224 QTest::addColumn<ServerSideDecorationManager::mode>("clientRequestMode"); 0225 QTest::addColumn<ServerSideDecorationManagerInterface::Mode>("serverRequestedMode"); 0226 0227 const auto serverNone = ServerSideDecorationManagerInterface::Mode::None; 0228 const auto serverClient = ServerSideDecorationManagerInterface::Mode::Client; 0229 const auto serverServer = ServerSideDecorationManagerInterface::Mode::Server; 0230 const auto clientNone = ServerSideDecorationManager::mode_None; 0231 const auto clientClient = ServerSideDecorationManager::mode_Client; 0232 const auto clientServer = ServerSideDecorationManager::mode_Server; 0233 0234 QTest::newRow("none->none") << serverNone << clientNone << clientNone << serverNone; 0235 QTest::newRow("none->client") << serverNone << clientNone << clientClient << serverClient; 0236 QTest::newRow("none->server") << serverNone << clientNone << clientServer << serverServer; 0237 QTest::newRow("client->none") << serverClient << clientClient << clientNone << serverNone; 0238 QTest::newRow("client->client") << serverClient << clientClient << clientClient << serverClient; 0239 QTest::newRow("client->server") << serverClient << clientClient << clientServer << serverServer; 0240 QTest::newRow("server->none") << serverServer << clientServer << clientNone << serverNone; 0241 QTest::newRow("server->client") << serverServer << clientServer << clientClient << serverClient; 0242 QTest::newRow("server->server") << serverServer << clientServer << clientServer << serverServer; 0243 } 0244 0245 void TestServerSideDecoration::testRequest() 0246 { 0247 using namespace KWin; 0248 QFETCH(KWin::ServerSideDecorationManagerInterface::Mode, defaultMode); 0249 m_serverSideDecorationManagerInterface->setDefaultMode(defaultMode); 0250 QCOMPARE(m_serverSideDecorationManagerInterface->defaultMode(), defaultMode); 0251 0252 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); 0253 QSignalSpy decorationCreated(m_serverSideDecorationManagerInterface, &ServerSideDecorationManagerInterface::decorationCreated); 0254 0255 // create server side deco 0256 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0257 0258 auto serverSideDecoration = std::make_unique<ServerSideDecoration>(); 0259 serverSideDecoration->init(m_serverSideDecorationManager->create(*surface.get())); 0260 QSignalSpy modeChangedSpy(serverSideDecoration.get(), &ServerSideDecoration::modeChanged); 0261 QVERIFY(decorationCreated.wait()); 0262 0263 auto serverDeco = decorationCreated.first().first().value<ServerSideDecorationInterface *>(); 0264 QVERIFY(serverDeco); 0265 QSignalSpy preferredModeChangedSpy(serverDeco, &ServerSideDecorationInterface::preferredModeChanged); 0266 0267 // after binding the client should get the default mode 0268 QVERIFY(modeChangedSpy.wait()); 0269 QCOMPARE(modeChangedSpy.count(), 1); 0270 QTEST(modeChangedSpy.last().at(0).value<ServerSideDecorationManager::mode>(), "clientMode"); 0271 0272 // request a change 0273 QFETCH(ServerSideDecorationManager::mode, clientRequestMode); 0274 serverSideDecoration->request_mode(clientRequestMode); 0275 // mode not yet changed 0276 QCOMPARE(modeChangedSpy.count(), 1); 0277 0278 QVERIFY(preferredModeChangedSpy.wait()); 0279 QCOMPARE(preferredModeChangedSpy.count(), 1); 0280 QFETCH(ServerSideDecorationManagerInterface::Mode, serverRequestedMode); 0281 QCOMPARE(serverDeco->preferredMode(), serverRequestedMode); 0282 0283 // mode not yet changed 0284 QCOMPARE(serverDeco->mode(), defaultMode); 0285 serverDeco->setMode(serverRequestedMode); 0286 QCOMPARE(serverDeco->mode(), serverRequestedMode); 0287 0288 // should be sent to client 0289 QVERIFY(modeChangedSpy.wait()); 0290 QCOMPARE(modeChangedSpy.count(), 2); 0291 QCOMPARE(modeChangedSpy.last().at(0).value<ServerSideDecorationManager::mode>(), clientRequestMode); 0292 } 0293 0294 void TestServerSideDecoration::testSurfaceDestroy() 0295 { 0296 using namespace KWin; 0297 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); 0298 QSignalSpy decorationCreated(m_serverSideDecorationManagerInterface, &ServerSideDecorationManagerInterface::decorationCreated); 0299 0300 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0301 QVERIFY(serverSurfaceCreated.wait()); 0302 0303 auto serverSurface = serverSurfaceCreated.first().first().value<SurfaceInterface *>(); 0304 auto serverSideDecoration = std::make_unique<ServerSideDecoration>(); 0305 serverSideDecoration->init(m_serverSideDecorationManager->create(*surface.get())); 0306 QSignalSpy modeChangedSpy(serverSideDecoration.get(), &ServerSideDecoration::modeChanged); 0307 QVERIFY(decorationCreated.wait()); 0308 auto serverDeco = decorationCreated.first().first().value<ServerSideDecorationInterface *>(); 0309 QVERIFY(serverDeco); 0310 0311 // destroy the parent surface 0312 QSignalSpy surfaceDestroyedSpy(serverSurface, &QObject::destroyed); 0313 QSignalSpy decorationDestroyedSpy(serverDeco, &QObject::destroyed); 0314 surface.reset(); 0315 QVERIFY(surfaceDestroyedSpy.wait()); 0316 QVERIFY(decorationDestroyedSpy.isEmpty()); 0317 // destroy the blur 0318 serverSideDecoration.reset(); 0319 QVERIFY(decorationDestroyedSpy.wait()); 0320 } 0321 0322 QTEST_GUILESS_MAIN(TestServerSideDecoration) 0323 #include "test_server_side_decoration.moc"