Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwaylandxdgoutputv1.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:critical reason:network-protocol
4
5#include <QWaylandCompositor>
6
9
10#include <wayland-server.h>
11
12QT_BEGIN_NAMESPACE
13/*!
14 * \qmltype XdgOutputV1
15 * \nativetype QWaylandXdgOutputV1
16 * \inqmlmodule QtWayland.Compositor.XdgShell
17 * \brief Represents a display in a compositor.
18 */
19
20/*!
21 * \class QWaylandXdgOutputV1
22 * \inmodule QtWaylandCompositor
23 * \brief Represents a display in a compositor.
24 */
25
26/*!
27 * \qmltype XdgOutputManagerV1
28 * \nativetype QWaylandXdgOutputManagerV1
29 * \inqmlmodule QtWayland.Compositor.XdgShell
30 * \since 5.14
31 * \brief Provides an extension for describing outputs in a desktop oriented fashion.
32 *
33 * The XdgOutputManagerV1 extension provides a way for a compositor to describe outputs in a way
34 * that is more in line with the concept of an output on desktop oriented systems.
35 *
36 * Some information may not make sense in other applications such as IVI systems.
37 *
38 * Typically the global compositor space on a desktop system is made of a
39 * contiguous or overlapping set of rectangular regions.
40 *
41 * XdgOutputManagerV1 corresponds to the Wayland interface, \c zxdg_output_manager_v1.
42 *
43 * To provide the functionality of the extension in a compositor, create an instance of the
44 * XdgOutputManagerV1 component and add it to the list of extensions supported by the compositor,
45 * and associated each XdgOutputV1 with its WaylandOutput:
46 *
47 * \qml
48 * import QtWayland.Compositor
49 *
50 * WaylandCompositor {
51 * XdgOutputManagerV1 {
52 * WaylandOutput {
53 * id: output1
54 *
55 * position: Qt.point(0, 0)
56 * window: Window {}
57 *
58 * XdgOutputV1 {
59 * name: "WL-1"
60 * logicalPosition: output1.position
61 * logicalSize: Qt.size(output1.geometry.width / output1.scaleFactor,
62 * output1.geometry.height / output1.scaleFactor)
63 * }
64 * }
65 *
66 * WaylandOutput {
67 * id: output2
68 *
69 * position: Qt.point(800, 0)
70 * window: Window {}
71 *
72 * XdgOutputV1 {
73 * name: "WL-2"
74 * logicalPosition: output2.position
75 * logicalSize: Qt.size(output2.geometry.width / output2.scaleFactor,
76 * output2.geometry.height / output2.scaleFactor)
77 * }
78 * }
79 * }
80 * }
81 * \endqml
82 */
83
84/*!
85 * \class QWaylandXdgOutputManagerV1
86 * \inmodule QtWaylandCompositor
87 * \since 5.14
88 * \brief Provides an extension for describing outputs in a desktop oriented fashion.
89 *
90 * The QWaylandXdgOutputManagerV1 extension provides a way for a compositor to describe outputs in a way
91 * that is more in line with the concept of an output on desktop oriented systems.
92 *
93 * Some information may not make sense in other applications such as IVI systems.
94 *
95 * QWaylandXdgOutputManagerV1 corresponds to the Wayland interface, \c zxdg_output_manager_v1.
96 */
97
98/*!
99 * Constructs a QWaylandXdgOutputManagerV1 object.
100 */
101QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1()
102 : QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1>(*new QWaylandXdgOutputManagerV1Private())
103{
104}
105
106/*!
107 * Constructs a QWaylandXdgOutputManagerV1 object for the provided \a compositor.
108 */
109QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1(QWaylandCompositor *compositor)
110 : QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1>(compositor, *new QWaylandXdgOutputManagerV1Private())
111{
112}
113
114// QWaylandXdgOutputManagerV1Private
115
116/*!
117 * Initializes the extension.
118 */
119void QWaylandXdgOutputManagerV1::initialize()
120{
121 Q_D(QWaylandXdgOutputManagerV1);
122
123 QWaylandCompositorExtensionTemplate::initialize();
124 QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
125 if (!compositor) {
126 qCWarning(qLcWaylandCompositor) << "Failed to find QWaylandCompositor when initializing QWaylandXdgOutputManagerV1";
127 return;
128 }
129 d->init(compositor->display(), d->interfaceVersion());
130}
131
132/*!
133 * Returns the Wayland interface for QWaylandXdgOutputManagerV1.
134 */
135const wl_interface *QWaylandXdgOutputManagerV1::interface()
136{
137 return QWaylandXdgOutputManagerV1Private::interface();
138}
139
140// QWaylandXdgOutputManagerV1Private
141
142void QWaylandXdgOutputManagerV1Private::registerXdgOutput(QWaylandOutput *output, QWaylandXdgOutputV1 *xdgOutput)
143{
144 if (!xdgOutputs.contains(output)) {
145 xdgOutputs[output] = xdgOutput;
146 }
147}
148
149void QWaylandXdgOutputManagerV1Private::unregisterXdgOutput(QWaylandOutput *output)
150{
151 xdgOutputs.remove(output);
152}
153
154QWaylandXdgOutputV1 *QWaylandXdgOutputManagerV1Private::xdgOutput(QWaylandOutput *output) const
155{
156 return xdgOutputs.value(output);
157}
158
159void QWaylandXdgOutputManagerV1Private::zxdg_output_manager_v1_get_xdg_output(Resource *resource,
160 uint32_t id,
161 wl_resource *outputResource)
162{
163 Q_Q(QWaylandXdgOutputManagerV1);
164
165 // Verify if the associated output exist
166 auto *output = QWaylandOutput::fromResource(outputResource);
167 if (!output) {
168 qCWarning(qLcWaylandCompositor,
169 "The client is requesting a QWaylandXdgOutputV1 for a "
170 "QWaylandOutput that doesn't exist");
171 wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "output not found");
172 return;
173 }
174
175 // Do we have a QWaylandXdgOutputV1 for this output?
176 if (!xdgOutputs.contains(output)) {
177 qCWarning(qLcWaylandCompositor,
178 "The client is requesting a QWaylandXdgOutputV1 that the compositor "
179 "didn't create before");
180 wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT,
181 "compositor didn't create a QWaylandXdgOutputV1 for this zxdg_output_v1 object");
182 return;
183 }
184
185 // Bind QWaylandXdgOutputV1 and initialize
186 auto *xdgOutput = xdgOutputs[output];
187 auto *xdgOutputPrivate = QWaylandXdgOutputV1Private::get(xdgOutput);
188 Q_ASSERT(xdgOutputPrivate);
189 xdgOutputPrivate->setManager(q);
190 xdgOutputPrivate->setOutput(output);
191 xdgOutputPrivate->add(resource->client(), id, qMin(resource->version(), QWaylandXdgOutputV1Private::interfaceVersion()));
192}
193
194// QWaylandXdgOutputV1
195
196QWaylandXdgOutputV1::QWaylandXdgOutputV1()
197 : QObject(*new QWaylandXdgOutputV1Private)
198{
199}
200
201QWaylandXdgOutputV1::QWaylandXdgOutputV1(QWaylandOutput *output, QWaylandXdgOutputManagerV1 *manager)
202 : QObject(*new QWaylandXdgOutputV1Private)
203{
204 Q_D(QWaylandXdgOutputV1);
205
206 // Set members before emitting changed signals so that handlers will
207 // see both already set and not nullptr, avoiding potential crashes
208 d->manager = manager;
209 d->output = output;
210
211 QWaylandXdgOutputManagerV1Private::get(d->manager)->registerXdgOutput(output, this);
212
213 emit managerChanged();
214 emit outputChanged();
215}
216
217QWaylandXdgOutputV1::~QWaylandXdgOutputV1()
218{
219 Q_D(QWaylandXdgOutputV1);
220
221 if (d->manager)
222 QWaylandXdgOutputManagerV1Private::get(d->manager)->unregisterXdgOutput(d->output);
223}
224
225/*!
226 * \qmlproperty XdgOutputManagerV1 XdgOutputV1::manager
227 * \readonly
228 *
229 * This property holds the object that manages this XdgOutputV1.
230 */
231/*!
232 * \property QWaylandXdgOutputV1::manager
233 * \readonly
234 * \internal
235 *
236 * This property holds the object that manages this QWaylandXdgOutputV1.
237 */
238QWaylandXdgOutputManagerV1 *QWaylandXdgOutputV1::manager() const
239{
240 Q_D(const QWaylandXdgOutputV1);
241 return d->manager;
242}
243
244/*!
245 * \qmlproperty WaylandOutput XdgOutputV1::output
246 * \readonly
247 *
248 * This property holds the WaylandOutput associated with this XdgOutputV1.
249 */
250/*!
251 * \property QWaylandXdgOutputV1::output
252 * \readonly
253 *
254 * This property holds the QWaylandOutput associated with this QWaylandXdgOutputV1.
255 */
256QWaylandOutput *QWaylandXdgOutputV1::output() const
257{
258 Q_D(const QWaylandXdgOutputV1);
259 return d->output;
260}
261
262/*!
263 * \qmlproperty string XdgOutputV1::name
264 *
265 * This property holds the name of this output.
266 *
267 * The naming convention is compositor defined, but limited to alphanumeric
268 * characters and dashes ("-"). Each name is unique and will also remain
269 * consistent across sessions with the same hardware and software configuration.
270 *
271 * Examples of names include "HDMI-A-1", "WL-1", "X11-1" etc...
272 * However don't assume the name reflects the underlying technology.
273 *
274 * Changing this property after initialization doesn't take effect.
275 */
276/*!
277 * \property QWaylandXdgOutputV1::name
278 *
279 * This property holds the name of this output.
280 *
281 * The naming convention is compositor defined, but limited to alphanumeric
282 * characters and dashes ("-"). Each name is unique and will also remain
283 * consistent across sessions with the same hardware and software configuration.
284 *
285 * Examples of names include "HDMI-A-1", "WL-1", "X11-1" etc...
286 * However don't assume the name reflects the underlying technology.
287 *
288 * Changing this property after initialization doesn't take effect.
289 */
290QString QWaylandXdgOutputV1::name() const
291{
292 Q_D(const QWaylandXdgOutputV1);
293 return d->name;
294}
295
296void QWaylandXdgOutputV1::setName(const QString &name)
297{
298 Q_D(QWaylandXdgOutputV1);
299
300 if (d->name == name)
301 return;
302
303 // Can't change after clients bound to xdg-output
304 if (d->initialized) {
305 qCWarning(qLcWaylandCompositor, "QWaylandXdgOutputV1::name cannot be changed after initialization");
306 return;
307 }
308
309 d->name = name;
310 emit nameChanged();
311}
312
313/*!
314 * \qmlproperty string XdgOutputV1::description
315 *
316 * This property holds the description of this output.
317 *
318 * No convention is defined for the description.
319 *
320 * Changing this property after initialization doesn't take effect.
321 */
322/*!
323 * \property QWaylandXdgOutputV1::description
324 *
325 * This property holds the description of this output.
326 *
327 * No convention is defined for the description.
328 *
329 * Changing this property after initialization doesn't take effect.
330 */
331QString QWaylandXdgOutputV1::description() const
332{
333 Q_D(const QWaylandXdgOutputV1);
334 return d->description;
335}
336
337void QWaylandXdgOutputV1::setDescription(const QString &description)
338{
339 Q_D(QWaylandXdgOutputV1);
340
341 if (d->description == description)
342 return;
343
344 // Can't change after clients bound to xdg-output
345 if (d->initialized) {
346 qCWarning(qLcWaylandCompositor, "QWaylandXdgOutputV1::description cannot be changed after initialization");
347 return;
348 }
349
350 d->description = description;
351 emit descriptionChanged();
352}
353
354/*!
355 * \qmlproperty point XdgOutputV1::logicalPosition
356 *
357 * This property holds the coordinates of the output within the global compositor space.
358 *
359 * The default value is 0,0.
360 */
361/*!
362 * \property QWaylandXdgOutputV1::logicalPosition
363 *
364 * This property holds the coordinates of the output within the global compositor space.
365 *
366 * The default value is 0,0.
367 */
368QPoint QWaylandXdgOutputV1::logicalPosition() const
369{
370 Q_D(const QWaylandXdgOutputV1);
371 return d->logicalPos;
372}
373
374void QWaylandXdgOutputV1::setLogicalPosition(const QPoint &position)
375{
376 Q_D(QWaylandXdgOutputV1);
377
378 if (d->logicalPos == position)
379 return;
380
381 d->logicalPos = position;
382 if (d->initialized) {
383 d->sendLogicalPosition(position);
384 d->sendDone();
385 }
386 emit logicalPositionChanged();
387 emit logicalGeometryChanged();
388}
389
390/*!
391 * \qmlproperty size XdgOutputV1::logicalSize
392 *
393 * This property holds the size of the output in the global compositor space.
394 *
395 * The default value is -1,-1 which is invalid.
396 *
397 * Please remember that this is the logical size, not the physical size.
398 * For example, for a WaylandOutput mode 3840x2160 and a scale factor 2:
399 * \list
400 * \li A compositor not scaling the surface buffers, will report a logical size of 3840x2160.
401 * \li A compositor automatically scaling the surface buffers, will report a logical size of 1920x1080.
402 * \li A compositor using a fractional scale of 1.5, will report a logical size of 2560x1620.
403 * \endlist
404 */
405/*!
406 * \property QWaylandXdgOutputV1::logicalSize
407 *
408 * This property holds the size of the output in the global compositor space.
409 *
410 * The default value is -1,-1 which is invalid.
411 *
412 * Please remember that this is the logical size, not the physical size.
413 * For example, for a WaylandOutput mode 3840x2160 and a scale factor 2:
414 * \list
415 * \li A compositor not scaling the surface buffers, will report a logical size of 3840x2160.
416 * \li A compositor automatically scaling the surface buffers, will report a logical size of 1920x1080.
417 * \li A compositor using a fractional scale of 1.5, will report a logical size of 2560x1620.
418 * \endlist
419 */
420QSize QWaylandXdgOutputV1::logicalSize() const
421{
422 Q_D(const QWaylandXdgOutputV1);
423 return d->logicalSize;
424}
425
426void QWaylandXdgOutputV1::setLogicalSize(const QSize &size)
427{
428 Q_D(QWaylandXdgOutputV1);
429
430 if (d->logicalSize == size)
431 return;
432
433 d->logicalSize = size;
434 if (d->initialized) {
435 d->sendLogicalSize(size);
436 d->sendDone();
437 }
438 emit logicalSizeChanged();
439 emit logicalGeometryChanged();
440}
441
442/*!
443 * \qmlproperty rect XdgOutputV1::logicalGeometry
444 * \readonly
445 *
446 * This property holds the position and size of the output in the global compositor space.
447 * It's the combination of the logical position and logical size.
448 *
449 * \sa XdgOutputV1::logicalPosition
450 * \sa XdgOutputV1::logicalSize
451 */
452/*!
453 * \property QWaylandXdgOutputV1::logicalGeometry
454 * \readonly
455 *
456 * This property holds the position and size of the output in the global compositor space.
457 * It's the combination of the logical position and logical size.
458 *
459 * \sa QWaylandXdgOutputV1::logicalPosition
460 * \sa QWaylandXdgOutputV1::logicalSize
461 */
462QRect QWaylandXdgOutputV1::logicalGeometry() const
463{
464 Q_D(const QWaylandXdgOutputV1);
465 return QRect(d->logicalPos, d->logicalSize);
466}
467
468// QWaylandXdgOutputV1Private
469
470void QWaylandXdgOutputV1Private::sendLogicalPosition(const QPoint &position)
471{
472 const auto values = resourceMap().values();
473 for (auto *resource : values)
474 send_logical_position(resource->handle, position.x(), position.y());
475}
476
477void QWaylandXdgOutputV1Private::sendLogicalSize(const QSize &size)
478{
479 const auto values = resourceMap().values();
480 for (auto *resource : values)
481 send_logical_size(resource->handle, size.width(), size.height());
482}
483
484void QWaylandXdgOutputV1Private::maybeSendDone(const Resource *resource)
485{
486 if (resource->version() < 3)
487 send_done(resource->handle);
488}
489
490void QWaylandXdgOutputV1Private::sendDone()
491{
492 const auto values = resourceMap().values();
493 for (auto *resource : values)
494 maybeSendDone(resource);
495
496 QWaylandOutputPrivate::get(output)->sendDone();
497}
498
499void QWaylandXdgOutputV1Private::setManager(QWaylandXdgOutputManagerV1 *_manager)
500{
501 Q_Q(QWaylandXdgOutputV1);
502
503 if (!_manager) {
504 qCWarning(qLcWaylandCompositor,
505 "Cannot associate a null QWaylandXdgOutputManagerV1 to QWaylandXdgOutputV1 %p", this);
506 return;
507 }
508
509 if (manager == _manager)
510 return;
511
512 if (manager) {
513 qCWarning(qLcWaylandCompositor,
514 "Cannot associate a different QWaylandXdgOutputManagerV1 to QWaylandXdgOutputV1 %p "
515 "after initialization", this);
516 return;
517 }
518
519 manager = _manager;
520 emit q->managerChanged();
521}
522
523void QWaylandXdgOutputV1Private::setOutput(QWaylandOutput *_output)
524{
525 Q_Q(QWaylandXdgOutputV1);
526
527 if (!_output) {
528 qCWarning(qLcWaylandCompositor,
529 "Cannot associate a null QWaylandOutput to QWaylandXdgOutputV1 %p", this);
530 return;
531 }
532
533 if (output == _output)
534 return;
535
536 if (output) {
537 qCWarning(qLcWaylandCompositor,
538 "Cannot associate a different QWaylandOutput to QWaylandXdgOutputV1 %p "
539 "after initialization", this);
540 return;
541 }
542
543 // Assign output above manager, to make both values valid in handlers
544 output = _output;
545
546 if (!manager) {
547 // Try to find the manager from the output parents
548 for (auto *p = output->parent(); p != nullptr; p = p->parent()) {
549 if (auto *m = qobject_cast<QWaylandXdgOutputManagerV1 *>(p)) {
550 manager = m;
551 emit q->managerChanged();
552 break;
553 }
554 }
555 }
556
557 emit q->outputChanged();
558
559 // Register the output
560 if (manager)
561 QWaylandXdgOutputManagerV1Private::get(manager)->registerXdgOutput(output, q);
562}
563
564void QWaylandXdgOutputV1Private::zxdg_output_v1_bind_resource(Resource *resource)
565{
566 send_logical_position(resource->handle, logicalPos.x(), logicalPos.y());
567 send_logical_size(resource->handle, logicalSize.width(), logicalSize.height());
568 if (resource->version() >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION)
569 send_name(resource->handle, name);
570 if (resource->version() >= ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION)
571 send_description(resource->handle, description);
572 maybeSendDone(resource);
573
574 QWaylandOutputPrivate *output_d = QWaylandOutputPrivate::get(output);
575 auto *outputResource = output_d->resourceMap().value(resource->client());
576 if (outputResource)
577 output_d->maybeSendDone(outputResource);
578
579 initialized = true;
580}
581
582void QWaylandXdgOutputV1Private::zxdg_output_v1_destroy(Resource *resource)
583{
584 wl_resource_destroy(resource->handle);
585}
586
587QT_END_NAMESPACE
588
589#include "moc_qwaylandxdgoutputv1.cpp"