From 92a1cfc740e014bb63fb0f4168dd9236e71ecd0e Mon Sep 17 00:00:00 2001 From: Devin Lin Date: Fri, 13 Jun 2025 07:16:18 -0400 Subject: [PATCH] envmanager: Write options as immutable, and add kdeglobals This commit writes options as immutable to the config file ([$i] suffix), so that user defined options from desktop do not override our specified mobile settings. This commit also moves kdeglobals settings to be written to ~/.config/plasma-mobile/kdeglobals rather than directly to ~/.config/kdeglobals, continuing the work from !723 Fixes https://invent.kde.org/plasma/plasma-mobile/-/issues/467 --- envmanager/CMakeLists.txt | 2 +- envmanager/settings.cpp | 81 +++++++++++++++++++++++++-------------- envmanager/settings.h | 13 +++---- envmanager/utils.cpp | 79 ++++++++++++++++++++++++++++++++++++++ envmanager/utils.h | 15 +++++++- 5 files changed, 152 insertions(+), 38 deletions(-) create mode 100644 envmanager/utils.cpp diff --git a/envmanager/CMakeLists.txt b/envmanager/CMakeLists.txt index c30eca6a..fd0a255d 100644 --- a/envmanager/CMakeLists.txt +++ b/envmanager/CMakeLists.txt @@ -4,7 +4,7 @@ set(plasma-mobile-envmanager_SRCS main.cpp settings.cpp - utils.h + utils.cpp config.h ) diff --git a/envmanager/settings.cpp b/envmanager/settings.cpp index f99e0934..c467d16d 100644 --- a/envmanager/settings.cpp +++ b/envmanager/settings.cpp @@ -21,17 +21,13 @@ const QString SAVED_CONFIG_GROUP = u"SavedConfig"_s; // In bin/startplasmamobile, we add `~/.config/plasma-mobile` to XDG_CONFIG_DIRS to overlay our own configs const QString MOBILE_KWINRC_FILE = u"plasma-mobile/kwinrc"_s; const QString MOBILE_KSMSERVERRC_FILE = u"plasma-mobile/ksmserverrc"_s; +const QString MOBILE_KDEGLOBALS_FILE = u"plasma-mobile/kdeglobals"_s; Settings::Settings(QObject *parent) : QObject{parent} , m_isMobilePlatform{KRuntimePlatform::runtimePlatform().contains(u"phone"_s)} , m_mobileConfig{KSharedConfig::openConfig(CONFIG_FILE, KConfig::SimpleConfig)} - , m_kwinrcConfig{KSharedConfig::openConfig(MOBILE_KWINRC_FILE, KConfig::SimpleConfig)} , m_appBlacklistConfig{KSharedConfig::openConfig(u"applications-blacklistrc"_s, KConfig::SimpleConfig)} - , m_kdeglobalsConfig{KSharedConfig::openConfig(u"kdeglobals"_s, KConfig::SimpleConfig)} - , m_ksmServerConfig{KSharedConfig::openConfig(MOBILE_KSMSERVERRC_FILE, KConfig::SimpleConfig)} - , m_originalKwinrcConfig{KSharedConfig::openConfig(u"kwinrc"_s, KConfig::SimpleConfig)} - , m_configWatcher{KConfigWatcher::create(m_mobileConfig)} { } @@ -57,18 +53,19 @@ void Settings::applyConfiguration() void Settings::loadSavedConfiguration() { // kwinrc (legacy, we only write in the plasma-mobile/kwinrc file now) - loadKeys(u"kwinrc"_s, m_originalKwinrcConfig, getKwinrcSettings(m_mobileConfig)); - m_originalKwinrcConfig->sync(); + auto originalKwinrcConfig = KSharedConfig::openConfig(u"kwinrc"_s, KConfig::SimpleConfig); + loadKeys(u"kwinrc"_s, originalKwinrcConfig, getKwinrcSettings(m_mobileConfig)); + originalKwinrcConfig->sync(); reloadKWinConfig(); // applications-blacklistrc loadKeys(u"applications-blacklistrc"_s, m_appBlacklistConfig, APPLICATIONS_BLACKLIST_DEFAULT_SETTINGS); m_appBlacklistConfig->sync(); - // kdeglobals - loadKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_DEFAULT_SETTINGS); - loadKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_SETTINGS); - m_kdeglobalsConfig->sync(); + // kdeglobals (legacy, we only write in the plasma-mobile/kdeglobals file now) + auto originalKdeglobalsConfig = KSharedConfig::openConfig(u"kdeglobals"_s, KConfig::SimpleConfig); + loadKeys(u"kdeglobals"_s, originalKdeglobalsConfig, KDEGLOBALS_SETTINGS); + originalKdeglobalsConfig->sync(); // save our changes m_mobileConfig->sync(); @@ -76,29 +73,50 @@ void Settings::loadSavedConfiguration() void Settings::applyMobileConfiguration() { - // kwinrc-plasma-mobile - writeKeys(MOBILE_KWINRC_FILE, m_kwinrcConfig, getKwinrcSettings(m_mobileConfig)); - m_kwinrcConfig->sync(); - reloadKWinConfig(); + // kwinrc + { + auto kwinSettings = getKwinrcSettings(m_mobileConfig); + setOptionsImmutable(false, MOBILE_KWINRC_FILE, kwinSettings); + + auto kwinrc = kwinrcConfig(); + writeKeys(MOBILE_KWINRC_FILE, kwinrc, kwinSettings); + kwinrc->sync(); + reloadKWinConfig(); + + setOptionsImmutable(true, MOBILE_KWINRC_FILE, kwinSettings); + } // applications-blacklistrc - writeKeysAndSave(u"applications-blacklistrc"_s, - m_appBlacklistConfig, - APPLICATIONS_BLACKLIST_DEFAULT_SETTINGS, - true); // only write entries if they are not already defined in the config - m_appBlacklistConfig->sync(); + { + writeKeysAndSave(u"applications-blacklistrc"_s, + m_appBlacklistConfig, + APPLICATIONS_BLACKLIST_DEFAULT_SETTINGS, + true); // only write entries if they are not already defined in the config + m_appBlacklistConfig->sync(); + } // kdeglobals - writeKeysAndSave(u"kdeglobals"_s, - m_kdeglobalsConfig, - KDEGLOBALS_DEFAULT_SETTINGS, - true); // only write entries if they are not already defined in the config - writeKeysAndSave(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_SETTINGS, false); - m_kdeglobalsConfig->sync(); + { + setOptionsImmutable(false, MOBILE_KDEGLOBALS_FILE, KDEGLOBALS_SETTINGS); + + auto kdeglobals = KSharedConfig::openConfig(MOBILE_KDEGLOBALS_FILE, KConfig::SimpleConfig); + writeKeys(MOBILE_KDEGLOBALS_FILE, kdeglobals, KDEGLOBALS_DEFAULT_SETTINGS); // only write, don't make immutable + writeKeys(MOBILE_KDEGLOBALS_FILE, kdeglobals, KDEGLOBALS_SETTINGS); + kdeglobals->sync(); + + setOptionsImmutable(true, MOBILE_KDEGLOBALS_FILE, KDEGLOBALS_SETTINGS); + } // ksmserver - writeKeys(MOBILE_KSMSERVERRC_FILE, m_ksmServerConfig, KSMSERVER_SETTINGS); - m_ksmServerConfig->sync(); + { + setOptionsImmutable(false, MOBILE_KSMSERVERRC_FILE, KSMSERVER_SETTINGS); + + auto ksmserver = KSharedConfig::openConfig(MOBILE_KSMSERVERRC_FILE, KConfig::SimpleConfig); + writeKeys(MOBILE_KSMSERVERRC_FILE, ksmserver, KSMSERVER_SETTINGS); + ksmserver->sync(); + + setOptionsImmutable(true, MOBILE_KSMSERVERRC_FILE, KSMSERVER_SETTINGS); + } // save our changes m_mobileConfig->sync(); @@ -197,6 +215,11 @@ const QString Settings::loadSavedConfigSetting(KSharedConfig::Ptr &config, const return value; } +KSharedConfig::Ptr Settings::kwinrcConfig() const +{ + return KSharedConfig::openConfig(MOBILE_KWINRC_FILE, KConfig::SimpleConfig); +} + void Settings::reloadKWinConfig() { // Reload config @@ -205,7 +228,7 @@ void Settings::reloadKWinConfig() // Effects need to manually be loaded/unloaded in a live KWin session. - KConfigGroup pluginsGroup{m_kwinrcConfig, QStringLiteral("Plugins")}; + KConfigGroup pluginsGroup{kwinrcConfig(), QStringLiteral("Plugins")}; for (const auto &effect : KWIN_EFFECTS) { // Read from the config whether the effect is enabled (settings are suffixed with "Enabled", ex. blurEnabled) diff --git a/envmanager/settings.h b/envmanager/settings.h index 622d7f45..3ebb9fac 100644 --- a/envmanager/settings.h +++ b/envmanager/settings.h @@ -36,19 +36,18 @@ private: void saveConfigSetting(const QString &fileName, const QString &group, const QString &key, const QVariant value); const QString loadSavedConfigSetting(KSharedConfig::Ptr &config, const QString &fileName, const QString &group, const QString &key, bool write = true); + KSharedConfig::Ptr kwinrcConfig() const; void reloadKWinConfig(); // whether this is Plasma Mobile bool m_isMobilePlatform; KSharedConfig::Ptr m_mobileConfig; - KSharedConfig::Ptr m_kwinrcConfig; // (~/.config/kwinrc-plasma-mobile) + KSharedConfig::Ptr m_kwinrcConfig; // (~/.config/plasma-mobile/kwinrc) KSharedConfig::Ptr m_appBlacklistConfig; - KSharedConfig::Ptr m_kdeglobalsConfig; - KSharedConfig::Ptr m_ksmServerConfig; + KSharedConfig::Ptr m_kdeglobalsConfig; // (~/.config/plasma-mobile/kdeglobals) + KSharedConfig::Ptr m_ksmServerConfig; // (~/.config/plamsma-mobile/ksmserverrc) - // For legacy upgrade purposes (~/.config/kwinrc) - KSharedConfig::Ptr m_originalKwinrcConfig; - - KConfigWatcher::Ptr m_configWatcher; + // For legacy upgrade purposes + KSharedConfig::Ptr m_originalKdeglobalsConfig; // (~/.config/kdeglobals) }; diff --git a/envmanager/utils.cpp b/envmanager/utils.cpp new file mode 100644 index 00000000..82136a2b --- /dev/null +++ b/envmanager/utils.cpp @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: 2025 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "utils.h" + +#include + +void setOptionsImmutable(bool immutable, const QString &configFilePath, const QMap> &options) +{ + // Find ~/.config/{configFilePath} + QDir basePath{QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)}; + QString fullPath = basePath.filePath(configFilePath); + + QFile file{fullPath}; + if (!file.exists()) { + return; + } + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qCCritical(LOGGING_CATEGORY) << "Unable to read from" << configFilePath << "to change immutability!"; + return; + } + + QTextStream in(&file); + QStringList lines; + + QString configGroup; + + // Read file line by line, and add/remove [$i] suffixes from each option + while (!in.atEnd()) { + QString line = in.readLine(); + + if (line.trimmed().startsWith("//")) { + lines << line; + continue; + } + + // Split by first '=' sign + int equalsIndex = line.indexOf('='); + if (equalsIndex == -1) { + lines << line; + + // Is it a group? + if (line.startsWith("[") && line.endsWith("]")) { + configGroup = line.mid(1, line.length() - 2); + } + + continue; + } + + QString key = line.mid(0, equalsIndex); + QString value = line.mid(equalsIndex + 1); + const QString immutableSuffix = "[$i]"; + + // Remove [$i] key suffix + if (key.endsWith(immutableSuffix)) { + key.chop(immutableSuffix.length()); + } + + // Add [$i] key suffix, only edit line if it's found in provided options + if (immutable && (options.contains(configGroup) && options[configGroup].contains(key))) { + key += immutableSuffix; + } + + lines << (key + "=" + value); + } + file.close(); + + // Overwrite file with edited lines + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qCCritical(LOGGING_CATEGORY) << "Unable to write to" << configFilePath << "to change immutability!"; + return; + } + + QTextStream out(&file); + for (const QString &line : std::as_const(lines)) { + out << line << "\n"; + } + file.close(); +} diff --git a/envmanager/utils.h b/envmanager/utils.h index 1c0a25b8..f2cae9fc 100644 --- a/envmanager/utils.h +++ b/envmanager/utils.h @@ -1,12 +1,25 @@ -// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-FileCopyrightText: 2023-2025 Devin Lin // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include +#include #include +#include static const QLoggingCategory &LOGGING_CATEGORY() { static const QLoggingCategory category("plasma-mobile-envmanager"); return category; } + +/** + * Sets each config option in the config file to be immutable or not (appended with [$i]) + * See https://api.kde.org/frameworks/kconfig/html/options.html for more details. + * + * @param immutable whether to set options to be immutable, or to remove immutability + * @param configFilePath path to the config file + * @param options the options in the config file to affect (format: >) + */ +void setOptionsImmutable(bool immutable, const QString &configFilePath, const QMap> &options);