| /**************************************************************************** |
| ** |
| ** Copyright (C) 2017 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtWaylandCompositor module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 or (at your option) any later version |
| ** approved by the KDE Free Qt Foundation. The licenses are as published by |
| ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #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> |
| |
| 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(); |
| } |
| |
| /*! |
| * \qmltype WaylandView |
| * \inqmlmodule QtWayland.Compositor |
| * \since 5.8 |
| * \brief Represents a view of a surface on an output. |
| * |
| * The WaylandView 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. |
| */ |
| |
| /*! |
| * \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); |
| } |
| |
| } |
| |
| /*! |
| * \internal |
| * Didn't we decide to remove this property? |
| */ |
| QObject *QWaylandView::renderObject() const |
| { |
| Q_D(const QWaylandView); |
| return d->renderObject; |
| } |
| |
| /*! |
| * \qmlproperty WaylandSurface QtWaylandCompositor::WaylandView::surface |
| * |
| * This property holds the surface viewed by this WaylandView. |
| */ |
| |
| /*! |
| * \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(); |
| |
| 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(); |
| } |
| |
| /*! |
| * \qmlproperty WaylandOutput QtWaylandCompositor::WaylandView::output |
| * |
| * This property holds the output on which this view displays its surface. |
| */ |
| |
| /*! |
| * \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 = d->nextBuffer; |
| d->currentDamage = 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; |
| } |
| |
| /*! |
| * \qmlproperty bool QtWaylandCompositor::WaylandView::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. |
| */ |
| |
| /*! |
| * \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(); |
| } |
| /*! |
| * \qmlproperty bool QtWaylandCompositor::WaylandView::allowDiscardFrontBuffer |
| * |
| * By default, the view locks the current buffer until advance() is called. Set this property |
| * to 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. |
| */ |
| |
| /*! |
| * \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 |