Commit 33f46f6d authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

[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
parent 5bec89ac
......@@ -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<QString, QVariant> ColorCorrectDBusInterface::nightColorInfo()
{
return m_manager->info();
......
......@@ -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:
/**
......
......@@ -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<QString, QVariant> Manager::info() const
{
return QHash<QString, QVariant> {
{ QStringLiteral("Available"), kwinApp()->platform()->supportsGammaControl() },
{ QStringLiteral("Available"), isAvailable() },
{ QStringLiteral("ActiveEnabled"), true},
{ QStringLiteral("Active"), m_active},
......@@ -798,12 +845,12 @@ bool Manager::changeConfiguration(QHash<QString, QVariant> 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();
}
}
}
......@@ -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;
......
......@@ -52,5 +52,37 @@
This property holds a value to indicate whether Night Color is inhibited.
-->
<property name="inhibited" type="b" access="read"/>
<!--
This property holds a value to indicate whether Night Color is enabled.
-->
<property name="enabled" type="b" access="read"/>
<!--
This property holds a value to indicate whether Night Color is running.
-->
<property name="running" type="b" access="read"/>
<!--
This property holds a value to indicate whether Night Color is available.
-->
<property name="available" type="b" access="read"/>
<!--
This property holds a value to indicate the current screen color temperature.
-->
<property name="currentTemperature" type="u" access="read"/>
<!--
This property holds a value to indicate the target screen color temperature.
-->
<property name="targetTemperature" type="u" access="read"/>
<!--
This property holds a value to indicate the operating mode.
Valid modes: 0 - automatic, 1 - location, 2 - timings, 3 - constant.
-->
<property name="mode" type="u" access="read"/>
</interface>
</node>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment