From 23d3fc712cdf7fc0a4ff837082de9ba773e8605c Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Wed, 23 Mar 2022 15:35:50 +0000 Subject: Implement fractional_scale_v1 and wp_viewport This allows compositors to hint a non-integer scale to use on a window which we can hook to Qt's existing fractional scaling support. The viewport is used to communicate the relationship between buffer size and logical size to the compositor. It is a non-integer alternative to wl_buffer_scale Change-Id: I1a850f1bcd40e8d04e241e18a538b11f18bc671c Reviewed-by: Qt CI Bot Reviewed-by: David Edmundson --- src/client/qwaylandwindow.cpp | 61 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 6 deletions(-) (limited to 'src/client/qwaylandwindow.cpp') diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index f4d49c84..56b9af28 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -7,6 +7,7 @@ #include "qwaylanddisplay_p.h" #include "qwaylandsurface_p.h" #include "qwaylandinputdevice_p.h" +#include "qwaylandfractionalscale_p.h" #include "qwaylandscreen_p.h" #include "qwaylandshellsurface_p.h" #include "qwaylandsubsurface_p.h" @@ -16,6 +17,7 @@ #include "qwaylanddecorationfactory_p.h" #include "qwaylandshmbackingstore_p.h" #include "qwaylandshellintegration_p.h" +#include "qwaylandviewport_p.h" #include #include @@ -29,6 +31,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE namespace QtWaylandClient { @@ -91,6 +95,26 @@ void QWaylandWindow::initWindow() initializeWlSurface(); } + if (mDisplay->fractionalScaleManager() && qApp->highDpiScaleFactorRoundingPolicy() == Qt::HighDpiScaleFactorRoundingPolicy::PassThrough) { + mFractionalScale.reset(new QWaylandFractionalScale(mDisplay->fractionalScaleManager()->get_fractional_scale(mSurface->object()))); + + mScale = mFractionalScale->preferredScale(); + connect(mFractionalScale.data(), &QWaylandFractionalScale::preferredScaleChanged, this, [this]() { + if (mScale == mFractionalScale->preferredScale()) { + return; + } + mScale = mFractionalScale->preferredScale(); + ensureSize(); + if (mViewport) + updateViewport(); + if (isExposed()) { + // redraw at the new DPR + window()->requestUpdate(); + sendExposeEvent(QRect(QPoint(), geometry().size())); + } + }); + } + if (shouldCreateSubSurface()) { Q_ASSERT(!mSubSurfaceWindow); @@ -146,11 +170,17 @@ void QWaylandWindow::initWindow() } } + if (display()->viewporter() && !window()->flags().testFlag(Qt::BypassWindowManagerHint)) { + mViewport.reset(new QWaylandViewport(display()->createViewport(this))); + } + // Enable high-dpi rendering. Scale() returns the screen scale factor and will // typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale() // to inform the compositor that high-resolution buffers will be provided. - if (mSurface->version() >= 3) - mSurface->set_buffer_scale(mScale); + if (mViewport) + updateViewport(); + else if (mSurface->version() >= 3) + mSurface->set_buffer_scale(std::ceil(scale())); setWindowFlags(window()->flags()); QRect geometry = windowGeometry(); @@ -220,6 +250,8 @@ void QWaylandWindow::reset() mShellSurface = nullptr; delete mSubSurfaceWindow; mSubSurfaceWindow = nullptr; + mViewport.reset(); + mFractionalScale.reset(); if (mSurface) { emit wlSurfaceDestroyed(); @@ -322,6 +354,8 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect) QPlatformWindow::setGeometry(QRect(rect.x(), rect.y(), qBound(minimum.width(), rect.width(), maximum.width()), qBound(minimum.height(), rect.height(), maximum.height()))); + if (mViewport) + updateViewport(); if (mSubSurfaceWindow) { QMargins m = static_cast(QPlatformWindow::parent())->clientSideMargins(); @@ -370,6 +404,12 @@ void QWaylandWindow::setGeometry(const QRect &r) setOpaqueArea(QRect(QPoint(0, 0), rect.size())); } +void QWaylandWindow::updateViewport() +{ + if (!surfaceSize().isEmpty()) + mViewport->setDestination(surfaceSize()); +} + void QWaylandWindow::setGeometryFromApplyConfigure(const QPoint &globalPosition, const QSize &sizeWithMargins) { QMargins margins = clientSideMargins(); @@ -1242,6 +1282,7 @@ void QWaylandWindow::handleScreensChanged() return; QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); + mLastReportedScreen = newScreen; if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup && window()->type() != Qt::ToolTip @@ -1251,11 +1292,19 @@ void QWaylandWindow::handleScreensChanged() setGeometry(geometry); } - int scale = newScreen->isPlaceholder() ? 1 : static_cast(newScreen)->scale(); + if (mFractionalScale) + return; + + int scale = mLastReportedScreen->isPlaceholder() ? 1 : static_cast(mLastReportedScreen)->scale(); + if (scale != mScale) { mScale = scale; - if (mSurface && mSurface->version() >= 3) - mSurface->set_buffer_scale(mScale); + if (mSurface) { + if (mViewport) + updateViewport(); + else if (mSurface->version() >= 3) + mSurface->set_buffer_scale(std::ceil(mScale)); + } ensureSize(); } } @@ -1558,4 +1607,4 @@ void QWaylandWindow::closeChildPopups() { QT_END_NAMESPACE -#include "moc_qwaylandwindow_p.cpp" +#include "qwaylandwindow.moc" -- cgit v1.2.1