File indexing completed on 2024-04-28 05:36:16
0001 /* 0002 * SPDX-FileCopyrightText: Copyright 2023 Jakob Petsovits <jpetso@petsovits.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "powerdevilmigrateconfig.h" 0008 0009 #include "powerdevilenums.h" 0010 0011 #include <PowerDevilActivitySettings.h> 0012 #include <PowerDevilProfileSettings.h> 0013 #include <powerdevil_version.h> 0014 0015 #include <KConfigGroup> 0016 #include <KSharedConfig> 0017 0018 #include <algorithm> // std::min, std::max 0019 #include <functional> // std::invoke 0020 #include <type_traits> // std::remove_cvref_t 0021 0022 namespace 0023 { 0024 0025 template<typename T> 0026 struct IdentityTransformer { 0027 std::remove_cvref_t<T> operator()(T t) 0028 { 0029 return std::move(t); 0030 } 0031 }; 0032 0033 } // anonymous namespace 0034 0035 namespace PowerDevil 0036 { 0037 0038 void migrateActivitiesConfig(KSharedConfig::Ptr profilesConfig) 0039 { 0040 KConfigGroup migrationGroup = profilesConfig->group(QStringLiteral("Migration")); 0041 if (migrationGroup.hasKey("MigratedActivitiesToPlasma6")) { 0042 return; 0043 } 0044 0045 // Activity special behavior config written via ActivitySettings, reading must be done manually. 0046 const KConfigGroup oldActivitiesGroup = profilesConfig->group(QStringLiteral("Activities")); 0047 if (!oldActivitiesGroup.exists()) { 0048 return; 0049 } 0050 0051 // Every activity has its own group identified by its UUID. 0052 for (const QString &activityId : oldActivitiesGroup.groupList()) { 0053 const KConfigGroup oldConfig = oldActivitiesGroup.group(activityId); 0054 PowerDevil::ActivitySettings newConfig(activityId); 0055 0056 if (oldConfig.readEntry("mode", "None") == "SpecialBehavior") { 0057 if (const KConfigGroup oldSB = oldConfig.group(QStringLiteral("SpecialBehavior")); oldSB.exists()) { 0058 newConfig.setInhibitScreenManagement(oldSB.readEntry("noScreenManagement", false)); 0059 newConfig.setInhibitSuspend(oldSB.readEntry("noSuspend", false)); 0060 } 0061 } 0062 newConfig.save(); 0063 } 0064 0065 migrationGroup.writeEntry("MigratedActivitiesToPlasma6", "powerdevilrc"); 0066 profilesConfig->sync(); 0067 } 0068 0069 void ensureLockScreenIdleTimeoutInKScreenLockerKCM(int seconds) 0070 { 0071 KSharedConfig::Ptr lockerConfig = KSharedConfig::openConfig(QStringLiteral("kscreenlockerrc")); 0072 KConfigGroup group = lockerConfig->group(QStringLiteral("Daemon")); 0073 if (group.readEntry("Autolock", true) == false) { 0074 group.deleteEntry("Autolock"); // reset to default true value 0075 group.writeEntry("Timeout", std::max(1, std::min(group.readEntry("Timeout", 5), seconds / 60))); 0076 } 0077 lockerConfig->sync(); 0078 } 0079 0080 void migrateProfilesConfig(KSharedConfig::Ptr profilesConfig, bool isMobile, bool isVM, bool canSuspend) 0081 { 0082 KConfigGroup migrationGroup = profilesConfig->group(QStringLiteral("Migration")); 0083 if (migrationGroup.hasKey(QStringLiteral("MigratedProfilesToPlasma6"))) { 0084 return; 0085 } 0086 0087 for (const auto &profileName : {QStringLiteral("AC"), QStringLiteral("Battery"), QStringLiteral("LowBattery")}) { 0088 const KConfigGroup oldProfileGroup = profilesConfig->group(profileName); 0089 if (!oldProfileGroup.exists()) { 0090 continue; 0091 } 0092 PowerDevil::ProfileSettings profileSettings(profileName, isMobile, isVM, canSuspend); 0093 0094 auto migrateEntry = [&]<typename T, typename Transformer = IdentityTransformer<T>>(KConfigGroup & oldGroup, 0095 const QString &oldKey, 0096 void (ProfileSettings::*setter)(T), 0097 Transformer transform = IdentityTransformer<T>()) 0098 { 0099 if (!oldGroup.hasKey(oldKey)) { 0100 return; 0101 } 0102 // We know oldKey exists, so use any T value as default because we don't care what's in it 0103 T newValue = std::invoke(transform, oldGroup.readEntry(oldKey, std::remove_cvref_t<T>{})); 0104 (profileSettings.*setter)(newValue); 0105 }; 0106 0107 if (KConfigGroup group = oldProfileGroup.group(QStringLiteral("KeyboardBrightnessControl")); group.exists()) { 0108 profileSettings.setUseProfileSpecificKeyboardBrightness(true); 0109 migrateEntry(group, "value", &ProfileSettings::setKeyboardBrightness); 0110 } else { 0111 profileSettings.setUseProfileSpecificKeyboardBrightness(false); 0112 } 0113 0114 if (KConfigGroup group = oldProfileGroup.group(QStringLiteral("BrightnessControl")); group.exists()) { 0115 profileSettings.setUseProfileSpecificDisplayBrightness(true); 0116 migrateEntry(group, "value", &ProfileSettings::setDisplayBrightness); 0117 } else { 0118 profileSettings.setUseProfileSpecificDisplayBrightness(false); 0119 } 0120 0121 if (KConfigGroup group = oldProfileGroup.group(QStringLiteral("DimDisplay")); group.exists()) { 0122 profileSettings.setDimDisplayWhenIdle(true); 0123 migrateEntry(group, "idleTime", &ProfileSettings::setDimDisplayIdleTimeoutSec, [](int oldMsec) { 0124 return oldMsec / 1000; // standarize on using seconds, see powerdevil issue #3 on KDE Invent 0125 }); 0126 } else { 0127 profileSettings.setDimDisplayWhenIdle(false); 0128 } 0129 0130 if (KConfigGroup group = oldProfileGroup.group(QStringLiteral("DPMSControl")); group.exists()) { 0131 profileSettings.setTurnOffDisplayWhenIdle(true); 0132 // The "DPMSControl" group used seconds for "idleTime". Unlike other groups which 0133 // used milliseconds in Plasma 5, this one doesn't need division by 1000. 0134 migrateEntry(group, "idleTime", &ProfileSettings::setTurnOffDisplayIdleTimeoutSec); 0135 migrateEntry(group, "idleTimeoutWhenLocked", &ProfileSettings::setTurnOffDisplayIdleTimeoutWhenLockedSec); 0136 migrateEntry(group, "lockBeforeTurnOff", &ProfileSettings::setLockBeforeTurnOffDisplay); 0137 } else { 0138 profileSettings.setTurnOffDisplayWhenIdle(false); 0139 } 0140 0141 bool suspendThenHibernate = false; 0142 bool hybridSuspend = false; 0143 bool migrateLockScreenIdleTimeout = false; 0144 0145 if (KConfigGroup group = oldProfileGroup.group(QStringLiteral("SuspendSession")); group.exists()) { 0146 if (group.readEntry("suspendThenHibernate", false)) { 0147 suspendThenHibernate = true; 0148 } 0149 migrateEntry(group, "suspendType", &ProfileSettings::setAutoSuspendAction, [&](uint oldAction) { 0150 if (oldAction == 4 /* the old PowerButtonAction::SuspendHybrid */) { 0151 hybridSuspend = true; 0152 return qToUnderlying(PowerButtonAction::Sleep); 0153 } 0154 if (oldAction == qToUnderlying(PowerButtonAction::LockScreen)) { 0155 migrateLockScreenIdleTimeout = true; // see bottom of function 0156 return qToUnderlying(PowerButtonAction::NoAction); 0157 } 0158 return oldAction; 0159 }); 0160 migrateEntry(group, "idleTime", &ProfileSettings::setAutoSuspendIdleTimeoutSec, [](int oldMsec) { 0161 return oldMsec / 1000; // standarize on using seconds, see powerdevil issue #3 on KDE Invent 0162 }); 0163 // Note: setSleepMode() is called at the end, completing this section. 0164 } else { 0165 profileSettings.setAutoSuspendAction(qToUnderlying(PowerButtonAction::NoAction)); 0166 } 0167 0168 if (KConfigGroup group = oldProfileGroup.group(QStringLiteral("HandleButtonEvents")); group.exists()) { 0169 migrateEntry(group, "powerButtonAction", &ProfileSettings::setPowerButtonAction, [&](uint oldAction) { 0170 if (oldAction == 4 /* the old PowerButtonAction::SuspendHybrid */) { 0171 hybridSuspend = true; 0172 return qToUnderlying(PowerButtonAction::Sleep); 0173 } 0174 return oldAction; 0175 }); 0176 migrateEntry(group, "powerDownAction", &ProfileSettings::setPowerDownAction, [&](uint oldAction) { 0177 if (oldAction == 4 /* the old PowerButtonAction::SuspendHybrid */) { 0178 hybridSuspend = true; 0179 return qToUnderlying(PowerButtonAction::Sleep); 0180 } 0181 return oldAction; 0182 }); 0183 migrateEntry(group, "lidAction", &ProfileSettings::setLidAction, [&](uint oldAction) { 0184 if (oldAction == 4 /* the old PowerButtonAction::SuspendHybrid */) { 0185 hybridSuspend = true; 0186 return qToUnderlying(PowerButtonAction::Sleep); 0187 } 0188 return oldAction; 0189 }); 0190 migrateEntry(group, 0191 "triggerLidActionWhenExternalMonitorPresent", 0192 &ProfileSettings::setInhibitLidActionWhenExternalMonitorPresent, 0193 [](bool shouldTrigger) { 0194 return !shouldTrigger; 0195 }); 0196 } else { 0197 profileSettings.setPowerButtonAction(qToUnderlying(PowerButtonAction::NoAction)); 0198 profileSettings.setPowerDownAction(qToUnderlying(PowerButtonAction::NoAction)); 0199 profileSettings.setLidAction(qToUnderlying(PowerButtonAction::NoAction)); 0200 } 0201 0202 if (KConfigGroup group = oldProfileGroup.group(QStringLiteral("PowerProfile")); group.exists()) { 0203 migrateEntry(group, "profile", &ProfileSettings::setPowerProfile); 0204 } 0205 0206 if (KConfigGroup group = oldProfileGroup.group(QStringLiteral("RunScript")); group.exists()) { 0207 switch (group.readEntry("scriptPhase", 0)) { 0208 case 0: // on profile load 0209 migrateEntry(group, "scriptCommand", &ProfileSettings::setProfileLoadCommand); 0210 break; 0211 case 1: // on profile unload 0212 migrateEntry(group, "scriptCommand", &ProfileSettings::setProfileUnloadCommand); 0213 break; 0214 case 2: // on idle timeout 0215 migrateEntry(group, "scriptCommand", &ProfileSettings::setIdleTimeoutCommand); 0216 break; 0217 } 0218 migrateEntry(group, "idleTime", &ProfileSettings::setRunScriptIdleTimeoutSec, [](int oldMsec) { 0219 return oldMsec / 1000; // standarize on using seconds, see powerdevil issue #3 on KDE Invent 0220 }); 0221 } 0222 0223 if (suspendThenHibernate) { 0224 profileSettings.setSleepMode(qToUnderlying(SleepMode::SuspendThenHibernate)); 0225 } else if (hybridSuspend) { 0226 profileSettings.setSleepMode(qToUnderlying(SleepMode::HybridSuspend)); 0227 } 0228 0229 if (migrateLockScreenIdleTimeout) { 0230 // We had two different settings for this, ditch this and only keep the one in kscreenlockerrc 0231 ensureLockScreenIdleTimeoutInKScreenLockerKCM(profileSettings.autoSuspendIdleTimeoutSec()); 0232 } 0233 0234 profileSettings.save(); 0235 } 0236 0237 migrationGroup.writeEntry("MigratedProfilesToPlasma6", "powerdevilrc"); 0238 profilesConfig->sync(); 0239 } 0240 0241 void migrateConfig(bool isMobile, bool isVM, bool canSuspend) 0242 { 0243 KSharedConfig::Ptr profilesConfig = KSharedConfig::openConfig(QStringLiteral("powermanagementprofilesrc")); 0244 // TODO KF7 (or perhaps earlier): Remove Plasma 5->6 migration code and delete powermanagementprofilesrc 0245 0246 migrateActivitiesConfig(profilesConfig); 0247 migrateProfilesConfig(profilesConfig, isMobile, isVM, canSuspend); 0248 0249 #if POWERDEVIL_VERSION < QT_VERSION_CHECK(6, 0, 0) 0250 // quick-fixes for configs migrated prior to Plasma 6 RC1 (which we tweaked before final release) 0251 KSharedConfig::Ptr globalConfig = KSharedConfig::openConfig(QStringLiteral("powerdevilrc")); 0252 KConfigGroup batteryManagementGroup = globalConfig->group(QStringLiteral("BatteryManagement")); 0253 if (batteryManagementGroup.readEntry("BatteryCriticalAction", 0) == 4 /* the old PowerButtonAction::SuspendHybrid */) { 0254 batteryManagementGroup.writeEntry("BatteryCriticalAction", qToUnderlying(PowerButtonAction::Hibernate)); 0255 globalConfig->sync(); 0256 } 0257 for (const auto &profileName : {QStringLiteral("AC"), QStringLiteral("Battery"), QStringLiteral("LowBattery")}) { 0258 PowerDevil::ProfileSettings profileSettings(profileName, isMobile, isVM, canSuspend); 0259 if (profileSettings.autoSuspendAction() == qToUnderlying(PowerButtonAction::LockScreen)) { 0260 profileSettings.setAutoSuspendAction(qToUnderlying(PowerButtonAction::NoAction)); 0261 ensureLockScreenIdleTimeoutInKScreenLockerKCM(profileSettings.autoSuspendIdleTimeoutSec()); 0262 profileSettings.save(); 0263 } 0264 } 0265 #endif 0266 } 0267 0268 } // namespace PowerDevil