File indexing completed on 2024-05-19 05:37:52
0001 /* 0002 SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org> 0003 SPDX-FileCopyrightText: 2007-2008 Sebastian Kuegler <sebas@kde.org> 0004 SPDX-FileCopyrightText: 2007 Maor Vanmak <mvanmak1@gmail.com> 0005 SPDX-FileCopyrightText: 2008 Dario Freddi <drf54321@gmail.com> 0006 0007 SPDX-License-Identifier: LGPL-2.0-only 0008 */ 0009 0010 #include "powermanagementengine.h" 0011 0012 // kde-workspace/libs 0013 #include <sessionmanagement.h> 0014 0015 // solid specific includes 0016 #include <solid/device.h> 0017 #include <solid/deviceinterface.h> 0018 #include <solid/devicenotifier.h> 0019 0020 #include <KAuthorized> 0021 #include <KIdleTime> 0022 #include <KService> 0023 #include <klocalizedstring.h> 0024 0025 #include <QDebug> 0026 0027 #include <QDBusConnectionInterface> 0028 #include <QDBusError> 0029 #include <QDBusInterface> 0030 #include <QDBusMetaType> 0031 #include <QDBusPendingCallWatcher> 0032 #include <QDBusReply> 0033 #include <QIcon> 0034 0035 #include "powermanagementservice.h" 0036 #include <Plasma5Support/DataContainer> 0037 0038 static const char SOLID_POWERMANAGEMENT_SERVICE[] = "org.kde.Solid.PowerManagement"; 0039 static const char FDO_POWERMANAGEMENT_SERVICE[] = "org.freedesktop.PowerManagement"; 0040 0041 namespace 0042 { 0043 template<typename ReplyType> 0044 void createAsyncDBusMethodCallAndCallback(QObject *parent, 0045 const QString &destination, 0046 const QString &path, 0047 const QString &interface, 0048 const QString &method, 0049 std::function<void(ReplyType)> &&callback) 0050 { 0051 QDBusMessage msg = QDBusMessage::createMethodCall(destination, path, interface, method); 0052 QDBusPendingReply<ReplyType> reply = QDBusConnection::sessionBus().asyncCall(msg); 0053 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, parent); 0054 parent->connect(watcher, &QDBusPendingCallWatcher::finished, parent, [callback](QDBusPendingCallWatcher *watcher) { 0055 QDBusPendingReply<ReplyType> reply = *watcher; 0056 if (!reply.isError()) { 0057 callback(reply.value()); 0058 } 0059 watcher->deleteLater(); 0060 }); 0061 } 0062 } 0063 0064 PowermanagementEngine::PowermanagementEngine(QObject *parent) 0065 : Plasma5Support::DataEngine(parent) 0066 , m_sources(basicSourceNames()) 0067 , m_session(new SessionManagement(this)) 0068 { 0069 qDBusRegisterMetaType<QList<InhibitionInfo>>(); 0070 qDBusRegisterMetaType<InhibitionInfo>(); 0071 qDBusRegisterMetaType<QList<QVariant>>(); 0072 qDBusRegisterMetaType<QList<QVariantMap>>(); 0073 init(); 0074 } 0075 0076 PowermanagementEngine::~PowermanagementEngine() 0077 { 0078 } 0079 0080 void PowermanagementEngine::init() 0081 { 0082 connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceAdded, this, &PowermanagementEngine::deviceAdded); 0083 connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceRemoved, this, &PowermanagementEngine::deviceRemoved); 0084 0085 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(SOLID_POWERMANAGEMENT_SERVICE)) { 0086 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0087 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), 0088 QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"), 0089 QStringLiteral("brightnessChanged"), 0090 this, 0091 SLOT(screenBrightnessChanged(int)))) { 0092 qDebug() << "error connecting to Brightness changes via dbus"; 0093 } 0094 0095 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0096 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), 0097 QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"), 0098 QStringLiteral("brightnessMaxChanged"), 0099 this, 0100 SLOT(maximumScreenBrightnessChanged(int)))) { 0101 qDebug() << "error connecting to max brightness changes via dbus"; 0102 } 0103 0104 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0105 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl"), 0106 QStringLiteral("org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl"), 0107 QStringLiteral("keyboardBrightnessChanged"), 0108 this, 0109 SLOT(keyboardBrightnessChanged(int)))) { 0110 qDebug() << "error connecting to Keyboard Brightness changes via dbus"; 0111 } 0112 0113 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0114 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl"), 0115 QStringLiteral("org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl"), 0116 QStringLiteral("keyboardBrightnessMaxChanged"), 0117 this, 0118 SLOT(maximumKeyboardBrightnessChanged(int)))) { 0119 qDebug() << "error connecting to max keyboard Brightness changes via dbus"; 0120 } 0121 0122 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0123 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/HandleButtonEvents"), 0124 QStringLiteral("org.kde.Solid.PowerManagement.Actions.HandleButtonEvents"), 0125 QStringLiteral("triggersLidActionChanged"), 0126 this, 0127 SLOT(triggersLidActionChanged(bool)))) { 0128 qDebug() << "error connecting to lid action trigger changes via dbus"; 0129 } 0130 0131 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0132 QStringLiteral("/org/kde/Solid/PowerManagement/PolicyAgent"), 0133 QStringLiteral("org.kde.Solid.PowerManagement.PolicyAgent"), 0134 QStringLiteral("InhibitionsChanged"), 0135 this, 0136 SLOT(inhibitionsChanged(QList<InhibitionInfo>, QStringList)))) { 0137 qDebug() << "error connecting to inhibition changes via dbus"; 0138 } 0139 0140 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0141 QStringLiteral("/org/kde/Solid/PowerManagement"), 0142 SOLID_POWERMANAGEMENT_SERVICE, 0143 QStringLiteral("batteryRemainingTimeChanged"), 0144 this, 0145 SLOT(batteryRemainingTimeChanged(qulonglong)))) { 0146 qDebug() << "error connecting to remaining time changes"; 0147 } 0148 0149 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0150 QStringLiteral("/org/kde/Solid/PowerManagement"), 0151 SOLID_POWERMANAGEMENT_SERVICE, 0152 QStringLiteral("smoothedBatteryRemainingTimeChanged"), 0153 this, 0154 SLOT(smoothedBatteryRemainingTimeChanged(qulonglong)))) { 0155 qDebug() << "error connecting to smoothed remaining time changes"; 0156 } 0157 0158 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0159 QStringLiteral("/org/kde/Solid/PowerManagement"), 0160 SOLID_POWERMANAGEMENT_SERVICE, 0161 QStringLiteral("chargeStopThresholdChanged"), 0162 this, 0163 SLOT(chargeStopThresholdChanged(int)))) { 0164 qDebug() << "error connecting to charge stop threshold changes via dbus"; 0165 } 0166 0167 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0168 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"), 0169 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"), 0170 QStringLiteral("currentProfileChanged"), 0171 this, 0172 SLOT(updatePowerProfileCurrentProfile(QString)))) { 0173 qDebug() << "error connecting to current profile changes via dbus"; 0174 } 0175 0176 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0177 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"), 0178 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"), 0179 QStringLiteral("profileChoicesChanged"), 0180 this, 0181 SLOT(updatePowerProfileChoices(QStringList)))) { 0182 qDebug() << "error connecting to profile choices changes via dbus"; 0183 } 0184 0185 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0186 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"), 0187 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"), 0188 QStringLiteral("performanceInhibitedReasonChanged"), 0189 this, 0190 SLOT(updatePowerProfilePerformanceInhibitedReason(QString)))) { 0191 qDebug() << "error connecting to inhibition reason changes via dbus"; 0192 } 0193 0194 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0195 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"), 0196 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"), 0197 QStringLiteral("performanceDegradedReasonChanged"), 0198 this, 0199 SLOT(updatePowerProfilePerformanceDegradedReason(QString)))) { 0200 qDebug() << "error connecting to degradation reason changes via dbus"; 0201 } 0202 0203 if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, 0204 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"), 0205 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"), 0206 QStringLiteral("profileHoldsChanged"), 0207 this, 0208 SLOT(updatePowerProfileHolds(QList<QVariantMap>)))) { 0209 qDebug() << "error connecting to profile hold changes via dbus"; 0210 } 0211 } 0212 0213 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(FDO_POWERMANAGEMENT_SERVICE)) { 0214 if (!QDBusConnection::sessionBus().connect(FDO_POWERMANAGEMENT_SERVICE, 0215 QStringLiteral("/org/freedesktop/PowerManagement"), 0216 QStringLiteral("org.freedesktop.PowerManagement.Inhibit"), 0217 QStringLiteral("HasInhibitChanged"), 0218 this, 0219 SLOT(hasInhibitionChanged(bool)))) { 0220 qDebug() << "error connecting to fdo inhibition changes via dbus"; 0221 } 0222 } 0223 } 0224 0225 QStringList PowermanagementEngine::basicSourceNames() const 0226 { 0227 QStringList sources; 0228 sources << QStringLiteral("Battery") << QStringLiteral("AC Adapter") << QStringLiteral("Sleep States") << QStringLiteral("PowerDevil") 0229 << QStringLiteral("Inhibitions") << QStringLiteral("Power Profiles") << QStringLiteral("PowerManagement"); 0230 return sources; 0231 } 0232 0233 QStringList PowermanagementEngine::sources() const 0234 { 0235 return m_sources; 0236 } 0237 0238 bool PowermanagementEngine::sourceRequestEvent(const QString &name) 0239 { 0240 if (name == QLatin1String("Battery")) { 0241 const QList<Solid::Device> listBattery = Solid::Device::listFromType(Solid::DeviceInterface::Battery); 0242 m_batterySources.clear(); 0243 0244 if (listBattery.isEmpty()) { 0245 setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), false); 0246 setData(QStringLiteral("Battery"), QStringLiteral("Has Cumulative"), false); 0247 return true; 0248 } 0249 0250 uint index = 0; 0251 QStringList batterySources; 0252 0253 for (const Solid::Device &deviceBattery : listBattery) { 0254 const Solid::Battery *battery = deviceBattery.as<Solid::Battery>(); 0255 0256 const QString source = QStringLiteral("Battery%1").arg(index++); 0257 0258 batterySources << source; 0259 m_batterySources[deviceBattery.udi()] = source; 0260 0261 connect(battery, &Solid::Battery::chargeStateChanged, this, &PowermanagementEngine::updateBatteryChargeState); 0262 connect(battery, &Solid::Battery::chargePercentChanged, this, &PowermanagementEngine::updateBatteryChargePercent); 0263 connect(battery, &Solid::Battery::energyChanged, this, &PowermanagementEngine::updateBatteryEnergy); 0264 connect(battery, &Solid::Battery::presentStateChanged, this, &PowermanagementEngine::updateBatteryPresentState); 0265 0266 // Set initial values 0267 updateBatteryChargeState(battery->chargeState(), deviceBattery.udi()); 0268 updateBatteryChargePercent(battery->chargePercent(), deviceBattery.udi()); 0269 updateBatteryEnergy(battery->energy(), deviceBattery.udi()); 0270 updateBatteryPresentState(battery->isPresent(), deviceBattery.udi()); 0271 updateBatteryPowerSupplyState(battery->isPowerSupply(), deviceBattery.udi()); 0272 0273 setData(source, QStringLiteral("Vendor"), deviceBattery.vendor()); 0274 setData(source, QStringLiteral("Product"), deviceBattery.product()); 0275 setData(source, QStringLiteral("Capacity"), battery->capacity()); 0276 setData(source, QStringLiteral("Type"), batteryTypeToString(battery)); 0277 } 0278 0279 updateBatteryNames(); 0280 updateOverallBattery(); 0281 0282 setData(QStringLiteral("Battery"), QStringLiteral("Sources"), batterySources); 0283 setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), !batterySources.isEmpty()); 0284 if (!batterySources.isEmpty()) { 0285 createPowerManagementDBusMethodCallAndNotifyChanged<qulonglong>( 0286 QStringLiteral("batteryRemainingTime"), 0287 std::bind(&PowermanagementEngine::batteryRemainingTimeChanged, this, std::placeholders::_1)); 0288 createPowerManagementDBusMethodCallAndNotifyChanged<qulonglong>( 0289 QStringLiteral("smoothedBatteryRemainingTime"), 0290 std::bind(&PowermanagementEngine::smoothedBatteryRemainingTimeChanged, this, std::placeholders::_1)); 0291 } 0292 0293 createPowerManagementDBusMethodCallAndNotifyChanged<int>(QStringLiteral("chargeStopThreshold"), 0294 std::bind(&PowermanagementEngine::chargeStopThresholdChanged, this, std::placeholders::_1)); 0295 0296 m_sources = basicSourceNames() + batterySources; 0297 } else if (name == QLatin1String("AC Adapter")) { 0298 QDBusConnection::sessionBus().connect(QStringLiteral("org.freedesktop.PowerManagement"), 0299 QStringLiteral("/org/freedesktop/PowerManagement"), 0300 QStringLiteral("org.freedesktop.PowerManagement"), 0301 QStringLiteral("PowerSaveStatusChanged"), 0302 this, 0303 SLOT(updateAcPlugState(bool))); 0304 0305 QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.PowerManagement"), 0306 QStringLiteral("/org/freedesktop/PowerManagement"), 0307 QStringLiteral("org.freedesktop.PowerManagement"), 0308 QStringLiteral("GetPowerSaveStatus")); 0309 QDBusReply<bool> reply = QDBusConnection::sessionBus().call(msg); 0310 updateAcPlugState(reply.isValid() ? reply.value() : false); 0311 } else if (name == QLatin1String("Sleep States")) { 0312 setData(QStringLiteral("Sleep States"), QStringLiteral("Standby"), m_session->canSuspend()); 0313 setData(QStringLiteral("Sleep States"), QStringLiteral("Suspend"), m_session->canSuspend()); 0314 setData(QStringLiteral("Sleep States"), QStringLiteral("Hibernate"), m_session->canHibernate()); 0315 setData(QStringLiteral("Sleep States"), QStringLiteral("HybridSuspend"), m_session->canHybridSuspend()); 0316 setData(QStringLiteral("Sleep States"), QStringLiteral("LockScreen"), m_session->canLock()); 0317 setData(QStringLiteral("Sleep States"), QStringLiteral("Logout"), m_session->canLogout()); 0318 } else if (name == QLatin1String("PowerDevil")) { 0319 createAsyncDBusMethodCallAndCallback<int>(this, 0320 SOLID_POWERMANAGEMENT_SERVICE, 0321 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), 0322 QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"), 0323 QStringLiteral("brightness"), 0324 std::bind(&PowermanagementEngine::screenBrightnessChanged, this, std::placeholders::_1)); 0325 0326 createAsyncDBusMethodCallAndCallback<int>(this, 0327 SOLID_POWERMANAGEMENT_SERVICE, 0328 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), 0329 QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"), 0330 QStringLiteral("brightnessMax"), 0331 std::bind(&PowermanagementEngine::maximumScreenBrightnessChanged, this, std::placeholders::_1)); 0332 0333 createAsyncDBusMethodCallAndCallback<int>(this, 0334 SOLID_POWERMANAGEMENT_SERVICE, 0335 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl"), 0336 QStringLiteral("org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl"), 0337 QStringLiteral("keyboardBrightness"), 0338 std::bind(&PowermanagementEngine::keyboardBrightnessChanged, this, std::placeholders::_1)); 0339 0340 createAsyncDBusMethodCallAndCallback<int>(this, 0341 SOLID_POWERMANAGEMENT_SERVICE, 0342 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl"), 0343 QStringLiteral("org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl"), 0344 QStringLiteral("keyboardBrightnessMax"), 0345 std::bind(&PowermanagementEngine::maximumKeyboardBrightnessChanged, this, std::placeholders::_1)); 0346 0347 createPowerManagementDBusMethodCallAndNotifyChanged<bool>(QStringLiteral("isLidPresent"), [this](bool replyValue) { 0348 setData(QStringLiteral("PowerDevil"), QStringLiteral("Is Lid Present"), replyValue); 0349 }); 0350 0351 createAsyncDBusMethodCallAndCallback<bool>(this, 0352 SOLID_POWERMANAGEMENT_SERVICE, 0353 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/HandleButtonEvents"), 0354 QStringLiteral("org.kde.Solid.PowerManagement.Actions.HandleButtonEvents"), 0355 QStringLiteral("triggersLidAction"), 0356 std::bind(&PowermanagementEngine::triggersLidActionChanged, this, std::placeholders::_1)); 0357 } else if (name == QLatin1String("PowerManagement")) { 0358 createAsyncDBusMethodCallAndCallback<bool>(this, 0359 QStringLiteral("org.freedesktop.PowerManagement"), 0360 QStringLiteral("/org/freedesktop/PowerManagement"), 0361 QStringLiteral("org.freedesktop.PowerManagement.Inhibit"), 0362 QStringLiteral("HasInhibit"), 0363 [this](const bool &replyValue) { 0364 hasInhibitionChanged(replyValue); 0365 }); 0366 0367 } else if (name == QLatin1String("Inhibitions")) { 0368 createAsyncDBusMethodCallAndCallback<QList<InhibitionInfo>>(this, 0369 SOLID_POWERMANAGEMENT_SERVICE, 0370 QStringLiteral("/org/kde/Solid/PowerManagement/PolicyAgent"), 0371 QStringLiteral("org.kde.Solid.PowerManagement.PolicyAgent"), 0372 QStringLiteral("ListInhibitions"), 0373 [this](const QList<InhibitionInfo> &replyValue) { 0374 removeAllData(QStringLiteral("Inhibitions")); 0375 inhibitionsChanged(replyValue, QStringList()); 0376 }); 0377 // any info concerning lock screen/screensaver goes here 0378 } else if (name == QLatin1String("UserActivity")) { 0379 setData(QStringLiteral("UserActivity"), QStringLiteral("IdleTime"), KIdleTime::instance()->idleTime()); 0380 } else if (name == QLatin1String("Power Profiles")) { 0381 updatePowerProfileDaemonInstalled(QDBusConnection::systemBus().interface()->isServiceRegistered(QStringLiteral("net.hadess.PowerProfiles")).value()); 0382 createPowerProfileDBusMethodCallAndNotifyChanged<QString>( 0383 QStringLiteral("currentProfile"), 0384 std::bind(&PowermanagementEngine::updatePowerProfileCurrentProfile, this, std::placeholders::_1)); 0385 createPowerProfileDBusMethodCallAndNotifyChanged<QStringList>( 0386 QStringLiteral("profileChoices"), 0387 std::bind(&PowermanagementEngine::updatePowerProfileChoices, this, std::placeholders::_1)); 0388 createPowerProfileDBusMethodCallAndNotifyChanged<QString>( 0389 QStringLiteral("performanceInhibitedReason"), 0390 std::bind(&PowermanagementEngine::updatePowerProfilePerformanceInhibitedReason, this, std::placeholders::_1)); 0391 createPowerProfileDBusMethodCallAndNotifyChanged<QString>( 0392 QStringLiteral("performanceDegradedReason"), 0393 std::bind(&PowermanagementEngine::updatePowerProfilePerformanceDegradedReason, this, std::placeholders::_1)); 0394 createPowerProfileDBusMethodCallAndNotifyChanged<QList<QVariantMap>>( 0395 QStringLiteral("profileHolds"), 0396 std::bind(&PowermanagementEngine::updatePowerProfileHolds, this, std::placeholders::_1)); 0397 } else { 0398 qDebug() << "Data for" << name << "not found"; 0399 return false; 0400 } 0401 return true; 0402 } 0403 0404 QString PowermanagementEngine::batteryTypeToString(const Solid::Battery *battery) const 0405 { 0406 switch (battery->type()) { 0407 case Solid::Battery::PrimaryBattery: 0408 return QStringLiteral("Battery"); 0409 case Solid::Battery::UpsBattery: 0410 return QStringLiteral("Ups"); 0411 case Solid::Battery::MonitorBattery: 0412 return QStringLiteral("Monitor"); 0413 case Solid::Battery::MouseBattery: 0414 return QStringLiteral("Mouse"); 0415 case Solid::Battery::KeyboardBattery: 0416 return QStringLiteral("Keyboard"); 0417 case Solid::Battery::PdaBattery: 0418 return QStringLiteral("Pda"); 0419 case Solid::Battery::PhoneBattery: 0420 return QStringLiteral("Phone"); 0421 case Solid::Battery::GamingInputBattery: 0422 return QStringLiteral("GamingInput"); 0423 case Solid::Battery::BluetoothBattery: 0424 return QStringLiteral("Bluetooth"); 0425 default: 0426 return QStringLiteral("Unknown"); 0427 } 0428 } 0429 0430 bool PowermanagementEngine::updateSourceEvent(const QString &source) 0431 { 0432 if (source == QLatin1String("UserActivity")) { 0433 setData(QStringLiteral("UserActivity"), QStringLiteral("IdleTime"), KIdleTime::instance()->idleTime()); 0434 return true; 0435 } 0436 return Plasma5Support::DataEngine::updateSourceEvent(source); 0437 } 0438 0439 Plasma5Support::Service *PowermanagementEngine::serviceForSource(const QString &source) 0440 { 0441 if (source == QLatin1String("PowerDevil")) { 0442 return new PowerManagementService(this); 0443 } 0444 0445 return nullptr; 0446 } 0447 0448 QString PowermanagementEngine::batteryStateToString(int newState) const 0449 { 0450 QString state(QStringLiteral("Unknown")); 0451 if (newState == Solid::Battery::NoCharge) { 0452 state = QLatin1String("NoCharge"); 0453 } else if (newState == Solid::Battery::Charging) { 0454 state = QLatin1String("Charging"); 0455 } else if (newState == Solid::Battery::Discharging) { 0456 state = QLatin1String("Discharging"); 0457 } else if (newState == Solid::Battery::FullyCharged) { 0458 state = QLatin1String("FullyCharged"); 0459 } 0460 0461 return state; 0462 } 0463 0464 void PowermanagementEngine::updateBatteryChargeState(int newState, const QString &udi) 0465 { 0466 const QString source = m_batterySources[udi]; 0467 setData(source, QStringLiteral("State"), batteryStateToString(newState)); 0468 updateOverallBattery(); 0469 } 0470 0471 void PowermanagementEngine::updateBatteryPresentState(bool newState, const QString &udi) 0472 { 0473 const QString source = m_batterySources[udi]; 0474 setData(source, QStringLiteral("Plugged in"), newState); // FIXME This needs to be renamed and Battery Monitor adjusted 0475 } 0476 0477 void PowermanagementEngine::updateBatteryChargePercent(int newValue, const QString &udi) 0478 { 0479 const QString source = m_batterySources[udi]; 0480 setData(source, QStringLiteral("Percent"), newValue); 0481 updateOverallBattery(); 0482 } 0483 0484 void PowermanagementEngine::updateBatteryEnergy(double newValue, const QString &udi) 0485 { 0486 const QString source = m_batterySources[udi]; 0487 setData(source, QStringLiteral("Energy"), newValue); 0488 } 0489 0490 void PowermanagementEngine::updateBatteryPowerSupplyState(bool newState, const QString &udi) 0491 { 0492 const QString source = m_batterySources[udi]; 0493 setData(source, QStringLiteral("Is Power Supply"), newState); 0494 } 0495 0496 void PowermanagementEngine::updateBatteryNames() 0497 { 0498 uint unnamedBatteries = 0; 0499 for (const QString &source : std::as_const(m_batterySources)) { 0500 DataContainer *batteryDataContainer = containerForSource(source); 0501 if (batteryDataContainer) { 0502 const QString batteryVendor = batteryDataContainer->data()[QStringLiteral("Vendor")].toString(); 0503 const QString batteryProduct = batteryDataContainer->data()[QStringLiteral("Product")].toString(); 0504 0505 // Don't show battery name for primary power supply batteries. They usually have cryptic serial number names. 0506 const bool showBatteryName = batteryDataContainer->data()[QStringLiteral("Type")].toString() != QLatin1String("Battery") 0507 || !batteryDataContainer->data()[QStringLiteral("Is Power Supply")].toBool(); 0508 0509 if (!batteryProduct.isEmpty() && batteryProduct != QLatin1String("Unknown Battery") && showBatteryName) { 0510 if (!batteryVendor.isEmpty()) { 0511 setData(source, QStringLiteral("Pretty Name"), QString(batteryVendor + ' ' + batteryProduct)); 0512 } else { 0513 setData(source, QStringLiteral("Pretty Name"), batteryProduct); 0514 } 0515 } else { 0516 ++unnamedBatteries; 0517 if (unnamedBatteries > 1) { 0518 setData(source, QStringLiteral("Pretty Name"), i18nc("Placeholder is the battery number", "Battery %1", unnamedBatteries)); 0519 } else { 0520 setData(source, QStringLiteral("Pretty Name"), i18n("Battery")); 0521 } 0522 } 0523 } 0524 } 0525 } 0526 0527 void PowermanagementEngine::updateOverallBattery() 0528 { 0529 const QList<Solid::Device> listBattery = Solid::Device::listFromType(Solid::DeviceInterface::Battery); 0530 bool hasCumulative = false; 0531 0532 double energy = 0; 0533 double totalEnergy = 0; 0534 bool allFullyCharged = true; 0535 bool charging = false; 0536 bool noCharge = false; 0537 double totalPercentage = 0; 0538 int count = 0; 0539 0540 for (const Solid::Device &deviceBattery : listBattery) { 0541 const Solid::Battery *battery = deviceBattery.as<Solid::Battery>(); 0542 0543 if (battery && battery->isPowerSupply()) { 0544 hasCumulative = true; 0545 0546 energy += battery->energy(); 0547 totalEnergy += battery->energyFull(); 0548 totalPercentage += battery->chargePercent(); 0549 allFullyCharged = allFullyCharged && (battery->chargeState() == Solid::Battery::FullyCharged); 0550 charging = charging || (battery->chargeState() == Solid::Battery::Charging); 0551 noCharge = noCharge || (battery->chargeState() == Solid::Battery::NoCharge); 0552 ++count; 0553 } 0554 } 0555 0556 if (count == 1) { 0557 // Energy is sometimes way off causing us to show rubbish; this is a UPower issue 0558 // but anyway having just one battery and the tooltip showing strange readings 0559 // compared to the popup doesn't look polished. 0560 setData(QStringLiteral("Battery"), QStringLiteral("Percent"), qRound(totalPercentage)); 0561 } else if (totalEnergy > 0) { 0562 setData(QStringLiteral("Battery"), QStringLiteral("Percent"), qRound(energy / totalEnergy * 100)); 0563 } else if (count > 0) { // UPS don't have energy, see Bug 348588 0564 setData(QStringLiteral("Battery"), QStringLiteral("Percent"), qRound(totalPercentage / static_cast<qreal>(count))); 0565 } else { 0566 setData(QStringLiteral("Battery"), QStringLiteral("Percent"), int(0)); 0567 } 0568 0569 if (hasCumulative) { 0570 if (allFullyCharged) { 0571 setData(QStringLiteral("Battery"), QStringLiteral("State"), "FullyCharged"); 0572 } else if (charging) { 0573 setData(QStringLiteral("Battery"), QStringLiteral("State"), "Charging"); 0574 } else if (noCharge) { 0575 setData(QStringLiteral("Battery"), QStringLiteral("State"), "NoCharge"); 0576 } else { 0577 setData(QStringLiteral("Battery"), QStringLiteral("State"), "Discharging"); 0578 } 0579 } else { 0580 setData(QStringLiteral("Battery"), QStringLiteral("State"), "Unknown"); 0581 } 0582 0583 setData(QStringLiteral("Battery"), QStringLiteral("Has Cumulative"), hasCumulative); 0584 } 0585 0586 void PowermanagementEngine::updateAcPlugState(bool onBattery) 0587 { 0588 setData(QStringLiteral("AC Adapter"), QStringLiteral("Plugged in"), !onBattery); 0589 } 0590 0591 void PowermanagementEngine::updatePowerProfileDaemonInstalled(const bool &installed) 0592 { 0593 setData(QStringLiteral("Power Profiles"), QStringLiteral("Installed"), installed); 0594 } 0595 0596 void PowermanagementEngine::updatePowerProfileCurrentProfile(const QString &activeProfile) 0597 { 0598 setData(QStringLiteral("Power Profiles"), QStringLiteral("Current Profile"), activeProfile); 0599 } 0600 0601 void PowermanagementEngine::updatePowerProfileChoices(const QStringList &choices) 0602 { 0603 setData(QStringLiteral("Power Profiles"), QStringLiteral("Profiles"), choices); 0604 } 0605 0606 void PowermanagementEngine::updatePowerProfilePerformanceInhibitedReason(const QString &reason) 0607 { 0608 setData(QStringLiteral("Power Profiles"), QStringLiteral("Performance Inhibited Reason"), reason); 0609 } 0610 0611 void PowermanagementEngine::updatePowerProfilePerformanceDegradedReason(const QString &reason) 0612 { 0613 setData(QStringLiteral("Power Profiles"), QStringLiteral("Performance Degraded Reason"), reason); 0614 } 0615 0616 void PowermanagementEngine::updatePowerProfileHolds(const QList<QVariantMap> &holds) 0617 { 0618 QList<QVariantMap> out; 0619 std::transform(holds.cbegin(), holds.cend(), std::back_inserter(out), [this](const QVariantMap &hold) { 0620 QString prettyName; 0621 QString icon; 0622 populateApplicationData(hold[QStringLiteral("ApplicationId")].toString(), &prettyName, &icon); 0623 return QVariantMap{ 0624 {QStringLiteral("Name"), prettyName}, 0625 {QStringLiteral("Icon"), icon}, 0626 {QStringLiteral("Reason"), hold[QStringLiteral("Reason")]}, 0627 {QStringLiteral("Profile"), hold[QStringLiteral("Profile")]}, 0628 }; 0629 }); 0630 setData(QStringLiteral("Power Profiles"), QStringLiteral("Profile Holds"), QVariant::fromValue(out)); 0631 } 0632 0633 void PowermanagementEngine::deviceRemoved(const QString &udi) 0634 { 0635 if (m_batterySources.contains(udi)) { 0636 Solid::Device device(udi); 0637 Solid::Battery *battery = device.as<Solid::Battery>(); 0638 if (battery) { 0639 battery->disconnect(this); 0640 } 0641 0642 const QString source = m_batterySources[udi]; 0643 m_batterySources.remove(udi); 0644 removeSource(source); 0645 0646 QStringList sourceNames(m_batterySources.values()); 0647 sourceNames.removeAll(source); 0648 setData(QStringLiteral("Battery"), QStringLiteral("Sources"), sourceNames); 0649 setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), !sourceNames.isEmpty()); 0650 0651 updateOverallBattery(); 0652 } 0653 } 0654 0655 void PowermanagementEngine::deviceAdded(const QString &udi) 0656 { 0657 Solid::Device device(udi); 0658 if (device.isValid()) { 0659 const Solid::Battery *battery = device.as<Solid::Battery>(); 0660 0661 if (battery) { 0662 int index = 0; 0663 QStringList sourceNames(m_batterySources.values()); 0664 while (sourceNames.contains(QStringLiteral("Battery%1").arg(index))) { 0665 index++; 0666 } 0667 0668 const QString source = QStringLiteral("Battery%1").arg(index); 0669 sourceNames << source; 0670 m_batterySources[device.udi()] = source; 0671 0672 connect(battery, &Solid::Battery::chargeStateChanged, this, &PowermanagementEngine::updateBatteryChargeState); 0673 connect(battery, &Solid::Battery::chargePercentChanged, this, &PowermanagementEngine::updateBatteryChargePercent); 0674 connect(battery, &Solid::Battery::energyChanged, this, &PowermanagementEngine::updateBatteryEnergy); 0675 connect(battery, &Solid::Battery::presentStateChanged, this, &PowermanagementEngine::updateBatteryPresentState); 0676 connect(battery, &Solid::Battery::powerSupplyStateChanged, this, &PowermanagementEngine::updateBatteryPowerSupplyState); 0677 0678 // Set initial values 0679 updateBatteryChargeState(battery->chargeState(), device.udi()); 0680 updateBatteryChargePercent(battery->chargePercent(), device.udi()); 0681 updateBatteryEnergy(battery->energy(), device.udi()); 0682 updateBatteryPresentState(battery->isPresent(), device.udi()); 0683 updateBatteryPowerSupplyState(battery->isPowerSupply(), device.udi()); 0684 0685 setData(source, QStringLiteral("Vendor"), device.vendor()); 0686 setData(source, QStringLiteral("Product"), device.product()); 0687 setData(source, QStringLiteral("Capacity"), battery->capacity()); 0688 setData(source, QStringLiteral("Type"), batteryTypeToString(battery)); 0689 0690 setData(QStringLiteral("Battery"), QStringLiteral("Sources"), sourceNames); 0691 setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), !sourceNames.isEmpty()); 0692 0693 updateBatteryNames(); 0694 updateOverallBattery(); 0695 } 0696 } 0697 } 0698 0699 void PowermanagementEngine::batteryRemainingTimeChanged(qulonglong time) 0700 { 0701 // qDebug() << "Remaining time 2:" << time; 0702 setData(QStringLiteral("Battery"), QStringLiteral("Remaining msec"), time); 0703 } 0704 0705 void PowermanagementEngine::smoothedBatteryRemainingTimeChanged(qulonglong time) 0706 { 0707 setData(QStringLiteral("Battery"), QStringLiteral("Smoothed Remaining msec"), time); 0708 } 0709 0710 void PowermanagementEngine::screenBrightnessChanged(int brightness) 0711 { 0712 setData(QStringLiteral("PowerDevil"), QStringLiteral("Screen Brightness"), brightness); 0713 } 0714 0715 void PowermanagementEngine::maximumScreenBrightnessChanged(int maximumBrightness) 0716 { 0717 setData(QStringLiteral("PowerDevil"), QStringLiteral("Maximum Screen Brightness"), maximumBrightness); 0718 setData(QStringLiteral("PowerDevil"), QStringLiteral("Screen Brightness Available"), maximumBrightness > 0); 0719 } 0720 0721 void PowermanagementEngine::keyboardBrightnessChanged(int brightness) 0722 { 0723 setData(QStringLiteral("PowerDevil"), QStringLiteral("Keyboard Brightness"), brightness); 0724 } 0725 0726 void PowermanagementEngine::maximumKeyboardBrightnessChanged(int maximumBrightness) 0727 { 0728 setData(QStringLiteral("PowerDevil"), QStringLiteral("Maximum Keyboard Brightness"), maximumBrightness); 0729 setData(QStringLiteral("PowerDevil"), QStringLiteral("Keyboard Brightness Available"), maximumBrightness > 0); 0730 } 0731 0732 void PowermanagementEngine::triggersLidActionChanged(bool triggers) 0733 { 0734 setData(QStringLiteral("PowerDevil"), QStringLiteral("Triggers Lid Action"), triggers); 0735 } 0736 0737 void PowermanagementEngine::hasInhibitionChanged(bool inhibited) 0738 { 0739 setData(QStringLiteral("PowerManagement"), QStringLiteral("Has Inhibition"), inhibited); 0740 } 0741 0742 void PowermanagementEngine::inhibitionsChanged(const QList<InhibitionInfo> &added, const QStringList &removed) 0743 { 0744 for (auto it = removed.constBegin(); it != removed.constEnd(); ++it) { 0745 removeData(QStringLiteral("Inhibitions"), (*it)); 0746 } 0747 0748 for (auto it = added.constBegin(); it != added.constEnd(); ++it) { 0749 const QString &name = (*it).first; 0750 QString prettyName; 0751 QString icon; 0752 const QString &reason = (*it).second; 0753 0754 populateApplicationData(name, &prettyName, &icon); 0755 0756 setData(QStringLiteral("Inhibitions"), 0757 name, 0758 QVariantMap{{QStringLiteral("Name"), prettyName}, {QStringLiteral("Icon"), icon}, {QStringLiteral("Reason"), reason}}); 0759 } 0760 } 0761 0762 template<typename ReplyType> 0763 inline void PowermanagementEngine::createPowerManagementDBusMethodCallAndNotifyChanged(const QString &method, std::function<void(ReplyType)> &&callback) 0764 { 0765 createAsyncDBusMethodCallAndCallback<ReplyType>(this, 0766 SOLID_POWERMANAGEMENT_SERVICE, 0767 QStringLiteral("/org/kde/Solid/PowerManagement"), 0768 SOLID_POWERMANAGEMENT_SERVICE, 0769 method, 0770 std::move(callback)); 0771 } 0772 0773 template<typename ReplyType> 0774 inline void PowermanagementEngine::createPowerProfileDBusMethodCallAndNotifyChanged(const QString &method, std::function<void(ReplyType)> &&callback) 0775 { 0776 createAsyncDBusMethodCallAndCallback<ReplyType>(this, 0777 SOLID_POWERMANAGEMENT_SERVICE, 0778 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"), 0779 QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"), 0780 method, 0781 std::move(callback)); 0782 } 0783 0784 void PowermanagementEngine::populateApplicationData(const QString &name, QString *prettyName, QString *icon) 0785 { 0786 if (m_applicationInfo.contains(name)) { 0787 const auto &info = m_applicationInfo.value(name); 0788 *prettyName = info.first; 0789 *icon = info.second; 0790 } else { 0791 KService::Ptr service = KService::serviceByStorageId(name + ".desktop"); 0792 if (service) { 0793 *prettyName = service->name(); // cannot be null 0794 *icon = service->icon(); 0795 0796 m_applicationInfo.insert(name, qMakePair(*prettyName, *icon)); 0797 } else { 0798 *prettyName = name; 0799 *icon = name.section(QLatin1Char('/'), -1).toLower(); 0800 if (!QIcon::hasThemeIcon(*icon)) { 0801 icon->clear(); 0802 } 0803 } 0804 } 0805 } 0806 0807 void PowermanagementEngine::chargeStopThresholdChanged(int threshold) 0808 { 0809 setData(QStringLiteral("Battery"), QStringLiteral("Charge Stop Threshold"), threshold); 0810 } 0811 0812 K_PLUGIN_CLASS_WITH_JSON(PowermanagementEngine, "plasma-dataengine-powermanagement.json") 0813 0814 #include "powermanagementengine.moc"