diff options
author | David Edmundson <davidedmundson@kde.org> | 2022-03-23 15:35:50 +0000 |
---|---|---|
committer | David Edmundson <davidedmundson@kde.org> | 2022-12-07 20:36:40 +0000 |
commit | 23d3fc712cdf7fc0a4ff837082de9ba773e8605c (patch) | |
tree | 5b4866d8c3c0b7eb524a8f70050b3c2868b6ba01 /tests | |
parent | 5bae5debdf94f6bbec61f4ff50ecbf3c1231e0e3 (diff) | |
download | qtwayland-23d3fc712cdf7fc0a4ff837082de9ba773e8605c.tar.gz |
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 'tests')
-rw-r--r-- | tests/auto/client/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/auto/client/scaling/CMakeLists.txt | 10 | ||||
-rw-r--r-- | tests/auto/client/scaling/tst_scaling.cpp | 135 | ||||
-rw-r--r-- | tests/auto/client/shared/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tests/auto/client/shared/fractionalscalev1.cpp | 40 | ||||
-rw-r--r-- | tests/auto/client/shared/fractionalscalev1.h | 39 | ||||
-rw-r--r-- | tests/auto/client/shared/mockcompositor.cpp | 3 | ||||
-rw-r--r-- | tests/auto/client/shared/mockcompositor.h | 4 | ||||
-rw-r--r-- | tests/auto/client/shared/viewport.cpp | 58 | ||||
-rw-r--r-- | tests/auto/client/shared/viewport.h | 50 |
10 files changed, 347 insertions, 0 deletions
diff --git a/tests/auto/client/CMakeLists.txt b/tests/auto/client/CMakeLists.txt index 749e6b83..44cf3271 100644 --- a/tests/auto/client/CMakeLists.txt +++ b/tests/auto/client/CMakeLists.txt @@ -25,8 +25,10 @@ if (NOT WEBOS) add_subdirectory(xdgdecorationv1) add_subdirectory(xdgoutput) add_subdirectory(xdgshell) + add_subdirectory(scaling) endif() add_subdirectory(multithreaded) + if(QT_FEATURE_im) add_subdirectory(inputcontext) endif() diff --git a/tests/auto/client/scaling/CMakeLists.txt b/tests/auto/client/scaling/CMakeLists.txt new file mode 100644 index 00000000..a93f0c57 --- /dev/null +++ b/tests/auto/client/scaling/CMakeLists.txt @@ -0,0 +1,10 @@ +##################################################################### +## tst_scaling Test: +##################################################################### + +qt_internal_add_test(tst_scaling + SOURCES + tst_scaling.cpp + PUBLIC_LIBRARIES + SharedClientTest +) diff --git a/tests/auto/client/scaling/tst_scaling.cpp b/tests/auto/client/scaling/tst_scaling.cpp new file mode 100644 index 00000000..bceea92d --- /dev/null +++ b/tests/auto/client/scaling/tst_scaling.cpp @@ -0,0 +1,135 @@ +// 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 "mockcompositor.h" +#include <QtOpenGL/QOpenGLWindow> +#include <QtGui/QRasterWindow> +#include <QtGui/qpa/qplatformnativeinterface.h> +#include <QtWaylandClient/private/wayland-wayland-client-protocol.h> +#include <QtWaylandClient/private/qwaylandwindow_p.h> + +using namespace MockCompositor; + +class tst_scaling : public QObject, private DefaultCompositor +{ + Q_OBJECT +private slots: + void init(); + void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); } + void scaledWindow(); + void roundingPolicy_data(); + void roundingPolicy(); + +}; + +void tst_scaling::init() +{ + setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1); +} + +void tst_scaling::scaledWindow() +{ + QRasterWindow window; + window.resize(100, 100); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + + QSignalSpy configureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted); + QSignalSpy surfaceCommitSpy(exec([=] { return surface(); }), &Surface::commit); + + const QSize configureSize(100, 100); + + exec([=] { + QVERIFY(fractionalScale()); + fractionalScale()->send_preferred_scale(1.5 * 120); + xdgToplevel()->sendCompleteConfigure(configureSize); + }); + + QTRY_COMPARE(configureSpy.count(), 1); + QCOMPARE(window.devicePixelRatio(), 1.5); + + exec([=] { + Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer; + QVERIFY(buffer); + QCOMPARE(buffer->size(), QSize(150, 150)); + Viewport *vp = viewport(); + QVERIFY(vp); + QCOMPARE(vp->m_destination, QSize(100, 100)); + }); + + // resize the window + window.resize(200,200); + QCOMPARE(window.size(), QSize(200,200)); + + QVERIFY(surfaceCommitSpy.wait()); + exec([=] { + Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer; + QVERIFY(buffer); + QCOMPARE(buffer->size(), QSize(300, 300)); + Viewport *vp = viewport(); + QVERIFY(vp); + QCOMPARE(vp->m_destination, QSize(200, 200)); + }); + + // dynamic scale change + exec([=] { + QVERIFY(fractionalScale()); + fractionalScale()->send_preferred_scale(2.5 * 120); + }); + QTRY_COMPARE(window.devicePixelRatio(), 2.5); + QCOMPARE(window.size(), QSize(200,200)); + + QVERIFY(surfaceCommitSpy.wait()); + exec([=] { + Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer; + QVERIFY(buffer); + QCOMPARE(buffer->size(), QSize(500, 500)); + Viewport *vp = viewport(); + QVERIFY(vp); + QCOMPARE(vp->m_destination, QSize(200, 200)); + }); +} + +void tst_scaling::roundingPolicy_data() +{ + QTest::addColumn<QSize>("windowSize"); + QTest::addColumn<qreal>("scale"); + QTest::addColumn<QSize>("expectedBufferSize"); + + QTest::newRow("1.125 - round down") << QSize(10, 10) << 1.125 << QSize(11,11); + QTest::newRow("1.25 - round up") << QSize(10, 10) << 1.25 << QSize(13,13); + QTest::newRow("1.5 - don't round") << QSize(10, 10) << 1.5 << QSize(15,15); +} + +void tst_scaling::roundingPolicy() +{ + QFETCH(QSize, windowSize); + QFETCH(qreal, scale); + QFETCH(QSize, expectedBufferSize); + + + QRasterWindow window; + window.resize(windowSize); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + + QSignalSpy surfaceCommitSpy(exec([=] { return surface(); }), &Surface::commit); + + exec([=] { + QVERIFY(fractionalScale()); + fractionalScale()->send_preferred_scale(scale * 120); + xdgToplevel()->sendCompleteConfigure(); + }); + + QVERIFY(surfaceCommitSpy.wait()); + + exec([=] { + Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer; + QVERIFY(buffer); + QCOMPARE(buffer->size(), expectedBufferSize); + }); +} + + +QCOMPOSITOR_TEST_MAIN(tst_scaling) +#include "tst_scaling.moc" diff --git a/tests/auto/client/shared/CMakeLists.txt b/tests/auto/client/shared/CMakeLists.txt index 653927f0..8112ffb7 100644 --- a/tests/auto/client/shared/CMakeLists.txt +++ b/tests/auto/client/shared/CMakeLists.txt @@ -11,9 +11,11 @@ qt_manual_moc(moc_files corecompositor.h datadevice.h fullscreenshellv1.h + fractionalscalev1.h iviapplication.h textinput.h qttextinput.h + viewport.h xdgoutputv1.h xdgshell.h ) @@ -24,12 +26,14 @@ add_library(SharedClientTest coreprotocol.cpp coreprotocol.h datadevice.cpp datadevice.h fullscreenshellv1.cpp fullscreenshellv1.h + fractionalscalev1.cpp fractionalscalev1.h iviapplication.cpp iviapplication.h mockcompositor.cpp mockcompositor.h textinput.cpp textinput.h qttextinput.cpp qttextinput.h xdgoutputv1.cpp xdgoutputv1.h xdgshell.cpp xdgshell.h + viewport.cpp viewport.h ${moc_files} ) @@ -41,6 +45,8 @@ qt6_generate_wayland_protocol_server_sources(SharedClientTest ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/tablet-unstable-v2.xml ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/text-input-unstable-v2.xml ${PROJECT_SOURCE_DIR}/src/extensions/qt-text-input-method-unstable-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/fractional-scale-v1.xml + ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/viewporter.xml ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/wayland.xml ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-decoration-unstable-v1.xml ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-output-unstable-v1.xml diff --git a/tests/auto/client/shared/fractionalscalev1.cpp b/tests/auto/client/shared/fractionalscalev1.cpp new file mode 100644 index 00000000..5548c3d6 --- /dev/null +++ b/tests/auto/client/shared/fractionalscalev1.cpp @@ -0,0 +1,40 @@ +// 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 "fractionalscalev1.h" + +namespace MockCompositor { + +FractionalScaleManager::FractionalScaleManager(CoreCompositor *compositor, int version) + : QtWaylandServer::wp_fractional_scale_manager_v1(compositor->m_display, version) +{ +} + +void FractionalScaleManager::wp_fractional_scale_manager_v1_get_fractional_scale(Resource *resource, uint32_t id, wl_resource *surface) +{ + auto *s = fromResource<Surface>(surface); + auto *scaler = new FractionalScale(s, resource->client(), id, resource->version()); + connect(scaler, &QObject::destroyed, this, [this, scaler]() { + m_fractionalScales.removeOne(scaler); + }); + m_fractionalScales << scaler; +} + +FractionalScale::FractionalScale(Surface *surface, wl_client *client, int id, int version) + : QtWaylandServer::wp_fractional_scale_v1(client, id, version) + , m_surface(surface) +{ +} + +void FractionalScale::wp_fractional_scale_v1_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete this; +} + +void FractionalScale::wp_fractional_scale_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +} diff --git a/tests/auto/client/shared/fractionalscalev1.h b/tests/auto/client/shared/fractionalscalev1.h new file mode 100644 index 00000000..fd5483e9 --- /dev/null +++ b/tests/auto/client/shared/fractionalscalev1.h @@ -0,0 +1,39 @@ +// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef MOCKCOMPOSITOR_FRACTIONALSCALE_H +#define MOCKCOMPOSITOR_FRACTIONALSCALE_H + +#include "coreprotocol.h" +#include <qwayland-server-fractional-scale-v1.h> + +namespace MockCompositor { + +class FractionalScale; + +class FractionalScaleManager : public Global, public QtWaylandServer::wp_fractional_scale_manager_v1 +{ + Q_OBJECT +public: + explicit FractionalScaleManager(CoreCompositor *compositor, int version = 1); + QList<FractionalScale *> m_fractionalScales; + +protected: + void wp_fractional_scale_manager_v1_get_fractional_scale(Resource *resource, uint32_t id, wl_resource *surface) override; +}; + +class FractionalScale : public QObject, public QtWaylandServer::wp_fractional_scale_v1 +{ + Q_OBJECT +public: + explicit FractionalScale(Surface *surface, wl_client *client, int id, int version); + Surface *m_surface; + +protected: + void wp_fractional_scale_v1_destroy_resource(Resource *resource) override; + void wp_fractional_scale_v1_destroy(Resource *resource) override; +}; + +} + +#endif diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp index 1266f776..71f3775a 100644 --- a/tests/auto/client/shared/mockcompositor.cpp +++ b/tests/auto/client/shared/mockcompositor.cpp @@ -21,6 +21,9 @@ DefaultCompositor::DefaultCompositor(CompositorType t) add<Seat>(Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch); add<WlShell>(); add<XdgWmBase>(); + add<FractionalScaleManager>(); + add<Viewporter>(); + switch (m_type) { case CompositorType::Default: add<Shm>(); diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h index 3b70a430..6803a646 100644 --- a/tests/auto/client/shared/mockcompositor.h +++ b/tests/auto/client/shared/mockcompositor.h @@ -11,6 +11,8 @@ #include "fullscreenshellv1.h" #include "iviapplication.h" #include "xdgshell.h" +#include "viewport.h" +#include "fractionalscalev1.h" #include <QtGui/QGuiApplication> @@ -46,6 +48,8 @@ public: Keyboard *keyboard() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_keyboard; } FullScreenShellV1 *fullScreenShellV1() {return get<FullScreenShellV1>();}; IviSurface *iviSurface(int i = 0) { return get<IviApplication>()->m_iviSurfaces.value(i, nullptr); } + FractionalScale *fractionalScale(int i = 0) {return get<FractionalScaleManager>()->m_fractionalScales.value(i, nullptr); } + Viewport *viewport(int i = 0) {return get<Viewporter>()->m_viewports.value(i, nullptr); } uint sendXdgShellPing(); void xdgPingAndWaitForPong(); diff --git a/tests/auto/client/shared/viewport.cpp b/tests/auto/client/shared/viewport.cpp new file mode 100644 index 00000000..c1e763fe --- /dev/null +++ b/tests/auto/client/shared/viewport.cpp @@ -0,0 +1,58 @@ +// 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 "viewport.h" + +namespace MockCompositor { + +Viewporter::Viewporter(CoreCompositor *compositor, int version) + : QtWaylandServer::wp_viewporter(compositor->m_display, version) +{ +} + +void Viewporter::wp_viewporter_get_viewport(Resource *resource, uint32_t id, wl_resource *surface) +{ + auto *s = fromResource<Surface>(surface); + auto *viewport = new Viewport(s, resource->client(), id, resource->version()); + connect(viewport, &QObject::destroyed, this, [this, viewport]() { + m_viewports.removeOne(viewport); + }); + m_viewports << viewport; +} + +Viewport::Viewport(Surface *surface, wl_client *client, int id, int version) + : QtWaylandServer::wp_viewport(client, id, version) + , m_surface(surface) +{ +} + +void Viewport::wp_viewport_set_source(Resource *resource, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) +{ + Q_UNUSED(resource) + m_source = QRectF(wl_fixed_to_double(x), + wl_fixed_to_double(y), + wl_fixed_to_double(width), + wl_fixed_to_double(height)); + Q_EMIT sourceChanged(); +} + +void Viewport::wp_viewport_set_destination(Resource *resource, int32_t width, int32_t height) +{ + Q_UNUSED(resource) + + m_destination = QSize(width, height); + Q_EMIT destinationChanged(); +} + +void Viewport::wp_viewport_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete this; +} + +void Viewport::wp_viewport_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +} diff --git a/tests/auto/client/shared/viewport.h b/tests/auto/client/shared/viewport.h new file mode 100644 index 00000000..018e28e1 --- /dev/null +++ b/tests/auto/client/shared/viewport.h @@ -0,0 +1,50 @@ +// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef MOCKCOMPOSITOR_VIEWPORT_H +#define MOCKCOMPOSITOR_VIEWPORT_H + +#include "coreprotocol.h" +#include <qwayland-server-viewporter.h> + +namespace MockCompositor { + +class Viewport; + +class Viewporter : public Global, public QtWaylandServer::wp_viewporter +{ + Q_OBJECT +public: + explicit Viewporter(CoreCompositor *compositor, int version = 1); + QList<Viewport *> m_viewports; + +protected: + void wp_viewporter_get_viewport(Resource *resource, uint32_t id, wl_resource *surface) override; +}; + +class Viewport : public QObject, public QtWaylandServer::wp_viewport +{ + Q_OBJECT +public: + explicit Viewport(Surface *surface, wl_client *client, int id, int version); + + QRectF m_source; + QSize m_destination; + + Surface* m_surface; + +Q_SIGNALS: + void sourceChanged(); + void destinationChanged(); + +protected: + void wp_viewport_set_source(Resource *resource, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) override; + void wp_viewport_set_destination(Resource *resource, int32_t width, int32_t height) override; + + void wp_viewport_destroy_resource(Resource *resource) override; + void wp_viewport_destroy(Resource *resource) override; +}; + +} + +#endif |