Revision control

++ // 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"