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