diff --git a/src/plugins/platforms/wayland/CMakeLists.txt b/src/plugins/platforms/wayland/CMakeLists.txt index c7264d6774f..696a8b3d284 100644 --- a/src/plugins/platforms/wayland/CMakeLists.txt +++ b/src/plugins/platforms/wayland/CMakeLists.txt @@ -48,7 +48,8 @@ qt_internal_add_module(WaylandClient qwaylandtouch.cpp qwaylandtouch_p.h qwaylandwindow.cpp qwaylandwindow_p.h qwaylandwindowmanagerintegration.cpp qwaylandwindowmanagerintegration_p.h - shellintegration/qwaylandshellintegration_p.h + shellintegration/qwaylandclientshellapi_p.h + shellintegration/qwaylandshellintegration_p.h shellintegration/qwaylandshellintegration.cpp shellintegration/qwaylandshellintegrationfactory.cpp shellintegration/qwaylandshellintegrationfactory_p.h shellintegration/qwaylandshellintegrationplugin.cpp shellintegration/qwaylandshellintegrationplugin_p.h INCLUDE_DIRECTORIES diff --git a/src/plugins/platforms/wayland/configure.cmake b/src/plugins/platforms/wayland/configure.cmake index e0d0205b8a4..a8184fc1c38 100644 --- a/src/plugins/platforms/wayland/configure.cmake +++ b/src/plugins/platforms/wayland/configure.cmake @@ -37,6 +37,10 @@ qt_feature("wayland-client-xdg-shell" PRIVATE LABEL "xdg-shell" CONDITION QT_FEATURE_wayland_client ) +qt_feature("wayland-client-qt-shell" PRIVATE + LABEL "qt-shell" + CONDITION QT_FEATURE_wayland_client +) qt_feature("egl-extension-platform-wayland" PRIVATE LABEL "EGL wayland platform extension" CONDITION QT_FEATURE_wayland_client AND QT_FEATURE_opengl AND QT_FEATURE_egl AND TEST_egl_1_5_wayland @@ -45,4 +49,5 @@ qt_configure_add_summary_section(NAME "Qt Wayland Client Shell Integrations") qt_configure_add_summary_entry(ARGS "wayland-client-xdg-shell") qt_configure_add_summary_entry(ARGS "wayland-client-ivi-shell") qt_configure_add_summary_entry(ARGS "wayland-client-wl-shell") +qt_configure_add_summary_entry(ARGS "wayland-client-qt-shell") qt_configure_end_summary_section() # end of "Qt Wayland Client Shell Integrations" section diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/CMakeLists.txt b/src/plugins/platforms/wayland/plugins/shellintegration/CMakeLists.txt index fef15fe798e..eefa0227d4a 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/CMakeLists.txt +++ b/src/plugins/platforms/wayland/plugins/shellintegration/CMakeLists.txt @@ -12,3 +12,7 @@ endif() if(QT_FEATURE_wayland_client_xdg_shell) add_subdirectory(xdg-shell) endif() + +if(QT_FEATURE_wayland_client_qt_shell) + add_subdirectory(qt-shell) +endif() diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp index 0cd2cb1e893..033cbf6ec02 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp +++ b/src/plugins/platforms/wayland/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp @@ -44,23 +44,22 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { -bool QWaylandFullScreenShellV1Integration::initialize(QWaylandDisplay *display) +bool QWaylandFullScreenShellV1Integration::initialize() { - for (const QWaylandDisplay::RegistryGlobal &global : display->globals()) { - if (global.interface == QLatin1String("zwp_fullscreen_shell_v1") && !m_shell) { - m_shell.reset(new QtWayland::zwp_fullscreen_shell_v1(display->wl_registry(), global.id, global.version)); - break; - } - } - + if (m_shell) + return true; + wl_registry *registry; + uint32_t id; + uint32_t version; + bool found = findGlobal(QLatin1String("zwp_fullscreen_shell_v1"), ®istry, &id, &version); + if (found) + m_shell.reset(new QtWayland::zwp_fullscreen_shell_v1(registry, id, version)); if (!m_shell) { qCDebug(lcQpaWayland) << "Couldn't find global zwp_fullscreen_shell_v1 for fullscreen-shell"; return false; } - - return QWaylandShellIntegration::initialize(display); + return true; } - QWaylandShellSurface *QWaylandFullScreenShellV1Integration::createShellSurface(QWaylandWindow *window) { return new QWaylandFullScreenShellV1Surface(m_shell.data(), window); diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h b/src/plugins/platforms/wayland/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h index 131f9e72097..da99f6c4e0e 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h +++ b/src/plugins/platforms/wayland/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h @@ -43,6 +43,7 @@ #include #include #include +#include #include "qwayland-fullscreen-shell-unstable-v1.h" @@ -53,7 +54,7 @@ namespace QtWaylandClient { class Q_WAYLAND_CLIENT_EXPORT QWaylandFullScreenShellV1Integration : public QWaylandShellIntegration { public: - bool initialize(QWaylandDisplay *display) override; + bool initialize() override; QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override; private: diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp index 354ee19b886..7353cb1f968 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp +++ b/src/plugins/platforms/wayland/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp @@ -47,15 +47,16 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { -bool QWaylandWlShellIntegration::initialize(QWaylandDisplay *display) +bool QWaylandWlShellIntegration::initialize() { - const auto globals = display->globals(); - for (QWaylandDisplay::RegistryGlobal global : globals) { - if (global.interface == QLatin1String("wl_shell")) { - m_wlShell = new QtWayland::wl_shell(display->wl_registry(), global.id, 1); - break; - } - } + if (m_wlShell) + return true; + wl_registry *registry; + uint32_t id; + uint32_t version; + bool found = findGlobal(QLatin1String("wl_shell"), ®istry, &id, &version); + if (found) + m_wlShell = new QtWayland::wl_shell(registry, id, 1); if (!m_wlShell) { qCDebug(lcQpaWayland) << "Couldn't find global wl_shell"; @@ -66,7 +67,7 @@ bool QWaylandWlShellIntegration::initialize(QWaylandDisplay *display) << "\"xdg-shell\" if supported by the compositor" << "by setting the environment variable QT_WAYLAND_SHELL_INTEGRATION"; - return QWaylandShellIntegration::initialize(display); + return true; } QWaylandShellSurface *QWaylandWlShellIntegration::createShellSurface(QWaylandWindow *window) diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h b/src/plugins/platforms/wayland/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h index 3d76cc31073..47815d54a18 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h +++ b/src/plugins/platforms/wayland/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h @@ -63,7 +63,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandWlShellIntegration : public QWaylandShellI { public: QWaylandWlShellIntegration() {} - bool initialize(QWaylandDisplay *) override; + bool initialize() override; QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override; void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override; diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp index fcdd435c6b7..8390d76f68e 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp +++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp @@ -47,21 +47,21 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { -bool QWaylandXdgShellIntegration::initialize(QWaylandDisplay *display) +bool QWaylandXdgShellIntegration::initialize() { - for (QWaylandDisplay::RegistryGlobal global : display->globals()) { - if (global.interface == QLatin1String("xdg_wm_base")) { - m_xdgShell.reset(new QWaylandXdgShell(display, global.id, global.version)); - break; - } - } - + if (m_xdgShell) + return true; + wl_registry *registry; + uint32_t id; + uint32_t version; + bool found = findGlobal(QLatin1String("xdg_wm_base"), ®istry, &id, &version); + if (found) + m_xdgShell.reset(new QWaylandXdgShell(m_display, id, version)); if (!m_xdgShell) { qCDebug(lcQpaWayland) << "Couldn't find global xdg_wm_base for xdg-shell stable"; return false; } - - return QWaylandShellIntegration::initialize(display); + return true; } QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWindow *window) diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h index fced9eb07c2..cd54dd489d3 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h +++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h @@ -63,7 +63,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgShellIntegration : public QWaylandShell { public: QWaylandXdgShellIntegration() {} - bool initialize(QWaylandDisplay *display) override; + bool initialize() override; QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override; void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override; diff --git a/src/plugins/platforms/wayland/qtwaylandclientglobal.h b/src/plugins/platforms/wayland/qtwaylandclientglobal.h index 5f474f378b9..42f8ec8aac4 100644 --- a/src/plugins/platforms/wayland/qtwaylandclientglobal.h +++ b/src/plugins/platforms/wayland/qtwaylandclientglobal.h @@ -40,17 +40,6 @@ #ifndef QWAYLANDCLIENTGLOBAL_H #define QWAYLANDCLIENTGLOBAL_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 #include diff --git a/src/plugins/platforms/wayland/qwaylanddisplay_p.h b/src/plugins/platforms/wayland/qwaylanddisplay_p.h index 8be911188cf..cb345d7a049 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h @@ -217,6 +217,7 @@ public: bool isKeyboardAvailable() const; void initEventThread(); + public slots: void blockingReadEvents(); void flushRequests(); diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp index 73e4222fffb..274ae9a9df7 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -83,12 +83,14 @@ #include "qwaylandserverbufferintegration_p.h" #include "qwaylandserverbufferintegrationfactory_p.h" +#include "qwaylandshellsurface_p.h" #include "qwaylandshellintegration_p.h" #include "qwaylandshellintegrationfactory_p.h" #include "qwaylandinputdeviceintegration_p.h" #include "qwaylandinputdeviceintegrationfactory_p.h" +#include "qwaylandwindow_p.h" #if QT_CONFIG(accessibility_atspi_bridge) #include @@ -119,6 +121,19 @@ QWaylandIntegration::QWaylandIntegration() mFailed = true; return; } + + // ### Not ideal... + // We don't want to use QPlatformWindow::requestActivate here, since that gives a warning + // for most shells. Also, we don't want to put this into the specific shells that can use + // it, since we want to support more than one shell in one client. + // In addition, this will send a new requestActivate when the focus object changes, even if + // the focus window stays the same. + QObject::connect(qApp, &QGuiApplication::focusObjectChanged, qApp, [](){ + QWindow *fw = QGuiApplication::focusWindow(); + auto *w = fw ? static_cast(fw->handle()) : nullptr; + if (w && w->shellSurface()) + w->shellSurface()->requestActivate(); + }); } QWaylandIntegration::~QWaylandIntegration() @@ -435,6 +450,7 @@ void QWaylandIntegration::initializeShellIntegration() } else { preferredShells << QLatin1String("xdg-shell"); preferredShells << QLatin1String("wl-shell") << QLatin1String("ivi-shell"); + preferredShells << QLatin1String("qt-shell"); } for (const QString &preferredShell : qAsConst(preferredShells)) { diff --git a/src/plugins/platforms/wayland/qwaylandshellsurface.cpp b/src/plugins/platforms/wayland/qwaylandshellsurface.cpp index 1dfdfd5e007..81e05a444e8 100644 --- a/src/plugins/platforms/wayland/qwaylandshellsurface.cpp +++ b/src/plugins/platforms/wayland/qwaylandshellsurface.cpp @@ -40,6 +40,7 @@ #include "qwaylandshellsurface_p.h" #include "qwaylandwindow_p.h" #include "qwaylandextendedsurface_p.h" +#include "qwaylandinputdevice_p.h" QT_BEGIN_NAMESPACE @@ -61,6 +62,49 @@ void QWaylandShellSurface::sendProperty(const QString &name, const QVariant &val Q_UNUSED(value); } +QPlatformWindow *QWaylandShellSurface::platformWindow() +{ + return m_window; +} + +wl_surface *QWaylandShellSurface::wlSurface() +{ + return m_window ? m_window->wlSurface() : nullptr; +} + +void QWaylandShellSurface::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset) +{ + m_window->resizeFromApplyConfigure(sizeWithMargins, offset); +} + +void QWaylandShellSurface::repositionFromApplyConfigure(const QPoint &position) +{ + m_window->repositionFromApplyConfigure(position); +} + +void QWaylandShellSurface::setGeometryFromApplyConfigure(const QPoint &globalPosition, const QSize &sizeWithMargins) +{ + m_window->setGeometryFromApplyConfigure(globalPosition, sizeWithMargins); +} + +void QWaylandShellSurface::applyConfigureWhenPossible() +{ + m_window->applyConfigureWhenPossible(); +} + +void QWaylandShellSurface::handleActivationChanged(bool activated) +{ + if (activated) + m_window->display()->handleWindowActivated(m_window); + else + m_window->display()->handleWindowDeactivated(m_window); +} + +uint32_t QWaylandShellSurface::getSerial(QWaylandInputDevice *inputDevice) +{ + return inputDevice->serial(); +} + } QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandshellsurface_p.h b/src/plugins/platforms/wayland/qwaylandshellsurface_p.h index 080d13851bc..cdf1abdbc71 100644 --- a/src/plugins/platforms/wayland/qwaylandshellsurface_p.h +++ b/src/plugins/platforms/wayland/qwaylandshellsurface_p.h @@ -53,14 +53,16 @@ #include #include - -#include +#include #include +struct wl_surface; + QT_BEGIN_NAMESPACE class QVariant; class QWindow; +class QPlatformWindow; namespace QtWaylandClient { @@ -90,15 +92,30 @@ public: virtual void sendProperty(const QString &name, const QVariant &value); - inline QWaylandWindow *window() { return m_window; } - virtual void applyConfigure() {} virtual void requestWindowStates(Qt::WindowStates states) {Q_UNUSED(states);} virtual bool wantsDecorations() const { return false; } + virtual QMargins serverSideFrameMargins() const { return QMargins(); } virtual void propagateSizeHints() {} virtual void setWindowGeometry(const QRect &rect) { Q_UNUSED(rect); } + virtual void setWindowPosition(const QPoint &position) { Q_UNUSED(position); } + + virtual bool requestActivate() { return false; } + + inline QWaylandWindow *window() { return m_window; } + QPlatformWindow *platformWindow(); + struct wl_surface *wlSurface(); + +protected: + void resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset = {0, 0}); + void repositionFromApplyConfigure(const QPoint &position); + void setGeometryFromApplyConfigure(const QPoint &globalPosition, const QSize &sizeWithMargins); + void applyConfigureWhenPossible(); + void handleActivationChanged(bool activated); + + static uint32_t getSerial(QWaylandInputDevice *inputDevice); private: QWaylandWindow *m_window = nullptr; diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index 0cc185522b2..635c92a085e 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -342,7 +342,7 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect) qBound(minimum.height(), rect.height(), maximum.height()))); if (mSubSurfaceWindow) { - QMargins m = QPlatformWindow::parent()->frameMargins(); + QMargins m = static_cast(QPlatformWindow::parent())->clientSideMargins(); mSubSurfaceWindow->set_position(rect.x() + m.left(), rect.y() + m.top()); QWaylandWindow *parentWindow = mSubSurfaceWindow->parent(); @@ -372,16 +372,45 @@ void QWaylandWindow::setGeometry(const QRect &rect) if (isExposed() && !mInResizeFromApplyConfigure && exposeGeometry != mLastExposeGeometry) sendExposeEvent(exposeGeometry); - if (mShellSurface && isExposed()) + if (mShellSurface && isExposed()) { mShellSurface->setWindowGeometry(windowContentGeometry()); + if (!qt_window_private(window())->positionAutomatic) + mShellSurface->setWindowPosition(windowGeometry().topLeft()); + } if (isOpaque() && mMask.isEmpty()) setOpaqueArea(rect); } +void QWaylandWindow::setGeometryFromApplyConfigure(const QPoint &globalPosition, const QSize &sizeWithMargins) +{ + QMargins margins = clientSideMargins(); + + QPoint positionWithoutMargins = globalPosition + QPoint(margins.left(), margins.top()); + int widthWithoutMargins = qMax(sizeWithMargins.width() - (margins.left() + margins.right()), 1); + int heightWithoutMargins = qMax(sizeWithMargins.height() - (margins.top() + margins.bottom()), 1); + + QRect geometry(positionWithoutMargins, QSize(widthWithoutMargins, heightWithoutMargins)); + + mInResizeFromApplyConfigure = true; + setGeometry(geometry); + mInResizeFromApplyConfigure = false; +} + +void QWaylandWindow::repositionFromApplyConfigure(const QPoint &globalPosition) +{ + QMargins margins = clientSideMargins(); + QPoint positionWithoutMargins = globalPosition + QPoint(margins.left(), margins.top()); + + QRect geometry(positionWithoutMargins, windowGeometry().size()); + mInResizeFromApplyConfigure = true; + setGeometry(geometry); + mInResizeFromApplyConfigure = false; +} + void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset) { - QMargins margins = frameMargins(); + QMargins margins = clientSideMargins(); // Exclude shadows from margins once they are excluded from window geometry // 1) First resizeFromApplyConfigure() call will have sizeWithMargins equal to surfaceSize() @@ -394,7 +423,8 @@ void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, cons int widthWithoutMargins = qMax(sizeWithMargins.width() - (margins.left() + margins.right()), 1); int heightWithoutMargins = qMax(sizeWithMargins.height() - (margins.top() + margins.bottom()), 1); - QRect geometry(windowGeometry().topLeft(), QSize(widthWithoutMargins, heightWithoutMargins)); + QRect geometry(windowGeometry().topLeft() + QPoint(margins.left(), margins.top()), + QSize(widthWithoutMargins, heightWithoutMargins)); mOffset += offset; mInResizeFromApplyConfigure = true; @@ -411,7 +441,6 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect) mLastExposeGeometry = rect; } - static QList> activePopups; void QWaylandWindow::closePopups(QWaylandWindow *parent) @@ -719,7 +748,15 @@ QMargins QWaylandWindow::frameMargins() const { if (mWindowDecoration) return mWindowDecoration->margins(); - return QPlatformWindow::frameMargins(); + else if (mShellSurface) + return mShellSurface->serverSideFrameMargins(); + else + return QPlatformWindow::frameMargins(); +} + +QMargins QWaylandWindow::clientSideMargins() const +{ + return mWindowDecoration ? mWindowDecoration->margins() : QMargins{}; } /*! @@ -727,7 +764,7 @@ QMargins QWaylandWindow::frameMargins() const */ QSize QWaylandWindow::surfaceSize() const { - return geometry().marginsAdded(frameMargins()).size(); + return geometry().marginsAdded(clientSideMargins()).size(); } /*! @@ -753,7 +790,7 @@ QRect QWaylandWindow::windowContentGeometry() const */ QPointF QWaylandWindow::mapFromWlSurface(const QPointF &surfacePosition) const { - const QMargins margins = frameMargins(); + const QMargins margins = clientSideMargins(); return QPointF(surfacePosition.x() - margins.left(), surfacePosition.y() - margins.top()); } @@ -980,7 +1017,7 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan #if QT_CONFIG(cursor) if (e.type == QEvent::Enter) { - QRect contentGeometry = windowContentGeometry().marginsRemoved(frameMargins()); + QRect contentGeometry = windowContentGeometry().marginsRemoved(clientSideMargins()); if (contentGeometry.contains(e.local.toPoint())) restoreMouseCursor(inputDevice); } @@ -1213,7 +1250,8 @@ void QWaylandWindow::restoreMouseCursor(QWaylandInputDevice *device) void QWaylandWindow::requestActivateWindow() { - qCWarning(lcQpaWayland) << "Wayland does not support QWindow::requestActivate()"; + if (mShellSurface == nullptr || !mShellSurface->requestActivate()) + qCWarning(lcQpaWayland) << "Wayland does not support QWindow::requestActivate()"; } bool QWaylandWindow::isExposed() const @@ -1448,7 +1486,7 @@ bool QWaylandWindow::isOpaque() const void QWaylandWindow::setOpaqueArea(const QRegion &opaqueArea) { - const QRegion translatedOpaqueArea = opaqueArea.translated(frameMargins().left(), frameMargins().top()); + const QRegion translatedOpaqueArea = opaqueArea.translated(clientSideMargins().left(), clientSideMargins().top()); if (translatedOpaqueArea == mOpaqueArea || !mSurface) return; diff --git a/src/plugins/platforms/wayland/qwaylandwindow_p.h b/src/plugins/platforms/wayland/qwaylandwindow_p.h index 17ed9fdca13..f2dbe337fc7 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow_p.h +++ b/src/plugins/platforms/wayland/qwaylandwindow_p.h @@ -123,6 +123,8 @@ public: void setGeometry(const QRect &rect) override; void resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset = {0, 0}); + void repositionFromApplyConfigure(const QPoint &position); + void setGeometryFromApplyConfigure(const QPoint &globalPosition, const QSize &sizeWithMargins); void applyConfigureWhenPossible(); //rename to possible? @@ -239,6 +241,7 @@ protected: virtual void doHandleFrameCallback(); virtual QRect defaultGeometry() const; void sendExposeEvent(const QRect &rect); + QMargins clientSideMargins() const; QWaylandDisplay *mDisplay = nullptr; QScopedPointer mSurface; diff --git a/src/plugins/platforms/wayland/shellintegration/qwaylandclientshellapi_p.h b/src/plugins/platforms/wayland/shellintegration/qwaylandclientshellapi_p.h new file mode 100644 index 00000000000..a8863e7d3ed --- /dev/null +++ b/src/plugins/platforms/wayland/shellintegration/qwaylandclientshellapi_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWaylandClient module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDCLIENTSHELLAPI_P_H +#define QWAYLANDCLIENTSHELLAPI_P_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. +// + +// N O T E +// ------- +// This file provides a supported API for creating client-side shell +// extensions. Source compatibility will be preserved, but we may break +// forward and backward binary compatibility, even in patch releases. +// +// The supported API contains these classes: +// +// QtWaylandClient::QWaylandShellSurface +// QtWaylandClient::QWaylandShellIntegration +// QtWaylandClient::QWaylandShellIntegrationPlugin + +#include "QtWaylandClient/private/qwaylandshellsurface_p.h" +#include "QtWaylandClient/private/qwaylandshellintegration_p.h" +#include "QtWaylandClient/private/qwaylandshellintegrationplugin_p.h" + +#endif // QWAYLANDCLIENTSHELLAPI_P_H diff --git a/src/plugins/platforms/wayland/shellintegration/qwaylandshellintegration.cpp b/src/plugins/platforms/wayland/shellintegration/qwaylandshellintegration.cpp new file mode 100644 index 00000000000..7bc37792f8c --- /dev/null +++ b/src/plugins/platforms/wayland/shellintegration/qwaylandshellintegration.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWaylandClient module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qwaylandshellintegration_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +wl_surface *QWaylandShellIntegration::wlSurfaceForWindow(QWaylandWindow *window) +{ + return window->wlSurface(); +} + +bool QWaylandShellIntegration::findGlobal(const QString &interface, wl_registry **registry, uint32_t *id, uint32_t *version) +{ + for (QWaylandDisplay::RegistryGlobal &global : m_display->globals()) { + if (global.interface == interface) { + *registry = m_display->wl_registry(); + *id = global.id; + *version = global.version; + return true; + } + } + return false; +} + +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/shellintegration/qwaylandshellintegration_p.h b/src/plugins/platforms/wayland/shellintegration/qwaylandshellintegration_p.h index b308ffe25ee..4de19e7860c 100644 --- a/src/plugins/platforms/wayland/shellintegration/qwaylandshellintegration_p.h +++ b/src/plugins/platforms/wayland/shellintegration/qwaylandshellintegration_p.h @@ -52,10 +52,19 @@ // #include -#include +#include + + + +#include + +struct wl_surface; +struct wl_registry; QT_BEGIN_NAMESPACE +class QWindow; + namespace QtWaylandClient { class QWaylandWindow; @@ -68,9 +77,12 @@ public: QWaylandShellIntegration() {} virtual ~QWaylandShellIntegration() {} - virtual bool initialize(QWaylandDisplay *display) { + bool initialize(QWaylandDisplay *display) { m_display = display; - return true; + return initialize(); + } + virtual bool initialize() { + return false; } virtual QWaylandShellSurface *createShellSurface(QWaylandWindow *window) = 0; virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) { @@ -79,10 +91,49 @@ public: return nullptr; } + static wl_surface *wlSurfaceForWindow(QWaylandWindow *window); + bool findGlobal(const QString &interface, wl_registry **registry, uint32_t *id, uint32_t *version); + protected: QWaylandDisplay *m_display = nullptr; }; +template +class Q_WAYLAND_CLIENT_EXPORT QWaylandShellIntegrationTemplate : public QWaylandShellIntegration, public QWaylandClientExtension +{ +public: + QWaylandShellIntegrationTemplate(const int ver) : + QWaylandClientExtension(ver) + { + } + + bool initialize() override + { + QWaylandClientExtension::initialize(); + return isActive(); + } + + const struct wl_interface *extensionInterface() const override + { + return T::interface(); + } + + void bind(struct ::wl_registry *registry, int id, int ver) override + { + T* instance = static_cast(this); + // Make sure lowest version is used of the supplied version from the + // developer and the version specified in the protocol and also the + // compositor version. + if (this->version() > T::interface()->version) { + qWarning("Supplied protocol version to QWaylandClientExtensionTemplate is higher than the version of the protocol, using protocol version instead."); + } + int minVersion = qMin(ver, qMin(T::interface()->version, this->version())); + setVersion(minVersion); + instance->init(registry, id, minVersion); + } +}; + + } QT_END_NAMESPACE