From 961bcbde0834e437db343f0971c104d34b736930 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Wed, 25 Jul 2018 22:14:17 +0200 Subject: [PATCH] OutputManagement fractional scaling Summary: In order to have fractional scaling in kwin, we need to communicate it with kscreen, which means changing the data type in our config protocols. This introduces a new method on outputdevice and outputconfiguration to set/request scale as a float. wl_output is and should remain unchanged as an int No urgent rush for reviewing/merging this as it's useless without other changes. Test Plan: Attached unit tests Reviewers: #kwin, romangg Subscribers: romangg, zzag, kde-frameworks-devel Tags: #frameworks Differential Revision: https://phabricator.kde.org/D13601 --- .../client/test_wayland_outputdevice.cpp | 42 ++++++++++++++++++- .../client/test_wayland_outputmanagement.cpp | 32 +++++++++++++- src/wayland/server/outputchangeset.cpp | 8 +++- src/wayland/server/outputchangeset.h | 8 +++- src/wayland/server/outputchangeset_p.h | 4 +- .../server/outputconfiguration_interface.cpp | 23 +++++++++- src/wayland/server/outputdevice_interface.cpp | 42 ++++++++++++++++--- src/wayland/server/outputdevice_interface.h | 6 ++- .../server/outputmanagement_interface.cpp | 2 +- 9 files changed, 152 insertions(+), 15 deletions(-) diff --git a/src/wayland/autotests/client/test_wayland_outputdevice.cpp b/src/wayland/autotests/client/test_wayland_outputdevice.cpp index b349955d56..5bab04237c 100644 --- a/src/wayland/autotests/client/test_wayland_outputdevice.cpp +++ b/src/wayland/autotests/client/test_wayland_outputdevice.cpp @@ -44,6 +44,7 @@ private Q_SLOTS: void testRegistry(); void testModeChanges(); + void testScaleChange_legacy(); void testScaleChange(); void testSubPixel_data(); @@ -310,7 +311,7 @@ void TestWaylandOutputDevice::testModeChanges() QCOMPARE(output.pixelSize(), QSize(1280, 1024)); } -void TestWaylandOutputDevice::testScaleChange() +void TestWaylandOutputDevice::testScaleChange_legacy() { KWayland::Client::Registry registry; QSignalSpy interfacesAnnouncedSpy(®istry, &KWayland::Client::Registry::interfacesAnnounced); @@ -336,12 +337,51 @@ void TestWaylandOutputDevice::testScaleChange() m_serverOutputDevice->setScale(2); QVERIFY(outputChanged.wait()); QCOMPARE(output.scale(), 2); + QCOMPARE(output.scaleF(), 2.0); //check we're forward compatiable + // change once more outputChanged.clear(); m_serverOutputDevice->setScale(4); QVERIFY(outputChanged.wait()); QCOMPARE(output.scale(), 4); + QCOMPARE(output.scaleF(), 4.0); +} + +void TestWaylandOutputDevice::testScaleChange() +{ + KWayland::Client::Registry registry; + QSignalSpy interfacesAnnouncedSpy(®istry, &KWayland::Client::Registry::interfacesAnnounced); + QVERIFY(interfacesAnnouncedSpy.isValid()); + QSignalSpy announced(®istry, &KWayland::Client::Registry::outputDeviceAnnounced); + registry.setEventQueue(m_queue); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + registry.setup(); + wl_display_flush(m_connection->display()); + QVERIFY(interfacesAnnouncedSpy.wait()); + + KWayland::Client::OutputDevice output; + QSignalSpy outputChanged(&output, &KWayland::Client::OutputDevice::done); + QVERIFY(outputChanged.isValid()); + output.setup(registry.bindOutputDevice(announced.first().first().value(), announced.first().last().value())); + wl_display_flush(m_connection->display()); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.scaleF(), 1.0); + + // change the scale + outputChanged.clear(); + m_serverOutputDevice->setScaleF(2.2); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.scale(), 2); //check backwards compatibility works + QCOMPARE(wl_fixed_from_double(output.scaleF()), wl_fixed_from_double(2.2)); + + // change once more + outputChanged.clear(); + m_serverOutputDevice->setScaleF(4.9); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.scale(), 5); + QCOMPARE(wl_fixed_from_double(output.scaleF()), wl_fixed_from_double(4.9)); } void TestWaylandOutputDevice::testSubPixel_data() diff --git a/src/wayland/autotests/client/test_wayland_outputmanagement.cpp b/src/wayland/autotests/client/test_wayland_outputmanagement.cpp index 3a66f564bc..dfcf791267 100644 --- a/src/wayland/autotests/client/test_wayland_outputmanagement.cpp +++ b/src/wayland/autotests/client/test_wayland_outputmanagement.cpp @@ -60,6 +60,7 @@ private Q_SLOTS: void testFailed(); void testExampleConfig(); + void testScale(); void testRemoval(); @@ -229,7 +230,7 @@ void TestWaylandOutputManagement::applyPendingChanges() outputdevice->setGlobalPosition(c->position()); } if (c->scaleChanged()) { - outputdevice->setScale(c->scale()); + outputdevice->setScaleF(c->scaleF()); } } } @@ -472,5 +473,34 @@ void TestWaylandOutputManagement::testExampleConfig() QVERIFY(configAppliedSpy.wait(200)); } +void TestWaylandOutputManagement::testScale() +{ + createConfig(); + + auto config = m_outputConfiguration; + KWayland::Client::OutputDevice *output = m_clientOutputs.first(); + + config->setScaleF(output, 2.3); + config->apply(); + + QSignalSpy configAppliedSpy(config, &OutputConfiguration::applied); + m_outputConfigurationInterface->setApplied(); + QVERIFY(configAppliedSpy.isValid()); + QVERIFY(configAppliedSpy.wait(200)); + + QCOMPARE(output->scale(), 2); //test backwards compatibility + QCOMPARE(wl_fixed_from_double(output->scaleF()), wl_fixed_from_double(2.3)); + + config->setScale(output, 3); + config->apply(); + + m_outputConfigurationInterface->setApplied(); + QVERIFY(configAppliedSpy.isValid()); + QVERIFY(configAppliedSpy.wait(200)); + + QCOMPARE(output->scale(), 3); + QCOMPARE(output->scaleF(), 3.0); //test fowards compatibility +} + QTEST_GUILESS_MAIN(TestWaylandOutputManagement) #include "test_wayland_outputmanagement.moc" diff --git a/src/wayland/server/outputchangeset.cpp b/src/wayland/server/outputchangeset.cpp index 107e946301..2393dbb384 100644 --- a/src/wayland/server/outputchangeset.cpp +++ b/src/wayland/server/outputchangeset.cpp @@ -102,10 +102,16 @@ QPoint OutputChangeSet::position() const bool OutputChangeSet::scaleChanged() const { Q_D(); - return d->scale != d->o->scale(); + return !qFuzzyCompare(d->scale, d->o->scaleF()); } int OutputChangeSet::scale() const +{ + Q_D(); + return qRound(d->scale); +} + +qreal OutputChangeSet::scaleF() const { Q_D(); return d->scale; diff --git a/src/wayland/server/outputchangeset.h b/src/wayland/server/outputchangeset.h index c8c19d3773..62385b20ba 100644 --- a/src/wayland/server/outputchangeset.h +++ b/src/wayland/server/outputchangeset.h @@ -78,8 +78,14 @@ public: OutputDeviceInterface::Transform transform() const; /** The new value for globalPosition. */ QPoint position() const; - /** The new value for scale. */ + /** The new value for scale. + @deprecated see scaleF + */ int scale() const; + /** The new value for scale. + * @since 5.XX + */ + qreal scaleF() const; private: friend class OutputConfigurationInterface; diff --git a/src/wayland/server/outputchangeset_p.h b/src/wayland/server/outputchangeset_p.h index 4bbfee3d1c..4b555c810f 100644 --- a/src/wayland/server/outputchangeset_p.h +++ b/src/wayland/server/outputchangeset_p.h @@ -40,9 +40,9 @@ namespace KWayland int modeId; OutputDeviceInterface::Transform transform; QPoint position; - int scale; + qreal scale; }; } } -#endif \ No newline at end of file +#endif diff --git a/src/wayland/server/outputconfiguration_interface.cpp b/src/wayland/server/outputconfiguration_interface.cpp index 9d95d1ae5f..bef2b489f7 100644 --- a/src/wayland/server/outputconfiguration_interface.cpp +++ b/src/wayland/server/outputconfiguration_interface.cpp @@ -55,7 +55,7 @@ public: OutputManagementInterface *outputManagement; QHash changes; - static const quint32 s_version = 1; + static const quint32 s_version = 2; private: static void enableCallback(wl_client *client, wl_resource *resource, @@ -69,6 +69,8 @@ private: static void scaleCallback(wl_client *client, wl_resource *resource, wl_resource * outputdevice, int32_t scale); static void applyCallback(wl_client *client, wl_resource *resource); + static void scaleFCallback(wl_client *client, wl_resource *resource, + wl_resource * outputdevice, wl_fixed_t scale); OutputConfigurationInterface *q_func() { return reinterpret_cast(q); @@ -83,7 +85,8 @@ const struct org_kde_kwin_outputconfiguration_interface OutputConfigurationInter transformCallback, positionCallback, scaleCallback, - applyCallback + applyCallback, + scaleFCallback }; OutputConfigurationInterface::OutputConfigurationInterface(OutputManagementInterface* parent, wl_resource* parentResource): Resource(new Private(this, parent, parentResource)) @@ -185,6 +188,22 @@ void OutputConfigurationInterface::Private::scaleCallback(wl_client *client, wl_ s->pendingChanges(o)->d_func()->scale = scale; } +void OutputConfigurationInterface::Private::scaleFCallback(wl_client *client, wl_resource *resource, wl_resource * outputdevice, wl_fixed_t scale_fixed) +{ + Q_UNUSED(client); + const qreal scale = wl_fixed_to_double(scale_fixed); + + if (scale <= 0) { + qCWarning(KWAYLAND_SERVER) << "Requested to scale output device to" << scale << ", but I can't do that."; + return; + } + OutputDeviceInterface *o = OutputDeviceInterface::get(outputdevice); + auto s = cast(resource); + Q_ASSERT(s); + + s->pendingChanges(o)->d_func()->scale = scale; +} + void OutputConfigurationInterface::Private::applyCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client); diff --git a/src/wayland/server/outputdevice_interface.cpp b/src/wayland/server/outputdevice_interface.cpp index 6188650d66..c34da1ce56 100644 --- a/src/wayland/server/outputdevice_interface.cpp +++ b/src/wayland/server/outputdevice_interface.cpp @@ -54,7 +54,7 @@ public: QPoint globalPosition; QString manufacturer = QStringLiteral("org.kde.kwin"); QString model = QStringLiteral("none"); - int scale = 1; + qreal scale = 1.0; SubPixel subPixel = SubPixel::Unknown; Transform transform = Transform::Normal; QList modes; @@ -80,7 +80,7 @@ private: static QVector s_privates; }; -const quint32 OutputDeviceInterface::Private::s_version = 1; +const quint32 OutputDeviceInterface::Private::s_version = 2; QVector OutputDeviceInterface::Private::s_privates; @@ -138,7 +138,7 @@ OutputDeviceInterface::OutputDeviceInterface(Display *display, QObject *parent) connect(this, &OutputDeviceInterface::globalPositionChanged, this, [this, d] { d->updateGeometry(); }); connect(this, &OutputDeviceInterface::modelChanged, this, [this, d] { d->updateGeometry(); }); connect(this, &OutputDeviceInterface::manufacturerChanged, this, [this, d] { d->updateGeometry(); }); - connect(this, &OutputDeviceInterface::scaleChanged, this, [this, d] { d->updateScale(); }); + connect(this, &OutputDeviceInterface::scaleFChanged, this, [this, d] { d->updateScale(); }); } OutputDeviceInterface::~OutputDeviceInterface() = default; @@ -402,7 +402,11 @@ void OutputDeviceInterface::Private::sendGeometry(wl_resource *resource) void OutputDeviceInterface::Private::sendScale(const ResourceData &data) { - org_kde_kwin_outputdevice_send_scale(data.resource, scale); + if (wl_resource_get_version(data.resource) < ORG_KDE_KWIN_OUTPUTDEVICE_SCALEF_SINCE_VERSION) { + org_kde_kwin_outputdevice_send_scale(data.resource, qRound(scale)); + } else { + org_kde_kwin_outputdevice_send_scalef(data.resource, wl_fixed_from_double(scale)); + } } void OutputDeviceInterface::Private::sendDone(const ResourceData &data) @@ -441,12 +445,33 @@ SETTER(setPhysicalSize, const QSize&, physicalSize) SETTER(setGlobalPosition, const QPoint&, globalPosition) SETTER(setManufacturer, const QString&, manufacturer) SETTER(setModel, const QString&, model) -SETTER(setScale, int, scale) SETTER(setSubPixel, SubPixel, subPixel) SETTER(setTransform, Transform, transform) #undef SETTER +void OutputDeviceInterface::setScale(int scale) +{ + Q_D(); + if (d->scale == scale) { + return; + } + d->scale = scale; + emit scaleChanged(d->scale); + emit scaleFChanged(d->scale); +} + +void OutputDeviceInterface::setScaleF(qreal scale) +{ + Q_D(); + if (qFuzzyCompare(d->scale, scale)) { + return; + } + d->scale = scale; + emit scaleChanged(qRound(d->scale)); + emit scaleFChanged(d->scale); +} + QSize OutputDeviceInterface::physicalSize() const { Q_D(); @@ -472,11 +497,18 @@ QString OutputDeviceInterface::model() const } int OutputDeviceInterface::scale() const +{ + Q_D(); + return qRound(d->scale); +} + +qreal OutputDeviceInterface::scaleF() const { Q_D(); return d->scale; } + OutputDeviceInterface::SubPixel OutputDeviceInterface::subPixel() const { Q_D(); diff --git a/src/wayland/server/outputdevice_interface.h b/src/wayland/server/outputdevice_interface.h index e35e905413..1b7b25d66e 100644 --- a/src/wayland/server/outputdevice_interface.h +++ b/src/wayland/server/outputdevice_interface.h @@ -53,7 +53,7 @@ class KWAYLANDSERVER_EXPORT OutputDeviceInterface : public Global Q_PROPERTY(QString model READ model WRITE setModel NOTIFY modelChanged) Q_PROPERTY(QSize pixelSize READ pixelSize NOTIFY pixelSizeChanged) Q_PROPERTY(int refreshRate READ refreshRate NOTIFY refreshRateChanged) - Q_PROPERTY(int scale READ scale WRITE setScale NOTIFY scaleChanged) + Q_PROPERTY(qreal scale READ scaleF WRITE setScaleF NOTIFY scaleFChanged) Q_PROPERTY(QByteArray edid READ edid WRITE setEdid NOTIFY edidChanged) Q_PROPERTY(OutputDeviceInterface::Enablement enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(QByteArray uuid READ uuid WRITE setUuid NOTIFY uuidChanged) @@ -100,6 +100,7 @@ public: QSize pixelSize() const; int refreshRate() const; int scale() const; + qreal scaleF() const; SubPixel subPixel() const; Transform transform() const; QList modes() const; @@ -114,6 +115,7 @@ public: void setManufacturer(const QString &manufacturer); void setModel(const QString &model); void setScale(int scale); + void setScaleF(qreal scale); void setSubPixel(SubPixel subPixel); void setTransform(Transform transform); void addMode(Mode &mode); @@ -133,7 +135,9 @@ Q_SIGNALS: void modelChanged(const QString&); void pixelSizeChanged(const QSize&); void refreshRateChanged(int); + //@deprecated see scaleChanged(real) void scaleChanged(int); + void scaleFChanged(qreal); void subPixelChanged(SubPixel); void transformChanged(Transform); void modesChanged(); diff --git a/src/wayland/server/outputmanagement_interface.cpp b/src/wayland/server/outputmanagement_interface.cpp index eb687ba40f..3aa0213e3e 100644 --- a/src/wayland/server/outputmanagement_interface.cpp +++ b/src/wayland/server/outputmanagement_interface.cpp @@ -57,7 +57,7 @@ private: QHash configurationInterfaces; }; -const quint32 OutputManagementInterface::Private::s_version = 1; +const quint32 OutputManagementInterface::Private::s_version = 2; const struct org_kde_kwin_outputmanagement_interface OutputManagementInterface::Private::s_interface = { createConfigurationCallback