1 /********************************************************************
2 Copyright 2018 David Edmundson <davidedmundson@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #include <QtTest>
21
22 #include "../../server/display.h"
23 #include "../../server/output.h"
24
25 #include "../../server/xdg_output.h"
26 #include "../../src/client/connection_thread.h"
27 #include "../../src/client/event_queue.h"
28 #include "../../src/client/output.h"
29 #include "../../src/client/registry.h"
30 #include "../../src/client/xdgoutput.h"
31
32 class TestXdgOutput : public QObject
33 {
34 Q_OBJECT
35 public:
36 explicit TestXdgOutput(QObject* parent = nullptr);
37 private Q_SLOTS:
38 void init();
39 void cleanup();
40
41 void testChanges_data();
42 void testChanges();
43
44 private:
45 Wrapland::Server::Display* m_display;
46 Wrapland::Server::Output* m_serverOutput;
47
48 std::string m_name = "HDMI-A";
49 std::string m_make = "Foocorp";
50 std::string m_model = "Barmodel";
51 std::string m_description;
52
53 Wrapland::Client::ConnectionThread* m_connection;
54 Wrapland::Client::EventQueue* m_queue;
55 QThread* m_thread;
56 };
57
58 static const QString s_socketName = QStringLiteral("wrapland-test-xdg-output-0");
59
TestXdgOutput(QObject * parent)60 TestXdgOutput::TestXdgOutput(QObject* parent)
61 : QObject(parent)
62 , m_display(nullptr)
63 , m_serverOutput(nullptr)
64 , m_connection(nullptr)
65 , m_thread(nullptr)
66 {
67 }
68
init()69 void TestXdgOutput::init()
70 {
71 using namespace Wrapland::Server;
72 delete m_display;
73 m_display = new Display(this);
74 m_display->setSocketName(s_socketName);
75 m_display->start();
76
77 m_serverOutput = new Output(m_display);
78 m_serverOutput->add_mode(Output::Mode{QSize(1920, 1080), 60000, true, 1});
79 m_serverOutput->set_mode(1);
80 m_serverOutput->set_enabled(true);
81
82 m_serverOutput->set_name(m_name);
83 m_serverOutput->set_make(m_make);
84 m_serverOutput->set_model(m_model);
85
86 m_serverOutput->generate_description();
87 m_description = m_serverOutput->description();
88
89 // Not a sensible position for one monitor but works for this test. And a 1.5 scale factor.
90 m_serverOutput->set_geometry(QRectF(QPoint(11, 12), QSize(1280, 720)));
91 m_serverOutput->done();
92
93 // setup connection
94 m_connection = new Wrapland::Client::ConnectionThread;
95 QSignalSpy connectedSpy(m_connection, &Wrapland::Client::ConnectionThread::establishedChanged);
96 m_connection->setSocketName(s_socketName);
97
98 m_thread = new QThread(this);
99 m_connection->moveToThread(m_thread);
100 m_thread->start();
101
102 m_connection->establishConnection();
103 QVERIFY(connectedSpy.count() || connectedSpy.wait());
104 QCOMPARE(connectedSpy.count(), 1);
105
106 m_queue = new Wrapland::Client::EventQueue(this);
107 QVERIFY(!m_queue->isValid());
108 m_queue->setup(m_connection);
109 QVERIFY(m_queue->isValid());
110 }
111
cleanup()112 void TestXdgOutput::cleanup()
113 {
114 if (m_queue) {
115 delete m_queue;
116 m_queue = nullptr;
117 }
118 if (m_thread) {
119 m_thread->quit();
120 m_thread->wait();
121 delete m_thread;
122 m_thread = nullptr;
123 }
124 delete m_connection;
125 m_connection = nullptr;
126
127 delete m_serverOutput;
128 m_serverOutput = nullptr;
129
130 delete m_display;
131 m_display = nullptr;
132 }
133
testChanges_data()134 void TestXdgOutput::testChanges_data()
135 {
136 QTest::addColumn<int>("client_version");
137
138 QTest::newRow("v1") << 1;
139 QTest::newRow("v2") << 2;
140 QTest::newRow("v3") << 3;
141 }
142
testChanges()143 void TestXdgOutput::testChanges()
144 {
145 // Verify the server modes.
146 QFETCH(int, client_version);
147
148 Wrapland::Client::Registry registry;
149 QSignalSpy announced(®istry, SIGNAL(outputAnnounced(quint32, quint32)));
150 QSignalSpy xdgOutputAnnounced(®istry, SIGNAL(xdgOutputAnnounced(quint32, quint32)));
151
152 registry.setEventQueue(m_queue);
153 registry.create(m_connection->display());
154 QVERIFY(registry.isValid());
155 registry.setup();
156 QVERIFY(announced.wait());
157 if (xdgOutputAnnounced.count() != 1) {
158 QVERIFY(xdgOutputAnnounced.wait());
159 }
160
161 Wrapland::Client::Output output;
162 QSignalSpy outputChanged(&output, SIGNAL(changed()));
163
164 output.setup(registry.bindOutput(announced.first().first().value<quint32>(),
165 announced.first().last().value<quint32>()));
166 QVERIFY(outputChanged.wait());
167
168 QVERIFY(xdgOutputAnnounced.first().last().value<quint32>()
169 >= static_cast<quint32>(client_version));
170
171 std::unique_ptr<Wrapland::Client::XdgOutputManager> xdgOutputManager(
172 registry.createXdgOutputManager(
173 xdgOutputAnnounced.first().first().value<quint32>(), client_version, this));
174
175 std::unique_ptr<Wrapland::Client::XdgOutput> xdgOutput(
176 xdgOutputManager->getXdgOutput(&output, this));
177 QSignalSpy xdgOutputChanged(xdgOutput.get(), SIGNAL(changed()));
178
179 // check details are sent on client bind
180 QVERIFY(xdgOutputChanged.wait());
181 xdgOutputChanged.clear();
182
183 QCOMPARE(xdgOutput->logicalPosition(), QPoint(11, 12));
184 QCOMPARE(xdgOutput->logicalSize(), QSize(1280, 720));
185
186 if (client_version == 1) {
187 QCOMPARE(xdgOutput->name(), "");
188 QCOMPARE(xdgOutput->description(), "");
189 } else {
190 QCOMPARE(xdgOutput->name(), m_name);
191 QCOMPARE(xdgOutput->description(), m_description);
192 }
193
194 // dynamic updates
195 m_serverOutput->set_geometry(QRectF(QPoint(1000, 2000), QSize(100, 200)));
196
197 std::string updated_description = "Updated xdg-output description";
198 m_serverOutput->set_description(updated_description);
199 m_serverOutput->done();
200
201 QVERIFY(xdgOutputChanged.wait());
202 QCOMPARE(xdgOutputChanged.count(), 1);
203
204 QCOMPARE(xdgOutput->logicalPosition(), QPoint(1000, 2000));
205 QCOMPARE(xdgOutput->logicalSize(), QSize(100, 200));
206
207 if (client_version == 1) {
208 QCOMPARE(xdgOutput->description(), "");
209 } else if (client_version == 2) {
210 // Description is immutable in version 2.
211 QCOMPARE(xdgOutput->description(), m_description);
212 } else {
213 QCOMPARE(xdgOutput->description(), updated_description);
214 }
215 }
216
217 QTEST_GUILESS_MAIN(TestXdgOutput)
218 #include "xdg_output.moc"
219