Plasma5Support

powermanagementengine.cpp
1/*
2 SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
3 SPDX-FileCopyrightText: 2007-2008 Sebastian Kuegler <sebas@kde.org>
4 SPDX-FileCopyrightText: 2007 Maor Vanmak <mvanmak1@gmail.com>
5 SPDX-FileCopyrightText: 2008 Dario Freddi <drf54321@gmail.com>
6
7 SPDX-License-Identifier: LGPL-2.0-only
8*/
9
10#include "powermanagementengine.h"
11
12// solid specific includes
13#include <solid/device.h>
14#include <solid/deviceinterface.h>
15#include <solid/devicenotifier.h>
16
17#include <KAuthorized>
18#include <KIdleTime>
19#include <KService>
20#include <klocalizedstring.h>
21
22#include <QDebug>
23
24#include <QDBusConnectionInterface>
25#include <QDBusError>
26#include <QDBusInterface>
27#include <QDBusMetaType>
28#include <QDBusPendingCallWatcher>
29#include <QDBusReply>
30#include <QIcon>
31
32#include "powermanagementservice.h"
33#include <Plasma5Support/DataContainer>
34
35using namespace Qt::StringLiterals;
36
37static constexpr QLatin1String SOLID_POWERMANAGEMENT_SERVICE("org.kde.Solid.PowerManagement");
38static constexpr QLatin1String FDO_POWERMANAGEMENT_SERVICE("org.freedesktop.PowerManagement");
39
40namespace
41{
42template<typename ReplyType>
43void createAsyncDBusMethodCallAndCallback(QObject *parent,
44 const QString &destination,
45 const QString &path,
46 const QString &interface,
47 const QString &method,
48 std::function<void(ReplyType)> &&callback)
49{
50 QDBusMessage msg = QDBusMessage::createMethodCall(destination, path, interface, method);
52 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, parent);
53 parent->connect(watcher, &QDBusPendingCallWatcher::finished, parent, [callback](QDBusPendingCallWatcher *watcher) {
54 QDBusPendingReply<ReplyType> reply = *watcher;
55 if (!reply.isError()) {
56 callback(reply.value());
57 }
58 watcher->deleteLater();
59 });
60}
61}
62
63PowermanagementEngine::PowermanagementEngine(QObject *parent)
64 : Plasma5Support::DataEngine(parent)
65 , m_sources(basicSourceNames())
66{
67 qDBusRegisterMetaType<QList<InhibitionInfo>>();
68 qDBusRegisterMetaType<InhibitionInfo>();
69 qDBusRegisterMetaType<QList<QVariant>>();
70 qDBusRegisterMetaType<QList<QVariantMap>>();
71 init();
72}
73
74PowermanagementEngine::~PowermanagementEngine()
75{
76}
77
78void PowermanagementEngine::init()
79{
80 connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceAdded, this, &PowermanagementEngine::deviceAdded);
81 connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceRemoved, this, &PowermanagementEngine::deviceRemoved);
82
83 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(SOLID_POWERMANAGEMENT_SERVICE)) {
84 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
85 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/HandleButtonEvents"),
86 QStringLiteral("org.kde.Solid.PowerManagement.Actions.HandleButtonEvents"),
87 QStringLiteral("triggersLidActionChanged"),
88 this,
89 SLOT(triggersLidActionChanged(bool)))) {
90 qDebug() << "error connecting to lid action trigger changes via dbus";
91 }
92
93 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
94 QStringLiteral("/org/kde/Solid/PowerManagement/PolicyAgent"),
95 QStringLiteral("org.kde.Solid.PowerManagement.PolicyAgent"),
96 QStringLiteral("InhibitionsChanged"),
97 this,
98 SLOT(inhibitionsChanged(QList<InhibitionInfo>, QStringList)))) {
99 qDebug() << "error connecting to inhibition changes via dbus";
100 }
101
102 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
103 QStringLiteral("/org/kde/Solid/PowerManagement"),
104 SOLID_POWERMANAGEMENT_SERVICE,
105 QStringLiteral("batteryRemainingTimeChanged"),
106 this,
107 SLOT(batteryRemainingTimeChanged(qulonglong)))) {
108 qDebug() << "error connecting to remaining time changes";
109 }
110
111 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
112 QStringLiteral("/org/kde/Solid/PowerManagement"),
113 SOLID_POWERMANAGEMENT_SERVICE,
114 QStringLiteral("smoothedBatteryRemainingTimeChanged"),
115 this,
116 SLOT(smoothedBatteryRemainingTimeChanged(qulonglong)))) {
117 qDebug() << "error connecting to smoothed remaining time changes";
118 }
119
120 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
121 QStringLiteral("/org/kde/Solid/PowerManagement"),
122 SOLID_POWERMANAGEMENT_SERVICE,
123 QStringLiteral("chargeStopThresholdChanged"),
124 this,
125 SLOT(chargeStopThresholdChanged(int)))) {
126 qDebug() << "error connecting to charge stop threshold changes via dbus";
127 }
128
129 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
130 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"),
131 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"),
132 QStringLiteral("currentProfileChanged"),
133 this,
134 SLOT(updatePowerProfileCurrentProfile(QString)))) {
135 qDebug() << "error connecting to current profile changes via dbus";
136 }
137
138 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
139 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"),
140 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"),
141 QStringLiteral("profileChoicesChanged"),
142 this,
143 SLOT(updatePowerProfileChoices(QStringList)))) {
144 qDebug() << "error connecting to profile choices changes via dbus";
145 }
146
147 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
148 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"),
149 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"),
150 QStringLiteral("performanceInhibitedReasonChanged"),
151 this,
152 SLOT(updatePowerProfilePerformanceInhibitedReason(QString)))) {
153 qDebug() << "error connecting to inhibition reason changes via dbus";
154 }
155
156 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
157 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"),
158 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"),
159 QStringLiteral("performanceDegradedReasonChanged"),
160 this,
161 SLOT(updatePowerProfilePerformanceDegradedReason(QString)))) {
162 qDebug() << "error connecting to degradation reason changes via dbus";
163 }
164
165 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
166 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"),
167 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"),
168 QStringLiteral("profileHoldsChanged"),
169 this,
170 SLOT(updatePowerProfileHolds(QList<QVariantMap>)))) {
171 qDebug() << "error connecting to profile hold changes via dbus";
172 }
173 }
174
175 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE,
176 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"),
177 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"),
178 QStringLiteral("configuredProfileChanged"),
179 this,
180 SLOT(updatePowerProfileConfiguredProfile(QString)))) {
181 qDebug() << "error connecting to configured profile changes via dbus";
182 }
183
184 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(FDO_POWERMANAGEMENT_SERVICE)) {
185 if (!QDBusConnection::sessionBus().connect(FDO_POWERMANAGEMENT_SERVICE,
186 QStringLiteral("/org/freedesktop/PowerManagement"),
187 QStringLiteral("org.freedesktop.PowerManagement.Inhibit"),
188 QStringLiteral("HasInhibitChanged"),
189 this,
190 SLOT(hasInhibitionChanged(bool)))) {
191 qDebug() << "error connecting to fdo inhibition changes via dbus";
192 }
193 }
194}
195
196QStringList PowermanagementEngine::basicSourceNames() const
197{
199 sources << QStringLiteral("Battery") << QStringLiteral("AC Adapter") << QStringLiteral("Sleep States") << QStringLiteral("PowerDevil")
200 << QStringLiteral("Inhibitions") << QStringLiteral("Power Profiles") << QStringLiteral("PowerManagement");
201 return sources;
202}
203
205{
206 return m_sources;
207}
208
210{
211 if (name == QLatin1String("Battery")) {
212 const QList<Solid::Device> listBattery = Solid::Device::listFromType(Solid::DeviceInterface::Battery);
213 m_batterySources.clear();
214
215 if (listBattery.isEmpty()) {
216 setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), false);
217 setData(QStringLiteral("Battery"), QStringLiteral("Has Cumulative"), false);
218 return true;
219 }
220
221 uint index = 0;
222 QStringList batterySources;
223
224 for (const Solid::Device &deviceBattery : listBattery) {
225 const Solid::Battery *battery = deviceBattery.as<Solid::Battery>();
226
227 const QString source = QStringLiteral("Battery%1").arg(index++);
228
229 batterySources << source;
230 m_batterySources[deviceBattery.udi()] = source;
231
232 connect(battery, &Solid::Battery::chargeStateChanged, this, &PowermanagementEngine::updateBatteryChargeState);
233 connect(battery, &Solid::Battery::chargePercentChanged, this, &PowermanagementEngine::updateBatteryChargePercent);
234 connect(battery, &Solid::Battery::energyChanged, this, &PowermanagementEngine::updateBatteryEnergy);
235 connect(battery, &Solid::Battery::presentStateChanged, this, &PowermanagementEngine::updateBatteryPresentState);
236
237 // Set initial values
238 updateBatteryChargeState(battery->chargeState(), deviceBattery.udi());
239 updateBatteryChargePercent(battery->chargePercent(), deviceBattery.udi());
240 updateBatteryEnergy(battery->energy(), deviceBattery.udi());
241 updateBatteryPresentState(battery->isPresent(), deviceBattery.udi());
242 updateBatteryPowerSupplyState(battery->isPowerSupply(), deviceBattery.udi());
243
244 setData(source, QStringLiteral("Vendor"), deviceBattery.vendor());
245 setData(source, QStringLiteral("Product"), deviceBattery.product());
246 setData(source, QStringLiteral("Capacity"), battery->capacity());
247 setData(source, QStringLiteral("Type"), batteryTypeToString(battery));
248 }
249
250 updateBatteryNames();
251 updateOverallBattery();
252
253 setData(QStringLiteral("Battery"), QStringLiteral("Sources"), batterySources);
254 setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), !batterySources.isEmpty());
255 if (!batterySources.isEmpty()) {
256 createPowerManagementDBusMethodCallAndNotifyChanged<qulonglong>(
257 QStringLiteral("batteryRemainingTime"),
258 std::bind(&PowermanagementEngine::batteryRemainingTimeChanged, this, std::placeholders::_1));
259 createPowerManagementDBusMethodCallAndNotifyChanged<qulonglong>(
260 QStringLiteral("smoothedBatteryRemainingTime"),
261 std::bind(&PowermanagementEngine::smoothedBatteryRemainingTimeChanged, this, std::placeholders::_1));
262 }
263
264 createPowerManagementDBusMethodCallAndNotifyChanged<int>(QStringLiteral("chargeStopThreshold"),
265 std::bind(&PowermanagementEngine::chargeStopThresholdChanged, this, std::placeholders::_1));
266
267 m_sources = basicSourceNames() + batterySources;
268 } else if (name == QLatin1String("AC Adapter")) {
269 QDBusConnection::sessionBus().connect(QStringLiteral("org.freedesktop.PowerManagement"),
270 QStringLiteral("/org/freedesktop/PowerManagement"),
271 QStringLiteral("org.freedesktop.PowerManagement"),
272 QStringLiteral("PowerSaveStatusChanged"),
273 this,
274 SLOT(updateAcPlugState(bool)));
275
276 QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.PowerManagement"),
277 QStringLiteral("/org/freedesktop/PowerManagement"),
278 QStringLiteral("org.freedesktop.PowerManagement"),
279 QStringLiteral("GetPowerSaveStatus"));
281 updateAcPlugState(reply.isValid() ? reply.value() : false);
282 } else if (name == QLatin1String("PowerDevil")) {
283 createPowerManagementDBusMethodCallAndNotifyChanged<bool>(QStringLiteral("isLidPresent"), [this](bool replyValue) {
284 setData(QStringLiteral("PowerDevil"), QStringLiteral("Is Lid Present"), replyValue);
285 });
286
287 createAsyncDBusMethodCallAndCallback<bool>(this,
288 SOLID_POWERMANAGEMENT_SERVICE,
289 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/HandleButtonEvents"),
290 QStringLiteral("org.kde.Solid.PowerManagement.Actions.HandleButtonEvents"),
291 QStringLiteral("triggersLidAction"),
292 std::bind(&PowermanagementEngine::triggersLidActionChanged, this, std::placeholders::_1));
293 } else if (name == QLatin1String("PowerManagement")) {
294 createAsyncDBusMethodCallAndCallback<bool>(this,
295 QStringLiteral("org.freedesktop.PowerManagement"),
296 QStringLiteral("/org/freedesktop/PowerManagement"),
297 QStringLiteral("org.freedesktop.PowerManagement.Inhibit"),
298 QStringLiteral("HasInhibit"),
299 [this](const bool &replyValue) {
300 hasInhibitionChanged(replyValue);
301 });
302
303 } else if (name == QLatin1String("Inhibitions")) {
304 createAsyncDBusMethodCallAndCallback<QList<InhibitionInfo>>(this,
305 SOLID_POWERMANAGEMENT_SERVICE,
306 QStringLiteral("/org/kde/Solid/PowerManagement/PolicyAgent"),
307 QStringLiteral("org.kde.Solid.PowerManagement.PolicyAgent"),
308 QStringLiteral("ListInhibitions"),
309 [this](const QList<InhibitionInfo> &replyValue) {
310 removeAllData(QStringLiteral("Inhibitions"));
311 inhibitionsChanged(replyValue, QStringList());
312 });
313 // any info concerning lock screen/screensaver goes here
314 } else if (name == QLatin1String("UserActivity")) {
315 setData(QStringLiteral("UserActivity"), QStringLiteral("IdleTime"), KIdleTime::instance()->idleTime());
316 } else if (name == QLatin1String("Power Profiles")) {
317 updatePowerProfileDaemonInstalled(QDBusConnection::systemBus().interface()->isServiceRegistered(QStringLiteral("net.hadess.PowerProfiles")).value());
318 createPowerProfileDBusMethodCallAndNotifyChanged<QString>(
319 QStringLiteral("currentProfile"),
320 std::bind(&PowermanagementEngine::updatePowerProfileCurrentProfile, this, std::placeholders::_1));
321 createPowerProfileDBusMethodCallAndNotifyChanged<QStringList>(
322 QStringLiteral("profileChoices"),
323 std::bind(&PowermanagementEngine::updatePowerProfileChoices, this, std::placeholders::_1));
324 createPowerProfileDBusMethodCallAndNotifyChanged<QString>(
325 QStringLiteral("performanceInhibitedReason"),
326 std::bind(&PowermanagementEngine::updatePowerProfilePerformanceInhibitedReason, this, std::placeholders::_1));
327 createPowerProfileDBusMethodCallAndNotifyChanged<QString>(
328 QStringLiteral("performanceDegradedReason"),
329 std::bind(&PowermanagementEngine::updatePowerProfilePerformanceDegradedReason, this, std::placeholders::_1));
330 createPowerProfileDBusMethodCallAndNotifyChanged<QList<QVariantMap>>(
331 QStringLiteral("profileHolds"),
332 std::bind(&PowermanagementEngine::updatePowerProfileHolds, this, std::placeholders::_1));
333 createPowerProfileDBusMethodCallAndNotifyChanged<QString>(
334 QStringLiteral("configuredProfile"),
335 std::bind(&PowermanagementEngine::updatePowerProfileConfiguredProfile, this, std::placeholders::_1));
336 } else {
337 qDebug() << "Data for" << name << "not found";
338 return false;
339 }
340 return true;
341}
342
343QString PowermanagementEngine::batteryTypeToString(const Solid::Battery *battery) const
344{
345 switch (battery->type()) {
346 case Solid::Battery::PrimaryBattery:
347 return QStringLiteral("Battery");
348 case Solid::Battery::UpsBattery:
349 return QStringLiteral("Ups");
350 case Solid::Battery::MonitorBattery:
351 return QStringLiteral("Monitor");
352 case Solid::Battery::MouseBattery:
353 return QStringLiteral("Mouse");
354 case Solid::Battery::KeyboardBattery:
355 return QStringLiteral("Keyboard");
356 case Solid::Battery::PdaBattery:
357 return QStringLiteral("Pda");
358 case Solid::Battery::PhoneBattery:
359 return QStringLiteral("Phone");
360 case Solid::Battery::GamingInputBattery:
361 return QStringLiteral("GamingInput");
362 case Solid::Battery::BluetoothBattery:
363 return QStringLiteral("Bluetooth");
364 case Solid::Battery::TabletBattery:
365 return QStringLiteral("Tablet");
366 case Solid::Battery::HeadphoneBattery:
367 return QStringLiteral("Headphone");
368 case Solid::Battery::HeadsetBattery:
369 return QStringLiteral("Headset");
370 case Solid::Battery::TouchpadBattery:
371 return QStringLiteral("Touchpad");
372 default:
373 return QStringLiteral("Unknown");
374 }
375}
376
378{
379 if (source == QLatin1String("UserActivity")) {
380 setData(QStringLiteral("UserActivity"), QStringLiteral("IdleTime"), KIdleTime::instance()->idleTime());
381 return true;
382 }
384}
385
387{
388 if (source == QLatin1String("PowerDevil")) {
389 return new PowerManagementService(this);
390 }
391
392 return nullptr;
393}
394
395QString PowermanagementEngine::batteryStateToString(int newState) const
396{
397 QString state(QStringLiteral("Unknown"));
398 if (newState == Solid::Battery::NoCharge) {
399 state = QLatin1String("NoCharge");
400 } else if (newState == Solid::Battery::Charging) {
401 state = QLatin1String("Charging");
402 } else if (newState == Solid::Battery::Discharging) {
403 state = QLatin1String("Discharging");
404 } else if (newState == Solid::Battery::FullyCharged) {
405 state = QLatin1String("FullyCharged");
406 }
407
408 return state;
409}
410
411void PowermanagementEngine::updateBatteryChargeState(int newState, const QString &udi)
412{
413 const QString source = m_batterySources[udi];
414 setData(source, QStringLiteral("State"), batteryStateToString(newState));
415 updateOverallBattery();
416}
417
418void PowermanagementEngine::updateBatteryPresentState(bool newState, const QString &udi)
419{
420 const QString source = m_batterySources[udi];
421 setData(source, QStringLiteral("Plugged in"), newState); // FIXME This needs to be renamed and Battery Monitor adjusted
422}
423
424void PowermanagementEngine::updateBatteryChargePercent(int newValue, const QString &udi)
425{
426 const QString source = m_batterySources[udi];
427 setData(source, QStringLiteral("Percent"), newValue);
428 updateOverallBattery();
429}
430
431void PowermanagementEngine::updateBatteryEnergy(double newValue, const QString &udi)
432{
433 const QString source = m_batterySources[udi];
434 setData(source, QStringLiteral("Energy"), newValue);
435}
436
437void PowermanagementEngine::updateBatteryPowerSupplyState(bool newState, const QString &udi)
438{
439 const QString source = m_batterySources[udi];
440 setData(source, QStringLiteral("Is Power Supply"), newState);
441}
442
443void PowermanagementEngine::updateBatteryNames()
444{
445 uint unnamedBatteries = 0;
446 for (const QString &source : std::as_const(m_batterySources)) {
447 DataContainer *batteryDataContainer = containerForSource(source);
448 if (batteryDataContainer) {
449 const QString batteryVendor = batteryDataContainer->data()[QStringLiteral("Vendor")].toString();
450 const QString batteryProduct = batteryDataContainer->data()[QStringLiteral("Product")].toString();
451
452 // Don't show battery name for primary power supply batteries. They usually have cryptic serial number names.
453 const bool showBatteryName = batteryDataContainer->data()[QStringLiteral("Type")].toString() != QLatin1String("Battery")
454 || !batteryDataContainer->data()[QStringLiteral("Is Power Supply")].toBool();
455
456 if (!batteryProduct.isEmpty() && batteryProduct != QLatin1String("Unknown Battery") && showBatteryName) {
457 if (!batteryVendor.isEmpty()) {
458 setData(source, QStringLiteral("Pretty Name"), QString(batteryVendor + ' ' + batteryProduct));
459 } else {
460 setData(source, QStringLiteral("Pretty Name"), batteryProduct);
461 }
462 } else {
463 ++unnamedBatteries;
464 if (unnamedBatteries > 1) {
465 setData(source, QStringLiteral("Pretty Name"), i18nc("Placeholder is the battery number", "Battery %1", unnamedBatteries));
466 } else {
467 setData(source, QStringLiteral("Pretty Name"), i18n("Battery"));
468 }
469 }
470 }
471 }
472}
473
474void PowermanagementEngine::updateOverallBattery()
475{
476 const QList<Solid::Device> listBattery = Solid::Device::listFromType(Solid::DeviceInterface::Battery);
477 bool hasCumulative = false;
478
479 double energy = 0;
480 double totalEnergy = 0;
481 bool allFullyCharged = true;
482 bool charging = false;
483 bool noCharge = false;
484 double totalPercentage = 0;
485 int count = 0;
486
487 for (const Solid::Device &deviceBattery : listBattery) {
488 const Solid::Battery *battery = deviceBattery.as<Solid::Battery>();
489
490 if (battery && battery->isPowerSupply()) {
491 hasCumulative = true;
492
493 energy += battery->energy();
494 totalEnergy += battery->energyFull();
495 totalPercentage += battery->chargePercent();
496 allFullyCharged = allFullyCharged && (battery->chargeState() == Solid::Battery::FullyCharged);
497 charging = charging || (battery->chargeState() == Solid::Battery::Charging);
498 noCharge = noCharge || (battery->chargeState() == Solid::Battery::NoCharge);
499 ++count;
500 }
501 }
502
503 if (count == 1) {
504 // Energy is sometimes way off causing us to show rubbish; this is a UPower issue
505 // but anyway having just one battery and the tooltip showing strange readings
506 // compared to the popup doesn't look polished.
507 setData(QStringLiteral("Battery"), QStringLiteral("Percent"), qRound(totalPercentage));
508 } else if (totalEnergy > 0) {
509 setData(QStringLiteral("Battery"), QStringLiteral("Percent"), qRound(energy / totalEnergy * 100));
510 } else if (count > 0) { // UPS don't have energy, see Bug 348588
511 setData(QStringLiteral("Battery"), QStringLiteral("Percent"), qRound(totalPercentage / static_cast<qreal>(count)));
512 } else {
513 setData(QStringLiteral("Battery"), QStringLiteral("Percent"), int(0));
514 }
515
516 if (hasCumulative) {
517 if (allFullyCharged) {
518 setData(QStringLiteral("Battery"), QStringLiteral("State"), "FullyCharged");
519 } else if (charging) {
520 setData(QStringLiteral("Battery"), QStringLiteral("State"), "Charging");
521 } else if (noCharge) {
522 setData(QStringLiteral("Battery"), QStringLiteral("State"), "NoCharge");
523 } else {
524 setData(QStringLiteral("Battery"), QStringLiteral("State"), "Discharging");
525 }
526 } else {
527 setData(QStringLiteral("Battery"), QStringLiteral("State"), "Unknown");
528 }
529
530 setData(QStringLiteral("Battery"), QStringLiteral("Has Cumulative"), hasCumulative);
531}
532
533void PowermanagementEngine::updateAcPlugState(bool onBattery)
534{
535 setData(QStringLiteral("AC Adapter"), QStringLiteral("Plugged in"), !onBattery);
536}
537
538void PowermanagementEngine::updatePowerProfileDaemonInstalled(const bool &installed)
539{
540 setData(QStringLiteral("Power Profiles"), QStringLiteral("Installed"), installed);
541}
542
543void PowermanagementEngine::updatePowerProfileCurrentProfile(const QString &activeProfile)
544{
545 setData(QStringLiteral("Power Profiles"), QStringLiteral("Current Profile"), activeProfile);
546}
547
548void PowermanagementEngine::updatePowerProfileChoices(const QStringList &choices)
549{
550 setData(QStringLiteral("Power Profiles"), QStringLiteral("Profiles"), choices);
551}
552
553void PowermanagementEngine::updatePowerProfilePerformanceInhibitedReason(const QString &reason)
554{
555 setData(QStringLiteral("Power Profiles"), QStringLiteral("Performance Inhibited Reason"), reason);
556}
557
558void PowermanagementEngine::updatePowerProfilePerformanceDegradedReason(const QString &reason)
559{
560 setData(QStringLiteral("Power Profiles"), QStringLiteral("Performance Degraded Reason"), reason);
561}
562
563void PowermanagementEngine::updatePowerProfileHolds(const QList<QVariantMap> &holds)
564{
566 std::transform(holds.cbegin(), holds.cend(), std::back_inserter(out), [this](const QVariantMap &hold) {
567 QString prettyName;
568 QString icon;
569 populateApplicationData(hold[QStringLiteral("ApplicationId")].toString(), &prettyName, &icon);
570 return QVariantMap{
571 {QStringLiteral("Name"), prettyName},
572 {QStringLiteral("Icon"), icon},
573 {QStringLiteral("Reason"), hold[QStringLiteral("Reason")]},
574 {QStringLiteral("Profile"), hold[QStringLiteral("Profile")]},
575 };
576 });
577 setData(QStringLiteral("Power Profiles"), QStringLiteral("Profile Holds"), QVariant::fromValue(out));
578}
579
580void PowermanagementEngine::updatePowerProfileConfiguredProfile(const QString &activeProfile)
581{
582 setData(QStringLiteral("Power Profiles"), QStringLiteral("Configured Profile"), activeProfile);
583}
584
585void PowermanagementEngine::deviceRemoved(const QString &udi)
586{
587 if (m_batterySources.contains(udi)) {
588 Solid::Device device(udi);
589 Solid::Battery *battery = device.as<Solid::Battery>();
590 if (battery) {
591 battery->disconnect(this);
592 }
593
594 const QString source = m_batterySources[udi];
595 m_batterySources.remove(udi);
596 removeSource(source);
597
598 QStringList sourceNames(m_batterySources.values());
599 sourceNames.removeAll(source);
600 setData(QStringLiteral("Battery"), QStringLiteral("Sources"), sourceNames);
601 setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), !sourceNames.isEmpty());
602
603 updateOverallBattery();
604 }
605}
606
607void PowermanagementEngine::deviceAdded(const QString &udi)
608{
609 Solid::Device device(udi);
610 if (device.isValid()) {
611 const Solid::Battery *battery = device.as<Solid::Battery>();
612
613 if (battery) {
614 int index = 0;
615 QStringList sourceNames(m_batterySources.values());
616 while (sourceNames.contains(QStringLiteral("Battery%1").arg(index))) {
617 index++;
618 }
619
620 const QString source = QStringLiteral("Battery%1").arg(index);
621 sourceNames << source;
622 m_batterySources[device.udi()] = source;
623
624 connect(battery, &Solid::Battery::chargeStateChanged, this, &PowermanagementEngine::updateBatteryChargeState);
625 connect(battery, &Solid::Battery::chargePercentChanged, this, &PowermanagementEngine::updateBatteryChargePercent);
626 connect(battery, &Solid::Battery::energyChanged, this, &PowermanagementEngine::updateBatteryEnergy);
627 connect(battery, &Solid::Battery::presentStateChanged, this, &PowermanagementEngine::updateBatteryPresentState);
628 connect(battery, &Solid::Battery::powerSupplyStateChanged, this, &PowermanagementEngine::updateBatteryPowerSupplyState);
629
630 // Set initial values
631 updateBatteryChargeState(battery->chargeState(), device.udi());
632 updateBatteryChargePercent(battery->chargePercent(), device.udi());
633 updateBatteryEnergy(battery->energy(), device.udi());
634 updateBatteryPresentState(battery->isPresent(), device.udi());
635 updateBatteryPowerSupplyState(battery->isPowerSupply(), device.udi());
636
637 setData(source, QStringLiteral("Vendor"), device.vendor());
638 setData(source, QStringLiteral("Product"), device.product());
639 setData(source, QStringLiteral("Capacity"), battery->capacity());
640 setData(source, QStringLiteral("Type"), batteryTypeToString(battery));
641
642 setData(QStringLiteral("Battery"), QStringLiteral("Sources"), sourceNames);
643 setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), !sourceNames.isEmpty());
644
645 updateBatteryNames();
646 updateOverallBattery();
647 }
648 }
649}
650
651void PowermanagementEngine::batteryRemainingTimeChanged(qulonglong time)
652{
653 // qDebug() << "Remaining time 2:" << time;
654 setData(QStringLiteral("Battery"), QStringLiteral("Remaining msec"), time);
655}
656
657void PowermanagementEngine::smoothedBatteryRemainingTimeChanged(qulonglong time)
658{
659 setData(QStringLiteral("Battery"), QStringLiteral("Smoothed Remaining msec"), time);
660}
661
662void PowermanagementEngine::triggersLidActionChanged(bool triggers)
663{
664 setData(QStringLiteral("PowerDevil"), QStringLiteral("Triggers Lid Action"), triggers);
665}
666
667void PowermanagementEngine::hasInhibitionChanged(bool inhibited)
668{
669 setData(QStringLiteral("PowerManagement"), QStringLiteral("Has Inhibition"), inhibited);
670}
671
672void PowermanagementEngine::inhibitionsChanged(const QList<InhibitionInfo> &added, const QStringList &removed)
673{
674 for (auto it = removed.constBegin(); it != removed.constEnd(); ++it) {
675 removeData(QStringLiteral("Inhibitions"), (*it));
676 }
677
678 for (auto it = added.constBegin(); it != added.constEnd(); ++it) {
679 const QString &name = (*it).first;
680 QString prettyName;
681 QString icon;
682 const QString &reason = (*it).second;
683
684 populateApplicationData(name, &prettyName, &icon);
685
686 setData(QStringLiteral("Inhibitions"),
687 name,
688 QVariantMap{{QStringLiteral("Name"), prettyName}, {QStringLiteral("Icon"), icon}, {QStringLiteral("Reason"), reason}});
689 }
690}
691
692template<typename ReplyType>
693inline void PowermanagementEngine::createPowerManagementDBusMethodCallAndNotifyChanged(const QString &method, std::function<void(ReplyType)> &&callback)
694{
695 createAsyncDBusMethodCallAndCallback<ReplyType>(this,
696 SOLID_POWERMANAGEMENT_SERVICE,
697 QStringLiteral("/org/kde/Solid/PowerManagement"),
698 SOLID_POWERMANAGEMENT_SERVICE,
699 method,
700 std::move(callback));
701}
702
703template<typename ReplyType>
704inline void PowermanagementEngine::createPowerProfileDBusMethodCallAndNotifyChanged(const QString &method, std::function<void(ReplyType)> &&callback)
705{
706 createAsyncDBusMethodCallAndCallback<ReplyType>(this,
707 SOLID_POWERMANAGEMENT_SERVICE,
708 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"),
709 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"),
710 method,
711 std::move(callback));
712}
713
714void PowermanagementEngine::populateApplicationData(const QString &name, QString *prettyName, QString *icon)
715{
716 if (m_applicationInfo.contains(name)) {
717 const auto &info = m_applicationInfo.value(name);
718 *prettyName = info.first;
719 *icon = info.second;
720 } else {
721 KService::Ptr service = KService::serviceByStorageId(name + ".desktop"_L1);
722 if (service) {
723 *prettyName = service->name(); // cannot be null
724 *icon = service->icon();
725
726 m_applicationInfo.insert(name, qMakePair(*prettyName, *icon));
727 } else {
728 *prettyName = name;
729 *icon = name.section(QLatin1Char('/'), -1).toLower();
730 if (!QIcon::hasThemeIcon(*icon)) {
731 icon->clear();
732 }
733 }
734 }
735}
736
737void PowermanagementEngine::chargeStopThresholdChanged(int threshold)
738{
739 setData(QStringLiteral("Battery"), QStringLiteral("Charge Stop Threshold"), threshold);
740}
741
742K_PLUGIN_CLASS_WITH_JSON(PowermanagementEngine, "plasma-dataengine-powermanagement.json")
743
744#include "powermanagementengine.moc"
static KIdleTime * instance()
#define K_PLUGIN_CLASS_WITH_JSON(classname, jsonFile)
static Ptr serviceByStorageId(const QString &_storageId)
A set of data exported via a DataEngine.
const DataEngine::Data data() const
Returns the data for this DataContainer.
Data provider for plasmoids (Plasma plugins)
Definition dataengine.h:45
void removeSource(const QString &source)
Removes a data source.
virtual bool updateSourceEvent(const QString &source)
Called by internal updating mechanisms to trigger the engine to refresh the data contained in a given...
void removeData(const QString &source, const QString &key)
Removes a data entry from a source.
void setData(const QString &source, const QVariant &value)
Sets a value for a data source.
Q_INVOKABLE DataContainer * containerForSource(const QString &source)
Retrieves a pointer to the DataContainer for a given source.
void removeAllData(const QString &source)
Removes all the data associated with a data source.
This class provides a generic API for write access to settings or services.
Definition service.h:78
This class provides runtime information about the battery and AC status for use in power management P...
QStringList sources() const override
bool sourceRequestEvent(const QString &name) override
When a source that does not currently exist is requested by the consumer, this method is called to gi...
bool updateSourceEvent(const QString &source) override
Called by internal updating mechanisms to trigger the engine to refresh the data contained in a given...
Plasma5Support::Service * serviceForSource(const QString &source) override
void energyChanged(double energy, const QString &udi)
Solid::Battery::BatteryType type() const
int chargePercent() const
Solid::Battery::ChargeState chargeState() const
bool isPresent() const
double energyFull() const
int capacity() const
void powerSupplyStateChanged(bool newState, const QString &udi)
void presentStateChanged(bool newState, const QString &udi)
bool isPowerSupply() const
void chargePercentChanged(int value, const QString &udi)
void chargeStateChanged(int newState, const QString &udi=QString())
double energy() const
void deviceRemoved(const QString &udi)
void deviceAdded(const QString &udi)
static QList< Device > listFromType(const DeviceInterface::Type &type, const QString &parentUdi=QString())
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QString name(StandardAction id)
Namespace for everything in libplasma.
Definition datamodel.cpp:15
QCA_EXPORT void init()
QDBusPendingCall asyncCall(const QDBusMessage &message, int timeout) const const
QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const const
bool connect(const QString &service, const QString &path, const QString &interface, const QString &name, QObject *receiver, const char *slot)
QDBusConnection sessionBus()
QDBusConnection systemBus()
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
void finished(QDBusPendingCallWatcher *self)
bool isError() const const
typename Select< 0 >::Type value() const const
bool isValid() const const
void clear()
bool contains(const Key &key) const const
iterator insert(const Key &key, const T &value)
bool remove(const Key &key)
T value(const Key &key) const const
QList< T > values() const const
bool hasThemeIcon(const QString &name)
const_iterator cbegin() const const
const_iterator cend() const const
const_iterator constBegin() const const
const_iterator constEnd() const const
bool isEmpty() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
bool disconnect(const QMetaObject::Connection &connection)
QString arg(Args &&... args) const const
void clear()
QString first(qsizetype n) const const
bool isEmpty() const const
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
QString toLower() const const
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:59:38 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.