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 &currentProfile)
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"