From 33f46f6d6c10ae6fcedad51f932d34907bb6e749 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 7 Jan 2020 17:11:56 +0200 Subject: [PATCH] [nightcolor] Expose some properties to d-bus Summary: Currently, in order to retrieve the current screen color temperature applied to all screen as well other attributes of night color manager, one has to call nightColorInfo() periodically. This goes against well established patterns in d-bus world. It is recommended to expose a bunch of d-bus properties rather than have a method that returns all relevant properties stored in a JSON object. The ugliest thing about this patch is that a lot of code is duplicated to emit the PropertiesChanged signal. Unfortunately, QtDBus doesn't take care of this and we are left with only two options - either do weird things with QMetaObject or manually emit the signal. I have picked the second option since it's more comprehensible and less magic is going on, but I have to admit that the chosen approach is ugly. I hope that "Qt 6 will fix it." CCBUG: 400418 Reviewers: #kwin, davidedmundson Reviewed By: #kwin, davidedmundson Subscribers: kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D25946 --- colorcorrection/colorcorrectdbusinterface.cpp | 126 +++++++++++++++++- colorcorrection/colorcorrectdbusinterface.h | 12 ++ colorcorrection/manager.cpp | 111 +++++++++++++-- colorcorrection/manager.h | 62 +++++++++ org.kde.kwin.ColorCorrect.xml | 32 +++++ 5 files changed, 328 insertions(+), 15 deletions(-) diff --git a/colorcorrection/colorcorrectdbusinterface.cpp b/colorcorrection/colorcorrectdbusinterface.cpp index c1a4d6fc93..80df053d8f 100644 --- a/colorcorrection/colorcorrectdbusinterface.cpp +++ b/colorcorrection/colorcorrectdbusinterface.cpp @@ -38,7 +38,6 @@ ColorCorrectDBusInterface::ColorCorrectDBusInterface(Manager *parent) connect(m_inhibitorWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &ColorCorrectDBusInterface::removeInhibitorService); - // Argh, all this code is just to send one innocent signal... connect(m_manager, &Manager::inhibitedChanged, this, [this] { QVariantMap changedProperties; changedProperties.insert(QStringLiteral("inhibited"), m_manager->isInhibited()); @@ -58,6 +57,101 @@ ColorCorrectDBusInterface::ColorCorrectDBusInterface(Manager *parent) QDBusConnection::sessionBus().send(message); }); + connect(m_manager, &Manager::enabledChanged, this, [this] { + QVariantMap changedProperties; + changedProperties.insert(QStringLiteral("enabled"), m_manager->isEnabled()); + + QDBusMessage message = QDBusMessage::createSignal( + QStringLiteral("/ColorCorrect"), + QStringLiteral("org.freedesktop.DBus.Properties"), + QStringLiteral("PropertiesChanged") + ); + + message.setArguments({ + QStringLiteral("org.kde.kwin.ColorCorrect"), + changedProperties, + QStringList(), // invalidated_properties + }); + + QDBusConnection::sessionBus().send(message); + }); + + connect(m_manager, &Manager::runningChanged, this, [this] { + QVariantMap changedProperties; + changedProperties.insert(QStringLiteral("running"), m_manager->isRunning()); + + QDBusMessage message = QDBusMessage::createSignal( + QStringLiteral("/ColorCorrect"), + QStringLiteral("org.freedesktop.DBus.Properties"), + QStringLiteral("PropertiesChanged") + ); + + message.setArguments({ + QStringLiteral("org.kde.kwin.ColorCorrect"), + changedProperties, + QStringList(), // invalidated_properties + }); + + QDBusConnection::sessionBus().send(message); + }); + + connect(m_manager, &Manager::currentTemperatureChanged, this, [this] { + QVariantMap changedProperties; + changedProperties.insert(QStringLiteral("currentTemperature"), m_manager->currentTemperature()); + + QDBusMessage message = QDBusMessage::createSignal( + QStringLiteral("/ColorCorrect"), + QStringLiteral("org.freedesktop.DBus.Properties"), + QStringLiteral("PropertiesChanged") + ); + + message.setArguments({ + QStringLiteral("org.kde.kwin.ColorCorrect"), + changedProperties, + QStringList(), // invalidated_properties + }); + + QDBusConnection::sessionBus().send(message); + }); + + connect(m_manager, &Manager::targetTemperatureChanged, this, [this] { + QVariantMap changedProperties; + changedProperties.insert(QStringLiteral("targetTemperature"), m_manager->targetTemperature()); + + QDBusMessage message = QDBusMessage::createSignal( + QStringLiteral("/ColorCorrect"), + QStringLiteral("org.freedesktop.DBus.Properties"), + QStringLiteral("PropertiesChanged") + ); + + message.setArguments({ + QStringLiteral("org.kde.kwin.ColorCorrect"), + changedProperties, + QStringList(), // invalidated_properties + }); + + QDBusConnection::sessionBus().send(message); + }); + + connect(m_manager, &Manager::modeChanged, this, [this] { + QVariantMap changedProperties; + changedProperties.insert(QStringLiteral("mode"), uint(m_manager->mode())); + + QDBusMessage message = QDBusMessage::createSignal( + QStringLiteral("/ColorCorrect"), + QStringLiteral("org.freedesktop.DBus.Properties"), + QStringLiteral("PropertiesChanged") + ); + + message.setArguments({ + QStringLiteral("org.kde.kwin.ColorCorrect"), + changedProperties, + QStringList(), // invalidated_properties + }); + + QDBusConnection::sessionBus().send(message); + }); + connect(m_manager, &Manager::configChange, this, &ColorCorrectDBusInterface::nightColorConfigChanged); new ColorCorrectAdaptor(this); QDBusConnection::sessionBus().registerObject(QStringLiteral("/ColorCorrect"), this); @@ -68,6 +162,36 @@ bool ColorCorrectDBusInterface::isInhibited() const return m_manager->isInhibited(); } +bool ColorCorrectDBusInterface::isEnabled() const +{ + return m_manager->isEnabled(); +} + +bool ColorCorrectDBusInterface::isRunning() const +{ + return m_manager->isRunning(); +} + +bool ColorCorrectDBusInterface::isAvailable() const +{ + return m_manager->isAvailable(); +} + +int ColorCorrectDBusInterface::currentTemperature() const +{ + return m_manager->currentTemperature(); +} + +int ColorCorrectDBusInterface::targetTemperature() const +{ + return m_manager->targetTemperature(); +} + +int ColorCorrectDBusInterface::mode() const +{ + return m_manager->mode(); +} + QHash ColorCorrectDBusInterface::nightColorInfo() { return m_manager->info(); diff --git a/colorcorrection/colorcorrectdbusinterface.h b/colorcorrection/colorcorrectdbusinterface.h index 481f71fa7b..36fad03b6c 100644 --- a/colorcorrection/colorcorrectdbusinterface.h +++ b/colorcorrection/colorcorrectdbusinterface.h @@ -37,12 +37,24 @@ class ColorCorrectDBusInterface : public QObject, public QDBusContext Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.ColorCorrect") Q_PROPERTY(bool inhibited READ isInhibited) + Q_PROPERTY(bool enabled READ isEnabled) + Q_PROPERTY(bool running READ isRunning) + Q_PROPERTY(bool available READ isAvailable) + Q_PROPERTY(int currentTemperature READ currentTemperature) + Q_PROPERTY(int targetTemperature READ targetTemperature) + Q_PROPERTY(int mode READ mode) public: explicit ColorCorrectDBusInterface(Manager *parent); ~ColorCorrectDBusInterface() override = default; bool isInhibited() const; + bool isEnabled() const; + bool isRunning() const; + bool isAvailable() const; + int currentTemperature() const; + int targetTemperature() const; + int mode() const; public Q_SLOTS: /** diff --git a/colorcorrection/manager.cpp b/colorcorrection/manager.cpp index 5026730190..8f5e657dcf 100644 --- a/colorcorrection/manager.cpp +++ b/colorcorrection/manager.cpp @@ -90,7 +90,7 @@ void Manager::init() // we may always read in the current config readConfig(); - if (!kwinApp()->platform()->supportsGammaControl()) { + if (!isAvailable()) { return; } @@ -165,9 +165,10 @@ void Manager::hardReset() if (m_mode != NightColorMode::Constant) { updateSunTimings(true); } + updateTargetTemperature(); - if (kwinApp()->platform()->supportsGammaControl() && m_active && !isInhibited()) { - m_running = true; + if (isAvailable() && isEnabled() && !isInhibited()) { + setRunning(true); commitGammaRamps(currentTargetTemp()); } resetAllTimers(); @@ -211,6 +212,36 @@ void Manager::uninhibit() } } +bool Manager::isEnabled() const +{ + return m_active; +} + +bool Manager::isRunning() const +{ + return m_running; +} + +bool Manager::isAvailable() const +{ + return kwinApp()->platform()->supportsGammaControl(); +} + +int Manager::currentTemperature() const +{ + return m_currentTemp; +} + +int Manager::targetTemperature() const +{ + return m_targetTemperature; +} + +NightColorMode Manager::mode() const +{ + return m_mode; +} + void Manager::initShortcuts() { QAction *toggleAction = new QAction(this); @@ -226,7 +257,7 @@ void Manager::readConfig() Settings *s = Settings::self(); s->load(); - m_active = s->active(); + setEnabled(s->active()); const NightColorMode mode = s->mode(); switch (s->mode()) { @@ -234,11 +265,11 @@ void Manager::readConfig() case NightColorMode::Location: case NightColorMode::Timings: case NightColorMode::Constant: - m_mode = mode; + setMode(mode); break; default: // Fallback for invalid setting values. - m_mode = NightColorMode::Automatic; + setMode(NightColorMode::Automatic); break; } @@ -293,12 +324,12 @@ void Manager::readConfig() void Manager::resetAllTimers() { cancelAllTimers(); - if (kwinApp()->platform()->supportsGammaControl()) { - m_running = m_active && !isInhibited(); + if (isAvailable()) { + setRunning(isEnabled() && !isInhibited()); // we do this also for active being false in order to reset the temperature back to the day value resetQuickAdjustTimer(); } else { - m_running = false; + setRunning(false); } } @@ -319,6 +350,7 @@ void Manager::resetQuickAdjustTimer() if (m_mode != NightColorMode::Constant) { updateSunTimings(false); } + updateTargetTemperature(); int tempDiff = qAbs(currentTargetTemp() - m_currentTemp); // allow tolerance of one TEMPERATURE_STEP to compensate if a slow update is coincidental @@ -384,6 +416,8 @@ void Manager::resetSlowUpdateStartTimer() connect(m_slowUpdateStartTimer, &QTimer::timeout, this, &Manager::resetSlowUpdateStartTimer); updateSunTimings(false); + updateTargetTemperature(); + const int diff = QDateTime::currentDateTime().msecsTo(m_next.first); if (diff <= 0) { qCCritical(KWIN_COLORCORRECTION) << "Error in time calculation. Deactivating Night Color."; @@ -448,6 +482,19 @@ void Manager::slowUpdate(int targetTemp) } } +void Manager::updateTargetTemperature() +{ + const int targetTemperature = mode() != NightColorMode::Constant && daylight() ? m_dayTargetTemp : m_nightTargetTemp; + + if (m_targetTemperature == targetTemperature) { + return; + } + + m_targetTemperature = targetTemperature; + + emit targetTemperatureChanged(); +} + void Manager::updateSunTimings(bool force) { const QDateTime todayNow = QDateTime::currentDateTime(); @@ -624,7 +671,7 @@ void Manager::commitGammaRamps(int temperature) } if (o->setGammaRamp(ramp)) { - m_currentTemp = temperature; + setCurrentTemperature(temperature); m_failedCommitAttempts = 0; } else { m_failedCommitAttempts++; @@ -635,7 +682,7 @@ void Manager::commitGammaRamps(int temperature) // TODO: On multi monitor setups we could try to rollback earlier changes for already committed outputs qCWarning(KWIN_COLORCORRECTION) << "Gamma Ramp commit failed too often. Deactivating color correction for now."; m_failedCommitAttempts = 0; // reset so we can try again later (i.e. after suspend phase or config change) - m_running = false; + setRunning(false); cancelAllTimers(); } } @@ -645,7 +692,7 @@ void Manager::commitGammaRamps(int temperature) QHash Manager::info() const { return QHash { - { QStringLiteral("Available"), kwinApp()->platform()->supportsGammaControl() }, + { QStringLiteral("Available"), isAvailable() }, { QStringLiteral("ActiveEnabled"), true}, { QStringLiteral("Active"), m_active}, @@ -798,12 +845,12 @@ bool Manager::changeConfiguration(QHash data) Settings *s = Settings::self(); if (activeUpdate) { - m_active = active; + setEnabled(active); s->setActive(active); } if (modeUpdate) { - m_mode = mode; + setMode(mode); s->setMode(mode); } @@ -861,5 +908,41 @@ void Manager::autoLocationUpdate(double latitude, double longitude) emit configChange(info()); } +void Manager::setEnabled(bool enabled) +{ + if (m_active == enabled) { + return; + } + m_active = enabled; + emit enabledChanged(); +} + +void Manager::setRunning(bool running) +{ + if (m_running == running) { + return; + } + m_running = running; + emit runningChanged(); +} + +void Manager::setCurrentTemperature(int temperature) +{ + if (m_currentTemp == temperature) { + return; + } + m_currentTemp = temperature; + emit currentTemperatureChanged(); +} + +void Manager::setMode(NightColorMode mode) +{ + if (m_mode == mode) { + return; + } + m_mode = mode; + emit modeChanged(); +} + } } diff --git a/colorcorrection/manager.h b/colorcorrection/manager.h index cad325acd2..40bce5ba11 100644 --- a/colorcorrection/manager.h +++ b/colorcorrection/manager.h @@ -144,6 +144,36 @@ public: */ void uninhibit(); + /** + * Returns @c true if Night Color is enabled; otherwise @c false. + */ + bool isEnabled() const; + + /** + * Returns @c true if Night Color is currently running; otherwise @c false. + */ + bool isRunning() const; + + /** + * Returns @c true if Night Color is supported by platform; otherwise @c false. + */ + bool isAvailable() const; + + /** + * Returns the current screen color temperature. + */ + int currentTemperature() const; + + /** + * Returns the target screen color temperature. + */ + int targetTemperature() const; + + /** + * Returns the mode in which Night Color is operating. + */ + NightColorMode mode() const; + // for auto tests void reparseConfigAndReset(); @@ -159,6 +189,31 @@ Q_SIGNALS: */ void inhibitedChanged(); + /** + * Emitted whenever the night color manager is enabled or disabled. + */ + void enabledChanged(); + + /** + * Emitted whenever the night color manager starts or stops running. + */ + void runningChanged(); + + /** + * Emitted whenever the current screen color temperature has changed. + */ + void currentTemperatureChanged(); + + /** + * Emitted whenever the target screen color temperature has changed. + */ + void targetTemperatureChanged(); + + /** + * Emitted whenver the operation mode has changed. + */ + void modeChanged(); + private: void initShortcuts(); void readConfig(); @@ -176,6 +231,7 @@ private: */ void resetSlowUpdateTimer(); + void updateTargetTemperature(); void updateSunTimings(bool force); DateTimes getSunTimings(const QDateTime &dateTime, double latitude, double longitude, bool morning) const; bool checkAutomaticSunTimings() const; @@ -183,6 +239,11 @@ private: void commitGammaRamps(int temperature); + void setEnabled(bool enabled); + void setRunning(bool running); + void setCurrentTemperature(int temperature); + void setMode(NightColorMode mode); + ColorCorrectDBusInterface *m_iface; // Specifies whether Night Color is enabled. @@ -217,6 +278,7 @@ private: QTimer *m_quickAdjustTimer = nullptr; int m_currentTemp = NEUTRAL_TEMPERATURE; + int m_targetTemperature = NEUTRAL_TEMPERATURE; int m_dayTargetTemp = NEUTRAL_TEMPERATURE; int m_nightTargetTemp = DEFAULT_NIGHT_TEMPERATURE; diff --git a/org.kde.kwin.ColorCorrect.xml b/org.kde.kwin.ColorCorrect.xml index dd5b298a8f..7b45f3f1ea 100644 --- a/org.kde.kwin.ColorCorrect.xml +++ b/org.kde.kwin.ColorCorrect.xml @@ -52,5 +52,37 @@ This property holds a value to indicate whether Night Color is inhibited. --> + + + + + + + + + + + + + + + + + +