File indexing completed on 2024-11-03 03:39:56
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1999 David Faure <faure@kde.org> 0004 SPDX-FileCopyrightText: 2000 Waldo Bastian <bastian@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-only 0007 */ 0008 0009 #include "kded.h" 0010 #include "kded_debug.h" 0011 #include "kded_version.h" 0012 #include "kdedadaptor.h" 0013 0014 #include <KCrash> 0015 0016 #include <qplatformdefs.h> 0017 0018 #include <QApplication> 0019 #include <QCommandLineParser> 0020 #include <QDir> 0021 #include <QLoggingCategory> 0022 #include <QProcess> 0023 0024 #include <QDBusConnection> 0025 #include <QDBusConnectionInterface> 0026 #include <QDBusServiceWatcher> 0027 0028 #include <KConfigGroup> 0029 #include <KDBusService> 0030 #include <KDirWatch> 0031 #include <KPluginFactory> 0032 #include <KPluginMetaData> 0033 #include <KSharedConfig> 0034 0035 #include <memory> 0036 0037 Kded *Kded::_self = nullptr; 0038 0039 static bool delayedCheck; 0040 static bool bCheckSycoca; 0041 static bool bCheckUpdates; 0042 0043 #ifdef Q_DBUS_EXPORT 0044 extern Q_DBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &)); 0045 #else 0046 extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &)); 0047 #endif 0048 0049 static void runKonfUpdate() 0050 { 0051 QProcess kconfUpdate; 0052 kconfUpdate.start(QStringLiteral(KCONF_UPDATE_EXE), QStringList()); 0053 kconfUpdate.waitForFinished(); 0054 } 0055 0056 Kded::Kded() 0057 : m_pDirWatch(new KDirWatch(this)) 0058 , m_pTimer(new QTimer(this)) 0059 , m_needDelayedCheck(false) 0060 { 0061 _self = this; 0062 0063 m_serviceWatcher = new QDBusServiceWatcher(this); 0064 m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); 0065 m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); 0066 QObject::connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &Kded::slotApplicationRemoved); 0067 0068 new KdedAdaptor(this); 0069 0070 QDBusConnection session = QDBusConnection::sessionBus(); 0071 session.registerObject(QStringLiteral("/kbuildsycoca"), this); 0072 session.registerObject(QStringLiteral("/kded"), this); 0073 0074 m_pTimer->setSingleShot(true); 0075 connect(m_pTimer, &QTimer::timeout, this, static_cast<void (Kded::*)()>(&Kded::recreate)); 0076 } 0077 0078 Kded::~Kded() 0079 { 0080 _self = nullptr; 0081 m_pTimer->stop(); 0082 0083 for (auto it = m_modules.cbegin(); it != m_modules.cend(); ++it) { 0084 delete *it; 0085 } 0086 m_modules.clear(); 0087 } 0088 0089 // on-demand module loading 0090 // this function is called by the D-Bus message processing function before 0091 // calls are delivered to objects 0092 void Kded::messageFilter(const QDBusMessage &message) 0093 { 0094 // This happens when kded goes down and some modules try to clean up. 0095 if (!self()) { 0096 return; 0097 } 0098 0099 QString obj = KDEDModule::moduleForMessage(message); 0100 if (obj.isEmpty() || obj == QLatin1String("ksycoca")) { 0101 return; 0102 } 0103 0104 if (self()->m_dontLoad.value(obj, nullptr)) { 0105 return; 0106 } 0107 0108 self()->loadModule(obj, true); 0109 } 0110 0111 static int phaseForModule(const KPluginMetaData &module) 0112 { 0113 return module.value(QStringLiteral("X-KDE-Kded-phase"), 2); 0114 } 0115 0116 QList<KPluginMetaData> Kded::availableModules() const 0117 { 0118 QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf6/kded")); 0119 QSet<QString> moduleIds; 0120 for (const KPluginMetaData &md : std::as_const(plugins)) { 0121 moduleIds.insert(md.pluginId()); 0122 } 0123 return plugins; 0124 } 0125 0126 static KPluginMetaData findModule(const QString &id) 0127 { 0128 KPluginMetaData module(QStringLiteral("kf6/kded/") + id); 0129 if (module.isValid()) { 0130 return module; 0131 } 0132 qCWarning(KDED) << "could not find kded module with id" << id; 0133 return KPluginMetaData(); 0134 } 0135 0136 void Kded::initModules() 0137 { 0138 m_dontLoad.clear(); 0139 0140 bool kde_running = !qEnvironmentVariableIsEmpty("KDE_FULL_SESSION"); 0141 if (kde_running) { 0142 // not the same user like the one running the session (most likely we're run via sudo or something) 0143 const QByteArray sessionUID = qgetenv("KDE_SESSION_UID"); 0144 if (!sessionUID.isEmpty() && uid_t(sessionUID.toInt()) != getuid()) { 0145 kde_running = false; 0146 } 0147 // not the same kde version as the current desktop 0148 const QByteArray kdeSession = qgetenv("KDE_SESSION_VERSION"); 0149 if (kdeSession.toInt() != 6) { 0150 kde_running = false; 0151 } 0152 } 0153 0154 // Preload kded modules. 0155 const QList<KPluginMetaData> kdedModules = availableModules(); 0156 for (const KPluginMetaData &module : kdedModules) { 0157 // Should the service load on startup? 0158 const bool autoload = isModuleAutoloaded(module); 0159 if (!platformSupportsModule(module)) { 0160 continue; 0161 } 0162 0163 // see ksmserver's README for description of the phases 0164 bool prevent_autoload = false; 0165 switch (phaseForModule(module)) { 0166 case 0: // always autoload 0167 break; 0168 case 1: // autoload only in KDE 0169 if (!kde_running) { 0170 prevent_autoload = true; 0171 } 0172 break; 0173 case 2: // autoload delayed, only in KDE 0174 default: 0175 if (!kde_running) { 0176 prevent_autoload = true; 0177 } 0178 break; 0179 } 0180 0181 // Load the module if necessary and allowed 0182 if (autoload && !prevent_autoload) { 0183 if (!loadModule(module, false)) { 0184 continue; 0185 } 0186 } 0187 0188 // Remember if the module is allowed to load on demand 0189 bool loadOnDemand = isModuleLoadedOnDemand(module); 0190 if (!loadOnDemand) { 0191 noDemandLoad(module.pluginId()); 0192 } 0193 0194 // In case of reloading the configuration it is possible for a module 0195 // to run even if it is now allowed to. Stop it then. 0196 if (!loadOnDemand && !autoload) { 0197 unloadModule(module.pluginId()); 0198 } 0199 } 0200 } 0201 0202 void Kded::noDemandLoad(const QString &obj) 0203 { 0204 m_dontLoad.insert(obj, this); 0205 } 0206 0207 void Kded::setModuleAutoloading(const QString &obj, bool autoload) 0208 { 0209 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kded5rc")); 0210 // Ensure the service exists. 0211 KPluginMetaData module = findModule(obj); 0212 if (!module.isValid()) { 0213 return; 0214 } 0215 KConfigGroup cg(config, QStringLiteral("Module-").append(module.pluginId())); 0216 cg.writeEntry("autoload", autoload); 0217 cg.sync(); 0218 } 0219 0220 bool Kded::isModuleAutoloaded(const QString &obj) const 0221 { 0222 return isModuleAutoloaded(findModule(obj)); 0223 } 0224 0225 bool Kded::isModuleAutoloaded(const KPluginMetaData &module) const 0226 { 0227 if (!module.isValid()) { 0228 return false; 0229 } 0230 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kded5rc")); 0231 bool autoload = module.value(QStringLiteral("X-KDE-Kded-autoload"), false); 0232 KConfigGroup cg(config, QStringLiteral("Module-").append(module.pluginId())); 0233 autoload = cg.readEntry("autoload", autoload); 0234 return autoload; 0235 } 0236 0237 bool Kded::platformSupportsModule(const KPluginMetaData &module) const 0238 { 0239 const QStringList supportedPlatforms = module.value(QStringLiteral("X-KDE-OnlyShowOnQtPlatforms"), QStringList()); 0240 0241 return supportedPlatforms.isEmpty() || supportedPlatforms.contains(qApp->platformName()); 0242 } 0243 0244 bool Kded::isModuleLoadedOnDemand(const QString &obj) const 0245 { 0246 return isModuleLoadedOnDemand(findModule(obj)); 0247 } 0248 0249 bool Kded::isModuleLoadedOnDemand(const KPluginMetaData &module) const 0250 { 0251 if (!module.isValid()) { 0252 return false; 0253 } 0254 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kded5rc")); 0255 return module.value(QStringLiteral("X-KDE-Kded-load-on-demand"), true); 0256 } 0257 0258 KDEDModule *Kded::loadModule(const QString &obj, bool onDemand) 0259 { 0260 // Make sure this method is only called with valid module names. 0261 if (obj.contains(QLatin1Char('/'))) { 0262 qCWarning(KDED) << "attempting to load invalid kded module name:" << obj; 0263 return nullptr; 0264 } 0265 KDEDModule *module = m_modules.value(obj, nullptr); 0266 if (module) { 0267 return module; 0268 } 0269 return loadModule(findModule(obj), onDemand); 0270 } 0271 0272 KDEDModule *Kded::loadModule(const KPluginMetaData &module, bool onDemand) 0273 { 0274 if (!module.isValid() || module.fileName().isEmpty()) { 0275 qCWarning(KDED) << "attempted to load an invalid module."; 0276 return nullptr; 0277 } 0278 const QString moduleId = module.pluginId(); 0279 KDEDModule *oldModule = m_modules.value(moduleId, nullptr); 0280 if (oldModule) { 0281 qCDebug(KDED) << "kded module" << moduleId << "is already loaded."; 0282 return oldModule; 0283 } 0284 0285 if (onDemand) { 0286 if (!module.value(QStringLiteral("X-KDE-Kded-load-on-demand"), true)) { 0287 noDemandLoad(moduleId); 0288 return nullptr; 0289 } 0290 } 0291 0292 KDEDModule *kdedModule = nullptr; 0293 0294 auto factoryResult = KPluginFactory::loadFactory(module); 0295 if (factoryResult) { 0296 kdedModule = factoryResult.plugin->create<KDEDModule>(this); 0297 } else { 0298 qCWarning(KDED).nospace() << "Could not load kded module " << moduleId << ":" << factoryResult.errorText << " (library path was:" << module.fileName() 0299 << ")"; 0300 } 0301 0302 if (kdedModule) { 0303 kdedModule->setModuleName(moduleId); 0304 m_modules.insert(moduleId, kdedModule); 0305 // m_libs.insert(moduleId, lib); 0306 qCDebug(KDED) << "Successfully loaded module" << moduleId; 0307 return kdedModule; 0308 } 0309 return nullptr; 0310 } 0311 0312 bool Kded::unloadModule(const QString &obj) 0313 { 0314 KDEDModule *module = m_modules.value(obj, nullptr); 0315 if (!module) { 0316 return false; 0317 } 0318 qCDebug(KDED) << "Unloading module" << obj; 0319 m_modules.remove(obj); 0320 delete module; 0321 return true; 0322 } 0323 0324 QStringList Kded::loadedModules() 0325 { 0326 return m_modules.keys(); 0327 } 0328 0329 void Kded::slotApplicationRemoved(const QString &name) 0330 { 0331 #if 0 // see kdedmodule.cpp (KDED_OBJECTS) 0332 foreach (KDEDModule *module, m_modules) { 0333 module->removeAll(appId); 0334 } 0335 #endif 0336 m_serviceWatcher->removeWatchedService(name); 0337 const QList<qlonglong> windowIds = m_windowIdList.value(name); 0338 for (const auto id : windowIds) { 0339 m_globalWindowIdList.remove(id); 0340 for (KDEDModule *module : std::as_const(m_modules)) { 0341 Q_EMIT module->windowUnregistered(id); 0342 } 0343 } 0344 m_windowIdList.remove(name); 0345 } 0346 0347 void Kded::updateDirWatch() 0348 { 0349 if (!bCheckUpdates) { 0350 return; 0351 } 0352 0353 delete m_pDirWatch; 0354 m_pDirWatch = new KDirWatch(this); 0355 0356 QObject::connect(m_pDirWatch, &KDirWatch::dirty, this, &Kded::update); 0357 QObject::connect(m_pDirWatch, &KDirWatch::created, this, &Kded::update); 0358 QObject::connect(m_pDirWatch, &KDirWatch::deleted, this, &Kded::dirDeleted); 0359 0360 // For each resource 0361 for (const QString &dir : std::as_const(m_allResourceDirs)) { 0362 readDirectory(dir); 0363 } 0364 0365 QStringList dataDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); 0366 for (auto &dir : dataDirs) { 0367 dir += QLatin1String("/icons"); 0368 if (!m_pDirWatch->contains(dir)) { 0369 m_pDirWatch->addDir(dir, KDirWatch::WatchDirOnly); 0370 } 0371 } 0372 } 0373 0374 void Kded::updateResourceList() 0375 { 0376 KSycoca::clearCaches(); 0377 0378 if (!bCheckUpdates) { 0379 return; 0380 } 0381 0382 if (delayedCheck) { 0383 return; 0384 } 0385 0386 const QStringList dirs = KSycoca::self()->allResourceDirs(); 0387 // For each resource 0388 for (const auto &dir : dirs) { 0389 if (!m_allResourceDirs.contains(dir)) { 0390 m_allResourceDirs.append(dir); 0391 readDirectory(dir); 0392 } 0393 } 0394 } 0395 0396 void Kded::recreate() 0397 { 0398 recreate(false); 0399 } 0400 0401 void Kded::runDelayedCheck() 0402 { 0403 if (m_needDelayedCheck) { 0404 recreate(false); 0405 } 0406 m_needDelayedCheck = false; 0407 } 0408 0409 void Kded::recreate(bool initial) 0410 { 0411 // Using KLauncher here is difficult since we might not have a 0412 // database 0413 0414 if (!initial) { 0415 updateDirWatch(); // Update tree first, to be sure to miss nothing. 0416 KSycoca::self()->ensureCacheValid(); 0417 recreateDone(); 0418 } else { 0419 if (!delayedCheck) { 0420 updateDirWatch(); // this would search all the directories 0421 } 0422 if (bCheckSycoca) { 0423 KSycoca::self()->ensureCacheValid(); 0424 } 0425 recreateDone(); 0426 if (delayedCheck) { 0427 // do a proper ksycoca check after a delay 0428 QTimer::singleShot(60000, this, &Kded::runDelayedCheck); 0429 m_needDelayedCheck = true; 0430 delayedCheck = false; 0431 } else { 0432 m_needDelayedCheck = false; 0433 } 0434 } 0435 } 0436 0437 void Kded::recreateDone() 0438 { 0439 updateResourceList(); 0440 0441 initModules(); 0442 } 0443 0444 void Kded::dirDeleted(const QString &path) 0445 { 0446 update(path); 0447 } 0448 0449 void Kded::update(const QString &path) 0450 { 0451 if (path.endsWith(QLatin1String("/icons")) && m_pDirWatch->contains(path)) { 0452 // If the dir was created or updated there could be new folders to merge into the active theme(s) 0453 QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KIconLoader"), QStringLiteral("org.kde.KIconLoader"), QStringLiteral("iconChanged")); 0454 message << 0; 0455 QDBusConnection::sessionBus().send(message); 0456 } else { 0457 m_pTimer->start(1000); 0458 } 0459 } 0460 0461 void Kded::readDirectory(const QString &_path) 0462 { 0463 QString path(_path); 0464 if (!path.endsWith(QLatin1Char('/'))) { 0465 path += QLatin1Char('/'); 0466 } 0467 0468 if (m_pDirWatch->contains(path)) { // Already seen this one? 0469 return; 0470 } 0471 0472 Q_ASSERT(path != QDir::homePath()); 0473 m_pDirWatch->addDir(path, KDirWatch::WatchFiles | KDirWatch::WatchSubDirs); // add watch on this dir 0474 } 0475 0476 void Kded::registerWindowId(qlonglong windowId, const QString &sender) 0477 { 0478 if (!m_windowIdList.contains(sender)) { 0479 m_serviceWatcher->addWatchedService(sender); 0480 } 0481 0482 m_globalWindowIdList.insert(windowId); 0483 QList<qlonglong> windowIds = m_windowIdList.value(sender); 0484 windowIds.append(windowId); 0485 m_windowIdList.insert(sender, windowIds); 0486 0487 for (KDEDModule *module : std::as_const(m_modules)) { 0488 qCDebug(KDED) << module->moduleName(); 0489 Q_EMIT module->windowRegistered(windowId); 0490 } 0491 } 0492 0493 void Kded::unregisterWindowId(qlonglong windowId, const QString &sender) 0494 { 0495 m_globalWindowIdList.remove(windowId); 0496 QList<qlonglong> windowIds = m_windowIdList.value(sender); 0497 if (!windowIds.isEmpty()) { 0498 windowIds.removeAll(windowId); 0499 if (windowIds.isEmpty()) { 0500 m_serviceWatcher->removeWatchedService(sender); 0501 m_windowIdList.remove(sender); 0502 } else { 0503 m_windowIdList.insert(sender, windowIds); 0504 } 0505 } 0506 0507 for (KDEDModule *module : std::as_const(m_modules)) { 0508 qCDebug(KDED) << module->moduleName(); 0509 Q_EMIT module->windowUnregistered(windowId); 0510 } 0511 } 0512 0513 static void sighandler(int /*sig*/) 0514 { 0515 if (qApp) { 0516 qApp->quit(); 0517 } 0518 } 0519 0520 KUpdateD::KUpdateD() 0521 { 0522 m_pDirWatch = new KDirWatch(this); 0523 m_pTimer = new QTimer(this); 0524 m_pTimer->setSingleShot(true); 0525 connect(m_pTimer, &QTimer::timeout, this, &KUpdateD::runKonfUpdate); 0526 QObject::connect(m_pDirWatch, &KDirWatch::dirty, this, &KUpdateD::slotNewUpdateFile); 0527 0528 QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kconf_update"), QStandardPaths::LocateDirectory); 0529 for (auto &path : dirs) { 0530 Q_ASSERT(path != QDir::homePath()); 0531 if (!path.endsWith(QLatin1Char('/'))) { 0532 path += QLatin1Char('/'); 0533 } 0534 0535 if (!m_pDirWatch->contains(path)) { 0536 m_pDirWatch->addDir(path, KDirWatch::WatchFiles); 0537 } 0538 } 0539 } 0540 0541 KUpdateD::~KUpdateD() 0542 { 0543 } 0544 0545 void KUpdateD::runKonfUpdate() 0546 { 0547 ::runKonfUpdate(); 0548 } 0549 0550 void KUpdateD::slotNewUpdateFile(const QString &dirty) 0551 { 0552 Q_UNUSED(dirty); 0553 qCDebug(KDED) << dirty; 0554 m_pTimer->start(500); 0555 } 0556 0557 static void setupAppInfo(QApplication *app) 0558 { 0559 app->setApplicationName(QStringLiteral("kded6")); 0560 app->setOrganizationDomain(QStringLiteral("kde.org")); 0561 app->setApplicationVersion(QStringLiteral(KDED_VERSION_STRING)); 0562 } 0563 0564 static bool detectPlatform(int argc, char **argv) 0565 { 0566 if (qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) { 0567 return false; 0568 } 0569 for (int i = 0; i < argc; i++) { 0570 /* clang-format off */ 0571 if (qstrcmp(argv[i], "-platform") == 0 0572 || qstrcmp(argv[i], "--platform") == 0 0573 || QByteArrayView(argv[i]).startsWith("-platform=") 0574 || QByteArrayView(argv[i]).startsWith("--platform=")) { /* clang-format on */ 0575 return false; 0576 } 0577 } 0578 const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE"); 0579 if (sessionType.isEmpty()) { 0580 return false; 0581 } 0582 if (qstrcmp(sessionType.data(), "wayland") == 0) { 0583 qputenv("QT_QPA_PLATFORM", "wayland"); 0584 return true; 0585 } else if (qstrcmp(sessionType.data(), "x11") == 0) { 0586 qputenv("QT_QPA_PLATFORM", "xcb"); 0587 return true; 0588 } 0589 return false; 0590 } 0591 0592 int main(int argc, char *argv[]) 0593 { 0594 // options.add("check", qi18n("Check Sycoca database only once")); 0595 0596 // WABA: Make sure not to enable session management. 0597 qunsetenv("SESSION_MANAGER"); 0598 0599 const bool unsetQpa = detectPlatform(argc, argv); 0600 0601 // In older versions, QApplication creation was postponed until after 0602 // testing for --check, in which case, only a QCoreApplication was created. 0603 // Since that option is no longer used at startup, we removed that speed 0604 // optimization for code clarity and easier support of standard parameters. 0605 0606 QApplication app(argc, argv); 0607 if (unsetQpa) { 0608 qunsetenv("QT_QPA_PLATFORM"); 0609 } 0610 setupAppInfo(&app); 0611 app.setQuitOnLastWindowClosed(false); 0612 app.setQuitLockEnabled(false); 0613 0614 QCommandLineParser parser; 0615 parser.addHelpOption(); 0616 parser.addVersionOption(); 0617 parser.addOption(QCommandLineOption(QStringLiteral("check"), QStringLiteral("Check cache validity"))); 0618 QCommandLineOption replaceOption({QStringLiteral("replace")}, QStringLiteral("Replace an existing instance")); 0619 parser.addOption(replaceOption); 0620 parser.process(app); 0621 0622 // Parse command line before checking D-Bus 0623 if (parser.isSet(QStringLiteral("check"))) { 0624 // KDBusService not wanted here. 0625 KSycoca::self()->ensureCacheValid(); 0626 runKonfUpdate(); 0627 return 0; 0628 } 0629 0630 // Qt now has DBus in another thread, so we need to handle any messages 0631 // between the service registration and our paths existing 0632 // This means adding the spy now, so any received message gets 0633 // posted to the main thread 0634 qDBusAddSpyHook(Kded::messageFilter); 0635 0636 QDBusConnectionInterface *bus = QDBusConnection::sessionBus().interface(); 0637 // Also register as all the names we should respond to (org.kde.kcookiejar, org.kde.khotkeys etc.) 0638 // so that the calling code is independent from the physical "location" of the service. 0639 const QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf6/kded")); 0640 for (const KPluginMetaData &metaData : plugins) { 0641 const QString serviceName = metaData.value(QStringLiteral("X-KDE-DBus-ServiceName")); 0642 if (serviceName.isEmpty()) { 0643 continue; 0644 } 0645 // register them queued as an old kded could be running at this point 0646 if (!bus->registerService(serviceName, QDBusConnectionInterface::QueueService)) { 0647 qCWarning(KDED) << "Couldn't register name" << serviceName << "with DBUS - another process owns it already!"; 0648 } 0649 } 0650 KDBusService service(KDBusService::Unique | KDBusService::StartupOption(parser.isSet(replaceOption) ? KDBusService::Replace : 0)); 0651 0652 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kded5rc")); 0653 KConfigGroup cg(config, QStringLiteral("General")); 0654 0655 bCheckSycoca = cg.readEntry("CheckSycoca", true); 0656 bCheckUpdates = cg.readEntry("CheckUpdates", true); 0657 delayedCheck = cg.readEntry("DelayedCheck", false); 0658 0659 signal(SIGTERM, sighandler); 0660 signal(SIGHUP, sighandler); 0661 0662 KCrash::setFlags(KCrash::AutoRestart); 0663 0664 std::unique_ptr<Kded> kded = std::make_unique<Kded>(); 0665 0666 kded->recreate(true); // initial 0667 0668 if (bCheckUpdates) { 0669 (void)new KUpdateD; // Watch for updates 0670 } 0671 0672 runKonfUpdate(); // Run it once. 0673 0674 return app.exec(); // keep running 0675 } 0676 0677 #include "moc_kded.cpp"