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