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
This commit is contained in:
David Edmundson 2018-07-25 22:14:17 +02:00
parent 2a3b34ae6a
commit 961bcbde08
9 changed files with 152 additions and 15 deletions

View file

@ -44,6 +44,7 @@ private Q_SLOTS:
void testRegistry(); void testRegistry();
void testModeChanges(); void testModeChanges();
void testScaleChange_legacy();
void testScaleChange(); void testScaleChange();
void testSubPixel_data(); void testSubPixel_data();
@ -310,7 +311,7 @@ void TestWaylandOutputDevice::testModeChanges()
QCOMPARE(output.pixelSize(), QSize(1280, 1024)); QCOMPARE(output.pixelSize(), QSize(1280, 1024));
} }
void TestWaylandOutputDevice::testScaleChange() void TestWaylandOutputDevice::testScaleChange_legacy()
{ {
KWayland::Client::Registry registry; KWayland::Client::Registry registry;
QSignalSpy interfacesAnnouncedSpy(&registry, &KWayland::Client::Registry::interfacesAnnounced); QSignalSpy interfacesAnnouncedSpy(&registry, &KWayland::Client::Registry::interfacesAnnounced);
@ -336,12 +337,51 @@ void TestWaylandOutputDevice::testScaleChange()
m_serverOutputDevice->setScale(2); m_serverOutputDevice->setScale(2);
QVERIFY(outputChanged.wait()); QVERIFY(outputChanged.wait());
QCOMPARE(output.scale(), 2); QCOMPARE(output.scale(), 2);
QCOMPARE(output.scaleF(), 2.0); //check we're forward compatiable
// change once more // change once more
outputChanged.clear(); outputChanged.clear();
m_serverOutputDevice->setScale(4); m_serverOutputDevice->setScale(4);
QVERIFY(outputChanged.wait()); QVERIFY(outputChanged.wait());
QCOMPARE(output.scale(), 4); QCOMPARE(output.scale(), 4);
QCOMPARE(output.scaleF(), 4.0);
}
void TestWaylandOutputDevice::testScaleChange()
{
KWayland::Client::Registry registry;
QSignalSpy interfacesAnnouncedSpy(&registry, &KWayland::Client::Registry::interfacesAnnounced);
QVERIFY(interfacesAnnouncedSpy.isValid());
QSignalSpy announced(&registry, &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<quint32>(), announced.first().last().value<quint32>()));
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() void TestWaylandOutputDevice::testSubPixel_data()

View file

@ -60,6 +60,7 @@ private Q_SLOTS:
void testFailed(); void testFailed();
void testExampleConfig(); void testExampleConfig();
void testScale();
void testRemoval(); void testRemoval();
@ -229,7 +230,7 @@ void TestWaylandOutputManagement::applyPendingChanges()
outputdevice->setGlobalPosition(c->position()); outputdevice->setGlobalPosition(c->position());
} }
if (c->scaleChanged()) { if (c->scaleChanged()) {
outputdevice->setScale(c->scale()); outputdevice->setScaleF(c->scaleF());
} }
} }
} }
@ -472,5 +473,34 @@ void TestWaylandOutputManagement::testExampleConfig()
QVERIFY(configAppliedSpy.wait(200)); 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) QTEST_GUILESS_MAIN(TestWaylandOutputManagement)
#include "test_wayland_outputmanagement.moc" #include "test_wayland_outputmanagement.moc"

View file

@ -102,10 +102,16 @@ QPoint OutputChangeSet::position() const
bool OutputChangeSet::scaleChanged() const bool OutputChangeSet::scaleChanged() const
{ {
Q_D(); Q_D();
return d->scale != d->o->scale(); return !qFuzzyCompare(d->scale, d->o->scaleF());
} }
int OutputChangeSet::scale() const int OutputChangeSet::scale() const
{
Q_D();
return qRound(d->scale);
}
qreal OutputChangeSet::scaleF() const
{ {
Q_D(); Q_D();
return d->scale; return d->scale;

View file

@ -78,8 +78,14 @@ public:
OutputDeviceInterface::Transform transform() const; OutputDeviceInterface::Transform transform() const;
/** The new value for globalPosition. */ /** The new value for globalPosition. */
QPoint position() const; QPoint position() const;
/** The new value for scale. */ /** The new value for scale.
@deprecated see scaleF
*/
int scale() const; int scale() const;
/** The new value for scale.
* @since 5.XX
*/
qreal scaleF() const;
private: private:
friend class OutputConfigurationInterface; friend class OutputConfigurationInterface;

View file

@ -40,7 +40,7 @@ namespace KWayland
int modeId; int modeId;
OutputDeviceInterface::Transform transform; OutputDeviceInterface::Transform transform;
QPoint position; QPoint position;
int scale; qreal scale;
}; };
} }
} }

