summaryrefslogtreecommitdiffstats
path: root/src/compositor/extensions/qwaylandxdgshellv5.cpp
diff options
context:
space:
mode:
authorGiulio Camuffo <giulio.camuffo@kdab.com>2016-08-29 15:15:29 +0200
committerGiulio Camuffo <giulio.camuffo@kdab.com>2016-09-05 11:30:27 +0000
commitda61739728b2df7981b898da5dbdd4b74be068fc (patch)
tree7fc5100c02b883a9f58983bc01b2bf010f1f776d /src/compositor/extensions/qwaylandxdgshellv5.cpp
parent7eccad7db057ed841e3670d14274213dcf8416e5 (diff)
Rename the QWaylandXdg* classes to QWaylandXdg*V5
This frees the QWaylandXdg name for the hopefully coming stable version of xdg-shell. Change-Id: I9beb9b035c6497fb45bee5c9104485b564ca0619 Reviewed-by: Johan Helsing <johan.helsing@qt.io>
Diffstat (limited to 'src/compositor/extensions/qwaylandxdgshellv5.cpp')
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv5.cpp1190
1 files changed, 1190 insertions, 0 deletions
diff --git a/src/compositor/extensions/qwaylandxdgshellv5.cpp b/src/compositor/extensions/qwaylandxdgshellv5.cpp
new file mode 100644
index 000000000..284aa8b05
--- /dev/null
+++ b/src/compositor/extensions/qwaylandxdgshellv5.cpp
@@ -0,0 +1,1190 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandxdgshellv5.h"
+#include "qwaylandxdgshellv5_p.h"
+
+#ifdef QT_WAYLAND_COMPOSITOR_QUICK
+#include "qwaylandxdgshellv5integration_p.h"
+#endif
+
+#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/QWaylandSurface>
+#include <QtWaylandCompositor/QWaylandSurfaceRole>
+#include <QtWaylandCompositor/QWaylandResource>
+#include <QtWaylandCompositor/QWaylandSeat>
+
+#include <QtCore/QObject>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+QWaylandSurfaceRole QWaylandXdgSurfaceV5Private::s_role("xdg_surface");
+QWaylandSurfaceRole QWaylandXdgPopupV5Private::s_role("xdg_popup");
+
+QWaylandXdgShellV5Private::QWaylandXdgShellV5Private()
+ : QWaylandCompositorExtensionPrivate()
+ , xdg_shell()
+{
+}
+
+void QWaylandXdgShellV5Private::ping(Resource *resource, uint32_t serial)
+{
+ m_pings.insert(serial);
+ send_ping(resource->handle, serial);
+}
+
+void QWaylandXdgShellV5Private::registerSurface(QWaylandXdgSurfaceV5 *xdgSurface)
+{
+ m_xdgSurfaces.insert(xdgSurface->surface()->client()->client(), xdgSurface);
+}
+
+void QWaylandXdgShellV5Private::unregisterXdgSurface(QWaylandXdgSurfaceV5 *xdgSurface)
+{
+ auto xdgSurfacePrivate = QWaylandXdgSurfaceV5Private::get(xdgSurface);
+ if (!m_xdgSurfaces.remove(xdgSurfacePrivate->resource()->client(), xdgSurface))
+ qWarning("%s Unexpected state. Can't find registered xdg surface\n", Q_FUNC_INFO);
+}
+
+void QWaylandXdgShellV5Private::registerXdgPopup(QWaylandXdgPopupV5 *xdgPopup)
+{
+ m_xdgPopups.insert(xdgPopup->surface()->client()->client(), xdgPopup);
+}
+
+void QWaylandXdgShellV5Private::unregisterXdgPopup(QWaylandXdgPopupV5 *xdgPopup)
+{
+ auto xdgPopupPrivate = QWaylandXdgPopupV5Private::get(xdgPopup);
+ if (!m_xdgPopups.remove(xdgPopupPrivate->resource()->client(), xdgPopup))
+ qWarning("%s Unexpected state. Can't find registered xdg popup\n", Q_FUNC_INFO);
+}
+
+bool QWaylandXdgShellV5Private::isValidPopupParent(QWaylandSurface *parentSurface) const
+{
+ QWaylandXdgPopupV5 *topmostPopup = topmostPopupForClient(parentSurface->client()->client());
+ if (topmostPopup && topmostPopup->surface() != parentSurface) {
+ return false;
+ }
+
+ QWaylandSurfaceRole *parentRole = parentSurface->role();
+ if (parentRole != QWaylandXdgSurfaceV5::role() && parentRole != QWaylandXdgPopupV5::role()) {
+ return false;
+ }
+
+ return true;
+}
+
+QWaylandXdgPopupV5 *QWaylandXdgShellV5Private::topmostPopupForClient(wl_client *client) const
+{
+ QList<QWaylandXdgPopupV5 *> clientPopups = m_xdgPopups.values(client);
+ return clientPopups.empty() ? nullptr : clientPopups.last();
+}
+
+QWaylandXdgSurfaceV5 *QWaylandXdgShellV5Private::xdgSurfaceFromSurface(QWaylandSurface *surface)
+{
+ Q_FOREACH (QWaylandXdgSurfaceV5 *xdgSurface, m_xdgSurfaces) {
+ if (surface == xdgSurface->surface())
+ return xdgSurface;
+ }
+ return nullptr;
+}
+
+void QWaylandXdgShellV5Private::xdg_shell_destroy(Resource *resource)
+{
+ if (!m_xdgSurfaces.values(resource->client()).empty())
+ wl_resource_post_error(resource->handle, XDG_SHELL_ERROR_DEFUNCT_SURFACES,
+ "xdg_shell was destroyed before children");
+
+ wl_resource_destroy(resource->handle);
+}
+
+void QWaylandXdgShellV5Private::xdg_shell_get_xdg_surface(Resource *resource, uint32_t id,
+ wl_resource *surface_res)
+{
+ Q_Q(QWaylandXdgShellV5);
+ QWaylandSurface *surface = QWaylandSurface::fromResource(surface_res);
+
+ if (xdgSurfaceFromSurface(surface)) {
+ wl_resource_post_error(resource->handle, XDG_SHELL_ERROR_ROLE,
+ "An active xdg_surface already exists for wl_surface@%d",
+ wl_resource_get_id(surface->resource()));
+ return;
+ }
+
+ if (!surface->setRole(QWaylandXdgSurfaceV5::role(), resource->handle, XDG_SHELL_ERROR_ROLE))
+ return;
+
+ QWaylandResource xdgSurfaceResource(wl_resource_create(resource->client(), &xdg_surface_interface,
+ wl_resource_get_version(resource->handle), id));
+
+ emit q->xdgSurfaceRequested(surface, xdgSurfaceResource);
+
+ QWaylandXdgSurfaceV5 *xdgSurface = QWaylandXdgSurfaceV5::fromResource(xdgSurfaceResource.resource());
+ if (!xdgSurface) {
+ // A QWaylandXdgSurfaceV5 was not created in response to the xdgSurfaceRequested signal, so we
+ // create one as fallback here instead.
+ xdgSurface = new QWaylandXdgSurfaceV5(q, surface, xdgSurfaceResource);
+ }
+
+ registerSurface(xdgSurface);
+ emit q->xdgSurfaceCreated(xdgSurface);
+}
+
+void QWaylandXdgShellV5Private::xdg_shell_use_unstable_version(Resource *resource, int32_t version)
+{
+ if (xdg_shell::version_current != version) {
+ wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "incompatible version, server is %d, but client wants %d",
+ xdg_shell::version_current, version);
+ }
+}
+
+void QWaylandXdgShellV5Private::xdg_shell_get_xdg_popup(Resource *resource, uint32_t id,
+ wl_resource *surface_res, wl_resource *parent,
+ wl_resource *seatResource, uint32_t serial,
+ int32_t x, int32_t y)
+{
+ Q_UNUSED(serial);
+ Q_Q(QWaylandXdgShellV5);
+ QWaylandSurface *surface = QWaylandSurface::fromResource(surface_res);
+ QWaylandSurface *parentSurface = QWaylandSurface::fromResource(parent);
+
+ if (!isValidPopupParent(parentSurface)) {
+ wl_resource_post_error(resource->handle, XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
+ "the client specified an invalid popup parent surface");
+ return;
+ }
+
+ if (!surface->setRole(QWaylandXdgPopupV5::role(), resource->handle, XDG_SHELL_ERROR_ROLE)) {
+ return;
+ }
+
+ QWaylandResource xdgPopupResource (wl_resource_create(resource->client(), &xdg_popup_interface,
+ wl_resource_get_version(resource->handle), id));
+ QWaylandSeat *seat = QWaylandSeat::fromSeatResource(seatResource);
+ QPoint position(x, y);
+ emit q->xdgPopupRequested(surface, parentSurface, seat, position, xdgPopupResource);
+
+ QWaylandXdgPopupV5 *xdgPopup = QWaylandXdgPopupV5::fromResource(xdgPopupResource.resource());
+ if (!xdgPopup) {
+ // A QWaylandXdgPopupV5 was not created in response to the xdgPopupRequested signal, so we
+ // create one as fallback here instead.
+ xdgPopup = new QWaylandXdgPopupV5(q, surface, parentSurface, position, xdgPopupResource);
+ }
+
+ registerXdgPopup(xdgPopup);
+ emit q->xdgPopupCreated(xdgPopup);
+}
+
+void QWaylandXdgShellV5Private::xdg_shell_pong(Resource *resource, uint32_t serial)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgShellV5);
+ if (m_pings.remove(serial))
+ emit q->pong(serial);
+ else
+ qWarning("Received an unexpected pong!");
+}
+
+QWaylandXdgSurfaceV5Private::QWaylandXdgSurfaceV5Private()
+ : QWaylandCompositorExtensionPrivate()
+ , xdg_surface()
+ , m_surface(nullptr)
+ , m_parentSurface(nullptr)
+ , m_windowType(UnknownWindowType)
+ , m_unsetWindowGeometry(true)
+ , m_lastAckedConfigure({{}, QSize(0, 0), 0})
+{
+}
+
+void QWaylandXdgSurfaceV5Private::handleFocusLost()
+{
+ Q_Q(QWaylandXdgSurfaceV5);
+ QWaylandXdgSurfaceV5Private::ConfigureEvent current = lastSentConfigure();
+ current.states.removeOne(QWaylandXdgSurfaceV5::State::ActivatedState);
+ q->sendConfigure(current.size, current.states);
+}
+
+void QWaylandXdgSurfaceV5Private::handleFocusReceived()
+{
+ Q_Q(QWaylandXdgSurfaceV5);
+
+ QWaylandXdgSurfaceV5Private::ConfigureEvent current = lastSentConfigure();
+ if (!current.states.contains(QWaylandXdgSurfaceV5::State::ActivatedState)) {
+ current.states.push_back(QWaylandXdgSurfaceV5::State::ActivatedState);
+ }
+
+ q->sendConfigure(current.size, current.states);
+}
+
+QRect QWaylandXdgSurfaceV5Private::calculateFallbackWindowGeometry() const
+{
+ // TODO: The unset window geometry should include subsurfaces as well, so this solution
+ // won't work too well on those kinds of clients.
+ return QRect(QPoint(0, 0), m_surface->size() / m_surface->bufferScale());
+}
+
+void QWaylandXdgSurfaceV5Private::updateFallbackWindowGeometry()
+{
+ Q_Q(QWaylandXdgSurfaceV5);
+ if (!m_unsetWindowGeometry)
+ return;
+
+ const QRect unsetGeometry = calculateFallbackWindowGeometry();
+ if (unsetGeometry == m_windowGeometry)
+ return;
+
+ m_windowGeometry = unsetGeometry;
+ emit q->windowGeometryChanged();
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurfaceV5);
+ QWaylandXdgShellV5Private::get(m_xdgShell)->unregisterXdgSurface(q);
+ delete q;
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_move(Resource *resource, wl_resource *seat, uint32_t serial)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(serial);
+
+ Q_Q(QWaylandXdgSurfaceV5);
+ QWaylandSeat *input_device = QWaylandSeat::fromSeatResource(seat);
+ emit q->startMove(input_device);
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_resize(Resource *resource, wl_resource *seat,
+ uint32_t serial, uint32_t edges)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(serial);
+
+ Q_Q(QWaylandXdgSurfaceV5);
+ QWaylandSeat *input_device = QWaylandSeat::fromSeatResource(seat);
+ emit q->startResize(input_device, QWaylandXdgSurfaceV5::ResizeEdge(edges));
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_set_maximized(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurfaceV5);
+ emit q->setMaximized();
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_unset_maximized(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurfaceV5);
+ emit q->unsetMaximized();
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_set_fullscreen(Resource *resource, wl_resource *output_res)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurfaceV5);
+ QWaylandOutput *output = output_res ? QWaylandOutput::fromResource(output_res) : nullptr;
+ emit q->setFullscreen(output);
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_unset_fullscreen(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurfaceV5);
+ emit q->unsetFullscreen();
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_set_minimized(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurfaceV5);
+ emit q->setMinimized();
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_set_parent(Resource *resource, wl_resource *parent)
+{
+ Q_UNUSED(resource);
+ QWaylandXdgSurfaceV5 *parentSurface = nullptr;
+ if (parent) {
+ parentSurface = static_cast<QWaylandXdgSurfaceV5Private *>(
+ QWaylandXdgSurfaceV5Private::Resource::fromResource(parent)->xdg_surface_object)->q_func();
+ }
+
+ Q_Q(QWaylandXdgSurfaceV5);
+
+ if (m_parentSurface != parentSurface) {
+ m_parentSurface = parentSurface;
+ emit q->parentSurfaceChanged();
+ }
+
+ if (m_parentSurface && m_windowType != TransientWindowType) {
+ // There's a parent now, which means the surface is transient
+ m_windowType = TransientWindowType;
+ emit q->setTransient();
+ } else if (!m_parentSurface && m_windowType != TopLevelWindowType) {
+ // When the surface has no parent it is toplevel
+ m_windowType = TopLevelWindowType;
+ emit q->setTopLevel();
+ }
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_set_app_id(Resource *resource, const QString &app_id)
+{
+ Q_UNUSED(resource);
+ if (app_id == m_appId)
+ return;
+ Q_Q(QWaylandXdgSurfaceV5);
+ m_appId = app_id;
+ emit q->appIdChanged();
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_show_window_menu(Resource *resource, wl_resource *seatResource,
+ uint32_t serial, int32_t x, int32_t y)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(serial);
+ QPoint position(x, y);
+ auto seat = QWaylandSeat::fromSeatResource(seatResource);
+ Q_Q(QWaylandXdgSurfaceV5);
+ emit q->showWindowMenu(seat, position);
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_ack_configure(Resource *resource, uint32_t serial)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurfaceV5);
+
+ ConfigureEvent config;
+ Q_FOREVER {
+ if (m_pendingConfigures.empty()) {
+ qWarning("Received an unexpected ack_configure!");
+ return;
+ }
+
+ config = m_pendingConfigures.takeFirst();
+
+ if (config.serial == serial)
+ break;
+ }
+
+ QVector<uint> changedStates;
+ std::set_symmetric_difference(
+ m_lastAckedConfigure.states.begin(), m_lastAckedConfigure.states.end(),
+ config.states.begin(), config.states.end(),
+ std::back_inserter(changedStates));
+
+ m_lastAckedConfigure = config;
+
+ if (!changedStates.empty()) {
+ Q_FOREACH (uint state, changedStates) {
+ switch (state) {
+ case QWaylandXdgSurfaceV5::State::MaximizedState:
+ emit q->maximizedChanged();
+ break;
+ case QWaylandXdgSurfaceV5::State::FullscreenState:
+ emit q->fullscreenChanged();
+ break;
+ case QWaylandXdgSurfaceV5::State::ResizingState:
+ emit q->resizingChanged();
+ break;
+ case QWaylandXdgSurfaceV5::State::ActivatedState:
+ emit q->activatedChanged();
+ break;
+ }
+ }
+ emit q->statesChanged();
+ }
+
+ emit q->ackConfigure(serial);
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_set_title(Resource *resource, const QString &title)
+{
+ Q_UNUSED(resource);
+ if (title == m_title)
+ return;
+ Q_Q(QWaylandXdgSurfaceV5);
+ m_title = title;
+ emit q->titleChanged();
+}
+
+void QWaylandXdgSurfaceV5Private::xdg_surface_set_window_geometry(Resource *resource,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ Q_UNUSED(resource);
+
+ if (width <= 0 || height <= 0) {
+ qWarning() << "Invalid (non-positive) dimensions received in set_window_geometry";
+ return;
+ }
+
+ m_unsetWindowGeometry = false;
+
+ QRect geometry(x, y, width, height);
+
+ Q_Q(QWaylandXdgSurfaceV5);
+ if ((q->maximized() || q->fullscreen()) && m_lastAckedConfigure.size != geometry.size())
+ qWarning() << "Client window geometry did not obey last acked configure";
+
+ if (geometry == m_windowGeometry)
+ return;
+
+ m_windowGeometry = geometry;
+ emit q->windowGeometryChanged();
+}
+
+QWaylandXdgPopupV5Private::QWaylandXdgPopupV5Private()
+ : QWaylandCompositorExtensionPrivate()
+ , xdg_popup()
+ , m_surface(nullptr)
+ , m_parentSurface(nullptr)
+ , m_xdgShell(nullptr)
+{
+}
+
+void QWaylandXdgPopupV5Private::xdg_popup_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgPopupV5);
+ QWaylandXdgShellV5Private::get(m_xdgShell)->unregisterXdgPopup(q);
+ delete q;
+}
+
+void QWaylandXdgPopupV5Private::xdg_popup_destroy(Resource *resource)
+{
+ //TODO: post error if not topmost popup
+ wl_resource_destroy(resource->handle);
+}
+
+/*!
+ * Constructs a QWaylandXdgShellV5 object.
+ */
+QWaylandXdgShellV5::QWaylandXdgShellV5()
+ : QWaylandCompositorExtensionTemplate<QWaylandXdgShellV5>(*new QWaylandXdgShellV5Private())
+{ }
+
+/*!
+ * Constructs a QWaylandXdgShellV5 object for the provided \a compositor.
+ */
+QWaylandXdgShellV5::QWaylandXdgShellV5(QWaylandCompositor *compositor)
+ : QWaylandCompositorExtensionTemplate<QWaylandXdgShellV5>(compositor, *new QWaylandXdgShellV5Private())
+{ }
+
+/*!
+ * Initializes the shell extension.
+ */
+void QWaylandXdgShellV5::initialize()
+{
+ Q_D(QWaylandXdgShellV5);
+ QWaylandCompositorExtensionTemplate::initialize();
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ if (!compositor) {
+ qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandXdgShellV5";
+ return;
+ }
+ d->init(compositor->display(), 1);
+
+ handleSeatChanged(compositor->defaultSeat(), nullptr);
+
+ connect(compositor, &QWaylandCompositor::defaultSeatChanged,
+ this, &QWaylandXdgShellV5::handleSeatChanged);
+}
+
+/*!
+ * Returns the Wayland interface for the QWaylandXdgShellV5.
+ */
+const struct wl_interface *QWaylandXdgShellV5::interface()
+{
+ return QWaylandXdgShellV5Private::interface();
+}
+
+QByteArray QWaylandXdgShellV5::interfaceName()
+{
+ return QWaylandXdgShellV5Private::interfaceName();
+}
+
+/*!
+ * \qmlmethod void QtWaylandCompositor::XdgSurface::ping()
+ *
+ * Sends a ping event to the client. If the client replies to the event the
+ * \a pong signal will be emitted.
+ */
+
+/*!
+ * Sends a ping event to the client. If the client replies to the event the
+ * \a pong signal will be emitted.
+ */
+uint QWaylandXdgShellV5::ping(QWaylandClient *client)
+{
+ Q_D(QWaylandXdgShellV5);
+
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ Q_ASSERT(compositor);
+
+ uint32_t serial = compositor->nextSerial();
+
+ QWaylandXdgShellV5Private::Resource *clientResource = d->resourceMap().value(client->client(), nullptr);
+ Q_ASSERT(clientResource);
+
+ d->ping(clientResource, serial);
+ return serial;
+}
+
+void QWaylandXdgShellV5::closeAllPopups()
+{
+ Q_D(QWaylandXdgShellV5);
+ Q_FOREACH (struct wl_client *client, d->m_xdgPopups.keys()) {
+ QList<QWaylandXdgPopupV5 *> popups = d->m_xdgPopups.values(client);
+ std::reverse(popups.begin(), popups.end());
+ Q_FOREACH (QWaylandXdgPopupV5 *currentTopmostPopup, popups) {
+ currentTopmostPopup->sendPopupDone();
+ }
+ }
+}
+
+void QWaylandXdgShellV5::handleSeatChanged(QWaylandSeat *newSeat, QWaylandSeat *oldSeat)
+{
+ if (oldSeat != nullptr) {
+ disconnect(oldSeat, &QWaylandSeat::keyboardFocusChanged,
+ this, &QWaylandXdgShellV5::handleFocusChanged);
+ }
+
+ if (newSeat != nullptr) {
+ connect(newSeat, &QWaylandSeat::keyboardFocusChanged,
+ this, &QWaylandXdgShellV5::handleFocusChanged);
+ }
+}
+
+void QWaylandXdgShellV5::handleFocusChanged(QWaylandSurface *newSurface, QWaylandSurface *oldSurface)
+{
+ Q_D(QWaylandXdgShellV5);
+
+ QWaylandXdgSurfaceV5 *newXdgSurface = d->xdgSurfaceFromSurface(newSurface);
+ QWaylandXdgSurfaceV5 *oldXdgSurface = d->xdgSurfaceFromSurface(oldSurface);
+
+ if (newXdgSurface)
+ QWaylandXdgSurfaceV5Private::get(newXdgSurface)->handleFocusReceived();
+
+ if (oldXdgSurface)
+ QWaylandXdgSurfaceV5Private::get(oldXdgSurface)->handleFocusLost();
+}
+
+/*!
+ * \class QWaylandXdgSurfaceV5
+ * \inmodule QtWaylandCompositor
+ * \preliminary
+ * \brief The QWaylandXdgSurfaceV5 class provides desktop-style compositor-specific features to an xdg surface.
+ *
+ * This class is part of the QWaylandXdgShellV5 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 xdg_surface.
+ */
+
+/*!
+ * \qmlsignal QtWaylandCompositor::XdgSurface::setTopLevel()
+ *
+ * This signal is emitted when the parent surface is unset, effectively
+ * making the window top level.
+ */
+
+/*!
+ * \qmlsignal QtWaylandCompositor::XdgSurface::setTransient()
+ *
+ * This signal is emitted when the parent surface is set, effectively
+ * making the window transient.
+ */
+
+/*!
+ * Constructs a QWaylandXdgSurfaceV5.
+ */
+QWaylandXdgSurfaceV5::QWaylandXdgSurfaceV5()
+ : QWaylandShellSurfaceTemplate<QWaylandXdgSurfaceV5>(*new QWaylandXdgSurfaceV5Private)
+{
+}
+
+/*!
+ * Constructs a QWaylandXdgSurfaceV5 for \a surface and initializes it with the
+ * given \a xdgShell, \a surface, and resource \a res.
+ */
+QWaylandXdgSurfaceV5::QWaylandXdgSurfaceV5(QWaylandXdgShellV5 *xdgShell, QWaylandSurface *surface, const QWaylandResource &res)
+ : QWaylandShellSurfaceTemplate<QWaylandXdgSurfaceV5>(*new QWaylandXdgSurfaceV5Private)
+{
+ initialize(xdgShell, surface, res);
+}
+
+/*!
+ * \qmlmethod void QtWaylandCompositor::XdgSurface::initialize(object surface, object client, int id)
+ *
+ * Initializes the XdgSurface, associating it with the given \a surface,
+ * \a client, and \a id.
+ */
+
+/*!
+ * Initializes the QWaylandXdgSurfaceV5, associating it with the given \a xdgShell, \a surface
+ * and \a resource.
+ */
+void QWaylandXdgSurfaceV5::initialize(QWaylandXdgShellV5 *xdgShell, QWaylandSurface *surface, const QWaylandResource &resource)
+{
+ Q_D(QWaylandXdgSurfaceV5);
+ d->m_xdgShell = xdgShell;
+ d->m_surface = surface;
+ d->init(resource.resource());
+ setExtensionContainer(surface);
+ d->m_windowGeometry = d->calculateFallbackWindowGeometry();
+ connect(surface, &QWaylandSurface::sizeChanged, this, &QWaylandXdgSurfaceV5::handleSurfaceSizeChanged);
+ connect(surface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandXdgSurfaceV5::handleBufferScaleChanged);
+ emit shellChanged();
+ emit surfaceChanged();
+ emit windowGeometryChanged();
+ QWaylandCompositorExtension::initialize();
+}
+
+/*!
+ * \internal
+ */
+void QWaylandXdgSurfaceV5::initialize()
+{
+ QWaylandCompositorExtension::initialize();
+}
+
+QList<int> QWaylandXdgSurfaceV5::statesAsInts() const
+{
+ QList<int> list;
+ Q_FOREACH (uint state, states()) {
+ list << static_cast<int>(state);
+ }
+ return list;
+}
+
+void QWaylandXdgSurfaceV5::handleSurfaceSizeChanged()
+{
+ Q_D(QWaylandXdgSurfaceV5);
+ d->updateFallbackWindowGeometry();
+}
+
+void QWaylandXdgSurfaceV5::handleBufferScaleChanged()
+{
+ Q_D(QWaylandXdgSurfaceV5);
+ d->updateFallbackWindowGeometry();
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgSurface::shell
+ *
+ * This property holds the shell associated with this XdgSurface.
+ */
+
+/*!
+ * \property QWaylandXdgSurfaceV5::shell
+ *
+ * This property holds the shell associated with this QWaylandXdgSurfaceV5.
+ */
+QWaylandXdgShellV5 *QWaylandXdgSurfaceV5::shell() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_xdgShell;
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgSurface::surface
+ *
+ * This property holds the surface associated with this XdgSurface.
+ */
+
+/*!
+ * \property QWaylandXdgSurfaceV5::surface
+ *
+ * This property holds the surface associated with this QWaylandXdgSurfaceV5.
+ */
+QWaylandSurface *QWaylandXdgSurfaceV5::surface() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_surface;
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgSurface::parentSurface
+ *
+ * This property holds the XdgSurface parent of this XdgSurface.
+ * When a parent surface is set, the parentSurfaceChanged() signal
+ * is guaranteed to be emitted before setTopLevel() and setTransient().
+ *
+ * \sa QtWaylandCompositor::XdgSurface::setTopLevel()
+ * \sa QtWaylandCompositor::XdgSurface::setTransient()
+ */
+
+/*!
+ * \property QWaylandXdgSurfaceV5::parentSurface
+ *
+ * This property holds the XdgSurface parent of this XdgSurface.
+ * When a parent surface is set, the parentSurfaceChanged() signal
+ * is guaranteed to be emitted before setTopLevel() and setTransient().
+ *
+ * \sa QWaylandXdgSurfaceV5::setTopLevel()
+ * \sa QWaylandXdgSurfaceV5::setTransient()
+ */
+QWaylandXdgSurfaceV5 *QWaylandXdgSurfaceV5::parentSurface() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_parentSurface;
+}
+
+/*!
+ * \qmlproperty string QtWaylandCompositor::XdgSurface::title
+ *
+ * This property holds the title of the XdgSurface.
+ */
+
+/*!
+ * \property QWaylandXdgSurfaceV5::title
+ *
+ * This property holds the title of the QWaylandXdgSurfaceV5.
+ */
+QString QWaylandXdgSurfaceV5::title() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_title;
+}
+
+/*!
+ * \property QWaylandXdgSurfaceV5::appId
+ *
+ * This property holds the app id of the QWaylandXdgSurfaceV5.
+ */
+QString QWaylandXdgSurfaceV5::appId() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_appId;
+}
+
+/*!
+ * \property QWaylandXdgSurfaceV5::windowGeometry
+ *
+ * This property holds the window geometry of the QWaylandXdgSurfaceV5. The window
+ * geometry describes the window's visible bounds from the user's perspective.
+ * The geometry includes title bars and borders if drawn by the client, but
+ * excludes drop shadows. It is meant to be used for aligning and tiling
+ * windows.
+ */
+QRect QWaylandXdgSurfaceV5::windowGeometry() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_windowGeometry;
+}
+
+/*!
+ * \property QWaylandXdgSurfaceV5::states
+ *
+ * This property holds the last states the client acknowledged for this QWaylandXdgSurfaceV5.
+ */
+QVector<uint> QWaylandXdgSurfaceV5::states() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_lastAckedConfigure.states;
+}
+
+bool QWaylandXdgSurfaceV5::maximized() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_lastAckedConfigure.states.contains(QWaylandXdgSurfaceV5::State::MaximizedState);
+}
+
+bool QWaylandXdgSurfaceV5::fullscreen() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_lastAckedConfigure.states.contains(QWaylandXdgSurfaceV5::State::FullscreenState);
+}
+
+bool QWaylandXdgSurfaceV5::resizing() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_lastAckedConfigure.states.contains(QWaylandXdgSurfaceV5::State::ResizingState);
+}
+
+bool QWaylandXdgSurfaceV5::activated() const
+{
+ Q_D(const QWaylandXdgSurfaceV5);
+ return d->m_lastAckedConfigure.states.contains(QWaylandXdgSurfaceV5::State::ActivatedState);
+}
+
+/*!
+ * Returns the Wayland interface for the QWaylandXdgSurfaceV5.
+ */
+const wl_interface *QWaylandXdgSurfaceV5::interface()
+{
+ return QWaylandXdgSurfaceV5Private::interface();
+}
+
+QByteArray QWaylandXdgSurfaceV5::interfaceName()
+{
+ return QWaylandXdgSurfaceV5Private::interfaceName();
+}
+
+/*!
+ * Returns the surface role for the QWaylandXdgSurfaceV5.
+ */
+QWaylandSurfaceRole *QWaylandXdgSurfaceV5::role()
+{
+ return &QWaylandXdgSurfaceV5Private::s_role;
+}
+
+/*!
+ * Returns the QWaylandXdgSurfaceV5 corresponding to the \a resource.
+ */
+QWaylandXdgSurfaceV5 *QWaylandXdgSurfaceV5::fromResource(wl_resource *resource)
+{
+ auto xsResource = QWaylandXdgSurfaceV5Private::Resource::fromResource(resource);
+ if (!xsResource)
+ return nullptr;
+ return static_cast<QWaylandXdgSurfaceV5Private *>(xsResource->xdg_surface_object)->q_func();
+}
+
+QSize QWaylandXdgSurfaceV5::sizeForResize(const QSizeF &size, const QPointF &delta,
+ QWaylandXdgSurfaceV5::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();
+
+ return QSizeF(width, height).toSize();
+}
+
+/*!
+ * \qmlmethod int QtWaylandCompositor::XdgSurface::sendConfigure(size size, List<uint>)
+ *
+ * Sends a configure event to the client. Known states are enumerated in XdgSurface::State
+ */
+
+/*!
+ * Sends a configure event to the client. Known states are enumerated in QWaylandXdgSurfaceV5::State
+ */
+uint QWaylandXdgSurfaceV5::sendConfigure(const QSize &size, const QVector<uint> &states)
+{
+ Q_D(QWaylandXdgSurfaceV5);
+ auto statesBytes = QByteArray::fromRawData((char *)states.data(), states.size() * sizeof(State));
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ Q_ASSERT(compositor);
+ uint32_t serial = compositor->nextSerial();
+ d->m_pendingConfigures.append(QWaylandXdgSurfaceV5Private::ConfigureEvent{states, size, serial});
+ d->send_configure(size.width(), size.height(), statesBytes, serial);
+ return serial;
+}
+
+uint QWaylandXdgSurfaceV5::sendConfigure(const QSize &size, const QVector<QWaylandXdgSurfaceV5::State> &states)
+{
+ QVector<uint> asUints;
+ Q_FOREACH (QWaylandXdgSurfaceV5::State state, states) {
+ asUints << state;
+ }
+ return sendConfigure(size, asUints);
+}
+
+/*!
+ * \qmlmethod void QtWaylandCompositor::XdgSurface::sendClose()
+ *
+ * Sends a close event to the client.
+ */
+
+/*!
+ * Sends a close event to the client.
+ */
+void QWaylandXdgSurfaceV5::sendClose()
+{
+ Q_D(QWaylandXdgSurfaceV5);
+ d->send_close();
+}
+
+uint QWaylandXdgSurfaceV5::sendMaximized(const QSize &size)
+{
+ Q_D(QWaylandXdgSurfaceV5);
+ QWaylandXdgSurfaceV5Private::ConfigureEvent conf = d->lastSentConfigure();
+
+ if (!conf.states.contains(QWaylandXdgSurfaceV5::State::MaximizedState))
+ conf.states.append(QWaylandXdgSurfaceV5::State::MaximizedState);
+ conf.states.removeOne(QWaylandXdgSurfaceV5::State::FullscreenState);
+ conf.states.removeOne(QWaylandXdgSurfaceV5::State::ResizingState);
+
+ return sendConfigure(size, conf.states);
+}
+
+uint QWaylandXdgSurfaceV5::sendUnmaximized(const QSize &size)
+{
+ Q_D(QWaylandXdgSurfaceV5);
+ QWaylandXdgSurfaceV5Private::ConfigureEvent conf = d->lastSentConfigure();
+
+ conf.states.removeOne(QWaylandXdgSurfaceV5::State::MaximizedState);
+ conf.states.removeOne(QWaylandXdgSurfaceV5::State::FullscreenState);
+ conf.states.removeOne(QWaylandXdgSurfaceV5::State::ResizingState);
+
+ return sendConfigure(size, conf.states);
+}
+
+uint QWaylandXdgSurfaceV5::sendFullscreen(const QSize &size)
+{
+ Q_D(QWaylandXdgSurfaceV5);
+ QWaylandXdgSurfaceV5Private::ConfigureEvent conf = d->lastSentConfigure();
+
+ if (!conf.states.contains(QWaylandXdgSurfaceV5::State::FullscreenState))
+ conf.states.append(QWaylandXdgSurfaceV5::State::FullscreenState);
+ conf.states.removeOne(QWaylandXdgSurfaceV5::State::MaximizedState);
+ conf.states.removeOne(QWaylandXdgSurfaceV5::State::ResizingState);
+
+ return sendConfigure(size, conf.states);
+}
+
+uint QWaylandXdgSurfaceV5::sendResizing(const QSize &maxSize)
+{
+ Q_D(QWaylandXdgSurfaceV5);
+ QWaylandXdgSurfaceV5Private::ConfigureEvent conf = d->lastSentConfigure();
+
+ if (!conf.states.contains(QWaylandXdgSurfaceV5::State::ResizingState))
+ conf.states.append(QWaylandXdgSurfaceV5::State::ResizingState);
+ conf.states.removeOne(QWaylandXdgSurfaceV5::State::MaximizedState);
+ conf.states.removeOne(QWaylandXdgSurfaceV5::State::FullscreenState);
+
+ return sendConfigure(maxSize, conf.states);
+}
+
+#ifdef QT_WAYLAND_COMPOSITOR_QUICK
+QWaylandQuickShellIntegration *QWaylandXdgSurfaceV5::createIntegration(QWaylandQuickShellSurfaceItem *item)
+{
+ return new QtWayland::XdgShellV5Integration(item);
+}
+#endif
+
+/*!
+ * \class QWaylandXdgPopupV5
+ * \inmodule QtWaylandCompositor
+ * \preliminary
+ * \brief The QWaylandXdgPopupV5 class provides menus for an xdg surface
+ *
+ * This class is part of the QWaylandXdgShellV5 extension and provides a way to
+ * extend the functionality of an existing QWaylandSurface with features
+ * specific to desktop-style menus for an xdg surface.
+ *
+ * It corresponds to the Wayland interface xdg_popup.
+ */
+
+/*!
+ * Constructs a QWaylandXdgPopupV5.
+ */
+QWaylandXdgPopupV5::QWaylandXdgPopupV5()
+ : QWaylandShellSurfaceTemplate<QWaylandXdgPopupV5>(*new QWaylandXdgPopupV5Private)
+{
+}
+
+/*!
+ * Constructs a QWaylandXdgPopupV5 for \a surface and initializes it with the
+ * given \a parentSurface and \a resource.
+ */
+QWaylandXdgPopupV5::QWaylandXdgPopupV5(QWaylandXdgShellV5 *xdgShell, QWaylandSurface *surface,
+ QWaylandSurface *parentSurface, const QPoint &position, const QWaylandResource &resource)
+ : QWaylandShellSurfaceTemplate<QWaylandXdgPopupV5>(*new QWaylandXdgPopupV5Private)
+{
+ initialize(xdgShell, surface, parentSurface, position, resource);
+}
+
+/*!
+ * \qmlmethod void QtWaylandCompositor::XdgPopup::initialize(object surface, object parentSurface, object resource)
+ *
+ * Initializes the xdg popup, associating it with the given \a shell, \a surface,
+ * \a parentSurface and \a resource.
+ */
+
+/*!
+ * Initializes the QWaylandXdgPopupV5, associating it with the given \a shell \a surface,
+ * \a parentSurface and \a resource.
+ */
+void QWaylandXdgPopupV5::initialize(QWaylandXdgShellV5 *shell, QWaylandSurface *surface, QWaylandSurface *parentSurface,
+ const QPoint& position, const QWaylandResource &resource)
+{
+ Q_D(QWaylandXdgPopupV5);
+ d->m_surface = surface;
+ d->m_parentSurface = parentSurface;
+ d->m_xdgShell = shell;
+ d->m_position = position;
+ d->init(resource.resource());
+ setExtensionContainer(surface);
+ emit shellChanged();
+ emit surfaceChanged();
+ emit parentSurfaceChanged();
+ QWaylandCompositorExtension::initialize();
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgPopup::shell
+ *
+ * This property holds the shell associated with this XdgPopup.
+ */
+
+/*!
+ * \property QWaylandXdgPopupV5::shell
+ *
+ * This property holds the shell associated with this QWaylandXdgPopupV5.
+ */
+QWaylandXdgShellV5 *QWaylandXdgPopupV5::shell() const
+{
+ Q_D(const QWaylandXdgPopupV5);
+ return d->m_xdgShell;
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgPopup::surface
+ *
+ * This property holds the surface associated with this XdgPopup.
+ */
+
+/*!
+ * \property QWaylandXdgPopupV5::surface
+ *
+ * This property holds the surface associated with this QWaylandXdgPopupV5.
+ */
+QWaylandSurface *QWaylandXdgPopupV5::surface() const
+{
+ Q_D(const QWaylandXdgPopupV5);
+ return d->m_surface;
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgPopup::parentSurface
+ *
+ * This property holds the surface associated with the parent of this XdgPopup.
+ */
+
+/*!
+ * \property QWaylandXdgPopupV5::parentSurface
+ *
+ * This property holds the surface associated with the parent of this
+ * QWaylandXdgPopupV5.
+ */
+QWaylandSurface *QWaylandXdgPopupV5::parentSurface() const
+{
+ Q_D(const QWaylandXdgPopupV5);
+ return d->m_parentSurface;
+}
+
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgPopup::position
+ *
+ * This property holds the location of the upper left corner of the surface
+ * relative to the upper left corner of the parent surface, in surface local
+ * coordinates.
+ */
+
+/*!
+ * \property QWaylandXdgPopupV5::position
+ *
+ * This property holds the location of the upper left corner of the surface
+ * relative to the upper left corner of the parent surface, in surface local
+ * coordinates.
+ */
+QPoint QWaylandXdgPopupV5::position() const
+{
+ Q_D(const QWaylandXdgPopupV5);
+ return d->m_position;
+}
+
+/*!
+ * \internal
+ */
+void QWaylandXdgPopupV5::initialize()
+{
+ QWaylandCompositorExtension::initialize();
+}
+
+/*!
+ * Returns the Wayland interface for the QWaylandXdgPopupV5.
+ */
+const wl_interface *QWaylandXdgPopupV5::interface()
+{
+ return QWaylandXdgPopupV5Private::interface();
+}
+
+QByteArray QWaylandXdgPopupV5::interfaceName()
+{
+ return QWaylandXdgPopupV5Private::interfaceName();
+}
+
+/*!
+ * Returns the surface role for the QWaylandXdgPopupV5.
+ */
+QWaylandSurfaceRole *QWaylandXdgPopupV5::role()
+{
+ return &QWaylandXdgPopupV5Private::s_role;
+}
+
+QWaylandXdgPopupV5 *QWaylandXdgPopupV5::fromResource(wl_resource *resource)
+{
+ auto popupResource = QWaylandXdgPopupV5Private::Resource::fromResource(resource);
+ if (!popupResource)
+ return nullptr;
+ return static_cast<QWaylandXdgPopupV5Private *>(popupResource->xdg_popup_object)->q_func();
+}
+
+void QWaylandXdgPopupV5::sendPopupDone()
+{
+ Q_D(QWaylandXdgPopupV5);
+ d->send_popup_done();
+}
+
+#ifdef QT_WAYLAND_COMPOSITOR_QUICK
+QWaylandQuickShellIntegration *QWaylandXdgPopupV5::createIntegration(QWaylandQuickShellSurfaceItem *item)
+{
+ return new QtWayland::XdgPopupV5Integration(item);
+}
+#endif
+
+QT_END_NAMESPACE