File indexing completed on 2024-03-24 17:23:05
0001 // SPDX-License-Identifier: GPL-3.0-or-later 0002 /* 0003 Copyright 2017 - 2023 Martin Koller, kollix@aon.at 0004 0005 This file is part of liquidshell. 0006 0007 liquidshell is free software: you can redistribute it and/or modify 0008 it under the terms of the GNU General Public License as published by 0009 the Free Software Foundation, either version 3 of the License, or 0010 (at your option) any later version. 0011 0012 liquidshell is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 GNU General Public License for more details. 0016 0017 You should have received a copy of the GNU General Public License 0018 along with liquidshell. If not, see <http://www.gnu.org/licenses/>. 0019 */ 0020 0021 #include <Battery.hxx> 0022 0023 #include <QIcon> 0024 #include <QDBusConnection> 0025 #include <QDBusMessage> 0026 #include <QDBusVariant> 0027 #include <QDebug> 0028 0029 #include <Solid/Battery> 0030 0031 #include <KLocalizedString> 0032 #include <KIconLoader> 0033 #include <kcmutils_version.h> 0034 0035 #include <cmath> 0036 0037 //-------------------------------------------------------------------------------- 0038 0039 Battery::Battery(QWidget *parent) 0040 : SysTrayItem(parent) 0041 { 0042 QList<Solid::Device> devices = Solid::Device::listFromType(Solid::DeviceInterface::Battery); 0043 0044 for (Solid::Device dev : devices) 0045 { 0046 if ( dev.is<Solid::Battery>() && (dev.as<Solid::Battery>()->type() == Solid::Battery::PrimaryBattery) ) 0047 { 0048 device = dev; 0049 break; 0050 } 0051 } 0052 0053 if ( !device.isValid() ) 0054 hide(); 0055 else 0056 { 0057 QDBusConnection::systemBus() 0058 .connect("org.freedesktop.UPower", 0059 "/org/freedesktop/UPower", 0060 "org.freedesktop.DBus.Properties", 0061 "PropertiesChanged", 0062 this, 0063 SLOT(upowerPropertiesChanged(QString, QVariantMap, QStringList))); 0064 0065 QDBusMessage msg = 0066 QDBusMessage::createMethodCall("org.freedesktop.UPower", 0067 "/org/freedesktop/UPower", 0068 "org.freedesktop.DBus.Properties", 0069 "Get"); 0070 msg << QLatin1String("org.freedesktop.UPower") << QLatin1String("OnBattery"); 0071 QDBusConnection::systemBus().callWithCallback(msg, this, SLOT(onBatteryReply(QDBusMessage)), nullptr); 0072 0073 connect(device.as<Solid::Battery>(), &Solid::Battery::chargePercentChanged, this, &Battery::changed); 0074 connect(device.as<Solid::Battery>(), &Solid::Battery::chargeStateChanged, this, &Battery::changed); 0075 connect(device.as<Solid::Battery>(), &Solid::Battery::timeToFullChanged, this, &Battery::changed); 0076 connect(device.as<Solid::Battery>(), &Solid::Battery::timeToEmptyChanged, this, &Battery::changed); 0077 0078 connect(KIconLoader::global(), &KIconLoader::iconLoaderSettingsChanged, this, &Battery::changed); 0079 0080 changed(); 0081 } 0082 } 0083 0084 //-------------------------------------------------------------------------------- 0085 0086 QString Battery::secsToHM(int secs) const 0087 { 0088 int h = secs / 3600; 0089 int m = (secs % 3600) / 60; 0090 0091 QString hStr = i18np("%1 hour", "%1 hours", h); 0092 QString mStr = i18np("%1 minute", "%1 minutes", m); 0093 0094 QString result; 0095 0096 if ( h ) 0097 result = hStr; 0098 0099 if ( m ) 0100 { 0101 if ( h ) 0102 result += ", "; 0103 0104 result += mStr; 0105 } 0106 0107 return result; 0108 } 0109 0110 //-------------------------------------------------------------------------------- 0111 0112 void Battery::onBatteryReply(const QDBusMessage &msg) 0113 { 0114 onBattery = msg.arguments()[0].value<QDBusVariant>().variant().toBool(); 0115 changed(); 0116 } 0117 0118 //-------------------------------------------------------------------------------- 0119 0120 void Battery::upowerPropertiesChanged(const QString &interface, 0121 const QVariantMap &properties, 0122 const QStringList &invalidated) 0123 { 0124 Q_UNUSED(interface) 0125 Q_UNUSED(invalidated) 0126 0127 if ( properties.contains("OnBattery") ) 0128 { 0129 onBattery = properties.value("OnBattery").toBool(); 0130 changed(); 0131 } 0132 } 0133 0134 //-------------------------------------------------------------------------------- 0135 0136 QIcon Battery::getStatusIcon(int charge, bool isCharging) 0137 { 0138 QString iconName; 0139 0140 int p = qRound(charge / 20.0) * 20; 0141 0142 if ( p < 20 ) 0143 iconName = "caution"; 0144 else if ( p < 40 ) 0145 iconName = "low"; 0146 else 0147 iconName = QString("%1").arg(p, 3, 10, QLatin1Char('0')); 0148 0149 iconName = QString("battery%1-%2").arg(isCharging ? "-charging" : "").arg(iconName); 0150 0151 return QIcon::fromTheme(iconName); 0152 } 0153 0154 //-------------------------------------------------------------------------------- 0155 0156 void Battery::changed() 0157 { 0158 Solid::Battery *battery = device.as<Solid::Battery>(); 0159 0160 QString tip; 0161 0162 switch ( battery->chargeState() ) 0163 { 0164 case Solid::Battery::NoCharge: tip = i18n("Not Charging"); break; 0165 case Solid::Battery::FullyCharged: tip = i18n("Fully Charged"); break; 0166 0167 case Solid::Battery::Charging: 0168 case Solid::Battery::Discharging: 0169 { 0170 if ( battery->chargeState() == Solid::Battery::Charging ) 0171 { 0172 tip = i18n("Charging at %1%", battery->chargePercent()); 0173 if ( battery->timeToFull() ) // it can be 0, so we don't know 0174 tip += '\n' + i18n("Time until full: ") + secsToHM(battery->timeToFull()); 0175 } 0176 else 0177 { 0178 tip = i18n("Discharging at %1%", battery->chargePercent()); 0179 if ( battery->timeToEmpty() ) // it can be 0, so we don't know 0180 tip += '\n' + i18n("Remaining Time: ") + secsToHM(battery->timeToEmpty()); 0181 } 0182 0183 break; 0184 } 0185 } 0186 0187 setPixmap(getStatusIcon(battery->chargePercent(), 0188 battery->chargeState() == Solid::Battery::Charging).pixmap(size())); 0189 setToolTip(tip); 0190 0191 setVisible(onBattery || (battery->chargeState() != Solid::Battery::FullyCharged)); 0192 } 0193 0194 //-------------------------------------------------------------------------------- 0195 0196 QWidget *Battery::getDetailsList() 0197 { 0198 if ( !dialog ) 0199 { 0200 dialog = new KCMultiDialog(this); 0201 dialog->setAttribute(Qt::WA_DeleteOnClose); 0202 0203 // different KDE versions need different ways ... 0204 KPluginMetaData data("plasma/kcms/systemsettings_qwidgets/kcm_powerdevilglobalconfig"); 0205 0206 if ( data.isValid() ) 0207 { 0208 dialog->addModule(data); 0209 dialog->addModule(KPluginMetaData("plasma/kcms/systemsettings_qwidgets/kcm_powerdevilprofilesconfig")); 0210 } 0211 else 0212 { 0213 dialog->addModule("powerdevilglobalconfig"); 0214 dialog->addModule("powerdevilprofilesconfig"); 0215 } 0216 0217 dialog->adjustSize(); 0218 dialog->setWindowTitle(i18n("Power Management")); 0219 } 0220 0221 return dialog; 0222 } 0223 0224 //--------------------------------------------------------------------------------