File indexing completed on 2024-05-12 05:36:15

0001 // SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 #include "settings.h"
0005 #include "config.h"
0006 #include "utils.h"
0007 
0008 #include <KPackage/PackageLoader>
0009 #include <KRuntimePlatform>
0010 
0011 #include <QDBusConnection>
0012 #include <QDBusMessage>
0013 #include <QDebug>
0014 #include <QProcess>
0015 
0016 using namespace Qt::Literals::StringLiterals;
0017 
0018 const QString CONFIG_FILE = u"plasmamobilerc"_s;
0019 const QString SAVED_CONFIG_GROUP = u"SavedConfig"_s;
0020 
0021 Settings::Settings(QObject *parent)
0022     : QObject{parent}
0023     , m_isMobilePlatform{KRuntimePlatform::runtimePlatform().contains(u"phone"_s)}
0024     , m_mobileConfig{KSharedConfig::openConfig(CONFIG_FILE, KConfig::SimpleConfig)}
0025     , m_kwinrcConfig{KSharedConfig::openConfig(u"kwinrc"_s, KConfig::SimpleConfig)}
0026     , m_appBlacklistConfig{KSharedConfig::openConfig(u"applications-blacklistrc"_s, KConfig::SimpleConfig)}
0027     , m_kdeglobalsConfig{KSharedConfig::openConfig(u"kdeglobals"_s, KConfig::SimpleConfig)}
0028     , m_configWatcher{KConfigWatcher::create(m_mobileConfig)}
0029 {
0030 }
0031 
0032 Settings &Settings::self()
0033 {
0034     static Settings settings;
0035     return settings;
0036 }
0037 
0038 void Settings::applyConfiguration()
0039 {
0040     if (!m_isMobilePlatform) {
0041         qCDebug(LOGGING_CATEGORY) << "Configuration will not be applied, as the session is not Plasma Mobile.";
0042         qCDebug(LOGGING_CATEGORY) << "Restoring any previously saved configuration...";
0043         loadSavedConfiguration();
0044         return;
0045     }
0046 
0047     qCDebug(LOGGING_CATEGORY) << "Checking and applying mobile configuration...";
0048     applyMobileConfiguration();
0049 }
0050 
0051 void Settings::loadSavedConfiguration()
0052 {
0053     // kwinrc
0054     loadKeys(u"kwinrc"_s, m_kwinrcConfig, getKwinrcSettings(m_mobileConfig));
0055     m_kwinrcConfig->sync();
0056     reloadKWinConfig();
0057 
0058     // applications-blacklistrc
0059     loadKeys(u"applications-blacklistrc"_s, m_appBlacklistConfig, APPLICATIONS_BLACKLIST_DEFAULT_SETTINGS);
0060     m_appBlacklistConfig->sync();
0061 
0062     // kdeglobals
0063     loadKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_DEFAULT_SETTINGS);
0064     loadKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_SETTINGS);
0065     m_kdeglobalsConfig->sync();
0066 
0067     // save our changes
0068     m_mobileConfig->sync();
0069 }
0070 
0071 void Settings::applyMobileConfiguration()
0072 {
0073     // kwinrc
0074     writeKeys(u"kwinrc"_s, m_kwinrcConfig, getKwinrcSettings(m_mobileConfig), false);
0075     m_kwinrcConfig->sync();
0076     reloadKWinConfig();
0077 
0078     // applications-blacklistrc
0079     writeKeys(u"applications-blacklistrc"_s,
0080               m_appBlacklistConfig,
0081               APPLICATIONS_BLACKLIST_DEFAULT_SETTINGS,
0082               true); // only write entries if they are not already defined in the config
0083     m_appBlacklistConfig->sync();
0084 
0085     // kdeglobals
0086     writeKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_DEFAULT_SETTINGS,
0087               true); // only write entries if they are not already defined in the config
0088     writeKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_SETTINGS, false);
0089     m_kdeglobalsConfig->sync();
0090 
0091     // save our changes
0092     m_mobileConfig->sync();
0093 }
0094 
0095 void Settings::writeKeys(const QString &fileName, KSharedConfig::Ptr &config, const QMap<QString, QMap<QString, QVariant>> &settings, bool overwriteOnlyIfEmpty)
0096 {
0097     const auto groupNames = settings.keys();
0098     for (const auto &groupName : groupNames) {
0099         auto group = KConfigGroup{config, groupName};
0100 
0101         const auto keys = settings[groupName].keys();
0102         for (const auto &key : keys) {
0103             if (!group.hasKey(key) || !overwriteOnlyIfEmpty) {
0104                 // save key
0105                 saveConfigSetting(fileName, groupName, key, group.readEntry(key));
0106 
0107                 // overwrite with mobile setting
0108                 group.writeEntry(key, settings[groupName][key], KConfigGroup::Notify);
0109             }
0110         }
0111     }
0112 }
0113 
0114 void Settings::loadKeys(const QString &fileName, KSharedConfig::Ptr &config, const QMap<QString, QMap<QString, QVariant>> &settings)
0115 {
0116     const auto groupNames = settings.keys();
0117     for (const auto &groupName : groupNames) {
0118         const auto group = KConfigGroup{config, groupName};
0119 
0120         const auto keys = settings[groupName].keys();
0121         for (const auto &key : keys) {
0122             loadSavedConfigSetting(config, fileName, groupName, key);
0123         }
0124     }
0125 }
0126 
0127 // NOTE: this only saves a value if it hasn't already been saved
0128 void Settings::saveConfigSetting(const QString &fileName, const QString &group, const QString &key, const QVariant value)
0129 {
0130     const auto savedGroup = KConfigGroup{m_mobileConfig, SAVED_CONFIG_GROUP};
0131     const auto fileGroup = KConfigGroup{&savedGroup, fileName};
0132     auto keyGroup = KConfigGroup{&fileGroup, group};
0133 
0134     if (!keyGroup.hasKey(key)) {
0135         qCDebug(LOGGING_CATEGORY) << "In" << fileName << "saved" << key << "=" << value;
0136         keyGroup.writeEntry(key, value);
0137     }
0138 }
0139 
0140 // NOTE: this deletes the stored value from the config after loading
0141 const QString Settings::loadSavedConfigSetting(KSharedConfig::Ptr &config, const QString &fileName, const QString &group, const QString &key, bool write)
0142 {
0143     auto savedGroup = KConfigGroup{m_mobileConfig, SAVED_CONFIG_GROUP};
0144     auto fileGroup = KConfigGroup{&savedGroup, fileName};
0145     auto keyGroup = KConfigGroup{&fileGroup, group};
0146 
0147     if (!keyGroup.hasKey(key)) {
0148         return {};
0149     }
0150 
0151     const auto value = keyGroup.readEntry(key);
0152 
0153     // write to real config
0154     auto configGroup = KConfigGroup{config, group};
0155 
0156     if ((!configGroup.hasKey(key) || configGroup.readEntry(key) != value) && write) {
0157         qCDebug(LOGGING_CATEGORY) << "In" << fileName << "loading saved value of" << key << "which is" << value << "in" << group;
0158 
0159         if (value.isEmpty()) { // delete blank entries!
0160             configGroup.deleteEntry(key);
0161         } else {
0162             configGroup.writeEntry(key, value, KConfigGroup::Notify);
0163         }
0164     }
0165 
0166     // remove saved config option
0167     keyGroup.deleteEntry(key);
0168     return value;
0169 }
0170 
0171 void Settings::reloadKWinConfig()
0172 {
0173     QDBusMessage message = QDBusMessage::createSignal(u"/KWin"_s, u"org.kde.KWin"_s, u"reloadConfig"_s);
0174     QDBusConnection::sessionBus().send(message);
0175 }