diff --git a/components/workspace/BatteryIcon.qml b/components/workspace/BatteryIcon.qml index e4b1a724d..1ddbdcb7c 100644 --- a/components/workspace/BatteryIcon.qml +++ b/components/workspace/BatteryIcon.qml @@ -1,136 +1,138 @@ /* * Copyright 2011 Viranch Mehta * Copyright 2013 Kai Uwe Broulik * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.0 import org.kde.plasma.core 2.0 as PlasmaCore Item { property bool hasBattery property int percent property bool pluggedIn property string batteryType PlasmaCore.Svg { id: svg imagePath: "icons/battery" colorGroup: PlasmaCore.ColorScope.colorGroup onRepaintNeeded: { // needed to detect the hint item go away when theme changes batterySvg.visible = Qt.binding(function() { return !otherBatteriesSvg.visible && (!svg.hasElement("hint-dont-superimpose-fill") || !hasBattery); }) } } PlasmaCore.SvgItem { id: batterySvg anchors.centerIn: parent width: units.roundToIconSize(Math.min(parent.width, parent.height)) height: width svg: svg elementId: "Battery" visible: !otherBatteriesSvg.visible && (!svg.hasElement("hint-dont-superimpose-fill") || !hasBattery) } PlasmaCore.SvgItem { id: fillSvg anchors.fill: batterySvg svg: svg elementId: hasBattery ? fillElement(percent) : "Unavailable" visible: !otherBatteriesSvg.visible } function fillElement(p) { // We switched from having steps of 20 for the battery percentage to a more accurate // step of 10. This means we break other and older themes. // If the Fill10 element is not found, it is likely that the theme doesn't support // that and we use the older method of obtaining the fill element. if (!svg.hasElement("Fill10")) { print("No Fill10 element found in your theme's battery.svg - Using legacy 20% steps for battery icon"); if (p >= 90) { return "Fill100"; } else if (p >= 70) { return "Fill80"; } else if (p >= 50) { return "Fill60"; } else if (p > 20) { return "Fill40"; } else if (p >= 10) { return "Fill20"; } else { return "Fill0"; } } else { if (p >= 95) { return "Fill100"; } else if (p >= 85) { return "Fill90"; } else if (p >= 75) { return "Fill80"; } else if (p >= 65) { return "Fill70"; } else if (p >= 55) { return "Fill60"; } else if (p >= 45) { return "Fill50"; } else if (p >= 35) { return "Fill40"; } else if (p >= 25) { return "Fill30"; } else if (p >= 15) { return "Fill20"; } else if (p > 5) { return "Fill10"; } else { return "Fill0"; } } } PlasmaCore.SvgItem { anchors.fill: batterySvg svg: svg elementId: "AcAdapter" visible: pluggedIn && !otherBatteriesSvg.visible } PlasmaCore.IconItem { id: otherBatteriesSvg anchors.fill: batterySvg source: elementForType(batteryType) visible: source !== "" } function elementForType(t) { switch(t) { case "Mouse": return "input-mouse-battery"; case "Keyboard": return "input-keyboard-battery"; case "Pda": return "phone-battery"; case "Phone": return "phone-battery"; case "Ups": return "battery-ups"; case "GamingInput": return "input-gaming-battery"; + case "Bluetooth": + return "preferences-system-bluetooth-battery"; default: return ""; } } } diff --git a/dataengines/powermanagement/powermanagementengine.cpp b/dataengines/powermanagement/powermanagementengine.cpp index e6db1dfad..f642b976e 100644 --- a/dataengines/powermanagement/powermanagementengine.cpp +++ b/dataengines/powermanagement/powermanagementengine.cpp @@ -1,678 +1,681 @@ /* * Copyright 2007 Aaron Seigo * Copyright 2007-2008 Sebastian Kuegler * CopyRight 2007 Maor Vanmak * Copyright 2008 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License version 2 as * published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "powermanagementengine.h" //solid specific includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "powermanagementservice.h" static const char SOLID_POWERMANAGEMENT_SERVICE[] = "org.kde.Solid.PowerManagement"; Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(InhibitionInfo) PowermanagementEngine::PowermanagementEngine(QObject* parent, const QVariantList& args) : Plasma::DataEngine(parent, args) , m_sources(basicSourceNames()) { Q_UNUSED(args) qDBusRegisterMetaType>(); qDBusRegisterMetaType(); init(); } PowermanagementEngine::~PowermanagementEngine() {} void PowermanagementEngine::init() { connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceAdded, this, &PowermanagementEngine::deviceAdded); connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceRemoved, this, &PowermanagementEngine::deviceRemoved); if (QDBusConnection::sessionBus().interface()->isServiceRegistered(SOLID_POWERMANAGEMENT_SERVICE)) { if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"), QStringLiteral("brightnessChanged"), this, SLOT(screenBrightnessChanged(int)))) { qDebug() << "error connecting to Brightness changes via dbus"; } if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"), QStringLiteral("brightnessMaxChanged"), this, SLOT(maximumScreenBrightnessChanged(int)))) { qDebug() << "error connecting to max brightness changes via dbus"; } if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl"), QStringLiteral("keyboardBrightnessChanged"), this, SLOT(keyboardBrightnessChanged(int)))) { qDebug() << "error connecting to Keyboard Brightness changes via dbus"; } if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl"), QStringLiteral("keyboardBrightnessMaxChanged"), this, SLOT(maximumKeyboardBrightnessChanged(int)))) { qDebug() << "error connecting to max keyboard Brightness changes via dbus"; } if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/HandleButtonEvents"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.HandleButtonEvents"), QStringLiteral("triggersLidActionChanged"), this, SLOT(triggersLidActionChanged(bool)))) { qDebug() << "error connecting to lid action trigger changes via dbus"; } if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/PolicyAgent"), QStringLiteral("org.kde.Solid.PowerManagement.PolicyAgent"), QStringLiteral("InhibitionsChanged"), this, SLOT(inhibitionsChanged(QList,QStringList)))) { qDebug() << "error connecting to inhibition changes via dbus"; } if (!QDBusConnection::sessionBus().connect(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement"), SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("batteryRemainingTimeChanged"), this, SLOT(batteryRemainingTimeChanged(qulonglong)))) { qDebug() << "error connecting to remaining time changes"; } } } QStringList PowermanagementEngine::basicSourceNames() const { QStringList sources; sources << QStringLiteral("Battery") << QStringLiteral("AC Adapter") << QStringLiteral("Sleep States") << QStringLiteral("PowerDevil") << QStringLiteral("Inhibitions"); return sources; } QStringList PowermanagementEngine::sources() const { return m_sources; } bool PowermanagementEngine::sourceRequestEvent(const QString &name) { if (name == QLatin1String("Battery")) { const QList listBattery = Solid::Device::listFromType(Solid::DeviceInterface::Battery); m_batterySources.clear(); if (listBattery.isEmpty()) { setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), false); setData(QStringLiteral("Battery"), QStringLiteral("Has Cumulative"), false); return true; } uint index = 0; QStringList batterySources; foreach (const Solid::Device &deviceBattery, listBattery) { const Solid::Battery* battery = deviceBattery.as(); const QString source = QStringLiteral("Battery%1").arg(index++); batterySources << source; m_batterySources[deviceBattery.udi()] = source; connect(battery, &Solid::Battery::chargeStateChanged, this, &PowermanagementEngine::updateBatteryChargeState); connect(battery, &Solid::Battery::chargePercentChanged, this, &PowermanagementEngine::updateBatteryChargePercent); connect(battery, &Solid::Battery::energyChanged, this, &PowermanagementEngine::updateBatteryEnergy); connect(battery, &Solid::Battery::presentStateChanged, this, &PowermanagementEngine::updateBatteryPresentState); // Set initial values updateBatteryChargeState(battery->chargeState(), deviceBattery.udi()); updateBatteryChargePercent(battery->chargePercent(), deviceBattery.udi()); updateBatteryEnergy(battery->energy(), deviceBattery.udi()); updateBatteryPresentState(battery->isPresent(), deviceBattery.udi()); updateBatteryPowerSupplyState(battery->isPowerSupply(), deviceBattery.udi()); setData(source, QStringLiteral("Vendor"), deviceBattery.vendor()); setData(source, QStringLiteral("Product"), deviceBattery.product()); setData(source, QStringLiteral("Capacity"), battery->capacity()); setData(source, QStringLiteral("Type"), batteryType(battery)); } updateBatteryNames(); updateOverallBattery(); setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), !batterySources.isEmpty()); if (!batterySources.isEmpty()) { setData(QStringLiteral("Battery"), QStringLiteral("Sources"), batterySources); QDBusMessage msg = QDBusMessage::createMethodCall(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement"), SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("batteryRemainingTime")); QDBusPendingReply reply = QDBusConnection::sessionBus().asyncCall(msg); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { batteryRemainingTimeChanged(reply.value()); } watcher->deleteLater(); }); } m_sources = basicSourceNames() + batterySources; } else if (name == QLatin1String("AC Adapter")) { connect(Solid::PowerManagement::notifier(), &Solid::PowerManagement::Notifier::appShouldConserveResourcesChanged, this, &PowermanagementEngine::updateAcPlugState); updateAcPlugState(Solid::PowerManagement::appShouldConserveResources()); } else if (name == QLatin1String("Sleep States")) { const QSet sleepstates = Solid::PowerManagement::supportedSleepStates(); setData(QStringLiteral("Sleep States"), QStringLiteral("Standby"), sleepstates.contains(Solid::PowerManagement::StandbyState)); setData(QStringLiteral("Sleep States"), QStringLiteral("Suspend"), sleepstates.contains(Solid::PowerManagement::SuspendState)); setData(QStringLiteral("Sleep States"), QStringLiteral("Hibernate"), sleepstates.contains(Solid::PowerManagement::HibernateState)); setData(QStringLiteral("Sleep States"), QStringLiteral("HybridSuspend"), sleepstates.contains(Solid::PowerManagement::HybridSuspendState)); setData(QStringLiteral("Sleep States"), QStringLiteral("LockScreen"), KAuthorized::authorizeAction(QStringLiteral("lock_screen"))); setData(QStringLiteral("Sleep States"), QStringLiteral("Logout"), KAuthorized::authorize(QStringLiteral("logout"))); } else if (name == QLatin1String("PowerDevil")) { QDBusMessage screenMsg = QDBusMessage::createMethodCall(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"), QStringLiteral("brightness")); QDBusPendingReply screenReply = QDBusConnection::sessionBus().asyncCall(screenMsg); QDBusPendingCallWatcher *screenWatcher = new QDBusPendingCallWatcher(screenReply, this); QObject::connect(screenWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { screenBrightnessChanged(reply.value()); } watcher->deleteLater(); }); QDBusMessage maxScreenMsg = QDBusMessage::createMethodCall(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"), QStringLiteral("brightnessMax")); QDBusPendingReply maxScreenReply = QDBusConnection::sessionBus().asyncCall(maxScreenMsg); QDBusPendingCallWatcher *maxScreenWatcher = new QDBusPendingCallWatcher(maxScreenReply, this); QObject::connect(maxScreenWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { maximumScreenBrightnessChanged(reply.value()); } watcher->deleteLater(); }); QDBusMessage keyboardMsg = QDBusMessage::createMethodCall(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl"), QStringLiteral("keyboardBrightness")); QDBusPendingReply keyboardReply = QDBusConnection::sessionBus().asyncCall(keyboardMsg); QDBusPendingCallWatcher *keyboardWatcher = new QDBusPendingCallWatcher(keyboardReply, this); QObject::connect(keyboardWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { keyboardBrightnessChanged(reply.value()); } watcher->deleteLater(); }); QDBusMessage maxKeyboardMsg = QDBusMessage::createMethodCall(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl"), QStringLiteral("keyboardBrightnessMax")); QDBusPendingReply maxKeyboardReply = QDBusConnection::sessionBus().asyncCall(maxKeyboardMsg); QDBusPendingCallWatcher *maxKeyboardWatcher = new QDBusPendingCallWatcher(maxKeyboardReply, this); QObject::connect(maxKeyboardWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { maximumKeyboardBrightnessChanged(reply.value()); } watcher->deleteLater(); }); QDBusMessage lidIsPresentMsg = QDBusMessage::createMethodCall(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement"), SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("isLidPresent")); QDBusPendingReply lidIsPresentReply = QDBusConnection::sessionBus().asyncCall(lidIsPresentMsg); QDBusPendingCallWatcher *lidIsPresentWatcher = new QDBusPendingCallWatcher(lidIsPresentReply, this); QObject::connect(lidIsPresentWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { setData(QStringLiteral("PowerDevil"), QStringLiteral("Is Lid Present"), reply.value()); } watcher->deleteLater(); }); QDBusMessage triggersLidActionMsg = QDBusMessage::createMethodCall(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/Actions/HandleButtonEvents"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.HandleButtonEvents"), QStringLiteral("triggersLidAction")); QDBusPendingReply triggersLidActionReply = QDBusConnection::sessionBus().asyncCall(triggersLidActionMsg); QDBusPendingCallWatcher *triggersLidActionWatcher = new QDBusPendingCallWatcher(triggersLidActionReply, this); QObject::connect(triggersLidActionWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { triggersLidActionChanged(reply.value()); } watcher->deleteLater(); }); } else if (name == QLatin1Literal("Inhibitions")) { QDBusMessage inhibitionsMsg = QDBusMessage::createMethodCall(SOLID_POWERMANAGEMENT_SERVICE, QStringLiteral("/org/kde/Solid/PowerManagement/PolicyAgent"), QStringLiteral("org.kde.Solid.PowerManagement.PolicyAgent"), QStringLiteral("ListInhibitions")); QDBusPendingReply> inhibitionsReply = QDBusConnection::sessionBus().asyncCall(inhibitionsMsg); QDBusPendingCallWatcher *inhibitionsWatcher = new QDBusPendingCallWatcher(inhibitionsReply, this); QObject::connect(inhibitionsWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { QDBusPendingReply> reply = *watcher; watcher->deleteLater(); if (!reply.isError()) { removeAllData(QStringLiteral("Inhibitions")); inhibitionsChanged(reply.value(), QStringList()); } }); //any info concerning lock screen/screensaver goes here } else if (name == QLatin1String("UserActivity")) { setData(QStringLiteral("UserActivity"), QStringLiteral("IdleTime"), KIdleTime::instance()->idleTime()); } else { qDebug() << "Data for '" << name << "' not found"; return false; } return true; } QString PowermanagementEngine::batteryType(const Solid::Battery* battery) const { switch(battery->type()) { case Solid::Battery::PrimaryBattery: return QStringLiteral("Battery"); break; case Solid::Battery::UpsBattery: return QStringLiteral("Ups"); break; case Solid::Battery::MonitorBattery: return QStringLiteral("Monitor"); break; case Solid::Battery::MouseBattery: return QStringLiteral("Mouse"); break; case Solid::Battery::KeyboardBattery: return QStringLiteral("Keyboard"); break; case Solid::Battery::PdaBattery: return QStringLiteral("Pda"); break; case Solid::Battery::PhoneBattery: return QStringLiteral("Phone"); break; case Solid::Battery::GamingInputBattery: return QStringLiteral("GamingInput"); break; + case Solid::Battery::BluetoothBattery: + return QStringLiteral("Bluetooth"); + break; default: return QStringLiteral("Unknown"); } return QStringLiteral("Unknown"); } bool PowermanagementEngine::updateSourceEvent(const QString &source) { if (source == QLatin1String("UserActivity")) { setData(QStringLiteral("UserActivity"), QStringLiteral("IdleTime"), KIdleTime::instance()->idleTime()); return true; } return Plasma::DataEngine::updateSourceEvent(source); } Plasma::Service* PowermanagementEngine::serviceForSource(const QString &source) { if (source == QLatin1String("PowerDevil")) { return new PowerManagementService(this); } return nullptr; } QString PowermanagementEngine::batteryStateToString(int newState) const { QString state(QStringLiteral("Unknown")); if (newState == Solid::Battery::NoCharge) { state = QLatin1String("NoCharge"); } else if (newState == Solid::Battery::Charging) { state = QLatin1String("Charging"); } else if (newState == Solid::Battery::Discharging) { state = QLatin1String("Discharging"); } else if (newState == Solid::Battery::FullyCharged) { state = QLatin1String("FullyCharged"); } return state; } void PowermanagementEngine::updateBatteryChargeState(int newState, const QString& udi) { const QString source = m_batterySources[udi]; setData(source, QStringLiteral("State"), batteryStateToString(newState)); updateOverallBattery(); } void PowermanagementEngine::updateBatteryPresentState(bool newState, const QString& udi) { const QString source = m_batterySources[udi]; setData(source, QStringLiteral("Plugged in"), newState); // FIXME This needs to be renamed and Battery Monitor adjusted } void PowermanagementEngine::updateBatteryChargePercent(int newValue, const QString& udi) { const QString source = m_batterySources[udi]; setData(source, QStringLiteral("Percent"), newValue); updateOverallBattery(); } void PowermanagementEngine::updateBatteryEnergy(double newValue, const QString &udi) { const QString source = m_batterySources[udi]; setData(source, QStringLiteral("Energy"), newValue); } void PowermanagementEngine::updateBatteryPowerSupplyState(bool newState, const QString& udi) { const QString source = m_batterySources[udi]; setData(source, QStringLiteral("Is Power Supply"), newState); } void PowermanagementEngine::updateBatteryNames() { uint unnamedBatteries = 0; foreach (QString source, m_batterySources) { DataContainer *batteryDataContainer = containerForSource(source); if (batteryDataContainer) { const QString batteryVendor = batteryDataContainer->data()[QStringLiteral("Vendor")].toString(); const QString batteryProduct = batteryDataContainer->data()[QStringLiteral("Product")].toString(); // Don't show battery name for primary power supply batteries. They usually have cryptic serial number names. const bool showBatteryName = batteryDataContainer->data()[QStringLiteral("Type")].toString() != QLatin1String("Battery") || !batteryDataContainer->data()[QStringLiteral("Is Power Supply")].toBool(); if (!batteryProduct.isEmpty() && batteryProduct != QLatin1String("Unknown Battery") && showBatteryName) { if (!batteryVendor.isEmpty()) { setData(source, QStringLiteral("Pretty Name"), QString(batteryVendor + ' ' + batteryProduct)); } else { setData(source, QStringLiteral("Pretty Name"), batteryProduct); } } else { ++unnamedBatteries; if (unnamedBatteries > 1) { setData(source, QStringLiteral("Pretty Name"), i18nc("Placeholder is the battery number", "Battery %1", unnamedBatteries)); } else { setData(source, QStringLiteral("Pretty Name"), i18n("Battery")); } } } } } void PowermanagementEngine::updateOverallBattery() { const QList listBattery = Solid::Device::listFromType(Solid::DeviceInterface::Battery); bool hasCumulative = false; double energy = 0; double totalEnergy = 0; bool allFullyCharged = true; bool charging = false; bool noCharge = false; double totalPercentage = 0; int count = 0; foreach (const Solid::Device &deviceBattery, listBattery) { const Solid::Battery* battery = deviceBattery.as(); if (battery && battery->isPowerSupply()) { hasCumulative = true; energy += battery->energy(); totalEnergy += battery->energyFull(); totalPercentage += battery->chargePercent(); allFullyCharged = allFullyCharged && (battery->chargeState() == Solid::Battery::FullyCharged); charging = charging || (battery->chargeState() == Solid::Battery::Charging); noCharge = noCharge || (battery->chargeState() == Solid::Battery::NoCharge); ++count; } } if (count == 1) { // Energy is sometimes way off causing us to show rubbish; this is a UPower issue // but anyway having just one battery and the tooltip showing strange readings // compared to the popup doesn't look polished. setData(QStringLiteral("Battery"), QStringLiteral("Percent"), totalPercentage); } else if (totalEnergy > 0) { setData(QStringLiteral("Battery"), QStringLiteral("Percent"), qRound(energy / totalEnergy * 100)); } else if (count > 0) { // UPS don't have energy, see Bug 348588 setData(QStringLiteral("Battery"), QStringLiteral("Percent"), qRound(totalPercentage / static_cast(count))); } else { setData(QStringLiteral("Battery"), QStringLiteral("Percent"), 0); } if (hasCumulative) { if (allFullyCharged) { setData(QStringLiteral("Battery"), QStringLiteral("State"), "FullyCharged"); } else if (charging) { setData(QStringLiteral("Battery"), QStringLiteral("State"), "Charging"); } else if (noCharge) { setData(QStringLiteral("Battery"), QStringLiteral("State"), "NoCharge"); } else { setData(QStringLiteral("Battery"), QStringLiteral("State"), "Discharging"); } } else { setData(QStringLiteral("Battery"), QStringLiteral("State"), "Unknown"); } setData(QStringLiteral("Battery"), QStringLiteral("Has Cumulative"), hasCumulative); } void PowermanagementEngine::updateAcPlugState(bool onBattery) { setData(QStringLiteral("AC Adapter"), QStringLiteral("Plugged in"), !onBattery); } void PowermanagementEngine::deviceRemoved(const QString& udi) { if (m_batterySources.contains(udi)) { Solid::Device device(udi); Solid::Battery* battery = device.as(); if (battery) battery->disconnect(); const QString source = m_batterySources[udi]; m_batterySources.remove(udi); removeSource(source); QStringList sourceNames(m_batterySources.values()); sourceNames.removeAll(source); setData(QStringLiteral("Battery"), QStringLiteral("Sources"), sourceNames); setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), !sourceNames.isEmpty()); updateOverallBattery(); } } void PowermanagementEngine::deviceAdded(const QString& udi) { Solid::Device device(udi); if (device.isValid()) { const Solid::Battery* battery = device.as(); if (battery) { int index = 0; QStringList sourceNames(m_batterySources.values()); while (sourceNames.contains(QStringLiteral("Battery%1").arg(index))) { index++; } const QString source = QStringLiteral("Battery%1").arg(index); sourceNames << source; m_batterySources[device.udi()] = source; connect(battery, &Solid::Battery::chargeStateChanged, this, &PowermanagementEngine::updateBatteryChargeState); connect(battery, &Solid::Battery::chargePercentChanged, this, &PowermanagementEngine::updateBatteryChargePercent); connect(battery, &Solid::Battery::energyChanged, this, &PowermanagementEngine::updateBatteryEnergy); connect(battery, &Solid::Battery::presentStateChanged, this, &PowermanagementEngine::updateBatteryPresentState); connect(battery, &Solid::Battery::powerSupplyStateChanged, this, &PowermanagementEngine::updateBatteryPowerSupplyState); // Set initial values updateBatteryChargeState(battery->chargeState(), device.udi()); updateBatteryChargePercent(battery->chargePercent(), device.udi()); updateBatteryEnergy(battery->energy(), device.udi()); updateBatteryPresentState(battery->isPresent(), device.udi()); updateBatteryPowerSupplyState(battery->isPowerSupply(), device.udi()); setData(source, QStringLiteral("Vendor"), device.vendor()); setData(source, QStringLiteral("Product"), device.product()); setData(source, QStringLiteral("Capacity"), battery->capacity()); setData(source, QStringLiteral("Type"), batteryType(battery)); setData(QStringLiteral("Battery"), QStringLiteral("Sources"), sourceNames); setData(QStringLiteral("Battery"), QStringLiteral("Has Battery"), !sourceNames.isEmpty()); updateBatteryNames(); updateOverallBattery(); } } } void PowermanagementEngine::batteryRemainingTimeChanged(qulonglong time) { //qDebug() << "Remaining time 2:" << time; setData(QStringLiteral("Battery"), QStringLiteral("Remaining msec"), time); } void PowermanagementEngine::screenBrightnessChanged(int brightness) { setData(QStringLiteral("PowerDevil"), QStringLiteral("Screen Brightness"), brightness); } void PowermanagementEngine::maximumScreenBrightnessChanged(int maximumBrightness) { setData(QStringLiteral("PowerDevil"), QStringLiteral("Maximum Screen Brightness"), maximumBrightness); setData(QStringLiteral("PowerDevil"), QStringLiteral("Screen Brightness Available"), maximumBrightness > 0); } void PowermanagementEngine::keyboardBrightnessChanged(int brightness) { setData(QStringLiteral("PowerDevil"), QStringLiteral("Keyboard Brightness"), brightness); } void PowermanagementEngine::maximumKeyboardBrightnessChanged(int maximumBrightness) { setData(QStringLiteral("PowerDevil"), QStringLiteral("Maximum Keyboard Brightness"), maximumBrightness); setData(QStringLiteral("PowerDevil"), QStringLiteral("Keyboard Brightness Available"), maximumBrightness > 0); } void PowermanagementEngine::triggersLidActionChanged(bool triggers) { setData(QStringLiteral("PowerDevil"), QStringLiteral("Triggers Lid Action"), triggers); } void PowermanagementEngine::inhibitionsChanged(const QList &added, const QStringList &removed) { for (auto it = removed.constBegin(); it != removed.constEnd(); ++it) { removeData(QStringLiteral("Inhibitions"), (*it)); } for (auto it = added.constBegin(); it != added.constEnd(); ++it) { const QString &name = (*it).first; QString prettyName; QString icon; const QString &reason = (*it).second; populateApplicationData(name, &prettyName, &icon); setData(QStringLiteral("Inhibitions"), name, QVariantMap{ {QStringLiteral("Name"), prettyName}, {QStringLiteral("Icon"), icon}, {QStringLiteral("Reason"), reason} }); } } void PowermanagementEngine::populateApplicationData(const QString &name, QString *prettyName, QString *icon) { if (m_applicationInfo.contains(name)) { const auto &info = m_applicationInfo.value(name); *prettyName = info.first; *icon = info.second; } else { KService::Ptr service = KService::serviceByStorageId(name + ".desktop"); if (service) { *prettyName = service->property(QStringLiteral("Name"), QVariant::Invalid).toString(); // cannot be null *icon = service->icon(); m_applicationInfo.insert(name, qMakePair(*prettyName, *icon)); } else { *prettyName = name; *icon = name.section(QLatin1Char('/'), -1).toLower(); } } } K_EXPORT_PLASMA_DATAENGINE_WITH_JSON(powermanagement, PowermanagementEngine, "plasma-dataengine-powermanagement.json") #include "powermanagementengine.moc" diff --git a/dataengines/soliddevice/soliddeviceengine.cpp b/dataengines/soliddevice/soliddeviceengine.cpp index 8ec273822..be7f1acf2 100644 --- a/dataengines/soliddevice/soliddeviceengine.cpp +++ b/dataengines/soliddevice/soliddeviceengine.cpp @@ -1,711 +1,711 @@ /* * Copyright (C) 2007 Christopher Blauvelt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License version 2 as * published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "soliddeviceengine.h" #include "soliddeviceservice.h" #include #include #include #include #include #include #include #include #include #include //TODO: implement in libsolid2 namespace { template DevIface *getAncestorAs(const Solid::Device &device) { for (Solid::Device parent = device.parent(); parent.isValid(); parent = parent.parent()) { if (parent.is()) { return parent.as(); } } return nullptr; } } SolidDeviceEngine::SolidDeviceEngine(QObject* parent, const QVariantList& args) : Plasma::DataEngine(parent, args), m_temperature(nullptr), m_notifier(nullptr) { Q_UNUSED(args) m_signalmanager = new DeviceSignalMapManager(this); listenForNewDevices(); setMinimumPollingInterval(1000); connect(this, &Plasma::DataEngine::sourceRemoved, this, &SolidDeviceEngine::sourceWasRemoved); } SolidDeviceEngine::~SolidDeviceEngine() { } Plasma::Service* SolidDeviceEngine::serviceForSource(const QString& source) { return new SolidDeviceService (this, source); } void SolidDeviceEngine::listenForNewDevices() { if (m_notifier) { return; } //detect when new devices are added m_notifier = Solid::DeviceNotifier::instance(); connect(m_notifier, &Solid::DeviceNotifier::deviceAdded, this, &SolidDeviceEngine::deviceAdded); connect(m_notifier, &Solid::DeviceNotifier::deviceRemoved, this, &SolidDeviceEngine::deviceRemoved); } bool SolidDeviceEngine::sourceRequestEvent(const QString &name) { if (name.startsWith('/')) { Solid::Device device = Solid::Device(name); if (device.isValid()) { if (m_devicemap.contains(name) ) { return true; } else { m_devicemap[name] = device; return populateDeviceData(name); } } } else { Solid::Predicate predicate = Solid::Predicate::fromString(name); if (predicate.isValid() && !m_predicatemap.contains(name)) { foreach (const Solid::Device &device, Solid::Device::listFromQuery(predicate)) { m_predicatemap[name] << device.udi(); } setData(name, m_predicatemap[name]); return true; } } qDebug() << "Source is not a predicate or a device."; return false; } void SolidDeviceEngine::sourceWasRemoved(const QString &source) { m_devicemap.remove(source); m_predicatemap.remove(source); } bool SolidDeviceEngine::populateDeviceData(const QString &name) { Solid::Device device = m_devicemap.value(name); if (!device.isValid()) { return false; } QStringList devicetypes; setData(name, I18N_NOOP("Parent UDI"), device.parentUdi()); setData(name, I18N_NOOP("Vendor"), device.vendor()); setData(name, I18N_NOOP("Product"), device.product()); setData(name, I18N_NOOP("Description"), device.description()); setData(name, I18N_NOOP("Icon"), device.icon()); setData(name, I18N_NOOP("Emblems"), device.emblems()); setData(name, I18N_NOOP("State"), Idle); setData(name, I18N_NOOP("Operation result"), Working); setData(name, I18N_NOOP("Timestamp"), QDateTime::currentDateTimeUtc()); if (device.is()) { Solid::Processor *processor = device.as(); if (!processor) { return false; } devicetypes << I18N_NOOP("Processor"); setData(name, I18N_NOOP("Number"), processor->number()); setData(name, I18N_NOOP("Max Speed"), processor->maxSpeed()); setData(name, I18N_NOOP("Can Change Frequency"), processor->canChangeFrequency()); } if (device.is()) { Solid::Block *block = device.as(); if (!block) { return false; } devicetypes << I18N_NOOP("Block"); setData(name, I18N_NOOP("Major"), block->deviceMajor()); setData(name, I18N_NOOP("Minor"), block->deviceMinor()); setData(name, I18N_NOOP("Device"), block->device()); } if (device.is()) { Solid::StorageAccess *storageaccess = device.as(); if (!storageaccess) { return false; } devicetypes << I18N_NOOP("Storage Access"); setData(name, I18N_NOOP("Accessible"), storageaccess->isAccessible()); setData(name, I18N_NOOP("File Path"), storageaccess->filePath()); if (storageaccess->isAccessible()) { updateStorageSpace(name); } m_signalmanager->mapDevice(storageaccess, device.udi()); } if (device.is()) { Solid::StorageDrive *storagedrive = device.as(); if (!storagedrive) { return false; } devicetypes << I18N_NOOP("Storage Drive"); QStringList bus; bus << I18N_NOOP("Ide") << I18N_NOOP("Usb") << I18N_NOOP("Ieee1394") << I18N_NOOP("Scsi") << I18N_NOOP("Sata") << I18N_NOOP("Platform"); QStringList drivetype; drivetype << I18N_NOOP("Hard Disk") << I18N_NOOP("Cdrom Drive") << I18N_NOOP("Floppy") << I18N_NOOP("Tape") << I18N_NOOP("Compact Flash") << I18N_NOOP("Memory Stick") << I18N_NOOP("Smart Media") << I18N_NOOP("SdMmc") << I18N_NOOP("Xd"); setData(name, I18N_NOOP("Bus"), bus.at((int)storagedrive->bus())); setData(name, I18N_NOOP("Drive Type"), drivetype.at((int)storagedrive->driveType())); setData(name, I18N_NOOP("Removable"), storagedrive->isRemovable()); setData(name, I18N_NOOP("Hotpluggable"), storagedrive->isHotpluggable()); updateHardDiskTemperature(name); } else { bool isRemovable = false; bool isHotpluggable = false; Solid::StorageDrive *drive = getAncestorAs(device); if (drive) { //remove check for isHotpluggable() when plasmoids are changed to check for both properties isRemovable = (drive->isRemovable() || drive->isHotpluggable()); isHotpluggable = drive->isHotpluggable(); } setData(name, I18N_NOOP("Removable"), isRemovable); setData(name, I18N_NOOP("Hotpluggable"), isHotpluggable); } if (device.is()) { Solid::OpticalDrive *opticaldrive = device.as(); if (!opticaldrive) { return false; } devicetypes << I18N_NOOP("Optical Drive"); QStringList supportedtypes; Solid::OpticalDrive::MediumTypes mediatypes = opticaldrive->supportedMedia(); if (mediatypes & Solid::OpticalDrive::Cdr) { supportedtypes << I18N_NOOP("CD-R"); } if (mediatypes & Solid::OpticalDrive::Cdrw) { supportedtypes << I18N_NOOP("CD-RW"); } if (mediatypes & Solid::OpticalDrive::Dvd) { supportedtypes << I18N_NOOP("DVD"); } if (mediatypes & Solid::OpticalDrive::Dvdr) { supportedtypes << I18N_NOOP("DVD-R"); } if (mediatypes & Solid::OpticalDrive::Dvdrw) { supportedtypes << I18N_NOOP("DVD-RW"); } if (mediatypes & Solid::OpticalDrive::Dvdram) { supportedtypes << I18N_NOOP("DVD-RAM"); } if (mediatypes & Solid::OpticalDrive::Dvdplusr) { supportedtypes << I18N_NOOP("DVD+R"); } if (mediatypes & Solid::OpticalDrive::Dvdplusrw) { supportedtypes << I18N_NOOP("DVD+RW"); } if (mediatypes & Solid::OpticalDrive::Dvdplusdl) { supportedtypes << I18N_NOOP("DVD+DL"); } if (mediatypes & Solid::OpticalDrive::Dvdplusdlrw) { supportedtypes << I18N_NOOP("DVD+DLRW"); } if (mediatypes & Solid::OpticalDrive::Bd) { supportedtypes << I18N_NOOP("BD"); } if (mediatypes & Solid::OpticalDrive::Bdr) { supportedtypes << I18N_NOOP("BD-R"); } if (mediatypes & Solid::OpticalDrive::Bdre) { supportedtypes << I18N_NOOP("BD-RE"); } if (mediatypes & Solid::OpticalDrive::HdDvd) { supportedtypes << I18N_NOOP("HDDVD"); } if (mediatypes & Solid::OpticalDrive::HdDvdr) { supportedtypes << I18N_NOOP("HDDVD-R"); } if (mediatypes & Solid::OpticalDrive::HdDvdrw) { supportedtypes << I18N_NOOP("HDDVD-RW"); } setData(name, I18N_NOOP("Supported Media"), supportedtypes); setData(name, I18N_NOOP("Read Speed"), opticaldrive->readSpeed()); setData(name, I18N_NOOP("Write Speed"), opticaldrive->writeSpeed()); //the following method return QList so we need to convert it to QList const QList writespeeds = opticaldrive->writeSpeeds(); QList variantlist; foreach(int num, writespeeds) { variantlist << num; } setData(name, I18N_NOOP("Write Speeds"), variantlist); } if (device.is()) { Solid::StorageVolume *storagevolume = device.as(); if (!storagevolume) { return false; } devicetypes << I18N_NOOP("Storage Volume"); QStringList usagetypes; usagetypes << i18n("Other") << i18n("Unused") << i18n("File System") << i18n("Partition Table") << i18n("Raid") << i18n("Encrypted"); if (usagetypes.count() > storagevolume->usage()) { setData(name, I18N_NOOP("Usage"), usagetypes.at((int)storagevolume->usage())); } else { setData(name, I18N_NOOP("Usage"), i18n("Unknown")); } setData(name, I18N_NOOP("Ignored"), storagevolume->isIgnored()); setData(name, I18N_NOOP("File System Type"), storagevolume->fsType()); setData(name, I18N_NOOP("Label"), storagevolume->label()); setData(name, I18N_NOOP("UUID"), storagevolume->uuid()); updateInUse(name); //Check if the volume is part of an encrypted container //This needs to trigger an update for the encrypted container volume since //libsolid cannot notify us when the accessibility of the container changes Solid::Device encryptedContainer = storagevolume->encryptedContainer(); if (encryptedContainer.isValid()) { const QString containerUdi = encryptedContainer.udi(); setData(name, I18N_NOOP("Encrypted Container"), containerUdi); m_encryptedContainerMap[name] = containerUdi; //TODO: compress the calls? forceUpdateAccessibility(containerUdi); } } if (device.is()) { Solid::OpticalDisc *opticaldisc = device.as(); if (!opticaldisc) { return false; } devicetypes << I18N_NOOP("OpticalDisc"); //get the content types QStringList contenttypelist; const Solid::OpticalDisc::ContentTypes contenttypes = opticaldisc->availableContent(); if (contenttypes.testFlag(Solid::OpticalDisc::Audio)) { contenttypelist << I18N_NOOP("Audio"); } if (contenttypes.testFlag(Solid::OpticalDisc::Data)) { contenttypelist << I18N_NOOP("Data"); } if (contenttypes.testFlag(Solid::OpticalDisc::VideoCd)) { contenttypelist << I18N_NOOP("Video CD"); } if (contenttypes.testFlag(Solid::OpticalDisc::SuperVideoCd)) { contenttypelist << I18N_NOOP("Super Video CD"); } if (contenttypes.testFlag(Solid::OpticalDisc::VideoDvd)) { contenttypelist << I18N_NOOP("Video DVD"); } if (contenttypes.testFlag(Solid::OpticalDisc::VideoBluRay)) { contenttypelist << I18N_NOOP("Video Blu Ray"); } setData(name, I18N_NOOP("Available Content"), contenttypelist); QStringList disctypes; disctypes << I18N_NOOP("Unknown Disc Type") << I18N_NOOP("CD Rom") << I18N_NOOP("CD Recordable") << I18N_NOOP("CD Rewritable") << I18N_NOOP("DVD Rom") << I18N_NOOP("DVD Ram") << I18N_NOOP("DVD Recordable") << I18N_NOOP("DVD Rewritable") << I18N_NOOP("DVD Plus Recordable") << I18N_NOOP("DVD Plus Rewritable") << I18N_NOOP("DVD Plus Recordable Duallayer") << I18N_NOOP("DVD Plus Rewritable Duallayer") << I18N_NOOP("Blu Ray Rom") << I18N_NOOP("Blu Ray Recordable") << I18N_NOOP("Blu Ray Rewritable") << I18N_NOOP("HD DVD Rom") << I18N_NOOP("HD DVD Recordable") << I18N_NOOP("HD DVD Rewritable"); //+1 because the enum starts at -1 setData(name, I18N_NOOP("Disc Type"), disctypes.at((int)opticaldisc->discType() + 1)); setData(name, I18N_NOOP("Appendable"), opticaldisc->isAppendable()); setData(name, I18N_NOOP("Blank"), opticaldisc->isBlank()); setData(name, I18N_NOOP("Rewritable"), opticaldisc->isRewritable()); setData(name, I18N_NOOP("Capacity"), opticaldisc->capacity()); } if (device.is()) { Solid::Camera *camera = device.as(); if (!camera) { return false; } devicetypes << I18N_NOOP("Camera"); setData(name, I18N_NOOP("Supported Protocols"), camera->supportedProtocols()); setData(name, I18N_NOOP("Supported Drivers"), camera->supportedDrivers()); // Cameras are necessarily Removable and Hotpluggable setData(name, I18N_NOOP("Removable"), true); setData(name, I18N_NOOP("Hotpluggable"), true); } if (device.is()) { Solid::PortableMediaPlayer *mediaplayer = device.as(); if (!mediaplayer) { return false; } devicetypes << I18N_NOOP("Portable Media Player"); setData(name, I18N_NOOP("Supported Protocols"), mediaplayer->supportedProtocols()); setData(name, I18N_NOOP("Supported Drivers"), mediaplayer->supportedDrivers()); // Portable Media Players are necessarily Removable and Hotpluggable setData(name, I18N_NOOP("Removable"), true); setData(name, I18N_NOOP("Hotpluggable"), true); } if (device.is()) { Solid::Battery *battery = device.as(); if (!battery) { return false; } devicetypes << I18N_NOOP("Battery"); QStringList batterytype; batterytype << I18N_NOOP("Unknown Battery") << I18N_NOOP("PDA Battery") << I18N_NOOP("UPS Battery") << I18N_NOOP("Primary Battery") << I18N_NOOP("Mouse Battery") << I18N_NOOP("Keyboard Battery") << I18N_NOOP("Keyboard Mouse Battery") << I18N_NOOP("Camera Battery") << I18N_NOOP("Phone Battery") - << I18N_NOOP("Monitor Battery") << I18N_NOOP("Gaming Input Battery"); + << I18N_NOOP("Monitor Battery") << I18N_NOOP("Gaming Input Battery") << I18N_NOOP("Bluetooth Battery"); QStringList chargestate; chargestate << I18N_NOOP("Not Charging") << I18N_NOOP("Charging") << I18N_NOOP("Discharging") << I18N_NOOP("Fully Charged"); setData(name, I18N_NOOP("Plugged In"), battery->isPresent()); // FIXME Rename when interested parties are adjusted setData(name, I18N_NOOP("Type"), batterytype.value((int)battery->type())); setData(name, I18N_NOOP("Charge Percent"), battery->chargePercent()); setData(name, I18N_NOOP("Rechargeable"), battery->isRechargeable()); setData(name, I18N_NOOP("Charge State"), chargestate.at((int)battery->chargeState())); m_signalmanager->mapDevice(battery, device.udi()); } using namespace Solid; // we cannot just iterate the enum in reverse order since Battery comes second to last // and then our phone which also has a battery gets treated as battery :( static const Solid::DeviceInterface::Type typeOrder[] = { Solid::DeviceInterface::PortableMediaPlayer, Solid::DeviceInterface::Camera, Solid::DeviceInterface::OpticalDisc, Solid::DeviceInterface::StorageVolume, Solid::DeviceInterface::OpticalDrive, Solid::DeviceInterface::StorageDrive, Solid::DeviceInterface::NetworkShare, Solid::DeviceInterface::StorageAccess, Solid::DeviceInterface::Block, Solid::DeviceInterface::Battery, Solid::DeviceInterface::Processor }; for (int i = 0; i < 11; ++i) { const Solid::DeviceInterface *interface = device.asDeviceInterface(typeOrder[i]); if (interface) { setData(name, I18N_NOOP("Type Description"), Solid::DeviceInterface::typeDescription(typeOrder[i])); break; } } setData(name, I18N_NOOP("Device Types"), devicetypes); return true; } void SolidDeviceEngine::deviceAdded(const QString& udi) { Solid::Device device(udi); foreach (const QString &query, m_predicatemap.keys()) { Solid::Predicate predicate = Solid::Predicate::fromString(query); if (predicate.matches(device)) { m_predicatemap[query] << udi; setData(query, m_predicatemap[query]); } } if (device.is()) { Solid::OpticalDrive *drive = getAncestorAs(device); if (drive) { connect(drive, &Solid::OpticalDrive::ejectRequested, this, &SolidDeviceEngine::setUnmountingState); connect(drive, &Solid::OpticalDrive::ejectDone, this, &SolidDeviceEngine::setIdleState); } } else if (device.is()) { // update the volume in case of 2-stage devices if (m_devicemap.contains(udi) && containerForSource(udi)->data().value(I18N_NOOP("Size")).toULongLong() == 0) { Solid::GenericInterface * iface = device.as(); if (iface) { iface->setProperty("udi", udi); connect(iface, SIGNAL(propertyChanged(QMap)), this, SLOT(deviceChanged(QMap))); } } Solid::StorageAccess *access = device.as(); if (access) { connect(access, &Solid::StorageAccess::setupRequested, this, &SolidDeviceEngine::setMountingState); connect(access, &Solid::StorageAccess::setupDone, this, &SolidDeviceEngine::setIdleState); connect(access, &Solid::StorageAccess::teardownRequested, this, &SolidDeviceEngine::setUnmountingState); connect(access, &Solid::StorageAccess::teardownDone, this, &SolidDeviceEngine::setIdleState); } } } void SolidDeviceEngine::setMountingState(const QString &udi) { setData(udi, I18N_NOOP("State"), Mounting); setData(udi, I18N_NOOP("Operation result"), Working); } void SolidDeviceEngine::setUnmountingState(const QString &udi) { setData(udi, I18N_NOOP("State"), Unmounting); setData(udi, I18N_NOOP("Operation result"), Working); } void SolidDeviceEngine::setIdleState(Solid::ErrorType error, QVariant errorData, const QString &udi) { Q_UNUSED(errorData) if (error == Solid::NoError) { setData(udi, I18N_NOOP("Operation result"), Successful); } else { setData(udi, I18N_NOOP("Operation result"), Unsuccessful); } setData(udi, I18N_NOOP("State"), Idle); Solid::Device device = m_devicemap.value(udi); if (!device.isValid()) { return; } Solid::StorageAccess *storageaccess = device.as(); if (!storageaccess) { return; } setData(udi, I18N_NOOP("Accessible"), storageaccess->isAccessible()); setData(udi, I18N_NOOP("File Path"), storageaccess->filePath()); } void SolidDeviceEngine::deviceChanged(const QMap &props) { Solid::GenericInterface * iface = qobject_cast(sender()); if (iface && iface->isValid() && props.contains(QStringLiteral("Size")) && iface->property(QStringLiteral("Size")).toInt() > 0) { const QString udi = qobject_cast(iface)->property("udi").toString(); if (populateDeviceData(udi)) forceImmediateUpdateOfAllVisualizations(); } } bool SolidDeviceEngine::updateStorageSpace(const QString &udi) { Solid::Device device = m_devicemap.value(udi); Solid::StorageAccess *storageaccess = device.as(); if (!storageaccess || !storageaccess->isAccessible()) { return false; } QString path = storageaccess->filePath(); if (!m_paths.contains(path)) { QTimer *timer = new QTimer(this); timer->setSingleShot(true); connect(timer, &QTimer::timeout, [path]() { KNotification::event(KNotification::Error, i18n("Filesystem is not responding"), i18n("Filesystem mounted at '%1' is not responding", path)); }); m_paths.insert(path); // create job KIO::FileSystemFreeSpaceJob *job = KIO::fileSystemFreeSpace(QUrl::fromLocalFile(path)); // delete later timer connect(job, &KIO::FileSystemFreeSpaceJob::result, timer, &QTimer::deleteLater); // collect and process info connect(job, &KIO::FileSystemFreeSpaceJob::result, this, [this, timer, path, udi](KIO::Job *job, KIO::filesize_t size, KIO::filesize_t available) { timer->stop(); if (!job->error()) { setData(udi, I18N_NOOP("Free Space"), QVariant(available)); setData(udi, I18N_NOOP("Free Space Text"), KFormat().formatByteSize(available)); setData(udi, I18N_NOOP("Size"), QVariant(size)); } m_paths.remove(path); }); // start timer: after 15 seconds we will get an error timer->start(15000); } return false; } bool SolidDeviceEngine::updateHardDiskTemperature(const QString &udi) { Solid::Device device = m_devicemap.value(udi); Solid::Block *block = device.as(); if (!block) { return false; } if (!m_temperature) { m_temperature = new HddTemp(this); } if (m_temperature->sources().contains(block->device())) { setData(udi, I18N_NOOP("Temperature"), m_temperature->data(block->device(), HddTemp::Temperature)); setData(udi, I18N_NOOP("Temperature Unit"), m_temperature->data(block->device(), HddTemp::Unit)); return true; } return false; } bool SolidDeviceEngine::updateEmblems(const QString &udi) { Solid::Device device = m_devicemap.value(udi); setData(udi, I18N_NOOP("Emblems"), device.emblems() ); return true; } bool SolidDeviceEngine::forceUpdateAccessibility(const QString &udi) { Solid::Device device = m_devicemap.value(udi); if (!device.isValid()) { return false; } updateEmblems(udi); Solid::StorageAccess *storageaccess = device.as(); if (storageaccess) { setData(udi, I18N_NOOP("Accessible"), storageaccess->isAccessible()); } return true; } bool SolidDeviceEngine::updateInUse(const QString &udi) { Solid::Device device = m_devicemap.value(udi); if (!device.isValid()) { return false; } Solid::StorageAccess *storageaccess = device.as(); if (!storageaccess) { return false; } if (storageaccess->isAccessible()) { setData(udi, I18N_NOOP("In Use"), true); } else { Solid::StorageDrive *drive = getAncestorAs(Solid::Device(udi)); if (drive) { setData(udi, I18N_NOOP("In Use"), drive->isInUse()); } } return true; } bool SolidDeviceEngine::updateSourceEvent(const QString& source) { bool update1 = updateStorageSpace(source); bool update2 = updateHardDiskTemperature(source); bool update3 = updateEmblems(source); bool update4 = updateInUse(source); return (update1 || update2 || update3 || update4); } void SolidDeviceEngine::deviceRemoved(const QString& udi) { //libsolid cannot notify us when an encrypted container is closed, //hence we trigger an update when a device contained in an encrypted container device dies const QString containerUdi = m_encryptedContainerMap.value(udi, QString()); if (!containerUdi.isEmpty()) { forceUpdateAccessibility(containerUdi); m_encryptedContainerMap.remove(udi); } foreach (const QString &query, m_predicatemap.keys()) { m_predicatemap[query].removeAll(udi); setData(query, m_predicatemap[query]); } Solid::Device device(udi); if (device.is()) { Solid::StorageAccess *access = device.as(); if (access) { disconnect(access, nullptr, this, nullptr); } } else if (device.is()) { Solid::OpticalDrive *drive = getAncestorAs(device); if (drive) { disconnect(drive, nullptr, this, nullptr); } } m_devicemap.remove(udi); removeSource(udi); } void SolidDeviceEngine::deviceChanged(const QString& udi, const QString &property, const QVariant &value) { setData(udi, property, value); updateSourceEvent(udi); } K_EXPORT_PLASMA_DATAENGINE_WITH_JSON(soliddevice, SolidDeviceEngine, "plasma-dataengine-soliddevice.json") #include "soliddeviceengine.moc"