File indexing completed on 2024-12-15 05:06:52
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Kai Uwe Broulik <kde@broulik.de> 0003 * SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "powerprofile.h" 0009 0010 #include "power_profiles_interface.h" 0011 #include "powerprofileadaptor.h" 0012 #include "properties_interface.h" 0013 0014 #include <PowerDevilProfileSettings.h> 0015 #include <powerdevil_debug.h> 0016 0017 #include <KPluginFactory> 0018 0019 using namespace PowerDevil::BundledActions; 0020 0021 K_PLUGIN_CLASS_WITH_JSON(PowerProfile, "powerdevilpowerprofileaction.json") 0022 0023 static const QString activeProfileProperty = QStringLiteral("ActiveProfile"); 0024 static const QString profilesProperty = QStringLiteral("Profiles"); 0025 static const QString performanceInhibitedProperty = QStringLiteral("PerformanceInhibited"); 0026 static const QString performanceDegradedProperty = QStringLiteral("PerformanceDegraded"); 0027 static const QString profileHoldsProperty = QStringLiteral("ActiveProfileHolds"); 0028 0029 static const QString ppdName = QStringLiteral("net.hadess.PowerProfiles"); 0030 static const QString ppdPath = QStringLiteral("/net/hadess/PowerProfiles"); 0031 0032 PowerProfile::PowerProfile(QObject *parent) 0033 : Action(parent) 0034 , m_powerProfilesInterface(new NetHadessPowerProfilesInterface(ppdName, ppdPath, QDBusConnection::systemBus(), this)) 0035 , m_powerProfilesPropertiesInterface(new OrgFreedesktopDBusPropertiesInterface(ppdName, ppdPath, QDBusConnection::systemBus(), this)) 0036 , m_holdWatcher(new QDBusServiceWatcher(QString(), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration, this)) 0037 { 0038 new PowerProfileAdaptor(this); 0039 0040 connect(m_holdWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &PowerProfile::serviceUnregistered); 0041 connect(m_powerProfilesPropertiesInterface, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged, this, &PowerProfile::propertiesChanged); 0042 connect(m_powerProfilesInterface, &NetHadessPowerProfilesInterface::ProfileReleased, this, [this](unsigned int cookie) { 0043 auto it = std::find(m_holdMap.begin(), m_holdMap.end(), cookie); 0044 if (it != m_holdMap.end()) { 0045 if (m_holdMap.count(it.key()) == 1) { 0046 m_holdWatcher->removeWatchedService(it.key()); 0047 } 0048 m_holdMap.erase(it); 0049 } 0050 }); 0051 0052 auto watcher = new QDBusPendingCallWatcher(m_powerProfilesPropertiesInterface->GetAll(m_powerProfilesInterface->interface())); 0053 connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher] { 0054 watcher->deleteLater(); 0055 QDBusPendingReply<QVariantMap> reply = *watcher; 0056 if (watcher->isError()) { 0057 return; 0058 } 0059 readProperties(reply.value()); 0060 }); 0061 qDBusRegisterMetaType<QList<QVariantMap>>(); 0062 } 0063 0064 PowerProfile::~PowerProfile() = default; 0065 0066 void PowerProfile::onProfileLoad(const QString & /*previousProfile*/, const QString & /*newProfile*/) 0067 { 0068 if (!m_configuredProfile.isEmpty()) { 0069 setProfile(m_configuredProfile); 0070 } 0071 } 0072 0073 void PowerProfile::triggerImpl(const QVariantMap &args) 0074 { 0075 Q_UNUSED(args); 0076 } 0077 0078 bool PowerProfile::loadAction(const PowerDevil::ProfileSettings &profileSettings) 0079 { 0080 m_configuredProfile = profileSettings.powerProfile(); 0081 return !m_configuredProfile.isEmpty(); 0082 } 0083 0084 bool PowerProfile::isSupported() 0085 { 0086 return QDBusConnection::systemBus().interface()->activatableServiceNames().value().contains(ppdName); 0087 } 0088 0089 QStringList PowerProfile::profileChoices() const 0090 { 0091 return m_profileChoices; 0092 } 0093 0094 QString PowerProfile::currentProfile() const 0095 { 0096 return m_currentProfile; 0097 } 0098 0099 QString PowerProfile::performanceDegradedReason() const 0100 { 0101 return m_degradationReason; 0102 } 0103 0104 QString PowerProfile::performanceInhibitedReason() const 0105 { 0106 return m_performanceInhibitedReason; 0107 } 0108 0109 QList<QVariantMap> PowerProfile::profileHolds() const 0110 { 0111 return m_profileHolds; 0112 } 0113 0114 void PowerProfile::setProfile(const QString &profile) 0115 { 0116 auto call = m_powerProfilesPropertiesInterface->Set(m_powerProfilesInterface->interface(), activeProfileProperty, QDBusVariant(profile)); 0117 if (calledFromDBus()) { 0118 setDelayedReply(true); 0119 const auto msg = message(); 0120 auto watcher = new QDBusPendingCallWatcher(call); 0121 connect(watcher, &QDBusPendingCallWatcher::finished, this, [msg, watcher] { 0122 watcher->deleteLater(); 0123 if (watcher->isError()) { 0124 QDBusConnection::sessionBus().send(msg.createErrorReply(watcher->error())); 0125 } else { 0126 QDBusConnection::sessionBus().send(msg.createReply()); 0127 } 0128 }); 0129 } 0130 } 0131 0132 unsigned int PowerProfile::holdProfile(const QString &profile, const QString &reason, const QString &applicationId) 0133 { 0134 if (!m_profileChoices.contains(profile)) { 0135 sendErrorReply(QDBusError::InvalidArgs, QStringLiteral("%1 is not a valid profile").arg(profile)); 0136 return 0; // ignored by QtDBus 0137 } 0138 setDelayedReply(true); 0139 const auto msg = message(); 0140 auto call = m_powerProfilesInterface->HoldProfile(profile, reason, applicationId); 0141 auto watcher = new QDBusPendingCallWatcher(call); 0142 connect(watcher, &QDBusPendingCallWatcher::finished, this, [msg, watcher, this] { 0143 watcher->deleteLater(); 0144 QDBusPendingReply<unsigned int> reply = *watcher; 0145 if (reply.isError()) { 0146 QDBusConnection::sessionBus().send(msg.createErrorReply(watcher->error())); 0147 } else { 0148 m_holdWatcher->addWatchedService(msg.service()); 0149 m_holdMap.insert(msg.service(), reply.value()); 0150 QDBusConnection::sessionBus().send(msg.createReply(reply.value())); 0151 } 0152 }); 0153 return 0; // ignored by QtDBus 0154 } 0155 0156 void PowerProfile::releaseProfile(unsigned int cookie) 0157 { 0158 setDelayedReply(true); 0159 const auto msg = message(); 0160 auto call = m_powerProfilesInterface->ReleaseProfile(cookie); 0161 auto watcher = new QDBusPendingCallWatcher(call); 0162 connect(watcher, &QDBusPendingCallWatcher::finished, this, [msg, watcher, this] { 0163 watcher->deleteLater(); 0164 if (watcher->isError()) { 0165 QDBusConnection::sessionBus().send(msg.createErrorReply(watcher->error())); 0166 } else { 0167 m_holdMap.remove(msg.service(), msg.arguments()[0].toUInt()); 0168 if (m_holdMap.count(msg.service())) { 0169 m_holdWatcher->removeWatchedService(msg.service()); 0170 } 0171 QDBusConnection::sessionBus().send(msg.createReply()); 0172 } 0173 }); 0174 } 0175 0176 void PowerProfile::serviceUnregistered(const QString &name) 0177 { 0178 const auto cookies = m_holdMap.equal_range(name); 0179 for (auto it = cookies.first; it != cookies.second; ++it) { 0180 m_powerProfilesInterface->ReleaseProfile(*it); 0181 m_holdMap.erase(it); 0182 } 0183 m_holdWatcher->removeWatchedService(name); 0184 } 0185 0186 void PowerProfile::readProperties(const QVariantMap &properties) 0187 { 0188 if (properties.contains(activeProfileProperty)) { 0189 m_currentProfile = properties[activeProfileProperty].toString(); 0190 Q_EMIT currentProfileChanged(m_currentProfile); 0191 } 0192 0193 if (properties.contains(profilesProperty)) { 0194 QList<QVariantMap> profiles; 0195 properties[profilesProperty].value<QDBusArgument>() >> profiles; 0196 m_profileChoices.clear(); 0197 if (profiles.first()[QStringLiteral("Driver")] != QLatin1String("placeholder")) { 0198 std::transform(profiles.cbegin(), profiles.cend(), std::back_inserter(m_profileChoices), [](const QVariantMap &dict) { 0199 return dict[QStringLiteral("Profile")].toString(); 0200 }); 0201 } 0202 Q_EMIT profileChoicesChanged(m_profileChoices); 0203 } 0204 0205 if (properties.contains(performanceInhibitedProperty)) { 0206 m_performanceInhibitedReason = properties[performanceInhibitedProperty].toString(); 0207 Q_EMIT performanceInhibitedReasonChanged(m_performanceInhibitedReason); 0208 } 0209 0210 if (properties.contains(performanceDegradedProperty)) { 0211 m_degradationReason = properties[performanceDegradedProperty].toString(); 0212 Q_EMIT performanceDegradedReasonChanged(m_degradationReason); 0213 } 0214 0215 if (properties.contains(profileHoldsProperty)) { 0216 properties[profileHoldsProperty].value<QDBusArgument>() >> m_profileHolds; 0217 Q_EMIT profileHoldsChanged(m_profileHolds); 0218 } 0219 } 0220 0221 void PowerProfile::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated) 0222 { 0223 Q_UNUSED(invalidated) 0224 if (interface != m_powerProfilesInterface->interface()) { 0225 return; 0226 } 0227 readProperties(changed); 0228 } 0229 0230 #include "powerprofile.moc" 0231 0232 #include "moc_powerprofile.cpp"