summaryrefslogtreecommitdiffstats
path: root/src/client
diff options
context:
space:
mode:
authorDavid Edmundson <davidedmundson@kde.org>2022-03-23 15:35:50 +0000
committerDavid Edmundson <davidedmundson@kde.org>2022-12-07 20:36:40 +0000
commit23d3fc712cdf7fc0a4ff837082de9ba773e8605c (patch)
tree5b4866d8c3c0b7eb524a8f70050b3c2868b6ba01 /src/client
parent5bae5debdf94f6bbec61f4ff50ecbf3c1231e0e3 (diff)
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 <qt_ci_bot@qt-project.org> Reviewed-by: David Edmundson <davidedmundson@kde.org>
Diffstat (limited to 'src/client')
-rw-r--r--src/client/CMakeLists.txt4
-rw-r--r--src/client/qwaylanddisplay.cpp17
-rw-r--r--src/client/qwaylanddisplay_p.h8
-rw-r--r--src/client/qwaylandfractionalscale.cpp36
-rw-r--r--src/client/qwaylandfractionalscale_p.h50
-rw-r--r--src/client/qwaylandviewport.cpp35
-rw-r--r--src/client/qwaylandviewport_p.h42
-rw-r--r--src/client/qwaylandwindow.cpp61
-rw-r--r--src/client/qwaylandwindow_p.h7
9 files changed, 253 insertions, 7 deletions
diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt
index 820c9eada..47312010f 100644
--- a/src/client/CMakeLists.txt
+++ b/src/client/CMakeLists.txt
@@ -32,6 +32,7 @@ qt_internal_add_module(WaylandClient
qwaylanddecorationplugin.cpp qwaylanddecorationplugin_p.h
qwaylanddisplay.cpp qwaylanddisplay_p.h
qwaylandextendedsurface.cpp qwaylandextendedsurface_p.h
+ qwaylandfractionalscale.cpp qwaylandfractionalscale_p.h
qwaylandinputcontext.cpp qwaylandinputcontext_p.h
qwaylandtextinputv1.cpp qwaylandtextinputv1_p.h
qwaylandtextinputv2.cpp qwaylandtextinputv2_p.h
@@ -50,6 +51,7 @@ qt_internal_add_module(WaylandClient
qwaylandsubsurface.cpp qwaylandsubsurface_p.h
qwaylandsurface.cpp qwaylandsurface_p.h
qwaylandtouch.cpp qwaylandtouch_p.h
+ qwaylandviewport.cpp qwaylandviewport_p.h
qwaylandwindow.cpp qwaylandwindow_p.h
qwaylandwindowmanagerintegration.cpp qwaylandwindowmanagerintegration_p.h
shellintegration/qwaylandclientshellapi_p.h
@@ -88,6 +90,8 @@ qt6_generate_wayland_protocol_client_sources(WaylandClient
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/wayland.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/wp-primary-selection-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-output-unstable-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/fractional-scale-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/viewporter.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-key-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-text-input-method-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-windowmanager.xml
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index 18eb71c36..52ea64929 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -50,6 +50,8 @@
#include <QtWaylandClient/private/qwayland-text-input-unstable-v4-wip.h>
#include <QtWaylandClient/private/qwayland-wp-primary-selection-unstable-v1.h>
#include <QtWaylandClient/private/qwayland-qt-text-input-method-unstable-v1.h>
+#include <QtWaylandClient/private/qwayland-fractional-scale-v1.h>
+#include <QtWaylandClient/private/qwayland-viewporter.h>
#include <QtCore/private/qcore_unix_p.h>
@@ -294,6 +296,17 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
return mSubCompositor->get_subsurface(window->wlSurface(), parent->wlSurface());
}
+::wp_viewport *QWaylandDisplay::createViewport(QWaylandWindow *window)
+{
+ if (!mViewporter) {
+ qCWarning(lcQpaWayland) << "Can't create wp_viewport, not supported by the compositor.";
+ return nullptr;
+ }
+
+ Q_ASSERT(window->wlSurface());
+ return mViewporter->get_viewport(window->wlSurface());
+}
+
QWaylandShellIntegration *QWaylandDisplay::shellIntegration() const
{
return mWaylandIntegration->shellIntegration();
@@ -597,6 +610,10 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
mXdgOutputManager.reset(new QWaylandXdgOutputManagerV1(this, id, version));
for (auto *screen : std::as_const(mWaitingScreens))
screen->initXdgOutput(xdgOutputManager());
+ } else if (interface == QLatin1String(QtWayland::wp_fractional_scale_manager_v1::interface()->name)) {
+ mFractionalScaleManager.reset(new QtWayland::wp_fractional_scale_manager_v1(registry, id, 1));
+ } else if (interface == QLatin1String("wp_viewporter")) {
+ mViewporter.reset(new QtWayland::wp_viewporter(registry, id, qMin(1u, version)));
}
mGlobals.append(RegistryGlobal(id, interface, version, registry));
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index 473016f1e..640f33b8e 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -36,6 +36,7 @@
#endif
struct wl_cursor_image;
+struct wp_viewport;
QT_BEGIN_NAMESPACE
@@ -50,6 +51,8 @@ namespace QtWayland {
class zwp_text_input_manager_v2;
class zwp_text_input_manager_v4;
class qt_text_input_method_manager_v1;
+ class wp_viewporter;
+ class wp_fractional_scale_manager_v1;
}
namespace QtWaylandClient {
@@ -110,6 +113,7 @@ public:
struct wl_surface *createSurface(void *handle);
struct ::wl_region *createRegion(const QRegion &qregion);
struct ::wl_subsurface *createSubSurface(QWaylandWindow *window, QWaylandWindow *parent);
+ struct ::wp_viewport *createViewport(QWaylandWindow *window);
QWaylandShellIntegration *shellIntegration() const;
QWaylandClientBufferIntegration *clientBufferIntegration() const;
@@ -146,6 +150,8 @@ public:
QtWayland::zwp_text_input_manager_v4 *textInputManagerv4() const { return mTextInputManagerv4.data(); }
QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); }
QWaylandXdgOutputManagerV1 *xdgOutputManager() const { return mXdgOutputManager.data(); }
+ QtWayland::wp_fractional_scale_manager_v1 *fractionalScaleManager() const { return mFractionalScaleManager.data(); }
+ QtWayland::wp_viewporter *viewporter() const { return mViewporter.data(); }
struct RegistryGlobal {
uint32_t id;
@@ -265,6 +271,8 @@ private:
QScopedPointer<QtWayland::zwp_text_input_manager_v4> mTextInputManagerv4;
QScopedPointer<QWaylandHardwareIntegration> mHardwareIntegration;
QScopedPointer<QWaylandXdgOutputManagerV1> mXdgOutputManager;
+ QScopedPointer<QtWayland::wp_viewporter> mViewporter;
+ QScopedPointer<QtWayland::wp_fractional_scale_manager_v1> mFractionalScaleManager;
int mFd = -1;
int mWritableNotificationFd = -1;
QList<RegistryGlobal> mGlobals;
diff --git a/src/client/qwaylandfractionalscale.cpp b/src/client/qwaylandfractionalscale.cpp
new file mode 100644
index 000000000..324a0b729
--- /dev/null
+++ b/src/client/qwaylandfractionalscale.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwaylandfractionalscale_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandFractionalScale::QWaylandFractionalScale(struct ::wp_fractional_scale_v1 *object)
+ : QtWayland::wp_fractional_scale_v1(object)
+{}
+
+
+QWaylandFractionalScale::~QWaylandFractionalScale()
+{
+ destroy();
+}
+
+qreal QWaylandFractionalScale::preferredScale() const
+{
+ return mPreferredScale;
+}
+
+void QWaylandFractionalScale::wp_fractional_scale_v1_preferred_scale(uint scale)
+{
+ qreal preferredScale = scale / 120.0; // hardcoded denominator determined in the spec
+ if (preferredScale != mPreferredScale) {
+ mPreferredScale = preferredScale;
+ Q_EMIT preferredScaleChanged();
+ }
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandfractionalscale_p.h b/src/client/qwaylandfractionalscale_p.h
new file mode 100644
index 000000000..0483eb338
--- /dev/null
+++ b/src/client/qwaylandfractionalscale_p.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWAYLANDFRACTIONALSCALE_P_H
+#define QWAYLANDFRACTIONALSCALE_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.
+//
+
+#include <QtWaylandClient/private/qwayland-fractional-scale-v1.h>
+#include <QtWaylandClient/qtwaylandclientglobal.h>
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandFractionalScale : public QObject, public QtWayland::wp_fractional_scale_v1
+{
+ Q_OBJECT
+public:
+ explicit QWaylandFractionalScale(struct ::wp_fractional_scale_v1 *object);
+ ~QWaylandFractionalScale();
+
+ qreal preferredScale() const;
+
+Q_SIGNALS:
+ void preferredScaleChanged();
+
+protected:
+ void wp_fractional_scale_v1_preferred_scale(uint scale) override;
+
+private:
+ qreal mPreferredScale = 1.0;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/client/qwaylandviewport.cpp b/src/client/qwaylandviewport.cpp
new file mode 100644
index 000000000..3252718c0
--- /dev/null
+++ b/src/client/qwaylandviewport.cpp
@@ -0,0 +1,35 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwaylandviewport_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandViewport::QWaylandViewport(::wp_viewport *viewport)
+ : QtWayland::wp_viewport(viewport)
+{
+}
+
+QWaylandViewport::~QWaylandViewport()
+{
+ destroy();
+}
+
+void QWaylandViewport::setSource(const QRectF &source)
+{
+ set_source(wl_fixed_from_double(source.x()),
+ wl_fixed_from_double(source.y()),
+ wl_fixed_from_double(source.width()),
+ wl_fixed_from_double(source.height()));
+}
+
+void QWaylandViewport::setDestination(const QSize &destination)
+{
+ set_destination(destination.width(), destination.height());
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandviewport_p.h b/src/client/qwaylandviewport_p.h
new file mode 100644
index 000000000..e1dfeb3a7
--- /dev/null
+++ b/src/client/qwaylandviewport_p.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWAYLANDVIEWPORT_P_H
+#define QWAYLANDVIEWPORT_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.
+//
+
+#include <QtWaylandClient/private/qwayland-viewporter.h>
+#include <QtWaylandClient/qtwaylandclientglobal.h>
+
+#include <QRect>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandViewport : public QtWayland::wp_viewport
+{
+public:
+ explicit QWaylandViewport(::wp_viewport *viewport);
+ ~QWaylandViewport() override;
+
+ void setSource(const QRectF &source);
+ void setDestination(const QSize &destination);
+
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDVIEWPORT_P_H
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index f4d49c84d..56b9af282 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 <QtCore/QFileInfo>
#include <QtCore/QPointer>
@@ -29,6 +31,8 @@
#include <QtCore/QDebug>
#include <QtCore/QThread>
+#include <QtWaylandClient/private/qwayland-fractional-scale-v1.h>
+
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<QWaylandWindow *>(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<QWaylandScreen *>(newScreen)->scale();
+ if (mFractionalScale)
+ return;
+
+ int scale = mLastReportedScreen->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(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"
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index 0f8c55151..6531606a7 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -53,6 +53,8 @@ class QWaylandPointerEvent;
class QWaylandPointerGestureSwipeEvent;
class QWaylandPointerGesturePinchEvent;
class QWaylandSurface;
+class QWaylandFractionalScale;
+class QWaylandViewport;
class Q_WAYLANDCLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformWindow
{
@@ -233,6 +235,8 @@ protected:
// mSurface can be written by the main thread. Other threads should claim a read lock for access
mutable QReadWriteLock mSurfaceLock;
QScopedPointer<QWaylandSurface> mSurface;
+ QScopedPointer<QWaylandFractionalScale> mFractionalScale;
+ QScopedPointer<QWaylandViewport> mViewport;
QWaylandShellSurface *mShellSurface = nullptr;
QWaylandSubSurface *mSubSurfaceWindow = nullptr;
@@ -284,7 +288,7 @@ protected:
bool mSentInitialResize = false;
QPoint mOffset;
- int mScale = 1;
+ qreal mScale = 1;
QPlatformScreen *mLastReportedScreen = nullptr;
QIcon mWindowIcon;
@@ -314,6 +318,7 @@ private:
QPlatformScreen *calculateScreenFromSurfaceEvents() const;
void setOpaqueArea(const QRegion &opaqueArea);
bool isOpaque() const;
+ void updateViewport();
void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
void handleScreensChanged();