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