KWin
Loading...
Searching...
No Matches
test_wayland_output.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6// Qt
7#include <QSignalSpy>
8#include <QTest>
9// KWin
10#include "wayland/display.h"
11#include "wayland/output.h"
12
13#include "KWayland/Client/connection_thread.h"
14#include "KWayland/Client/event_queue.h"
15#include "KWayland/Client/output.h"
16#include "KWayland/Client/registry.h"
17
19
20// Wayland
21#include <wayland-client-protocol.h>
22
23class TestWaylandOutput : public QObject
24{
25 Q_OBJECT
26public:
27 explicit TestWaylandOutput(QObject *parent = nullptr);
28private Q_SLOTS:
29 void init();
30 void cleanup();
31
32 void testRegistry();
33 void testModeChange();
34 void testScaleChange();
35
36 void testSubPixel_data();
37 void testSubPixel();
38
39 void testTransform_data();
40 void testTransform();
41
42private:
43 KWin::Display *m_display;
44 KWayland::Client::ConnectionThread *m_connection;
45 KWayland::Client::EventQueue *m_queue;
46 QThread *m_thread;
47};
48
49static const QString s_socketName = QStringLiteral("kwin-test-wayland-output-0");
50
52 : QObject(parent)
53 , m_display(nullptr)
54 , m_connection(nullptr)
55 , m_thread(nullptr)
56{
57}
58
59void TestWaylandOutput::init()
60{
61 delete m_display;
62 m_display = new KWin::Display(this);
63 m_display->addSocketName(s_socketName);
64 m_display->start();
65 QVERIFY(m_display->isRunning());
66
67 // setup connection
68 m_connection = new KWayland::Client::ConnectionThread;
69 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
70 m_connection->setSocketName(s_socketName);
71
72 m_thread = new QThread(this);
73 m_connection->moveToThread(m_thread);
74 m_thread->start();
75
76 m_connection->initConnection();
77 QVERIFY(connectedSpy.wait());
78
79 m_queue = new KWayland::Client::EventQueue(this);
80 QVERIFY(!m_queue->isValid());
81 m_queue->setup(m_connection);
82 QVERIFY(m_queue->isValid());
83}
84
85void TestWaylandOutput::cleanup()
86{
87 if (m_queue) {
88 delete m_queue;
89 m_queue = nullptr;
90 }
91 if (m_thread) {
92 m_thread->quit();
93 m_thread->wait();
94 delete m_thread;
95 m_thread = nullptr;
96 }
97 delete m_connection;
98 m_connection = nullptr;
99
100 delete m_display;
101 m_display = nullptr;
102}
103
104void TestWaylandOutput::testRegistry()
105{
106 auto outputHandle = std::make_unique<FakeOutput>();
107 outputHandle->setMode(QSize(1024, 768), 60000);
108 outputHandle->moveTo(QPoint(100, 50));
109 outputHandle->setPhysicalSize(QSize(200, 100));
110
111 auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
112
113 KWayland::Client::Registry registry;
114 QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
115 registry.create(m_connection->display());
116 QVERIFY(registry.isValid());
117 registry.setup();
118 wl_display_flush(m_connection->display());
119 QVERIFY(announced.wait());
120
121 KWayland::Client::Output output;
122 QVERIFY(!output.isValid());
123 QCOMPARE(output.geometry(), QRect());
124 QCOMPARE(output.globalPosition(), QPoint());
125 QCOMPARE(output.manufacturer(), QString());
126 QCOMPARE(output.model(), QString());
127 QCOMPARE(output.physicalSize(), QSize());
128 QCOMPARE(output.pixelSize(), QSize());
129 QCOMPARE(output.refreshRate(), 0);
130 QCOMPARE(output.scale(), 1);
131 QCOMPARE(output.subPixel(), KWayland::Client::Output::SubPixel::Unknown);
132 QCOMPARE(output.transform(), KWayland::Client::Output::Transform::Normal);
133
134 QSignalSpy outputChanged(&output, &KWayland::Client::Output::changed);
135 auto o = registry.bindOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>());
136 QVERIFY(!KWayland::Client::Output::get(o));
137 output.setup(o);
138 QCOMPARE(KWayland::Client::Output::get(o), &output);
139 wl_display_flush(m_connection->display());
140 QVERIFY(outputChanged.wait());
141
142 QCOMPARE(output.geometry(), QRect(100, 50, 1024, 768));
143 QCOMPARE(output.globalPosition(), QPoint(100, 50));
144 QCOMPARE(output.manufacturer(), QString());
145 QCOMPARE(output.model(), QString());
146 QCOMPARE(output.physicalSize(), QSize(200, 100));
147 QCOMPARE(output.pixelSize(), QSize(1024, 768));
148 QCOMPARE(output.refreshRate(), 60000);
149 QCOMPARE(output.scale(), 1);
150 // for xwayland output it's unknown
151 QCOMPARE(output.subPixel(), KWayland::Client::Output::SubPixel::Unknown);
152 // for xwayland transform is normal
153 QCOMPARE(output.transform(), KWayland::Client::Output::Transform::Normal);
154}
155
156void TestWaylandOutput::testModeChange()
157{
158 auto outputHandle = std::make_unique<FakeOutput>();
159 outputHandle->setMode(QSize(1024, 768), 60000);
160
161 auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
162
163 KWayland::Client::Registry registry;
164 QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
165 registry.setEventQueue(m_queue);
166 registry.create(m_connection->display());
167 QVERIFY(registry.isValid());
168 registry.setup();
169 wl_display_flush(m_connection->display());
170 QVERIFY(announced.wait());
171
172 KWayland::Client::Output output;
173 QSignalSpy outputChanged(&output, &KWayland::Client::Output::changed);
174 QSignalSpy modeAddedSpy(&output, &KWayland::Client::Output::modeAdded);
175 output.setup(registry.bindOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>()));
176 wl_display_flush(m_connection->display());
177 QVERIFY(outputChanged.wait());
178 QCOMPARE(modeAddedSpy.count(), 1);
179 QCOMPARE(modeAddedSpy.at(0).first().value<KWayland::Client::Output::Mode>().size, QSize(1024, 768));
180 QCOMPARE(modeAddedSpy.at(0).first().value<KWayland::Client::Output::Mode>().refreshRate, 60000);
181 QCOMPARE(modeAddedSpy.at(0).first().value<KWayland::Client::Output::Mode>().flags, KWayland::Client::Output::Mode::Flags(KWayland::Client::Output::Mode::Flag::Current));
182 QCOMPARE(modeAddedSpy.at(0).first().value<KWayland::Client::Output::Mode>().output, QPointer<KWayland::Client::Output>(&output));
183 QCOMPARE(output.pixelSize(), QSize(1024, 768));
184 QCOMPARE(output.refreshRate(), 60000);
185
186 // change once more
187 outputHandle->setMode(QSize(1280, 1024), 90000);
188 QVERIFY(outputChanged.wait());
189 QCOMPARE(modeAddedSpy.count(), 2);
190 QCOMPARE(modeAddedSpy.at(1).first().value<KWayland::Client::Output::Mode>().size, QSize(1280, 1024));
191 QCOMPARE(modeAddedSpy.at(1).first().value<KWayland::Client::Output::Mode>().refreshRate, 90000);
192 QCOMPARE(modeAddedSpy.at(1).first().value<KWayland::Client::Output::Mode>().flags, KWayland::Client::Output::Mode::Flags(KWayland::Client::Output::Mode::Flag::Current));
193 QCOMPARE(modeAddedSpy.at(1).first().value<KWayland::Client::Output::Mode>().output, QPointer<KWayland::Client::Output>(&output));
194 QCOMPARE(output.pixelSize(), QSize(1280, 1024));
195 QCOMPARE(output.refreshRate(), 90000);
196}
197
198void TestWaylandOutput::testScaleChange()
199{
200 auto outputHandle = std::make_unique<FakeOutput>();
201 outputHandle->setMode(QSize(1024, 768), 60000);
202
203 auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
204
205 KWayland::Client::Registry registry;
206 QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
207 registry.create(m_connection->display());
208 QVERIFY(registry.isValid());
209 registry.setup();
210 wl_display_flush(m_connection->display());
211 QVERIFY(announced.wait());
212
213 KWayland::Client::Output output;
214 QSignalSpy outputChanged(&output, &KWayland::Client::Output::changed);
215 output.setup(registry.bindOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>()));
216 wl_display_flush(m_connection->display());
217 QVERIFY(outputChanged.wait());
218 QCOMPARE(output.scale(), 1);
219
220 // change the scale
221 outputChanged.clear();
222 outputHandle->setScale(2);
223 QVERIFY(outputChanged.wait());
224 QCOMPARE(output.scale(), 2);
225 // changing to same value should not trigger
226 outputHandle->setScale(2);
227 QVERIFY(!outputChanged.wait(100));
228
229 // change once more
230 outputChanged.clear();
231 outputHandle->setScale(4);
232 QVERIFY(outputChanged.wait());
233 QCOMPARE(output.scale(), 4);
234}
235
236void TestWaylandOutput::testSubPixel_data()
237{
238 QTest::addColumn<KWayland::Client::Output::SubPixel>("expected");
239 QTest::addColumn<KWin::Output::SubPixel>("actual");
240
241 QTest::newRow("none") << KWayland::Client::Output::SubPixel::None << KWin::Output::SubPixel::None;
242 QTest::newRow("horizontal/rgb") << KWayland::Client::Output::SubPixel::HorizontalRGB << KWin::Output::SubPixel::Horizontal_RGB;
243 QTest::newRow("horizontal/bgr") << KWayland::Client::Output::SubPixel::HorizontalBGR << KWin::Output::SubPixel::Horizontal_BGR;
244 QTest::newRow("vertical/rgb") << KWayland::Client::Output::SubPixel::VerticalRGB << KWin::Output::SubPixel::Vertical_RGB;
245 QTest::newRow("vertical/bgr") << KWayland::Client::Output::SubPixel::VerticalBGR << KWin::Output::SubPixel::Vertical_BGR;
246}
247
248void TestWaylandOutput::testSubPixel()
249{
250 QFETCH(KWin::Output::SubPixel, actual);
251
252 auto outputHandle = std::make_unique<FakeOutput>();
253 outputHandle->setMode(QSize(1024, 768), 60000);
254 outputHandle->setSubPixel(actual);
255
256 auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
257
258 KWayland::Client::Registry registry;
259 QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
260 registry.create(m_connection->display());
261 QVERIFY(registry.isValid());
262 registry.setup();
263 wl_display_flush(m_connection->display());
264 QVERIFY(announced.wait());
265
266 KWayland::Client::Output output;
267 QSignalSpy outputChanged(&output, &KWayland::Client::Output::changed);
268 output.setup(registry.bindOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>()));
269 wl_display_flush(m_connection->display());
270 if (outputChanged.isEmpty()) {
271 QVERIFY(outputChanged.wait());
272 }
273
274 QTEST(output.subPixel(), "expected");
275}
276
277void TestWaylandOutput::testTransform_data()
278{
279 QTest::addColumn<KWayland::Client::Output::Transform>("expected");
280 QTest::addColumn<KWin::OutputTransform::Kind>("actual");
281
282 QTest::newRow("90") << KWayland::Client::Output::Transform::Rotated90 << KWin::OutputTransform::Rotate90;
283 QTest::newRow("180") << KWayland::Client::Output::Transform::Rotated180 << KWin::OutputTransform::Rotate180;
284 QTest::newRow("270") << KWayland::Client::Output::Transform::Rotated270 << KWin::OutputTransform::Rotate270;
285 QTest::newRow("Flipped") << KWayland::Client::Output::Transform::Flipped << KWin::OutputTransform::FlipX;
286 QTest::newRow("Flipped 90") << KWayland::Client::Output::Transform::Flipped90 << KWin::OutputTransform::FlipX90;
287 QTest::newRow("Flipped 180") << KWayland::Client::Output::Transform::Flipped180 << KWin::OutputTransform::FlipX180;
288 QTest::newRow("Flipped 280") << KWayland::Client::Output::Transform::Flipped270 << KWin::OutputTransform::FlipX270;
289}
290
291void TestWaylandOutput::testTransform()
292{
293 QFETCH(KWin::OutputTransform::Kind, actual);
294
295 auto outputHandle = std::make_unique<FakeOutput>();
296 outputHandle->setMode(QSize(1024, 768), 60000);
297 outputHandle->setTransform(actual);
298
299 auto outputInterface = std::make_unique<KWin::OutputInterface>(m_display, outputHandle.get());
300
301 using namespace KWin;
302
303 KWayland::Client::Registry registry;
304 QSignalSpy announced(&registry, &KWayland::Client::Registry::outputAnnounced);
305 registry.create(m_connection->display());
306 QVERIFY(registry.isValid());
307 registry.setup();
308 wl_display_flush(m_connection->display());
309 QVERIFY(announced.wait());
310
311 KWayland::Client::Output *output = registry.createOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>(), &registry);
312 QSignalSpy outputChanged(output, &KWayland::Client::Output::changed);
313 wl_display_flush(m_connection->display());
314 if (outputChanged.isEmpty()) {
315 QVERIFY(outputChanged.wait());
316 }
317
318 QTEST(output->transform(), "expected");
319
320 // change back to normal
321 outputChanged.clear();
322 outputHandle->setTransform(KWin::OutputTransform::Normal);
323 if (outputChanged.isEmpty()) {
324 QVERIFY(outputChanged.wait());
325 }
326 QCOMPARE(output->transform(), KWayland::Client::Output::Transform::Normal);
327}
328
329QTEST_GUILESS_MAIN(TestWaylandOutput)
330#include "test_wayland_output.moc"
Class holding the Wayland server display loop.
Definition display.h:34
bool addSocketName(const QString &name=QString())
Definition display.cpp:68
bool isRunning() const
Definition display.cpp:144
bool start()
Definition display.cpp:92
TestWaylandOutput(QObject *parent=nullptr)
KWayland::Client::Registry * registry