File indexing completed on 2024-11-10 04:56:17
0001 /* 0002 SPDX-FileCopyrightText: 2016 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 // client 0010 #include "KWayland/Client/compositor.h" 0011 #include "KWayland/Client/connection_thread.h" 0012 #include "KWayland/Client/event_queue.h" 0013 #include "KWayland/Client/registry.h" 0014 #include "KWayland/Client/shadow.h" 0015 #include "KWayland/Client/shm_pool.h" 0016 #include "KWayland/Client/surface.h" 0017 // server 0018 #include "core/graphicsbufferview.h" 0019 #include "wayland/compositor.h" 0020 #include "wayland/display.h" 0021 #include "wayland/shadow.h" 0022 0023 using namespace KWin; 0024 0025 class ShadowTest : public QObject 0026 { 0027 Q_OBJECT 0028 private Q_SLOTS: 0029 void init(); 0030 void cleanup(); 0031 0032 void testCreateShadow(); 0033 void testShadowElements(); 0034 void testSurfaceDestroy(); 0035 0036 private: 0037 KWin::Display *m_display = nullptr; 0038 0039 KWayland::Client::ConnectionThread *m_connection = nullptr; 0040 CompositorInterface *m_compositorInterface = nullptr; 0041 ShadowManagerInterface *m_shadowInterface = nullptr; 0042 QThread *m_thread = nullptr; 0043 KWayland::Client::EventQueue *m_queue = nullptr; 0044 KWayland::Client::ShmPool *m_shm = nullptr; 0045 KWayland::Client::Compositor *m_compositor = nullptr; 0046 KWayland::Client::ShadowManager *m_shadow = nullptr; 0047 }; 0048 0049 static const QString s_socketName = QStringLiteral("kwayland-test-shadow-0"); 0050 0051 void ShadowTest::init() 0052 { 0053 delete m_display; 0054 m_display = new KWin::Display(this); 0055 m_display->addSocketName(s_socketName); 0056 m_display->start(); 0057 QVERIFY(m_display->isRunning()); 0058 m_display->createShm(); 0059 m_compositorInterface = new CompositorInterface(m_display, m_display); 0060 m_shadowInterface = new ShadowManagerInterface(m_display, m_display); 0061 0062 // setup connection 0063 m_connection = new KWayland::Client::ConnectionThread; 0064 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected); 0065 m_connection->setSocketName(s_socketName); 0066 0067 m_thread = new QThread(this); 0068 m_connection->moveToThread(m_thread); 0069 m_thread->start(); 0070 0071 m_connection->initConnection(); 0072 QVERIFY(connectedSpy.wait()); 0073 0074 m_queue = new KWayland::Client::EventQueue(this); 0075 m_queue->setup(m_connection); 0076 0077 KWayland::Client::Registry registry; 0078 QSignalSpy interfacesAnnouncedSpy(®istry, &KWayland::Client::Registry::interfacesAnnounced); 0079 registry.setEventQueue(m_queue); 0080 registry.create(m_connection); 0081 QVERIFY(registry.isValid()); 0082 registry.setup(); 0083 QVERIFY(interfacesAnnouncedSpy.wait()); 0084 0085 m_shm = registry.createShmPool(registry.interface(KWayland::Client::Registry::Interface::Shm).name, registry.interface(KWayland::Client::Registry::Interface::Shm).version, this); 0086 QVERIFY(m_shm->isValid()); 0087 m_compositor = 0088 registry.createCompositor(registry.interface(KWayland::Client::Registry::Interface::Compositor).name, registry.interface(KWayland::Client::Registry::Interface::Compositor).version, this); 0089 QVERIFY(m_compositor->isValid()); 0090 m_shadow = 0091 registry.createShadowManager(registry.interface(KWayland::Client::Registry::Interface::Shadow).name, registry.interface(KWayland::Client::Registry::Interface::Shadow).version, this); 0092 QVERIFY(m_shadow->isValid()); 0093 } 0094 0095 void ShadowTest::cleanup() 0096 { 0097 #define CLEANUP(variable) \ 0098 if (variable) { \ 0099 delete variable; \ 0100 variable = nullptr; \ 0101 } 0102 CLEANUP(m_shm) 0103 CLEANUP(m_compositor) 0104 CLEANUP(m_shadow) 0105 CLEANUP(m_queue) 0106 if (m_connection) { 0107 m_connection->deleteLater(); 0108 m_connection = nullptr; 0109 } 0110 if (m_thread) { 0111 m_thread->quit(); 0112 m_thread->wait(); 0113 delete m_thread; 0114 m_thread = nullptr; 0115 } 0116 0117 CLEANUP(m_display) 0118 #undef CLEANUP 0119 0120 // these are the children of the display 0121 m_compositorInterface = nullptr; 0122 m_shadowInterface = nullptr; 0123 } 0124 0125 void ShadowTest::testCreateShadow() 0126 { 0127 // this test verifies the basic shadow behavior, create for surface, commit it, etc. 0128 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); 0129 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0130 QVERIFY(surfaceCreatedSpy.wait()); 0131 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>(); 0132 QVERIFY(serverSurface); 0133 // a surface without anything should not have a Shadow 0134 QVERIFY(!serverSurface->shadow()); 0135 QSignalSpy shadowChangedSpy(serverSurface, &SurfaceInterface::shadowChanged); 0136 0137 // let's create a shadow for the Surface 0138 std::unique_ptr<KWayland::Client::Shadow> shadow(m_shadow->createShadow(surface.get())); 0139 // that should not have triggered the shadowChangedSpy) 0140 QVERIFY(!shadowChangedSpy.wait(100)); 0141 0142 // now let's commit the surface, that should trigger the shadow changed 0143 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0144 QVERIFY(shadowChangedSpy.wait()); 0145 QCOMPARE(shadowChangedSpy.count(), 1); 0146 0147 // we didn't set anything on the shadow, so it should be all default values 0148 auto serverShadow = serverSurface->shadow(); 0149 QVERIFY(serverShadow); 0150 QCOMPARE(serverShadow->offset(), QMarginsF()); 0151 QVERIFY(!serverShadow->topLeft()); 0152 QVERIFY(!serverShadow->top()); 0153 QVERIFY(!serverShadow->topRight()); 0154 QVERIFY(!serverShadow->right()); 0155 QVERIFY(!serverShadow->bottomRight()); 0156 QVERIFY(!serverShadow->bottom()); 0157 QVERIFY(!serverShadow->bottomLeft()); 0158 QVERIFY(!serverShadow->left()); 0159 0160 // now let's remove the shadow 0161 m_shadow->removeShadow(surface.get()); 0162 // just removing should not remove it yet, surface needs to be committed 0163 QVERIFY(!shadowChangedSpy.wait(100)); 0164 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0165 QVERIFY(shadowChangedSpy.wait()); 0166 QCOMPARE(shadowChangedSpy.count(), 2); 0167 QVERIFY(!serverSurface->shadow()); 0168 } 0169 0170 static QImage bufferToImage(KWin::GraphicsBuffer *clientBuffer) 0171 { 0172 if (clientBuffer) { 0173 KWin::GraphicsBufferView view(clientBuffer); 0174 if (QImage *image = view.image()) { 0175 return image->copy(); 0176 } 0177 } 0178 return QImage(); 0179 } 0180 0181 void ShadowTest::testShadowElements() 0182 { 0183 // this test verifies that all shadow elements are correctly passed to the server 0184 // first create surface 0185 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); 0186 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0187 QVERIFY(surfaceCreatedSpy.wait()); 0188 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>(); 0189 QVERIFY(serverSurface); 0190 QSignalSpy shadowChangedSpy(serverSurface, &SurfaceInterface::shadowChanged); 0191 0192 // now create the shadow 0193 std::unique_ptr<KWayland::Client::Shadow> shadow(m_shadow->createShadow(surface.get())); 0194 QImage topLeftImage(QSize(10, 10), QImage::Format_ARGB32_Premultiplied); 0195 topLeftImage.fill(Qt::white); 0196 shadow->attachTopLeft(m_shm->createBuffer(topLeftImage)); 0197 QImage topImage(QSize(11, 11), QImage::Format_ARGB32_Premultiplied); 0198 topImage.fill(Qt::black); 0199 shadow->attachTop(m_shm->createBuffer(topImage)); 0200 QImage topRightImage(QSize(12, 12), QImage::Format_ARGB32_Premultiplied); 0201 topRightImage.fill(Qt::red); 0202 shadow->attachTopRight(m_shm->createBuffer(topRightImage)); 0203 QImage rightImage(QSize(13, 13), QImage::Format_ARGB32_Premultiplied); 0204 rightImage.fill(Qt::darkRed); 0205 shadow->attachRight(m_shm->createBuffer(rightImage)); 0206 QImage bottomRightImage(QSize(14, 14), QImage::Format_ARGB32_Premultiplied); 0207 bottomRightImage.fill(Qt::green); 0208 shadow->attachBottomRight(m_shm->createBuffer(bottomRightImage)); 0209 QImage bottomImage(QSize(15, 15), QImage::Format_ARGB32_Premultiplied); 0210 bottomImage.fill(Qt::darkGreen); 0211 shadow->attachBottom(m_shm->createBuffer(bottomImage)); 0212 QImage bottomLeftImage(QSize(16, 16), QImage::Format_ARGB32_Premultiplied); 0213 bottomLeftImage.fill(Qt::blue); 0214 shadow->attachBottomLeft(m_shm->createBuffer(bottomLeftImage)); 0215 QImage leftImage(QSize(17, 17), QImage::Format_ARGB32_Premultiplied); 0216 leftImage.fill(Qt::darkBlue); 0217 shadow->attachLeft(m_shm->createBuffer(leftImage)); 0218 shadow->setOffsets(QMarginsF(1, 2, 3, 4)); 0219 shadow->commit(); 0220 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0221 0222 QVERIFY(shadowChangedSpy.wait()); 0223 auto serverShadow = serverSurface->shadow(); 0224 QVERIFY(serverShadow); 0225 QCOMPARE(serverShadow->offset(), QMarginsF(1, 2, 3, 4)); 0226 QCOMPARE(bufferToImage(serverShadow->topLeft()), topLeftImage); 0227 QCOMPARE(bufferToImage(serverShadow->top()), topImage); 0228 QCOMPARE(bufferToImage(serverShadow->topRight()), topRightImage); 0229 QCOMPARE(bufferToImage(serverShadow->right()), rightImage); 0230 QCOMPARE(bufferToImage(serverShadow->bottomRight()), bottomRightImage); 0231 QCOMPARE(bufferToImage(serverShadow->bottom()), bottomImage); 0232 QCOMPARE(bufferToImage(serverShadow->bottomLeft()), bottomLeftImage); 0233 QCOMPARE(bufferToImage(serverShadow->left()), leftImage); 0234 } 0235 0236 void ShadowTest::testSurfaceDestroy() 0237 { 0238 using namespace KWin; 0239 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); 0240 0241 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0242 QVERIFY(serverSurfaceCreated.wait()); 0243 auto serverSurface = serverSurfaceCreated.first().first().value<SurfaceInterface *>(); 0244 QSignalSpy shadowChangedSpy(serverSurface, &SurfaceInterface::shadowChanged); 0245 0246 std::unique_ptr<KWayland::Client::Shadow> shadow(m_shadow->createShadow(surface.get())); 0247 shadow->commit(); 0248 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0249 QVERIFY(shadowChangedSpy.wait()); 0250 auto serverShadow = serverSurface->shadow(); 0251 QVERIFY(serverShadow); 0252 0253 // destroy the parent surface 0254 QSignalSpy surfaceDestroyedSpy(serverSurface, &QObject::destroyed); 0255 QSignalSpy shadowDestroyedSpy(serverShadow, &QObject::destroyed); 0256 surface.reset(); 0257 QVERIFY(surfaceDestroyedSpy.wait()); 0258 QVERIFY(shadowDestroyedSpy.isEmpty()); 0259 // destroy the shadow 0260 shadow.reset(); 0261 QVERIFY(shadowDestroyedSpy.wait()); 0262 QCOMPARE(shadowDestroyedSpy.count(), 1); 0263 } 0264 0265 QTEST_GUILESS_MAIN(ShadowTest) 0266 #include "test_shadow.moc"