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

source code of qtwayland/src/compositor/compositor_api/qwaylandview.cpp