View file

@ -55,7 +55,7 @@ public:
OutputManagementInterface *outputManagement; OutputManagementInterface *outputManagement;
QHash<OutputDeviceInterface*, OutputChangeSet*> changes; QHash<OutputDeviceInterface*, OutputChangeSet*> changes;
static const quint32 s_version = 1; static const quint32 s_version = 2;
private: private:
static void enableCallback(wl_client *client, wl_resource *resource, static void enableCallback(wl_client *client, wl_resource *resource,
@ -69,6 +69,8 @@ private:
static void scaleCallback(wl_client *client, wl_resource *resource, static void scaleCallback(wl_client *client, wl_resource *resource,
wl_resource * outputdevice, int32_t scale); wl_resource * outputdevice, int32_t scale);
static void applyCallback(wl_client *client, wl_resource *resource); 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() { OutputConfigurationInterface *q_func() {
return reinterpret_cast<OutputConfigurationInterface *>(q); return reinterpret_cast<OutputConfigurationInterface *>(q);
@ -83,7 +85,8 @@ const struct org_kde_kwin_outputconfiguration_interface OutputConfigurationInter
transformCallback, transformCallback,
positionCallback, positionCallback,
scaleCallback, scaleCallback,
applyCallback applyCallback,
scaleFCallback
}; };
OutputConfigurationInterface::OutputConfigurationInterface(OutputManagementInterface* parent, wl_resource* parentResource): Resource(new Private(this, parent, parentResource)) 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; 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<Private>(resource);
Q_ASSERT(s);
s->pendingChanges(o)->d_func()->scale = scale;
}
void OutputConfigurationInterface::Private::applyCallback(wl_client *client, wl_resource *resource) void OutputConfigurationInterface::Private::applyCallback(wl_client *client, wl_resource *resource)
{ {
Q_UNUSED(client); Q_UNUSED(client);

View file

@ -54,7 +54,7 @@ public:
QPoint globalPosition; QPoint globalPosition;
QString manufacturer = QStringLiteral("org.kde.kwin"); QString manufacturer = QStringLiteral("org.kde.kwin");
QString model = QStringLiteral("none"); QString model = QStringLiteral("none");
int scale = 1; qreal scale = 1.0;
SubPixel subPixel = SubPixel::Unknown; SubPixel subPixel = SubPixel::Unknown;
Transform transform = Transform::Normal; Transform transform = Transform::Normal;
QList<Mode> modes; QList<Mode> modes;
@ -80,7 +80,7 @@ private:
static QVector<Private*> s_privates; static QVector<Private*> s_privates;
}; };
const quint32 OutputDeviceInterface::Private::s_version = 1; const quint32 OutputDeviceInterface::Private::s_version = 2;
QVector<OutputDeviceInterface::Private*> OutputDeviceInterface::Private::s_privates; QVector<OutputDeviceInterface::Private*> 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::globalPositionChanged, this, [this, d] { d->updateGeometry(); });
connect(this, &OutputDeviceInterface::modelChanged, 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::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; OutputDeviceInterface::~OutputDeviceInterface() = default;
@ -402,7 +402,11 @@ void OutputDeviceInterface::Private::sendGeometry(wl_resource *resource)
void OutputDeviceInterface::Private::sendScale(const ResourceData &data) 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) void OutputDeviceInterface::Private::sendDone(const ResourceData &data)
@ -441,12 +445,33 @@ SETTER(setPhysicalSize, const QSize&, physicalSize)
SETTER(setGlobalPosition, const QPoint&, globalPosition) SETTER(setGlobalPosition, const QPoint&, globalPosition)
SETTER(setManufacturer, const QString&, manufacturer) SETTER(setManufacturer, const QString&, manufacturer)
SETTER(setModel, const QString&, model) SETTER(setModel, const QString&, model)
SETTER(setScale, int, scale)
SETTER(setSubPixel, SubPixel, subPixel) SETTER(setSubPixel, SubPixel, subPixel)
SETTER(setTransform, Transform, transform) SETTER(setTransform, Transform, transform)
#undef SETTER #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 QSize OutputDeviceInterface::physicalSize() const
{ {
Q_D(); Q_D();
@ -472,11 +497,18 @@ QString OutputDeviceInterface::model() const
} }
int OutputDeviceInterface::scale() const int OutputDeviceInterface::scale() const
{
Q_D();
return qRound(d->scale);
}
qreal OutputDeviceInterface::scaleF() const
{ {
Q_D(); Q_D();
return d->scale; return d->scale;
} }
OutputDeviceInterface::SubPixel OutputDeviceInterface::subPixel() const OutputDeviceInterface::SubPixel OutputDeviceInterface::subPixel() const
{ {
Q_D(); Q_D();

View file

@ -53,7 +53,7 @@ class KWAYLANDSERVER_EXPORT OutputDeviceInterface : public Global
Q_PROPERTY(QString model READ model WRITE setModel NOTIFY modelChanged) Q_PROPERTY(QString model READ model WRITE setModel NOTIFY modelChanged)
Q_PROPERTY(QSize pixelSize READ pixelSize NOTIFY pixelSizeChanged) Q_PROPERTY(QSize pixelSize READ pixelSize NOTIFY pixelSizeChanged)
Q_PROPERTY(int refreshRate READ refreshRate NOTIFY refreshRateChanged) 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(QByteArray edid READ edid WRITE setEdid NOTIFY edidChanged)
Q_PROPERTY(OutputDeviceInterface::Enablement enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(OutputDeviceInterface::Enablement enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(QByteArray uuid READ uuid WRITE setUuid NOTIFY uuidChanged) Q_PROPERTY(QByteArray uuid READ uuid WRITE setUuid NOTIFY uuidChanged)
@ -100,6 +100,7 @@ public:
QSize pixelSize() const; QSize pixelSize() const;
int refreshRate() const; int refreshRate() const;
int scale() const; int scale() const;
qreal scaleF() const;
SubPixel subPixel() const; SubPixel subPixel() const;
Transform transform() const; Transform transform() const;
QList<Mode> modes() const; QList<Mode> modes() const;
@ -114,6 +115,7 @@ public:
void setManufacturer(const QString &manufacturer); void setManufacturer(const QString &manufacturer);
void setModel(const QString &model); void setModel(const QString &model);
void setScale(int scale); void setScale(int scale);
void setScaleF(qreal scale);
void setSubPixel(SubPixel subPixel); void setSubPixel(SubPixel subPixel);
void setTransform(Transform transform); void setTransform(Transform transform);
void addMode(Mode &mode); void addMode(Mode &mode);
@ -133,7 +135,9 @@ Q_SIGNALS:
void modelChanged(const QString&); void modelChanged(const QString&);
void pixelSizeChanged(const QSize&); void pixelSizeChanged(const QSize&);
void refreshRateChanged(int); void refreshRateChanged(int);
//@deprecated see scaleChanged(real)
void scaleChanged(int); void scaleChanged(int);
void scaleFChanged(qreal);
void subPixelChanged(SubPixel); void subPixelChanged(SubPixel);
void transformChanged(Transform); void transformChanged(Transform);
void modesChanged(); void modesChanged();

View file

@ -57,7 +57,7 @@ private:
QHash<wl_resource*, OutputConfigurationInterface*> configurationInterfaces; QHash<wl_resource*, OutputConfigurationInterface*> 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 = { const struct org_kde_kwin_outputmanagement_interface OutputManagementInterface::Private::s_interface = {
createConfigurationCallback createConfigurationCallback