From b4119fd680c667d73cab95d2cb0f962618f00688 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Tue, 12 Apr 2022 08:48:34 +0400 Subject: Client: Expose a way to set window margins via native interface The lack of such API is a big hassle to me since a long time. All that time I was forced to have my own fork of the xdg-shell plugin in the application code in order to have shadows on Wayland with custom client-side decorations. I hope I won't have to maintain the fork anymore. Change-Id: Iaf498469843b5cac5c458049164065c4ef15877d Reviewed-by: David Edmundson (cherry picked from commit c9f355ebe8d8171c2de265c00780d7f39b580409) Reviewed-by: Qt Cherry-pick Bot --- src/client/qwaylandnativeinterface.cpp | 17 +++++++++++++++++ src/client/qwaylandnativeinterface_p.h | 5 +++++ src/client/qwaylandwindow.cpp | 17 +++++++++++++++-- src/client/qwaylandwindow_p.h | 3 +++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp index 6d858348..f2620fc4 100644 --- a/src/client/qwaylandnativeinterface.cpp +++ b/src/client/qwaylandnativeinterface.cpp @@ -129,6 +129,17 @@ void *QWaylandNativeInterface::nativeResourceForContext(const QByteArray &resour } #endif // opengl +QPlatformNativeInterface::NativeResourceForWindowFunction QWaylandNativeInterface::nativeResourceFunctionForWindow(const QByteArray &resource) +{ + QByteArray lowerCaseResource = resource.toLower(); + + if (lowerCaseResource == "setmargins") { + return NativeResourceForWindowFunction(reinterpret_cast(setWindowMargins)); + } + + return nullptr; +} + QVariantMap QWaylandNativeInterface::windowProperties(QPlatformWindow *window) const { QWaylandWindow *waylandWindow = static_cast(window); @@ -158,6 +169,12 @@ void QWaylandNativeInterface::emitWindowPropertyChanged(QPlatformWindow *window, emit windowPropertyChanged(window,name); } +void QWaylandNativeInterface::setWindowMargins(QWindow *window, const QMargins &margins) +{ + QWaylandWindow *wlWindow = static_cast(window->handle()); + wlWindow->setCustomMargins(margins); +} + } QT_END_NAMESPACE diff --git a/src/client/qwaylandnativeinterface_p.h b/src/client/qwaylandnativeinterface_p.h index d05d7c38..b39d9952 100644 --- a/src/client/qwaylandnativeinterface_p.h +++ b/src/client/qwaylandnativeinterface_p.h @@ -24,6 +24,8 @@ QT_BEGIN_NAMESPACE +class QMargins; + namespace QtWaylandClient { class QWaylandIntegration; @@ -41,6 +43,7 @@ public: #if QT_CONFIG(opengl) void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override; #endif + NativeResourceForWindowFunction nativeResourceFunctionForWindow(const QByteArray &resource) override; QVariantMap windowProperties(QPlatformWindow *window) const override; QVariant windowProperty(QPlatformWindow *window, const QString &name) const override; QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override; @@ -49,6 +52,8 @@ public: void emitWindowPropertyChanged(QPlatformWindow *window, const QString &name); private: + static void setWindowMargins(QWindow *window, const QMargins &margins); + QWaylandIntegration *m_integration = nullptr; QHash m_windowProperties; }; diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 5a8dd0aa..e8b50939 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -397,8 +397,12 @@ void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, cons // 2) Following resizeFromApplyConfigure() calls should have sizeWithMargins equal to // windowContentGeometry() which excludes shadows, therefore in this case we have to // exclude them too in order not to accidentally apply smaller size to the window. - if (mWindowDecorationEnabled && (sizeWithMargins != surfaceSize())) - margins = mWindowDecoration->margins(QWaylandAbstractDecoration::ShadowsExcluded); + if (sizeWithMargins != surfaceSize()) { + if (mWindowDecorationEnabled) + margins = mWindowDecoration->margins(QWaylandAbstractDecoration::ShadowsExcluded); + if (!mCustomMargins.isNull()) + margins -= mCustomMargins; + } int widthWithoutMargins = qMax(sizeWithMargins.width() - (margins.left() + margins.right()), 1); int heightWithoutMargins = qMax(sizeWithMargins.height() - (margins.top() + margins.bottom()), 1); @@ -735,6 +739,12 @@ QMargins QWaylandWindow::clientSideMargins() const return mWindowDecorationEnabled ? mWindowDecoration->margins() : QMargins{}; } +void QWaylandWindow::setCustomMargins(const QMargins &margins) { + const QMargins oldMargins = mCustomMargins; + mCustomMargins = margins; + setGeometry(geometry().marginsRemoved(oldMargins).marginsAdded(margins)); +} + /*! * Size, with decorations (including including eventual shadows) in wl_surface coordinates */ @@ -754,6 +764,9 @@ QRect QWaylandWindow::windowContentGeometry() const if (mWindowDecorationEnabled) shadowMargins = mWindowDecoration->margins(QWaylandAbstractDecoration::ShadowsOnly); + if (!mCustomMargins.isNull()) + shadowMargins += mCustomMargins; + return QRect(QPoint(shadowMargins.left(), shadowMargins.top()), surfaceSize().shrunkBy(shadowMargins)); } diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index e3f59a1d..e1280268 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -109,6 +109,7 @@ public: bool waitForFrameSync(int timeout); QMargins frameMargins() const override; + void setCustomMargins(const QMargins &margins); QSize surfaceSize() const; QRect windowContentGeometry() const; QPointF mapFromWlSurface(const QPointF &surfacePosition) const; @@ -286,6 +287,8 @@ protected: QWaylandBuffer *mQueuedBuffer = nullptr; QRegion mQueuedBufferDamage; + QMargins mCustomMargins; + private: void setGeometry_helper(const QRect &rect); void initWindow(); -- cgit v1.2.1