Directory: | ./ |
---|---|
File: | src/client/output.cpp |
Date: | 2024-01-22 17:25:27 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 182 | 188 | 96.8% |
Branches: | 66 | 98 | 67.3% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /******************************************************************** | ||
2 | Copyright 2013 Martin Gräßlin <mgraesslin@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 "output.h" | ||
21 | #include "wayland_pointer_p.h" | ||
22 | // Qt | ||
23 | #include <QPoint> | ||
24 | #include <QRect> | ||
25 | #include <QSize> | ||
26 | #include <QVector> | ||
27 | // wayland | ||
28 | #include <wayland-client-protocol.h> | ||
29 | |||
30 | namespace Wrapland | ||
31 | { | ||
32 | |||
33 | namespace Client | ||
34 | { | ||
35 | |||
36 | namespace | ||
37 | { | ||
38 | typedef QList<Output::Mode> Modes; | ||
39 | } | ||
40 | |||
41 | class Q_DECL_HIDDEN Output::Private | ||
42 | { | ||
43 | public: | ||
44 | Private(Output* q); | ||
45 | ~Private(); | ||
46 | void setup(wl_output* o); | ||
47 | |||
48 | WaylandPointer<wl_output, wl_output_release> output; | ||
49 | 167 | EventQueue* queue = nullptr; | |
50 | QSize physicalSize; | ||
51 | QPoint globalPosition; | ||
52 | QString manufacturer; | ||
53 | QString model; | ||
54 | 167 | int scale = 1; | |
55 | 167 | SubPixel subPixel = SubPixel::Unknown; | |
56 | 167 | Transform transform = Transform::Normal; | |
57 | Modes modes; | ||
58 |
1/2✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
|
167 | Modes::iterator currentMode = modes.end(); |
59 | |||
60 | static Output* get(wl_output* o); | ||
61 | |||
62 | private: | ||
63 | static void geometryCallback(void* data, | ||
64 | wl_output* output, | ||
65 | int32_t x, | ||
66 | int32_t y, | ||
67 | int32_t physicalWidth, | ||
68 | int32_t physicalHeight, | ||
69 | int32_t subPixel, | ||
70 | char const* make, | ||
71 | char const* model, | ||
72 | int32_t transform); | ||
73 | static void modeCallback(void* data, | ||
74 | wl_output* output, | ||
75 | uint32_t flags, | ||
76 | int32_t width, | ||
77 | int32_t height, | ||
78 | int32_t refresh); | ||
79 | static void doneCallback(void* data, wl_output* output); | ||
80 | static void scaleCallback(void* data, wl_output* output, int32_t scale); | ||
81 | void setPhysicalSize(QSize const& size); | ||
82 | void setGlobalPosition(QPoint const& pos); | ||
83 | void setManufacturer(QString const& manufacturer); | ||
84 | void setModel(QString const& model); | ||
85 | void setScale(int scale); | ||
86 | void setSubPixel(SubPixel subPixel); | ||
87 | void setTransform(Transform transform); | ||
88 | void addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh); | ||
89 | |||
90 | Output* q; | ||
91 | static struct wl_output_listener s_outputListener; | ||
92 | |||
93 | static QVector<Private*> s_allOutputs; | ||
94 | }; | ||
95 | |||
96 | QVector<Output::Private*> Output::Private::s_allOutputs; | ||
97 | |||
98 | 501 | Output::Private::Private(Output* q) | |
99 | 167 | : q(q) | |
100 | { | ||
101 |
1/2✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
|
167 | s_allOutputs << this; |
102 | 167 | } | |
103 | |||
104 | 167 | Output::Private::~Private() | |
105 | { | ||
106 |
1/2✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
|
167 | s_allOutputs.removeOne(this); |
107 | 167 | } | |
108 | |||
109 | 9 | Output* Output::Private::get(wl_output* o) | |
110 | { | ||
111 | 18 | auto it = std::find_if(s_allOutputs.constBegin(), s_allOutputs.constEnd(), [o](Private* p) { | |
112 | 9 | const wl_output* reference = p->output; | |
113 | 9 | return reference == o; | |
114 | }); | ||
115 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
|
9 | if (it != s_allOutputs.constEnd()) { |
116 | 8 | return (*it)->q; | |
117 | } | ||
118 | 1 | return nullptr; | |
119 | 9 | } | |
120 | |||
121 | 167 | void Output::Private::setup(wl_output* o) | |
122 | { | ||
123 |
1/2✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
|
167 | Q_ASSERT(o); |
124 |
1/2✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
|
167 | Q_ASSERT(!output); |
125 | 167 | output.setup(o); | |
126 | 167 | wl_output_add_listener(output, &s_outputListener, this); | |
127 | 167 | } | |
128 | |||
129 | 3 | bool Output::Mode::operator==(Output::Mode const& m) const | |
130 | { | ||
131 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
|
3 | return size == m.size && refreshRate == m.refreshRate && flags == m.flags && output == m.output; |
132 | } | ||
133 | |||
134 | 167 | Output::Output(QObject* parent) | |
135 | 167 | : QObject(parent) | |
136 |
2/4✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 167 times.
|
167 | , d(new Private(this)) |
137 | 167 | { | |
138 | 167 | } | |
139 | |||
140 | 323 | Output::~Output() | |
141 | 323 | { | |
142 |
1/2✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
|
167 | d->output.release(); |
143 | 323 | } | |
144 | |||
145 | wl_output_listener Output::Private::s_outputListener = { | ||
146 | geometryCallback, | ||
147 | modeCallback, | ||
148 | doneCallback, | ||
149 | scaleCallback, | ||
150 | }; | ||
151 | |||
152 | 109 | void Output::Private::geometryCallback(void* data, | |
153 | wl_output* output, | ||
154 | int32_t x, | ||
155 | int32_t y, | ||
156 | int32_t physicalWidth, | ||
157 | int32_t physicalHeight, | ||
158 | int32_t subPixel, | ||
159 | char const* make, | ||
160 | char const* model, | ||
161 | int32_t transform) | ||
162 | { | ||
163 | Q_UNUSED(transform) | ||
164 | 109 | auto o = reinterpret_cast<Output::Private*>(data); | |
165 |
1/2✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
|
109 | Q_ASSERT(o->output == output); |
166 | 109 | o->setGlobalPosition(QPoint(x, y)); | |
167 |
1/2✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
|
109 | o->setManufacturer(make); |
168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | o->setModel(model); |
169 | 109 | o->setPhysicalSize(QSize(physicalWidth, physicalHeight)); | |
170 | 218 | auto toSubPixel = [subPixel]() { | |
171 |
6/7✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 104 times.
✗ Branch 6 not taken.
|
109 | switch (subPixel) { |
172 | case WL_OUTPUT_SUBPIXEL_NONE: | ||
173 | 1 | return SubPixel::None; | |
174 | case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: | ||
175 | 1 | return SubPixel::HorizontalRGB; | |
176 | case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: | ||
177 | 1 | return SubPixel::HorizontalBGR; | |
178 | case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: | ||
179 | 1 | return SubPixel::VerticalRGB; | |
180 | case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: | ||
181 | 1 | return SubPixel::VerticalBGR; | |
182 | 104 | case WL_OUTPUT_SUBPIXEL_UNKNOWN: | |
183 | default: | ||
184 | 104 | return SubPixel::Unknown; | |
185 | } | ||
186 | 109 | }; | |
187 | 109 | o->setSubPixel(toSubPixel()); | |
188 | 218 | auto toTransform = [transform]() { | |
189 |
8/9✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 102 times.
✗ Branch 8 not taken.
|
109 | switch (transform) { |
190 | case WL_OUTPUT_TRANSFORM_90: | ||
191 | 1 | return Transform::Rotated90; | |
192 | case WL_OUTPUT_TRANSFORM_180: | ||
193 | 1 | return Transform::Rotated180; | |
194 | case WL_OUTPUT_TRANSFORM_270: | ||
195 | 1 | return Transform::Rotated270; | |
196 | case WL_OUTPUT_TRANSFORM_FLIPPED: | ||
197 | 1 | return Transform::Flipped; | |
198 | case WL_OUTPUT_TRANSFORM_FLIPPED_90: | ||
199 | 1 | return Transform::Flipped90; | |
200 | case WL_OUTPUT_TRANSFORM_FLIPPED_180: | ||
201 | 1 | return Transform::Flipped180; | |
202 | case WL_OUTPUT_TRANSFORM_FLIPPED_270: | ||
203 | 1 | return Transform::Flipped270; | |
204 | 102 | case WL_OUTPUT_TRANSFORM_NORMAL: | |
205 | default: | ||
206 | 102 | return Transform::Normal; | |
207 | } | ||
208 | 109 | }; | |
209 | 109 | o->setTransform(toTransform()); | |
210 | 109 | } | |
211 | |||
212 | 134 | void Output::Private::modeCallback(void* data, | |
213 | wl_output* output, | ||
214 | uint32_t flags, | ||
215 | int32_t width, | ||
216 | int32_t height, | ||
217 | int32_t refresh) | ||
218 | { | ||
219 | 134 | auto o = reinterpret_cast<Output::Private*>(data); | |
220 |
1/2✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
|
134 | Q_ASSERT(o->output == output); |
221 | 134 | o->addMode(flags, width, height, refresh); | |
222 | 134 | } | |
223 | |||
224 | 134 | void Output::Private::addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh) | |
225 | { | ||
226 | 134 | Mode mode; | |
227 |
1/2✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
|
134 | mode.output = QPointer<Output>(q); |
228 | 134 | mode.refreshRate = refresh; | |
229 | 134 | mode.size = QSize(width, height); | |
230 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 98 times.
|
134 | if (flags & WL_OUTPUT_MODE_CURRENT) { |
231 | 98 | mode.flags |= Mode::Flag::Current; | |
232 | 98 | } | |
233 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 22 times.
|
134 | if (flags & WL_OUTPUT_MODE_PREFERRED) { |
234 | 22 | mode.flags |= Mode::Flag::Preferred; | |
235 | 22 | } | |
236 | |||
237 |
1/2✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
|
134 | modes.append(mode); |
238 | 134 | bool existing = false; | |
239 | |||
240 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 98 times.
|
134 | if (flags & WL_OUTPUT_MODE_CURRENT) { |
241 |
2/2✓ Branch 0 taken 98 times.
✓ Branch 1 taken 51 times.
|
149 | for (int i = modes.size() - 2; i >= 0; i--) { |
242 |
1/2✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
|
51 | auto& m = modes[i]; |
243 | |||
244 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 46 times.
|
51 | if (m.flags.testFlag(Mode::Flag::Current)) { |
245 | 5 | m.flags &= ~Mode::Flags(Mode::Flag::Current); | |
246 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | Q_EMIT q->modeChanged(m); |
247 | 5 | } | |
248 | |||
249 |
3/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
51 | if (m.refreshRate == mode.refreshRate && m.size == mode.size) { |
250 |
4/8✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
5 | modes.erase(modes.begin() + i); |
251 | 5 | existing = true; | |
252 | 5 | } | |
253 | 51 | } | |
254 | |||
255 |
2/4✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
|
98 | currentMode = modes.end() - 1; |
256 | 98 | } | |
257 | |||
258 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 129 times.
|
134 | if (existing) { |
259 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | Q_EMIT q->modeChanged(mode); |
260 | 5 | } else { | |
261 |
1/2✓ Branch 0 taken 129 times.
✗ Branch 1 not taken.
|
129 | Q_EMIT q->modeAdded(mode); |
262 | } | ||
263 | 134 | } | |
264 | |||
265 | 98 | void Output::Private::scaleCallback(void* data, wl_output* output, int32_t scale) | |
266 | { | ||
267 | 98 | auto o = reinterpret_cast<Output::Private*>(data); | |
268 |
1/2✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
|
98 | Q_ASSERT(o->output == output); |
269 | 98 | o->setScale(scale); | |
270 | 98 | } | |
271 | |||
272 | 114 | void Output::Private::doneCallback(void* data, wl_output* output) | |
273 | { | ||
274 | 114 | auto o = reinterpret_cast<Output::Private*>(data); | |
275 |
1/2✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
|
114 | Q_ASSERT(o->output == output); |
276 | 114 | Q_EMIT o->q->changed(); | |
277 | 114 | } | |
278 | |||
279 | 167 | void Output::setup(wl_output* output) | |
280 | { | ||
281 | 167 | d->setup(output); | |
282 | 167 | } | |
283 | |||
284 | ✗ | EventQueue* Output::eventQueue() const | |
285 | { | ||
286 | ✗ | return d->queue; | |
287 | } | ||
288 | |||
289 | 156 | void Output::setEventQueue(EventQueue* queue) | |
290 | { | ||
291 | 156 | d->queue = queue; | |
292 | 156 | } | |
293 | |||
294 | 109 | void Output::Private::setGlobalPosition(QPoint const& pos) | |
295 | { | ||
296 | 109 | globalPosition = pos; | |
297 | 109 | } | |
298 | |||
299 | 109 | void Output::Private::setManufacturer(QString const& m) | |
300 | { | ||
301 | 109 | manufacturer = m; | |
302 | 109 | } | |
303 | |||
304 | 109 | void Output::Private::setModel(QString const& m) | |
305 | { | ||
306 | 109 | model = m; | |
307 | 109 | } | |
308 | |||
309 | 109 | void Output::Private::setPhysicalSize(QSize const& size) | |
310 | { | ||
311 | 109 | physicalSize = size; | |
312 | 109 | } | |
313 | |||
314 | 98 | void Output::Private::setScale(int s) | |
315 | { | ||
316 | 98 | scale = s; | |
317 | 98 | } | |
318 | |||
319 | 2 | QRect Output::geometry() const | |
320 | { | ||
321 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (d->currentMode == d->modes.end()) { |
322 | 1 | return QRect(); | |
323 | } | ||
324 | 1 | return QRect(d->globalPosition, pixelSize()); | |
325 | 2 | } | |
326 | |||
327 | 109 | void Output::Private::setSubPixel(Output::SubPixel s) | |
328 | { | ||
329 | 109 | subPixel = s; | |
330 | 109 | } | |
331 | |||
332 | 109 | void Output::Private::setTransform(Output::Transform t) | |
333 | { | ||
334 | 109 | transform = t; | |
335 | 109 | } | |
336 | |||
337 | 2 | QPoint Output::globalPosition() const | |
338 | { | ||
339 | 2 | return d->globalPosition; | |
340 | } | ||
341 | |||
342 | 2 | QString Output::manufacturer() const | |
343 | { | ||
344 | 2 | return d->manufacturer; | |
345 | } | ||
346 | |||
347 | 2 | QString Output::model() const | |
348 | { | ||
349 | 2 | return d->model; | |
350 | } | ||
351 | |||
352 | 3 | wl_output* Output::output() | |
353 | { | ||
354 | 3 | return d->output; | |
355 | } | ||
356 | |||
357 | 2 | QSize Output::physicalSize() const | |
358 | { | ||
359 | 2 | return d->physicalSize; | |
360 | } | ||
361 | |||
362 | 6 | QSize Output::pixelSize() const | |
363 | { | ||
364 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
|
6 | if (d->currentMode == d->modes.end()) { |
365 | 1 | return QSize(); | |
366 | } | ||
367 | 5 | return (*d->currentMode).size; | |
368 | 6 | } | |
369 | |||
370 | 2 | int Output::refreshRate() const | |
371 | { | ||
372 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (d->currentMode == d->modes.end()) { |
373 | 1 | return 0; | |
374 | } | ||
375 | 1 | return (*d->currentMode).refreshRate; | |
376 | 2 | } | |
377 | |||
378 | 8 | int Output::scale() const | |
379 | { | ||
380 | 8 | return d->scale; | |
381 | } | ||
382 | |||
383 | 16 | bool Output::isValid() const | |
384 | { | ||
385 | 16 | return d->output.isValid(); | |
386 | } | ||
387 | |||
388 | 12 | Output::SubPixel Output::subPixel() const | |
389 | { | ||
390 | 12 | return d->subPixel; | |
391 | } | ||
392 | |||
393 | 16 | Output::Transform Output::transform() const | |
394 | { | ||
395 | 16 | return d->transform; | |
396 | } | ||
397 | |||
398 | 2 | QList<Output::Mode> Output::modes() const | |
399 | { | ||
400 | 2 | return d->modes; | |
401 | } | ||
402 | |||
403 | 12 | Output::operator wl_output*() | |
404 | { | ||
405 | 12 | return d->output; | |
406 | } | ||
407 | |||
408 | ✗ | Output::operator wl_output*() const | |
409 | { | ||
410 | ✗ | return d->output; | |
411 | } | ||
412 | |||
413 | 9 | Output* Output::get(wl_output* o) | |
414 | { | ||
415 | 9 | return Private::get(o); | |
416 | } | ||
417 | |||
418 | ✗ | void Output::release() | |
419 | { | ||
420 | ✗ | d->output.release(); | |
421 | } | ||
422 | |||
423 | } | ||
424 | } | ||
425 |