File indexing completed on 2024-05-12 03:54:27
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1999 Preston Brown <pbrown@kde.org> 0004 SPDX-FileCopyrightText: 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "ksharedconfig.h" 0010 #include "kconfig_p.h" 0011 #include "kconfiggroup.h" 0012 #include <QCoreApplication> 0013 #include <QThread> 0014 #include <QThreadStorage> 0015 0016 void _k_globalMainConfigSync(); 0017 0018 using SharedConfigList = QList<KSharedConfig *>; 0019 0020 class GlobalSharedConfig 0021 { 0022 public: 0023 GlobalSharedConfig() 0024 : wasTestModeEnabled(false) 0025 { 0026 if (!qApp || QThread::currentThread() == qApp->thread()) { 0027 // We want to force the sync() before the QCoreApplication 0028 // instance is gone. Otherwise we trigger a QLockFile::lock() 0029 // after QCoreApplication is gone, calling qAppName() for a non 0030 // existent app... 0031 qAddPostRoutine(&_k_globalMainConfigSync); 0032 } 0033 // In other threads, QThreadStorage takes care of deleting the GlobalSharedConfigList when 0034 // the thread exits. 0035 } 0036 0037 SharedConfigList configList; 0038 // in addition to the list, we need to hold the main config, 0039 // so that it's not created and destroyed all the time. 0040 KSharedConfigPtr mainConfig; 0041 bool wasTestModeEnabled; 0042 }; 0043 0044 static QThreadStorage<GlobalSharedConfig *> s_storage; 0045 template<typename T> 0046 T *perThreadGlobalStatic() 0047 { 0048 if (!s_storage.hasLocalData()) { 0049 s_storage.setLocalData(new T); 0050 } 0051 return s_storage.localData(); 0052 } 0053 0054 // Q_GLOBAL_STATIC(GlobalSharedConfigList, globalSharedConfigList), but per thread: 0055 static GlobalSharedConfig *globalSharedConfig() 0056 { 0057 return perThreadGlobalStatic<GlobalSharedConfig>(); 0058 } 0059 0060 void _k_globalMainConfigSync() 0061 { 0062 if (KSharedConfigPtr mainConfig = globalSharedConfig()->mainConfig) { 0063 mainConfig->sync(); 0064 } 0065 } 0066 0067 KSharedConfigPtr KSharedConfig::openConfig(const QString &_fileName, OpenFlags flags, QStandardPaths::StandardLocation resType) 0068 { 0069 QString fileName(_fileName); 0070 GlobalSharedConfig *global = globalSharedConfig(); 0071 if (fileName.isEmpty() && !flags.testFlag(KConfig::SimpleConfig)) { 0072 // Determine the config file name that KConfig will make up (see KConfigPrivate::changeFileName) 0073 fileName = KConfig::mainConfigName(); 0074 } 0075 0076 if (!global->wasTestModeEnabled && QStandardPaths::isTestModeEnabled()) { 0077 global->wasTestModeEnabled = true; 0078 global->configList.clear(); 0079 global->mainConfig = nullptr; 0080 } 0081 0082 for (auto *cfg : std::as_const(global->configList)) { 0083 if (cfg->name() == fileName && cfg->d_ptr->openFlags == flags && cfg->locationType() == resType) { 0084 return KSharedConfigPtr(cfg); 0085 } 0086 } 0087 0088 KSharedConfigPtr ptr(new KSharedConfig(fileName, flags, resType)); 0089 0090 if (_fileName.isEmpty() && flags == FullConfig && resType == QStandardPaths::GenericConfigLocation) { 0091 global->mainConfig = ptr; 0092 0093 const bool isMainThread = !qApp || QThread::currentThread() == qApp->thread(); 0094 static bool userWarned = false; 0095 if (isMainThread && !userWarned) { 0096 userWarned = true; 0097 const bool isReadOnly = qEnvironmentVariableIsEmpty("KDE_HOME_READONLY"); 0098 if (isReadOnly && QCoreApplication::applicationName() != QLatin1String("kdialog")) { 0099 if (ptr->group(QStringLiteral("General")).readEntry(QStringLiteral("warn_unwritable_config"), true)) { 0100 ptr->isConfigWritable(true); 0101 } 0102 } 0103 } 0104 } 0105 0106 return ptr; 0107 } 0108 0109 KSharedConfig::Ptr KSharedConfig::openStateConfig(const QString &_fileName) 0110 { 0111 // KF6 TODO: port this to XDG_STATE_HOME (default ~/.local/state) 0112 // See https://gitlab.freedesktop.org/xdg/xdg-specs/-/blob/master/basedir/basedir-spec.xml 0113 QString fileName(_fileName); 0114 0115 if (fileName.isEmpty()) { 0116 fileName = QCoreApplication::applicationName() + QLatin1String("staterc"); 0117 } 0118 0119 return openConfig(fileName, SimpleConfig, QStandardPaths::AppDataLocation); 0120 } 0121 0122 KSharedConfig::KSharedConfig(const QString &fileName, OpenFlags flags, QStandardPaths::StandardLocation resType) 0123 : KConfig(fileName, flags, resType) 0124 { 0125 globalSharedConfig()->configList.append(this); 0126 } 0127 0128 KSharedConfig::~KSharedConfig() 0129 { 0130 if (s_storage.hasLocalData()) { 0131 globalSharedConfig()->configList.removeAll(this); 0132 } 0133 } 0134 0135 KConfigGroup KSharedConfig::groupImpl(const QString &groupName) 0136 { 0137 KSharedConfigPtr ptr(this); 0138 return KConfigGroup(ptr, groupName); 0139 } 0140 0141 const KConfigGroup KSharedConfig::groupImpl(const QString &groupName) const 0142 { 0143 const KSharedConfigPtr ptr(const_cast<KSharedConfig *>(this)); 0144 return KConfigGroup(ptr, groupName); 0145 }