diff options
Diffstat (limited to 'src/imports/compositor-extensions')
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 ¢roid) +{ + 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 ¢roid); + 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 |