Revision control

++ // Copyright (C) 2021 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:critical reason:network-protocol
++
++ #include "qwaylandqtshell.h"
++ #include "qwaylandqtshell_p.h"
++ #include "qwaylandqtshellchrome.h"
++
++ #include <QtWaylandCompositor/QWaylandCompositor>
++ #include <QtWaylandCompositor/QWaylandSurface>
++ #include "qwaylandqtshell.h"
++ #include <QtWaylandCompositor/QWaylandResource>
++
++ #if QT_CONFIG(wayland_compositor_quick)
++ # include "qwaylandqtshellintegration_p.h"
++ #endif
++
++ #include <QtWaylandCompositor/QWaylandResource>
++ #include <QDebug>
++ #include "compositor_api/qwaylandseat.h"
++
++ #include <QtWaylandCompositor/private/qwaylandutils_p.h>
++
++ QT_BEGIN_NAMESPACE
++
++ /*!
++ * \qmltype QtShell
++ * \nativetype QWaylandQtShell
++ * \inqmlmodule QtWayland.Compositor.QtShell
++ * \since 6.3
++ * \brief Provides a shell extension for Qt applications running on a Qt Wayland Compositor.
++ *
++ * The QtShell extension provides a way to associate an QtShellSurface with a regular Wayland
++ * surface. The QtShell extension is written to support the window management features which are
++ * supported by Qt. It may be suitable on a platform where both the compositor and client
++ * applications are written with Qt, and where applications are trusted not to abuse features such
++ * as manual window positioning and "bring-to-front".
++ *
++ * For other use cases, consider using IviApplication or XdgShell instead.
++ *
++ * \code
++ * import QtWayland.Compositor.QtShell
++ *
++ * WaylandCompositor {
++ * property ListModel shellSurfaces: ListModel {}
++ * QtShell {
++ * onQtShellSurfaceCreated: {
++ * shellSurfaces.append({shellSurface: qtShellSurface})
++ * }
++ * }
++ * }
++ * \endcode
++ */
++ QWaylandQtShell::QWaylandQtShell()
++ : QWaylandCompositorExtensionTemplate<QWaylandQtShell>(*new QWaylandQtShellPrivate())
++ {
++ }
++
++ QWaylandQtShell::QWaylandQtShell(QWaylandCompositor *compositor)
++ : QWaylandCompositorExtensionTemplate<QWaylandQtShell>(compositor, *new QWaylandQtShellPrivate())
++ {
++ }
++
++ bool QWaylandQtShell::moveChromeToFront(QWaylandQtShellChrome *chrome)
++ {
++ Q_D(QWaylandQtShell);
++ for (int i = 0; i < d->m_chromes.size(); ++i) {
++ if (d->m_chromes.at(i) == chrome) {
++ if (i > 0) {
++ QWaylandQtShellChrome *currentActive = d->m_chromes.first();
++ d->m_chromes.move(i, 0);
++ chrome->activate();
++ currentActive->deactivate();
++ }
++ return true;
++ }
++ }
++
++ return false;
++ }
++
++ void QWaylandQtShell::registerChrome(QWaylandQtShellChrome *chrome)
++ {
++ Q_D(QWaylandQtShell);
++ if (moveChromeToFront(chrome))
++ return;
++
++ QWaylandQtShellChrome *currentActive = d->m_chromes.isEmpty() ? nullptr : d->m_chromes.first();
++
++ d->m_chromes.prepend(chrome);
++ chrome->activate();
++
++ if (currentActive != nullptr)
++ currentActive->deactivate();
++
++ connect(chrome, &QWaylandQtShellChrome::activated, this, &QWaylandQtShell::chromeActivated);
++ connect(chrome, &QWaylandQtShellChrome::deactivated, this, &QWaylandQtShell::chromeDeactivated);
++ }
++
++ void QWaylandQtShell::unregisterChrome(QWaylandQtShellChrome *chrome)
++ {
++ Q_D(QWaylandQtShell);
++
++ chrome->disconnect(this);
++ int index = d->m_chromes.indexOf(chrome);
++ if (index >= 0) {
++ d->m_chromes.removeAt(index);
++ if (index == 0 && d->m_chromes.size() > 0)
++ d->m_chromes.at(0)->activate();
++ }
++ }
++
++ void QWaylandQtShell::chromeActivated()
++ {
++ QWaylandQtShellChrome *c = qobject_cast<QWaylandQtShellChrome *>(sender());
++ if (c != nullptr) {
++ moveChromeToFront(c);
++ }
++ }
++
++ void QWaylandQtShell::chromeDeactivated()
++ {
++ Q_D(QWaylandQtShell);
++ QWaylandQtShellChrome *c = qobject_cast<QWaylandQtShellChrome *>(sender());
++ if (d->m_chromes.size() > 1 && d->m_chromes.at(0) == c) {
++ d->m_chromes.move(0, 1);
++ d->m_chromes.at(0)->activate();
++ } else if (d->m_chromes.size() == 1) { // One window must be active
++ d->m_chromes.at(0)->activate();
++ }
++ }
++
++ void QWaylandQtShell::initialize()
++ {
++ Q_D(QWaylandQtShell);
++ QWaylandCompositorExtensionTemplate::initialize();
++
++ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
++ if (!compositor) {
++ qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandQtShell";
++ return;
++ }
++
++ d->init(compositor->display(), 1);
++ }
++
++ const struct wl_interface *QWaylandQtShell::interface()
++ {
++ return QWaylandQtShellPrivate::interface();
++ }
++
++ /*!
++ * \internal
++ */
++ QByteArray QWaylandQtShell::interfaceName()
++ {
++ return QWaylandQtShellPrivate::interfaceName();
++ }
++
++ /*!
++ * \qmlsignal void QtShell::qtShellSurfaceRequested(WaylandSurface surface, WaylandResource resource)
++ *
++ * This signal is emitted when the client has requested a QtShellSurface to be associated
++ * with \a surface. The handler for this signal is expected to create the QtShellSurface for
++ * \a resource and initialize it within the scope of the signal emission. If no QtShellSurface is
++ * created, a default one will be created instead.
++ */
++
++ /*!
++ * \qmlsignal void QtShell::qtShellSurfaceCreated(QtShellSurface *qtShellSurface)
++ *
++ * This signal is emitted when an QtShellSurface has been created. The supplied \a qtShellSurface is
++ * most commonly used to instantiate a ShellSurfaceItem.
++ */
++
++ QWaylandQtShellPrivate::QWaylandQtShellPrivate()
++ {
++ }
++
++ void QWaylandQtShellPrivate::unregisterQtShellSurface(QWaylandQtShellSurface *qtShellSurface)
++ {
++ Q_UNUSED(qtShellSurface)
++ }
++
++ void QWaylandQtShellPrivate::zqt_shell_v1_surface_create(QtWaylandServer::zqt_shell_v1::Resource *resource, wl_resource *surfaceResource, uint32_t id)
++ {
++ Q_Q(QWaylandQtShell);
++ QWaylandSurface *surface = QWaylandSurface::fromResource(surfaceResource);
++
++ if (!surface->setRole(QWaylandQtShellSurface::role(), resource->handle, ZQT_SHELL_V1_ERROR_ROLE))
++ return;
++
++ QWaylandResource qtShellSurfaceResource(wl_resource_create(resource->client(), &zqt_shell_surface_v1_interface,
++ wl_resource_get_version(resource->handle), id));
++
++ emit q->qtShellSurfaceRequested(surface, qtShellSurfaceResource);
++
++ QWaylandQtShellSurface *qtShellSurface = QWaylandQtShellSurface::fromResource(qtShellSurfaceResource.resource());
++
++ if (!qtShellSurface)
++ qtShellSurface = new QWaylandQtShellSurface(q, surface, qtShellSurfaceResource);
++
++ emit q->qtShellSurfaceCreated(qtShellSurface);
++ }
++
++ QWaylandSurfaceRole QWaylandQtShellSurfacePrivate::s_role("qt_shell_surface");
++
++ /*!
++ * \qmltype QtShellSurface
++ * \nativetype QWaylandQtShellSurface
++ * \inqmlmodule QtWayland.Compositor.QtShell
++ * \since 6.3
++ * \brief Provides a simple way to identify and resize a surface.
++ *
++ * This type is part of the \l{QtShell} extension and provides a way to extend
++ * the functionality of an existing WaylandSurface with window management functionality.
++ *
++ * The QtShellSurface type holds the core functionality needed to create a compositor that supports
++ * the QtShell extension. It can be used directly, or via the QtShellChrome type, depending on what
++ * the needs of the compositor are. The QtShellChrome type has default behaviors and convenience
++ * APIs for working with QtShellSurface objects.
++ */
++
++ /*!
++ \qmlsignal void QtShellSurface::startMove()
++
++ The client has requested an interactive move operation in the compositor by calling
++ \l{QWindow::startSystemMove()}.
++
++ \sa capabilities
++ */
++
++ /*!
++ \qmlsignal void QtShellSurface::startResize(enum edges)
++
++ The client has requested an interactive resize operation in the compositor by calling
++ \l{QWindow::startSystemResize()}.
++
++ The \a edges provides information about which edge of the window should be moved during the
++ resize. It is a mask of the following values:
++ \list
++ \li Qt.TopEdge
++ \li Qt.LeftEdge
++ \li Qt.RightEdge
++ \li Qt.BottomEdge
++ \endlist
++
++ \sa capabilities
++ */
++
++ QWaylandQtShellSurface::QWaylandQtShellSurface()
++ : QWaylandShellSurfaceTemplate<QWaylandQtShellSurface>(*new QWaylandQtShellSurfacePrivate())
++ {
++ }
++
++ QWaylandQtShellSurface::QWaylandQtShellSurface(QWaylandQtShell *application, QWaylandSurface *surface, const QWaylandResource &resource)
++ : QWaylandShellSurfaceTemplate<QWaylandQtShellSurface>(*new QWaylandQtShellSurfacePrivate())
++ {
++ initialize(application, surface, resource);
++ }
++
++ /*!
++ * \qmlmethod void QtShellSurface::initialize(QtShell qtShell, WaylandSurface surface, WaylandResource resource)
++ *
++ * Initializes the QtShellSurface, associating it with the given \a qtShell, \a surface, and
++ * \a resource.
++ */
++ void QWaylandQtShellSurface::initialize(QWaylandQtShell *qtShell, QWaylandSurface *surface, const QWaylandResource &resource)
++ {
++ Q_D(QWaylandQtShellSurface);
++
++ d->m_qtShell = qtShell;
++ d->m_surface = surface;
++
++ connect(d->m_surface, &QWaylandSurface::damaged, this, &QWaylandQtShellSurface::surfaceCommitted);
++
++ d->init(resource.resource());
++ setExtensionContainer(surface);
++
++ emit surfaceChanged();
++
++ QWaylandCompositorExtension::initialize();
++ }
++
++ /*!
++ * \qmlproperty WaylandSurface QtShellSurface::surface
++ *
++ * This property holds the surface associated with this QtShellSurface.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::surface
++ *
++ * This property holds the surface associated with this QWaylandQtShellSurface.
++ */
++ QWaylandSurface *QWaylandQtShellSurface::surface() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_surface;
++ }
++
++ QWaylandQtShell *QWaylandQtShellSurface::shell() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_qtShell;
++ }
++
++ /*!
++ * \qmlproperty point QtShellSurface::windowPosition
++ *
++ * This property holds the position of the shell surface relative to its output.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::windowPosition
++ *
++ * This property holds the position of the shell surface relative to its output.
++ */
++ QPoint QWaylandQtShellSurface::windowPosition() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_windowGeometry.topLeft();
++ }
++
++ void QWaylandQtShellSurface::setWindowPosition(const QPoint &position)
++ {
++ Q_D(QWaylandQtShellSurface);
++
++ // We don't care about the ack in this case, so use UINT_MAX as serial
++ d->send_set_position(UINT32_MAX, position.x(), position.y());
++ d->send_configure(UINT32_MAX);
++
++ d->m_windowGeometry.moveTopLeft(position);
++ d->m_positionSet = true;
++ emit positionAutomaticChanged();
++ emit windowGeometryChanged();
++ }
++
++ /*!
++ * \qmlproperty rect QtShellSurface::windowGeometry
++ *
++ * This property holds the window geometry of the shell surface.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::windowGeometry
++ *
++ * This property holds the window geometry of the shell surface.
++ */
++ QRect QWaylandQtShellSurface::windowGeometry() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_windowGeometry;
++ }
++
++ /*!
++ * \qmlproperty size QtShellSurface::minimumSize
++ *
++ * The minimum size of the window if the client has specified one. Otherwise an invalid size.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::minimumSize
++ *
++ * The minimum size of the window if the client has specified one. Otherwise an
++ * invalid size.
++ */
++ QSize QWaylandQtShellSurface::minimumSize() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_minimumSize;
++ }
++
++ /*!
++ * \qmlproperty size QtShellSurface::maximumSize
++ *
++ * The maximum size of the window if the client has specified one. Otherwise an invalid size.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::maximumSize
++ *
++ * The maximum size of the window if the client has specified one. Otherwise an
++ * invalid size.
++ */
++ QSize QWaylandQtShellSurface::maximumSize() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_maximumSize;
++ }
++
++ /*!
++ * \qmlmethod void QtShellSurface::requestWindowGeometry(int windowState, rect windowGeometry)
++ *
++ * Requests a new \a windowState and \a windowGeometry for the QtShellSurface. The state and
++ * geometry is updated when the client has acknowledged the request (at which point it is safe to
++ * assume that the surface's buffer has been resized if necessary).
++ */
++ void QWaylandQtShellSurface::requestWindowGeometry(uint windowState, const QRect &windowGeometry)
++ {
++ Q_D(QWaylandQtShellSurface);
++ if (!windowGeometry.isValid())
++ return;
++
++ d->configure(windowState, windowGeometry);
++ }
++
++ void QWaylandQtShellSurfacePrivate::configure(uint windowState, const QRect &newGeometry)
++ {
++ QWaylandCompositor *compositor = m_surface != nullptr ? m_surface->compositor() : nullptr;
++ if (!compositor) {
++ qWarning() << "Failed to find QWaylandCompositor when configuring QWaylandQtShell";
++ return;
++ }
++
++ uint32_t serial = compositor->nextSerial();
++ m_pendingConfigures[serial] = {windowState, newGeometry};
++
++ send_set_position(serial, newGeometry.x(), newGeometry.y());
++ send_resize(serial, newGeometry.width(), newGeometry.height());
++ send_set_window_state(serial, windowState & ~Qt::WindowActive);
++ send_configure(serial);
++ }
++
++ void QWaylandQtShellSurface::setFrameMargins(const QMargins &margins)
++ {
++ Q_D(QWaylandQtShellSurface);
++ if (d->m_frameMargins == margins)
++ return;
++
++ d->m_frameMargins = margins;
++ d->updateFrameMargins();
++
++ emit frameMarginChanged();
++ }
++
++ /*!
++ * \qmlproperty int QtShellSurface::frameMarginLeft
++ *
++ * This holds the window frame margin to the left of the surface.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::frameMarginLeft
++ *
++ * This property holds the window frame margin to the left of the surface.
++ */
++ void QWaylandQtShellSurface::setFrameMarginLeft(int left)
++ {
++ Q_D(QWaylandQtShellSurface);
++ if (d->m_frameMargins.left() == left)
++ return;
++
++ d->m_frameMargins.setLeft(left);
++ d->updateFrameMargins();
++
++ emit frameMarginChanged();
++ }
++
++ int QWaylandQtShellSurface::frameMarginLeft() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_frameMargins.left();
++ }
++
++ /*!
++ * \qmlproperty int QtShellSurface::frameMarginRight
++ *
++ * This holds the window frame margin to the right of the surface.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::frameMarginRight
++ *
++ * This property holds the window frame margin to the right of the surface.
++ */
++ void QWaylandQtShellSurface::setFrameMarginRight(int right)
++ {
++ Q_D(QWaylandQtShellSurface);
++ if (d->m_frameMargins.right() == right)
++ return;
++
++ d->m_frameMargins.setRight(right);
++ d->updateFrameMargins();
++
++ emit frameMarginChanged();
++ }
++
++ int QWaylandQtShellSurface::frameMarginRight() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_frameMargins.right();
++ }
++
++ /*!
++ * \qmlproperty int QtShellSurface::frameMarginTop
++ *
++ * This holds the window frame margin above the surface.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::frameMarginTop
++ *
++ * This property holds the window frame margin above the surface.
++ */
++ void QWaylandQtShellSurface::setFrameMarginTop(int top)
++ {
++ Q_D(QWaylandQtShellSurface);
++ if (d->m_frameMargins.top() == top)
++ return;
++ d->m_frameMargins.setTop(top);
++ d->updateFrameMargins();
++
++ emit frameMarginChanged();
++ }
++
++ int QWaylandQtShellSurface::frameMarginTop() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_frameMargins.top();
++ }
++
++ /*!
++ * \qmlproperty int QtShellSurface::frameMarginBottom
++ *
++ * This holds the window frame margin below the surface.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::frameMarginBottom
++ *
++ * This property holds the window frame margin below the surface.
++ */
++ void QWaylandQtShellSurface::setFrameMarginBottom(int bottom)
++ {
++ Q_D(QWaylandQtShellSurface);
++ if (d->m_frameMargins.bottom() == bottom)
++ return;
++ d->m_frameMargins.setBottom(bottom);
++ d->updateFrameMargins();
++
++ emit frameMarginChanged();
++ }
++
++ /*!
++ * \property QWaylandQtShellSurface::positionAutomatic
++ *
++ * This property holds whether the window position is automatically determined
++ * by the compositor.
++ *
++ * The value is \c true if the position has not been explicitly set; otherwise
++ * \c false.
++ */
++ bool QWaylandQtShellSurface::positionAutomatic() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return !d->m_positionSet;
++ }
++
++ int QWaylandQtShellSurface::frameMarginBottom() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_frameMargins.bottom();
++ }
++
++ /*!
++ * \qmlproperty int QtShellSurface::windowFlags
++ *
++ * This property holds the window flags of the QtShellSurface.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::windowFlags
++ *
++ * This property holds the window flags of the QWaylandQtShellSurface.
++ */
++ uint QWaylandQtShellSurface::windowFlags() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_windowFlags;
++ }
++
++ /*!
++ * \qmlmethod void QtShellSurface::sendClose()
++ *
++ * Requests that the client application closes itself.
++ */
++ void QWaylandQtShellSurface::sendClose()
++ {
++ Q_D(QWaylandQtShellSurface);
++ d->send_close();
++ }
++
++ /*!
++ * \qmlproperty string QtShellSurface::windowTitle
++ *
++ * This property holds the window title of the QtShellSurface.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::windowTitle
++ *
++ * This property holds the window title of the QWaylandQtShellSurface.
++ */
++ QString QWaylandQtShellSurface::windowTitle() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_windowTitle;
++ }
++
++ /*!
++ * \qmlproperty bool QtShellSurface::active
++ *
++ * This property holds whether the surface is currently considered active.
++ *
++ * \note There are no restrictions in QtShellSurface that prevents multiple surfaces from being
++ * active simultaneously. Such logic must either be implemented by the compositor itself, or by
++ * using the QtShellChrome type, which will automatically manage the activation state of surfaces.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::active
++ *
++ * This property holds whether the surface is currently considered active.
++ *
++ * \note There are no restrictions in QWaylandQtShellSurface that prevent
++ * multiple surfaces from being active simultaneously. Such logic must
++ * either be implemented by the compositor itself, or by using the
++ * QWaylandQtShellChrome type, which will automatically manage the
++ * activation state of surfaces.
++ */
++ void QWaylandQtShellSurface::setActive(bool active)
++ {
++ Q_D(QWaylandQtShellSurface);
++ if (d->m_active == active)
++ return;
++
++ d->m_active = active;
++ QWaylandCompositor *compositor = d->m_surface ? d->m_surface->compositor() : nullptr;
++ QWaylandSeat *seat = compositor ? compositor->defaultSeat() : nullptr;
++ if (seat && active)
++ seat->setKeyboardFocus(surface());
++ emit activeChanged();
++ }
++
++ bool QWaylandQtShellSurface::active() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_active;
++ }
++
++ /*!
++ * \qmlproperty enum QtShellSurface::capabilities
++ *
++ * This property holds the capabilities of the compositor. By default, no special capabilities are
++ * enabled.
++ *
++ * \list
++ * \li QtShellSurface.InteractiveMove The client can trigger a server-side interactive move
++ * operation using \l{QWindow::startSystemMove()}. The compositor will be notified of this
++ * through the \l{startMove()} signal.
++ * \li QtShellSurface.InteractiveResize The client can trigger a server-side interactive resize
++ * operation using \l{QWindow::startSystemResize()}. The compositor will be notified of this
++ * through the \l{startResize()} signal.
++ * \endlist
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::capabilities
++ *
++ * This property holds the capabilities of the compositor. By default, no
++ * special capabilities are enabled.
++ *
++ * \list
++ * \li QWaylandQtShellSurface::InteractiveMove The client can trigger a
++ * server-side interactive move operation using
++ * QWindow::startSystemMove(). The compositor will be notified of this
++ * through the startMove() signal.
++ * \li QWaylandQtShellSurface::InteractiveResize The client can trigger a
++ * server-side interactive resize operation using
++ * QWindow::startSystemResize(). The compositor will be notified of this
++ * through the startResize() signal.
++ * \endlist
++ */
++ void QWaylandQtShellSurface::setCapabilities(CapabilityFlags capabilities)
++ {
++ Q_D(QWaylandQtShellSurface);
++ if (d->m_capabilities == capabilities)
++ return;
++
++ d->m_capabilities = capabilities;
++ d->send_set_capabilities(capabilities);
++
++ emit capabilitiesChanged();
++ }
++
++ QWaylandQtShellSurface::CapabilityFlags QWaylandQtShellSurface::capabilities() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_capabilities;
++ }
++
++ /*!
++ * \qmlproperty int QtShellSurface::windowState
++ *
++ * This property holds the window state of the QtShellSurface.
++ *
++ * \note When \l{requestWindowGeometry()} is called to update state of the surface, the
++ * \c windowState property will not be updated until the client has acknowledged the state change.
++ */
++
++ /*!
++ * \property QWaylandQtShellSurface::windowState
++ *
++ * This property holds the window state of the QWaylandQtShellSurface.
++ *
++ * \note When requestWindowGeometry() is called to update state of the surface,
++ * the windowState property will not be updated until the client has
++ * acknowledged the state change.
++ */
++ uint QWaylandQtShellSurface::windowState() const
++ {
++ Q_D(const QWaylandQtShellSurface);
++ return d->m_windowState;
++ }
++
++ void QWaylandQtShellSurface::surfaceCommitted()
++ {
++ Q_D(QWaylandQtShellSurface);
++ if (d->m_lastAckedConfigure < UINT32_MAX) {
++ QRect targetRect = d->m_windowGeometry;
++ uint windowState = d->m_windowState;
++ for (auto it = d->m_pendingConfigures.begin(); it != d->m_pendingConfigures.end(); ) {
++ if (it.key() == d->m_lastAckedConfigure) {
++ targetRect = it.value().second;
++ windowState = it.value().first;
++ }
++
++ if (it.key() <= d->m_lastAckedConfigure)
++ it = d->m_pendingConfigures.erase(it);
++ else
++ break;
++ }
++
++ if (d->m_windowState != windowState) {
++ d->m_windowState = windowState;
++ emit windowStateChanged();
++ }
++
++ if (d->m_windowGeometry != targetRect) {
++ d->m_windowGeometry = targetRect;
++ d->m_positionSet = true;
++ emit positionAutomaticChanged();
++ emit windowGeometryChanged();
++ }
++
++ d->m_lastAckedConfigure = UINT32_MAX;
++ d->m_pendingPosition = QPoint{};
++ d->m_pendingPositionValid = false;
++ d->m_pendingSize = QSize{};
++ } else {
++ QRect oldRect = d->m_windowGeometry;
++ if (d->m_pendingPositionValid) {
++ d->m_windowGeometry.moveTopLeft(d->m_pendingPosition);
++ d->m_pendingPosition = QPoint{};
++ d->m_pendingPositionValid = false;
++ d->m_positionSet = true;
++ emit positionAutomaticChanged();
++ }
++
++ if (d->m_pendingSize.isValid()) {
++ d->m_windowGeometry.setSize(d->m_pendingSize);
++ d->m_pendingSize = QSize{};
++ }
++
++ if (d->m_windowGeometry != oldRect)
++ emit windowGeometryChanged();
++ }
++ }
++
++ /*!
++ * \internal
++ * Returns the Wayland interface for the QWaylandQtShellSurface.
++ */
++ const wl_interface *QWaylandQtShellSurface::interface()
++ {
++ return QWaylandQtShellSurfacePrivate::interface();
++ }
++
++ QByteArray QWaylandQtShellSurface::interfaceName()
++ {
++ return QWaylandQtShellSurfacePrivate::interfaceName();
++ }
++
++ /*!
++ * \internal
++ * Returns the surface role for the QWaylandQtShellSurface.
++ */
++ QWaylandSurfaceRole *QWaylandQtShellSurface::role()
++ {
++ return &QWaylandQtShellSurfacePrivate::s_role;
++ }
++
++ /*!
++ * \internal
++ * Returns the QWaylandQtShellSurface corresponding to the \a resource.
++ */
++ QWaylandQtShellSurface *QWaylandQtShellSurface::fromResource(wl_resource *resource)
++ {
++ if (auto p = QtWayland::fromResource<QWaylandQtShellSurfacePrivate *>(resource))
++ return p->q_func();
++ return nullptr;
++ }
++
++ #if QT_CONFIG(wayland_compositor_quick)
++ QWaylandQuickShellIntegration *QWaylandQtShellSurface::createIntegration(QWaylandQuickShellSurfaceItem *item)
++ {
++ return new QtWayland::QtShellIntegration(item);
++ }
++ #endif
++
++ /*!
++ * \internal
++ */
++ void QWaylandQtShellSurface::initialize()
++ {
++ QWaylandShellSurfaceTemplate::initialize();
++ }
++
++ QWaylandQtShellSurfacePrivate::QWaylandQtShellSurfacePrivate()
++ {
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_ack_configure(Resource *resource, uint32_t serial)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ if (serial < UINT32_MAX)
++ m_lastAckedConfigure = serial;
++
++ // Fake a surface commit because we won't get one as long as the window is unexposed
++ if (m_windowState & Qt::WindowMinimized)
++ q->surfaceCommitted();
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_reposition(Resource *resource, int32_t x, int32_t y)
++ {
++ Q_UNUSED(resource);
++
++ m_pendingPosition = QPoint(x, y);
++ m_pendingPositionValid = true;
++ m_lastAckedConfigure = UINT32_MAX;
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_size(Resource *resource, int32_t width, int32_t height)
++ {
++ Q_UNUSED(resource);
++
++ m_pendingSize = QSize(width, height);
++ m_lastAckedConfigure = UINT32_MAX;
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_minimum_size(Resource *resource, int32_t width, int32_t height)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ m_minimumSize = QSize{width, height};
++ emit q->minimumSizeChanged();
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_maximum_size(Resource *resource, int32_t width, int32_t height)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ m_maximumSize = QSize{width, height};
++ emit q->maximumSizeChanged();
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_destroy_resource(QtWaylandServer::zqt_shell_surface_v1::Resource *resource)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ QWaylandQtShellPrivate::get(m_qtShell)->unregisterQtShellSurface(q);
++ delete q;
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_destroy(QtWaylandServer::zqt_shell_surface_v1::Resource *resource)
++ {
++ wl_resource_destroy(resource->handle);
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_window_flags(Resource *resource, uint32_t flags)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ m_windowFlags = flags;
++ emit q->windowFlagsChanged();
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_change_window_state(Resource *resource, uint32_t state)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ uint oldWindowState = m_windowState;
++ m_windowState = state & ~Qt::WindowActive;
++
++ if (oldWindowState != m_windowState)
++ emit q->windowStateChanged();
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_start_system_resize(Resource *resource, uint32_t serial, uint32_t edge)
++ {
++ Q_UNUSED(resource);
++ Q_UNUSED(serial);
++ Q_Q(QWaylandQtShellSurface);
++ emit q->startResize(Qt::Edges(edge));
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_start_system_move(Resource *resource, uint32_t serial)
++ {
++ Q_UNUSED(resource);
++ Q_UNUSED(serial);
++ Q_Q(QWaylandQtShellSurface);
++ emit q->startMove();
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_window_title(Resource *resource,
++ const QString &title)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ m_windowTitle = title;
++ emit q->windowTitleChanged();
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_request_activate(Resource *resource)
++
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ q->setActive(true);
++
++ if (m_surface) {
++ auto view = m_surface->primaryView();
++ auto item = view ? qobject_cast<QWaylandQuickItem *>(view->renderObject()) : nullptr;
++ if (item)
++ item->forceActiveFocus();
++ }
++ }
++
++ void QWaylandQtShellSurfacePrivate::updateFrameMargins()
++ {
++ send_set_frame_margins(m_frameMargins.left(), m_frameMargins.right(),
++ m_frameMargins.top(), m_frameMargins.bottom());
++ }
++
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_raise(Resource *resource)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ emit q->raiseRequested();
++ }
++
++ void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_lower(Resource *resource)
++ {
++ Q_UNUSED(resource);
++ Q_Q(QWaylandQtShellSurface);
++ emit q->lowerRequested();
++ }
++
++ QT_END_NAMESPACE
++
++ #include "moc_qwaylandqtshell_p.cpp"