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
qwaylandviewporter.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:critical reason:network-protocol
4
6
7#include <QtWaylandCompositor/QWaylandSurface>
8#include <QtWaylandCompositor/QWaylandCompositor>
9
10#include <QtWaylandCompositor/private/qwaylandsurface_p.h>
11
13
14/*!
15 \class QWaylandViewporter
16 \inmodule QtWaylandCompositor
17 \since 5.13
18 \brief Provides an extension for surface resizing and cropping.
19
20 The QWaylandViewporter extension provides a way for clients to resize and crop surface
21 contents.
22
23 QWaylandViewporter corresponds to the Wayland interface, \c wp_viewporter.
24*/
25
26/*!
27 Constructs a QWaylandViewporter object.
28*/
29QWaylandViewporter::QWaylandViewporter()
30 : QWaylandCompositorExtensionTemplate<QWaylandViewporter>(*new QWaylandViewporterPrivate)
31{
32}
33
34/*!
35 * Constructs a QWaylandViewporter object for the provided \a compositor.
36 */
37QWaylandViewporter::QWaylandViewporter(QWaylandCompositor *compositor)
38 : QWaylandCompositorExtensionTemplate<QWaylandViewporter>(compositor, *new QWaylandViewporterPrivate())
39{
40}
41
42/*!
43 Initializes the extension.
44*/
45void QWaylandViewporter::initialize()
46{
47 Q_D(QWaylandViewporter);
48
49 QWaylandCompositorExtensionTemplate::initialize();
50 auto *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
51 if (!compositor) {
52 qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandViewporter";
53 return;
54 }
55 d->init(compositor->display(), 1);
56}
57
58/*!
59 Returns the Wayland interface for the QWaylandViewporter.
60*/
61const wl_interface *QWaylandViewporter::interface()
62{
63 return QWaylandViewporterPrivate::interface();
64}
65
66void QWaylandViewporterPrivate::wp_viewporter_destroy(Resource *resource)
67{
68 // Viewport objects are allowed ot outlive the viewporter
69 wl_resource_destroy(resource->handle);
70}
71
72void QWaylandViewporterPrivate::wp_viewporter_get_viewport(Resource *resource, uint id, wl_resource *surfaceResource)
73{
74 auto *surface = QWaylandSurface::fromResource(surfaceResource);
75 if (!surface) {
76 qWarning() << "Couldn't find surface for viewporter";
77 return;
78 }
79
80 auto *surfacePrivate = QWaylandSurfacePrivate::get(surface);
81 if (surfacePrivate->viewport) {
82 wl_resource_post_error(resource->handle, WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
83 "viewport already exists for surface");
84 return;
85 }
86
87 surfacePrivate->viewport = new Viewport(surface, resource->client(), id);
88}
89
90QWaylandViewporterPrivate::Viewport::Viewport(QWaylandSurface *surface, wl_client *client, int id)
91 : QtWaylandServer::wp_viewport(client, id, /*version*/ 1)
92 , m_surface(surface)
93{
94 Q_ASSERT(surface);
95}
96
97QWaylandViewporterPrivate::Viewport::~Viewport()
98{
99 if (m_surface) {
100 auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
101 Q_ASSERT(surfacePrivate->viewport == this);
102 surfacePrivate->viewport = nullptr;
103 }
104}
105
106// This function has to be called immediately after a surface is committed, before no
107// other client events have been dispatched, or we may incorrectly error out on an
108// incomplete pending state. See comment below.
109void QWaylandViewporterPrivate::Viewport::checkCommittedState()
110{
111 auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
112
113 // We can't use the current state for destination/source when checking,
114 // as that has fallbacks to the buffer size so we can't distinguish
115 // between the set/unset case. We use the pending state because no other
116 // requests has modified it yet.
117 QSize destination = surfacePrivate->pending.destinationSize;
118 QRectF source = surfacePrivate->pending.sourceGeometry;
119
120 if (!destination.isValid() && source.size() != source.size().toSize()) {
121 wl_resource_post_error(resource()->handle, error_bad_size,
122 "non-integer size (%fx%f) with unset destination",
123 source.width(), source.height());
124 return;
125 }
126
127 if (m_surface->bufferSize().isValid()) {
128 QRectF max = QRectF(QPointF(), m_surface->bufferSize() / m_surface->bufferScale());
129 // We can't use QRectF.contains, because that would return false for values on the border
130 if (max.united(source) != max) {
131 wl_resource_post_error(resource()->handle, error_out_of_buffer,
132 "source %f,%f, %fx%f extends outside attached buffer %fx%f",
133 source.x(), source.y(), source.width(), source.height(),
134 max.width(), max.height());
135 return;
136 }
137 }
138}
139
140
141void QWaylandViewporterPrivate::Viewport::wp_viewport_destroy_resource(Resource *resource)
142{
143 Q_UNUSED(resource);
144 delete this;
145}
146
147void QWaylandViewporterPrivate::Viewport::wp_viewport_destroy(Resource *resource)
148{
149 if (m_surface) {
150 auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
151 surfacePrivate->pending.destinationSize = QSize();
152 surfacePrivate->pending.sourceGeometry = QRectF();
153 }
154 wl_resource_destroy(resource->handle);
155}
156
157void QWaylandViewporterPrivate::Viewport::wp_viewport_set_source(QtWaylandServer::wp_viewport::Resource *resource, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height)
158{
159 Q_UNUSED(resource);
160
161 if (!m_surface) {
162 wl_resource_post_error(resource->handle, error_no_surface,
163 "set_source requested for destroyed surface");
164 return;
165 }
166
167 QPointF position(wl_fixed_to_double(x), wl_fixed_to_double(y));
168 QSizeF size(wl_fixed_to_double(width), wl_fixed_to_double(height));
169 QRectF sourceGeometry(position, size);
170
171 if (sourceGeometry == QRectF(-1, -1, -1, -1)) {
172 auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
173 surfacePrivate->pending.sourceGeometry = QRectF();
174 return;
175 }
176
177 if (position.x() < 0 || position.y() < 0) {
178 wl_resource_post_error(resource->handle, error_bad_value,
179 "negative position in set_source");
180 return;
181 }
182
183 if (!size.isValid()) {
184 wl_resource_post_error(resource->handle, error_bad_value,
185 "negative size in set_source");
186 return;
187 }
188
189 auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
190 surfacePrivate->pending.sourceGeometry = sourceGeometry;
191}
192
193void QWaylandViewporterPrivate::Viewport::wp_viewport_set_destination(QtWaylandServer::wp_viewport::Resource *resource, int32_t width, int32_t height)
194{
195 Q_UNUSED(resource);
196
197 if (!m_surface) {
198 wl_resource_post_error(resource->handle, error_no_surface,
199 "set_destination requested for destroyed surface");
200 return;
201 }
202
203 QSize destinationSize(width, height);
204 if (!destinationSize.isValid() && destinationSize != QSize(-1, -1)) {
205 wl_resource_post_error(resource->handle, error_bad_value,
206 "negative size in set_destination");
207 return;
208 }
209 auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
210 surfacePrivate->pending.destinationSize = destinationSize;
211}
212
213QT_END_NAMESPACE
214
215#include "moc_qwaylandviewporter.cpp"
Combined button and popup list for selecting options.