Torc  0.1
torcpowerunixdbus.cpp
Go to the documentation of this file.
1 /* Class TorcPowerUnixDBus
2 *
3 * This file is part of the Torc project.
4 *
5 * Copyright (C) Mark Kendall 2012-18
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA.
21 */
22 
23 // clazy:excludeall=function-args-by-ref
24 
25 // Torc
26 #include "torclogging.h"
27 #include "torcpowerunixdbus.h"
28 
40 {
41  static bool available = false;
42  static bool checked = false;
43 
44  if (!checked)
45  {
46  checked = true;
47 
48  QDBusInterface upower(QStringLiteral("org.freedesktop.UPower"),
49  QStringLiteral("/org/freedesktop/UPower"),
50  QStringLiteral("org.freedesktop.UPower"),
51  QDBusConnection::systemBus());
52  QDBusInterface consolekit(QStringLiteral("org.freedesktop.ConsoleKit"),
53  QStringLiteral("/org/freedesktop/ConsoleKit/Manager"),
54  QStringLiteral("org.freedesktop.ConsoleKit.Manager"),
55  QDBusConnection::systemBus());
56 
57  available = upower.isValid() && consolekit.isValid();
58 
59  if (!available)
60  LOG(VB_GENERAL, LOG_WARNING, QStringLiteral("UPower and ConsoleKit not available"));
61  }
62 
63  return available;
64 }
65 
67  : TorcPower(),
68  m_onBattery(false),
69  m_devices(QMap<QString,int>()),
70  m_upowerInterface(QStringLiteral("org.freedesktop.UPower"),
71  QStringLiteral("/org/freedesktop/UPower"),
72  QStringLiteral("org.freedesktop.UPower"),
73  QDBusConnection::systemBus()),
74  m_consoleInterface(QStringLiteral("org.freedesktop.ConsoleKit"),
75  QStringLiteral("/org/freedesktop/ConsoleKit/Manager"),
76  QStringLiteral("org.freedesktop.ConsoleKit.Manager"),
77  QDBusConnection::systemBus())
78 {
79  if (m_consoleInterface.isValid())
80  {
81  QDBusReply<bool> shutdown = m_consoleInterface.call(QStringLiteral("CanStop"));
82  if (shutdown.isValid() && shutdown.value())
83  m_canShutdown->SetValue(QVariant((bool)true));
84 
85  QDBusReply<bool> restart = m_consoleInterface.call(QStringLiteral("CanRestart"));
86  if (restart.isValid() && restart.value())
87  m_canRestart->SetValue(QVariant((bool)true));
88  }
89  else
90  {
91  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to create ConsoleKit interface"));
92  }
93 
94  // populate devices
95  if (m_upowerInterface.isValid())
96  {
97  QDBusReply<QList<QDBusObjectPath> > devicecheck = m_upowerInterface.call(QStringLiteral("EnumerateDevices"));
98 
99  if (devicecheck.isValid())
100  foreach (const QDBusObjectPath &device, devicecheck.value())
101  m_devices.insert(device.path(), GetBatteryLevel(device.path()));
102  }
103  else
104  {
105  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to create UPower interface"));
106  }
107 
108  // register for events
109  if (!QDBusConnection::systemBus().connect(
110  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("/org/freedesktop/UPower"),
111  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("Sleeping"),
112  this, SLOT(Suspending())))
113  {
114  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to register for sleep events"));
115  }
116 
117  if (!QDBusConnection::systemBus().connect(
118  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("/org/freedesktop/UPower"),
119  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("Resuming"),
120  this, SLOT(WokeUp())))
121  {
122  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to register for resume events"));
123  }
124 
125  if (!QDBusConnection::systemBus().connect(
126  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("/org/freedesktop/UPower"),
127  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("Changed"),
128  this, SLOT(Changed())))
129  {
130  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to register for Changed"));
131  }
132 
133  if (!QDBusConnection::systemBus().connect(
134  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("/org/freedesktop/UPower"),
135  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("DeviceChanged"), QStringLiteral("o"),
136  this, SLOT(DeviceChanged(QDBusObjectPath))))
137  {
138  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to register for DeviceChanged"));
139  }
140 
141  if (!QDBusConnection::systemBus().connect(
142  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("/org/freedesktop/UPower"),
143  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("DeviceAdded"), QStringLiteral("o"),
144  this, SLOT(DeviceAdded(QDBusObjectPath))))
145  {
146  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to register for DeviceAdded"));
147  }
148 
149  if (!QDBusConnection::systemBus().connect(
150  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("/org/freedesktop/UPower"),
151  QStringLiteral("org.freedesktop.UPower"), QStringLiteral("DeviceRemoved"), QStringLiteral("o"),
152  this, SLOT(DeviceRemoved(QDBusObjectPath))))
153  {
154  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to register for DeviceRemoved"));
155  }
156 
157  // set battery state
158  Changed();
159 
160  Debug();
161 }
162 
164 {
165  m_httpServiceLock.lockForWrite();
166  if (m_consoleInterface.isValid() && m_canShutdown->GetValue().toBool())
167  {
168  QList<QVariant> dummy;
169  if (m_consoleInterface.callWithCallback(QStringLiteral("Stop"), dummy, (QObject*)this, SLOT(DBusCallback()), SLOT(DBusError(QDBusError))))
170  {
171  m_httpServiceLock.unlock();
172  ShuttingDown();
173  return true;
174  }
175 
176  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Shutdown call failed"));
177  }
178  m_httpServiceLock.unlock();
179  return false;
180 }
181 
183 {
184  m_httpServiceLock.lockForWrite();
185  if (m_upowerInterface.isValid() && m_canSuspend->GetValue().toBool())
186  {
187  QList<QVariant> dummy;
188  if (m_upowerInterface.callWithCallback(QStringLiteral("AboutToSleep"), dummy, (QObject*)this, SLOT(DBusCallback()), SLOT(DBusError(QDBusError))))
189  {
190  if (m_upowerInterface.callWithCallback(QStringLiteral("Suspend"), dummy, (QObject*)this, SLOT(DBusCallback()), SLOT(DBusError(QDBusError))))
191  {
192  m_httpServiceLock.unlock();
193  Suspending();
194  return true;
195  }
196  }
197 
198  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Suspend call failed"));
199  }
200  m_httpServiceLock.unlock();
201  return false;
202 }
203 
205 {
206  m_httpServiceLock.lockForWrite();
207  if (m_upowerInterface.isValid() && m_canHibernate->GetValue().toBool())
208  {
209  QList<QVariant> dummy;
210  if (m_upowerInterface.callWithCallback(QStringLiteral("AboutToSleep"), dummy, (QObject*)this, SLOT(DBusCallback()), SLOT(DBusError(QDBusError))))
211  {
212  if (m_upowerInterface.callWithCallback(QStringLiteral("Hibernate"), dummy, (QObject*)this, SLOT(DBusCallback()), SLOT(DBusError(QDBusError))))
213  {
214  m_httpServiceLock.unlock();
215  Hibernating();
216  return true;
217  }
218  }
219 
220  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Hibernate call failed"));
221  }
222  m_httpServiceLock.unlock();
223  return false;
224 }
225 
227 {
228  m_httpServiceLock.lockForWrite();
229  if (m_consoleInterface.isValid() && m_canRestart->GetValue().toBool())
230  {
231  QList<QVariant> dummy;
232  if (m_consoleInterface.callWithCallback(QStringLiteral("Restart"), dummy, (QObject*)this, SLOT(DBusCallback()), SLOT(DBusError(QDBusError))))
233  {
234  m_httpServiceLock.unlock();
235  Restarting();
236  return true;
237  }
238 
239  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Restart call failed"));
240  }
241  m_httpServiceLock.unlock();
242  return false;
243 }
244 
245 void TorcPowerUnixDBus::DeviceAdded(QDBusObjectPath Device)
246 {
247  {
248  QWriteLocker locker(&m_httpServiceLock);
249 
250  if (m_devices.contains(Device.path()))
251  return;
252 
253  m_devices.insert(Device.path(), GetBatteryLevel(Device.path()));
254  }
255 
256  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Added UPower.Device '%1'").arg(Device.path()));
257  UpdateBattery();
258 }
259 
260 void TorcPowerUnixDBus::DeviceRemoved(QDBusObjectPath Device)
261 {
262  {
263  QWriteLocker locker(&m_httpServiceLock);
264 
265  if (!m_devices.contains(Device.path()))
266  return;
267 
268  m_devices.remove(Device.path());
269  }
270 
271  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Removed UPower.Device '%1'").arg(Device.path()));
272  UpdateBattery();
273 }
274 
275 void TorcPowerUnixDBus::DeviceChanged(QDBusObjectPath Device)
276 {
277  {
278  QWriteLocker locker(&m_httpServiceLock);
279 
280  if (!m_devices.contains(Device.path()))
281  return;
282 
283  m_devices[Device.path()] = GetBatteryLevel(Device.path());
284  }
285 
286  UpdateBattery();
287 }
288 
289 void TorcPowerUnixDBus::DBusError(QDBusError Error)
290 {
291  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("DBus callback error: %1, %2")
292  .arg(Error.name(), Error.message().trimmed()));
293 }
294 
296 {
297 }
298 
300 {
301  UpdateProperties();
302  UpdateBattery();
303 }
304 
305 void TorcPowerUnixDBus::UpdateBattery(void)
306 {
307  m_httpServiceLock.lockForWrite();
308  if (m_onBattery)
309  {
310  qreal total = 0;
311  int count = 0;
312 
313  QMap<QString,int>::const_iterator it = m_devices.constBegin();
314  for ( ; it != m_devices.constEnd(); ++it)
315  {
316  if (it.value() >= 0 && it.value() <= 100)
317  {
318  count++;
319  total += (qreal)it.value();
320  }
321  }
322 
323  if (count > 0)
324  {
325  m_batteryLevel = lround(total / count);
326  }
327  else
328  {
330  }
331  }
332  else
333  {
335  }
336  m_httpServiceLock.unlock();
337 
339 }
340 
341 int TorcPowerUnixDBus::GetBatteryLevel(const QString &Path)
342 {
343  QWriteLocker locker(&m_httpServiceLock);
344  QDBusInterface interface(QStringLiteral("org.freedesktop.UPower"), Path, QStringLiteral("org.freedesktop.UPower.Device"),
345  QDBusConnection::systemBus());
346 
347  if (interface.isValid())
348  {
349  QVariant battery = interface.property("IsRechargeable");
350  if (battery.isValid() && battery.toBool() == true)
351  {
352  QVariant percent = interface.property("Percentage");
353  if (percent.isValid())
354  {
355  int result = lround(percent.toFloat() * 100.0);
356  return qBound(0, result, 100);
357  }
358  }
359  else
360  {
361  return TorcPower::ACPower;
362  }
363  }
364 
366 }
367 
368 void TorcPowerUnixDBus::UpdateProperties(void)
369 {
370  QWriteLocker locker(&m_httpServiceLock);
371 
372  m_canSuspend->SetValue(QVariant((bool)false));
373  m_canHibernate->SetValue(QVariant((bool)false));
374  m_onBattery = false;
375 
376  if (m_upowerInterface.isValid())
377  {
378  QVariant cansuspend = m_upowerInterface.property("CanSuspend");
379  if (cansuspend.isValid() && cansuspend.toBool() == true)
380  m_canSuspend->SetValue(QVariant((bool)true));
381 
382  QVariant canhibernate = m_upowerInterface.property("CanHibernate");
383  if (canhibernate.isValid() && canhibernate.toBool() == true)
384  m_canHibernate->SetValue(QVariant((bool)true));
385 
386  QVariant onbattery = m_upowerInterface.property("OnBattery");
387  if (onbattery.isValid() && onbattery.toBool() == true)
388  m_onBattery = true;
389  }
390 }
391 
393 {
394  void Score(int &Score)
395  {
396  if (Score <= 10 && TorcPowerUnixDBus::Available())
397  Score = 10;
398  }
399 
400  TorcPower* Create(int Score)
401  {
402  if (Score <= 10 && TorcPowerUnixDBus::Available())
403  return new TorcPowerUnixDBus();
404 
405  return nullptr;
406  }
void Restarting(void)
Definition: torcpower.cpp:511
QVariant GetValue(void)
bool DoHibernate(void) override
static void Create(void)
void DeviceAdded(QDBusObjectPath Device)
void BatteryUpdated(int Level)
Definition: torcpower.cpp:275
void Debug(void)
Definition: torcpower.cpp:251
TorcSetting * m_canHibernate
Definition: torcpower.h:95
void DeviceChanged(QDBusObjectPath Device)
TorcSetting * m_canSuspend
Definition: torcpower.h:94
void Hibernating(void)
Definition: torcpower.cpp:505
void DeviceRemoved(QDBusObjectPath Device)
void ShuttingDown(void)
Definition: torcpower.cpp:493
static bool Available(void)
void Suspending(void)
Definition: torcpower.cpp:499
QReadWriteLock m_httpServiceLock
TorcSetting * m_canShutdown
Definition: torcpower.h:93
TorcPowerFactoryUnixDBus TorcPowerFactoryUnixDBus
void WokeUp(void)
Definition: torcpower.cpp:517
A generic power status class.
Definition: torcpower.h:12
void DBusError(QDBusError Error)
int m_batteryLevel
Definition: torcpower.h:97
bool SetValue(const QVariant &Value)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: torclogging.h:20
bool DoSuspend(void) override
bool DoShutdown(void) override
int GetBatteryLevel(void)
Definition: torcpower.cpp:410
TorcSetting * m_canRestart
Definition: torcpower.h:96
bool DoRestart(void) override