diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 290f399a7c4970f1aad2c04e365e978f10363adf..3c7bbf65029cc862c4185fc48b23cb63a81a8c77 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -236,6 +236,7 @@ qt_add_dbus_adaptor(kwin_dbus_SRCS ${kwin_effects_dbus_xml} effects.h KWin::Effe qt_add_dbus_adaptor(kwin_dbus_SRCS org.kde.KWin.VirtualDesktopManager.xml dbusinterface.h KWin::VirtualDesktopManagerDBusInterface) qt_add_dbus_adaptor(kwin_dbus_SRCS org.kde.KWin.Session.xml sm.h KWin::SessionManager) qt_add_dbus_adaptor(kwin_dbus_SRCS org.kde.KWin.Plugins.xml dbusinterface.h KWin::PluginManagerDBusInterface) +qt_add_dbus_adaptor(kwin_dbus_SRCS org.kde.KWin.Gamma.xml dbusinterface.h KWin::GammaDBusInterface) if (KWIN_BUILD_SCREENLOCKER) qt_add_dbus_interface(kwin_dbus_SRCS ${KSCREENLOCKER_DBUS_INTERFACES_DIR}/kf5_org.freedesktop.ScreenSaver.xml screenlocker_interface) @@ -346,6 +347,7 @@ install( org.kde.kwin.Compositing.xml org.kde.kwin.Effects.xml org.kde.KWin.Plugins.xml + org.kde.KWin.Gamma.xml ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kwin.VirtualKeyboard.xml ${CMAKE_CURRENT_BINARY_DIR}/org.kde.KWin.TabletModeManager.xml DESTINATION diff --git a/src/colors/colordevice.cpp b/src/colors/colordevice.cpp index 80eef239cdf5c16b5f7dfe8ffb27e22a6d6223b3..0119d0c9f56cdfc65eb51a3f45c1e5388c318bcd 100644 --- a/src/colors/colordevice.cpp +++ b/src/colors/colordevice.cpp @@ -14,6 +14,9 @@ #include +#include +#include + #include namespace KWin @@ -43,6 +46,7 @@ public: DirtyTemperatureToneCurve = 0x1, DirtyBrightnessToneCurve = 0x2, DirtyCalibrationToneCurve = 0x4, + DirtyCustomGammaToneCurve = 0x8, }; Q_DECLARE_FLAGS(DirtyToneCurves, DirtyToneCurveBit) @@ -51,6 +55,7 @@ public: void updateTemperatureToneCurves(); void updateBrightnessToneCurves(); void updateCalibrationToneCurves(); + void updateCustomGammaToneCurves(); Output *output; DirtyToneCurves dirtyCurves; @@ -59,9 +64,16 @@ public: uint brightness = 100; uint temperature = 6500; + struct _gamma { + double red = 1; + double green = 1; + double blue = 1; + } gamma; + std::unique_ptr temperatureStage; std::unique_ptr brightnessStage; std::unique_ptr calibrationStage; + std::unique_ptr customGammaStage; std::shared_ptr transformation; }; @@ -71,6 +83,9 @@ void ColorDevicePrivate::rebuildPipeline() if (dirtyCurves & DirtyCalibrationToneCurve) { updateCalibrationToneCurves(); } + if (dirtyCurves & DirtyCustomGammaToneCurve) { + updateCustomGammaToneCurves(); + } if (dirtyCurves & DirtyBrightnessToneCurve) { updateBrightnessToneCurves(); } @@ -101,6 +116,13 @@ void ColorDevicePrivate::rebuildPipeline() return; } } + if (customGammaStage) { + if (auto s = customGammaStage->dup()) { + stages.push_back(std::move(s)); + } else { + return; + } + } const auto tmp = std::make_shared(std::move(stages)); if (tmp->valid()) { @@ -240,6 +262,17 @@ ColorDevice::ColorDevice(Output *output, QObject *parent) connect(d->updateTimer, &QTimer::timeout, this, &ColorDevice::update); d->output = output; + + // load gamma values + auto config = KSharedConfig::openConfig(); + auto group = config->group(QStringLiteral("Gamma/") + output->name()); + + double red = group.readEntry("red", 1.0); + auto green = group.readEntry("green", 1.0); + auto blue = group.readEntry("blue", 1.0); + + setGamma(red, green, blue); + scheduleUpdate(); } @@ -314,9 +347,41 @@ void ColorDevice::update() d->output->setColorTransformation(d->transformation); } + void ColorDevice::scheduleUpdate() { d->updateTimer->start(); } +void ColorDevice::setGamma(double r, double g, double b) +{ + d->gamma.red = r; + d->gamma.blue = b; + d->gamma.green = g; + + d->dirtyCurves |= ColorDevicePrivate::DirtyCustomGammaToneCurve; + scheduleUpdate(); +} + +void ColorDevicePrivate::updateCustomGammaToneCurves() +{ + customGammaStage.reset(); + + cmsToneCurve *toneCurves[] = { + cmsBuildGamma(nullptr, 1 / gamma.red), + cmsBuildGamma(nullptr, 1 / gamma.green), + cmsBuildGamma(nullptr, 1 / gamma.blue), + }; + + customGammaStage = std::make_unique(cmsStageAllocToneCurves(nullptr, 3, toneCurves)); + if (!customGammaStage) { + qCWarning(KWIN_CORE) << "Failed to create the custom gamma pipeline stage"; + } +} + +QVector ColorDevice::getGamma() const +{ + return { d->gamma.red, d->gamma.green, d->gamma.blue }; +} + } // namespace KWin diff --git a/src/colors/colordevice.h b/src/colors/colordevice.h index 49370c38d9530d58695df0b324590e92c51f053c..75f37c43680884ae067f32b01a484bcb4a9dfc58 100644 --- a/src/colors/colordevice.h +++ b/src/colors/colordevice.h @@ -62,6 +62,16 @@ public: */ void setProfile(const QString &profile); + /** + * Sets the gamma values + */ + void setGamma(double red, double green, double blue); + + /** + * Returns the gamma values + */ + QVector getGamma() const; + public Q_SLOTS: void update(); void scheduleUpdate(); diff --git a/src/colors/colormanager.cpp b/src/colors/colormanager.cpp index ca36b7781d2ca3f161e8081bd1100e2ef6085d3e..33fc2c075d70b0d34b3a1bca7d125af54af2f5f9 100644 --- a/src/colors/colormanager.cpp +++ b/src/colors/colormanager.cpp @@ -21,6 +21,7 @@ class ColorManagerPrivate { public: QVector devices; + QHash deviceMap; }; ColorManager::ColorManager(QObject *parent) @@ -65,6 +66,7 @@ void ColorManager::handleOutputEnabled(Output *output) { ColorDevice *device = new ColorDevice(output, this); d->devices.append(device); + d->deviceMap.insert(output->name() , device); Q_EMIT deviceAdded(device); } @@ -79,6 +81,7 @@ void ColorManager::handleOutputDisabled(Output *output) } ColorDevice *device = *it; d->devices.erase(it); + d->deviceMap.remove(output->name()); Q_EMIT deviceRemoved(device); delete device; } @@ -93,4 +96,21 @@ void ColorManager::handleSessionActiveChanged(bool active) } } +void ColorManager::syncGamma() +{ + auto config = KSharedConfig::openConfig(); + const auto devs = devices(); + + for (const auto dev : devs) { + auto group = config->group(QStringLiteral("Gamma/") + dev->output()->name()); + auto gamma = dev->getGamma(); + if (gamma.size() == 3) { + group.writeEntry("red", gamma[0]); + group.writeEntry("green", gamma[1]); + group.writeEntry("blue", gamma[2]); + } + } + config->sync(); +} + } // namespace KWin diff --git a/src/colors/colormanager.h b/src/colors/colormanager.h index 746010da6cb2e349198683dab321d678d540a447..e9d5a4ff1cc3a380ce6272f1a6c3c5de7a6b33be 100644 --- a/src/colors/colormanager.h +++ b/src/colors/colormanager.h @@ -38,6 +38,11 @@ public: */ QVector devices() const; + /** + * saves gamma of all color devices + */ + void syncGamma(); + Q_SIGNALS: /** * This signal is emitted when a new color device @a device has been added. diff --git a/src/dbusinterface.cpp b/src/dbusinterface.cpp index 76011ffe8e8dababcb805dac18452087ecbb87fc..758c2da48621a311f0936422548c28d8080c15c9 100644 --- a/src/dbusinterface.cpp +++ b/src/dbusinterface.cpp @@ -10,9 +10,14 @@ // own #include "dbusinterface.h" #include "compositingadaptor.h" +#include "gammaadaptor.h" #include "pluginsadaptor.h" #include "virtualdesktopmanageradaptor.h" +#include "colordevice.h" +#include "colormanager.h" +#include "output.h" + // kwin #include "atoms.h" #include "composite.h" @@ -543,4 +548,72 @@ void PluginManagerDBusInterface::UnloadPlugin(const QString &name) m_manager->unloadPlugin(name); } +GammaDBusInterface::GammaDBusInterface(QObject *parent) + : QObject(parent) +{ + new GammaAdaptor(this); + + QDBusConnection::sessionBus().registerObject(QStringLiteral("/Gamma"), + QStringLiteral("org.kde.KWin.Gamma"), + this); + + activeDevice = ColorManager::self()->devices()[0]; + + connect(ColorManager::self(), &ColorManager::deviceAdded, [this](ColorDevice *device) { + Q_EMIT deviceAdded(device->output()->name()); + }); + + connect(ColorManager::self(), &ColorManager::deviceRemoved, [this](ColorDevice *device) { + Q_EMIT deviceRemoved(device->output()->name()); + + if (activeDevice == device) + activeDevice = ColorManager::self()->devices()[0]; + }); +} + +QString GammaDBusInterface::getActiveDevice() const +{ + return activeDevice->output()->name(); +} + +void GammaDBusInterface::setActiveDevice(QString device) +{ + const auto devs = ColorManager::self()->devices(); + for (const auto dev : devs) { + if (dev->output()->name() == device) { + activeDevice = dev; + return; + } + } +} + +QStringList GammaDBusInterface::devices() const +{ + QStringList ls; + const auto devs = ColorManager::self()->devices(); + for (const auto d : devs) { + ls.push_back(d->output()->name()); + } + return ls; +} + +void GammaDBusInterface::set(double r, double g, double b) +{ + activeDevice->setGamma(r, g, b); +} + +QVector GammaDBusInterface::get() const +{ + const auto gamma = activeDevice->getGamma(); + if (gamma.size() != 3) { + return {1, 1, 1}; + } + return gamma; +} + +void GammaDBusInterface::save() +{ + ColorManager::self()->syncGamma(); +} + } // namespace diff --git a/src/dbusinterface.h b/src/dbusinterface.h index a50ece86862a4800a193fe38e844262e94cc4753..a87ef41af3f8f346b696f9327b538e2323640519 100644 --- a/src/dbusinterface.h +++ b/src/dbusinterface.h @@ -296,6 +296,38 @@ private: PluginManager *m_manager; }; +class ColorDevice; + +class GammaDBusInterface : public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.Gamma") + +public: + Q_PROPERTY(QString activeDevice READ getActiveDevice WRITE setActiveDevice); + + explicit GammaDBusInterface(QObject *parent); + +public Q_SLOTS: + + QStringList devices() const; + + QVector get() const; + void set(double r, double g, double b); + + QString getActiveDevice() const; + void setActiveDevice(QString device); + + void save(); + +Q_SIGNALS: + void deviceAdded(QString device); + void deviceRemoved(QString device); + +private: + ColorDevice *activeDevice; +}; + } // namespace #endif // KWIN_DBUS_INTERFACE_H diff --git a/src/org.kde.KWin.Gamma.xml b/src/org.kde.KWin.Gamma.xml new file mode 100644 index 0000000000000000000000000000000000000000..6bbc0f4550c4241ce61f675e334d65f776f8481d --- /dev/null +++ b/src/org.kde.KWin.Gamma.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/workspace.cpp b/src/workspace.cpp index c0d3e1a83cd005f9b88e4bcad56e87099e134ef1..d238dfdc96c3e02f3aaa0b7dd1dc7b16be4c0f23 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -181,6 +181,8 @@ Workspace::Workspace() decorationBridge->init(); connect(this, &Workspace::configChanged, decorationBridge, &Decoration::DecorationBridge::reconfigure); + new GammaDBusInterface(this); + new DBusInterface(this); Outline::create(this);