File indexing completed on 2024-05-12 05:38:48
0001 /* 0002 * SPDX-FileCopyrightText: 2008-2010 Dario Freddi <drf@kde.org> 0003 * SPDX-FileCopyrightText: 2023 Jakob Petsovits <jpetso@petsovits.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "PowerKCM.h" 0009 0010 #include "ExternalServiceSettings.h" 0011 0012 // powerdevil/kcmodule/common 0013 #include <PowerButtonActionModel.h> 0014 #include <PowerProfileModel.h> 0015 #include <SleepModeModel.h> 0016 0017 // powerdevil/daemon 0018 #include <PowerDevilGlobalSettings.h> 0019 #include <PowerDevilProfileSettings.h> 0020 #include <controllers/lidcontroller.h> 0021 #include <powerdevilenums.h> 0022 #include <powerdevilpowermanagement.h> 0023 0024 // debug category for qCDebug() 0025 #include <powerdevil_debug.h> 0026 0027 // KDE 0028 #include <KLocalizedString> 0029 #include <KPluginFactory> 0030 #include <Kirigami/Platform/TabletModeWatcher> 0031 #include <Solid/Battery> 0032 #include <Solid/Device> 0033 0034 // Qt 0035 #include <QDBusConnection> 0036 #include <QDBusConnectionInterface> 0037 #include <QDBusMessage> 0038 #include <QDBusPendingCall> 0039 #include <QDBusServiceWatcher> 0040 #include <QQuickItem> 0041 #include <QQuickRenderControl> 0042 0043 K_PLUGIN_FACTORY_WITH_JSON(PowerDevilProfilesConfigFactory, "kcm_powerdevilprofilesconfig.json", { 0044 registerPlugin<PowerDevil::PowerKCM>(); 0045 registerPlugin<PowerDevil::PowerConfigData>(); 0046 }) 0047 0048 namespace PowerDevil 0049 { 0050 0051 PowerConfigData::PowerConfigData(QObject *parent, const KPluginMetaData &metaData) 0052 : PowerConfigData(parent, 0053 Kirigami::Platform::TabletModeWatcher::self()->isTabletMode() /*isMobile*/, 0054 PowerDevil::PowerManagement::instance()->isVirtualMachine() /*isVM*/, 0055 PowerDevil::PowerManagement::instance()->canSuspend(), 0056 PowerDevil::PowerManagement::instance()->canHibernate()) 0057 { 0058 Q_UNUSED(metaData); 0059 } 0060 0061 PowerConfigData::PowerConfigData(QObject *parent, bool isMobile, bool isVM, bool canSuspend, bool canHibernate) 0062 : KCModuleData(parent) 0063 , m_globalSettings(new GlobalSettings(canSuspend, canHibernate, this)) 0064 , m_settingsAC(new ProfileSettings("AC", isMobile, isVM, canSuspend, this)) 0065 , m_settingsBattery(new ProfileSettings("Battery", isMobile, isVM, canSuspend, this)) 0066 , m_settingsLowBattery(new ProfileSettings("LowBattery", isMobile, isVM, canSuspend, this)) 0067 { 0068 autoRegisterSkeletons(); 0069 } 0070 0071 PowerConfigData::~PowerConfigData() 0072 { 0073 } 0074 0075 GlobalSettings *PowerConfigData::global() const 0076 { 0077 return m_globalSettings; 0078 } 0079 0080 ProfileSettings *PowerConfigData::profileAC() const 0081 { 0082 return m_settingsAC; 0083 } 0084 0085 ProfileSettings *PowerConfigData::profileBattery() const 0086 { 0087 return m_settingsBattery; 0088 } 0089 0090 ProfileSettings *PowerConfigData::profileLowBattery() const 0091 { 0092 return m_settingsLowBattery; 0093 } 0094 0095 PowerKCM::PowerKCM(QObject *parent, const KPluginMetaData &metaData) 0096 : KQuickManagedConfigModule(parent, metaData) 0097 , m_settings(new PowerConfigData(this, metaData)) 0098 , m_externalServiceSettings(new ExternalServiceSettings(this)) 0099 , m_supportsBatteryProfiles(false) 0100 , m_isPowerSupplyBatteryPresent(false) 0101 , m_isPeripheralBatteryPresent(false) 0102 , m_isLidPresent(false) 0103 , m_isPowerButtonPresent(false) 0104 , m_powerManagementServiceRegistered(false) 0105 , m_autoSuspendActionModel(new PowerButtonActionModel(this, 0106 PowerManagement::instance(), 0107 { 0108 PowerButtonAction::NoAction, 0109 PowerButtonAction::Sleep, 0110 PowerButtonAction::Hibernate, 0111 PowerButtonAction::Shutdown, 0112 })) 0113 , m_batteryCriticalActionModel(new PowerButtonActionModel(this, 0114 PowerManagement::instance(), 0115 { 0116 PowerButtonAction::NoAction, 0117 PowerButtonAction::Sleep, 0118 PowerButtonAction::Hibernate, 0119 PowerButtonAction::Shutdown, 0120 })) 0121 , m_powerButtonActionModel(new PowerButtonActionModel(this, 0122 PowerManagement::instance(), 0123 { 0124 PowerButtonAction::NoAction, 0125 PowerButtonAction::Sleep, 0126 PowerButtonAction::Hibernate, 0127 PowerButtonAction::Shutdown, 0128 PowerButtonAction::LockScreen, 0129 PowerButtonAction::PromptLogoutDialog, 0130 PowerButtonAction::TurnOffScreen, 0131 })) 0132 , m_lidActionModel(new PowerButtonActionModel(this, 0133 PowerManagement::instance(), 0134 { 0135 PowerButtonAction::NoAction, 0136 PowerButtonAction::Sleep, 0137 PowerButtonAction::Hibernate, 0138 PowerButtonAction::Shutdown, 0139 PowerButtonAction::LockScreen, 0140 PowerButtonAction::TurnOffScreen, 0141 })) 0142 , m_sleepModeModel(new SleepModeModel(this, PowerManagement::instance())) 0143 , m_powerProfileModel(new PowerProfileModel(this)) 0144 { 0145 qmlRegisterUncreatableMetaObject(PowerDevil::staticMetaObject, "org.kde.powerdevil", 1, 0, "PowerDevil", QStringLiteral("For enums and flags only")); 0146 0147 connect(m_externalServiceSettings, &ExternalServiceSettings::settingsChanged, this, &PowerKCM::settingsChanged); 0148 connect(m_externalServiceSettings, 0149 &ExternalServiceSettings::isChargeStartThresholdSupportedChanged, 0150 this, 0151 &PowerKCM::isChargeStartThresholdSupportedChanged); 0152 connect(m_externalServiceSettings, &ExternalServiceSettings::isChargeStopThresholdSupportedChanged, this, &PowerKCM::isChargeStopThresholdSupportedChanged); 0153 connect(m_externalServiceSettings, 0154 &ExternalServiceSettings::chargeStopThresholdMightNeedReconnectChanged, 0155 this, 0156 &PowerKCM::chargeStopThresholdMightNeedReconnectChanged); 0157 0158 QDBusServiceWatcher *watcher = new QDBusServiceWatcher("org.kde.Solid.PowerManagement", 0159 QDBusConnection::sessionBus(), 0160 QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration, 0161 this); 0162 0163 connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &PowerKCM::onServiceRegistered); 0164 connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, &PowerKCM::onServiceUnregistered); 0165 0166 if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.Solid.PowerManagement")) { 0167 onServiceRegistered("org.kde.Solid.PowerManagement"); 0168 } else { 0169 onServiceUnregistered("org.kde.Solid.PowerManagement"); 0170 } 0171 0172 // Load all the plugins, so we can tell the UI which ones are supported 0173 const QVector<KPluginMetaData> offers = KPluginMetaData::findPlugins(QStringLiteral("powerdevil/action")); 0174 0175 for (const KPluginMetaData &offer : offers) { 0176 QString actionId = offer.value(QStringLiteral("X-KDE-PowerDevil-Action-ID")); 0177 bool supported = true; 0178 0179 // Does it have a runtime requirement? 0180 if (offer.value(QStringLiteral("X-KDE-PowerDevil-Action-HasRuntimeRequirement"), false)) { 0181 qCDebug(POWERDEVIL) << offer.name() << " has a runtime requirement"; 0182 0183 QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", 0184 "/org/kde/Solid/PowerManagement", 0185 "org.kde.Solid.PowerManagement", 0186 "isActionSupported"); 0187 call.setArguments(QVariantList() << actionId); 0188 QDBusPendingReply<bool> reply = QDBusConnection::sessionBus().asyncCall(call); 0189 reply.waitForFinished(); 0190 0191 if (reply.isValid()) { 0192 if (!reply.value()) { 0193 supported = false; 0194 qCDebug(POWERDEVIL) << "The action " << actionId << " appears not to be supported by the core."; 0195 } 0196 } else { 0197 qCDebug(POWERDEVIL) << "There was a problem in contacting DBus!! Assuming the action is ok."; 0198 } 0199 } 0200 0201 m_supportedActions.insert(actionId, supported); 0202 } 0203 } 0204 0205 void PowerKCM::load() 0206 { 0207 QWindow *renderWindowAsKAuthParent = QQuickRenderControl::renderWindowFor(mainUi()->window()); 0208 m_externalServiceSettings->load(renderWindowAsKAuthParent); 0209 0210 const auto devices = Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString()); 0211 for (const Solid::Device &device : devices) { 0212 const Solid::Battery *b = qobject_cast<const Solid::Battery *>(device.asDeviceInterface(Solid::DeviceInterface::Battery)); 0213 if (b->isPowerSupply()) { 0214 setPowerSupplyBatteryPresent(true); 0215 if (b->type() == Solid::Battery::PrimaryBattery || b->type() == Solid::Battery::UpsBattery) { 0216 setSupportsBatteryProfiles(true); 0217 } 0218 } else { 0219 setPeripheralBatteryPresent(true); 0220 } 0221 } 0222 0223 setLidPresent(LidController().isLidPresent()); 0224 setPowerButtonPresent(true /* HACK This needs proper API to determine! */); 0225 0226 KQuickManagedConfigModule::load(); 0227 } 0228 0229 void PowerKCM::save() 0230 { 0231 KQuickManagedConfigModule::save(); 0232 0233 QWindow *renderWindowAsKAuthParent = QQuickRenderControl::renderWindowFor(mainUi()->window()); 0234 m_externalServiceSettings->save(renderWindowAsKAuthParent); 0235 0236 // Notify daemon 0237 QDBusMessage call = 0238 QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement", "org.kde.Solid.PowerManagement", "refreshStatus"); 0239 QDBusConnection::sessionBus().asyncCall(call); 0240 } 0241 0242 bool PowerKCM::isSaveNeeded() const 0243 { 0244 return m_externalServiceSettings->isSaveNeeded(); 0245 } 0246 0247 QVariantMap PowerKCM::supportedActions() const 0248 { 0249 return m_supportedActions; 0250 } 0251 0252 PowerConfigData *PowerKCM::settings() const 0253 { 0254 return m_settings; 0255 } 0256 0257 ExternalServiceSettings *PowerKCM::externalServiceSettings() const 0258 { 0259 return m_externalServiceSettings; 0260 } 0261 0262 QString PowerKCM::currentProfile() const 0263 { 0264 return m_currentProfile; 0265 } 0266 0267 void PowerKCM::setCurrentProfile(const QString ¤tProfile) 0268 { 0269 if (currentProfile == m_currentProfile) { 0270 return; 0271 } 0272 m_currentProfile = currentProfile; 0273 Q_EMIT currentProfileChanged(); 0274 } 0275 0276 bool PowerKCM::supportsBatteryProfiles() const 0277 { 0278 return m_supportsBatteryProfiles; 0279 } 0280 0281 void PowerKCM::setSupportsBatteryProfiles(bool supportsBatteryProfiles) 0282 { 0283 if (supportsBatteryProfiles == m_supportsBatteryProfiles) { 0284 return; 0285 } 0286 m_supportsBatteryProfiles = supportsBatteryProfiles; 0287 Q_EMIT supportsBatteryProfilesChanged(); 0288 } 0289 0290 bool PowerKCM::isChargeStartThresholdSupported() const 0291 { 0292 return m_externalServiceSettings->isChargeStartThresholdSupported(); 0293 } 0294 0295 bool PowerKCM::isChargeStopThresholdSupported() const 0296 { 0297 return m_externalServiceSettings->isChargeStopThresholdSupported(); 0298 } 0299 0300 bool PowerKCM::chargeStopThresholdMightNeedReconnect() const 0301 { 0302 return m_externalServiceSettings->chargeStopThresholdMightNeedReconnect(); 0303 } 0304 0305 bool PowerKCM::isPowerSupplyBatteryPresent() const 0306 { 0307 return m_isPowerSupplyBatteryPresent; 0308 } 0309 0310 bool PowerKCM::isPeripheralBatteryPresent() const 0311 { 0312 return m_isPeripheralBatteryPresent; 0313 } 0314 0315 void PowerKCM::setPowerSupplyBatteryPresent(bool isBatteryPresent) 0316 { 0317 if (isBatteryPresent == m_isPowerSupplyBatteryPresent) { 0318 return; 0319 } 0320 m_isPowerSupplyBatteryPresent = isBatteryPresent; 0321 Q_EMIT isPowerSupplyBatteryPresentChanged(); 0322 } 0323 0324 void PowerKCM::setPeripheralBatteryPresent(bool isBatteryPresent) 0325 { 0326 if (isBatteryPresent == m_isPeripheralBatteryPresent) { 0327 return; 0328 } 0329 m_isPeripheralBatteryPresent = isBatteryPresent; 0330 Q_EMIT isPeripheralBatteryPresentChanged(); 0331 } 0332 0333 bool PowerKCM::isLidPresent() const 0334 { 0335 return m_isLidPresent; 0336 } 0337 0338 bool PowerKCM::isPowerButtonPresent() const 0339 { 0340 return m_isPowerButtonPresent; 0341 } 0342 0343 void PowerKCM::setLidPresent(bool isLidPresent) 0344 { 0345 if (isLidPresent == m_isLidPresent) { 0346 return; 0347 } 0348 m_isLidPresent = isLidPresent; 0349 Q_EMIT isLidPresentChanged(); 0350 } 0351 0352 void PowerKCM::setPowerButtonPresent(bool isPowerButtonPresent) 0353 { 0354 if (isPowerButtonPresent == m_isPowerButtonPresent) { 0355 return; 0356 } 0357 m_isPowerButtonPresent = isPowerButtonPresent; 0358 Q_EMIT isPowerButtonPresentChanged(); 0359 } 0360 0361 QObject *PowerKCM::autoSuspendActionModel() const 0362 { 0363 return m_autoSuspendActionModel; 0364 } 0365 0366 QObject *PowerKCM::batteryCriticalActionModel() const 0367 { 0368 return m_batteryCriticalActionModel; 0369 } 0370 0371 QObject *PowerKCM::powerButtonActionModel() const 0372 { 0373 return m_powerButtonActionModel; 0374 } 0375 0376 QObject *PowerKCM::lidActionModel() const 0377 { 0378 return m_lidActionModel; 0379 } 0380 0381 QObject *PowerKCM::sleepModeModel() const 0382 { 0383 return m_sleepModeModel; 0384 } 0385 0386 QObject *PowerKCM::powerProfileModel() const 0387 { 0388 return m_powerProfileModel; 0389 } 0390 0391 bool PowerKCM::powerManagementServiceRegistered() const 0392 { 0393 return m_powerManagementServiceRegistered; 0394 } 0395 0396 QString PowerKCM::powerManagementServiceErrorReason() const 0397 { 0398 return m_powerManagementServiceErrorReason; 0399 } 0400 0401 void PowerKCM::setPowerManagementServiceRegistered(bool registered) 0402 { 0403 if (registered == m_powerManagementServiceRegistered) { 0404 return; 0405 } 0406 m_powerManagementServiceRegistered = registered; 0407 Q_EMIT powerManagementServiceRegisteredChanged(); 0408 } 0409 0410 void PowerKCM::setPowerManagementServiceErrorReason(const QString &reason) 0411 { 0412 if (reason == m_powerManagementServiceErrorReason) { 0413 return; 0414 } 0415 m_powerManagementServiceErrorReason = reason; 0416 Q_EMIT powerManagementServiceErrorReasonChanged(); 0417 } 0418 0419 void PowerKCM::onServiceRegistered(const QString & /*service*/) 0420 { 0421 QDBusMessage call = QDBusMessage::createMethodCall(QStringLiteral("org.kde.Solid.PowerManagement"), 0422 QStringLiteral("/org/kde/Solid/PowerManagement"), 0423 QStringLiteral("org.kde.Solid.PowerManagement"), 0424 QStringLiteral("currentProfile")); 0425 QDBusPendingCallWatcher *currentProfileWatcher = new QDBusPendingCallWatcher(QDBusConnection::sessionBus().asyncCall(call), this); 0426 0427 QObject::connect(currentProfileWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { 0428 QDBusPendingReply<QString> reply = *watcher; 0429 0430 if (!reply.isError()) { 0431 setCurrentProfile(reply.value()); 0432 } 0433 0434 watcher->deleteLater(); 0435 }); 0436 0437 setPowerManagementServiceRegistered(true); 0438 } 0439 0440 void PowerKCM::onServiceUnregistered(const QString & /*service*/) 0441 { 0442 setPowerManagementServiceErrorReason(i18n("The Power Management Service appears not to be running.")); 0443 setPowerManagementServiceRegistered(false); 0444 } 0445 0446 } // namespace PowerDevil 0447 0448 #include "PowerKCM.moc" 0449 0450 #include "moc_PowerKCM.cpp"