1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qwaylandcompositorextension.h"
5#include "qwaylandcompositorextension_p.h"
6
7#include <QtCore/QCoreApplication>
8#include <QtCore/QDebug>
9
10#include <wayland-server-core.h>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 * \class QWaylandCompositorExtensionTemplate
16 * \inmodule QtWaylandCompositor
17 * \since 5.8
18 * \brief QWaylandCompositorExtensionTemplate is a convenience class for subclassing
19 * QWaylandCompositorExtension.
20 *
21 * QWaylandCompositorExtensionTemplate is a template class which inherits
22 * QWaylandCompositorExtension and is convenience for building custom Wayland extensions with Qt.
23 *
24 * It provides the connection between Qt Wayland Compositor and the class generated by
25 * \c qtwaylandscanner, based on the XML description of the extension protocol.
26 *
27 * It provides two specific pieces of convenience:
28 * \list
29 * \li A reimplementation of \l{QWaylandCompositorExtension::extensionInterface()} which returns
30 * the \c wl_interface pointer for the qtwaylandscanner-generated base class.
31 * \li A static \l{findIn()} function which searches for an instance of the extension in a
32 * provided container, and returns this if it is found.
33 * \endlist
34 *
35 * Typically, a new extension will dual-inherit QWaylandCompositorExtensionTemplate and the class
36 * generated by \c qtwaylandscanner.
37 *
38 * QWaylandCompositorExtensionTemplate should be parameterized with the subclass itself:
39 * \code
40 * class MyExtension
41 * : public QWaylandCompositorExtensionTemplate<MyExtension>
42 * , QtWaylandServer::my_extension
43 * \endcode
44 *
45 * In this example, \c MyExtension is an implementation of the generated interface \c my_extension.
46 *
47 * \sa {Custom Shell}
48 */
49
50/*!
51 * \fn template <typename T> T *QWaylandCompositorExtensionTemplate<T>::findIn(QWaylandObject *container)
52 *
53 * If any instance of the interface has been registered with \a container, this is returned.
54 * Otherwise null is returned. The look-up is based on the generated \c interfaceName() which
55 * matches the interface name in the protocol description.
56 */
57
58/*!
59 * \class QWaylandCompositorExtension
60 * \inmodule QtWaylandCompositor
61 * \since 5.8
62 * \brief QWaylandCompositorExtension is the base class for compositor extensions.
63 *
64 * QWaylandCompositorExtension is the base class for implementing Wayland extensions on the
65 * compositor-side of the connection. If no other extension container is explicitly set, it will
66 * automatically add itself to its parent object, granted that this inherits from QWaylandObject.
67 *
68 * For example, for registering global extensions, you can inherit from QWaylandCompositorExtension
69 * and pass the QWaylandCompositor object as extension container.
70 *
71 * \sa QWaylandCompositorExtensionTemplate, {Custom Shell}
72 */
73
74/*!
75 * Creates a QWaylandCompositorExtension with no container.
76 *
77 * \sa setExtensionContainer()
78 */
79QWaylandCompositorExtension::QWaylandCompositorExtension()
80 : QWaylandObject(*new QWaylandCompositorExtensionPrivate())
81{
82}
83
84/*!
85 * Creates a QWaylandCompositorExtension and adds it to the extension \a container. The \a container
86 * does not become the parent of the QWaylandCompositorExtension.
87 *
88 * The extension adds itself to \a container later, when \l{initialize()} is called. For this to
89 * happen automatically, an event loop must be running in the current thread.
90 *
91 * The QWaylandCompositorExtension will remove itself again when it is destroyed.
92 */
93QWaylandCompositorExtension::QWaylandCompositorExtension(QWaylandObject *container)
94 : QWaylandObject(*new QWaylandCompositorExtensionPrivate())
95{
96 d_func()->extension_container = container;
97 QCoreApplication::postEvent(receiver: this, event: new QEvent(QEvent::Polish));
98}
99
100QWaylandCompositorExtension::QWaylandCompositorExtension(QWaylandCompositorExtensionPrivate &dd)
101 : QWaylandObject(dd)
102{
103}
104
105QWaylandCompositorExtension::QWaylandCompositorExtension(QWaylandObject *container, QWaylandCompositorExtensionPrivate &dd)
106 : QWaylandObject(dd)
107{
108 d_func()->extension_container = container;
109 QCoreApplication::postEvent(receiver: this, event: new QEvent(QEvent::Polish));
110}
111
112QWaylandCompositorExtension::~QWaylandCompositorExtension()
113{
114 Q_D(QWaylandCompositorExtension);
115 if (d->extension_container)
116 d->extension_container->removeExtension(extension: this);
117}
118
119/*!
120 * \fn const wl_interface *QWaylandCompositorExtension::extensionInterface() const
121 *
122 * A pure virtual function which should be reimplemented to return the \c wl_interface which
123 * corresponds to this QWaylandCompositorExtension.
124 */
125
126/*!
127 * \return the extension container for this QWaylandCompositorExtension or null if none has been
128 * set.
129 */
130QWaylandObject *QWaylandCompositorExtension::extensionContainer() const
131{
132 Q_D(const QWaylandCompositorExtension);
133 return d->extension_container;
134}
135
136/*!
137 * Sets the extension container for this QWaylandCompositorExtension to \a container. This must be
138 * called before \l{initialize()} and cannot be changed once the QWaylandCompositorExtension has
139 * been initialized.
140 */
141void QWaylandCompositorExtension::setExtensionContainer(QWaylandObject *container)
142{
143 Q_D(QWaylandCompositorExtension);
144 d->extension_container = container;
145}
146
147/*!
148 * Initializes the QWaylandCompositorExtension. The default implementation adopts the parent object
149 * as extension container if none has been set, and if the parent inherits from QWaylandObject. The
150 * default implementation also adds the QWaylandCompositorExtension to the list of extensions
151 * managed by the extension container.
152 *
153 * Override this function in subclasses to provide custom initialization code.
154 */
155void QWaylandCompositorExtension::initialize()
156{
157 Q_D(QWaylandCompositorExtension);
158 if (d->initialized) {
159 qWarning() << "QWaylandCompositorExtension:" << extensionInterface()->name << "is already initialized";
160 return;
161 }
162
163 if (!d->extension_container && parent()) {
164 QWaylandObject *parentObj = qobject_cast<QWaylandObject*>(object: parent());
165 if (parentObj)
166 setExtensionContainer(parentObj);
167 }
168
169 if (!d->extension_container) {
170 qWarning() << "QWaylandCompositorExtension:" << extensionInterface()->name << "requests to initialize with no extension container set";
171 return;
172 }
173
174 d->extension_container->addExtension(extension: this);
175 d->initialized = true;
176}
177
178bool QWaylandCompositorExtension::isInitialized() const
179{
180 Q_D(const QWaylandCompositorExtension);
181 return d->initialized;
182}
183
184bool QWaylandCompositorExtension::event(QEvent *event)
185{
186 switch(event->type()) {
187 case QEvent::Polish:
188 if (!isInitialized())
189 initialize();
190 break;
191 default:
192 break;
193 }
194 return QWaylandObject::event(event);
195}
196
197/*!
198 * \class QWaylandObject
199 * \inmodule QtWaylandCompositor
200 * \since 5.8
201 * \brief QWaylandObject is the base class for objects that can contain Wayland extensions.
202 *
203 * The QWaylandObject encapsulate extension container functionality. Any QWaylandObject object
204 * will automatically be an extension container and QWaylandCompositorExtension object which is
205 * a child of this will automatically add itself to its extension list, and remove itself when
206 * the extension object is destroyed.
207 */
208
209/*!
210 * Creates a QWaylandObject as a child of \a parent.
211 */
212QWaylandObject::QWaylandObject(QObject *parent)
213 :QObject(parent)
214{
215}
216
217QWaylandObject::QWaylandObject(QObjectPrivate &d, QObject *parent)
218 :QObject(d, parent)
219{
220}
221
222
223QWaylandObject::~QWaylandObject()
224{
225 for (QWaylandCompositorExtension *extension : std::as_const(t&: extension_vector))
226 QWaylandCompositorExtensionPrivate::get(extension)->extension_container = nullptr;
227}
228
229/*!
230 * Returns the compositor extension which matches \a name if one has been registered with the
231 * QWaylandObject. If no extension matching the name has been registered, this function returns
232 * null.
233 */
234QWaylandCompositorExtension *QWaylandObject::extension(const QByteArray &name)
235{
236 for (int i = 0; i < extension_vector.size(); i++) {
237 if (extension_vector.at(i)->extensionInterface()->name == name)
238 return extension_vector.at(i);
239 }
240 return nullptr;
241}
242
243/*!
244 * Returns the compositor extension which matches \a interface if one has been registered with the
245 * QWaylandObject. If no extension matching the interface has been registered, this function
246 * returns null.
247 */
248QWaylandCompositorExtension *QWaylandObject::extension(const wl_interface *interface)
249{
250 for (int i = 0; i < extension_vector.size(); i++) {
251 if (extension_vector.at(i)->extensionInterface() == interface)
252 return extension_vector.at(i);
253 }
254 return nullptr;
255}
256
257/*!
258 * Returns the list of compositor extensions that have been registered with this QWaylandObject.
259 */
260QList<QWaylandCompositorExtension *> QWaylandObject::extensions() const
261{
262 return extension_vector;
263}
264
265/*!
266 * Registers \a extension with this QWaylandObject.
267 */
268void QWaylandObject::addExtension(QWaylandCompositorExtension *extension)
269{
270 Q_ASSERT(!extension_vector.contains(extension));
271 extension_vector.append(t: extension);
272}
273
274/*!
275 * Removes \a extension from the list of registered extensions in this QWaylandObject, if it has
276 * previously been registered using \l{addExtension()}.
277 */
278void QWaylandObject::removeExtension(QWaylandCompositorExtension *extension)
279{
280 if (!extension->isInitialized())
281 return;
282 Q_ASSERT(extension_vector.contains(extension));
283 extension_vector.removeOne(t: extension);
284}
285
286QT_END_NAMESPACE
287
288#include "moc_qwaylandcompositorextension.cpp"
289

source code of qtwayland/src/compositor/global/qwaylandcompositorextension.cpp