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 @@ -45,6 +45,7 @@ void testRegistry(); void testModeChanges(); void testScaleChange(); + void testColorCurvesChange(); void testSubPixel_data(); void testSubPixel(); @@ -61,6 +62,7 @@ KWayland::Server::Display *m_display; KWayland::Server::OutputDeviceInterface *m_serverOutputDevice; QByteArray m_edid; + KWayland::Server::OutputDeviceInterface::ColorCurves m_initColorCurves; KWayland::Client::ConnectionThread *m_connection; KWayland::Client::EventQueue *m_queue; QThread *m_thread; @@ -114,6 +116,21 @@ m_edid = QByteArray::fromBase64("AP///////wAQrBbwTExLQQ4WAQOANCB46h7Frk80sSYOUFSlSwCBgKlA0QBxTwEBAQEBAQEBKDyAoHCwI0AwIDYABkQhAAAaAAAA/wBGNTI1TTI0NUFLTEwKAAAA/ABERUxMIFUyNDEwCiAgAAAA/QA4TB5REQAKICAgICAgAToCAynxUJAFBAMCBxYBHxITFCAVEQYjCQcHZwMMABAAOC2DAQAA4wUDAQI6gBhxOC1AWCxFAAZEIQAAHgEdgBhxHBYgWCwlAAZEIQAAngEdAHJR0B4gbihVAAZEIQAAHowK0Iog4C0QED6WAAZEIQAAGAAAAAAAAAAAAAAAAAAAPg=="); m_serverOutputDevice->setEdid(m_edid); + m_initColorCurves.red.clear(); + m_initColorCurves.green.clear(); + m_initColorCurves.blue.clear(); + // 8 bit color ramps + for (int i = 0; i < 256; i++) { + quint16 val = (double)i / 255 * UINT16_MAX; + m_initColorCurves.red << val ; + m_initColorCurves.green << val ; + } + // 10 bit color ramp + for (int i = 0; i < 320; i++) { + m_initColorCurves.blue << (double)i / 319 * UINT16_MAX; + } + m_serverOutputDevice->setColorCurves(m_initColorCurves); + m_serverOutputDevice->create(); // setup connection @@ -182,6 +199,9 @@ QCOMPARE(output.pixelSize(), QSize()); QCOMPARE(output.refreshRate(), 0); QCOMPARE(output.scale(), 1); + QCOMPARE(output.colorCurves().red, QVector()); + QCOMPARE(output.colorCurves().green, QVector()); + QCOMPARE(output.colorCurves().blue, QVector()); QCOMPARE(output.subPixel(), KWayland::Client::OutputDevice::SubPixel::Unknown); QCOMPARE(output.transform(), KWayland::Client::OutputDevice::Transform::Normal); QCOMPARE(output.enabled(), OutputDevice::Enablement::Enabled); @@ -202,6 +222,9 @@ QCOMPARE(output.pixelSize(), QSize(1024, 768)); QCOMPARE(output.refreshRate(), 60000); QCOMPARE(output.scale(), 1); + QCOMPARE(output.colorCurves().red, m_initColorCurves.red); + QCOMPARE(output.colorCurves().green, m_initColorCurves.green); + QCOMPARE(output.colorCurves().blue, m_initColorCurves.blue); // for xwayland output it's unknown QCOMPARE(output.subPixel(), KWayland::Client::OutputDevice::SubPixel::Unknown); // for xwayland transform is normal @@ -344,6 +367,53 @@ QCOMPARE(output.scale(), 4); } +void TestWaylandOutputDevice::testColorCurvesChange() +{ + 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.colorCurves().red, m_initColorCurves.red); + QCOMPARE(output.colorCurves().green, m_initColorCurves.green); + QCOMPARE(output.colorCurves().blue, m_initColorCurves.blue); + + // change the color curves + outputChanged.clear(); + KWayland::Server::OutputDeviceInterface::ColorCurves cc; + cc.red = QVector(256, 0); + cc.green = QVector(256, UINT16_MAX); + cc.blue = QVector(320, 1); + m_serverOutputDevice->setColorCurves(cc); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.colorCurves().red, cc.red); + QCOMPARE(output.colorCurves().green, cc.green); + QCOMPARE(output.colorCurves().blue, cc.blue); + + // change once more + outputChanged.clear(); + cc.red = QVector(256, 0); + cc.green = QVector(256, UINT16_MAX); + cc.blue = QVector(320, UINT16_MAX); + m_serverOutputDevice->setColorCurves(cc); + QVERIFY(outputChanged.wait()); + QCOMPARE(output.colorCurves().red, cc.red); + QCOMPARE(output.colorCurves().green, cc.green); + QCOMPARE(output.colorCurves().blue, cc.blue); +} + void TestWaylandOutputDevice::testSubPixel_data() { using namespace KWayland::Client; 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 @@ -231,6 +231,9 @@ if (c->scaleChanged()) { outputdevice->setScale(c->scale()); } + if (c->colorCurvesChanged()) { + outputdevice->setColorCurves(c->colorCurves()); + } } } @@ -269,6 +272,9 @@ QCOMPARE(output->pixelSize(), QSize()); QCOMPARE(output->refreshRate(), 0); QCOMPARE(output->scale(), 1); + QCOMPARE(output->colorCurves().red, QVector()); + QCOMPARE(output->colorCurves().green, QVector()); + QCOMPARE(output->colorCurves().blue, QVector()); QCOMPARE(output->subPixel(), KWayland::Client::OutputDevice::SubPixel::Unknown); QCOMPARE(output->transform(), KWayland::Client::OutputDevice::Transform::Normal); QCOMPARE(output->enabled(), OutputDevice::Enablement::Enabled); @@ -388,6 +394,8 @@ config->setTransform(output, OutputDevice::Transform::Rotated90); config->setPosition(output, QPoint(13, 37)); config->setScale(output, 2); + const auto zeroVector = QVector(256, 0); + config->setColorCurves(output, zeroVector, zeroVector, zeroVector); config->setEnabled(output, OutputDevice::Enablement::Disabled); config->apply(); @@ -406,6 +414,8 @@ config->setTransform(output, OutputDevice::Transform::Normal); config->setPosition(output, QPoint(0, 1920)); config->setScale(output, 1); + const auto oneVector = QVector(256, 1); + config->setColorCurves(output, oneVector, oneVector, oneVector); config->setEnabled(output, OutputDevice::Enablement::Enabled); config->apply(); diff --git a/src/client/outputconfiguration.h b/src/client/outputconfiguration.h --- a/src/client/outputconfiguration.h +++ b/src/client/outputconfiguration.h @@ -22,6 +22,7 @@ #include #include +#include #include "outputdevice.h" #include @@ -198,6 +199,21 @@ void setScale(OutputDevice *outputdevice, qint32 scale); /** + * Set color curves for this output. The respective color curve vector + * lengths must equal the current ones in the OutputDevice. The codomain + * of the curves is always the full uint16 value range, such that any vector + * is accepted as long as it has the right size. + * The changes done in this call will be recorded in the + * OutputDevice and only applied after apply() has been called. + * + * @param red color curve of red channel. + * @param green color curve of green channel. + * @param blue color curve of blue channel. + * @param outputdevice the OutputDevice this change applies to. + */ + void setColorCurves(OutputDevice *outputdevice, QVector red, QVector green, QVector blue); + + /** * Ask the compositor to apply the changes. * This results in the compositor looking at all outputdevices and if they have * pending changes from the set* calls, these changes will be tested with the diff --git a/src/client/outputconfiguration.cpp b/src/client/outputconfiguration.cpp --- a/src/client/outputconfiguration.cpp +++ b/src/client/outputconfiguration.cpp @@ -168,6 +168,30 @@ org_kde_kwin_outputconfiguration_scale(d->outputconfiguration, od, scale); } +void OutputConfiguration::setColorCurves(OutputDevice *outputdevice, + QVector red, QVector green, QVector blue) +{ + org_kde_kwin_outputdevice *od = outputdevice->output(); + + wl_array wlRed, wlGreen, wlBlue; + + auto fillArray = [](QVector &origin, wl_array *dest) { + wl_array_init(dest); + const size_t memLength = sizeof(uint16_t) * origin.size(); + void *s = wl_array_add(dest, memLength); + memcpy(s, origin.data(), memLength); + }; + fillArray(red, &wlRed); + fillArray(green, &wlGreen); + fillArray(blue, &wlBlue); + + org_kde_kwin_outputconfiguration_colorcurves(d->outputconfiguration, od, &wlRed, &wlGreen, &wlBlue); + + wl_array_release(&wlRed); + wl_array_release(&wlGreen); + wl_array_release(&wlBlue); +} + void OutputConfiguration::apply() { org_kde_kwin_outputconfiguration_apply(d->outputconfiguration); diff --git a/src/client/outputdevice.h b/src/client/outputdevice.h --- a/src/client/outputdevice.h +++ b/src/client/outputdevice.h @@ -1,5 +1,6 @@ /******************************************************************** Copyright 2013 Martin Gräßlin +Copyright 2018 Roman Gilg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -23,6 +24,7 @@ #include #include #include +#include #include @@ -126,6 +128,12 @@ bool operator==(const Mode &m) const; }; + struct ColorCurves { + QVector red, green, blue; + + bool operator==(const ColorCurves &cc) const; + bool operator!=(const ColorCurves &cc) const; + }; explicit OutputDevice(QObject *parent = nullptr); virtual ~OutputDevice(); @@ -194,6 +202,10 @@ * directly from client surfaces. **/ Transform transform() const; + /** + * Color curves. + **/ + ColorCurves colorCurves() const; /** * @returns The Modes of this OutputDevice. @@ -271,6 +283,12 @@ **/ void modeChanged(const KWayland::Client::OutputDevice::Mode &mode); /** + * Emitted whenever the color curves changed. + * + * @since 5.TODO + **/ + void colorCurvesChanged(); + /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the OutputDevice got created by @@ -292,6 +310,7 @@ Q_DECLARE_METATYPE(KWayland::Client::OutputDevice::Transform) Q_DECLARE_METATYPE(KWayland::Client::OutputDevice::Enablement) Q_DECLARE_METATYPE(KWayland::Client::OutputDevice::Mode) +Q_DECLARE_METATYPE(KWayland::Client::OutputDevice::ColorCurves) Q_DECLARE_OPERATORS_FOR_FLAGS(KWayland::Client::OutputDevice::Mode::Flags) #endif diff --git a/src/client/outputdevice.cpp b/src/client/outputdevice.cpp --- a/src/client/outputdevice.cpp +++ b/src/client/outputdevice.cpp @@ -1,5 +1,6 @@ /******************************************************************** Copyright 2013 Martin Gräßlin +Copyright 2018 Roman Gilg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -58,6 +59,9 @@ QByteArray edid; OutputDevice::Enablement enabled = OutputDevice::Enablement::Enabled; QByteArray uuid; + + ColorCurves colorCurves; + bool done = false; private: @@ -72,6 +76,9 @@ static void enabledCallback(void *data, org_kde_kwin_outputdevice *output, int32_t enabled); static void uuidCallback(void *data, org_kde_kwin_outputdevice *output, const char *uuid); + static void colorcurvesCallback(void *data, org_kde_kwin_outputdevice *output, + wl_array *red, wl_array *green, wl_array *blue); + void setPhysicalSize(const QSize &size); void setGlobalPosition(const QPoint &pos); void setManufacturer(const QString &manufacturer); @@ -106,6 +113,14 @@ && output == m.output; } +bool OutputDevice::ColorCurves::operator==(const OutputDevice::ColorCurves &cc) const +{ + return red == cc.red && green == cc.green && blue == cc.blue; +} +bool OutputDevice::ColorCurves::operator!=(const ColorCurves &cc) const { + return !operator==(cc); +} + OutputDevice::OutputDevice(QObject *parent) : QObject(parent) , d(new Private(this)) @@ -124,7 +139,8 @@ scaleCallback, edidCallback, enabledCallback, - uuidCallback + uuidCallback, + colorcurvesCallback }; void OutputDevice::Private::geometryCallback(void *data, org_kde_kwin_outputdevice *output, @@ -292,6 +308,33 @@ } } +void OutputDevice::Private::colorcurvesCallback(void *data, org_kde_kwin_outputdevice *output, + wl_array *red, + wl_array *green, + wl_array *blue) +{ + Q_UNUSED(output); + auto o = reinterpret_cast(data); + + auto cc = ColorCurves(); + + auto setCurve = [](const wl_array *curve, QVector *destination) { + destination->resize(curve->size / sizeof(uint16_t)); + memcpy(destination->data(), curve->data, curve->size); + }; + setCurve(red, &cc.red); + setCurve(green, &cc.green); + setCurve(blue, &cc.blue); + + if (o->colorCurves != cc) { + o->colorCurves = cc; + emit o->q->colorCurvesChanged(); + if (o->done) { + emit o->q->changed(); + } + } +} + void OutputDevice::setup(org_kde_kwin_outputdevice *output) { d->setup(output); @@ -439,6 +482,11 @@ return d->uuid; } +OutputDevice::ColorCurves OutputDevice::colorCurves() const +{ + return d->colorCurves; +} + void OutputDevice::destroy() { d->output.destroy(); 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. @@ -150,6 +150,20 @@ + + + Set color curves of output devices through RGB color ramps. Allows color + correction of output device from user space. + + These are the raw values. A compositor might opt to adjust these values + internally, for example to shift color temperature at night. + + + + + + + Sent after the server has successfully applied the changes. 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,23 @@ + + + Decribes the color intensity profile of the output. + Commonly used for gamma/color correction. + + The array contains all color ramp values of the output. + For example on 8bit screens there are 256 of them. + + The array elements are unsigned 16bit integers. + + + + + 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 @@ -69,6 +69,10 @@ * @returns @c true if the scale() property of the outputdevice has changed. */ bool scaleChanged() const; + /** Whether the colorCurves() property of the outputdevice changed. + * @returns @c true if the colorCurves() property of the outputdevice has changed. + */ + bool colorCurvesChanged() const; /** The new value for enabled. */ OutputDeviceInterface::Enablement enabled() const; @@ -80,6 +84,8 @@ QPoint position() const; /** The new value for scale. */ int scale() const; + /** The new value for colorCurves. */ + OutputDeviceInterface::ColorCurves colorCurves() 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 @@ -34,6 +34,7 @@ , transform(o->transform()) , position(o->globalPosition()) , scale(o->scale()) + , colorCurves(o->colorCurves()) { } @@ -111,5 +112,17 @@ return d->scale; } +bool OutputChangeSet::colorCurvesChanged() const +{ + Q_D(); + return d->colorCurves != d->o->colorCurves(); +} + +OutputDeviceInterface::ColorCurves OutputChangeSet::colorCurves() const +{ + Q_D(); + return d->colorCurves; +} + } } 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 @@ -41,8 +41,9 @@ OutputDeviceInterface::Transform transform; QPoint position; int scale; + OutputDeviceInterface::ColorCurves colorCurves; }; } } -#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,9 @@ 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 colorcurvesCallback(wl_client *client, wl_resource *resource, + wl_resource * outputdevice, + wl_array *red, wl_array *green, wl_array *blue); OutputConfigurationInterface *q_func() { return reinterpret_cast(q); @@ -83,7 +86,8 @@ transformCallback, positionCallback, scaleCallback, - applyCallback + applyCallback, + colorcurvesCallback }; OutputConfigurationInterface::OutputConfigurationInterface(OutputManagementInterface* parent, wl_resource* parentResource): Resource(new Private(this, parent, parentResource)) @@ -193,6 +197,42 @@ s->emitConfigurationChangeRequested(); } +void OutputConfigurationInterface::Private::colorcurvesCallback(wl_client *client, wl_resource *resource, + wl_resource * outputdevice, + wl_array *red, wl_array *green, wl_array *blue) +{ + Q_UNUSED(client); + OutputDeviceInterface *o = OutputDeviceInterface::get(outputdevice); + OutputDeviceInterface::ColorCurves oldCc = o->colorCurves(); + + auto checkArg = [](const wl_array *newColor, const QVector &oldColor) { + return (newColor->size % sizeof(uint16_t) == 0) && + (newColor->size / sizeof(uint16_t) == static_cast(oldColor.size())); + }; + if (!checkArg(red, oldCc.red) || !checkArg(green, oldCc.green) || !checkArg(blue, oldCc.blue)) { + qCWarning(KWAYLAND_SERVER) << "Requested to change color curves, but have wrong size."; + return; + } + + auto s = cast(resource); + Q_ASSERT(s); + OutputDeviceInterface::ColorCurves cc; + + auto fillVector = [](const wl_array *array, QVector *v) { + const uint16_t *pos = (uint16_t*)array->data; + + while((char*)pos < (char*)array->data + array->size) { + v->append(*pos); + pos++; + } + }; + fillVector(red, &cc.red); + fillVector(green, &cc.green); + fillVector(blue, &cc.blue); + + s->pendingChanges(o)->d_func()->colorCurves = cc; +} + void OutputConfigurationInterface::Private::emitConfigurationChangeRequested() const { auto configinterface = reinterpret_cast(q); 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 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "global.h" @@ -91,6 +92,11 @@ ModeFlags flags; int id = -1; }; + struct ColorCurves { + QVector red, green, blue; + bool operator==(const ColorCurves &cc) const; + bool operator!=(const ColorCurves &cc) const; + }; virtual ~OutputDeviceInterface(); QSize physicalSize() const; @@ -102,6 +108,7 @@ int scale() const; SubPixel subPixel() const; Transform transform() const; + ColorCurves colorCurves() const; QList modes() const; int currentModeId() const; @@ -116,6 +123,7 @@ void setScale(int scale); void setSubPixel(SubPixel subPixel); void setTransform(Transform transform); + void setColorCurves(const ColorCurves &colorCurves); void addMode(Mode &mode); void setCurrentMode(const int modeId); @@ -136,6 +144,7 @@ void scaleChanged(int); void subPixelChanged(SubPixel); void transformChanged(Transform); + void colorCurvesChanged(ColorCurves); void modesChanged(); void currentModeChanged(); @@ -157,5 +166,6 @@ Q_DECLARE_METATYPE(KWayland::Server::OutputDeviceInterface::Enablement) Q_DECLARE_METATYPE(KWayland::Server::OutputDeviceInterface::SubPixel) Q_DECLARE_METATYPE(KWayland::Server::OutputDeviceInterface::Transform) +Q_DECLARE_METATYPE(KWayland::Server::OutputDeviceInterface::ColorCurves) #endif 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 @@ -45,6 +45,7 @@ void sendDone(const ResourceData &data); void updateGeometry(); void updateScale(); + void updateColorCurves(); void sendUuid(); void sendEdid(); @@ -57,6 +58,7 @@ int scale = 1; SubPixel subPixel = SubPixel::Unknown; Transform transform = Transform::Normal; + ColorCurves colorCurves; QList modes; QList resources; @@ -74,13 +76,14 @@ int32_t toSubPixel() const; void sendGeometry(wl_resource *resource); void sendScale(const ResourceData &data); + void sendColorCurves(const ResourceData &data); static const quint32 s_version; OutputDeviceInterface *q; static QVector s_privates; }; -const quint32 OutputDeviceInterface::Private::s_version = 1; +const quint32 OutputDeviceInterface::Private::s_version = 2; QVector OutputDeviceInterface::Private::s_privates; @@ -139,6 +142,7 @@ 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::colorCurvesChanged, this, [this, d] { d->updateColorCurves(); }); } OutputDeviceInterface::~OutputDeviceInterface() = default; @@ -333,6 +337,7 @@ sendGeometry(resource); sendScale(r); + sendColorCurves(r); auto currentModeIt = modes.constEnd(); for (auto it = modes.constBegin(); it != modes.constEnd(); ++it) { @@ -405,6 +410,31 @@ org_kde_kwin_outputdevice_send_scale(data.resource, scale); } +void OutputDeviceInterface::Private::sendColorCurves(const ResourceData &data) +{ + if (data.version < ORG_KDE_KWIN_OUTPUTDEVICE_COLORCURVES_SINCE_VERSION) { + return; + } + + wl_array wlRed, wlGreen, wlBlue; + + auto fillArray = [](const QVector &origin, wl_array *dest) { + wl_array_init(dest); + const size_t memLength = sizeof(uint16_t) * origin.size(); + void *s = wl_array_add(dest, memLength); + memcpy(s, origin.data(), memLength); + }; + fillArray(colorCurves.red, &wlRed); + fillArray(colorCurves.green, &wlGreen); + fillArray(colorCurves.blue, &wlBlue); + + org_kde_kwin_outputdevice_send_colorcurves(data.resource, &wlRed, &wlGreen, &wlBlue); + + wl_array_release(&wlRed); + wl_array_release(&wlGreen); + wl_array_release(&wlBlue); +} + void OutputDeviceInterface::Private::sendDone(const ResourceData &data) { org_kde_kwin_outputdevice_send_done(data.resource); @@ -426,6 +456,22 @@ } } +void OutputDeviceInterface::Private::updateColorCurves() +{ + for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) { + sendColorCurves(*it); + sendDone(*it); + } +} + +bool OutputDeviceInterface::ColorCurves::operator==(const ColorCurves &cc) const +{ + return red == cc.red && green == cc.green && blue == cc.blue; +} +bool OutputDeviceInterface::ColorCurves::operator!=(const ColorCurves &cc) const { + return !operator==(cc); +} + #define SETTER(setterName, type, argumentName) \ void OutputDeviceInterface::setterName(type arg) \ { \ @@ -489,6 +535,12 @@ return d->transform; } +OutputDeviceInterface::ColorCurves OutputDeviceInterface::colorCurves() const +{ + Q_D(); + return d->colorCurves; +} + QList< OutputDeviceInterface::Mode > OutputDeviceInterface::modes() const { Q_D(); @@ -511,6 +563,17 @@ return reinterpret_cast(d.data()); } +void OutputDeviceInterface::setColorCurves(const ColorCurves &colorCurves) +{ + Q_D(); + + if (d->colorCurves == colorCurves) { + return; + } + d->colorCurves = colorCurves; + emit colorCurvesChanged(d->colorCurves); +} + void OutputDeviceInterface::setEdid(const QByteArray &edid) { 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