diff --git a/autotests/client/test_wayland_outputdevice.cpp b/autotests/client/test_wayland_outputdevice.cpp --- a/autotests/client/test_wayland_outputdevice.cpp +++ b/autotests/client/test_wayland_outputdevice.cpp @@ -44,6 +44,7 @@ void testRegistry(); void testModeChanges(); + void testScaleChange_legacy(); void testScaleChange(); void testSubPixel_data(); @@ -310,7 +311,7 @@ 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 @@ 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/autotests/client/test_wayland_outputmanagement.cpp b/autotests/client/test_wayland_outputmanagement.cpp --- a/autotests/client/test_wayland_outputmanagement.cpp +++ b/autotests/client/test_wayland_outputmanagement.cpp @@ -60,6 +60,7 @@ void testFailed(); void testExampleConfig(); + void testScale(); void testRemoval(); @@ -229,7 +230,7 @@ outputdevice->setGlobalPosition(c->position()); } if (c->scaleChanged()) { - outputdevice->setScale(c->scale()); + outputdevice->setScaleF(c->scaleF()); } } } @@ -472,5 +473,34 @@ 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/client/outputconfiguration.h b/src/client/outputconfiguration.h --- a/src/client/outputconfiguration.h +++ b/src/client/outputconfiguration.h @@ -191,12 +191,24 @@ * Scale rendering of this output. * The changes done in this call will be recorded in the * OutputDevice and only applied after apply() has been called. + * @deprecated see setScaleF(qreal) * * @param scale the scaling factor for this output device. * @param outputdevice the OutputDevice this change applies to. */ void setScale(OutputDevice *outputdevice, qint32 scale); + /** + * Scale rendering of this output. + * The changes done in this call will be recorded in the + * OutputDevice and only applied after apply() has been called. + * + * @param scale the scaling factor for this output device. + * @param outputdevice the OutputDevice this change applies to. + * @since 5.XXX + */ + void setScaleF(OutputDevice *outputdevice, qreal scale); + /** * Ask the compositor to apply the changes. * This results in the compositor looking at all outputdevices and if they have diff --git a/src/client/outputconfiguration.cpp b/src/client/outputconfiguration.cpp --- a/src/client/outputconfiguration.cpp +++ b/src/client/outputconfiguration.cpp @@ -163,9 +163,18 @@ } void OutputConfiguration::setScale(OutputDevice *outputdevice, qint32 scale) +{ + setScaleF(outputdevice, scale); +} + +void OutputConfiguration::setScaleF(OutputDevice *outputdevice, qreal scale) { org_kde_kwin_outputdevice *od = outputdevice->output(); - org_kde_kwin_outputconfiguration_scale(d->outputconfiguration, od, scale); + if (wl_proxy_get_version(d->outputconfiguration) < ORG_KDE_KWIN_OUTPUTCONFIGURATION_SCALEF_SINCE_VERSION) { + org_kde_kwin_outputconfiguration_scale(d->outputconfiguration, od, qRound(scale)); + } else { + org_kde_kwin_outputconfiguration_scalef(d->outputconfiguration, od, wl_fixed_from_double(scale)); + } } void OutputConfiguration::apply() diff --git a/src/client/outputdevice.h b/src/client/outputdevice.h --- a/src/client/outputdevice.h +++ b/src/client/outputdevice.h @@ -180,8 +180,19 @@ * A scale larger than 1 means that the compositor will automatically scale surface buffers * by this amount when rendering. This is used for very high resolution displays where * applications rendering at the native resolution would be too small to be legible. + * @deprecated see scaleF **/ int scale() const; + + /** + * Scaling factor of this output. + * + * A scale larger than 1 means that the compositor will automatically scale surface buffers + * by this amount when rendering. This is used for very high resolution displays where + * applications rendering at the native resolution would be too small to be legible. + * @since 5.XXX + **/ + qreal scaleF() const; /** * Subpixel orientation of this OutputDevice. **/ diff --git a/src/client/outputdevice.cpp b/src/client/outputdevice.cpp --- a/src/client/outputdevice.cpp +++ b/src/client/outputdevice.cpp @@ -49,7 +49,7 @@ QPoint globalPosition; QString manufacturer; QString model; - int scale = 1; + qreal scale = 1.0; SubPixel subPixel = SubPixel::Unknown; Transform transform = Transform::Normal; Modes modes; @@ -67,6 +67,7 @@ static void modeCallback(void *data, org_kde_kwin_outputdevice *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh, int32_t mode_id); static void doneCallback(void *data, org_kde_kwin_outputdevice *output); static void scaleCallback(void *data, org_kde_kwin_outputdevice *output, int32_t scale); + static void scaleFCallback(void *data, org_kde_kwin_outputdevice *output, wl_fixed_t scale); static void edidCallback(void *data, org_kde_kwin_outputdevice *output, const char *raw); static void enabledCallback(void *data, org_kde_kwin_outputdevice *output, int32_t enabled); @@ -76,7 +77,7 @@ void setGlobalPosition(const QPoint &pos); void setManufacturer(const QString &manufacturer); void setModel(const QString &model); - void setScale(int scale); + void setScale(qreal scale); void setSubPixel(SubPixel subPixel); void setTransform(Transform transform); void addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh, int32_t mode_id); @@ -124,7 +125,8 @@ scaleCallback, edidCallback, enabledCallback, - uuidCallback + uuidCallback, + scaleFCallback }; void OutputDevice::Private::geometryCallback(void *data, org_kde_kwin_outputdevice *output, @@ -245,6 +247,13 @@ o->setScale(scale); } +void OutputDevice::Private::scaleFCallback(void *data, org_kde_kwin_outputdevice *output, wl_fixed_t scale_fixed) +{ + auto o = reinterpret_cast(data); + Q_ASSERT(o->output == output); + o->setScale(wl_fixed_to_double(scale_fixed)); +} + void OutputDevice::Private::doneCallback(void *data, org_kde_kwin_outputdevice *output) { auto o = reinterpret_cast(data); @@ -327,7 +336,7 @@ physicalSize = size; } -void OutputDevice::Private::setScale(int s) +void OutputDevice::Private::setScale(qreal s) { scale = s; } @@ -392,10 +401,16 @@ } int OutputDevice::scale() const +{ + return qRound(d->scale); +} + +qreal OutputDevice::scaleF() const { return d->scale; } + bool OutputDevice::isValid() const { return d->output.isValid(); diff --git a/src/client/protocols/output-management.xml b/src/client/protocols/output-management.xml --- a/src/client/protocols/output-management.xml +++ b/src/client/protocols/output-management.xml @@ -28,7 +28,7 @@ THIS SOFTWARE. ]]> - + This interface enables clients to set properties of output devices for screen configuration purposes via the server. To this end output devices are referenced @@ -80,7 +80,7 @@ - + outputconfiguration is a client-specific resource that can be used to ask the server to apply changes to available output devices. @@ -163,6 +163,15 @@ + + + Sets the scaling factor for this output device. + Sending both scale and scalef is undefined. + + + + + diff --git a/src/client/protocols/outputdevice.xml b/src/client/protocols/outputdevice.xml --- a/src/client/protocols/outputdevice.xml +++ b/src/client/protocols/outputdevice.xml @@ -29,7 +29,7 @@ ]]> - + An outputdevice describes a display device available to the compositor. outputdevice is similar to wl_output, but focuses on output @@ -228,6 +228,34 @@ + + + This event contains scaling geometry information + that is not in the geometry event. It may be sent after + binding the output object or if the output scale changes + later. If it is not sent, the client should assume a + scale of 1. + + A scale larger than 1 means that the compositor will + automatically scale surface buffers by this amount + when rendering. This is used for high resolution + displays where applications rendering at the native + resolution would be too small to be legible. + + It is intended that scaling aware clients track the + current output of a surface, and if it is on a scaled + output it should use wl_surface.set_buffer_scale with + the scale of the output. That way the compositor can + avoid scaling the surface, and the client can supply + a higher detail image. + + wl_output will keep the output scale as an integer. In every situation except + configuring the window manager you want to use that. + + + + + diff --git a/src/client/registry.cpp b/src/client/registry.cpp --- a/src/client/registry.cpp +++ b/src/client/registry.cpp @@ -198,14 +198,14 @@ &Registry::fakeInputRemoved }}, {Registry::Interface::OutputManagement, { - 1, + 2, QByteArrayLiteral("org_kde_kwin_outputmanagement"), &org_kde_kwin_outputmanagement_interface, &Registry::outputManagementAnnounced, &Registry::outputManagementRemoved }}, {Registry::Interface::OutputDevice, { - 1, + 2, QByteArrayLiteral("org_kde_kwin_outputdevice"), &org_kde_kwin_outputdevice_interface, &Registry::outputDeviceAnnounced, diff --git a/src/server/outputchangeset.h b/src/server/outputchangeset.h --- a/src/server/outputchangeset.h +++ b/src/server/outputchangeset.h @@ -78,8 +78,14 @@ 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/server/outputchangeset.cpp b/src/server/outputchangeset.cpp --- a/src/server/outputchangeset.cpp +++ b/src/server/outputchangeset.cpp @@ -102,10 +102,16 @@ bool OutputChangeSet::scaleChanged() const { Q_D(); - return d->scale != d->o->scale(); + return !qFuzzyCompare(d->scale, d->o->scale()); } int OutputChangeSet::scale() const +{ + Q_D(); + return qRound(d->scale); +} + +qreal OutputChangeSet::scaleF() const { Q_D(); return d->scale; diff --git a/src/server/outputchangeset_p.h b/src/server/outputchangeset_p.h --- a/src/server/outputchangeset_p.h +++ b/src/server/outputchangeset_p.h @@ -40,9 +40,9 @@ int modeId; OutputDeviceInterface::Transform transform; QPoint position; - int scale; + qreal scale; }; } } -#endif \ No newline at end of file +#endif diff --git a/src/server/outputconfiguration_interface.cpp b/src/server/outputconfiguration_interface.cpp --- a/src/server/outputconfiguration_interface.cpp +++ b/src/server/outputconfiguration_interface.cpp @@ -55,7 +55,7 @@ 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 @@ 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,9 @@ transformCallback, positionCallback, scaleCallback, - applyCallback + applyCallback, + scaleFCallback, + resourceDestroyedCallback }; OutputConfigurationInterface::OutputConfigurationInterface(OutputManagementInterface* parent, wl_resource* parentResource): Resource(new Private(this, parent, parentResource)) @@ -185,6 +189,22 @@ 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/server/outputdevice_interface.h b/src/server/outputdevice_interface.h --- a/src/server/outputdevice_interface.h +++ b/src/server/outputdevice_interface.h @@ -53,7 +53,7 @@ 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 @@ 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 @@ 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 @@ 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/server/outputdevice_interface.cpp b/src/server/outputdevice_interface.cpp --- a/src/server/outputdevice_interface.cpp +++ b/src/server/outputdevice_interface.cpp @@ -54,7 +54,7 @@ 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 @@ static QVector s_privates; }; -const quint32 OutputDeviceInterface::Private::s_version = 1; +const quint32 OutputDeviceInterface::Private::s_version = 2; QVector OutputDeviceInterface::Private::s_privates; @@ -402,7 +402,11 @@ 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) @@ -442,6 +446,7 @@ SETTER(setManufacturer, const QString&, manufacturer) SETTER(setModel, const QString&, model) SETTER(setScale, int, scale) +SETTER(setScaleF, qreal, scale) SETTER(setSubPixel, SubPixel, subPixel) SETTER(setTransform, Transform, transform) @@ -472,11 +477,18 @@ } 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/server/outputmanagement_interface.cpp b/src/server/outputmanagement_interface.cpp --- a/src/server/outputmanagement_interface.cpp +++ b/src/server/outputmanagement_interface.cpp @@ -57,7 +57,7 @@ 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