Source code
Revision control
Copy as Markdown
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qwaylandcompositorextension.h"
#include "qwaylandcompositorextension_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <wayland-server-core.h>
QT_BEGIN_NAMESPACE
/*!
* \class QWaylandCompositorExtensionTemplate
* \inmodule QtWaylandCompositor
* \since 5.8
* \brief QWaylandCompositorExtensionTemplate is a convenience class for subclassing
* QWaylandCompositorExtension.
*
* QWaylandCompositorExtensionTemplate is a template class which inherits
* QWaylandCompositorExtension and is convenience for building custom Wayland extensions with Qt.
*
* It provides the connection between Qt Wayland Compositor and the class generated by
* \c qtwaylandscanner, based on the XML description of the extension protocol.
*
* It provides two specific pieces of convenience:
* \list
* \li A reimplementation of \l{QWaylandCompositorExtension::extensionInterface()} which returns
* the \c wl_interface pointer for the qtwaylandscanner-generated base class.
* \li A static \l{findIn()} function which searches for an instance of the extension in a
* provided container, and returns this if it is found.
* \endlist
*
* Typically, a new extension will dual-inherit QWaylandCompositorExtensionTemplate and the class
* generated by \c qtwaylandscanner.
*
* QWaylandCompositorExtensionTemplate should be parameterized with \a T being the subclass itself:
* \code
* class MyExtension
* : public QWaylandCompositorExtensionTemplate<MyExtension>
* , QtWaylandServer::my_extension
* \endcode
*
* In this example, \c MyExtension is an implementation of the generated interface \c my_extension.
*
* \sa {Custom Shell}
*/
/*!
* \fn template <typename T> T *QWaylandCompositorExtensionTemplate<T>::findIn(QWaylandObject *container)
*
* If any instance of the interface has been registered with \a container, this is returned.
* Otherwise null is returned. The look-up is based on the generated \c interfaceName() which
* matches the interface name in the protocol description.
*/
/*!
* \class QWaylandCompositorExtension
* \inmodule QtWaylandCompositor
* \since 5.8
* \brief QWaylandCompositorExtension is the base class for compositor extensions.
*
* QWaylandCompositorExtension is the base class for implementing Wayland extensions on the
* compositor-side of the connection. If no other extension container is explicitly set, it will
* automatically add itself to its parent object, granted that this inherits from QWaylandObject.
*
* For example, for registering global extensions, you can inherit from QWaylandCompositorExtension
* and pass the QWaylandCompositor object as extension container.
*
* \sa QWaylandCompositorExtensionTemplate, {Custom Shell}
*/
/*!
* Creates a QWaylandCompositorExtension with no container.
*
* \sa setExtensionContainer()
*/
QWaylandCompositorExtension::QWaylandCompositorExtension()
: QWaylandObject(*new QWaylandCompositorExtensionPrivate())
{
}
/*!
* Creates a QWaylandCompositorExtension and adds it to the extension \a container. The \a container
* does not become the parent of the QWaylandCompositorExtension.
*
* The extension adds itself to \a container later, when \l{initialize()} is called. For this to
* happen automatically, an event loop must be running in the current thread.
*
* The QWaylandCompositorExtension will remove itself again when it is destroyed.
*/
QWaylandCompositorExtension::QWaylandCompositorExtension(QWaylandObject *container)
: QWaylandObject(*new QWaylandCompositorExtensionPrivate())
{
d_func()->extension_container = container;
QCoreApplication::postEvent(this, new QEvent(QEvent::Polish));
}
QWaylandCompositorExtension::QWaylandCompositorExtension(QWaylandCompositorExtensionPrivate &dd)
: QWaylandObject(dd)
{
}
QWaylandCompositorExtension::QWaylandCompositorExtension(QWaylandObject *container, QWaylandCompositorExtensionPrivate &dd)
: QWaylandObject(dd)
{
d_func()->extension_container = container;
QCoreApplication::postEvent(this, new QEvent(QEvent::Polish));
}
QWaylandCompositorExtension::~QWaylandCompositorExtension()
{
Q_D(QWaylandCompositorExtension);
if (d->extension_container)
d->extension_container->removeExtension(this);
}
/*!
* \fn const wl_interface *QWaylandCompositorExtension::extensionInterface() const
*
* A pure virtual function which should be reimplemented to return the \c wl_interface which
* corresponds to this QWaylandCompositorExtension.
*/
/*!
* \return the extension container for this QWaylandCompositorExtension or null if none has been
* set.
*/
QWaylandObject *QWaylandCompositorExtension::extensionContainer() const
{
Q_D(const QWaylandCompositorExtension);
return d->extension_container;
}
/*!
* Sets the extension container for this QWaylandCompositorExtension to \a container. This must be
* called before \l{initialize()} and cannot be changed once the QWaylandCompositorExtension has
* been initialized.
*/
void QWaylandCompositorExtension::setExtensionContainer(QWaylandObject *container)
{
Q_D(QWaylandCompositorExtension);
d->extension_container = container;
}
/*!
* Initializes the QWaylandCompositorExtension. The default implementation adopts the parent object
* as extension container if none has been set, and if the parent inherits from QWaylandObject. The
* default implementation also adds the QWaylandCompositorExtension to the list of extensions
* managed by the extension container.
*
* Override this function in subclasses to provide custom initialization code.
*/
void QWaylandCompositorExtension::initialize()
{
Q_D(QWaylandCompositorExtension);
if (d->initialized) {
qWarning() << "QWaylandCompositorExtension:" << extensionInterface()->name << "is already initialized";
return;
}
if (!d->extension_container && parent()) {
QWaylandObject *parentObj = qobject_cast<QWaylandObject*>(parent());
if (parentObj)
setExtensionContainer(parentObj);
}
if (!d->extension_container) {
qWarning() << "QWaylandCompositorExtension:" << extensionInterface()->name << "requests to initialize with no extension container set";
return;
}
d->extension_container->addExtension(this);
d->initialized = true;
}
bool QWaylandCompositorExtension::isInitialized() const
{
Q_D(const QWaylandCompositorExtension);
return d->initialized;
}
bool QWaylandCompositorExtension::event(QEvent *event)
{
switch(event->type()) {
case QEvent::Polish:
if (!isInitialized())
initialize();
break;
default:
break;
}
return QWaylandObject::event(event);
}
/*!
* \class QWaylandObject
* \inmodule QtWaylandCompositor
* \since 5.8
* \brief QWaylandObject is the base class for objects that can contain Wayland extensions.
*
* The QWaylandObject encapsulate extension container functionality. Any QWaylandObject object
* will automatically be an extension container and QWaylandCompositorExtension object which is
* a child of this will automatically add itself to its extension list, and remove itself when
* the extension object is destroyed.
*/
/*!
* Creates a QWaylandObject as a child of \a parent.
*/
QWaylandObject::QWaylandObject(QObject *parent)
:QObject(parent)
{
}
QWaylandObject::QWaylandObject(QObjectPrivate &d, QObject *parent)
:QObject(d, parent)
{
}
QWaylandObject::~QWaylandObject()
{
for (QWaylandCompositorExtension *extension : std::as_const(extension_vector))
QWaylandCompositorExtensionPrivate::get(extension)->extension_container = nullptr;
}
/*!
* Returns the compositor extension which matches \a name if one has been registered with the
* QWaylandObject. If no extension matching the name has been registered, this function returns
* null.
*/
QWaylandCompositorExtension *QWaylandObject::extension(const QByteArray &name)
{
for (int i = 0; i < extension_vector.size(); i++) {
if (extension_vector.at(i)->extensionInterface()->name == name)
return extension_vector.at(i);
}
return nullptr;
}
/*!
* Returns the compositor extension which matches \a interface if one has been registered with the
* QWaylandObject. If no extension matching the interface has been registered, this function
* returns null.
*/
QWaylandCompositorExtension *QWaylandObject::extension(const wl_interface *interface)
{
for (int i = 0; i < extension_vector.size(); i++) {
if (extension_vector.at(i)->extensionInterface() == interface)
return extension_vector.at(i);
}
return nullptr;
}
/*!
* Returns the list of compositor extensions that have been registered with this QWaylandObject.
*/
QList<QWaylandCompositorExtension *> QWaylandObject::extensions() const
{
return extension_vector;
}
/*!
* Registers \a extension with this QWaylandObject.
*/
void QWaylandObject::addExtension(QWaylandCompositorExtension *extension)
{
Q_ASSERT(!extension_vector.contains(extension));
extension_vector.append(extension);
}
/*!
* Removes \a extension from the list of registered extensions in this QWaylandObject, if it has
* previously been registered using \l{addExtension()}.
*/
void QWaylandObject::removeExtension(QWaylandCompositorExtension *extension)
{
if (!extension->isInitialized())
return;
Q_ASSERT(extension_vector.contains(extension));
extension_vector.removeOne(extension);
}
QT_END_NAMESPACE
#include "moc_qwaylandcompositorextension.cpp"