1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 Jolla Ltd, author: <giulio.camuffo@jollamobile.com>
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29
30 #include "qwaylandview.h"
31 #include "qwaylandview_p.h"
32 #include "qwaylandsurface.h"
33 #include <QtWaylandCompositor/QWaylandSeat>
34 #include <QtWaylandCompositor/QWaylandCompositor>
35
36 #include <QtWaylandCompositor/private/qwaylandsurface_p.h>
37 #include <QtWaylandCompositor/private/qwaylandoutput_p.h>
38
39 #include <QtCore/QMutex>
40
41 QT_BEGIN_NAMESPACE
42
markSurfaceAsDestroyed(QWaylandSurface * surface)43 void QWaylandViewPrivate::markSurfaceAsDestroyed(QWaylandSurface *surface)
44 {
45 Q_Q(QWaylandView);
46 Q_ASSERT(surface == this->surface);
47
48 setSurface(nullptr);
49 QPointer<QWaylandView> deleteGuard(q);
50 emit q->surfaceDestroyed();
51 if (!deleteGuard.isNull())
52 clearFrontBuffer();
53 }
54
55 /*!
56 * \qmltype WaylandView
57 * \inqmlmodule QtWayland.Compositor
58 * \since 5.8
59 * \brief Represents a view of a surface on an output.
60 *
61 * The WaylandView corresponds to the presentation of a surface on a specific
62 * output, managing the buffers that contain the contents to be rendered.
63 * You can have several views into the same surface.
64 */
65
66 /*!
67 * \class QWaylandView
68 * \inmodule QtWaylandCompositor
69 * \since 5.8
70 * \brief The QWaylandView class represents a view of a surface on an output.
71 *
72 * The QWaylandView corresponds to the presentation of a surface on a specific
73 * output, managing the buffers that contain the contents to be rendered.
74 * You can have several views into the same surface.
75 */
76
77 /*!
78 * Constructs a QWaylandView with the given \a renderObject and \a parent.
79 */
QWaylandView(QObject * renderObject,QObject * parent)80 QWaylandView::QWaylandView(QObject *renderObject, QObject *parent)
81 : QObject(*new QWaylandViewPrivate(),parent)
82 {
83 d_func()->renderObject = renderObject;
84 }
85
86 /*!
87 * Destroys the QWaylandView.
88 */
~QWaylandView()89 QWaylandView::~QWaylandView()
90 {
91 Q_D(QWaylandView);
92 if (d->surface) {
93 if (d->output)
94 QWaylandOutputPrivate::get(d->output)->removeView(this, d->surface);
95
96 QWaylandSurfacePrivate::get(d->surface)->derefView(this);
97 }
98
99 }
100
101 /*!
102 * \internal
103 * Didn't we decide to remove this property?
104 */
renderObject() const105 QObject *QWaylandView::renderObject() const
106 {
107 Q_D(const QWaylandView);
108 return d->renderObject;
109 }
110
111 /*!
112 * \qmlproperty WaylandSurface QtWaylandCompositor::WaylandView::surface
113 *
114 * This property holds the surface viewed by this WaylandView.
115 */
116
117 /*!
118 * \property QWaylandView::surface
119 *
120 * This property holds the surface viewed by this QWaylandView.
121 */
surface() const122 QWaylandSurface *QWaylandView::surface() const
123 {
124 Q_D(const QWaylandView);
125 return d->surface;
126 }
127
128
setSurface(QWaylandSurface * newSurface)129 void QWaylandViewPrivate::setSurface(QWaylandSurface *newSurface)
130 {
131 Q_Q(QWaylandView);
132 if (surface) {
133 QWaylandSurfacePrivate::get(surface)->derefView(q);
134 if (output)
135 QWaylandOutputPrivate::get(output)->removeView(q, surface);
136 }
137
138 surface = newSurface;
139
140 nextBuffer = QWaylandBufferRef();
141 nextBufferCommitted = false;
142 nextDamage = QRegion();
143
144 if (surface) {
145 QWaylandSurfacePrivate::get(surface)->refView(q);
146 if (output)
147 QWaylandOutputPrivate::get(output)->addView(q, surface);
148 }
149 }
150
clearFrontBuffer()151 void QWaylandViewPrivate::clearFrontBuffer()
152 {
153 if (!bufferLocked) {
154 currentBuffer = QWaylandBufferRef();
155 currentDamage = QRegion();
156 }
157 }
158
setSurface(QWaylandSurface * newSurface)159 void QWaylandView::setSurface(QWaylandSurface *newSurface)
160 {
161 Q_D(QWaylandView);
162 if (d->surface == newSurface)
163 return;
164
165 d->setSurface(newSurface);
166 d->clearFrontBuffer();
167 emit surfaceChanged();
168 }
169
170 /*!
171 * \qmlproperty WaylandOutput QtWaylandCompositor::WaylandView::output
172 *
173 * This property holds the output on which this view displays its surface.
174 */
175
176 /*!
177 * \property QWaylandView::output
178 *
179 * This property holds the output on which this view displays its surface.
180 */
output() const181 QWaylandOutput *QWaylandView::output() const
182 {
183 Q_D(const QWaylandView);
184 return d->output;
185 }
186
setOutput(QWaylandOutput * newOutput)187 void QWaylandView::setOutput(QWaylandOutput *newOutput)
188 {
189 Q_D(QWaylandView);
190 if (d->output == newOutput)
191 return;
192
193 if (d->output && d->surface)
194 QWaylandOutputPrivate::get(d->output)->removeView(this, d->surface);
195
196 d->output = newOutput;
197
198 if (d->output && d->surface)
199 QWaylandOutputPrivate::get(d->output)->addView(this, d->surface);
200
201 emit outputChanged();
202 }
203
204 /*!
205 * This function is called when a new \a buffer is committed to this view's surface.
206 * \a damage contains the region that is different from the current buffer, i.e. the
207 * region that needs to be updated.
208 * The new \a buffer will become current on the next call to advance().
209 *
210 * Subclasses that reimplement this function \e must call the base implementation.
211 */
bufferCommitted(const QWaylandBufferRef & buffer,const QRegion & damage)212 void QWaylandView::bufferCommitted(const QWaylandBufferRef &buffer, const QRegion &damage)
213 {
214 Q_D(QWaylandView);
215 QMutexLocker locker(&d->bufferMutex);
216 d->nextBuffer = buffer;
217 d->nextDamage = damage;
218 d->nextBufferCommitted = true;
219 }
220
221 /*!
222 * Updates the current buffer and damage region to the latest version committed by the client.
223 * Returns true if new content was committed since the previous call to advance().
224 * Otherwise returns false.
225 *
226 * \sa currentBuffer(), currentDamage()
227 */
advance()228 bool QWaylandView::advance()
229 {
230 Q_D(QWaylandView);
231
232 if (!d->nextBufferCommitted && !d->forceAdvanceSucceed)
233 return false;
234
235 if (d->bufferLocked)
236 return false;
237
238 if (d->surface && d->surface->primaryView() == this) {
239 const auto views = d->surface->views();
240 for (QWaylandView *view : views) {
241 if (view != this && view->allowDiscardFrontBuffer() && view->d_func()->currentBuffer == d->currentBuffer)
242 view->discardCurrentBuffer();
243 }
244 }
245
246 QMutexLocker locker(&d->bufferMutex);
247 d->forceAdvanceSucceed = false;
248 d->nextBufferCommitted = false;
249 d->currentBuffer = d->nextBuffer;
250 d->currentDamage = d->nextDamage;
251 return true;
252 }
253
254 /*!
255 * Force the view to discard its current buffer, to allow it to be reused on the client side.
256 */
discardCurrentBuffer()257 void QWaylandView::discardCurrentBuffer()
258 {
259 Q_D(QWaylandView);
260 QMutexLocker locker(&d->bufferMutex);
261 d->currentBuffer = QWaylandBufferRef();
262 d->forceAdvanceSucceed = true;
263 }
264
265 /*!
266 * Returns a reference to this view's current buffer.
267 */
currentBuffer()268 QWaylandBufferRef QWaylandView::currentBuffer()
269 {
270 Q_D(QWaylandView);
271 QMutexLocker locker(&d->bufferMutex);
272 return d->currentBuffer;
273 }
274
275 /*!
276 * Returns the current damage region of this view.
277 */
currentDamage()278 QRegion QWaylandView::currentDamage()
279 {
280 Q_D(QWaylandView);
281 QMutexLocker locker(&d->bufferMutex);
282 return d->currentDamage;
283 }
284
285 /*!
286 * \qmlproperty bool QtWaylandCompositor::WaylandView::bufferLocked
287 *
288 * This property holds whether the view's buffer is currently locked. When
289 * the buffer is locked, advance() will not advance to the next buffer and
290 * returns \c false.
291 *
292 * The default is \c false.
293 */
294
295 /*!
296 * \property QWaylandView::bufferLocked
297 *
298 * This property holds whether the view's buffer is currently locked. When
299 * the buffer is locked, advance() will not advance to the next buffer
300 * and returns \c false.
301 *
302 * The default is \c false.
303 */
isBufferLocked() const304 bool QWaylandView::isBufferLocked() const
305 {
306 Q_D(const QWaylandView);
307 return d->bufferLocked;
308 }
309
setBufferLocked(bool locked)310 void QWaylandView::setBufferLocked(bool locked)
311 {
312 Q_D(QWaylandView);
313 if (d->bufferLocked == locked)
314 return;
315 d->bufferLocked = locked;
316 emit bufferLockedChanged();
317 }
318 /*!
319 * \qmlproperty bool QtWaylandCompositor::WaylandView::allowDiscardFrontBuffer
320 *
321 * By default, the view locks the current buffer until advance() is called. Set this property
322 * to true to allow Qt to release the buffer when the primary view is no longer using it.
323 *
324 * This can be used to avoid the situation where a secondary view that updates on a lower
325 * frequency will throttle the frame rate of the client application.
326 */
327
328 /*!
329 * \property QWaylandView::allowDiscardFrontBuffer
330 *
331 * By default, the view locks the current buffer until advance() is called. Set this property
332 * to \c true to allow Qt to release the buffer when the primary view is no longer using it.
333 *
334 * This can be used to avoid the situation where a secondary view that updates on a lower
335 * frequency will throttle the frame rate of the client application.
336 */
allowDiscardFrontBuffer() const337 bool QWaylandView::allowDiscardFrontBuffer() const
338 {
339 Q_D(const QWaylandView);
340 return d->allowDiscardFrontBuffer;
341 }
342
setAllowDiscardFrontBuffer(bool discard)343 void QWaylandView::setAllowDiscardFrontBuffer(bool discard)
344 {
345 Q_D(QWaylandView);
346 if (d->allowDiscardFrontBuffer == discard)
347 return;
348 d->allowDiscardFrontBuffer = discard;
349 emit allowDiscardFrontBufferChanged();
350 }
351
352 /*!
353 * Makes this QWaylandView the primary view for the surface.
354 *
355 * It has no effect if this QWaylandView is not holding any QWaylandSurface
356 *
357 * \sa QWaylandSurface::primaryView
358 */
setPrimary()359 void QWaylandView::setPrimary()
360 {
361 Q_D(QWaylandView);
362 if (d->surface)
363 d->surface->setPrimaryView(this);
364 else
365 qWarning("Calling setPrimary() on a QWaylandView without a surface has no effect.");
366 }
367
368 /*!
369 * Returns true if this QWaylandView is the primary view for the QWaylandSurface
370 *
371 * \sa QWaylandSurface::primaryView
372 */
isPrimary() const373 bool QWaylandView::isPrimary() const
374 {
375 Q_D(const QWaylandView);
376 return d->surface && d->surface->primaryView() == this;
377 }
378
379 /*!
380 * Returns the Wayland surface resource for this QWaylandView.
381 */
surfaceResource() const382 struct wl_resource *QWaylandView::surfaceResource() const
383 {
384 Q_D(const QWaylandView);
385 if (!d->surface)
386 return nullptr;
387 return d->surface->resource();
388 }
389
390 QT_END_NAMESPACE
391