summaryrefslogtreecommitdiffstats
path: root/src/imports/compositor-extensions
diff options
context:
space:
mode:
Diffstat (limited to 'src/imports/compositor-extensions')
-rw-r--r--src/imports/compositor-extensions/CMakeLists.txt10
-rw-r--r--src/imports/compositor-extensions/iviapplication/CMakeLists.txt28
-rw-r--r--src/imports/compositor-extensions/iviapplication/qwaylandcompositoriviapplicationforeign.cpp29
-rw-r--r--src/imports/compositor-extensions/iviapplication/qwaylandcompositoriviapplicationforeign_p.h39
-rw-r--r--src/imports/compositor-extensions/presentationtime/CMakeLists.txt29
-rw-r--r--src/imports/compositor-extensions/presentationtime/qwaylandcompositorpresentationtimeforeign.cpp32
-rw-r--r--src/imports/compositor-extensions/presentationtime/qwaylandcompositorpresentationtimeforeign_p.h30
-rw-r--r--src/imports/compositor-extensions/qtshell/CMakeLists.txt33
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshell.cpp847
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshell.h181
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshell.qdoc22
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshell_p.h108
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp1500
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.h157
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome_p.h87
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshellintegration.cpp39
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshellintegration_p.h45
-rw-r--r--src/imports/compositor-extensions/wlshell/CMakeLists.txt17
-rw-r--r--src/imports/compositor-extensions/wlshell/qwaylandcompositorwlshell.cpp30
-rw-r--r--src/imports/compositor-extensions/wlshell/qwaylandcompositorwlshell_p.h37
-rw-r--r--src/imports/compositor-extensions/xdgshell/CMakeLists.txt18
-rw-r--r--src/imports/compositor-extensions/xdgshell/qwaylandcompositorxdgshell.cpp27
-rw-r--r--src/imports/compositor-extensions/xdgshell/qwaylandcompositorxdgshell_p.h66
23 files changed, 3411 insertions, 0 deletions
diff --git a/src/imports/compositor-extensions/CMakeLists.txt b/src/imports/compositor-extensions/CMakeLists.txt
new file mode 100644
index 000000000..28d187ab4
--- /dev/null
+++ b/src/imports/compositor-extensions/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Generated from compositor-extensions.pro.
+
+add_subdirectory(xdgshell)
+add_subdirectory(iviapplication)
+add_subdirectory(wlshell)
+add_subdirectory(qtshell)
+add_subdirectory(presentationtime)
diff --git a/src/imports/compositor-extensions/iviapplication/CMakeLists.txt b/src/imports/compositor-extensions/iviapplication/CMakeLists.txt
new file mode 100644
index 000000000..a2899fa27
--- /dev/null
+++ b/src/imports/compositor-extensions/iviapplication/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Generated from iviapplication.pro.
+
+#####################################################################
+## qwaylandcompositoriviapplicationplugin Plugin:
+#####################################################################
+
+qt_internal_add_qml_module(WaylandCompositorIviapplication
+ URI "QtWayland.Compositor.IviApplication"
+ VERSION "${PROJECT_VERSION}"
+ SOURCES
+ qwaylandcompositoriviapplicationforeign.cpp qwaylandcompositoriviapplicationforeign_p.h
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::WaylandCompositor
+ NO_GENERATE_CPP_EXPORTS
+ PAST_MAJOR_VERSIONS 1
+)
+
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorIviapplication WaylandCompositor)
+
+#### Keys ignored in scope 1:.:.:iviapplication.pro:<TRUE>:
+# CXX_MODULE = "qml"
+# QML_IMPORT_VERSION = "$$QT_VERSION"
+# TARGETPATH = "QtWayland/Compositor/IviApplication"
diff --git a/src/imports/compositor-extensions/iviapplication/qwaylandcompositoriviapplicationforeign.cpp b/src/imports/compositor-extensions/iviapplication/qwaylandcompositoriviapplicationforeign.cpp
new file mode 100644
index 000000000..66a38fbf4
--- /dev/null
+++ b/src/imports/compositor-extensions/iviapplication/qwaylandcompositoriviapplicationforeign.cpp
@@ -0,0 +1,29 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwaylandcompositoriviapplicationforeign_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlmodule QtWayland.Compositor.IviApplication
+ \title Qt Wayland IviApplication Extension
+ \ingroup qmlmodules
+ \brief Provides a Qt API for the IviApplication shell extension.
+
+ \section2 Summary
+ IviApplication is a shell extension suitable for lightweight compositors,
+ for example in In-Vehicle Infotainment (IVI) systems.
+
+ IviApplication corresponds to the Wayland \c ivi_application interface.
+
+ \section2 Usage
+ To use this module, import it like this:
+ \qml
+ import QtWayland.Compositor.IviApplication
+ \endqml
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qwaylandcompositoriviapplicationforeign_p.cpp"
diff --git a/src/imports/compositor-extensions/iviapplication/qwaylandcompositoriviapplicationforeign_p.h b/src/imports/compositor-extensions/iviapplication/qwaylandcompositoriviapplicationforeign_p.h
new file mode 100644
index 000000000..89d5e7eba
--- /dev/null
+++ b/src/imports/compositor-extensions/iviapplication/qwaylandcompositoriviapplicationforeign_p.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDCOMPOSITORIVIAPPLICATIONFOREIGN_H
+#define QWAYLANDCOMPOSITORIVIAPPLICATIONFOREIGN_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
+
+#include <QtWaylandCompositor/qwaylandquickextension.h>
+#include <QtWaylandCompositor/qwaylandiviapplication.h>
+#include <QtWaylandCompositor/qwaylandivisurface.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_ELEMENT(QWaylandIviApplication, IviApplication, 1, 0)
+
+struct QWaylandIviSurfaceForeign {
+ Q_GADGET
+ QML_FOREIGN(QWaylandIviSurface)
+ QML_NAMED_ELEMENT(IviSurface)
+ QML_ADDED_IN_VERSION(1, 0)
+};
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/imports/compositor-extensions/presentationtime/CMakeLists.txt b/src/imports/compositor-extensions/presentationtime/CMakeLists.txt
new file mode 100644
index 000000000..2a817c012
--- /dev/null
+++ b/src/imports/compositor-extensions/presentationtime/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## qwaylandcompositorpresentationtimeplugin Plugin:
+#####################################################################
+
+# Note: INTERFACE_AUTOMOC_MACRO_NAMES is a CMake 3.27 feature, so readd it here for older CMake versions.
+list(APPEND CMAKE_AUTOMOC_MACRO_NAMES
+ "Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_ELEMENT"
+ "Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS"
+ "Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS"
+ "Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CONTAINER_CLASS")
+
+qt_internal_add_qml_module(WaylandCompositorPresentationTime
+ URI "QtWayland.Compositor.PresentationTime"
+ VERSION "${PROJECT_VERSION}"
+ SOURCES
+ qwaylandcompositorpresentationtimeforeign.cpp qwaylandcompositorpresentationtimeforeign_p.h
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::WaylandCompositorPrivate
+ NO_GENERATE_CPP_EXPORTS
+ PAST_MAJOR_VERSIONS 1
+)
+
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorPresentationTime
+ WaylandCompositor)
diff --git a/src/imports/compositor-extensions/presentationtime/qwaylandcompositorpresentationtimeforeign.cpp b/src/imports/compositor-extensions/presentationtime/qwaylandcompositorpresentationtimeforeign.cpp
new file mode 100644
index 000000000..05807e74f
--- /dev/null
+++ b/src/imports/compositor-extensions/presentationtime/qwaylandcompositorpresentationtimeforeign.cpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2021 LG Electronics Inc.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwaylandcompositorpresentationtimeforeign_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlmodule QtWayland.Compositor.PresentationTime
+ \title Qt Wayland Presentation Time Extension
+ \ingroup qmlmodules
+ \since 6.3
+ \brief Provides tracking the timing when a frame is presented on screen.
+
+ \section2 Summary
+ The PresentationTime extension provides a way to track rendering timing
+ for a surface. Client can request feedbacks associated with a surface,
+ then compositor send events for the feedback with the time when the surface
+ is presented on-screen.
+
+ PresentationTime corresponds to the Wayland \c wp_presentation interface.
+
+ \section2 Usage
+ To use this module, import it like this:
+ \qml
+ import QtWayland.Compositor.PresentationTime
+ \endqml
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qwaylandcompositorpresentationtimeforeign_p.cpp"
diff --git a/src/imports/compositor-extensions/presentationtime/qwaylandcompositorpresentationtimeforeign_p.h b/src/imports/compositor-extensions/presentationtime/qwaylandcompositorpresentationtimeforeign_p.h
new file mode 100644
index 000000000..63827320e
--- /dev/null
+++ b/src/imports/compositor-extensions/presentationtime/qwaylandcompositorpresentationtimeforeign_p.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2021 LG Electronics Inc.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDCOMPOSITORPRESENTATIONTIMEFOREIGN_H
+#define QWAYLANDCOMPOSITORPRESENTATIONTIMEFOREIGN_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
+
+#include <QtWaylandCompositor/qwaylandquickextension.h>
+#include <QtWaylandCompositor/private/qwaylandpresentationtime_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_ELEMENT(QWaylandPresentationTime, PresentationTime, 1, 0)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/imports/compositor-extensions/qtshell/CMakeLists.txt b/src/imports/compositor-extensions/qtshell/CMakeLists.txt
new file mode 100644
index 000000000..429d0c26b
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## qwaylandqtshellplugin Plugin:
+#####################################################################
+
+qt_internal_add_qml_module(WaylandCompositorQtShell
+ URI "QtWayland.Compositor.QtShell"
+ VERSION "${PROJECT_VERSION}"
+ PLUGIN_TARGET WaylandCompositorQtShell
+ SOURCES
+ qwaylandqtshell.cpp qwaylandqtshell.h qwaylandqtshell_p.h
+ qwaylandqtshellintegration.cpp qwaylandqtshellintegration_p.h
+ qwaylandqtshellchrome.cpp qwaylandqtshellchrome.h qwaylandqtshellchrome_p.h
+ DEPENDENCIES
+ QtQuick
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+ Qt::QuickPrivate
+ Qt::WaylandCompositor
+ Qt::WaylandCompositorPrivate
+ PAST_MAJOR_VERSIONS 1
+)
+
+qt6_generate_wayland_protocol_server_sources(WaylandCompositorQtShell
+ FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../extensions/qt-shell-unstable-v1.xml
+)
+
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorQtShell WaylandCompositor)
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshell.cpp b/src/imports/compositor-extensions/qtshell/qwaylandqtshell.cpp
new file mode 100644
index 000000000..0e918e734
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshell.cpp
@@ -0,0 +1,847 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#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/compositor_api/qwaylandseat.h>
+
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ * \qmltype QtShell
+ * \instantiates 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.
+ *
+ * \qml
+ * import QtWayland.Compositor.QtShell
+ *
+ * WaylandCompositor {
+ * property ListModel shellSurfaces: ListModel {}
+ * QtShell {
+ * onQtShellSurfaceCreated: {
+ * shellSurfaces.append({shellSurface: qtShellSurface})
+ * }
+ * }
+ * }
+ * \endqml
+ */
+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
+ * \instantiates 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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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] = qMakePair(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.
+ */
+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.
+ */
+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.
+ */
+
+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.
+ */
+void QWaylandQtShellSurface::setFrameMarginBottom(int bottom)
+{
+ Q_D(QWaylandQtShellSurface);
+ if (d->m_frameMargins.bottom() == bottom)
+ return;
+ d->m_frameMargins.setBottom(bottom);
+ d->updateFrameMargins();
+
+ emit frameMarginChanged();
+}
+
+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.
+ */
+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.
+ */
+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.
+ */
+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
+ */
+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.
+ */
+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();
+ }
+}
+
+/*!
+ * Returns the Wayland interface for the QWaylandQtShellSurface.
+ */
+const wl_interface *QWaylandQtShellSurface::interface()
+{
+ return QWaylandQtShellSurfacePrivate::interface();
+}
+
+QByteArray QWaylandQtShellSurface::interfaceName()
+{
+ return QWaylandQtShellSurfacePrivate::interfaceName();
+}
+
+/*!
+ * Returns the surface role for the QWaylandQtShellSurface.
+ */
+QWaylandSurfaceRole *QWaylandQtShellSurface::role()
+{
+ return &QWaylandQtShellSurfacePrivate::s_role;
+}
+
+/*!
+ * 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);
+}
+
+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"
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshell.h b/src/imports/compositor-extensions/qtshell/qwaylandqtshell.h
new file mode 100644
index 000000000..d322b9415
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshell.h
@@ -0,0 +1,181 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDQTSHELL_H
+#define QWAYLANDQTSHELL_H
+
+#include <QtWaylandCompositor/QWaylandCompositorExtension>
+#include <QtWaylandCompositor/QWaylandSurface>
+#include <QtWaylandCompositor/QWaylandResource>
+#include <QtCore/QSize>
+
+#include <QtWaylandCompositor/QWaylandShellSurface>
+#include <QtWaylandCompositor/qwaylandquickchildren.h>
+#include <QtWaylandCompositor/qwaylandquickextension.h>
+
+struct wl_resource;
+struct wl_interface;
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandQtShellPrivate;
+class QWaylandQtShellSurface;
+class QWaylandQtShellChrome;
+
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandQtShell : public QWaylandCompositorExtensionTemplate<QWaylandQtShell>
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandQtShell)
+
+public:
+ QWaylandQtShell();
+ QWaylandQtShell(QWaylandCompositor *compositor);
+
+ void initialize() override;
+
+ static const struct wl_interface *interface();
+ static QByteArray interfaceName();
+
+ void registerChrome(QWaylandQtShellChrome *chrome);
+ void unregisterChrome(QWaylandQtShellChrome *chrome);
+
+private Q_SLOTS:
+ void chromeActivated();
+ void chromeDeactivated();
+
+Q_SIGNALS:
+ void qtShellSurfaceRequested(QWaylandSurface *surface, const QWaylandResource &resource);
+ void qtShellSurfaceCreated(QWaylandQtShellSurface *qtShellSurface);
+
+private:
+ bool moveChromeToFront(QWaylandQtShellChrome *chrome);
+};
+
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_ELEMENT(QWaylandQtShell, QtShell, 1, 0)
+
+
+class QWaylandQtShellSurfacePrivate;
+class QWaylandSurfaceRole;
+class QWaylandResource;
+
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandQtShellSurface : public QWaylandShellSurfaceTemplate<QWaylandQtShellSurface>
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(QtShellSurface)
+ QML_ADDED_IN_VERSION(1, 0)
+ Q_DECLARE_PRIVATE(QWaylandQtShellSurface)
+ Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(QWaylandQtShellSurface)
+ Q_PROPERTY(QWaylandSurface *surface READ surface NOTIFY surfaceChanged)
+ Q_PROPERTY(uint windowFlags READ windowFlags NOTIFY windowFlagsChanged)
+ Q_PROPERTY(uint windowState READ windowState NOTIFY windowStateChanged)
+ Q_PROPERTY(QString windowTitle READ windowTitle READ windowTitle NOTIFY windowTitleChanged)
+ Q_PROPERTY(QRect windowGeometry READ windowGeometry NOTIFY windowGeometryChanged)
+ Q_PROPERTY(QPoint windowPosition READ windowPosition WRITE setWindowPosition NOTIFY windowGeometryChanged)
+ Q_PROPERTY(bool positionAutomatic READ positionAutomatic NOTIFY positionAutomaticChanged)
+ Q_PROPERTY(QSize minimumSize READ minimumSize NOTIFY minimumSizeChanged)
+ Q_PROPERTY(QSize maximumSize READ maximumSize NOTIFY maximumSizeChanged)
+ Q_PROPERTY(int frameMarginLeft READ frameMarginLeft WRITE setFrameMarginLeft NOTIFY frameMarginChanged)
+ Q_PROPERTY(int frameMarginRight READ frameMarginRight WRITE setFrameMarginRight NOTIFY frameMarginChanged)
+ Q_PROPERTY(int frameMarginTop READ frameMarginTop WRITE setFrameMarginTop NOTIFY frameMarginChanged)
+ Q_PROPERTY(int frameMarginBottom READ frameMarginBottom WRITE setFrameMarginBottom NOTIFY frameMarginChanged)
+ Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
+ Q_PROPERTY(CapabilityFlags capabilities READ capabilities WRITE setCapabilities NOTIFY capabilitiesChanged)
+ Q_MOC_INCLUDE("qwaylandsurface.h")
+
+public:
+ // Matches the "capabilities" enum in the protocol xml
+ enum CapabilityFlag {
+ InteractiveMove = 1,
+ InteractiveResize = 2
+ };
+ Q_DECLARE_FLAGS(CapabilityFlags, CapabilityFlag)
+ Q_ENUM(CapabilityFlag)
+
+ QWaylandQtShellSurface();
+ QWaylandQtShellSurface(QWaylandQtShell *application, QWaylandSurface *surface, const QWaylandResource &resource);
+
+ void initialize(QWaylandQtShell *qtShell, QWaylandSurface *surface,
+ const QWaylandResource &resource);
+
+ QWaylandSurface *surface() const;
+
+ static const wl_interface *interface();
+ static QByteArray interfaceName();
+ static QWaylandSurfaceRole *role();
+ static QWaylandQtShellSurface *fromResource(::wl_resource *resource);
+
+ QRect windowGeometry() const;
+
+ void setWindowPosition(const QPoint &position);
+ QPoint windowPosition() const;
+
+ Q_INVOKABLE void requestWindowGeometry(uint windowState, const QRect &windowGeometry);
+
+ QSize minimumSize() const;
+ QSize maximumSize() const;
+
+ void setFrameMargins(const QMargins &margins);
+
+ int frameMarginLeft() const;
+ void setFrameMarginLeft(int left);
+
+ int frameMarginRight() const;
+ void setFrameMarginRight(int right);
+
+ int frameMarginTop() const;
+ void setFrameMarginTop(int top);
+
+ int frameMarginBottom() const;
+ void setFrameMarginBottom(int bottom);
+
+ bool positionAutomatic() const;
+
+ bool active() const;
+ void setActive(bool active);
+
+ QString windowTitle() const;
+
+ uint windowFlags() const;
+
+ Q_INVOKABLE void sendClose();
+
+ uint windowState() const;
+ void setWindowState(uint windowState);
+#if QT_CONFIG(wayland_compositor_quick)
+ QWaylandQuickShellIntegration *createIntegration(QWaylandQuickShellSurfaceItem *item) override;
+#endif
+
+ CapabilityFlags capabilities() const;
+ void setCapabilities(CapabilityFlags capabilities);
+
+Q_SIGNALS:
+ void surfaceChanged();
+ void windowFlagsChanged();
+ void windowStateChanged();
+ void windowGeometryChanged();
+ void minimumSizeChanged();
+ void maximumSizeChanged();
+ void positionAutomaticChanged();
+ void startMove();
+ void startResize(Qt::Edges edges);
+ void windowTitleChanged();
+ void frameMarginChanged();
+ void raiseRequested();
+ void lowerRequested();
+ void activeChanged();
+ void capabilitiesChanged();
+
+private Q_SLOTS:
+ void surfaceCommitted();
+
+private:
+ friend class QWaylandQtShellChrome;
+
+ void initialize() override;
+
+ QWaylandQtShell *shell() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQTSHELL_H
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshell.qdoc b/src/imports/compositor-extensions/qtshell/qwaylandqtshell.qdoc
new file mode 100644
index 000000000..d0e961245
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshell.qdoc
@@ -0,0 +1,22 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \qmlmodule QtWayland.Compositor.QtShell
+ \title Qt Wayland Qt Shell Extension
+ \ingroup qmlmodules
+ \since 6.3
+ \brief Provides a shell extension for Qt applications running on a Qt Wayland Compositor.
+ \section2 Summary
+ 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.
+ \section2 Usage
+ To use this module, import it like this:
+ \qml
+ import QtWayland.Compositor.IviApplication
+ \endqml
+*/
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshell_p.h b/src/imports/compositor-extensions/qtshell/qwaylandqtshell_p.h
new file mode 100644
index 000000000..ad93dee1a
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshell_p.h
@@ -0,0 +1,108 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDQTSHELL_P_H
+#define QWAYLANDQTSHELL_P_H
+
+#include <QtWaylandCompositor/private/qwaylandshellsurface_p.h>
+#include <QtWaylandCompositor/QWaylandSurfaceRole>
+
+#include <QHash>
+
+#include "qwayland-server-qt-shell-unstable-v1.h"
+#include "qwaylandqtshell.h"
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandQtShellPrivate
+ : public QWaylandCompositorExtensionPrivate
+ , public QtWaylandServer::zqt_shell_v1
+{
+ Q_DECLARE_PUBLIC(QWaylandQtShell)
+
+public:
+ QWaylandQtShellPrivate();
+ static QWaylandQtShellPrivate *get(QWaylandQtShell *qtShell) { return qtShell->d_func(); }
+ void unregisterQtShellSurface(QWaylandQtShellSurface *qtShellSurface);
+
+ QList<QWaylandQtShellChrome *> m_chromes;
+
+protected:
+ void zqt_shell_v1_surface_create(Resource *resource, wl_resource *surface, uint32_t id) override;
+};
+
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandQtShellSurfacePrivate
+ : public QWaylandShellSurfacePrivate
+ , public QtWaylandServer::zqt_shell_surface_v1
+{
+ Q_DECLARE_PUBLIC(QWaylandQtShellSurface)
+
+public:
+ QWaylandQtShellSurfacePrivate();
+ static QWaylandQtShellSurfacePrivate *get(QWaylandQtShellSurface *qtShellSurface)
+ {
+ return qtShellSurface->d_func();
+ }
+
+ void updateFrameMargins();
+ void configure(uint windowState, const QRect &newGeometry);
+
+protected:
+ void zqt_shell_surface_v1_destroy_resource(Resource *resource) override;
+ void zqt_shell_surface_v1_destroy(Resource *resource) override;
+ void zqt_shell_surface_v1_reposition(Resource *resource, int32_t x, int32_t y) override;
+ void zqt_shell_surface_v1_set_size(Resource *resource, int32_t width, int32_t height) override;
+ void zqt_shell_surface_v1_set_minimum_size(Resource *resource, int32_t width, int32_t height) override;
+ void zqt_shell_surface_v1_set_maximum_size(Resource *resource, int32_t width, int32_t height) override;
+ void zqt_shell_surface_v1_set_window_title(Resource *resource, const QString &title) override;
+ void zqt_shell_surface_v1_set_window_flags(Resource *resource, uint32_t flags) override;
+ void zqt_shell_surface_v1_change_window_state(Resource *resource, uint32_t state) override;
+ void zqt_shell_surface_v1_ack_configure(Resource *resource, uint32_t serial) override;
+
+ void zqt_shell_surface_v1_start_system_resize(Resource *resource, uint32_t serial, uint32_t edge) override;
+ void zqt_shell_surface_v1_start_system_move(Resource *resource, uint32_t serial) override;
+
+ void zqt_shell_surface_v1_raise(Resource *resource) override;
+ void zqt_shell_surface_v1_lower(Resource *resource) override;
+
+ void zqt_shell_surface_v1_request_activate(Resource *resource) override;
+
+private:
+ QWaylandQtShell *m_qtShell = nullptr;
+ QWaylandSurface *m_surface = nullptr;
+ QRect m_windowGeometry;
+ QSize m_minimumSize;
+ QSize m_maximumSize;
+ uint m_windowFlags = 0;
+ uint m_windowState = 0;
+ QString m_windowTitle;
+ QMargins m_frameMargins;
+ bool m_positionSet = false;
+ bool m_active = false;
+
+ QPoint m_pendingPosition;
+ bool m_pendingPositionValid = false;
+ QSize m_pendingSize;
+
+ uint32_t m_lastAckedConfigure = UINT32_MAX;
+ QMap<uint32_t, QPair<uint, QRect> > m_pendingConfigures;
+
+ QWaylandQtShellSurface::CapabilityFlags m_capabilities;
+
+ static QWaylandSurfaceRole s_role;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQTSHELL_P_H
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp b/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp
new file mode 100644
index 000000000..ffccf5d21
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp
@@ -0,0 +1,1500 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwaylandqtshellchrome.h"
+#include "qwaylandqtshellchrome_p.h"
+#include "qwaylandqtshell.h"
+
+#include <QtWaylandCompositor/qwaylandquickshellsurfaceitem.h>
+
+QT_BEGIN_NAMESPACE
+
+QPointF QWaylandQtShellChromePrivate::constrainPoint(const QPointF &point) const
+{
+ float x0 = maximizedRect.left();
+ float y0 = maximizedRect.top();
+ float x1 = maximizedRect.right();
+ float y1 = maximizedRect.bottom();
+ return QPoint(qBound(x0, point.x(), x1),
+ qBound(y0, point.y(), y1));
+}
+
+void QWaylandQtShellChromePrivate::updateDecorationInteraction(quint8 flags,
+ const QQuickHandlerPoint &centroid)
+{
+ if (shellSurface == nullptr)
+ return;
+
+ if (decorationInteraction == quint8(DecorationInteraction::None)) {
+ decorationInteraction = flags;
+ decorationInteractionPosition = centroid.scenePressPosition();
+ decorationInteractionGeometry = shellSurface->windowGeometry();
+ }
+
+ if (decorationInteraction != flags)
+ return;
+
+ QPointF position = constrainPoint(centroid.scenePosition());
+ float dx = position.x() - decorationInteractionPosition.x();
+ float dy = position.y() - decorationInteractionPosition.y();
+
+ float minWidth = qMax(0, shellSurface->minimumSize().width());
+ float minHeight = qMax(0, shellSurface->minimumSize().height());
+
+ float maxWidth = shellSurface->maximumSize().width();
+ float maxHeight = shellSurface->maximumSize().height();
+
+ float minX = maxWidth >= 0.0f
+ ? decorationInteractionGeometry.right() - maxWidth
+ : -FLT_MAX;
+ float minY = maxHeight >= 0.0f
+ ? decorationInteractionGeometry.bottom() - maxHeight
+ : -FLT_MAX;
+ float maxX = maxWidth >= 0
+ ? decorationInteractionGeometry.left() + maxWidth
+ : FLT_MAX;
+ float maxY = maxHeight >= 0.0f
+ ? decorationInteractionGeometry.top() + maxHeight
+ : FLT_MAX;
+
+ float newLeft = decorationInteractionGeometry.left();
+ if (flags & quint8(DecorationInteraction::WestBound)) {
+ newLeft = qBound(minX,
+ newLeft + dx,
+ float(decorationInteractionGeometry.right() - minWidth));
+ }
+
+ float newTop = decorationInteractionGeometry.top();
+ if (flags & quint8(DecorationInteraction::NorthBound)) {
+ newTop = qBound(minY,
+ newTop + dy,
+ decorationInteractionGeometry.bottom() + minHeight);
+ }
+
+ float newRight = decorationInteractionGeometry.right();
+ if (flags & quint8(DecorationInteraction::EastBound)) {
+ newRight = qBound(decorationInteractionGeometry.left() + minWidth,
+ newRight + dx,
+ maxX);
+ }
+
+ float newBottom = decorationInteractionGeometry.bottom();
+ if (flags & quint8(DecorationInteraction::SouthBound)) {
+ newBottom = qBound(decorationInteractionGeometry.top() + minHeight,
+ newBottom + dy,
+ maxY);
+ }
+
+ shellSurface->requestWindowGeometry(shellSurface->windowState(),
+ QRect(int(newLeft), int(newTop),
+ int(newRight - newLeft), int(newBottom - newTop)));
+}
+
+/*!
+ * \qmltype QtShellChrome
+ * \instantiates QWaylandQtShellChrome
+ * \inqmlmodule QtWayland.Compositor.QtShell
+ * \since 6.3
+ * \brief Provides default window manager functionality for use with the \c qt-shell extension.
+ *
+ * The QtShellChrome is a convenience type that can be used to provide window manager functionality
+ * to the interaction with clients over the \c qt-shell
+ * \l{Shell Extensions - Qt Wayland Compositor}{shell extension protocol}.
+ *
+ * Given a ShellSurfaceItem with an associated QtShellSurface, the item will automatically adapt
+ * its size to match the surface. It will also provide automatic handling of:
+ * \list
+ * \li Window states, such as maximized, minimized and fullscreen.
+ * \li Window activation.
+ * \li Window resizing using with resize handles (if the appropriate properties are set.)
+ * \li Window repositioning using title bar interaction (if the \l titleBar property is set.)
+ * \endlist
+ *
+ * The QtShellChrome is intended to be used together with QtShell and QtShellSurface.
+ *
+ * \sa {QtShell Compositor}
+ */
+QWaylandQtShellChrome::QWaylandQtShellChrome(QQuickItem *parent)
+ : QQuickItem(*new QWaylandQtShellChromePrivate{}, parent)
+{
+ init();
+}
+
+QWaylandQtShellChrome::QWaylandQtShellChrome(QWaylandQtShellChromePrivate &dd,
+ QQuickItem *parent)
+ : QQuickItem(dd, parent)
+{
+ init();
+}
+
+QWaylandQtShellChrome::~QWaylandQtShellChrome()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shell != nullptr)
+ d->shell->unregisterChrome(this);
+}
+
+void QWaylandQtShellChrome::init()
+{
+ connect(this, &QWaylandQtShellChrome::currentWindowStateChanged,
+ this, &QWaylandQtShellChrome::windowMetaInfoChanged);
+
+ connect(this, &QWaylandQtShellChrome::currentWindowFlagsChanged,
+ this, &QWaylandQtShellChrome::windowMetaInfoChanged);
+
+ connect(this, &QWaylandQtShellChrome::windowMetaInfoChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ connect(this, &QWaylandQtShellChrome::leftResizeHandleChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ connect(this, &QWaylandQtShellChrome::rightResizeHandleChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ connect(this, &QWaylandQtShellChrome::topResizeHandleChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ connect(this, &QWaylandQtShellChrome::bottomResizeHandleChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ connect(this, &QWaylandQtShellChrome::topLeftResizeHandleChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ connect(this, &QWaylandQtShellChrome::bottomLeftResizeHandleChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ connect(this, &QWaylandQtShellChrome::topRightResizeHandleChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ connect(this, &QWaylandQtShellChrome::bottomRightResizeHandleChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+}
+
+/*!
+ * \qmlmethod void QtShellChrome::toggleFullScreen()
+ *
+ * Toggles between fullscreen and normal window states. This method also clears the minimized
+ * or maximized window states if either is set.
+ */
+void QWaylandQtShellChrome::toggleFullScreen()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return;
+
+ uint newState;
+ if ((d->shellSurface->windowState() & Qt::WindowFullScreen) == Qt::WindowFullScreen)
+ newState = d->currentState & ~Qt::WindowFullScreen;
+ else
+ newState = d->currentState | Qt::WindowFullScreen;
+
+ if ((newState & (Qt::WindowMinimized | Qt::WindowMaximized)) != 0)
+ newState &= ~(Qt::WindowMinimized | Qt::WindowMaximized);
+
+ setWindowState(newState);
+}
+
+/*!
+ * \qmlmethod void QtShellChrome::toggleMaximized()
+ *
+ * Toggles between maximized and normal states. This method also clears the minimized
+ * window state if it is set.
+ */
+void QWaylandQtShellChrome::toggleMaximized()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return;
+
+ uint newState;
+ if ((d->shellSurface->windowState() & Qt::WindowMaximized) == Qt::WindowMaximized)
+ newState = d->currentState & ~Qt::WindowMaximized;
+ else
+ newState = d->currentState | Qt::WindowMaximized;
+
+ if ((newState & Qt::WindowMinimized) == Qt::WindowMinimized)
+ newState &= ~Qt::WindowMinimized;
+
+ setWindowState(newState);
+}
+
+/*!
+ * \qmlmethod void QtShellChrome::toggleMinimized()
+ *
+ * Toggles between minimized and normal states. This method also clears the maximized
+ * window state if it is set.
+ */
+void QWaylandQtShellChrome::toggleMinimized()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return;
+
+ uint newState;
+ if ((d->shellSurface->windowState() & Qt::WindowMinimized) == Qt::WindowMinimized)
+ newState = d->currentState & ~Qt::WindowMinimized;
+ else
+ newState = d->currentState | Qt::WindowMinimized;
+
+ if ((newState & Qt::WindowMaximized) == Qt::WindowMaximized)
+ newState &= ~Qt::WindowMaximized;
+
+ setWindowState(newState);
+}
+
+/*!
+ * \qmlproperty ShellSurfaceItem QtShellChrome::shellSurfaceItem
+ *
+ * This property holds the shell surface item associated with this QtShellChrome. It will
+ * in turn manage the \c shellSurface of this item. The \c shellSurface of the item is expected to
+ * be of the type QtShellSurface.
+ *
+ * \qml
+ * QtShellChrome {
+ * id: chrome
+ * ShellSurfaceItem {
+ * id: sfi
+ * anchors.fill: parent
+ * moveItem: chrome
+ * }
+ * shellSurfaceItem: sfi
+ * }
+ * \endqml
+ */
+void QWaylandQtShellChrome::setShellSurfaceItem(QWaylandQuickShellSurfaceItem *shellSurfaceItem)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurfaceItem == shellSurfaceItem)
+ return;
+
+ if (d->shellSurfaceItem != nullptr)
+ d->shellSurfaceItem->disconnect(this);
+
+ d->shellSurfaceItem = shellSurfaceItem;
+
+ if (d->shellSurfaceItem != nullptr) {
+ connect(d->shellSurfaceItem, &QWaylandQuickShellSurfaceItem::shellSurfaceChanged,
+ this, &QWaylandQtShellChrome::updateShellSurface);
+ connect(d->shellSurfaceItem, &QWaylandQuickShellSurfaceItem::surfaceDestroyed,
+ this, &QWaylandQtShellChrome::clientDestroyed);
+ }
+
+ updateShellSurface();
+ emit shellSurfaceItemChanged();
+}
+
+QWaylandQuickShellSurfaceItem *QWaylandQtShellChrome::shellSurfaceItem() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->shellSurfaceItem;
+}
+
+void QWaylandQtShellChrome::stopGrab()
+{
+ Q_D(QWaylandQtShellChrome);
+ d->decorationInteraction = quint8(QWaylandQtShellChromePrivate::DecorationInteraction::None);
+}
+
+void QWaylandQtShellChrome::leftResize()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->leftResizeHandleHandler->active())
+ return;
+
+ d->updateDecorationInteraction(quint8(QWaylandQtShellChromePrivate::DecorationInteraction::WestBound),
+ d->leftResizeHandleHandler->centroid());
+}
+
+void QWaylandQtShellChrome::rightResize()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->rightResizeHandleHandler->active())
+ return;
+
+ d->updateDecorationInteraction(quint8(QWaylandQtShellChromePrivate::DecorationInteraction::EastBound),
+ d->rightResizeHandleHandler->centroid());
+}
+
+void QWaylandQtShellChrome::topResize()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->topResizeHandleHandler->active())
+ return;
+
+ d->updateDecorationInteraction(quint8(QWaylandQtShellChromePrivate::DecorationInteraction::NorthBound),
+ d->topResizeHandleHandler->centroid());
+}
+
+void QWaylandQtShellChrome::bottomResize()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->bottomResizeHandleHandler->active())
+ return;
+
+ d->updateDecorationInteraction(quint8(QWaylandQtShellChromePrivate::DecorationInteraction::SouthBound),
+ d->bottomResizeHandleHandler->centroid());
+}
+
+void QWaylandQtShellChrome::topLeftResize()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->topLeftResizeHandleHandler->active())
+ return;
+
+ d->updateDecorationInteraction(quint8(QWaylandQtShellChromePrivate::DecorationInteraction::WestBound)
+ | quint8(QWaylandQtShellChromePrivate::DecorationInteraction::NorthBound),
+ d->topLeftResizeHandleHandler->centroid());
+}
+
+void QWaylandQtShellChrome::topRightResize()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->topRightResizeHandleHandler->active())
+ return;
+
+ d->updateDecorationInteraction(quint8(QWaylandQtShellChromePrivate::DecorationInteraction::EastBound)
+ | quint8(QWaylandQtShellChromePrivate::DecorationInteraction::NorthBound),
+ d->topRightResizeHandleHandler->centroid());
+}
+
+void QWaylandQtShellChrome::bottomLeftResize()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->bottomLeftResizeHandleHandler->active())
+ return;
+
+ d->updateDecorationInteraction(quint8(QWaylandQtShellChromePrivate::DecorationInteraction::WestBound)
+ | quint8(QWaylandQtShellChromePrivate::DecorationInteraction::SouthBound),
+ d->bottomLeftResizeHandleHandler->centroid());
+}
+
+void QWaylandQtShellChrome::bottomRightResize()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->bottomRightResizeHandleHandler->active())
+ return;
+
+ d->updateDecorationInteraction(quint8(QWaylandQtShellChromePrivate::DecorationInteraction::EastBound)
+ | quint8(QWaylandQtShellChromePrivate::DecorationInteraction::SouthBound),
+ d->bottomRightResizeHandleHandler->centroid());
+}
+
+void QWaylandQtShellChrome::titleBarMove()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->titleBarHandler->active())
+ return;
+
+ quint8 flags = quint8(QWaylandQtShellChromePrivate::DecorationInteraction::TitleBar);
+ QQuickHandlerPoint centroid = d->titleBarHandler->centroid();
+ if (d->decorationInteraction == quint8(QWaylandQtShellChromePrivate::DecorationInteraction::None)) {
+ d->decorationInteraction = flags;
+ d->decorationInteractionPosition = d->shellSurface->windowPosition() - centroid.scenePressPosition();
+
+ activate();
+ }
+
+ if (d->decorationInteraction != flags)
+ return;
+
+ QPointF position = d->constrainPoint(centroid.scenePosition());
+ d->shellSurface->setWindowPosition((position + d->decorationInteractionPosition).toPoint());
+}
+
+/*!
+ * \qmlproperty Item QtShellChrome::titleBar
+ *
+ * This property holds the default title bar item of the QtShellChrome. If set, a \l DragHandler
+ * will be installed on the title bar which moves the window around on user interaction. In
+ * addition, the window will automatically be activated if the title bar is clicked.
+ *
+ * The title bar will automatically hide and show, depending on the window flags and the
+ * window's full screen state.
+ *
+ * \qml
+ * QtShellChrome {
+ * Rectangle {
+ * id: tb
+ * anchors.top: parent.top
+ * anchors.right: parent.right
+ * anchors.left: parent.left
+ * height: 50
+ * color: "black"
+ *
+ * Text {
+ * color: "white"
+ * anchors.centerIn: parent
+ * text: shellSurfaceItem.shellSurface.windowTitle
+ * font.pixelSize: 25
+ * }
+ * }
+ * titleBar: tb
+ * }
+ * \endqml
+ *
+ * \note Unless explicit frame margins are set, the title bar's height will be included in the
+ * window's top frame margin.
+ */
+QQuickItem *QWaylandQtShellChrome::titleBar() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->titleBar;
+}
+
+void QWaylandQtShellChrome::setTitleBar(QQuickItem *item)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->titleBar == item)
+ return;
+
+ if (d->titleBar != nullptr) {
+ d->titleBar->disconnect(this);
+
+ delete d->titleBarHandler;
+ d->titleBarHandler = nullptr;
+ }
+
+ d->titleBar = item;
+
+ if (d->titleBar != nullptr) {
+ connect(d->titleBar, &QQuickItem::heightChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ d->titleBarHandler = new QQuickDragHandler(d->titleBar);
+ d->titleBarHandler->setTarget(nullptr);
+
+ connect(d->titleBarHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::stopGrab);
+ connect(d->titleBarHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::activateOnGrab);
+ connect(d->titleBarHandler, &QQuickMultiPointHandler::centroidChanged,
+ this, &QWaylandQtShellChrome::titleBarMove);
+ }
+
+ emit titleBarChanged();
+}
+
+/*!
+ * \qmlproperty Item QtShellChrome::leftResizeHandle
+ *
+ * This property holds the default left resize handle of the QtShellChrome. If set, a \l DragHandler
+ * will be installed on the resize handle which resizes the window by moving its left edge.
+ *
+ * The handle will automatically hide and show, depending on the window flags and the window's full
+ * screen state.
+ *
+ * \qml
+ * QtShellChrome {
+ * Rectangle {
+ * id: lrh
+ * anchors.left: parent.left
+ * anchors.top: parent.top
+ * anchors.bottom: parent.bottom
+ * width: 5
+ * color: "white"
+ * }
+ * leftResizeHandle: lrh
+ * }
+ * \endqml
+ *
+ * \note Unless explicit frame margins are set, the handle's width will be included in the
+ * window's left frame margin.
+ */
+QQuickItem *QWaylandQtShellChrome::leftResizeHandle() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->leftResizeHandle;
+}
+
+void QWaylandQtShellChrome::setLeftResizeHandle(QQuickItem *item)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->leftResizeHandle == item)
+ return;
+
+ if (d->leftResizeHandle != nullptr) {
+ d->leftResizeHandle->disconnect(this);
+
+ delete d->leftResizeHandleHandler;
+ d->leftResizeHandleHandler = nullptr;
+ }
+
+ d->leftResizeHandle = item;
+
+ if (d->leftResizeHandle != nullptr) {
+ connect(d->leftResizeHandle, &QQuickItem::widthChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ d->leftResizeHandleHandler = new QQuickDragHandler(d->leftResizeHandle);
+ d->leftResizeHandleHandler->setCursorShape(Qt::SizeHorCursor);
+ d->leftResizeHandleHandler->setTarget(nullptr);
+
+ connect(d->leftResizeHandleHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::stopGrab);
+ connect(d->leftResizeHandleHandler, &QQuickMultiPointHandler::centroidChanged,
+ this, &QWaylandQtShellChrome::leftResize);
+ }
+
+ emit leftResizeHandleChanged();
+}
+
+/*!
+ * \qmlproperty Item QtShellChrome::rightResizeHandle
+ *
+ * This property holds the default right resize handle of the QtShellChrome. If set, a \l DragHandler
+ * will be installed on the resize handle which resizes the window by moving its right edge.
+ *
+ * The handle will automatically hide and show, depending on the window flags and the window's full
+ * screen state.
+ *
+ * \qml
+ * QtShellChrome {
+ * Rectangle {
+ * id: rrh
+ * anchors.right: parent.right
+ * anchors.top: parent.top
+ * anchors.bottom: parent.bottom
+ * width: 5
+ * color: "white"
+ * }
+ * rightResizeHandle: rrh
+ * }
+ * \endqml
+ *
+ * \note Unless explicit frame margins are set, the handle's width will be included in the
+ * window's right frame margin.
+ */
+QQuickItem *QWaylandQtShellChrome::rightResizeHandle() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->rightResizeHandle;
+}
+
+void QWaylandQtShellChrome::setRightResizeHandle(QQuickItem *item)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->rightResizeHandle == item)
+ return;
+
+ if (d->rightResizeHandle != nullptr) {
+ d->rightResizeHandle->disconnect(this);
+
+ delete d->rightResizeHandleHandler;
+ d->rightResizeHandleHandler = nullptr;
+ }
+
+ d->rightResizeHandle = item;
+
+ if (d->rightResizeHandle != nullptr) {
+ connect(d->rightResizeHandle, &QQuickItem::widthChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ d->rightResizeHandleHandler = new QQuickDragHandler(d->rightResizeHandle);
+ d->rightResizeHandleHandler->setCursorShape(Qt::SizeHorCursor);
+ d->rightResizeHandleHandler->setTarget(nullptr);
+
+ connect(d->rightResizeHandleHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::stopGrab);
+ connect(d->rightResizeHandleHandler, &QQuickMultiPointHandler::centroidChanged,
+ this, &QWaylandQtShellChrome::rightResize);
+ }
+
+ emit rightResizeHandleChanged();
+}
+
+/*!
+ * \qmlproperty Item QtShellChrome::topResizeHandle
+ *
+ * This property holds the default top resize handle of the QtShellChrome. If set, a \l DragHandler
+ * will be installed on the resize handle which resizes the window by moving its top edge.
+ *
+ * The handle will automatically hide and show, depending on the window flags and the window's full
+ * screen state.
+ *
+ * \qml
+ * QtShellChrome {
+ * Rectangle {
+ * id: trh
+ * anchors.top: parent.top
+ * anchors.left: parent.left
+ * anchors.right: parent.right
+ * height: 5
+ * color: "white"
+ * }
+ * topResizeHandle: trh
+ * }
+ * \endqml
+ *
+ * \note Unless explicit frame margins are set, the handle's height will be included in the
+ * window's top frame margin.
+ */
+QQuickItem *QWaylandQtShellChrome::topResizeHandle() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->topResizeHandle;
+}
+
+void QWaylandQtShellChrome::setTopResizeHandle(QQuickItem *item)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->topResizeHandle == item)
+ return;
+
+ if (d->topResizeHandle != nullptr) {
+ d->topResizeHandle->disconnect(this);
+
+ delete d->topResizeHandleHandler;
+ d->topResizeHandleHandler = nullptr;
+ }
+
+ d->topResizeHandle = item;
+
+ if (d->topResizeHandle != nullptr) {
+ connect(d->topResizeHandle, &QQuickItem::heightChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ d->topResizeHandleHandler = new QQuickDragHandler(d->topResizeHandle);
+ d->topResizeHandleHandler->setCursorShape(Qt::SizeVerCursor);
+ d->topResizeHandleHandler->setTarget(nullptr);
+
+ connect(d->topResizeHandleHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::stopGrab);
+ connect(d->topResizeHandleHandler, &QQuickMultiPointHandler::centroidChanged,
+ this, &QWaylandQtShellChrome::topResize);
+ }
+
+ emit topResizeHandleChanged();
+}
+
+/*!
+ * \qmlproperty Item QtShellChrome::bottomResizeHandle
+ *
+ * This property holds the default bottom resize handle of the QtShellChrome. If set, a \l DragHandler
+ * will be installed on the resize handle which resizes the window by moving its bottom edge.
+ *
+ * The handle will automatically hide and show, depending on the window flags and the window's full
+ * screen state.
+ *
+ * \qml
+ * QtShellChrome {
+ * Rectangle {
+ * id: brh
+ * anchors.bottom: parent.bottom
+ * anchors.left: parent.left
+ * anchors.right: parent.right
+ * height: 5
+ * color: "white"
+ * }
+ * bottomResizeHandle: brh
+ * }
+ * \endqml
+ *
+ * \note Unless explicit frame margins are set, the handle's height will be included in the
+ * window's bottom frame margin.
+ */
+QQuickItem *QWaylandQtShellChrome::bottomResizeHandle() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->bottomResizeHandle;
+}
+
+void QWaylandQtShellChrome::setBottomResizeHandle(QQuickItem *item)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->bottomResizeHandle == item)
+ return;
+
+ if (d->bottomResizeHandle != nullptr) {
+ d->bottomResizeHandle->disconnect(this);
+
+ delete d->bottomResizeHandleHandler;
+ d->bottomResizeHandleHandler = nullptr;
+ }
+
+ d->bottomResizeHandle = item;
+
+ if (d->bottomResizeHandle != nullptr) {
+ connect(d->bottomResizeHandle, &QQuickItem::heightChanged,
+ this, &QWaylandQtShellChrome::updateDecorations);
+
+ d->bottomResizeHandleHandler = new QQuickDragHandler(d->bottomResizeHandle);
+ d->bottomResizeHandleHandler->setCursorShape(Qt::SizeVerCursor);
+ d->bottomResizeHandleHandler->setTarget(nullptr);
+
+ connect(d->bottomResizeHandleHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::stopGrab);
+ connect(d->bottomResizeHandleHandler, &QQuickMultiPointHandler::centroidChanged,
+ this, &QWaylandQtShellChrome::bottomResize);
+
+ }
+
+ emit bottomResizeHandleChanged();
+}
+
+/*!
+ * \qmlproperty Item QtShellChrome::topLeftResizeHandle
+ *
+ * This property holds the default top-left resize handle of the QtShellChrome. If set, a \l DragHandler
+ * will be installed on the resize handle which resizes the window by moving its top and left edges
+ * in equal amounts.
+ *
+ * The handle will automatically hide and show, depending on the window flags and the window's full
+ * screen state.
+ *
+ * \qml
+ * QtShellChrome {
+ * Rectangle {
+ * id: tlrh
+ * anchors.top: parent.top
+ * anchors.left: parent.left
+ * height: 5
+ * width: 5
+ * color: "white"
+ * }
+ * topLeftResizeHandle: tlrh
+ * }
+ * \endqml
+ */
+QQuickItem *QWaylandQtShellChrome::topLeftResizeHandle() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->topLeftResizeHandle;
+}
+
+void QWaylandQtShellChrome::setTopLeftResizeHandle(QQuickItem *item)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->topLeftResizeHandle == item)
+ return;
+
+ if (d->topLeftResizeHandle != nullptr) {
+ delete d->topLeftResizeHandleHandler;
+ d->topLeftResizeHandleHandler = nullptr;
+ }
+
+ d->topLeftResizeHandle = item;
+
+ if (d->topLeftResizeHandle != nullptr) {
+ d->topLeftResizeHandleHandler = new QQuickDragHandler(d->topLeftResizeHandle);
+ d->topLeftResizeHandleHandler->setCursorShape(Qt::SizeFDiagCursor);
+ d->topLeftResizeHandleHandler->setTarget(nullptr);
+
+ connect(d->topLeftResizeHandleHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::stopGrab);
+ connect(d->topLeftResizeHandleHandler, &QQuickMultiPointHandler::centroidChanged,
+ this, &QWaylandQtShellChrome::topLeftResize);
+ }
+
+ emit topLeftResizeHandleChanged();
+}
+
+/*!
+ * \qmlproperty Item QtShellChrome::bottomLeftResizeHandle
+ *
+ * This property holds the default bottom-left resize handle of the QtShellChrome. If set, a \l DragHandler
+ * will be installed on the resize handle which resizes the window by moving its bottom and left edges
+ * in equal amounts.
+ *
+ * The handle will automatically hide and show, depending on the window flags and the window's full
+ * screen state.
+ *
+ * \qml
+ * QtShellChrome {
+ * Rectangle {
+ * id: blrh
+ * anchors.bottom: parent.bottom
+ * anchors.left: parent.left
+ * height: 5
+ * width: 5
+ * color: "white"
+ * }
+ * bottomLeftResizeHandle: blrh
+ * }
+ * \endqml
+ */
+QQuickItem *QWaylandQtShellChrome::bottomLeftResizeHandle() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->bottomLeftResizeHandle;
+}
+
+void QWaylandQtShellChrome::setBottomLeftResizeHandle(QQuickItem *item)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->bottomLeftResizeHandle == item)
+ return;
+
+ if (d->bottomLeftResizeHandle != nullptr) {
+ delete d->bottomLeftResizeHandleHandler;
+ d->bottomLeftResizeHandleHandler = nullptr;
+ }
+
+ d->bottomLeftResizeHandle = item;
+
+ if (d->bottomLeftResizeHandle != nullptr) {
+ d->bottomLeftResizeHandleHandler = new QQuickDragHandler(d->bottomLeftResizeHandle);
+ d->bottomLeftResizeHandleHandler->setCursorShape(Qt::SizeBDiagCursor);
+ d->bottomLeftResizeHandleHandler->setTarget(nullptr);
+
+ connect(d->bottomLeftResizeHandleHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::stopGrab);
+ connect(d->bottomLeftResizeHandleHandler, &QQuickMultiPointHandler::centroidChanged,
+ this, &QWaylandQtShellChrome::bottomLeftResize);
+ }
+
+ emit bottomLeftResizeHandleChanged();
+}
+
+/*!
+ * \qmlproperty Item QtShellChrome::topRightResizeHandle
+ *
+ * This property holds the default top-right resize handle of the QtShellChrome. If set, a \l DragHandler
+ * will be installed on the resize handle which resizes the window by moving its top and right edges
+ * in equal amounts.
+ *
+ * The handle will automatically hide and show, depending on the window flags and the window's full
+ * screen state.
+ *
+ * \qml
+ * QtShellChrome {
+ * Rectangle {
+ * id: trrh
+ * anchors.top: parent.top
+ * anchors.right: parent.right
+ * height: 5
+ * width: 5
+ * color: "white"
+ * }
+ * topRightResizeHandle: trrh
+ * }
+ * \endqml
+ */
+QQuickItem *QWaylandQtShellChrome::topRightResizeHandle() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->topRightResizeHandle;
+}
+
+void QWaylandQtShellChrome::setTopRightResizeHandle(QQuickItem *item)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->topRightResizeHandle == item)
+ return;
+
+ if (d->topRightResizeHandle != nullptr) {
+ delete d->topRightResizeHandleHandler;
+ d->topRightResizeHandleHandler = nullptr;
+ }
+
+ d->topRightResizeHandle = item;
+
+ if (d->topRightResizeHandle != nullptr) {
+ d->topRightResizeHandleHandler = new QQuickDragHandler(d->topRightResizeHandle);
+ d->topRightResizeHandleHandler->setCursorShape(Qt::SizeBDiagCursor);
+ d->topRightResizeHandleHandler->setTarget(nullptr);
+
+ connect(d->topRightResizeHandleHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::stopGrab);
+ connect(d->topRightResizeHandleHandler, &QQuickMultiPointHandler::centroidChanged,
+ this, &QWaylandQtShellChrome::topRightResize);
+ }
+
+ emit topRightResizeHandleChanged();
+}
+
+/*!
+ * \qmlproperty Item QtShellChrome::bottomRightResizeHandle
+ *
+ * This property holds the default bottom-right resize handle of the QtShellChrome. If set, a \l DragHandler
+ * will be installed on the resize handle which resizes the window by moving its bottom and right edges
+ * in equal amounts.
+ *
+ * The handle will automatically hide and show, depending on the window flags and the window's full
+ * screen state.
+ *
+ * \qml
+ * QtShellChrome {
+ * Rectangle {
+ * id: brrh
+ * anchors.bottom: parent.bottom
+ * anchors.right: parent.right
+ * height: 5
+ * width: 5
+ * color: "white"
+ * }
+ * bottomRightResizeHandle: brrh
+ * }
+ * \endqml
+ */
+QQuickItem *QWaylandQtShellChrome::bottomRightResizeHandle() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->bottomRightResizeHandle;
+}
+
+void QWaylandQtShellChrome::setBottomRightResizeHandle(QQuickItem *item)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->bottomRightResizeHandle == item)
+ return;
+
+ if (d->bottomRightResizeHandle != nullptr) {
+ delete d->bottomRightResizeHandleHandler;
+ d->bottomRightResizeHandleHandler = nullptr;
+ }
+
+ d->bottomRightResizeHandle = item;
+
+ if (d->bottomRightResizeHandle != nullptr) {
+ d->bottomRightResizeHandleHandler = new QQuickDragHandler(d->bottomRightResizeHandle);
+ d->bottomRightResizeHandleHandler->setCursorShape(Qt::SizeFDiagCursor);
+ d->bottomRightResizeHandleHandler->setTarget(nullptr);
+
+ connect(d->bottomRightResizeHandleHandler, &QQuickPointerHandler::grabChanged,
+ this, &QWaylandQtShellChrome::stopGrab);
+ connect(d->bottomRightResizeHandleHandler, &QQuickMultiPointHandler::centroidChanged,
+ this, &QWaylandQtShellChrome::bottomRightResize);
+ }
+
+ emit bottomRightResizeHandleChanged();
+}
+
+/*!
+ * \qmlproperty rect QtShellChrome::maximizedRect
+ *
+ * This property holds the are of the WaylandOutput which is available to be filled by the
+ * window when it is in maximized state. By default, the window will fill the entire geometry
+ * of the WaylandOutput when it is maximized. Changing it can be useful for example when the
+ * compositor has other system UI which should not be obscured by maximized applications, such as
+ * a task bar.
+ */
+void QWaylandQtShellChrome::setMaximizedRect(const QRect &rect)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->maximizedRect == rect)
+ return;
+
+ d->maximizedRect = rect;
+ emit maximizedRectChanged();
+}
+
+QRect QWaylandQtShellChrome::maximizedRect() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ if (d->maximizedRect.isValid())
+ return d->maximizedRect;
+ else if (d->shellSurfaceItem != nullptr && d->shellSurfaceItem->output() != nullptr)
+ return d->shellSurfaceItem->output()->geometry();
+
+ return QRect{};
+}
+
+void QWaylandQtShellChrome::updateDecorations()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return;
+
+ bool decorations = hasDecorations();
+ bool titleBarShowing = hasTitleBar();
+
+ QMargins margins;
+ if (d->automaticFrameMargins) {
+ if (d->leftResizeHandle != nullptr && decorations)
+ margins.setLeft(d->leftResizeHandle->width());
+ if (d->rightResizeHandle != nullptr && decorations)
+ margins.setRight(d->rightResizeHandle->width());
+ if (d->bottomResizeHandle != nullptr && decorations)
+ margins.setBottom(d->bottomResizeHandle->height());
+
+ margins.setTop((decorations && d->topResizeHandle != nullptr ? d->topResizeHandle->height() : 0)
+ + (titleBarShowing && d->titleBar != nullptr ? d->titleBar->height() : 0));
+ } else {
+ margins = d->explicitFrameMargins;
+ }
+ d->shellSurface->setFrameMargins(margins);
+
+ if (d->titleBar != nullptr)
+ d->titleBar->setVisible(titleBarShowing);
+ if (d->leftResizeHandle != nullptr)
+ d->leftResizeHandle->setVisible(decorations);
+ if (d->rightResizeHandle != nullptr)
+ d->rightResizeHandle->setVisible(decorations);
+ if (d->topResizeHandle != nullptr)
+ d->topResizeHandle->setVisible(decorations);
+ if (d->bottomResizeHandle != nullptr)
+ d->bottomResizeHandle->setVisible(decorations);
+ if (d->bottomLeftResizeHandle != nullptr)
+ d->bottomLeftResizeHandle->setVisible(decorations);
+ if (d->topLeftResizeHandle != nullptr)
+ d->topLeftResizeHandle->setVisible(decorations);
+ if (d->bottomRightResizeHandle != nullptr)
+ d->bottomRightResizeHandle->setVisible(decorations);
+ if (d->topRightResizeHandle != nullptr)
+ d->topRightResizeHandle->setVisible(decorations);
+
+ bool minimizedOrMaximized = (d->currentState & (Qt::WindowMaximized|Qt::WindowMinimized)) != 0;
+ if (d->leftResizeHandleHandler != nullptr)
+ d->leftResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
+ if (d->rightResizeHandleHandler != nullptr)
+ d->rightResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
+ if (d->bottomResizeHandleHandler != nullptr)
+ d->bottomResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
+ if (d->topResizeHandleHandler != nullptr)
+ d->topResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
+ if (d->bottomLeftResizeHandleHandler != nullptr)
+ d->bottomLeftResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
+ if (d->bottomRightResizeHandleHandler != nullptr)
+ d->bottomRightResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
+ if (d->topLeftResizeHandleHandler != nullptr)
+ d->topLeftResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
+ if (d->topRightResizeHandleHandler != nullptr)
+ d->topRightResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
+ if (d->titleBarHandler != nullptr)
+ d->titleBarHandler->setEnabled(titleBarShowing && !minimizedOrMaximized);
+}
+
+void QWaylandQtShellChrome::updateGeometry()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return;
+
+ QRect windowGeometry = d->shellSurface->windowGeometry();
+
+ QPointF position = windowGeometry.topLeft();
+ position.rx() -= d->shellSurface->frameMarginLeft();
+ position.ry() -= d->shellSurface->frameMarginTop();
+
+ QSizeF size = windowGeometry.size();
+ size.rwidth() += d->shellSurface->frameMarginLeft() + d->shellSurface->frameMarginRight();
+ size.rheight() += d->shellSurface->frameMarginTop() + d->shellSurface->frameMarginBottom();
+
+ setPosition(position);
+ setSize(size);
+}
+
+void QWaylandQtShellChrome::updateSurface()
+{
+ Q_D(QWaylandQtShellChrome);
+ QWaylandSurface *surface = d->shellSurface != nullptr ? d->shellSurface->surface() : nullptr;
+ if (d->surface == surface)
+ return;
+
+ if (d->surface != nullptr)
+ d->surface->disconnect(this);
+
+ d->surface = surface;
+
+ if (d->surface != nullptr) {
+ connect(d->surface, &QWaylandSurface::hasContentChanged,
+ this, &QWaylandQtShellChrome::updateAutomaticPosition);
+ }
+}
+
+void QWaylandQtShellChrome::updateShellSurface()
+{
+ Q_D(QWaylandQtShellChrome);
+ QWaylandQtShellSurface *sf = d->shellSurfaceItem != nullptr
+ ? qobject_cast<QWaylandQtShellSurface *>(d->shellSurfaceItem->shellSurface())
+ : nullptr;
+ if (d->shellSurface == sf)
+ return;
+
+ if (d->shellSurface != nullptr) {
+ d->shellSurface->disconnect(this);
+ if (d->shell != nullptr)
+ d->shell->unregisterChrome(this);
+ d->shell = nullptr;
+ }
+
+ d->shellSurface = sf;
+ if (d->shellSurface != nullptr) {
+ d->shell = d->shellSurface->shell();
+ if (d->shell != nullptr)
+ d->shell->registerChrome(this);
+
+ updateWindowFlags();
+ connect(d->shellSurface, &QWaylandQtShellSurface::windowFlagsChanged,
+ this, &QWaylandQtShellChrome::updateWindowFlags);
+ connect(d->shellSurface, &QWaylandQtShellSurface::windowStateChanged,
+ this, &QWaylandQtShellChrome::updateWindowState);
+ connect(d->shellSurface, &QWaylandQtShellSurface::frameMarginChanged,
+ this, &QWaylandQtShellChrome::updateGeometry);
+ connect(d->shellSurface, &QWaylandQtShellSurface::windowGeometryChanged,
+ this, &QWaylandQtShellChrome::updateGeometry);
+ connect(d->shellSurface, &QWaylandQtShellSurface::raiseRequested,
+ this, &QWaylandQtShellChrome::raise);
+ connect(d->shellSurface, &QWaylandQtShellSurface::lowerRequested,
+ this, &QWaylandQtShellChrome::lower);
+ connect(d->shellSurface, &QWaylandQtShellSurface::activeChanged,
+ this, &QWaylandQtShellChrome::updateActiveState);
+ connect(d->shellSurface, &QWaylandQtShellSurface::surfaceChanged,
+ this, &QWaylandQtShellChrome::updateSurface);
+ }
+
+ updateDecorations();
+ updateSurface();
+}
+
+void QWaylandQtShellChrome::updateWindowState()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return;
+
+ setWindowState(d->shellSurface->windowState());
+}
+
+void QWaylandQtShellChrome::updateWindowFlags()
+{
+ Q_D(QWaylandQtShellChrome);
+
+ uint nextFlags = d->shellSurface == nullptr || d->shellSurface->windowFlags() == Qt::Window
+ ? d->defaultFlags
+ : d->shellSurface->windowFlags();
+
+ if (d->currentFlags != nextFlags) {
+ d->currentFlags = nextFlags;
+ emit currentWindowFlagsChanged();
+ }
+}
+
+/*!
+ * \qmlproperty int QtShellChrome::windowFlags
+ *
+ * This property holds the window flags of the QtShellChrome. They will match the \c windowFlags
+ * property of the associated QtShellSurface, except when this is equal to Qt.Window. In this case,
+ * a set of default window flags will be used instead. The default window flags are Qt.Window,
+ * Qt.WindowMaximizeButtonHint, Qt.WindowMinimizeButtonHint and Qt.WindowCloseButtonHint.
+ */
+uint QWaylandQtShellChrome::currentWindowFlags() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->currentFlags;
+}
+
+/*!
+ * \qmlproperty int QtShellChrome::windowState
+ *
+ * This property holds the window state of the shell surface. It will be updated immediately when
+ * the window state is requested on the compositor-side, before this has been acknowledged by the
+ * client. Therefore, it may in brief periods differ from the shell surface's \c windowState
+ * property, which will be updated when the client has acknowledged the request.
+ */
+uint QWaylandQtShellChrome::currentWindowState() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ return d->currentState;
+}
+
+bool QWaylandQtShellChrome::hasTitleBar() const
+{
+ Q_D(const QWaylandQtShellChrome);
+
+ bool frameless = (d->currentFlags & Qt::FramelessWindowHint) == Qt::FramelessWindowHint
+ || ((d->currentFlags & Qt::Popup) == Qt::Popup
+ && (d->currentFlags & Qt::Tool) != Qt::Tool)
+ || (d->currentState & Qt::WindowFullScreen) == Qt::WindowFullScreen;
+ return !frameless;
+}
+
+/*!
+ * \qmlproperty bool QtShellChrome::hasDecorations
+ *
+ * This property is true if the QtShellChrome's decorations should be visible, based on its window
+ * state and window flags.
+ */
+bool QWaylandQtShellChrome::hasDecorations() const
+{
+ Q_D(const QWaylandQtShellChrome);
+
+ return hasTitleBar() && (d->currentFlags & Qt::Window) == Qt::Window;
+}
+
+QRect QWaylandQtShellChrome::maxContentRect() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return QRect{};
+
+ int x0 = d->maximizedRect.x() + d->shellSurface->frameMarginLeft();
+ int x1 = d->maximizedRect.x() + d->maximizedRect.width() - d->shellSurface->frameMarginRight();
+ int y0 = d->maximizedRect.y() + d->shellSurface->frameMarginTop();
+ int y1 = d->maximizedRect.y() + d->maximizedRect.height() - d->shellSurface->frameMarginBottom();
+
+ return QRect(x0, y0, x1 - x0, y1 - y0);
+}
+
+static int randomPos(int windowSize, int screenSize)
+{
+ return (windowSize >= screenSize) ? 0 : rand() % (screenSize - windowSize);
+}
+
+void QWaylandQtShellChrome::setWindowState(uint nextState)
+{
+ Q_D(QWaylandQtShellChrome);
+
+ if (d->currentState == nextState)
+ return;
+
+ if (d->shellSurface == nullptr || d->shellSurfaceItem == nullptr)
+ return;
+
+ QWaylandOutput *output = d->shellSurfaceItem->output();
+ if (output == nullptr)
+ return;
+
+ if ((d->currentState & (Qt::WindowMinimized | Qt::WindowMaximized | Qt::WindowFullScreen)) == 0) {
+ d->restoreGeometry = d->shellSurface->windowGeometry();
+ }
+
+ d->currentState = nextState;
+ emit currentWindowStateChanged();
+
+ if ((nextState & Qt::WindowMinimized) != 0) {
+ d->shellSurface->requestWindowGeometry(nextState, QRect(0, 0, 1, 1));
+ d->shellSurfaceItem->setVisible(false);
+ deactivate();
+ } else if ((nextState & Qt::WindowFullScreen) != 0) {
+ d->shellSurfaceItem->setVisible(true);
+ d->shellSurface->requestWindowGeometry(nextState, QRect(QPoint(0, 0), output->window()->size()));
+ activate();
+ } else if ((nextState & Qt::WindowMaximized) != 0) {
+ d->shellSurfaceItem->setVisible(true);
+ d->shellSurface->requestWindowGeometry(nextState, maxContentRect());
+ activate();
+ } else {
+ d->shellSurfaceItem->setVisible(true);
+ d->shellSurface->requestWindowGeometry(nextState, d->restoreGeometry);
+ activate();
+ }
+}
+
+void QWaylandQtShellChrome::updateAutomaticPosition()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (!d->positionSet && d->shellSurface != nullptr) {
+ bool randomize = d->shellSurface->positionAutomatic();
+ QRect rect = d->shellSurface->windowGeometry();
+ QRect space = maxContentRect();
+
+ int xpos = randomize ? randomPos(rect.width(), space.width()) + space.x()
+ : qMax(rect.x(), space.x());
+ int ypos = randomize ? randomPos(rect.height(), space.height()) + space.y()
+ : qMax(rect.y(), space.y());
+
+ d->shellSurface->setWindowPosition(QPoint(xpos, ypos));
+ d->positionSet = true;
+ }
+}
+
+/*!
+ * \qmlmethod void QtShellChrome::deactivate()
+ *
+ * Manually deactivates this window. If the window was active, this will activate the next window in
+ * the stack instead.
+ */
+void QWaylandQtShellChrome::deactivate()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurface != nullptr)
+ d->shellSurface->setActive(false);
+}
+
+void QWaylandQtShellChrome::activateOnGrab(QPointingDevice::GrabTransition transition)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->titleBarHandler != nullptr) {
+ switch (transition) {
+ case QPointingDevice::GrabPassive:
+ case QPointingDevice::OverrideGrabPassive:
+ case QPointingDevice::GrabExclusive:
+ activate();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*!
+ * \qmlmethod void QtShellChrome::activate()
+ *
+ * Manually activate this window. This will also raise the window.
+ *
+ * \sa raise()
+ */
+void QWaylandQtShellChrome::activate()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurface != nullptr)
+ d->shellSurface->setActive(true);
+ raise();
+}
+
+/*!
+ * \qmlmethod void QtShellChrome::raise()
+ *
+ * Raise this window, so that it stacks on top of other windows (except if the other window's
+ * flags prohibit this.)
+ */
+void QWaylandQtShellChrome::raise()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurfaceItem != nullptr)
+ d->shellSurfaceItem->raise();
+}
+
+/*!
+ * \qmlmethod void QtShellChrome::lower()
+ *
+ * Lower this window, so that it stacks underneath other windows (except if the other window's
+ * window flags prohibit this.)
+ */
+void QWaylandQtShellChrome::lower()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurfaceItem != nullptr)
+ d->shellSurfaceItem->lower();
+}
+
+void QWaylandQtShellChrome::updateActiveState()
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return;
+
+ if (d->shellSurface->active()) {
+ raise();
+ emit activated();
+ } else {
+ emit deactivated();
+ }
+}
+
+/*!
+ * \qmlproperty int QtShellChrome::frameMarginLeft
+ *
+ * Sets the size of the left margin of the QtShellChrome which is reserved for window decorations.
+ * By default, this will equal the width of the \l leftResizeHandle if it is set. Otherwise it will
+ * be 0.
+ *
+ * \note By setting this property explicitly, all default frame margins will be overridden with
+ * their corresponding properties.
+ */
+void QWaylandQtShellChrome::setFrameMarginLeft(int left)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->explicitFrameMargins.left() == left)
+ return;
+
+ d->explicitFrameMargins.setLeft(left);
+ d->automaticFrameMargins = false;
+ updateDecorations();
+
+ emit frameMarginChanged();
+}
+
+int QWaylandQtShellChrome::frameMarginLeft() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return 0;
+ return d->shellSurface->frameMarginLeft();
+}
+
+/*!
+ * \qmlproperty int QtShellChrome::frameMarginRight
+ *
+ * Sets the size of the right margin of the QtShellChrome which is reserved for window decorations.
+ * By default, this will equal the width of the \l rightResizeHandle if it is set. Otherwise it will
+ * be 0.
+ *
+ * \note By setting this property explicitly, all default frame margins will be overridden with
+ * their corresponding properties.
+ */
+void QWaylandQtShellChrome::setFrameMarginRight(int right)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->explicitFrameMargins.right() == right)
+ return;
+
+ d->explicitFrameMargins.setRight(right);
+ d->automaticFrameMargins = false;
+ updateDecorations();
+
+ emit frameMarginChanged();
+}
+
+int QWaylandQtShellChrome::frameMarginRight() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return 0;
+ return d->shellSurface->frameMarginRight();
+}
+
+/*!
+ * \qmlproperty int QtShellChrome::frameMarginTop
+ *
+ * Sets the size of the top margin of the QtShellChrome which is reserved for window decorations.
+ * By default, this will equal the sum of the \l leftResizeHandle and the \l{titleBar}'s heights,
+ * if they are set. Otherwise it will be 0.
+ *
+ * \note By setting this property explicitly, all default frame margins will be overridden with
+ * their corresponding properties.
+ */
+void QWaylandQtShellChrome::setFrameMarginTop(int top)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->explicitFrameMargins.top() == top)
+ return;
+ d->explicitFrameMargins.setTop(top);
+ d->automaticFrameMargins = false;
+ updateDecorations();
+
+ emit frameMarginChanged();
+}
+
+int QWaylandQtShellChrome::frameMarginTop() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return 0;
+ return d->shellSurface->frameMarginTop();
+}
+
+/*!
+ * \qmlproperty int QtShellChrome::frameMarginBottom
+ *
+ * Sets the size of the bottom margin of the QtShellChrome which is reserved for window decorations.
+ * By default, this will equal the height of the \l bottomResizeHandle if it is set. Otherwise it will
+ * be 0.
+ *
+ * \note By setting this property explicitly, all default frame margins will be overridden with
+ * their corresponding properties.
+ */
+void QWaylandQtShellChrome::setFrameMarginBottom(int bottom)
+{
+ Q_D(QWaylandQtShellChrome);
+ if (d->explicitFrameMargins.bottom() == bottom)
+ return;
+ d->explicitFrameMargins.setBottom(bottom);
+ d->automaticFrameMargins = false;
+ updateDecorations();
+
+ emit frameMarginChanged();
+}
+
+int QWaylandQtShellChrome::frameMarginBottom() const
+{
+ Q_D(const QWaylandQtShellChrome);
+ if (d->shellSurface == nullptr)
+ return 0;
+ return d->shellSurface->frameMarginBottom();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwaylandqtshellchrome.cpp"
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.h b/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.h
new file mode 100644
index 000000000..4fb98008c
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.h
@@ -0,0 +1,157 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDQTSHELLCHROME_H
+#define QWAYLANDQTSHELLCHROME_H
+
+#include <QtQuick/qquickitem.h>
+#include <QtWaylandCompositor/qwaylandquickshellsurfaceitem.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandQtShellChromePrivate;
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandQtShellChrome : public QQuickItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(QtShellChrome)
+ QML_ADDED_IN_VERSION(1, 0)
+ Q_DECLARE_PRIVATE(QWaylandQtShellChrome)
+ Q_PROPERTY(bool hasDecorations READ hasDecorations NOTIFY windowMetaInfoChanged)
+ Q_PROPERTY(uint windowState READ currentWindowState NOTIFY currentWindowStateChanged)
+ Q_PROPERTY(uint windowFlags READ currentWindowFlags NOTIFY currentWindowFlagsChanged)
+ Q_PROPERTY(QWaylandQuickShellSurfaceItem *shellSurfaceItem READ shellSurfaceItem WRITE setShellSurfaceItem NOTIFY shellSurfaceItemChanged)
+ Q_PROPERTY(QRect maximizedRect READ maximizedRect WRITE setMaximizedRect NOTIFY maximizedRectChanged)
+
+ Q_PROPERTY(int frameMarginLeft READ frameMarginLeft WRITE setFrameMarginLeft NOTIFY frameMarginChanged)
+ Q_PROPERTY(int frameMarginRight READ frameMarginRight WRITE setFrameMarginRight NOTIFY frameMarginChanged)
+ Q_PROPERTY(int frameMarginTop READ frameMarginTop WRITE setFrameMarginTop NOTIFY frameMarginChanged)
+ Q_PROPERTY(int frameMarginBottom READ frameMarginBottom WRITE setFrameMarginBottom NOTIFY frameMarginChanged)
+
+ Q_PROPERTY(QQuickItem *titleBar READ titleBar WRITE setTitleBar NOTIFY titleBarChanged);
+ Q_PROPERTY(QQuickItem *leftResizeHandle READ leftResizeHandle WRITE setLeftResizeHandle NOTIFY leftResizeHandleChanged);
+ Q_PROPERTY(QQuickItem *rightResizeHandle READ rightResizeHandle WRITE setRightResizeHandle NOTIFY rightResizeHandleChanged);
+ Q_PROPERTY(QQuickItem *topResizeHandle READ topResizeHandle WRITE setTopResizeHandle NOTIFY topResizeHandleChanged);
+ Q_PROPERTY(QQuickItem *bottomResizeHandle READ bottomResizeHandle WRITE setBottomResizeHandle NOTIFY bottomResizeHandleChanged);
+ Q_PROPERTY(QQuickItem *topLeftResizeHandle READ topLeftResizeHandle WRITE setTopLeftResizeHandle NOTIFY topLeftResizeHandleChanged);
+ Q_PROPERTY(QQuickItem *topRightResizeHandle READ topRightResizeHandle WRITE setTopRightResizeHandle NOTIFY topRightResizeHandleChanged);
+ Q_PROPERTY(QQuickItem *bottomLeftResizeHandle READ bottomLeftResizeHandle WRITE setBottomLeftResizeHandle NOTIFY bottomLeftResizeHandleChanged);
+ Q_PROPERTY(QQuickItem *bottomRightResizeHandle READ bottomRightResizeHandle WRITE setBottomRightResizeHandle NOTIFY bottomRightResizeHandleChanged);
+public:
+ QWaylandQtShellChrome(QQuickItem *parent = nullptr);
+ ~QWaylandQtShellChrome() override;
+
+ bool hasTitleBar() const;
+ bool hasDecorations() const;
+ uint currentWindowState() const;
+ uint currentWindowFlags() const;
+
+ void setMaximizedRect(const QRect &rect);
+ QRect maximizedRect() const;
+
+ void setShellSurfaceItem(QWaylandQuickShellSurfaceItem *shellSurfaceItem);
+ QWaylandQuickShellSurfaceItem *shellSurfaceItem() const;
+
+ void setTitleBar(QQuickItem *item);
+ QQuickItem *titleBar() const;
+
+ void setLeftResizeHandle(QQuickItem *item);
+ QQuickItem *leftResizeHandle() const;
+
+ void setRightResizeHandle(QQuickItem *item);
+ QQuickItem *rightResizeHandle() const;
+
+ void setTopResizeHandle(QQuickItem *item);
+ QQuickItem *topResizeHandle() const;
+
+ void setBottomResizeHandle(QQuickItem *item);
+ QQuickItem *bottomResizeHandle() const;
+
+ void setTopLeftResizeHandle(QQuickItem *item);
+ QQuickItem *topLeftResizeHandle() const;
+
+ void setBottomLeftResizeHandle(QQuickItem *item);
+ QQuickItem *bottomLeftResizeHandle() const;
+
+ void setTopRightResizeHandle(QQuickItem *item);
+ QQuickItem *topRightResizeHandle() const;
+
+ void setBottomRightResizeHandle(QQuickItem *item);
+ QQuickItem *bottomRightResizeHandle() const;
+
+ int frameMarginLeft() const;
+ void setFrameMarginLeft(int left);
+
+ int frameMarginRight() const;
+ void setFrameMarginRight(int right);
+
+ int frameMarginTop() const;
+ void setFrameMarginTop(int top);
+
+ int frameMarginBottom() const;
+ void setFrameMarginBottom(int bottom);
+
+Q_SIGNALS:
+ void currentWindowStateChanged();
+ void currentWindowFlagsChanged();
+ void windowMetaInfoChanged();
+ void shellSurfaceItemChanged();
+ void maximizedRectChanged();
+
+ void titleBarChanged();
+ void leftResizeHandleChanged();
+ void rightResizeHandleChanged();
+ void topResizeHandleChanged();
+ void bottomResizeHandleChanged();
+ void topLeftResizeHandleChanged();
+ void bottomLeftResizeHandleChanged();
+ void topRightResizeHandleChanged();
+ void bottomRightResizeHandleChanged();
+
+ void activated();
+ void deactivated();
+
+ void clientDestroyed();
+ void frameMarginChanged();
+
+public Q_SLOTS:
+ void raise();
+ void lower();
+ void toggleMaximized();
+ void toggleMinimized();
+ void toggleFullScreen();
+ void activate();
+ void deactivate();
+
+private Q_SLOTS:
+ void activateOnGrab(QPointingDevice::GrabTransition transition);
+ void updateSurface();
+ void updateShellSurface();
+ void updateWindowFlags();
+ void updateWindowState();
+ void updateGeometry();
+ void updateDecorations();
+ void updateActiveState();
+ void updateAutomaticPosition();
+ void stopGrab();
+ void leftResize();
+ void rightResize();
+ void topResize();
+ void bottomResize();
+ void topLeftResize();
+ void topRightResize();
+ void bottomLeftResize();
+ void bottomRightResize();
+ void titleBarMove();
+
+protected:
+ QWaylandQtShellChrome(QWaylandQtShellChromePrivate &dd, QQuickItem *parent);
+
+private:
+ void setWindowState(uint nextState);
+ void init();
+ QRect maxContentRect() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQTSHELLSURFACEITEM_H
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome_p.h b/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome_p.h
new file mode 100644
index 000000000..b62225794
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome_p.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDQTSHELLCHROME_P_H
+#define QWAYLANDQTSHELLCHROME_P_H
+
+#include "qwaylandqtshell.h"
+
+#include <QtCore/qpointer.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickdraghandler_p.h>
+
+#include <QtWaylandCompositor/qwaylandquickshellsurfaceitem.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandQtShellChromePrivate : public QQuickItemPrivate
+{
+public:
+ void updateDecorationInteraction(quint8 flags, const QQuickHandlerPoint &centroid);
+ QPointF constrainPoint(const QPointF &point) const;
+
+ bool positionSet = false;
+ bool automaticFrameMargins = true;
+ QMargins explicitFrameMargins;
+
+ uint currentState = Qt::WindowNoState;
+ uint defaultFlags = Qt::Window
+ | Qt::WindowMaximizeButtonHint
+ | Qt::WindowMinimizeButtonHint
+ | Qt::WindowCloseButtonHint;
+ uint currentFlags = defaultFlags;
+ QRect restoreGeometry = QRect(0, 0, 100, 100);
+ QRect maximizedRect;
+ QPointer<QWaylandQuickShellSurfaceItem> shellSurfaceItem;
+ QPointer<QWaylandQtShellSurface> shellSurface;
+ QPointer<QWaylandSurface> surface;
+ QPointer<QWaylandQtShell> shell;
+
+ enum class DecorationInteraction : quint8 {
+ None = 0,
+ WestBound = 1,
+ EastBound = 2,
+ NorthBound = 4,
+ SouthBound = 8,
+ TitleBar = 16
+ };
+
+ quint8 decorationInteraction = quint8(DecorationInteraction::None);
+ QPointF decorationInteractionPosition;
+ QRect decorationInteractionGeometry;
+
+ QQuickItem *leftResizeHandle = nullptr;
+ QQuickDragHandler *leftResizeHandleHandler = nullptr;
+ QQuickDragHandler *rightResizeHandleHandler = nullptr;
+ QQuickDragHandler *topResizeHandleHandler = nullptr;
+ QQuickDragHandler *bottomResizeHandleHandler = nullptr;
+ QQuickDragHandler *topLeftResizeHandleHandler = nullptr;
+ QQuickDragHandler *topRightResizeHandleHandler = nullptr;
+ QQuickDragHandler *bottomLeftResizeHandleHandler = nullptr;
+ QQuickDragHandler *bottomRightResizeHandleHandler = nullptr;
+ QQuickDragHandler *titleBarHandler = nullptr;
+
+ QQuickItem *rightResizeHandle = nullptr;
+ QQuickItem *topResizeHandle = nullptr;
+ QQuickItem *bottomResizeHandle = nullptr;
+ QQuickItem *topLeftResizeHandle = nullptr;
+ QQuickItem *bottomLeftResizeHandle = nullptr;
+ QQuickItem *topRightResizeHandle = nullptr;
+ QQuickItem *bottomRightResizeHandle = nullptr;
+ QQuickItem *titleBar = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQTSHELLCHROME_P_H
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshellintegration.cpp b/src/imports/compositor-extensions/qtshell/qwaylandqtshellintegration.cpp
new file mode 100644
index 000000000..07a936322
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshellintegration.cpp
@@ -0,0 +1,39 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwaylandqtshellintegration_p.h"
+
+#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/QWaylandQuickShellSurfaceItem>
+#include <QtWaylandCompositor/QWaylandSeat>
+#include "qwaylandqtshell.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWayland {
+
+QtShellIntegration::QtShellIntegration(QWaylandQuickShellSurfaceItem *item)
+ : QWaylandQuickShellIntegration(item)
+ , m_item(item)
+ , m_shellSurface(qobject_cast<QWaylandQtShellSurface *>(item->shellSurface()))
+{
+ m_item->setSurface(m_shellSurface->surface());
+ connect(m_shellSurface, &QWaylandQtShellSurface::destroyed,
+ this, &QtShellIntegration::handleQtShellSurfaceDestroyed);
+}
+
+QtShellIntegration::~QtShellIntegration()
+{
+ m_item->setSurface(nullptr);
+}
+
+void QtShellIntegration::handleQtShellSurfaceDestroyed()
+{
+ m_shellSurface = nullptr;
+}
+
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwaylandqtshellintegration_p.cpp"
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshellintegration_p.h b/src/imports/compositor-extensions/qtshell/qwaylandqtshellintegration_p.h
new file mode 100644
index 000000000..ea9cac634
--- /dev/null
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshellintegration_p.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDQTSHELLINTEGRATION_H
+#define QWAYLANDQTSHELLINTEGRATION_H
+
+#include <QtWaylandCompositor/private/qwaylandquickshellsurfaceitem_p.h>
+
+#include "qwaylandqtshell.h"
+
+QT_BEGIN_NAMESPACE
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+namespace QtWayland {
+
+class QtShellIntegration : public QWaylandQuickShellIntegration
+{
+ Q_OBJECT
+public:
+ QtShellIntegration(QWaylandQuickShellSurfaceItem *item);
+ ~QtShellIntegration() override;
+
+private Q_SLOTS:
+ void handleQtShellSurfaceDestroyed();
+
+private:
+ QWaylandQuickShellSurfaceItem *m_item = nullptr;
+ QWaylandQtShellSurface *m_shellSurface = nullptr;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQTSHELLINTEGRATION_H
diff --git a/src/imports/compositor-extensions/wlshell/CMakeLists.txt b/src/imports/compositor-extensions/wlshell/CMakeLists.txt
new file mode 100644
index 000000000..8987621d3
--- /dev/null
+++ b/src/imports/compositor-extensions/wlshell/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_qml_module(WaylandCompositorWLShell
+ URI "QtWayland.Compositor.WlShell"
+ VERSION "${PROJECT_VERSION}"
+ SOURCES
+ qwaylandcompositorwlshell_p.h qwaylandcompositorwlshell.cpp
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::WaylandCompositor
+ NO_GENERATE_CPP_EXPORTS
+ PAST_MAJOR_VERSIONS 1
+)
+
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorWLShell WaylandCompositor)
diff --git a/src/imports/compositor-extensions/wlshell/qwaylandcompositorwlshell.cpp b/src/imports/compositor-extensions/wlshell/qwaylandcompositorwlshell.cpp
new file mode 100644
index 000000000..3d7e6a6f1
--- /dev/null
+++ b/src/imports/compositor-extensions/wlshell/qwaylandcompositorwlshell.cpp
@@ -0,0 +1,30 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwaylandcompositorwlshell_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlmodule QtWayland.Compositor.WlShell
+ \title Qt Wayland WlShell extension
+ \ingroup qmlmodules
+ \brief Provides a Qt API for the WlShell extension.
+
+ \section2 Summary
+ WlShell is a shell extension providing window system features typical to
+ desktop systems. It is superseded by XdgShell and exists in Qt mainly
+ for backwards compatibility with older applications.
+
+ WlShell corresponds to the Wayland interface \c wl_shell.
+
+ \section2 Usage
+ To use this module, import it like this:
+ \qml
+ import QtWayland.Compositor.WlShell
+ \endqml
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qwaylandcompositorwlshell_p.cpp"
diff --git a/src/imports/compositor-extensions/wlshell/qwaylandcompositorwlshell_p.h b/src/imports/compositor-extensions/wlshell/qwaylandcompositorwlshell_p.h
new file mode 100644
index 000000000..295d3562f
--- /dev/null
+++ b/src/imports/compositor-extensions/wlshell/qwaylandcompositorwlshell_p.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDWLSHELLFOREIGN_H
+#define QWAYLANDWLSHELLFOREIGN_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
+
+#include <QtWaylandCompositor/qwaylandquickextension.h>
+#include <QtWaylandCompositor/qwaylandwlshell.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_ELEMENT(QWaylandWlShell, WlShell, 1, 0)
+
+struct QWaylandWlShellForeign {
+ Q_GADGET
+ QML_FOREIGN(QWaylandWlShell)
+ QML_NAMED_ELEMENT(WlShellSurface)
+ QML_ADDED_IN_VERSION(1, 0)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/imports/compositor-extensions/xdgshell/CMakeLists.txt b/src/imports/compositor-extensions/xdgshell/CMakeLists.txt
new file mode 100644
index 000000000..32f032d93
--- /dev/null
+++ b/src/imports/compositor-extensions/xdgshell/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_qml_module(WaylandCompositorXdgShell
+ URI "QtWayland.Compositor.XdgShell"
+ VERSION "${PROJECT_VERSION}"
+ SOURCES
+ qwaylandcompositorxdgshell_p.h
+ qwaylandcompositorxdgshell.cpp
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::WaylandCompositor
+ NO_GENERATE_CPP_EXPORTS
+ PAST_MAJOR_VERSIONS 1
+)
+
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorXdgShell WaylandCompositor)
diff --git a/src/imports/compositor-extensions/xdgshell/qwaylandcompositorxdgshell.cpp b/src/imports/compositor-extensions/xdgshell/qwaylandcompositorxdgshell.cpp
new file mode 100644
index 000000000..15c96c718
--- /dev/null
+++ b/src/imports/compositor-extensions/xdgshell/qwaylandcompositorxdgshell.cpp
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwaylandcompositorxdgshell_p.h"
+
+QT_BEGIN_NAMESPACE
+/*!
+ \qmlmodule QtWayland.Compositor.XdgShell
+ \title Qt Wayland XdgShell Extension
+ \ingroup qmlmodules
+ \brief Provides a Qt API for the XdgShell shell extension.
+
+ \section2 Summary
+ XdgShell is a shell extension providing window system features typical to
+ desktop systems.
+
+ XdgShell corresponds to the Wayland interface, \c xdg_shell.
+
+ \section2 Usage
+ To use this module, import it like this:
+ \qml
+ import QtWayland.Compositor.XdgShell
+ \endqml
+*/
+QT_END_NAMESPACE
+
+#include "moc_qwaylandcompositorxdgshell_p.cpp"
diff --git a/src/imports/compositor-extensions/xdgshell/qwaylandcompositorxdgshell_p.h b/src/imports/compositor-extensions/xdgshell/qwaylandcompositorxdgshell_p.h
new file mode 100644
index 000000000..f8a70d6ef
--- /dev/null
+++ b/src/imports/compositor-extensions/xdgshell/qwaylandcompositorxdgshell_p.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDCOMPOSITORXDGSHELLFOREIGN_H
+#define QWAYLANDCOMPOSITORXDGSHELLFOREIGN_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
+
+#include <QtWaylandCompositor/QWaylandQuickExtension>
+#include <QtWaylandCompositor/QWaylandXdgShell>
+#include <QtWaylandCompositor/QWaylandXdgDecorationManagerV1>
+#include <QtWaylandCompositor/QWaylandQuickXdgOutputV1>
+
+QT_BEGIN_NAMESPACE
+
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_ELEMENT(QWaylandXdgShell, XdgShell, 1, 3)
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_ELEMENT(QWaylandXdgDecorationManagerV1,
+ XdgDecorationManagerV1, 1, 3)
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_ELEMENT(QWaylandXdgOutputManagerV1, XdgOutputManagerV1,
+ 1, 14)
+
+struct QWaylandXdgSurfaceForeign {
+ Q_GADGET
+ QML_FOREIGN(QWaylandXdgSurface)
+ QML_NAMED_ELEMENT(XdgSurface)
+ QML_ADDED_IN_VERSION(1, 3)
+};
+
+struct QWaylandXdgTopLevelForeign {
+ Q_GADGET
+ QML_FOREIGN(QWaylandXdgToplevel)
+ QML_NAMED_ELEMENT(XdgToplevel)
+ QML_ADDED_IN_VERSION(1, 3)
+ QML_UNCREATABLE("Cannot create instance of XdgShellToplevel")
+};
+
+struct QWaylandXdgPopupForeign {
+ Q_GADGET
+ QML_FOREIGN(QWaylandXdgPopup)
+ QML_NAMED_ELEMENT(XdgPopup)
+ QML_ADDED_IN_VERSION(1, 3)
+ QML_UNCREATABLE("Cannot create instance of XdgShellPopup")
+};
+
+struct QWaylandQuickXdgOutputV1Foreign {
+ Q_GADGET
+ QML_FOREIGN(QWaylandQuickXdgOutputV1)
+ QML_NAMED_ELEMENT(XdgOutputV1)
+ QML_ADDED_IN_VERSION(1, 14)
+};
+
+QT_END_NAMESPACE
+
+#endif