File indexing completed on 2024-06-02 05:36:42

0001 /*
0002     SPDX-FileCopyrightText: 2014 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/display.h"
0011 #include "wayland/output.h"
0012 
0013 #include "KWayland/Client/connection_thread.h"
0014 #include "KWayland/Client/event_queue.h"
0015 #include "KWayland/Client/output.h"
0016 #include "KWayland/Client/registry.h"
0017 
0018 #include "../../../tests/fakeoutput.h"
0019 
0020 // Wayland
0021 #include <wayland-client-protocol.h>
0022 
0023 class TestWaylandOutput : public QObject
0024 {
0025     Q_OBJECT
0026 public:
0027     explicit TestWaylandOutput(QObject *parent = nullptr);
0028 private Q_SLOTS:
0029     void init();
0030     void cleanup();
0031 
0032     void testRegistry();
0033     void testModeChange();
0034     void testScaleChange();
0035 
0036     void testSubPixel_data();
0037     void testSubPixel();
0038 
0039     void testTransform_data();
0040     void testTransform();
0041 
0042 private:
0043     KWin::Display *m_display;
0044     KWayland::Client::ConnectionThread *m_connection;
0045     KWayland::Client::EventQueue *m_queue;
0046     QThread *m_thread;
0047 };
0048 
0049 static const QString s_socketName = QStringLiteral("kwin-test-wayland-output-0");
0050 
0051 TestWaylandOutput::TestWaylandOutput(QObject *parent)
0052     : QObject(parent)
0053     , m_display(nullptr)
0054     , m_connection(nullptr)
0055     , m_thread(nullptr)
0056 {
0057 }
0058 
0059 void TestWaylandOutput::init()
0060 {
0061     delete m_display;
0062     m_display = new KWin::Display(this);
0063     m_display->addSocketName(s_socketName);
0064     m_display->start();
0065     QVERIFY(m_display->isRunning());
0066 
0067     // setup connection
0068     m_connection = new KWayland::Client::ConnectionThread;
0069     QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
0070     m_connection->setSocketName(s_socketName);
0071 
0072     m_thread = new QThread(this);
0073     m_connection->moveToThread(m_thread);
0074     m_thread->start();
0075 
0076     m_connection->initConnection();
0077     QVERIFY(connectedSpy.wait());
0078 
0079     m_queue = new KWayland::Client::EventQueue(this);
0080     QVERIFY(!m_queue->isValid());
0081     m_queue->setup(m_connection);
0082     QVERIFY(m_queue->isValid());
0083 }
0084 
0085 void TestWaylandOutput::cleanup()
0086 {
0087     if (m_queue) {
0088         delete m_queue;
0089         m_queue = nullptr;
0090     }
0091     if (m_thread) {
0092         m_thread->quit();
0093         m_thread->wait();
0094         delete m_thread;
0095         m_thread = nullptr;
0096     }
0097     delete m_connection;
0098     m_connection = nullptr;
0099 
0100     delete m_display;
0101     m_display = nullptr;
0102 }
0103 
0104 void TestWaylandOutput::testRegistry()
0105 {
0106     auto outputHandle = std::make_unique<FakeOutput>();
0107     outputHandle->setMode(QSize(1024, 768), 60000);
0108     outputHandle->moveTo(QPoint(100, 50));
0109     outputHandle->setPhysicalSize(QSize(200, 100));
0110 
0111     auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
0112 
0113     KWayland::Client::Registry registry;
0114     QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
0115     registry.create(m_connection->display());
0116     QVERIFY(registry.isValid());
0117     registry.setup();
0118     wl_display_flush(m_connection->display());
0119     QVERIFY(announced.wait());
0120 
0121     KWayland::Client::Output output;
0122     QVERIFY(!output.isValid());
0123     QCOMPARE(output.geometry(), QRect());
0124     QCOMPARE(output.globalPosition(), QPoint());
0125     QCOMPARE(output.manufacturer(), QString());
0126     QCOMPARE(output.model(), QString());
0127     QCOMPARE(output.physicalSize(), QSize());
0128     QCOMPARE(output.pixelSize(), QSize());
0129     QCOMPARE(output.refreshRate(), 0);
0130     QCOMPARE(output.scale(), 1);
0131     QCOMPARE(output.subPixel(), KWayland::Client::Output::SubPixel::Unknown);
0132     QCOMPARE(output.transform(), KWayland::Client::Output::Transform::Normal);
0133 
0134     QSignalSpy outputChanged(&output, &KWayland::Client::Output::changed);
0135     auto o = registry.bindOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>());
0136     QVERIFY(!KWayland::Client::Output::get(o));
0137     output.setup(o);
0138     QCOMPARE(KWayland::Client::Output::get(o), &output);
0139     wl_display_flush(m_connection->display());
0140     QVERIFY(outputChanged.wait());
0141 
0142     QCOMPARE(output.geometry(), QRect(100, 50, 1024, 768));
0143     QCOMPARE(output.globalPosition(), QPoint(100, 50));
0144     QCOMPARE(output.manufacturer(), QString());
0145     QCOMPARE(output.model(), QString());
0146     QCOMPARE(output.physicalSize(), QSize(200, 100));
0147     QCOMPARE(output.pixelSize(), QSize(1024, 768));
0148     QCOMPARE(output.refreshRate(), 60000);
0149     QCOMPARE(output.scale(), 1);
0150     // for xwayland output it's unknown
0151     QCOMPARE(output.subPixel(), KWayland::Client::Output::SubPixel::Unknown);
0152     // for xwayland transform is normal
0153     QCOMPARE(output.transform(), KWayland::Client::Output::Transform::Normal);
0154 }
0155 
0156 void TestWaylandOutput::testModeChange()
0157 {
0158     auto outputHandle = std::make_unique<FakeOutput>();
0159     outputHandle->setMode(QSize(1024, 768), 60000);
0160 
0161     auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
0162 
0163     KWayland::Client::Registry registry;
0164     QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
0165     registry.setEventQueue(m_queue);
0166     registry.create(m_connection->display());
0167     QVERIFY(registry.isValid());
0168     registry.setup();
0169     wl_display_flush(m_connection->display());
0170     QVERIFY(announced.wait());
0171 
0172     KWayland::Client::Output output;
0173     QSignalSpy outputChanged(&output, &KWayland::Client::Output::changed);
0174     QSignalSpy modeAddedSpy(&output, &KWayland::Client::Output::modeAdded);
0175     output.setup(registry.bindOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>()));
0176     wl_display_flush(m_connection->display());
0177     QVERIFY(outputChanged.wait());
0178     QCOMPARE(modeAddedSpy.count(), 1);
0179     QCOMPARE(modeAddedSpy.at(0).first().value<KWayland::Client::Output::Mode>().size, QSize(1024, 768));
0180     QCOMPARE(modeAddedSpy.at(0).first().value<KWayland::Client::Output::Mode>().refreshRate, 60000);
0181     QCOMPARE(modeAddedSpy.at(0).first().value<KWayland::Client::Output::Mode>().flags, KWayland::Client::Output::Mode::Flags(KWayland::Client::Output::Mode::Flag::Current));
0182     QCOMPARE(modeAddedSpy.at(0).first().value<KWayland::Client::Output::Mode>().output, QPointer<KWayland::Client::Output>(&output));
0183     QCOMPARE(output.pixelSize(), QSize(1024, 768));
0184     QCOMPARE(output.refreshRate(), 60000);
0185 
0186     // change once more
0187     outputHandle->setMode(QSize(1280, 1024), 90000);
0188     QVERIFY(outputChanged.wait());
0189     QCOMPARE(modeAddedSpy.count(), 2);
0190     QCOMPARE(modeAddedSpy.at(1).first().value<KWayland::Client::Output::Mode>().size, QSize(1280, 1024));
0191     QCOMPARE(modeAddedSpy.at(1).first().value<KWayland::Client::Output::Mode>().refreshRate, 90000);
0192     QCOMPARE(modeAddedSpy.at(1).first().value<KWayland::Client::Output::Mode>().flags, KWayland::Client::Output::Mode::Flags(KWayland::Client::Output::Mode::Flag::Current));
0193     QCOMPARE(modeAddedSpy.at(1).first().value<KWayland::Client::Output::Mode>().output, QPointer<KWayland::Client::Output>(&output));
0194     QCOMPARE(output.pixelSize(), QSize(1280, 1024));
0195     QCOMPARE(output.refreshRate(), 90000);
0196 }
0197 
0198 void TestWaylandOutput::testScaleChange()
0199 {
0200     auto outputHandle = std::make_unique<FakeOutput>();
0201     outputHandle->setMode(QSize(1024, 768), 60000);
0202 
0203     auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
0204 
0205     KWayland::Client::Registry registry;
0206     QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
0207     registry.create(m_connection->display());
0208     QVERIFY(registry.isValid());
0209     registry.setup();
0210     wl_display_flush(m_connection->display());
0211     QVERIFY(announced.wait());
0212 
0213     KWayland::Client::Output output;
0214     QSignalSpy outputChanged(&output, &KWayland::Client::Output::changed);
0215     output.setup(registry.bindOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>()));
0216     wl_display_flush(m_connection->display());
0217     QVERIFY(outputChanged.wait());
0218     QCOMPARE(output.scale(), 1);
0219 
0220     // change the scale
0221     outputChanged.clear();
0222     outputHandle->setScale(2);
0223     QVERIFY(outputChanged.wait());
0224     QCOMPARE(output.scale(), 2);
0225     // changing to same value should not trigger
0226     outputHandle->setScale(2);
0227     QVERIFY(!outputChanged.wait(100));
0228 
0229     // change once more
0230     outputChanged.clear();
0231     outputHandle->setScale(4);
0232     QVERIFY(outputChanged.wait());
0233     QCOMPARE(output.scale(), 4);
0234 }
0235 
0236 void TestWaylandOutput::testSubPixel_data()
0237 {
0238     QTest::addColumn<KWayland::Client::Output::SubPixel>("expected");
0239     QTest::addColumn<KWin::Output::SubPixel>("actual");
0240 
0241     QTest::newRow("none") << KWayland::Client::Output::SubPixel::None << KWin::Output::SubPixel::None;
0242     QTest::newRow("horizontal/rgb") << KWayland::Client::Output::SubPixel::HorizontalRGB << KWin::Output::SubPixel::Horizontal_RGB;
0243     QTest::newRow("horizontal/bgr") << KWayland::Client::Output::SubPixel::HorizontalBGR << KWin::Output::SubPixel::Horizontal_BGR;
0244     QTest::newRow("vertical/rgb") << KWayland::Client::Output::SubPixel::VerticalRGB << KWin::Output::SubPixel::Vertical_RGB;
0245     QTest::newRow("vertical/bgr") << KWayland::Client::Output::SubPixel::VerticalBGR << KWin::Output::SubPixel::Vertical_BGR;
0246 }
0247 
0248 void TestWaylandOutput::testSubPixel()
0249 {
0250     QFETCH(KWin::Output::SubPixel, actual);
0251 
0252     auto outputHandle = std::make_unique<FakeOutput>();
0253     outputHandle->setMode(QSize(1024, 768), 60000);
0254     outputHandle->setSubPixel(actual);
0255 
0256     auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
0257 
0258     KWayland::Client::Registry registry;
0259     QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
0260     registry.create(m_connection->display());
0261     QVERIFY(registry.isValid());
0262     registry.setup();
0263     wl_display_flush(m_connection->display());
0264     QVERIFY(announced.wait());
0265 
0266     KWayland::Client::Output output;
0267     QSignalSpy outputChanged(&output, &KWayland::Client::Output::changed);
0268     output.setup(registry.bindOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>()));
0269     wl_display_flush(m_connection->display());
0270     if (outputChanged.isEmpty()) {
0271         QVERIFY(outputChanged.wait());
0272     }
0273 
0274     QTEST(output.subPixel(), "expected");
0275 }
0276 
0277 void TestWaylandOutput::testTransform_data()
0278 {
0279     QTest::addColumn<KWayland::Client::Output::Transform>("expected");
0280     QTest::addColumn<KWin::OutputTransform::Kind>("actual");
0281 
0282     QTest::newRow("90") << KWayland::Client::Output::Transform::Rotated90 << KWin::OutputTransform::Rotate90;
0283     QTest::newRow("180") << KWayland::Client::Output::Transform::Rotated180 << KWin::OutputTransform::Rotate180;
0284     QTest::newRow("270") << KWayland::Client::Output::Transform::Rotated270 << KWin::OutputTransform::Rotate270;
0285     QTest::newRow("Flipped") << KWayland::Client::Output::Transform::Flipped << KWin::OutputTransform::FlipX;
0286     QTest::newRow("Flipped 90") << KWayland::Client::Output::Transform::Flipped90 << KWin::OutputTransform::FlipX90;
0287     QTest::newRow("Flipped 180") << KWayland::Client::Output::Transform::Flipped180 << KWin::OutputTransform::FlipX180;
0288     QTest::newRow("Flipped 280") << KWayland::Client::Output::Transform::Flipped270 << KWin::OutputTransform::FlipX270;
0289 }
0290 
0291 void TestWaylandOutput::testTransform()
0292 {
0293     QFETCH(KWin::OutputTransform::Kind, actual);
0294 
0295     auto outputHandle = std::make_unique<FakeOutput>();
0296     outputHandle->setMode(QSize(1024, 768), 60000);
0297     outputHandle->setTransform(actual);
0298 
0299     auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
0300 
0301     using namespace KWin;
0302 
0303     KWayland::Client::Registry registry;
0304     QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
0305     registry.create(m_connection->display());
0306     QVERIFY(registry.isValid());
0307     registry.setup();
0308     wl_display_flush(m_connection->display());
0309     QVERIFY(announced.wait());
0310 
0311     KWayland::Client::Output *output = registry.createOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>(), &registry);
0312     QSignalSpy outputChanged(output, &KWayland::Client::Output::changed);
0313     wl_display_flush(m_connection->display());
0314     if (outputChanged.isEmpty()) {
0315         QVERIFY(outputChanged.wait());
0316     }
0317 
0318     QTEST(output->transform(), "expected");
0319 
0320     // change back to normal
0321     outputChanged.clear();
0322     outputHandle->setTransform(KWin::OutputTransform::Normal);
0323     if (outputChanged.isEmpty()) {
0324         QVERIFY(outputChanged.wait());
0325     }
0326     QCOMPARE(output->transform(), KWayland::Client::Output::Transform::Normal);
0327 }
0328 
0329 QTEST_GUILESS_MAIN(TestWaylandOutput)
0330 #include "test_wayland_output.moc"