Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
5#include "qwaylandoutput.h"
6#include "qwaylandoutput_p.h"
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#include <QtWaylandCompositor/private/qwaylandxdgoutputv1_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) {
30 return QtWaylandServer::wl_output::subpixel_unknown;
32 return QtWaylandServer::wl_output::subpixel_none;
34 return QtWaylandServer::wl_output::subpixel_horizontal_rgb;
36 return QtWaylandServer::wl_output::subpixel_horizontal_bgr;
38 return QtWaylandServer::wl_output::subpixel_vertical_rgb;
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) {
52 return QtWaylandServer::wl_output::transform_90;
54 return QtWaylandServer::wl_output::transform_180;
56 return QtWaylandServer::wl_output::transform_270;
58 return QtWaylandServer::wl_output::transform_flipped;
60 return QtWaylandServer::wl_output::transform_flipped_90;
62 return QtWaylandServer::wl_output::transform_flipped_180;
64 return QtWaylandServer::wl_output::transform_flipped_270;
65 default:
66 break;
67 }
68
69 return QtWaylandServer::wl_output::transform_normal;
70}
71
75
79
81{
82 sendGeometry(resource);
83
84 for (const QWaylandOutputMode &mode : modes)
85 sendMode(resource, mode);
86
87 if (resource->version() >= 2) {
88 send_scale(resource->handle, scaleFactor);
89 send_done(resource->handle);
90 }
91}
92
93void QWaylandOutputPrivate::_q_handleMaybeWindowPixelSizeChanged()
94{
95 if (!window)
96 return;
97
98 const QSize pixelSize = window->size() * window->devicePixelRatio();
99
100 if (pixelSize != windowPixelSize) {
101 windowPixelSize = pixelSize;
103 }
104}
105
106void QWaylandOutputPrivate::_q_handleWindowDestroyed()
107{
108 Q_Q(QWaylandOutput);
109 window = nullptr;
110 emit q->windowChanged();
111 emit q->windowDestroyed();
112}
113
114void QWaylandOutputPrivate::sendGeometry(const Resource *resource)
115{
116 send_geometry(resource->handle,
117 position.x(), position.y(),
118 physicalSize.width(), physicalSize.height(),
119 toWlSubpixel(subpixel), manufacturer, model,
121}
122
124{
125 for (const Resource *resource : resourceMap().values()) {
126 sendGeometry(resource);
127 if (resource->version() >= 2)
128 send_done(resource->handle);
129 }
130
131 if (xdgOutput)
133}
134
135void QWaylandOutputPrivate::sendMode(const Resource *resource, const QWaylandOutputMode &mode)
136{
137 quint32 flags = 0;
138 if (currentMode == modes.indexOf(mode))
139 flags |= QtWaylandServer::wl_output::mode_current;
140 if (preferredMode == modes.indexOf(mode))
141 flags |= QtWaylandServer::wl_output::mode_preferred;
142
143 send_mode(resource->handle, flags,
144 mode.size().width(), mode.size().height(),
145 mode.refreshRate());
146}
147
149{
150 for (const Resource *resource : resourceMap().values()) {
151 for (const QWaylandOutputMode &mode : modes)
152 sendMode(resource, mode);
153 if (resource->version() >= 2)
154 send_done(resource->handle);
155 }
156
157 if (xdgOutput)
159}
160
162{
163 Q_Q(QWaylandOutput);
164 Q_ASSERT(window);
165 if (sizeFollowsWindow && currentMode <= modes.size() - 1) {
166 if (currentMode >= 0) {
167 QWaylandOutputMode mode = modes.at(currentMode);
168 mode.setSize(windowPixelSize);
169 modes.replace(currentMode, mode);
170 emit q->geometryChanged();
171 if (!availableGeometry.isValid())
172 emit q->availableGeometryChanged();
174 } else {
175 // We didn't add a mode during the initialization because the window
176 // size was invalid, let's add it now
177 int mHzRefreshRate = qFloor(window->screen()->refreshRate() * 1000);
178 QWaylandOutputMode mode(windowPixelSize, mHzRefreshRate);
179 if (mode.isValid()) {
180 modes.clear();
181 q->addMode(mode, true);
182 q->setCurrentMode(mode);
183 }
184 }
185 }
186}
187
189{
190 for (int i = 0; i < surfaceViews.size(); i++) {
191 if (surface == surfaceViews.at(i).surface) {
192 if (!surfaceViews.at(i).views.contains(view)) {
193 surfaceViews[i].views.append(view);
194 }
195 return;
196 }
197 }
198
199 surfaceViews.append(QWaylandSurfaceViewMapper(surface,view));
200}
201
203{
204 Q_Q(QWaylandOutput);
205 for (int i = 0; i < surfaceViews.size(); i++) {
206 if (surface == surfaceViews.at(i).surface) {
207 bool removed = surfaceViews[i].views.removeOne(view);
208 if (surfaceViews.at(i).views.isEmpty() && removed) {
209 if (surfaceViews.at(i).has_entered)
210 q->surfaceLeave(surface);
211 surfaceViews.remove(i);
212 }
213 return;
214 }
215 }
216 qWarning("%s Could not find view %p for surface %p to remove. Possible invalid state", Q_FUNC_INFO, view, surface);
217}
218
223
272
277{
278 Q_D(QWaylandOutput);
279 if (d->compositor)
280 QWaylandCompositorPrivate::get(d->compositor)->removeOutput(this);
281}
282
287{
288 Q_D(QWaylandOutput);
289
290 Q_ASSERT(!d->initialized);
291 Q_ASSERT(d->compositor);
292 Q_ASSERT(d->compositor->isCreated());
293
294 if (!d->window && d->sizeFollowsWindow) {
295 qWarning("Setting QWaylandOutput::sizeFollowsWindow without a window has no effect");
296 }
297
298 // Replace modes with one that follows the window size and refresh rate,
299 // but only if window size is valid
300 if (d->window && d->sizeFollowsWindow) {
301 QWaylandOutputMode mode(d->window->size() * d->window->devicePixelRatio(),
302 qFloor(d->window->screen()->refreshRate() * 1000));
303 if (mode.isValid()) {
304 d->modes.clear();
305 addMode(mode, true);
307 }
308 }
309
310 QWaylandCompositorPrivate::get(d->compositor)->addOutput(this);
311
312 if (d->window) {
313 QObjectPrivate::connect(d->window, &QWindow::widthChanged, d, &QWaylandOutputPrivate::_q_handleMaybeWindowPixelSizeChanged);
314 QObjectPrivate::connect(d->window, &QWindow::heightChanged, d, &QWaylandOutputPrivate::_q_handleMaybeWindowPixelSizeChanged);
315 QObjectPrivate::connect(d->window, &QWindow::screenChanged, d, &QWaylandOutputPrivate::_q_handleMaybeWindowPixelSizeChanged);
316 QObjectPrivate::connect(d->window, &QObject::destroyed, d, &QWaylandOutputPrivate::_q_handleWindowDestroyed);
317 }
318
319 d->init(d->compositor->display(), 2);
320
321 d->initialized = true;
322}
323
328{
329 if (auto p = QtWayland::fromResource<QWaylandOutputPrivate *>(resource))
330 return p->q_func();
331 return nullptr;
332}
333
337struct ::wl_resource *QWaylandOutput::resourceForClient(QWaylandClient *client) const
338{
339 Q_D(const QWaylandOutput);
340 QWaylandOutputPrivate::Resource *r = d->resourceMap().value(client->client());
341 if (r)
342 return r->handle;
343
344 return nullptr;
345}
346
353{
354 Q_D(QWaylandOutput);
355 if (!d->window)
356 return;
357 d->window->requestUpdate();
358}
359
373{
374 return d_func()->compositor;
375}
376
381{
382 Q_D(QWaylandOutput);
383
384 if (d->compositor == compositor)
385 return;
386
387 if (d->initialized) {
388 qWarning("Setting QWaylandCompositor %p on QWaylandOutput %p is not supported after QWaylandOutput has been initialized\n", compositor, this);
389 return;
390 }
391 if (d->compositor && d->compositor != compositor) {
392 qWarning("Possible initialization error. Moving QWaylandOutput %p between compositor instances.\n", this);
393 }
394
395 d->compositor = compositor;
396
397 QWaylandCompositorPrivate::get(compositor)->addPolishObject(this);
398}
399
412{
413 return d_func()->manufacturer;
414}
415
417{
418 Q_D(QWaylandOutput);
419
420 if (d->manufacturer == manufacturer)
421 return;
422
423 d->manufacturer = manufacturer;
424 d->sendGeometryInfo();
426}
427
440{
441 return d_func()->model;
442}
443
445{
446 Q_D(QWaylandOutput);
447
448 if (d->model == model)
449 return;
450
451 d->model = model;
452 d->sendGeometryInfo();
454}
455
468{
469 return d_func()->position;
470}
471
473{
474 Q_D(QWaylandOutput);
475 if (d->position == pt)
476 return;
477
478 d->position = pt;
479
480 d->sendGeometryInfo();
481
484}
485
489QList<QWaylandOutputMode> QWaylandOutput::modes() const
490{
491 Q_D(const QWaylandOutput);
492 return d->modes.toList();
493}
494
501{
502 Q_D(QWaylandOutput);
503
504 if (!mode.isValid()) {
505 qWarning("Cannot add an invalid mode");
506 return;
507 }
508
509 if (d->modes.indexOf(mode) < 0)
510 d->modes.append(mode);
511
512 if (preferred)
513 d->preferredMode = d->modes.indexOf(mode);
514
515 emit modeAdded();
516}
517
526{
527 Q_D(const QWaylandOutput);
528
529 if (d->currentMode >= 0 && d->currentMode <= d->modes.size() - 1)
530 return d->modes.at(d->currentMode);
531 return QWaylandOutputMode();
532}
533
542{
543 Q_D(QWaylandOutput);
544
545 int index = d->modes.indexOf(mode);
546 if (index < 0) {
547 qWarning("Cannot set an unknown QWaylandOutput mode as current");
548 return;
549 }
550
551 d->currentMode = index;
552
555 if (!d->availableGeometry.isValid())
557
558 d->sendModesInfo();
559}
560
575{
576 Q_D(const QWaylandOutput);
577 return QRect(d->position, currentMode().size());
578}
579
600{
601 Q_D(const QWaylandOutput);
602
603 if (!d->availableGeometry.isValid())
604 return QRect(QPoint(0, 0), currentMode().size());
605
606 return d->availableGeometry;
607}
608
609void QWaylandOutput::setAvailableGeometry(const QRect &availableGeometry)
610{
611 Q_D(QWaylandOutput);
612 if (d->availableGeometry == availableGeometry)
613 return;
614
615 if (availableGeometry.topLeft().x() < 0 || availableGeometry.topLeft().y() < 0)
616 qWarning("Available geometry should be a portion of the output");
617
618 d->availableGeometry = availableGeometry;
619
621}
622
639{
640 return d_func()->physicalSize;
641}
642
644{
645 Q_D(QWaylandOutput);
646 if (d->physicalSize == size)
647 return;
648
649 d->physicalSize = size;
650
651 d->sendGeometryInfo();
652
654}
655
695{
696 return d_func()->subpixel;
697}
698
700{
701 Q_D(QWaylandOutput);
702 if (d->subpixel == subpixel)
703 return;
704
705 d->subpixel = subpixel;
706
707 d->sendGeometryInfo();
708
710}
711
757{
758 return d_func()->transform;
759}
760
762{
763 Q_D(QWaylandOutput);
764 if (d->transform == transform)
765 return;
766
767 d->transform = transform;
768
769 d->sendGeometryInfo();
770
772}
773
798{
799 return d_func()->scaleFactor;
800}
801
803{
804 Q_D(QWaylandOutput);
805 if (d->scaleFactor == scale)
806 return;
807
808 d->scaleFactor = scale;
809
810 const auto resMap = d->resourceMap();
811 for (QWaylandOutputPrivate::Resource *resource : resMap) {
812 if (resource->version() >= 2) {
813 d->send_scale(resource->handle, scale);
814 d->send_done(resource->handle);
815 }
816 }
817
819
820 if (d->xdgOutput)
821 QWaylandXdgOutputV1Private::get(d->xdgOutput)->sendDone();
822}
823
848{
849 return d_func()->sizeFollowsWindow;
850}
851
853{
854 Q_D(QWaylandOutput);
855
856 if (follow != d->sizeFollowsWindow) {
857 d->sizeFollowsWindow = follow;
859 }
860}
861
877{
878 return d_func()->window;
879}
880
882{
883 Q_D(QWaylandOutput);
884 if (d->window == window)
885 return;
886 if (d->initialized) {
887 qWarning("Setting QWindow %p on QWaylandOutput %p is not supported after QWaylandOutput has been initialized\n", window, this);
888 return;
889 }
890 d->window = window;
892}
893
898{
899 Q_D(QWaylandOutput);
900 for (int i = 0; i < d->surfaceViews.size(); i++) {
901 QWaylandSurfaceViewMapper &surfacemapper = d->surfaceViews[i];
902 if (surfacemapper.maybePrimaryView())
903 surfacemapper.surface->frameStarted();
904 }
905}
906
911{
912 Q_D(QWaylandOutput);
913 for (int i = 0; i < d->surfaceViews.size(); i++) {
914 const QWaylandSurfaceViewMapper &surfacemapper = d->surfaceViews.at(i);
915 if (surfacemapper.surface && surfacemapper.surface->hasContent()) {
916 if (!surfacemapper.has_entered) {
917 surfaceEnter(surfacemapper.surface);
918 d->surfaceViews[i].has_entered = true;
919 }
920 if (auto primaryView = surfacemapper.maybePrimaryView()) {
921 if (!QWaylandViewPrivate::get(primaryView)->independentFrameCallback)
922 surfacemapper.surface->sendFrameCallbacks();
923 }
924 }
925 }
926 wl_display_flush_clients(d->compositor->display());
927}
928
933{
934 if (!surface)
935 return;
936
937 auto clientResource = resourceForClient(surface->client());
938 if (clientResource)
939 QWaylandSurfacePrivate::get(surface)->send_enter(clientResource);
940}
941
946{
947 if (!surface || !surface->client())
948 return;
949
950 auto *clientResource = resourceForClient(surface->client());
951 if (clientResource)
952 QWaylandSurfacePrivate::get(surface)->send_leave(clientResource);
953}
954
959{
960 if (event->type() == QEvent::Polish)
961 initialize();
962 return QObject::event(event);
963}
964
966
967#include "moc_qwaylandoutput.cpp"
\inmodule QtCore
Definition qcoreevent.h:45
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
bool removeOne(const AT &t)
Definition qlist.h:598
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void remove(qsizetype i, qsizetype n=1)
Definition qlist.h:794
void replace(qsizetype i, parameter_type t)
Definition qlist.h:543
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:299
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1389
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:170
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
qreal refreshRate
the approximate vertical refresh rate of the screen in Hz
Definition qscreen.h:64
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\qmltype WaylandClient \instantiates QWaylandClient \inqmlmodule QtWayland.Compositor
wl_client * client() const
Returns the Wayland client of this QWaylandClient.
static QWaylandCompositorPrivate * get(QWaylandCompositor *compositor)
\qmltype WaylandCompositor \instantiates QWaylandCompositor \inqmlmodule QtWayland....
\inmodule QtWaylandCompositor
\inmodule QtWaylandCompositor
void removeView(QWaylandView *view, QWaylandSurface *surface)
void addView(QWaylandView *view, QWaylandSurface *surface)
~QWaylandOutputPrivate() override
void sendMode(const Resource *resource, const QWaylandOutputMode &mode)
void output_bind_resource(Resource *resource) override
QPointer< QWaylandXdgOutputV1 > xdgOutput
void sendGeometry(const Resource *resource)
\qmltype WaylandOutput \instantiates QWaylandOutput \inqmlmodule QtWayland.Compositor
QWaylandOutput::Subpixel subpixel
\qmlproperty enum QtWayland.Compositor::WaylandOutput::subpixel
void availableGeometryChanged()
void scaleFactorChanged()
bool sizeFollowsWindow
\qmlproperty bool QtWayland.Compositor::WaylandOutput::sizeFollowsWindow
void setSizeFollowsWindow(bool follow)
void modelChanged()
void setScaleFactor(int scale)
void setAvailableGeometry(const QRect &availableGeometry)
static QWaylandOutput * fromResource(wl_resource *resource)
Returns the QWaylandOutput corresponding to resource.
QString manufacturer
\qmlproperty string QtWayland.Compositor::WaylandOutput::manufacturer
QPoint position
\qmlproperty point QtWayland.Compositor::WaylandOutput::position
void subpixelChanged()
void setCurrentMode(const QWaylandOutputMode &mode)
Sets the current mode.
struct::wl_resource * resourceForClient(QWaylandClient *client) const
QSize physicalSize
\qmlproperty size QtWayland.Compositor::WaylandOutput::physicalSize
void setPosition(const QPoint &pt)
void surfaceLeave(QWaylandSurface *surface)
QRect availableGeometry
\qmlproperty rect QtWayland.Compositor::WaylandOutput::availableGeometry
void frameStarted()
Informs QWaylandOutput that a frame has started.
virtual void initialize()
virtual void update()
Schedules a QEvent::UpdateRequest to be delivered to the QWaylandOutput's \l{window()}{window}.
QRect geometry
\qmlproperty rect QtWayland.Compositor::WaylandOutput::geometry
void setTransform(const Transform &transform)
bool event(QEvent *event) override
~QWaylandOutput() override
Destroys the QWaylandOutput.
void setModel(const QString &model)
void setCompositor(QWaylandCompositor *compositor)
void addMode(const QWaylandOutputMode &mode, bool preferred=false)
Adds the mode mode to the output and mark it as preferred if preferred is true.
QList< QWaylandOutputMode > modes() const
Returns the list of modes.
Subpixel
This enum type is used to specify the subpixel arrangement of a QWaylandOutput.
void setPhysicalSize(const QSize &size)
void surfaceEnter(QWaylandSurface *surface)
Transform
This enum type is used to specify the orientation of a QWaylandOutput.
void transformChanged()
void sendFrameCallbacks()
Sends pending frame callbacks.
QWindow * window
\qmlproperty Window QtWayland.Compositor::WaylandOutput::window
void sizeFollowsWindowChanged()
void currentModeChanged()
QWaylandOutputMode currentMode() const
Returns the output's size in pixels and refresh rate in mHz.
QString model
\qmlproperty string QtWayland.Compositor::WaylandOutput::model
void windowChanged()
void physicalSizeChanged()
void setSubpixel(const Subpixel &subpixel)
void setManufacturer(const QString &manufacturer)
void manufacturerChanged()
void positionChanged()
int scaleFactor
\qmlproperty int QtWayland.Compositor::WaylandOutput::scaleFactor
QWaylandOutput::Transform transform
\qmlproperty enum QtWayland.Compositor::WaylandOutput::transform
QWaylandCompositor * compositor
void geometryChanged()
void setWindow(QWindow *window)
static QWaylandSurfacePrivate * get(QWaylandSurface *surface)
\qmltype WaylandSurface \instantiates QWaylandSurface \inqmlmodule QtWayland.Compositor
Q_INVOKABLE void frameStarted()
Prepares all frame callbacks for sending.
QWaylandClient * client
\qmlproperty WaylandClient QtWayland.Compositor::WaylandSurface::client
static QWaylandViewPrivate * get(QWaylandView *view)
\qmltype WaylandView \instantiates QWaylandView \inqmlmodule QtWayland.Compositor
static QWaylandXdgOutputV1Private * get(QWaylandXdgOutputV1 *xdgOutput)
\inmodule QtGui
Definition qwindow.h:63
void heightChanged(int arg)
QSize size() const override
Returns the size of the window excluding any window frame.
Definition qwindow.h:210
void widthChanged(int arg)
void screenChanged(QScreen *screen)
This signal is emitted when a window's screen changes, either by being set explicitly with setScreen(...
Combined button and popup list for selecting options.
#define Q_FUNC_INFO
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:166
int qFloor(T v)
Definition qmath.h:42
static QOpenGLCompositor * compositor
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLbitfield flags
struct _cl_event * event
GLuint GLenum GLenum transform
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
GLenum GLenum GLenum GLenum GLenum scale
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_EMIT
#define emit
unsigned int quint32
Definition qtypes.h:50
static QtWaylandServer::wl_output::transform toWlTransform(const QWaylandOutput::Transform &value)
static QT_BEGIN_NAMESPACE QtWaylandServer::wl_output::subpixel toWlSubpixel(const QWaylandOutput::Subpixel &value)
QSqlQueryModel * model
[16]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QQuickView * view
[0]
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:962
bool contains(const AT &t) const noexcept
Definition qlist.h:45
QList< QWaylandView * > views