File indexing completed on 2024-05-12 05:35:40
0001 // vim: noexpandtab shiftwidth=4 tabstop=4 0002 /* 0003 SPDX-FileCopyrightText: 2002 Daniel Molkentin <molkentin@kde.org> 0004 SPDX-FileCopyrightText: 2020 Kai Uwe Broulik <kde@broulik.de> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "kcmkded.h" 0010 0011 #include "debug.h" 0012 0013 #include <QDBusConnection> 0014 #include <QDBusConnectionInterface> 0015 #include <QDBusPendingCall> 0016 #include <QDBusPendingCallWatcher> 0017 0018 #include <KConfig> 0019 #include <KConfigGroup> 0020 #include <KLocalizedString> 0021 #include <KPluginFactory> 0022 0023 #include <algorithm> 0024 0025 #include "filterproxymodel.h" 0026 #include "modulesmodel.h" 0027 0028 #include "kded_interface.h" 0029 #include "kdedconfigdata.h" 0030 0031 K_PLUGIN_FACTORY_WITH_JSON(KCMStyleFactory, "kcm_kded.json", registerPlugin<KDEDConfig>(); registerPlugin<KDEDConfigData>();) 0032 0033 static const QString s_kdedServiceName = QStringLiteral("org.kde.kded6"); 0034 0035 KDEDConfig::KDEDConfig(QObject *parent, const KPluginMetaData &metaData) 0036 : KQuickConfigModule(parent, metaData) 0037 , m_model(new ModulesModel(this)) 0038 , m_filteredModel(new FilterProxyModel(this)) 0039 , m_kdedInterface(new org::kde::kded6(s_kdedServiceName, QStringLiteral("/kded"), QDBusConnection::sessionBus())) 0040 , m_kdedWatcher(new QDBusServiceWatcher(s_kdedServiceName, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this)) 0041 { 0042 qmlRegisterUncreatableType<KDEDConfig>("org.kde.private.kcms.style", 1, 0, "KCM", QStringLiteral("Cannot create instances of KCM")); 0043 qmlRegisterAnonymousType<ModulesModel>("org.kde.plasma.kded.kcm", 0); 0044 qmlRegisterAnonymousType<FilterProxyModel>("org.kde.plasma.kded.kcm", 0); 0045 0046 setButtons(Apply | Default | Help); 0047 0048 m_filteredModel->setSourceModel(m_model); 0049 0050 connect(m_model, &ModulesModel::autoloadedModulesChanged, this, [this] { 0051 setNeedsSave(m_model->needsSave()); 0052 setRepresentsDefaults(m_model->representsDefault()); 0053 }); 0054 0055 connect(m_kdedWatcher, &QDBusServiceWatcher::serviceOwnerChanged, this, [this](const QString &service, const QString &oldOwner, const QString &newOwner) { 0056 Q_UNUSED(service) 0057 Q_UNUSED(oldOwner) 0058 setKdedRunning(!newOwner.isEmpty()); 0059 }); 0060 setKdedRunning(QDBusConnection::sessionBus().interface()->isServiceRegistered(s_kdedServiceName)); 0061 } 0062 0063 ModulesModel *KDEDConfig::model() const 0064 { 0065 return m_model; 0066 } 0067 0068 FilterProxyModel *KDEDConfig::filteredModel() const 0069 { 0070 return m_filteredModel; 0071 } 0072 0073 bool KDEDConfig::kdedRunning() const 0074 { 0075 return m_kdedRunning; 0076 } 0077 0078 void KDEDConfig::setKdedRunning(bool kdedRunning) 0079 { 0080 if (m_kdedRunning == kdedRunning) { 0081 return; 0082 } 0083 0084 m_kdedRunning = kdedRunning; 0085 Q_EMIT kdedRunningChanged(); 0086 0087 if (kdedRunning) { 0088 getModuleStatus(); 0089 } else { 0090 m_model->setRunningModulesKnown(false); 0091 } 0092 } 0093 0094 void KDEDConfig::startModule(const QString &moduleName) 0095 { 0096 startOrStopModule(moduleName, Running); 0097 } 0098 0099 void KDEDConfig::stopModule(const QString &moduleName) 0100 { 0101 startOrStopModule(moduleName, NotRunning); 0102 } 0103 0104 void KDEDConfig::startOrStopModule(const QString &moduleName, ModuleStatus status) 0105 { 0106 auto call = (status == NotRunning ? m_kdedInterface->unloadModule(moduleName) : m_kdedInterface->loadModule(moduleName)); 0107 0108 QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(call, this); 0109 connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this, moduleName, status](QDBusPendingCallWatcher *watcher) { 0110 QDBusPendingReply<bool> reply = *watcher; 0111 watcher->deleteLater(); 0112 0113 if (reply.isError()) { 0114 if (status == NotRunning) { 0115 Q_EMIT errorMessage(i18n("Failed to stop service: %1", reply.error().message())); 0116 } else { 0117 Q_EMIT errorMessage(i18n("Failed to start service: %1", reply.error().message())); 0118 } 0119 return; 0120 } 0121 0122 if (!reply.value()) { 0123 if (status == NotRunning) { 0124 Q_EMIT errorMessage(i18n("Failed to stop service.")); 0125 } else { 0126 Q_EMIT errorMessage(i18n("Failed to start service.")); 0127 } 0128 return; 0129 } 0130 0131 qCDebug(KCM_KDED) << "Successfully" << (status == Running ? "started" : "stopped") << moduleName; 0132 if (status == Running) { 0133 m_lastStartedModule = moduleName; 0134 } else { 0135 m_lastStartedModule.clear(); 0136 } 0137 getModuleStatus(); 0138 }); 0139 } 0140 0141 void KDEDConfig::getModuleStatus() 0142 { 0143 auto call = m_kdedInterface->loadedModules(); 0144 0145 QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(call, this); 0146 connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { 0147 QDBusPendingReply<QStringList> reply = *watcher; 0148 watcher->deleteLater(); 0149 0150 if (reply.isError()) { 0151 qCWarning(KCM_KDED) << "Failed to get loaded modules" << reply.error().name() << reply.error().message(); 0152 return; 0153 } 0154 0155 QStringList runningModules = reply.value(); 0156 m_model->setRunningModules(runningModules); 0157 m_model->setRunningModulesKnown(true); 0158 0159 // Check if the user just tried starting a module that then disabled itself again. 0160 // Some kded modules disable themselves on start when they deem themselves unnecessary 0161 // based on some configuration independent of kded or the current environment. 0162 // At least provide some feedback and not leave the user wondering why the service doesn't start. 0163 if (!m_lastStartedModule.isEmpty() && !runningModules.contains(m_lastStartedModule)) { 0164 Q_EMIT showSelfDisablingModulesHint(); 0165 } 0166 m_lastStartedModule.clear(); 0167 0168 // Check if any modules got started/stopped as a result of reloading kded 0169 if (!m_runningModulesBeforeReconfigure.isEmpty()) { 0170 std::sort(m_runningModulesBeforeReconfigure.begin(), m_runningModulesBeforeReconfigure.end()); 0171 std::sort(runningModules.begin(), runningModules.end()); 0172 0173 if (m_runningModulesBeforeReconfigure != runningModules) { 0174 Q_EMIT showRunningModulesChangedAfterSaveHint(); 0175 } 0176 } 0177 m_runningModulesBeforeReconfigure.clear(); 0178 }); 0179 } 0180 0181 void KDEDConfig::load() 0182 { 0183 m_model->load(); 0184 0185 setNeedsSave(false); 0186 setRepresentsDefaults(m_model->representsDefault()); 0187 } 0188 0189 void KDEDConfig::save() 0190 { 0191 KConfig kdedrc(QStringLiteral("kded5rc"), KConfig::NoGlobals); 0192 0193 for (int i = 0; i < m_model->rowCount(); ++i) { 0194 const QModelIndex idx = m_model->index(i, 0); 0195 0196 const auto type = static_cast<ModuleType>(idx.data(ModulesModel::TypeRole).toInt()); 0197 if (type != AutostartType) { 0198 continue; 0199 } 0200 0201 const QString moduleName = idx.data(ModulesModel::ModuleNameRole).toString(); 0202 0203 const bool autoloadEnabled = idx.data(ModulesModel::AutoloadEnabledRole).toBool(); 0204 KConfigGroup cg(&kdedrc, QStringLiteral("Module-%1").arg(moduleName)); 0205 cg.writeEntry("autoload", autoloadEnabled); 0206 } 0207 0208 kdedrc.sync(); 0209 m_model->refreshAutoloadEnabledSavedState(); 0210 setNeedsSave(false); 0211 0212 m_runningModulesBeforeReconfigure = m_model->runningModules(); 0213 0214 // Is all of this really necessary? I would also think it to be fire and forget... 0215 // Only if changing autoload for a module may load/unload it, otherwise there's no point. 0216 // Autoload doesn't affect a running session and reloading the running modules is also useless then. 0217 auto call = m_kdedInterface->reconfigure(); 0218 QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(call, this); 0219 connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { 0220 QDBusPendingReply<void> reply = *watcher; 0221 watcher->deleteLater(); 0222 0223 if (reply.isError()) { 0224 Q_EMIT errorMessage(i18n("Failed to notify KDE Service Manager (kded6) of saved changed: %1", reply.error().message())); 0225 return; 0226 } 0227 0228 qCDebug(KCM_KDED) << "Successfully reconfigured kded"; 0229 getModuleStatus(); 0230 }); 0231 } 0232 0233 void KDEDConfig::defaults() 0234 { 0235 for (int i = 0; i < m_model->rowCount(); ++i) { 0236 const QModelIndex idx = m_model->index(i, 0); 0237 m_model->setData(idx, true, ModulesModel::AutoloadEnabledRole); 0238 } 0239 } 0240 0241 #include "kcmkded.moc" 0242 #include "moc_kcmkded.cpp"