Revision control

++ // Copyright (C) 2017 Jolla Ltd, author: <giulio.camuffo@jollamobile.com>
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qwaylandview.h"
++ #include "qwaylandview_p.h"
++ #include "qwaylandsurface.h"
++ #include <QtWaylandCompositor/QWaylandSeat>
++ #include <QtWaylandCompositor/QWaylandCompositor>
++
++ #include <QtWaylandCompositor/private/qwaylandsurface_p.h>
++ #include <QtWaylandCompositor/private/qwaylandoutput_p.h>
++
++ #include <QtCore/QMutex>
++ #include <QtCore/qpointer.h>
++
++ QT_BEGIN_NAMESPACE
++
++ void QWaylandViewPrivate::markSurfaceAsDestroyed(QWaylandSurface *surface)
++ {
++ Q_Q(QWaylandView);
++ Q_ASSERT(surface == this->surface);
++
++ setSurface(nullptr);
++ QPointer<QWaylandView> deleteGuard(q);
++ emit q->surfaceDestroyed();
++ if (!deleteGuard.isNull())
++ clearFrontBuffer();
++ }
++
++ /*!
++ * \class QWaylandView
++ * \inmodule QtWaylandCompositor
++ * \since 5.8
++ * \brief The QWaylandView class represents a view of a surface on an output.
++ *
++ * The QWaylandView corresponds to the presentation of a surface on a specific
++ * output, managing the buffers that contain the contents to be rendered.
++ * You can have several views into the same surface.
++ */
++
++ /*!
++ * Constructs a QWaylandView with the given \a renderObject and \a parent.
++ */
++ QWaylandView::QWaylandView(QObject *renderObject, QObject *parent)
++ : QObject(*new QWaylandViewPrivate(),parent)
++ {
++ d_func()->renderObject = renderObject;
++ }
++
++ /*!
++ * Destroys the QWaylandView.
++ */
++ QWaylandView::~QWaylandView()
++ {
++ Q_D(QWaylandView);
++ if (d->surface) {
++ if (d->output)
++ QWaylandOutputPrivate::get(d->output)->removeView(this, d->surface);
++
++ QWaylandSurfacePrivate::get(d->surface)->derefView(this);
++ }
++
++ }
++
++ /*!
++ * \property QWaylandView::renderObject
++ * \internal
++ * Didn't we decide to remove this property?
++ */
++ QObject *QWaylandView::renderObject() const
++ {
++ Q_D(const QWaylandView);
++ return d->renderObject;
++ }
++
++ /*!
++ * \property QWaylandView::surface
++ *
++ * This property holds the surface viewed by this QWaylandView.
++ */
++ QWaylandSurface *QWaylandView::surface() const
++ {
++ Q_D(const QWaylandView);
++ return d->surface;
++ }
++
++
++ void QWaylandViewPrivate::setSurface(QWaylandSurface *newSurface)
++ {
++ Q_Q(QWaylandView);
++ if (surface) {
++ QWaylandSurfacePrivate::get(surface)->derefView(q);
++ if (output)
++ QWaylandOutputPrivate::get(output)->removeView(q, surface);
++ }
++
++ surface = newSurface;
++
++ nextBuffer = QWaylandBufferRef();
++ nextBufferCommitted = false;
++ nextDamage = QRegion();
++ forceAdvanceSucceed = false;
++
++ if (surface) {
++ QWaylandSurfacePrivate::get(surface)->refView(q);
++ if (output)
++ QWaylandOutputPrivate::get(output)->addView(q, surface);
++ }
++ }
++
++ void QWaylandViewPrivate::clearFrontBuffer()
++ {
++ if (!bufferLocked) {
++ currentBuffer = QWaylandBufferRef();
++ currentDamage = QRegion();
++ }
++ }
++
++ void QWaylandView::setSurface(QWaylandSurface *newSurface)
++ {
++ Q_D(QWaylandView);
++ if (d->surface == newSurface)
++ return;
++
++ d->setSurface(newSurface);
++ d->clearFrontBuffer();
++ emit surfaceChanged();
++ }
++
++ /*!
++ * \property QWaylandView::output
++ *
++ * This property holds the output on which this view displays its surface.
++ */
++ QWaylandOutput *QWaylandView::output() const
++ {
++ Q_D(const QWaylandView);
++ return d->output;
++ }
++
++ void QWaylandView::setOutput(QWaylandOutput *newOutput)
++ {
++ Q_D(QWaylandView);
++ if (d->output == newOutput)
++ return;
++
++ if (d->output && d->surface)
++ QWaylandOutputPrivate::get(d->output)->removeView(this, d->surface);
++
++ d->output = newOutput;
++
++ if (d->output && d->surface)
++ QWaylandOutputPrivate::get(d->output)->addView(this, d->surface);
++
++ emit outputChanged();
++ }
++
++ /*!
++ * This function is called when a new \a buffer is committed to this view's surface.
++ * \a damage contains the region that is different from the current buffer, i.e. the
++ * region that needs to be updated.
++ * The new \a buffer will become current on the next call to advance().
++ *
++ * Subclasses that reimplement this function \e must call the base implementation.
++ */
++ void QWaylandView::bufferCommitted(const QWaylandBufferRef &buffer, const QRegion &damage)
++ {
++ Q_D(QWaylandView);
++ QMutexLocker locker(&d->bufferMutex);
++ d->nextBuffer = buffer;
++ d->nextDamage = damage;
++ d->nextBufferCommitted = true;
++ }
++
++ /*!
++ * Updates the current buffer and damage region to the latest version committed by the client.
++ * Returns true if new content was committed since the previous call to advance().
++ * Otherwise returns false.
++ *
++ * \sa currentBuffer(), currentDamage()
++ */
++ bool QWaylandView::advance()
++ {
++ Q_D(QWaylandView);
++
++ if (!d->nextBufferCommitted && !d->forceAdvanceSucceed)
++ return false;
++
++ if (d->bufferLocked)
++ return false;
++
++ if (d->surface && d->surface->primaryView() == this) {
++ const auto views = d->surface->views();
++ for (QWaylandView *view : views) {
++ if (view != this && view->allowDiscardFrontBuffer() && view->d_func()->currentBuffer == d->currentBuffer)
++ view->discardCurrentBuffer();
++ }
++ }
++
++ QMutexLocker locker(&d->bufferMutex);
++ d->forceAdvanceSucceed = false;
++ d->nextBufferCommitted = false;
++ d->currentBuffer = std::exchange(d->nextBuffer, {});
++ d->currentDamage = std::exchange(d->nextDamage, {});
++ return true;
++ }
++
++ /*!
++ * Force the view to discard its current buffer, to allow it to be reused on the client side.
++ */
++ void QWaylandView::discardCurrentBuffer()
++ {
++ Q_D(QWaylandView);
++ QMutexLocker locker(&d->bufferMutex);
++ d->currentBuffer = QWaylandBufferRef();
++ d->forceAdvanceSucceed = true;
++ }
++
++ /*!
++ * Returns a reference to this view's current buffer.
++ */
++ QWaylandBufferRef QWaylandView::currentBuffer()
++ {
++ Q_D(QWaylandView);
++ QMutexLocker locker(&d->bufferMutex);
++ return d->currentBuffer;
++ }
++
++ /*!
++ * Returns the current damage region of this view.
++ */
++ QRegion QWaylandView::currentDamage()
++ {
++ Q_D(QWaylandView);
++ QMutexLocker locker(&d->bufferMutex);
++ return d->currentDamage;
++ }
++
++ /*!
++ * \property QWaylandView::bufferLocked
++ *
++ * This property holds whether the view's buffer is currently locked. When
++ * the buffer is locked, advance() will not advance to the next buffer
++ * and returns \c false.
++ *
++ * The default is \c false.
++ */
++ bool QWaylandView::isBufferLocked() const
++ {
++ Q_D(const QWaylandView);
++ return d->bufferLocked;
++ }
++
++ void QWaylandView::setBufferLocked(bool locked)
++ {
++ Q_D(QWaylandView);
++ if (d->bufferLocked == locked)
++ return;
++ d->bufferLocked = locked;
++ emit bufferLockedChanged();
++
++ if (d->surface == nullptr && !d->bufferLocked)
++ d->clearFrontBuffer();
++ }
++
++ /*!
++ * \property QWaylandView::allowDiscardFrontBuffer
++ *
++ * By default, the view locks the current buffer until advance() is called. Set this property
++ * to \c true to allow Qt to release the buffer when the primary view is no longer using it.
++ *
++ * This can be used to avoid the situation where a secondary view that updates on a lower
++ * frequency will throttle the frame rate of the client application.
++ */
++ bool QWaylandView::allowDiscardFrontBuffer() const
++ {
++ Q_D(const QWaylandView);
++ return d->allowDiscardFrontBuffer;
++ }
++
++ void QWaylandView::setAllowDiscardFrontBuffer(bool discard)
++ {
++ Q_D(QWaylandView);
++ if (d->allowDiscardFrontBuffer == discard)
++ return;
++ d->allowDiscardFrontBuffer = discard;
++ emit allowDiscardFrontBufferChanged();
++ }
++
++ /*!
++ * Makes this QWaylandView the primary view for the surface.
++ *
++ * It has no effect if this QWaylandView is not holding any QWaylandSurface
++ *
++ * \sa QWaylandSurface::primaryView
++ */
++ void QWaylandView::setPrimary()
++ {
++ Q_D(QWaylandView);
++ if (d->surface)
++ d->surface->setPrimaryView(this);
++ else
++ qWarning("Calling setPrimary() on a QWaylandView without a surface has no effect.");
++ }
++
++ /*!
++ * Returns true if this QWaylandView is the primary view for the QWaylandSurface
++ *
++ * \sa QWaylandSurface::primaryView
++ */
++ bool QWaylandView::isPrimary() const
++ {
++ Q_D(const QWaylandView);
++ return d->surface && d->surface->primaryView() == this;
++ }
++
++ /*!
++ * Returns the Wayland surface resource for this QWaylandView.
++ */
++ struct wl_resource *QWaylandView::surfaceResource() const
++ {
++ Q_D(const QWaylandView);
++ if (!d->surface)
++ return nullptr;
++ return d->surface->resource();
++ }
++
++ QT_END_NAMESPACE
++
++ #include "moc_qwaylandview.cpp"