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