diff options
Diffstat (limited to 'src/plugins/shellintegration/qt-shell')
7 files changed, 427 insertions, 0 deletions
diff --git a/src/plugins/shellintegration/qt-shell/CMakeLists.txt b/src/plugins/shellintegration/qt-shell/CMakeLists.txt new file mode 100644 index 000000000..b4f9f8b5c --- /dev/null +++ b/src/plugins/shellintegration/qt-shell/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## QWaylandQtShellIntegrationPlugin Plugin: +##################################################################### + +qt_internal_add_plugin(QWaylandQtShellIntegrationPlugin + OUTPUT_NAME qt-shell + PLUGIN_TYPE wayland-shell-integration + SOURCES + main.cpp + qwaylandqtshellintegration.cpp qwaylandqtshellintegration.h + qwaylandqtsurface.cpp qwaylandqtsurface_p.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::GuiPrivate + Qt::WaylandClientPrivate + Wayland::Client +) + +qt6_generate_wayland_protocol_client_sources(QWaylandQtShellIntegrationPlugin + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/../../../extensions/qt-shell-unstable-v1.xml +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(QWaylandQtShellIntegrationPlugin CONDITION QT_FEATURE_xkbcommon + LIBRARIES + XKB::XKB +) diff --git a/src/plugins/shellintegration/qt-shell/main.cpp b/src/plugins/shellintegration/qt-shell/main.cpp new file mode 100644 index 000000000..41b6028f6 --- /dev/null +++ b/src/plugins/shellintegration/qt-shell/main.cpp @@ -0,0 +1,31 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include <QtWaylandClient/private/qwaylandshellintegrationplugin_p.h> +#include "qwaylandqtshellintegration.h" + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +class QWaylandQtShellIntegrationPlugin : public QWaylandShellIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QWaylandShellIntegrationFactoryInterface_iid FILE "qt-shell.json") + +public: + QWaylandShellIntegration *create(const QString &key, const QStringList ¶mList) override; +}; + +QWaylandShellIntegration *QWaylandQtShellIntegrationPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(key); + Q_UNUSED(paramList); + return new QWaylandQtShellIntegration(); +} + +} + +QT_END_NAMESPACE + +#include "main.moc" diff --git a/src/plugins/shellintegration/qt-shell/qt-shell.json b/src/plugins/shellintegration/qt-shell/qt-shell.json new file mode 100644 index 000000000..aa6df6235 --- /dev/null +++ b/src/plugins/shellintegration/qt-shell/qt-shell.json @@ -0,0 +1,3 @@ +{ + "Keys":[ "qt-shell" ] +} diff --git a/src/plugins/shellintegration/qt-shell/qwaylandqtshellintegration.cpp b/src/plugins/shellintegration/qt-shell/qwaylandqtshellintegration.cpp new file mode 100644 index 000000000..17b87033f --- /dev/null +++ b/src/plugins/shellintegration/qt-shell/qwaylandqtshellintegration.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qwaylandqtshellintegration.h" + +#include <QtCore/qsize.h> +#include <QtCore/qdebug.h> + +#include <QtWaylandClient/private/qwaylanddisplay_p.h> +#include <QtWaylandClient/private/qwaylandwindow_p.h> + +#include "qwaylandqtsurface_p.h" + +#include <mutex> + +#include <unistd.h> + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +QWaylandQtShellIntegration::QWaylandQtShellIntegration() + : QWaylandShellIntegrationTemplate(1) +{ + QWaylandWindow::fixedToplevelPositions = false; +} + +QWaylandShellSurface *QWaylandQtShellIntegration::createShellSurface(QWaylandWindow *window) +{ + auto *surface = surface_create(wlSurfaceForWindow(window)); + return new QWaylandQtSurface(surface, window); +} + +} + +QT_END_NAMESPACE diff --git a/src/plugins/shellintegration/qt-shell/qwaylandqtshellintegration.h b/src/plugins/shellintegration/qt-shell/qwaylandqtshellintegration.h new file mode 100644 index 000000000..18d033569 --- /dev/null +++ b/src/plugins/shellintegration/qt-shell/qwaylandqtshellintegration.h @@ -0,0 +1,35 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QWAYLANDQTINTEGRATION_H +#define QWAYLANDQTINTEGRATION_H + +#include <QtCore/qmutex.h> + +#include <QtWaylandClient/private/qwaylandshellintegration_p.h> +#include <QScopedPointer> +#include "qwayland-qt-shell-unstable-v1.h" + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +class QWaylandWindow; +class QWaylandDisplay; + + +class Q_WAYLANDCLIENT_EXPORT QWaylandQtShellIntegration + : public QWaylandShellIntegrationTemplate<QWaylandQtShellIntegration> + , public QtWayland::zqt_shell_v1 +{ +public: + QWaylandQtShellIntegration(); + + QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override; +}; + +} + +QT_END_NAMESPACE + +#endif // QWAYLANDQTINTEGRATION_H diff --git a/src/plugins/shellintegration/qt-shell/qwaylandqtsurface.cpp b/src/plugins/shellintegration/qt-shell/qwaylandqtsurface.cpp new file mode 100644 index 000000000..ddbb7783c --- /dev/null +++ b/src/plugins/shellintegration/qt-shell/qwaylandqtsurface.cpp @@ -0,0 +1,216 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qwaylandqtsurface_p.h" +#include <qpa/qwindowsysteminterface.h> +#include <qpa/qplatformwindow.h> + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +QWaylandQtSurface::QWaylandQtSurface(struct ::zqt_shell_surface_v1 *shell_surface, QWaylandWindow *window) + : QWaylandShellSurface(window) + , QtWayland::zqt_shell_surface_v1(shell_surface) +{ + sendSizeHints(); +} + +QWaylandQtSurface::~QWaylandQtSurface() +{ + zqt_shell_surface_v1::destroy(); +} + +void QWaylandQtSurface::resetConfiguration() +{ + m_pendingPosition = QPoint(-1, -1); + m_pendingSize = QSize(); + m_pendingPositionValid = false; + m_pendingStates = m_currentStates; +} + +void QWaylandQtSurface::applyConfigure() +{ + if (m_pendingSize.isValid() && m_pendingPositionValid) + setGeometryFromApplyConfigure(m_pendingPosition, m_pendingSize); + else if (m_pendingSize.isValid()) + resizeFromApplyConfigure(m_pendingSize); + else if (m_pendingPositionValid) + repositionFromApplyConfigure(m_pendingPosition); + + if (m_pendingStates != m_currentStates) { + QWindowSystemInterface::handleWindowStateChanged(platformWindow()->window(), m_pendingStates); + m_currentStates = m_pendingStates; + } + + ack_configure(m_currentConfigureSerial); + + resetConfiguration(); + m_currentConfigureSerial = UINT32_MAX; +} + +void QWaylandQtSurface::setTitle(const QString &title) +{ + set_window_title(title); +} + +void QWaylandQtSurface::zqt_shell_surface_v1_set_capabilities(uint32_t capabilities) +{ + m_capabilities = capabilities; +} + +void QWaylandQtSurface::zqt_shell_surface_v1_set_position(uint32_t serial, int32_t x, int32_t y) +{ + if (serial < m_currentConfigureSerial && m_currentConfigureSerial != UINT32_MAX) + return; + + if (serial != m_currentConfigureSerial) { + m_currentConfigureSerial = serial; + resetConfiguration(); + } + + m_pendingPosition = QPoint(x, y); + m_pendingPositionValid = true; +} + +void QWaylandQtSurface::zqt_shell_surface_v1_resize(uint32_t serial, int32_t width, int32_t height) +{ + if (serial < m_currentConfigureSerial && m_currentConfigureSerial != UINT32_MAX) + return; + + if (serial != m_currentConfigureSerial) { + m_currentConfigureSerial = serial; + resetConfiguration(); + } + + m_pendingSize = QSize(width, height); +} + +void QWaylandQtSurface::zqt_shell_surface_v1_configure(uint32_t serial) +{ + if (serial < m_currentConfigureSerial) + return; + + if (serial > m_currentConfigureSerial) { + m_currentConfigureSerial = serial; + resetConfiguration(); + } + + applyConfigureWhenPossible(); +} + +void QWaylandQtSurface::zqt_shell_surface_v1_close() +{ + platformWindow()->window()->close(); +} + +void QWaylandQtSurface::zqt_shell_surface_v1_set_frame_margins(uint32_t left, uint32_t right, + uint32_t top, uint32_t bottom) +{ + QPlatformWindow *win = platformWindow(); + m_frameMargins = QMargins(left, top, right, bottom); + m_pendingPosition = win->geometry().topLeft(); + m_pendingPositionValid = true; + m_pendingSize = win->geometry().size(); + applyConfigureWhenPossible(); +} + +bool QWaylandQtSurface::requestActivate() +{ + request_activate(); + return true; +} + +void QWaylandQtSurface::propagateSizeHints() +{ + sendSizeHints(); +} + +void QWaylandQtSurface::sendSizeHints() +{ + QPlatformWindow *win = platformWindow(); + if (win) { + const int minWidth = qMax(0, win->windowMinimumSize().width()); + const int minHeight = qMax(0, win->windowMinimumSize().height()); + set_minimum_size(minWidth, minHeight); + + int maxWidth = qMax(0, win->windowMaximumSize().width()); + if (maxWidth == QWINDOWSIZE_MAX) + maxWidth = -1; + int maxHeight = qMax(0, win->windowMaximumSize().height()); + if (maxHeight == QWINDOWSIZE_MAX) + maxHeight = -1; + set_maximum_size(maxWidth, maxHeight); + } +} + +void QWaylandQtSurface::zqt_shell_surface_v1_set_window_state(uint32_t serial, uint32_t state) +{ + if (serial < m_currentConfigureSerial && m_currentConfigureSerial != UINT32_MAX) + return; + + if (serial != m_currentConfigureSerial) { + m_currentConfigureSerial = serial; + resetConfiguration(); + } + m_pendingStates = Qt::WindowStates(state); +} + +void QWaylandQtSurface::setWindowGeometry(const QRect &rect) +{ + set_size(rect.width(), rect.height()); +} + +void QWaylandQtSurface::setWindowPosition(const QPoint &position) +{ + reposition(position.x(), position.y()); +} + +void QWaylandQtSurface::setWindowFlags(Qt::WindowFlags flags) +{ + set_window_flags(flags); +} + +void QWaylandQtSurface::requestWindowStates(Qt::WindowStates states) +{ + change_window_state(states & ~Qt::WindowActive); +} + +bool QWaylandQtSurface::resize(QWaylandInputDevice *inputDevice, Qt::Edges edge) +{ + if (m_capabilities & ZQT_SHELL_SURFACE_V1_CAPABILITIES_INTERACTIVE_RESIZE) { + start_system_resize(getSerial(inputDevice), uint(edge)); + return true; + } + + return false; +} + +bool QWaylandQtSurface::move(QWaylandInputDevice *inputDevice) +{ + if (m_capabilities & ZQT_SHELL_SURFACE_V1_CAPABILITIES_INTERACTIVE_RESIZE) { + start_system_move(getSerial(inputDevice)); + return true; + } + + return false; +} + +QMargins QWaylandQtSurface::serverSideFrameMargins() const +{ + return m_frameMargins; +} + +void QWaylandQtSurface::raise() +{ + QtWayland::zqt_shell_surface_v1::raise(); +} + +void QWaylandQtSurface::lower() +{ + QtWayland::zqt_shell_surface_v1::lower(); +} + +} + +QT_END_NAMESPACE diff --git a/src/plugins/shellintegration/qt-shell/qwaylandqtsurface_p.h b/src/plugins/shellintegration/qt-shell/qwaylandqtsurface_p.h new file mode 100644 index 000000000..6431bd552 --- /dev/null +++ b/src/plugins/shellintegration/qt-shell/qwaylandqtsurface_p.h @@ -0,0 +1,72 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QWAYLANDQTSURFACE_H +#define QWAYLANDQTSURFACE_H + +#include <QtCore/qpoint.h> +#include <QtWaylandClient/private/qwaylandshellsurface_p.h> +#include "qwayland-qt-shell-unstable-v1.h" + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +class QWaylandWindow; +class QWaylandInputDevice; + +class Q_WAYLANDCLIENT_EXPORT QWaylandQtSurface : public QWaylandShellSurface + , public QtWayland::zqt_shell_surface_v1 +{ +public: + QWaylandQtSurface(struct ::zqt_shell_surface_v1 *shell_surface, QWaylandWindow *window); + ~QWaylandQtSurface() override; + + void applyConfigure() override; + void setWindowGeometry(const QRect &rect) override; + void setWindowPosition(const QPoint &position) override; + + void setWindowFlags(Qt::WindowFlags flags) override; + void requestWindowStates(Qt::WindowStates states) override; + void setTitle(const QString &title) override; + + bool resize(QWaylandInputDevice *, Qt::Edges) override; + bool move(QWaylandInputDevice *) override; + bool requestActivate() override; + + void propagateSizeHints() override; + + QMargins serverSideFrameMargins() const override; + + void raise() override; + void lower() override; + + std::any surfaceRole() const override { return object(); }; + +private: + void resetConfiguration(); + void sendSizeHints(); + void zqt_shell_surface_v1_close() override; + void zqt_shell_surface_v1_resize(uint32_t serial, int32_t width, int32_t height) override; + void zqt_shell_surface_v1_set_position(uint32_t serial, int32_t x, int32_t y) override; + void zqt_shell_surface_v1_configure(uint32_t serial) override; + void zqt_shell_surface_v1_set_window_state(uint32_t serial, uint32_t state) override; + void zqt_shell_surface_v1_set_frame_margins(uint32_t left, uint32_t right, + uint32_t top, uint32_t bottom) override; + void zqt_shell_surface_v1_set_capabilities(uint32_t capabilities) override; + + QSize m_pendingSize; + QPoint m_pendingPosition = { -1, -1 }; + bool m_pendingPositionValid = false; + Qt::WindowStates m_pendingStates = Qt::WindowNoState; + Qt::WindowStates m_currentStates = Qt::WindowNoState; + QMargins m_frameMargins; + uint32_t m_currentConfigureSerial = UINT32_MAX; + uint32_t m_capabilities = 0; +}; + +} + +QT_END_NAMESPACE + +#endif // QWAYLANDQTSURFACE_H |