Revision control
++ // Copyright (C) 2017 The Qt Company Ltd.
++ // Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:critical reason:network-protocol
++
++ #include "qwaylandwlshell.h"
++ #include "qwaylandwlshell_p.h"
++
++ #if QT_CONFIG(wayland_compositor_quick)
++ #include "qwaylandwlshellintegration_p.h"
++ #endif
++ #include <QtWaylandCompositor/private/qwaylandutils_p.h>
++
++ #include <QtWaylandCompositor/QWaylandCompositor>
++ #include <QtWaylandCompositor/QWaylandView>
++ #include <QtWaylandCompositor/QWaylandOutput>
++ #include <QtWaylandCompositor/QWaylandClient>
++
++ #include <QtCore/QObject>
++ #include <QtCore/QDebug>
++
++ QT_BEGIN_NAMESPACE
++
++ QWaylandSurfaceRole QWaylandWlShellSurfacePrivate::s_role("wl_shell_surface");
++
++ QWaylandWlShellPrivate::QWaylandWlShellPrivate()
++ {
++ }
++
++ void QWaylandWlShellPrivate::shell_get_shell_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface_res)
++ {
++ Q_Q(QWaylandWlShell);
++ QWaylandSurface *surface = QWaylandSurface::fromResource(surface_res);
++
++ QWaylandResource shellSurfaceResource(wl_resource_create(resource->client(), &wl_shell_surface_interface,
++ wl_resource_get_version(resource->handle), id));
++
++ // XXX FIXME
++ // The role concept was formalized in wayland 1.7, so that release adds one error
++ // code for each interface that implements a role, and we are supposed to pass here
++ // the newly constructed resource and the correct error code so that if setting the
++ // role fails, a proper error can be sent to the client.
++ // However we're still using wayland 1.4, which doesn't have interface specific role
++ // errors, so the best we can do is to use wl_display's object_id error.
++ wl_resource *displayRes = wl_client_get_object(resource->client(), 1);
++ if (!surface->setRole(QWaylandWlShellSurface::role(), displayRes, WL_DISPLAY_ERROR_INVALID_OBJECT))
++ return;
++
++ emit q->wlShellSurfaceRequested(surface, shellSurfaceResource);
++
++ QWaylandWlShellSurface *shellSurface = QWaylandWlShellSurface::fromResource(shellSurfaceResource.resource());
++ if (!shellSurface) {
++ // A QWaylandWlShellSurface was not created in response to the wlShellSurfaceRequested
++ // signal, so we create one as fallback here instead.
++ shellSurface = new QWaylandWlShellSurface(q, surface, shellSurfaceResource);
++ }
++
++ m_shellSurfaces.append(shellSurface);
++ emit q->wlShellSurfaceCreated(shellSurface);
++ }
++
++ void QWaylandWlShellPrivate::unregisterShellSurface(QWaylandWlShellSurface *shellSurface)
++ {
++ if (!m_shellSurfaces.removeOne(shellSurface))
++ qWarning("Unexpected state. Can't find registered shell surface.");
++ }
++
++ QWaylandWlShellSurfacePrivate::QWaylandWlShellSurfacePrivate()
++ {
++ }
++
++ QWaylandWlShellSurfacePrivate::~QWaylandWlShellSurfacePrivate()
++ {
++ }
++
++ void QWaylandWlShellSurfacePrivate::ping(uint32_t serial)
++ {
++ m_pings.insert(serial);
++ send_ping(serial);
++ }
++
++ void QWaylandWlShellSurfacePrivate::setWindowType(Qt::WindowType windowType)
++ {
++ if (m_windowType == windowType)
++ return;
++ m_windowType = windowType;
++
++ Q_Q(QWaylandWlShellSurface);
++ emit q->windowTypeChanged();
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_destroy_resource(Resource *)
++ {
++ Q_Q(QWaylandWlShellSurface);
++
++ delete q;
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_move(Resource *resource,
++ struct wl_resource *input_device_super,
++ uint32_t serial)
++ {
++ Q_UNUSED(resource);
++ Q_UNUSED(serial);
++
++ Q_Q(QWaylandWlShellSurface);
++ QWaylandSeat *input_device = QWaylandSeat::fromSeatResource(input_device_super);
++ emit q->startMove(input_device);
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_resize(Resource *resource,
++ struct wl_resource *input_device_super,
++ uint32_t serial,
++ uint32_t edges)
++ {
++ Q_UNUSED(resource);
++ Q_UNUSED(serial);
++ Q_Q(QWaylandWlShellSurface);
++
++ QWaylandSeat *input_device = QWaylandSeat::fromSeatResource(input_device_super);
++ emit q->startResize(input_device, QWaylandWlShellSurface::ResizeEdge(edges));
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_set_toplevel(Resource *resource)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandWlShellSurface);
++ setWindowType(Qt::WindowType::Window);
++ emit q->setDefaultToplevel();
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_set_transient(Resource *resource,
++ struct wl_resource *parent_surface_resource,
++ int x,
++ int y,
++ uint32_t flags)
++ {
++
++ Q_UNUSED(resource);
++ Q_Q(QWaylandWlShellSurface);
++ QWaylandSurface *parent_surface = QWaylandSurface::fromResource(parent_surface_resource);
++ setWindowType(Qt::WindowType::SubWindow);
++ emit q->setTransient(parent_surface, QPoint(x,y), flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_set_fullscreen(Resource *resource,
++ uint32_t method,
++ uint32_t framerate,
++ struct wl_resource *output_resource)
++ {
++ Q_UNUSED(resource);
++ Q_UNUSED(method);
++ Q_UNUSED(framerate);
++ Q_Q(QWaylandWlShellSurface);
++ QWaylandOutput *output = output_resource
++ ? QWaylandOutput::fromResource(output_resource)
++ : nullptr;
++ setWindowType(Qt::WindowType::Window);
++ emit q->setFullScreen(QWaylandWlShellSurface::FullScreenMethod(method), framerate, output);
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_set_popup(Resource *resource, wl_resource *input_device, uint32_t serial, wl_resource *parent, int32_t x, int32_t y, uint32_t flags)
++ {
++ Q_UNUSED(resource);
++ Q_UNUSED(serial);
++ Q_UNUSED(flags);
++ Q_Q(QWaylandWlShellSurface);
++ QWaylandSeat *input = QWaylandSeat::fromSeatResource(input_device);
++ QWaylandSurface *parentSurface = QWaylandSurface::fromResource(parent);
++ setWindowType(Qt::WindowType::Popup);
++ emit q->setPopup(input, parentSurface, QPoint(x,y));
++
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_set_maximized(Resource *resource,
++ struct wl_resource *output_resource)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandWlShellSurface);
++ QWaylandOutput *output = output_resource
++ ? QWaylandOutput::fromResource(output_resource)
++ : nullptr;
++ setWindowType(Qt::WindowType::Window);
++ emit q->setMaximized(output);
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_pong(Resource *resource,
++ uint32_t serial)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandWlShellSurface);
++ if (m_pings.remove(serial))
++ emit q->pong();
++ else
++ qWarning("Received an unexpected pong!");
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_set_title(Resource *resource,
++ const QString &title)
++ {
++ Q_UNUSED(resource);
++ if (title == m_title)
++ return;
++ Q_Q(QWaylandWlShellSurface);
++ m_title = title;
++ emit q->titleChanged();
++ }
++
++ void QWaylandWlShellSurfacePrivate::shell_surface_set_class(Resource *resource,
++ const QString &className)
++ {
++ Q_UNUSED(resource);
++ if (className == m_className)
++ return;
++ Q_Q(QWaylandWlShellSurface);
++ m_className = className;
++ emit q->classNameChanged();
++ }
++
++ /*!
++ * \qmltype WlShell
++ * \nativetype QWaylandWlShell
++ * \inqmlmodule QtWayland.Compositor.WlShell
++ * \since 5.8
++ * \brief Provides an extension for desktop-style user interfaces.
++ *
++ * The WlShell extension provides a way to associate a ShellSurface
++ * with a regular Wayland surface. Using the shell surface interface, the client
++ * can request that the surface is resized, moved, and so on.
++ *
++ * WlShell corresponds to the Wayland interface \c wl_shell.
++ *
++ * To provide the functionality of the shell extension in a compositor, create
++ * an instance of the WlShell component and add it to the list of extensions
++ * supported by the compositor:
++ *
++ * \qml
++ * import QtWayland.Compositor.WlShell
++ *
++ * WaylandCompositor {
++ * WlShell {
++ * // ...
++ * }
++ * }
++ * \endqml
++ */
++
++ /*!
++ * \class QWaylandWlShell
++ * \inmodule QtWaylandCompositor
++ * \since 5.8
++ * \brief The QWaylandWlShell class is an extension for desktop-style user interfaces.
++ *
++ * The QWaylandWlShell extension provides a way to associate a QWaylandWlShellSurface with
++ * a regular Wayland surface. Using the shell surface interface, the client
++ * can request that the surface is resized, moved, and so on.
++ *
++ * WlShell corresponds to the Wayland interface \c wl_shell.
++ */
++
++ /*!
++ * Constructs a QWaylandWlShell object.
++ */
++ QWaylandWlShell::QWaylandWlShell()
++ : QWaylandShellTemplate<QWaylandWlShell>(*new QWaylandWlShellPrivate())
++ { }
++
++ /*!
++ * Constructs a QWaylandWlShell object for the provided \a compositor.
++ */
++ QWaylandWlShell::QWaylandWlShell(QWaylandCompositor *compositor)
++ : QWaylandShellTemplate<QWaylandWlShell>(compositor, *new QWaylandWlShellPrivate())
++ { }
++
++
++ /*!
++ * Initializes the WlShell extension.
++ */
++ void QWaylandWlShell::initialize()
++ {
++ Q_D(QWaylandWlShell);
++ QWaylandShellTemplate::initialize();
++ QWaylandCompositor *compositor = qobject_cast<QWaylandCompositor *>(extensionContainer());
++ if (!compositor) {
++ qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandWlShell";
++ return;
++ }
++ d->init(compositor->display(), 1);
++ }
++
++ QList<QWaylandWlShellSurface *> QWaylandWlShell::shellSurfaces() const
++ {
++ Q_D(const QWaylandWlShell);
++ return d->m_shellSurfaces;
++ }
++
++ QList<QWaylandWlShellSurface *> QWaylandWlShell::shellSurfacesForClient(QWaylandClient *client) const
++ {
++ Q_D(const QWaylandWlShell);
++ QList<QWaylandWlShellSurface *> surfsForClient;
++ for (QWaylandWlShellSurface *shellSurface : d->m_shellSurfaces) {
++ if (shellSurface->surface() && shellSurface->surface()->client() == client)
++ surfsForClient.append(shellSurface);
++ }
++ return surfsForClient;
++ }
++
++ QList<QWaylandWlShellSurface *> QWaylandWlShell::mappedPopups() const
++ {
++ Q_D(const QWaylandWlShell);
++ QList<QWaylandWlShellSurface *> popupSurfaces;
++ for (QWaylandWlShellSurface *shellSurface : d->m_shellSurfaces) {
++ if (shellSurface->windowType() == Qt::WindowType::Popup
++ && shellSurface->surface() && shellSurface->surface()->hasContent()) {
++ popupSurfaces.append(shellSurface);
++ }
++ }
++ return popupSurfaces;
++ }
++
++ QWaylandClient *QWaylandWlShell::popupClient() const
++ {
++ Q_D(const QWaylandWlShell);
++ for (QWaylandWlShellSurface *shellSurface : d->m_shellSurfaces) {
++ if (shellSurface->windowType() == Qt::WindowType::Popup
++ && shellSurface->surface() && shellSurface->surface()->hasContent()) {
++ return shellSurface->surface()->client();
++ }
++ }
++ return nullptr;
++ }
++
++ void QWaylandWlShell::closeAllPopups()
++ {
++ const auto mapped = mappedPopups();
++ for (QWaylandWlShellSurface *shellSurface : mapped)
++ shellSurface->sendPopupDone();
++ }
++
++ /*!
++ * Returns the Wayland interface for the QWaylandWlShell.
++ */
++ const struct wl_interface *QWaylandWlShell::interface()
++ {
++ return QWaylandWlShellPrivate::interface();
++ }
++
++ /*!
++ * \qmlsignal void WlShell::wlShellSurfaceRequested(WaylandSurface surface, WaylandResource resource)
++ *
++ * This signal is emitted when the client has requested a \c wl_shell_surface to be associated with
++ * \a surface. The handler for this signal may create a shell surface for \a resource and initialize
++ * it within the scope of the signal emission. Otherwise a WlShellSurface will be created
++ * automatically.
++ */
++
++ /*!
++ * \fn void QWaylandWlShell::wlShellSurfaceRequested(QWaylandSurface *surface, const QWaylandResource &resource)
++ *
++ * This signal is emitted when the client has requested a \c wl_shell_surface to be associated with
++ * \a surface. The handler for this signal may create a shell surface for \a resource and initialize
++ * it within the scope of the signal emission. Otherwise a QWaylandWlShellSurface will be created
++ * automatically.
++ */
++
++ /*!
++ * \qmlsignal void WlShell::wlShellSurfaceCreated(WlShellSurface shellSurface)
++ *
++ * This signal is emitted when the client has created a \c wl_shell_surface.
++ * A common use case is to let the handler of this signal instantiate a ShellSurfaceItem or
++ * WaylandQuickItem for displaying \a shellSurface in a QtQuick scene.
++ */
++
++ /*!
++ * \fn void QWaylandWlShell::wlShellSurfaceCreated(QWaylandWlShellSurface *shellSurface)
++ *
++ * This signal is emitted when the client has created a \c wl_shell_surface.
++ * A common use case is to let the handler of this signal instantiate a QWaylandShellSurfaceItem or
++ * QWaylandQuickItem for displaying \a shellSurface in a QtQuick scene.
++ */
++
++ /*!
++ * \internal
++ */
++ QByteArray QWaylandWlShell::interfaceName()
++ {
++ return QWaylandWlShellPrivate::interfaceName();
++ }
++
++ /*!
++ * \qmltype WlShellSurface
++ * \nativetype QWaylandWlShellSurface
++ * \inqmlmodule QtWayland.Compositor.WlShell
++ * \since 5.8
++ * \brief Provides a \c wl_shell_surface that offers desktop-style compositor-specific features to a surface.
++ *
++ * This type is part of the \l{WlShell} extension and provides a way to extend
++ * the functionality of an existing WaylandSurface with features specific to desktop-style
++ * compositors, such as resizing and moving the surface.
++ *
++ * It corresponds to the Wayland interface \c wl_shell_surface.
++ */
++
++ /*!
++ * \class QWaylandWlShellSurface
++ * \inmodule QtWaylandCompositor
++ * \since 5.8
++ * \brief The QWaylandWlShellSurface class provides desktop-style compositor-specific features to a surface.
++ *
++ * This class is part of the QWaylandWlShell extension and provides a way to extend
++ * the functionality of an existing QWaylandSurface with features specific to desktop-style
++ * compositors, such as resizing and moving the surface.
++ *
++ * It corresponds to the Wayland interface \c wl_shell_surface.
++ */
++
++ /*!
++ * Constructs a QWaylandWlShellSurface.
++ */
++ QWaylandWlShellSurface::QWaylandWlShellSurface()
++ : QWaylandShellSurfaceTemplate<QWaylandWlShellSurface>(*new QWaylandWlShellSurfacePrivate)
++ {
++ }
++
++ /*!
++ * Constructs a QWaylandWlShellSurface for \a surface and initializes it with the given \a shell and resource \a res.
++ */
++ QWaylandWlShellSurface::QWaylandWlShellSurface(QWaylandWlShell *shell, QWaylandSurface *surface, const QWaylandResource &res)
++ : QWaylandShellSurfaceTemplate<QWaylandWlShellSurface>(*new QWaylandWlShellSurfacePrivate)
++ {
++ initialize(shell, surface, res);
++ }
++
++ QWaylandWlShellSurface::~QWaylandWlShellSurface()
++ {
++ Q_D(QWaylandWlShellSurface);
++ if (d->m_shell)
++ QWaylandWlShellPrivate::get(d->m_shell)->unregisterShellSurface(this);
++ }
++
++ /*!
++ * \qmlmethod void WlShellSurface::initialize(WlShell shell, WaylandSurface surface, WaylandResource resource)
++ *
++ * Initializes the WlShellSurface and associates it with the given \a shell, \a surface, and \a resource.
++ */
++
++ /*!
++ * Initializes the QWaylandWlShellSurface and associates it with the given \a shell, \a surface, and \a resource.
++ */
++ void QWaylandWlShellSurface::initialize(QWaylandWlShell *shell, QWaylandSurface *surface, const QWaylandResource &resource)
++ {
++ Q_D(QWaylandWlShellSurface);
++ d->m_shell = shell;
++ d->m_surface = surface;
++ d->init(resource.resource());
++ setExtensionContainer(surface);
++ emit surfaceChanged();
++ emit shellChanged();
++ QWaylandCompositorExtension::initialize();
++ }
++
++ /*!
++ * \internal
++ */
++ void QWaylandWlShellSurface::initialize()
++ {
++ QWaylandCompositorExtension::initialize();
++ }
++
++ const struct wl_interface *QWaylandWlShellSurface::interface()
++ {
++ return QWaylandWlShellSurfacePrivate::interface();
++ }
++
++ /*!
++ * \internal
++ */
++ QByteArray QWaylandWlShellSurface::interfaceName()
++ {
++ return QWaylandWlShellSurfacePrivate::interfaceName();
++ }
++
++ QSize QWaylandWlShellSurface::sizeForResize(const QSizeF &size, const QPointF &delta, QWaylandWlShellSurface::ResizeEdge edge)
++ {
++ qreal width = size.width();
++ qreal height = size.height();
++ if (edge & LeftEdge)
++ width -= delta.x();
++ else if (edge & RightEdge)
++ width += delta.x();
++
++ if (edge & TopEdge)
++ height -= delta.y();
++ else if (edge & BottomEdge)
++ height += delta.y();
++
++ QSizeF newSize(qMax(width, 1.0), qMax(height, 1.0));
++ return newSize.toSize();
++ }
++
++ /*!
++ * \enum QWaylandWlShellSurface::ResizeEdge
++ *
++ * This enum type provides a way to specify an edge or corner of
++ * the surface.
++ *
++ * \value NoneEdge No edge.
++ * \value TopEdge The top edge.
++ * \value BottomEdge The bottom edge.
++ * \value LeftEdge The left edge.
++ * \value TopLeftEdge The top left corner.
++ * \value BottomLeftEdge The bottom left corner.
++ * \value RightEdge The right edge.
++ * \value TopRightEdge The top right corner.
++ * \value BottomRightEdge The bottom right corner.
++ */
++
++ /*!
++ * \qmlmethod void WlShellSurface::sendConfigure(size s, enum edges)
++ *
++ * Sends a configure event to the client, suggesting that it resize its surface to
++ * the provided size \a s. The \a edges provide a hint about how the surface
++ * was resized.
++ */
++
++ /*!
++ * Sends a configure event to the client, suggesting that it resize its surface to
++ * the provided \a size. The \a edges provide a hint about how the surface
++ * was resized.
++ */
++ void QWaylandWlShellSurface::sendConfigure(const QSize &size, ResizeEdge edges)
++ {
++ Q_D(QWaylandWlShellSurface);
++ if (!size.isValid()) {
++ qWarning() << "Can't configure wl_shell_surface with an invalid size" << size;
++ return;
++ }
++ d->send_configure(edges, size.width(), size.height());
++ }
++
++ /*!
++ * \qmlmethod void WlShellSurface::sendPopupDone()
++ *
++ * Sends a popup_done event to the client to indicate that the user has clicked
++ * somewhere outside the client's surfaces.
++ */
++
++ /*!
++ * Sends a popup_done event to the client to indicate that the user has clicked
++ * somewhere outside the client's surfaces.
++ */
++ void QWaylandWlShellSurface::sendPopupDone()
++ {
++ Q_D(QWaylandWlShellSurface);
++ d->send_popup_done();
++ }
++
++ #if QT_CONFIG(wayland_compositor_quick)
++ QWaylandQuickShellIntegration *QWaylandWlShellSurface::createIntegration(QWaylandQuickShellSurfaceItem *item)
++ {
++ return new QtWayland::WlShellIntegration(item);
++ }
++ #endif
++
++ /*!
++ * \qmlproperty WaylandSurface WlShellSurface::surface
++ *
++ * This property holds the \c wl_surface associated with this WlShellSurface.
++ */
++
++ /*!
++ * \property QWaylandWlShellSurface::surface
++ *
++ * This property holds the surface associated with this QWaylandWlShellSurface.
++ */
++ QWaylandSurface *QWaylandWlShellSurface::surface() const
++ {
++ Q_D(const QWaylandWlShellSurface);
++ return d->m_surface;
++ }
++
++ /*!
++ * \qmlproperty WlShell WlShellSurface::shell
++ *
++ * This property holds the shell associated with this WlShellSurface.
++ */
++
++ /*!
++ * \property QWaylandWlShellSurface::shell
++ *
++ * This property holds the shell associated with this QWaylandWlShellSurface.
++ */
++ QWaylandWlShell *QWaylandWlShellSurface::shell() const
++ {
++ Q_D(const QWaylandWlShellSurface);
++ return d->m_shell;
++ }
++
++ /*!
++ * \qmlproperty enum WlShellSurface::windowType
++ *
++ * This property holds the window type of the WlShellSurface.
++ */
++
++ Qt::WindowType QWaylandWlShellSurface::windowType() const
++ {
++ Q_D(const QWaylandWlShellSurface);
++ return d->m_windowType;
++ }
++
++ /*!
++ * \qmlproperty string WlShellSurface::title
++ *
++ * This property holds the title of the WlShellSurface.
++ */
++
++ /*!
++ * \property QWaylandWlShellSurface::title
++ *
++ * This property holds the title of the QWaylandWlShellSurface.
++ */
++ QString QWaylandWlShellSurface::title() const
++ {
++ Q_D(const QWaylandWlShellSurface);
++ return d->m_title;
++ }
++
++ /*!
++ * \qmlproperty string WlShellSurface::className
++ *
++ * This property holds the class name of the WlShellSurface.
++ */
++
++ /*!
++ * \property QWaylandWlShellSurface::className
++ *
++ * This property holds the class name of the QWaylandWlShellSurface.
++ */
++ QString QWaylandWlShellSurface::className() const
++ {
++ Q_D(const QWaylandWlShellSurface);
++ return d->m_className;
++ }
++
++ QWaylandSurfaceRole *QWaylandWlShellSurface::role()
++ {
++ return &QWaylandWlShellSurfacePrivate::s_role;
++ }
++
++ /*!
++ * \qmlmethod void WlShellSurface::ping()
++ *
++ * Sends a ping event to the client. If the client replies to the event the pong
++ * signal will be emitted.
++ */
++
++ /*!
++ * Sends a ping event to the client. If the client replies to the event the pong
++ * signal will be emitted.
++ */
++ void QWaylandWlShellSurface::ping()
++ {
++ Q_D(QWaylandWlShellSurface);
++ uint32_t serial = d->m_surface->compositor()->nextSerial();
++ d->ping(serial);
++ }
++
++ /*!
++ * Returns the QWaylandWlShellSurface object associated with the given \a resource, or null if no such object exists.
++ */
++ QWaylandWlShellSurface *QWaylandWlShellSurface::fromResource(wl_resource *resource)
++ {
++ if (auto p = QtWayland::fromResource<QWaylandWlShellSurfacePrivate *>(resource))
++ return p->q_func();
++ return nullptr;
++ }
++
++ QT_END_NAMESPACE
++
++ #include "moc_qwaylandwlshell.cpp"