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
qwaylandoutput.cpp
Go to the documentation of this file.
1// Copyright (C) 2017-2016 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
2// Copyright (C) 2017 Klarälvdalens Datakonsult AB (KDAB).
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4// Qt-Security score:critical reason:network-protocol
5
8
9#include <QtWaylandCompositor/QWaylandCompositor>
10#include <QtWaylandCompositor/QWaylandView>
11
12#include <QtWaylandCompositor/private/qwaylandsurface_p.h>
13#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
14#include <QtWaylandCompositor/private/qwaylandview_p.h>
15#include <QtWaylandCompositor/private/qwaylandutils_p.h>
16
17#include <QtCore/QCoreApplication>
18#include <QtCore/QtMath>
19#include <QtGui/QWindow>
20#include <QtGui/QExposeEvent>
21#include <QtGui/QScreen>
22#include <private/qobject_p.h>
23
25
26static QtWaylandServer::wl_output::subpixel toWlSubpixel(const QWaylandOutput::Subpixel &value)
27{
28 switch (value) {
29 case QWaylandOutput::SubpixelUnknown:
30 return QtWaylandServer::wl_output::subpixel_unknown;
31 case QWaylandOutput::SubpixelNone:
32 return QtWaylandServer::wl_output::subpixel_none;
33 case QWaylandOutput::SubpixelHorizontalRgb:
34 return QtWaylandServer::wl_output::subpixel_horizontal_rgb;
35 case QWaylandOutput::SubpixelHorizontalBgr:
36 return QtWaylandServer::wl_output::subpixel_horizontal_bgr;
37 case QWaylandOutput::SubpixelVerticalRgb:
38 return QtWaylandServer::wl_output::subpixel_vertical_rgb;
39 case QWaylandOutput::SubpixelVerticalBgr:
40 return QtWaylandServer::wl_output::subpixel_vertical_bgr;
41 default:
42 break;
43 }
44
45 return QtWaylandServer::wl_output::subpixel_unknown;
46}
47
48static QtWaylandServer::wl_output::transform toWlTransform(const QWaylandOutput::Transform &value)
49{
50 switch (value) {
51 case QWaylandOutput::Transform90:
52 return QtWaylandServer::wl_output::transform_90;
53 case QWaylandOutput::Transform180:
54 return QtWaylandServer::wl_output::transform_180;
55 case QWaylandOutput::Transform270:
56 return QtWaylandServer::wl_output::transform_270;
57 case QWaylandOutput::TransformFlipped:
58 return QtWaylandServer::wl_output::transform_flipped;
59 case QWaylandOutput::TransformFlipped90:
60 return QtWaylandServer::wl_output::transform_flipped_90;
61 case QWaylandOutput::TransformFlipped180:
62 return QtWaylandServer::wl_output::transform_flipped_180;
63 case QWaylandOutput::TransformFlipped270:
64 return QtWaylandServer::wl_output::transform_flipped_270;
65 default:
66 break;
67 }
68
69 return QtWaylandServer::wl_output::transform_normal;
70}
71
72QWaylandOutputPrivate::QWaylandOutputPrivate()
73{
74}
75
76QWaylandOutputPrivate::~QWaylandOutputPrivate()
77{
78}
79
80void QWaylandOutputPrivate::output_bind_resource(Resource *resource)
81{
82 sendGeometry(resource);
83
84 for (const QWaylandOutputMode &mode : std::as_const(modes))
85 sendMode(resource, mode);
86
87 maybeSendScale(resource, scaleFactor);
88 maybeSendDone(resource);
89}
90
91void QWaylandOutputPrivate::_q_handleMaybeWindowPixelSizeChanged()
92{
93 if (!window)
94 return;
95
96 const QSize pixelSize = window->size() * window->devicePixelRatio();
97
98 if (pixelSize != windowPixelSize) {
99 windowPixelSize = pixelSize;
100 handleWindowPixelSizeChanged();
101 }
102}
103
104void QWaylandOutputPrivate::_q_handleWindowDestroyed()
105{
106 Q_Q(QWaylandOutput);
107 window = nullptr;
108 emit q->windowChanged();
109 emit q->windowDestroyed();
110}
111
112void QWaylandOutputPrivate::sendGeometry(const Resource *resource)
113{
114 send_geometry(resource->handle,
115 position.x(), position.y(),
116 physicalSize.width(), physicalSize.height(),
117 toWlSubpixel(subpixel), manufacturer, model,
118 toWlTransform(transform));
119}
120
121void QWaylandOutputPrivate::sendGeometryInfo()
122{
123 const auto resources = resourceMap().values();
124 for (const Resource *resource : resources) {
125 sendGeometry(resource);
126 maybeSendDone(resource);
127 }
128}
129
130void QWaylandOutputPrivate::sendMode(const Resource *resource, const QWaylandOutputMode &mode)
131{
132 quint32 flags = 0;
133 if (currentMode == modes.indexOf(mode))
134 flags |= QtWaylandServer::wl_output::mode_current;
135 if (preferredMode == modes.indexOf(mode))
136 flags |= QtWaylandServer::wl_output::mode_preferred;
137
138 send_mode(resource->handle, flags,
139 mode.size().width(), mode.size().height(),
140 mode.refreshRate());
141}
142
143void QWaylandOutputPrivate::sendModesInfo()
144{
145 const auto resources = resourceMap().values();
146 for (const Resource *resource : resources) {
147 for (const QWaylandOutputMode &mode : std::as_const(modes))
148 sendMode(resource, mode);
149 maybeSendDone(resource);
150 }
151}
152
153void QWaylandOutputPrivate::maybeSendDone(const Resource *resource)
154{
155 if (resource->version() >= 2)
156 send_done(resource->handle);
157}
158
159void QWaylandOutputPrivate::sendDone()
160{
161 const auto values = resourceMap().values();
162 for (auto *resource : values)
163 maybeSendDone(resource);
164}
165
166void QWaylandOutputPrivate::handleWindowPixelSizeChanged()
167{
168 Q_Q(QWaylandOutput);
169 Q_ASSERT(window);
170 if (sizeFollowsWindow && currentMode < modes.size()) {
171 if (currentMode >= 0) {
172 QWaylandOutputMode &mode = modes[currentMode];
173 mode.setSize(windowPixelSize);
174 emit q->geometryChanged();
175 if (!availableGeometry.isValid())
176 emit q->availableGeometryChanged();
177 sendModesInfo();
178 } else {
179 // We didn't add a mode during the initialization because the window
180 // size was invalid, let's add it now
181 int mHzRefreshRate = qFloor(window->screen()->refreshRate() * 1000);
182 QWaylandOutputMode mode(windowPixelSize, mHzRefreshRate);
183 if (mode.isValid()) {
184 modes.clear();
185 q->addMode(mode, true);
186 q->setCurrentMode(mode);
187 }
188 }
189 }
190}
191
192void QWaylandOutputPrivate::addView(QWaylandView *view, QWaylandSurface *surface)
193{
194 for (int i = 0; i < surfaceViews.size(); i++) {
195 if (surface == surfaceViews.at(i).surface) {
196 if (!surfaceViews.at(i).views.contains(view)) {
197 surfaceViews[i].views.append(view);
198 }
199 return;
200 }
201 }
202
203 surfaceViews.append(QWaylandSurfaceViewMapper(surface,view));
204}
205
206void QWaylandOutputPrivate::removeView(QWaylandView *view, QWaylandSurface *surface)
207{
208 Q_Q(QWaylandOutput);
209 for (int i = 0; i < surfaceViews.size(); i++) {
210 if (surface == surfaceViews.at(i).surface) {
211 bool removed = surfaceViews[i].views.removeOne(view);
212 if (removed && surfaceViews.at(i).views.isEmpty()) {
213 if (surfaceViews.at(i).has_entered)
214 q->surfaceLeave(surface);
215 surfaceViews.remove(i);
216 }
217 return;
218 }
219 }
220 qWarning("%s Could not find view %p for surface %p to remove. Possible invalid state", Q_FUNC_INFO, view, surface);
221}
222
223QWaylandOutput::QWaylandOutput()
224 : QWaylandObject(*new QWaylandOutputPrivate())
225{
226}
227
228/*!
229 \qmltype WaylandOutput
230 \nativetype QWaylandOutput
231 \inqmlmodule QtWayland.Compositor
232 \since 5.8
233 \brief Provides access to a displayable area managed by the compositor.
234
235 The WaylandOutput manages a rectangular area within bounds of the compositor's
236 geometry, to use it for displaying client content. This could, for instance, be
237 a screen managed by the WaylandCompositor.
238
239 The type corresponds to the \c wl_output interface in the Wayland protocol.
240
241 \note If the compositor has multiple Wayland outputs, the \l Qt::AA_ShareOpenGLContexts
242 attribute must be set before the \l QGuiApplication object is constructed.
243*/
244
245/*!
246 \class QWaylandOutput
247 \inmodule QtWaylandCompositor
248 \since 5.8
249 \brief The QWaylandOutput class represents a displayable area managed by the compositor.
250
251 The QWaylandOutput manages a rectangular area within bounds of the compositor's
252 geometry, to use it for displaying client content. This could, for instance, be
253 a screen managed by the WaylandCompositor.
254
255 The class corresponds to the \c wl_output interface in the Wayland protocol.
256*/
257
258/*!
259 * Constructs a QWaylandOutput in \a compositor and with the specified \a window. The
260 * \l{QWaylandCompositor::create()}{create()} function must be called on the
261 * \a compositor before constructing a QWaylandOutput for it.
262 *
263 * The QWaylandOutput object is initialized later, in reaction to an event.
264 * At this point it is added as an output for the \a compositor. If it is the
265 * first QWaylandOutput object created for this \a compositor, it becomes the
266 * \l{QWaylandCompositor::defaultOutput()}{default output}.
267 */
268QWaylandOutput::QWaylandOutput(QWaylandCompositor *compositor, QWindow *window)
269 : QWaylandObject(*new QWaylandOutputPrivate())
270{
271 Q_D(QWaylandOutput);
272 d->compositor = compositor;
273 d->window = window;
274 QWaylandCompositorPrivate::get(compositor)->addPolishObject(this);
275}
276
277/*!
278 * Destroys the QWaylandOutput.
279 */
280QWaylandOutput::~QWaylandOutput()
281{
282 Q_D(QWaylandOutput);
283
284 const auto surfaceViews = d->surfaceViews; // intentional copy
285 for (const QWaylandSurfaceViewMapper &surfacemapper : surfaceViews) {
286 for (QWaylandView *view : surfacemapper.views) {
287 if (view->output() == this)
288 view->setOutput(nullptr);
289 }
290 }
291
292 if (d->compositor)
293 QWaylandCompositorPrivate::get(d->compositor)->removeOutput(this);
294}
295
296/*!
297 * \internal
298 */
299void QWaylandOutput::initialize()
300{
301 Q_D(QWaylandOutput);
302
303 Q_ASSERT(!d->initialized);
304 Q_ASSERT(d->compositor);
305 Q_ASSERT(d->compositor->isCreated());
306
307 if (!d->window && d->sizeFollowsWindow) {
308 qWarning("Setting QWaylandOutput::sizeFollowsWindow without a window has no effect");
309 }
310
311 // Replace modes with one that follows the window size and refresh rate,
312 // but only if window size is valid
313 if (d->window && d->sizeFollowsWindow) {
314 QWaylandOutputMode mode(d->window->size() * d->window->devicePixelRatio(),
315 qFloor(d->window->screen()->refreshRate() * 1000));
316 if (mode.isValid()) {
317 d->modes.clear();
318 addMode(mode, true);
319 setCurrentMode(mode);
320 }
321 }
322
323 QWaylandCompositorPrivate::get(d->compositor)->addOutput(this);
324
325 if (d->window) {
326 QObjectPrivate::connect(d->window, &QWindow::widthChanged, d, &QWaylandOutputPrivate::_q_handleMaybeWindowPixelSizeChanged);
327 QObjectPrivate::connect(d->window, &QWindow::heightChanged, d, &QWaylandOutputPrivate::_q_handleMaybeWindowPixelSizeChanged);
328 QObjectPrivate::connect(d->window, &QWindow::screenChanged, d, &QWaylandOutputPrivate::_q_handleMaybeWindowPixelSizeChanged);
329 QObjectPrivate::connect(d->window, &QObject::destroyed, d, &QWaylandOutputPrivate::_q_handleWindowDestroyed);
330 }
331
332 d->init(d->compositor->display(), 2);
333
334 d->initialized = true;
335}
336
337/*!
338 * Returns the QWaylandOutput corresponding to \a resource.
339 */
340QWaylandOutput *QWaylandOutput::fromResource(wl_resource *resource)
341{
342 if (auto p = QtWayland::fromResource<QWaylandOutputPrivate *>(resource))
343 return p->q_func();
344 return nullptr;
345}
346
347/*!
348 * \internal
349 */
350struct ::wl_resource *QWaylandOutput::resourceForClient(QWaylandClient *client) const
351{
352 Q_D(const QWaylandOutput);
353 QWaylandOutputPrivate::Resource *r = d->resourceMap().value(client->client());
354 if (r)
355 return r->handle;
356
357 return nullptr;
358}
359
360/*!
361 * Schedules a QEvent::UpdateRequest to be delivered to the QWaylandOutput's \l{window()}{window}.
362 *
363 * \sa QWindow::requestUpdate()
364 */
365void QWaylandOutput::update()
366{
367 Q_D(QWaylandOutput);
368 if (!d->window)
369 return;
370 d->window->requestUpdate();
371}
372
373/*!
374 * \qmlproperty WaylandCompositor QtWayland.Compositor::WaylandOutput::compositor
375 *
376 * This property holds the compositor displaying content on this WaylandOutput.
377 *
378 * \note This property can be set only once, before the WaylandOutput component
379 * is completed.
380 */
381
382/*!
383 * \property QWaylandOutput::compositor
384 *
385 * This property holds the compositor displaying content on this QWaylandOutput.
386 *
387 * \note This property can be set only once, before the QWaylandOutput has been
388 * initialized.
389 */
390
391/*!
392 * Returns the compositor for this QWaylandOutput.
393 */
394QWaylandCompositor *QWaylandOutput::compositor() const
395{
396 return d_func()->compositor;
397}
398
399/*!
400 * \internal
401 */
402void QWaylandOutput::setCompositor(QWaylandCompositor *compositor)
403{
404 Q_D(QWaylandOutput);
405
406 if (d->compositor == compositor)
407 return;
408
409 if (d->initialized) {
410 qWarning("Setting QWaylandCompositor %p on QWaylandOutput %p is not supported after QWaylandOutput has been initialized\n", compositor, this);
411 return;
412 }
413 if (d->compositor && d->compositor != compositor) {
414 qWarning("Possible initialization error. Moving QWaylandOutput %p between compositor instances.\n", this);
415 }
416
417 d->compositor = compositor;
418
419 QWaylandCompositorPrivate::get(compositor)->addPolishObject(this);
420}
421
422/*!
423 * \qmlproperty string QtWayland.Compositor::WaylandOutput::manufacturer
424 *
425 * This property holds a textual description of the manufacturer of the display
426 * managed by this WaylandOutput.
427 */
428
429/*!
430 * \property QWaylandOutput::manufacturer
431 *
432 * This property holds a textual description of the manufacturer of the display
433 * managed by this QWaylandOutput.
434 */
435QString QWaylandOutput::manufacturer() const
436{
437 return d_func()->manufacturer;
438}
439
440void QWaylandOutput::setManufacturer(const QString &manufacturer)
441{
442 Q_D(QWaylandOutput);
443
444 if (d->manufacturer == manufacturer)
445 return;
446
447 d->manufacturer = manufacturer;
448 d->sendGeometryInfo();
449 Q_EMIT manufacturerChanged();
450}
451
452/*!
453 * \qmlproperty string QtWayland.Compositor::WaylandOutput::model
454 *
455 * This property holds a textual description of the model of the display
456 * managed by this WaylandOutput.
457 */
458
459/*!
460 * \property QWaylandOutput::model
461 *
462 * This property holds a textual description of the model of the display
463 * managed by this QWaylandOutput.
464 */
465QString QWaylandOutput::model() const
466{
467 return d_func()->model;
468}
469
470void QWaylandOutput::setModel(const QString &model)
471{
472 Q_D(QWaylandOutput);
473
474 if (d->model == model)
475 return;
476
477 d->model = model;
478 d->sendGeometryInfo();
479 Q_EMIT modelChanged();
480}
481
482/*!
483 * \qmlproperty point QtWayland.Compositor::WaylandOutput::position
484 *
485 * This property holds the position of this WaylandOutput in the compositor's coordinate system.
486 */
487
488/*!
489 * \property QWaylandOutput::position
490 *
491 * This property holds the position of this QWaylandOutput in the compositor's coordinate system.
492 */
493QPoint QWaylandOutput::position() const
494{
495 return d_func()->position;
496}
497
498void QWaylandOutput::setPosition(const QPoint &pt)
499{
500 Q_D(QWaylandOutput);
501 if (d->position == pt)
502 return;
503
504 d->position = pt;
505
506 d->sendGeometryInfo();
507
508 Q_EMIT positionChanged();
509 Q_EMIT geometryChanged();
510}
511
512/*!
513 * Returns the list of modes.
514 */
515QList<QWaylandOutputMode> QWaylandOutput::modes() const
516{
517 Q_D(const QWaylandOutput);
518 return d->modes.toList();
519}
520
521/*!
522 * Adds the mode \a mode to the output and mark it as preferred
523 * if \a preferred is \c true.
524 * Please note there can only be one preferred mode.
525 */
526void QWaylandOutput::addMode(const QWaylandOutputMode &mode, bool preferred)
527{
528 Q_D(QWaylandOutput);
529
530 if (!mode.isValid()) {
531 qWarning("Cannot add an invalid mode");
532 return;
533 }
534
535 int index = d->modes.indexOf(mode);
536 if (index < 0) {
537 d->modes.append(mode);
538 index = d->modes.size() - 1;
539 }
540
541 if (preferred)
542 d->preferredMode = index;
543
544 emit modeAdded();
545}
546
547/*!
548 * Returns the output's size in pixels and refresh rate in mHz.
549 * If the current mode is not set it will return an invalid mode.
550 *
551 * \sa QWaylandOutput::modes
552 * \sa QWaylandOutputMode
553 */
554QWaylandOutputMode QWaylandOutput::currentMode() const
555{
556 Q_D(const QWaylandOutput);
557
558 return d->modes.value(d->currentMode);
559}
560
561/*!
562 * Sets the current mode.
563 * The mode \a mode must have been previously added.
564 *
565 * \sa QWaylandOutput::modes
566 * \sa QWaylandOutputMode
567 */
568void QWaylandOutput::setCurrentMode(const QWaylandOutputMode &mode)
569{
570 Q_D(QWaylandOutput);
571
572 int index = d->modes.indexOf(mode);
573 if (index < 0) {
574 qWarning("Cannot set an unknown QWaylandOutput mode as current");
575 return;
576 }
577
578 d->currentMode = index;
579
580 Q_EMIT currentModeChanged();
581 Q_EMIT geometryChanged();
582 if (!d->availableGeometry.isValid())
583 emit availableGeometryChanged();
584
585 d->sendModesInfo();
586}
587
588/*!
589 * \qmlproperty rect QtWayland.Compositor::WaylandOutput::geometry
590 *
591 * This property holds the geometry of the WaylandOutput.
592 */
593
594/*!
595 * \property QWaylandOutput::geometry
596 *
597 * This property holds the geometry of the QWaylandOutput.
598 *
599 * \sa QWaylandOutput::currentMode
600 */
601QRect QWaylandOutput::geometry() const
602{
603 Q_D(const QWaylandOutput);
604 return QRect(d->position, currentMode().size());
605}
606
607/*!
608 * \qmlproperty rect QtWayland.Compositor::WaylandOutput::availableGeometry
609 *
610 * This property holds the geometry of the WaylandOutput available for displaying content.
611 * The available geometry is in output coordinates space, starts from 0,0 and it's as big
612 * as the output by default.
613 *
614 * \sa QWaylandOutput::geometry
615 */
616
617/*!
618 * \property QWaylandOutput::availableGeometry
619 *
620 * This property holds the geometry of the QWaylandOutput available for displaying content.
621 * The available geometry is in output coordinates space, starts from 0,0 and it's as big
622 * as the output by default.
623 *
624 * \sa QWaylandOutput::currentMode, QWaylandOutput::geometry
625 */
626QRect QWaylandOutput::availableGeometry() const
627{
628 Q_D(const QWaylandOutput);
629
630 if (!d->availableGeometry.isValid())
631 return QRect(QPoint(0, 0), currentMode().size());
632
633 return d->availableGeometry;
634}
635
636void QWaylandOutput::setAvailableGeometry(const QRect &availableGeometry)
637{
638 Q_D(QWaylandOutput);
639 if (d->availableGeometry == availableGeometry)
640 return;
641
642 if (availableGeometry.topLeft().x() < 0 || availableGeometry.topLeft().y() < 0)
643 qWarning("Available geometry should be a portion of the output");
644
645 d->availableGeometry = availableGeometry;
646
647 Q_EMIT availableGeometryChanged();
648}
649
650/*!
651 * \qmlproperty size QtWayland.Compositor::WaylandOutput::physicalSize
652 *
653 * This property holds the physical size of the WaylandOutput in millimeters.
654 *
655 * \sa QWaylandOutput::geometry
656 */
657
658/*!
659 * \property QWaylandOutput::physicalSize
660 *
661 * This property holds the physical size of the QWaylandOutput in millimeters.
662 *
663 * \sa QWaylandOutput::geometry, QWaylandOutput::currentMode
664 */
665QSize QWaylandOutput::physicalSize() const
666{
667 return d_func()->physicalSize;
668}
669
670void QWaylandOutput::setPhysicalSize(const QSize &size)
671{
672 Q_D(QWaylandOutput);
673 if (d->physicalSize == size)
674 return;
675
676 d->physicalSize = size;
677
678 d->sendGeometryInfo();
679
680 Q_EMIT physicalSizeChanged();
681}
682
683/*!
684 * \enum QWaylandOutput::Subpixel
685 *
686 * This enum type is used to specify the subpixel arrangement of a QWaylandOutput.
687 *
688 * \value SubpixelUnknown The subpixel arrangement is not set.
689 * \value SubpixelNone There are no subpixels.
690 * \value SubpixelHorizontalRgb The subpixels are arranged horizontally in red, green, blue order.
691 * \value SubpixelHorizontalBgr The subpixels are arranged horizontally in blue, green, red order.
692 * \value SubpixelVerticalRgb The subpixels are arranged vertically in red, green, blue order.
693 * \value SubpixelVerticalBgr The subpixels are arranged vertically in blue, green, red order.
694 *
695 * \sa QWaylandOutput::subpixel
696 */
697
698/*!
699 * \qmlproperty enum QtWayland.Compositor::WaylandOutput::subpixel
700 *
701 * This property holds the subpixel arrangement of this WaylandOutput.
702 *
703 * \list
704 * \li WaylandOutput.SubpixelUnknown The subpixel arrangement is not set.
705 * \li WaylandOutput.SubpixelNone There are no subpixels.
706 * \li WaylandOutput.SubpixelHorizontalRgb The subpixels are arranged horizontally in red, green, blue order.
707 * \li WaylandOutput.SubpixelHorizontalBgr The subpixels are arranged horizontally in blue, green, red order.
708 * \li WaylandOutput.SubpixelVerticalRgb The subpixels are arranged vertically in red, green, blue order.
709 * \li WaylandOutput.SubpixelVerticalBgr The subpixels are arranged vertically in blue, green, red order.
710 * \endlist
711 *
712 * The default is WaylandOutput.SubpixelUnknown.
713 */
714
715/*!
716 * \property QWaylandOutput::subpixel
717 *
718 * This property holds the subpixel arrangement of this QWaylandOutput. The default is
719 * QWaylandOutput::SubpixelUnknown.
720 */
721QWaylandOutput::Subpixel QWaylandOutput::subpixel() const
722{
723 return d_func()->subpixel;
724}
725
726void QWaylandOutput::setSubpixel(const Subpixel &subpixel)
727{
728 Q_D(QWaylandOutput);
729 if (d->subpixel == subpixel)
730 return;
731
732 d->subpixel = subpixel;
733
734 d->sendGeometryInfo();
735
736 Q_EMIT subpixelChanged();
737}
738
739/*! \enum QWaylandOutput::Transform
740 *
741 * This enum type is used to specify the orientation of a QWaylandOutput.
742 *
743 * \value TransformNormal The orientation is normal.
744 * \value Transform90 The orientation is rotated 90 degrees.
745 * \value Transform180 The orientation is rotated 180 degrees.
746 * \value Transform270 The orientation is rotated 270 degrees.
747 * \value TransformFlipped The orientation is mirrored.
748 * \value TransformFlipped90 The orientation is mirrored, and rotated 90 degrees.
749 * \value TransformFlipped180 The orientation is mirrored, and rotated 180 degrees.
750 * \value TransformFlipped270 The orientation is mirrored, and rotated 270 degrees.
751 *
752 * \sa QWaylandOutput::transform
753*/
754
755/*!
756 * \qmlproperty enum QtWayland.Compositor::WaylandOutput::transform
757 *
758 * This property holds the transformation that the QWaylandCompositor applies to a surface
759 * to compensate for the orientation of the QWaylandOutput.
760 *
761 * \list
762 * \li WaylandOutput.TransformNormal The orientation is normal.
763 * \li WaylandOutput.Transform90 The orientation is rotated 90 degrees.
764 * \li WaylandOutput.Transform180 The orientation is rotated 180 degrees.
765 * \li WaylandOutput.Transform270 The orientation is rotated 270 degrees.
766 * \li WaylandOutput.TransformFlipped The orientation is mirrored.
767 * \li WaylandOutput.TransformFlipped90 The orientation is mirrored, then rotated 90 degrees.
768 * \li WaylandOutput.TransformFlipped180 The orientation is mirrored, then rotated 180 degrees.
769 * \li WaylandOutput.TransformFlipped270 The orientation is mirrored, then rotated 270 degrees.
770 * \endlist
771 *
772 * The default is WaylandOutput.TransformNormal.
773 */
774
775/*!
776 * \property QWaylandOutput::transform
777 *
778 * This property holds the transformation that the QWaylandCompositor applies to a surface
779 * to compensate for the orientation of the QWaylandOutput.
780 *
781 * The default is QWaylandOutput::TransformNormal.
782 */
783QWaylandOutput::Transform QWaylandOutput::transform() const
784{
785 return d_func()->transform;
786}
787
788void QWaylandOutput::setTransform(const Transform &transform)
789{
790 Q_D(QWaylandOutput);
791 if (d->transform == transform)
792 return;
793
794 d->transform = transform;
795
796 d->sendGeometryInfo();
797
798 Q_EMIT transformChanged();
799}
800
801/*!
802 * \qmlproperty int QtWayland.Compositor::WaylandOutput::scaleFactor
803 *
804 * This property holds the factor by which the WaylandCompositor scales surface buffers
805 * before they are displayed. It is used on high density output devices where unscaled content
806 * would be too small to be practical. The client can in turn set the scale factor of its
807 * buffer to match the output if it prefers to provide high resolution content that is
808 * suitable for the output device.
809 *
810 * The default is 1 (no scaling).
811 */
812
813/*!
814 * \property QWaylandOutput::scaleFactor
815 *
816 * This property holds the factor by which the QWaylandCompositor scales surface buffers
817 * before they are displayed. This is used on high density output devices where unscaled content
818 * would be too small to be practical. The client can in turn set the scale factor of its
819 * buffer to match the output if it prefers to provide high resolution content that is
820 * suitable for the output device.
821 *
822 * The default is 1 (no scaling).
823 */
824int QWaylandOutput::scaleFactor() const
825{
826 return d_func()->scaleFactor;
827}
828
829void QWaylandOutputPrivate::maybeSendScale(const Resource *resource,
830 int scale)
831{
832 if (resource->version() >= 2)
833 send_scale(resource->handle, scale);
834}
835
836void QWaylandOutput::setScaleFactor(int scale)
837{
838 Q_D(QWaylandOutput);
839 if (d->scaleFactor == scale)
840 return;
841
842 d->scaleFactor = scale;
843
844 const auto resMap = d->resourceMap();
845 for (QWaylandOutputPrivate::Resource *resource : resMap) {
846 d->maybeSendScale(resource, scale);
847 d->maybeSendDone(resource);
848 }
849
850 Q_EMIT scaleFactorChanged();
851}
852
853/*!
854 * \qmlproperty bool QtWayland.Compositor::WaylandOutput::sizeFollowsWindow
855 * \default false
856 *
857 * This property controls whether the size of the WaylandOutput matches the
858 * size of its window.
859 *
860 * If this property is true, all modes previously added are replaced by a
861 * mode that matches window size and screen refresh rate. It is especially
862 * useful in a nested compositor setup during development.
863 */
864
865/*!
866 * \property QWaylandOutput::sizeFollowsWindow
867 *
868 * This property controls whether the size of the QWaylandOutput matches the
869 * size of its window.
870 *
871 * If this property is true, all modes previously added are replaced by a
872 * mode that matches window size and screen refresh rate.
873 *
874 * The default is false.
875 */
876bool QWaylandOutput::sizeFollowsWindow() const
877{
878 return d_func()->sizeFollowsWindow;
879}
880
881void QWaylandOutput::setSizeFollowsWindow(bool follow)
882{
883 Q_D(QWaylandOutput);
884
885 if (follow != d->sizeFollowsWindow) {
886 d->sizeFollowsWindow = follow;
887 Q_EMIT sizeFollowsWindowChanged();
888 }
889}
890
891/*!
892 * \qmlproperty Window QtWayland.Compositor::WaylandOutput::window
893 *
894 * This property holds the Window for this WaylandOutput.
895 *
896 * \note This property can be set only once, before the WaylandOutput
897 * component is completed.
898 */
899
900/*!
901 * \property QWaylandOutput::window
902 *
903 * This property holds the QWindow for this QWaylandOutput.
904 */
905QWindow *QWaylandOutput::window() const
906{
907 return d_func()->window;
908}
909
910void QWaylandOutput::setWindow(QWindow *window)
911{
912 Q_D(QWaylandOutput);
913 if (d->window == window)
914 return;
915 if (d->initialized) {
916 qWarning("Setting QWindow %p on QWaylandOutput %p is not supported after QWaylandOutput has been initialized\n", window, this);
917 return;
918 }
919 d->window = window;
920 emit windowChanged();
921}
922
923/*!
924 * Informs QWaylandOutput that a frame has started.
925 */
926void QWaylandOutput::frameStarted()
927{
928 Q_D(QWaylandOutput);
929
930 d->canSendFrameCallbacks = true;
931
932 for (const QWaylandSurfaceViewMapper &surfacemapper : std::as_const(d->surfaceViews)) {
933 if (QWaylandView *primaryView = surfacemapper.maybePrimaryView()) {
934 if (Q_LIKELY(!QWaylandViewPrivate::get(primaryView)->independentFrameCallback))
935 surfacemapper.surface->frameStarted();
936 }
937 }
938}
939
940/*!
941 * Sends pending frame callbacks.
942 */
943void QWaylandOutput::sendFrameCallbacks()
944{
945 Q_D(QWaylandOutput);
946
947 if (Q_UNLIKELY(!d->canSendFrameCallbacks))
948 return;
949
950 d->canSendFrameCallbacks = false;
951
952 for (int i = 0; i < d->surfaceViews.size(); i++) {
953 const QWaylandSurfaceViewMapper &surfacemapper = d->surfaceViews.at(i);
954 if (surfacemapper.surface && surfacemapper.surface->hasContent()) {
955 if (!surfacemapper.has_entered) {
956 surfaceEnter(surfacemapper.surface);
957 d->surfaceViews[i].has_entered = true;
958 }
959 if (auto primaryView = surfacemapper.maybePrimaryView()) {
960 if (!QWaylandViewPrivate::get(primaryView)->independentFrameCallback)
961 surfacemapper.surface->sendFrameCallbacks();
962 }
963 }
964 }
965 wl_display_flush_clients(d->compositor->display());
966}
967
968/*!
969 * \internal
970 */
971void QWaylandOutput::surfaceEnter(QWaylandSurface *surface)
972{
973 if (!surface)
974 return;
975
976 auto clientResource = resourceForClient(surface->client());
977 if (clientResource)
978 QWaylandSurfacePrivate::get(surface)->send_enter(clientResource);
979}
980
981/*!
982 * \internal
983 */
984void QWaylandOutput::surfaceLeave(QWaylandSurface *surface)
985{
986 if (!surface || !surface->client())
987 return;
988
989 auto *clientResource = resourceForClient(surface->client());
990 if (clientResource)
991 QWaylandSurfacePrivate::get(surface)->send_leave(clientResource);
992}
993
994/*!
995 * \internal
996 */
997bool QWaylandOutput::event(QEvent *event)
998{
999 if (event->type() == QEvent::Polish)
1000 initialize();
1001 return QObject::event(event);
1002}
1003
1004QT_END_NAMESPACE
1005
1006#include "moc_qwaylandoutput.cpp"
Combined button and popup list for selecting options.
static QtWaylandServer::wl_output::transform toWlTransform(const QWaylandOutput::Transform &value)
static QT_BEGIN_NAMESPACE QtWaylandServer::wl_output::subpixel toWlSubpixel(const QWaylandOutput::Subpixel &value)