1 /*
2  * SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  */
6 
7 #include "monitor.h"
8 #include "monitor_p.h"
9 
10 #include <QDBusConnection>
11 #include <QDBusMessage>
12 #include <QDBusPendingCallWatcher>
13 #include <QDBusPendingReply>
14 #include <QDBusServiceWatcher>
15 
16 static const QString s_serviceName = QStringLiteral("org.kde.KWin");
17 static const QString s_nightColorPath = QStringLiteral("/ColorCorrect");
18 static const QString s_nightColorInterface = QStringLiteral("org.kde.kwin.ColorCorrect");
19 static const QString s_propertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties");
20 
MonitorPrivate(QObject * parent)21 MonitorPrivate::MonitorPrivate(QObject *parent)
22     : QObject(parent)
23 {
24     QDBusServiceWatcher *watcher = new QDBusServiceWatcher(s_serviceName, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this);
25     connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &MonitorPrivate::handleServiceRegistered);
26     connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, &MonitorPrivate::handleServiceUnregistered);
27 
28     handleServiceRegistered();
29 }
30 
~MonitorPrivate()31 MonitorPrivate::~MonitorPrivate()
32 {
33 }
34 
handleServiceRegistered()35 void MonitorPrivate::handleServiceRegistered()
36 {
37     QDBusConnection bus = QDBusConnection::sessionBus();
38 
39     // clang-format off
40     const bool connected = bus.connect(s_serviceName,
41                                        s_nightColorPath,
42                                        s_propertiesInterface,
43                                        QStringLiteral("PropertiesChanged"),
44                                        this,
45                                        SLOT(handlePropertiesChanged(QString,QVariantMap,QStringList)));
46     // clang-format on
47     if (!connected) {
48         return;
49     }
50 
51     QDBusMessage message = QDBusMessage::createMethodCall(s_serviceName, s_nightColorPath, s_propertiesInterface, QStringLiteral("GetAll"));
52     message.setArguments({s_nightColorInterface});
53 
54     QDBusPendingReply<QVariantMap> properties = bus.asyncCall(message);
55     QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(properties, this);
56 
57     connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) {
58         self->deleteLater();
59 
60         const QDBusPendingReply<QVariantMap> properties = *self;
61         if (properties.isError()) {
62             return;
63         }
64 
65         updateProperties(properties.value());
66     });
67 }
68 
handleServiceUnregistered()69 void MonitorPrivate::handleServiceUnregistered()
70 {
71     QDBusConnection bus = QDBusConnection::sessionBus();
72 
73     // clang-format off
74     bus.disconnect(s_serviceName,
75                    s_nightColorPath,
76                    s_propertiesInterface,
77                    QStringLiteral("PropertiesChanged"),
78                    this,
79                    SLOT(handlePropertiesChanged(QString,QVariantMap,QStringList)));
80     // clang-format on
81 
82     setAvailable(false);
83 }
84 
handlePropertiesChanged(const QString & interfaceName,const QVariantMap & changedProperties,const QStringList & invalidatedProperties)85 void MonitorPrivate::handlePropertiesChanged(const QString &interfaceName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties)
86 {
87     Q_UNUSED(interfaceName)
88     Q_UNUSED(invalidatedProperties)
89 
90     updateProperties(changedProperties);
91 }
92 
currentTemperature() const93 int MonitorPrivate::currentTemperature() const
94 {
95     return m_currentTemperature;
96 }
97 
targetTemperature() const98 int MonitorPrivate::targetTemperature() const
99 {
100     return m_targetTemperature;
101 }
102 
updateProperties(const QVariantMap & properties)103 void MonitorPrivate::updateProperties(const QVariantMap &properties)
104 {
105     const QVariant available = properties.value(QStringLiteral("available"));
106     if (available.isValid()) {
107         setAvailable(available.toBool());
108     }
109 
110     const QVariant enabled = properties.value(QStringLiteral("enabled"));
111     if (enabled.isValid()) {
112         setEnabled(enabled.toBool());
113     }
114 
115     const QVariant running = properties.value(QStringLiteral("running"));
116     if (running.isValid()) {
117         setRunning(running.toBool());
118     }
119 
120     const QVariant currentTemperature = properties.value(QStringLiteral("currentTemperature"));
121     if (currentTemperature.isValid()) {
122         setCurrentTemperature(currentTemperature.toInt());
123     }
124 
125     const QVariant targetTemperature = properties.value(QStringLiteral("targetTemperature"));
126     if (targetTemperature.isValid()) {
127         setTargetTemperature(targetTemperature.toInt());
128     }
129 }
130 
setCurrentTemperature(int temperature)131 void MonitorPrivate::setCurrentTemperature(int temperature)
132 {
133     if (m_currentTemperature == temperature) {
134         return;
135     }
136     m_currentTemperature = temperature;
137     Q_EMIT currentTemperatureChanged();
138 }
139 
setTargetTemperature(int temperature)140 void MonitorPrivate::setTargetTemperature(int temperature)
141 {
142     if (m_targetTemperature == temperature) {
143         return;
144     }
145     m_targetTemperature = temperature;
146     Q_EMIT targetTemperatureChanged();
147 }
148 
isAvailable() const149 bool MonitorPrivate::isAvailable() const
150 {
151     return m_isAvailable;
152 }
153 
setAvailable(bool available)154 void MonitorPrivate::setAvailable(bool available)
155 {
156     if (m_isAvailable == available) {
157         return;
158     }
159     m_isAvailable = available;
160     Q_EMIT availableChanged();
161 }
162 
isEnabled() const163 bool MonitorPrivate::isEnabled() const
164 {
165     return m_isEnabled;
166 }
167 
setEnabled(bool enabled)168 void MonitorPrivate::setEnabled(bool enabled)
169 {
170     if (m_isEnabled == enabled) {
171         return;
172     }
173     m_isEnabled = enabled;
174     Q_EMIT enabledChanged();
175 }
176 
isRunning() const177 bool MonitorPrivate::isRunning() const
178 {
179     return m_isRunning;
180 }
181 
setRunning(bool running)182 void MonitorPrivate::setRunning(bool running)
183 {
184     if (m_isRunning == running) {
185         return;
186     }
187     m_isRunning = running;
188     Q_EMIT runningChanged();
189 }
190 
Monitor(QObject * parent)191 Monitor::Monitor(QObject *parent)
192     : QObject(parent)
193     , d(new MonitorPrivate(this))
194 {
195     connect(d, &MonitorPrivate::availableChanged, this, &Monitor::availableChanged);
196     connect(d, &MonitorPrivate::enabledChanged, this, &Monitor::enabledChanged);
197     connect(d, &MonitorPrivate::runningChanged, this, &Monitor::runningChanged);
198     connect(d, &MonitorPrivate::currentTemperatureChanged, this, &Monitor::currentTemperatureChanged);
199     connect(d, &MonitorPrivate::targetTemperatureChanged, this, &Monitor::targetTemperatureChanged);
200 }
201 
~Monitor()202 Monitor::~Monitor()
203 {
204 }
205 
isAvailable() const206 bool Monitor::isAvailable() const
207 {
208     return d->isAvailable();
209 }
210 
isEnabled() const211 bool Monitor::isEnabled() const
212 {
213     return d->isEnabled();
214 }
215 
isRunning() const216 bool Monitor::isRunning() const
217 {
218     return d->isRunning();
219 }
220 
currentTemperature() const221 int Monitor::currentTemperature() const
222 {
223     return d->currentTemperature();
224 }
225 
targetTemperature() const226 int Monitor::targetTemperature() const
227 {
228     return d->targetTemperature();
229 }
230