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