File indexing completed on 2024-12-01 09:48:49
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_version.h" 0011 #include "kdedadaptor.h" 0012 0013 #include <KCrash> 0014 0015 #include <qplatformdefs.h> 0016 0017 #include <QApplication> 0018 #include <QCommandLineParser> 0019 #include <QDir> 0020 #include <QLoggingCategory> 0021 #include <QProcess> 0022 0023 #include <QDBusConnection> 0024 #include <QDBusConnectionInterface> 0025 #include <QDBusServiceWatcher> 0026 0027 #include <KConfigGroup> 0028 #include <KDBusService> 0029 #include <KDirWatch> 0030 #include <KPluginFactory> 0031 #include <KPluginInfo> 0032 #include <KPluginMetaData> 0033 #include <KServiceTypeTrader> 0034 #include <KSharedConfig> 0035 0036 #ifdef Q_OS_OSX 0037 #include <CoreFoundation/CoreFoundation.h> 0038 #endif 0039 0040 #include <memory> 0041 0042 Q_DECLARE_LOGGING_CATEGORY(KDED) 0043 0044 Q_LOGGING_CATEGORY(KDED, "kf.kded", QtWarningMsg) 0045 0046 Kded *Kded::_self = nullptr; 0047 0048 static bool delayedCheck; 0049 static bool bCheckSycoca; 0050 static bool bCheckUpdates; 0051 0052 #ifdef Q_DBUS_EXPORT 0053 extern Q_DBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &)); 0054 #else 0055 extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &)); 0056 #endif 0057 0058 static void runKonfUpdate() 0059 { 0060 QProcess kconfUpdate; 0061 kconfUpdate.start(QStringLiteral(KCONF_UPDATE_EXE), QStringList()); 0062 kconfUpdate.waitForFinished(); 0063 } 0064 0065 Kded::Kded() 0066 : m_pDirWatch(new KDirWatch(this)) 0067 , m_pTimer(new QTimer(this)) 0068 , m_needDelayedCheck(false) 0069 { 0070 _self = this; 0071 0072 m_serviceWatcher = new QDBusServiceWatcher(this); 0073 m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); 0074 m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); 0075 QObject::connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &Kded::slotApplicationRemoved); 0076 0077 new KBuildsycocaAdaptor(this); 0078 new KdedAdaptor(this); 0079 0080 QDBusConnection session = QDBusConnection::sessionBus(); 0081 session.registerObject(QStringLiteral("/kbuildsycoca"), this); 0082 session.registerObject(QStringLiteral("/kded"), this); 0083 0084 qDBusAddSpyHook(messageFilter); 0085 0086 m_pTimer->setSingleShot(true); 0087 connect(m_pTimer, &QTimer::timeout, this, static_cast<void (Kded::*)()>(&Kded::recreate)); 0088 } 0089 0090 Kded::~Kded() 0091 { 0092 _self = nullptr; 0093 m_pTimer->stop(); 0094 0095 for (auto it = m_modules.cbegin(); it != m_modules.cend(); ++it) { 0096 KDEDModule *module(it.value()); 0097 0098 // first disconnect otherwise slotKDEDModuleRemoved() is called 0099 // and changes m_modules while we're iterating over it 0100 disconnect(module, &KDEDModule::moduleDeleted, this, &Kded::slotKDEDModuleRemoved); 0101 0102 delete module; 0103 } 0104 } 0105 0106 // on-demand module loading 0107 // this function is called by the D-Bus message processing function before 0108 // calls are delivered to objects 0109 void Kded::messageFilter(const QDBusMessage &message) 0110 { 0111 // This happens when kded goes down and some modules try to clean up. 0112 if (!self()) { 0113 return; 0114 } 0115 0116 QString obj = KDEDModule::moduleForMessage(message); 0117 if (obj.isEmpty() || obj == QLatin1String("ksycoca")) { 0118 return; 0119 } 0120 0121 if (self()->m_dontLoad.value(obj, nullptr)) { 0122 return; 0123 } 0124 0125 self()->loadModule(obj, true); 0126 } 0127 0128 static int phaseForModule(const KPluginMetaData &module) 0129 { 0130 return module.value(QStringLiteral("X-KDE-Kded-phase"), 2); 0131 } 0132 0133 QVector<KPluginMetaData> Kded::availableModules() const 0134 { 0135 QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/kded")); 0136 QSet<QString> moduleIds; 0137 for (const KPluginMetaData &md : std::as_const(plugins)) { 0138 moduleIds.insert(md.pluginId()); 0139 } 0140 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0141 // also search for old .desktop based kded modules 0142 QT_WARNING_PUSH 0143 QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") 0144 QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") 0145 const KPluginInfo::List oldStylePlugins = KPluginInfo::fromServices(KServiceTypeTrader::self()->query(QStringLiteral("KDEDModule"))); 0146 QT_WARNING_POP 0147 for (const KPluginInfo &info : oldStylePlugins) { 0148 if (moduleIds.contains(info.pluginName())) { 0149 qCWarning(KDED).nospace() << "kded module " << info.pluginName() 0150 << " has already been found using " 0151 "JSON metadata, please don't install the now unneeded .desktop file (" 0152 << info.entryPath() << ")."; 0153 } else { 0154 qCDebug(KDED).nospace() << "kded module " << info.pluginName() << " still uses .desktop files (" << info.entryPath() 0155 << "). Please port it to JSON metadata."; 0156 plugins.append(info.toMetaData()); 0157 } 0158 } 0159 #endif 0160 return plugins; 0161 } 0162 0163 static KPluginMetaData findModule(const QString &id) 0164 { 0165 KPluginMetaData module(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/kded/") + id); 0166 if (module.isValid()) { 0167 return module; 0168 } 0169 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0170 // TODO KF6: remove the .desktop fallback code 0171 KService::Ptr oldStyleModule = KService::serviceByDesktopPath(QStringLiteral("kded/") + id + QStringLiteral(".desktop")); 0172 if (oldStyleModule) { 0173 qCDebug(KDED).nospace() << "kded module " << oldStyleModule->desktopEntryName() << " still uses .desktop files (" << oldStyleModule->entryPath() 0174 << "). Please port it to JSON metadata."; 0175 QT_WARNING_PUSH 0176 QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") 0177 QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") 0178 return KPluginInfo(oldStyleModule).toMetaData(); 0179 QT_WARNING_POP 0180 } 0181 #endif 0182 qCWarning(KDED) << "could not find kded module with id" << id; 0183 return KPluginMetaData(); 0184 } 0185 0186 void Kded::initModules() 0187 { 0188 m_dontLoad.clear(); 0189 #ifdef Q_OS_OSX 0190 // it seems there is no reason to honour KDE_FULL_SESSION on OS X even if it's set for some reason. 0191 // That way kdeinit5 is always auto-started if required (and the kded is as good a candidate 0192 // for starting this service as any other application). 0193 bool kde_running = false; 0194 #else 0195 bool kde_running = !qEnvironmentVariableIsEmpty("KDE_FULL_SESSION"); 0196 #endif 0197 if (kde_running) { 0198 #ifndef Q_OS_WIN 0199 // not the same user like the one running the session (most likely we're run via sudo or something) 0200 const QByteArray sessionUID = qgetenv("KDE_SESSION_UID"); 0201 if (!sessionUID.isEmpty() && uid_t(sessionUID.toInt()) != getuid()) { 0202 kde_running = false; 0203 } 0204 #endif 0205 // TODO: Change 5 to KDED_VERSION_MAJOR the moment KF5 are stable 0206 // not the same kde version as the current desktop 0207 const QByteArray kdeSession = qgetenv("KDE_SESSION_VERSION"); 0208 if (kdeSession.toInt() != 5) { 0209 kde_running = false; 0210 } 0211 } 0212 0213 // Preload kded modules. 0214 const QVector<KPluginMetaData> kdedModules = availableModules(); 0215 for (const KPluginMetaData &module : kdedModules) { 0216 // Should the service load on startup? 0217 const bool autoload = isModuleAutoloaded(module); 0218 if (!platformSupportsModule(module)) { 0219 continue; 0220 } 0221 0222 // see ksmserver's README for description of the phases 0223 bool prevent_autoload = false; 0224 switch (phaseForModule(module)) { 0225 case 0: // always autoload 0226 break; 0227 case 1: // autoload only in KDE 0228 if (!kde_running) { 0229 prevent_autoload = true; 0230 } 0231 break; 0232 case 2: // autoload delayed, only in KDE 0233 default: 0234 if (!kde_running) { 0235 prevent_autoload = true; 0236 } 0237 break; 0238 } 0239 0240 // Load the module if necessary and allowed 0241 if (autoload && !prevent_autoload) { 0242 if (!loadModule(module, false)) { 0243 continue; 0244 } 0245 } 0246 0247 // Remember if the module is allowed to load on demand 0248 bool loadOnDemand = isModuleLoadedOnDemand(module); 0249 if (!loadOnDemand) { 0250 noDemandLoad(module.pluginId()); 0251 } 0252 0253 // In case of reloading the configuration it is possible for a module 0254 // to run even if it is now allowed to. Stop it then. 0255 if (!loadOnDemand && !autoload) { 0256 unloadModule(module.pluginId()); 0257 } 0258 } 0259 } 0260 0261 void Kded::loadSecondPhase() 0262 { 0263 qCDebug(KDED) << "Second phase autoload is deprecated"; 0264 } 0265 0266 void Kded::noDemandLoad(const QString &obj) 0267 { 0268 m_dontLoad.insert(obj, this); 0269 } 0270 0271 void Kded::setModuleAutoloading(const QString &obj, bool autoload) 0272 { 0273 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0274 // Ensure the service exists. 0275 KPluginMetaData module = findModule(obj); 0276 if (!module.isValid()) { 0277 return; 0278 } 0279 KConfigGroup cg(config, QStringLiteral("Module-").append(module.pluginId())); 0280 cg.writeEntry("autoload", autoload); 0281 cg.sync(); 0282 } 0283 0284 bool Kded::isModuleAutoloaded(const QString &obj) const 0285 { 0286 return isModuleAutoloaded(findModule(obj)); 0287 } 0288 0289 bool Kded::isModuleAutoloaded(const KPluginMetaData &module) const 0290 { 0291 if (!module.isValid()) { 0292 return false; 0293 } 0294 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0295 bool autoload = module.value(QStringLiteral("X-KDE-Kded-autoload"), false); 0296 KConfigGroup cg(config, QStringLiteral("Module-").append(module.pluginId())); 0297 autoload = cg.readEntry("autoload", autoload); 0298 return autoload; 0299 } 0300 0301 bool Kded::platformSupportsModule(const KPluginMetaData &module) const 0302 { 0303 const QStringList supportedPlatforms = module.value(QStringLiteral("X-KDE-OnlyShowOnQtPlatforms"), QStringList()); 0304 0305 return supportedPlatforms.isEmpty() || supportedPlatforms.contains(qApp->platformName()); 0306 } 0307 0308 bool Kded::isModuleLoadedOnDemand(const QString &obj) const 0309 { 0310 return isModuleLoadedOnDemand(findModule(obj)); 0311 } 0312 0313 bool Kded::isModuleLoadedOnDemand(const KPluginMetaData &module) const 0314 { 0315 if (!module.isValid()) { 0316 return false; 0317 } 0318 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0319 return module.value(QStringLiteral("X-KDE-Kded-load-on-demand"), true); 0320 } 0321 0322 KDEDModule *Kded::loadModule(const QString &obj, bool onDemand) 0323 { 0324 // Make sure this method is only called with valid module names. 0325 if (obj.contains(QLatin1Char('/'))) { 0326 qCWarning(KDED) << "attempting to load invalid kded module name:" << obj; 0327 return nullptr; 0328 } 0329 KDEDModule *module = m_modules.value(obj, nullptr); 0330 if (module) { 0331 return module; 0332 } 0333 return loadModule(findModule(obj), onDemand); 0334 } 0335 0336 KDEDModule *Kded::loadModule(const KPluginMetaData &module, bool onDemand) 0337 { 0338 if (!module.isValid() || module.fileName().isEmpty()) { 0339 qCWarning(KDED) << "attempted to load an invalid module."; 0340 return nullptr; 0341 } 0342 const QString moduleId = module.pluginId(); 0343 KDEDModule *oldModule = m_modules.value(moduleId, nullptr); 0344 if (oldModule) { 0345 qCDebug(KDED) << "kded module" << moduleId << "is already loaded."; 0346 return oldModule; 0347 } 0348 0349 if (onDemand) { 0350 if (!module.value(QStringLiteral("X-KDE-Kded-load-on-demand"), true)) { 0351 noDemandLoad(moduleId); 0352 return nullptr; 0353 } 0354 } 0355 0356 KDEDModule *kdedModule = nullptr; 0357 0358 auto factoryResult = KPluginFactory::loadFactory(module); 0359 if (factoryResult) { 0360 kdedModule = factoryResult.plugin->create<KDEDModule>(this); 0361 } else { 0362 // TODO: remove this fallback code, the kded modules should all be fixed instead 0363 factoryResult = KPluginFactory::loadFactory(KPluginMetaData(QStringLiteral("kded_") + module.fileName())); 0364 if (factoryResult) { 0365 qCWarning(KDED).nospace() << "found kded module " << moduleId << " by prepending 'kded_' to the library path, please fix your metadata."; 0366 kdedModule = factoryResult.plugin->create<KDEDModule>(this); 0367 } else { 0368 qCWarning(KDED).nospace() << "Could not load kded module " << moduleId << ":" << factoryResult.errorText 0369 << " (library path was:" << module.fileName() << ")"; 0370 } 0371 } 0372 0373 if (kdedModule) { 0374 kdedModule->setModuleName(moduleId); 0375 m_modules.insert(moduleId, kdedModule); 0376 // m_libs.insert(moduleId, lib); 0377 connect(kdedModule, &KDEDModule::moduleDeleted, this, &Kded::slotKDEDModuleRemoved); 0378 qCDebug(KDED) << "Successfully loaded module" << moduleId; 0379 return kdedModule; 0380 } 0381 return nullptr; 0382 } 0383 0384 bool Kded::unloadModule(const QString &obj) 0385 { 0386 KDEDModule *module = m_modules.value(obj, nullptr); 0387 if (!module) { 0388 return false; 0389 } 0390 qCDebug(KDED) << "Unloading module" << obj; 0391 m_modules.remove(obj); 0392 delete module; 0393 return true; 0394 } 0395 0396 QStringList Kded::loadedModules() 0397 { 0398 return m_modules.keys(); 0399 } 0400 0401 void Kded::slotKDEDModuleRemoved(KDEDModule *module) 0402 { 0403 m_modules.remove(module->moduleName()); 0404 } 0405 0406 void Kded::slotApplicationRemoved(const QString &name) 0407 { 0408 #if 0 // see kdedmodule.cpp (KDED_OBJECTS) 0409 foreach (KDEDModule *module, m_modules) { 0410 module->removeAll(appId); 0411 } 0412 #endif 0413 m_serviceWatcher->removeWatchedService(name); 0414 const QList<qlonglong> windowIds = m_windowIdList.value(name); 0415 for (const auto id : windowIds) { 0416 m_globalWindowIdList.remove(id); 0417 for (KDEDModule *module : std::as_const(m_modules)) { 0418 Q_EMIT module->windowUnregistered(id); 0419 } 0420 } 0421 m_windowIdList.remove(name); 0422 } 0423 0424 void Kded::updateDirWatch() 0425 { 0426 if (!bCheckUpdates) { 0427 return; 0428 } 0429 0430 delete m_pDirWatch; 0431 m_pDirWatch = new KDirWatch(this); 0432 0433 QObject::connect(m_pDirWatch, &KDirWatch::dirty, this, &Kded::update); 0434 QObject::connect(m_pDirWatch, &KDirWatch::created, this, &Kded::update); 0435 QObject::connect(m_pDirWatch, &KDirWatch::deleted, this, &Kded::dirDeleted); 0436 0437 // For each resource 0438 for (const QString &dir : std::as_const(m_allResourceDirs)) { 0439 readDirectory(dir); 0440 } 0441 0442 QStringList dataDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); 0443 for (auto &dir : dataDirs) { 0444 dir += QLatin1String("/icons"); 0445 if (!m_pDirWatch->contains(dir)) { 0446 m_pDirWatch->addDir(dir, KDirWatch::WatchDirOnly); 0447 } 0448 } 0449 } 0450 0451 void Kded::updateResourceList() 0452 { 0453 KSycoca::clearCaches(); 0454 0455 if (!bCheckUpdates) { 0456 return; 0457 } 0458 0459 if (delayedCheck) { 0460 return; 0461 } 0462 0463 const QStringList dirs = KSycoca::self()->allResourceDirs(); 0464 // For each resource 0465 for (const auto &dir : dirs) { 0466 if (!m_allResourceDirs.contains(dir)) { 0467 m_allResourceDirs.append(dir); 0468 readDirectory(dir); 0469 } 0470 } 0471 } 0472 0473 void Kded::recreate() 0474 { 0475 recreate(false); 0476 } 0477 0478 void Kded::runDelayedCheck() 0479 { 0480 if (m_needDelayedCheck) { 0481 recreate(false); 0482 } 0483 m_needDelayedCheck = false; 0484 } 0485 0486 void Kded::recreate(bool initial) 0487 { 0488 // Using KLauncher here is difficult since we might not have a 0489 // database 0490 0491 if (!initial) { 0492 updateDirWatch(); // Update tree first, to be sure to miss nothing. 0493 KSycoca::self()->ensureCacheValid(); 0494 recreateDone(); 0495 } else { 0496 if (!delayedCheck) { 0497 updateDirWatch(); // this would search all the directories 0498 } 0499 if (bCheckSycoca) { 0500 KSycoca::self()->ensureCacheValid(); 0501 } 0502 recreateDone(); 0503 if (delayedCheck) { 0504 // do a proper ksycoca check after a delay 0505 QTimer::singleShot(60000, this, &Kded::runDelayedCheck); 0506 m_needDelayedCheck = true; 0507 delayedCheck = false; 0508 } else { 0509 m_needDelayedCheck = false; 0510 } 0511 } 0512 } 0513 0514 void Kded::recreateDone() 0515 { 0516 updateResourceList(); 0517 0518 initModules(); 0519 } 0520 0521 void Kded::dirDeleted(const QString &path) 0522 { 0523 update(path); 0524 } 0525 0526 void Kded::update(const QString &path) 0527 { 0528 if (path.endsWith(QLatin1String("/icons")) && m_pDirWatch->contains(path)) { 0529 // If the dir was created or updated there could be new folders to merge into the active theme(s) 0530 QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KIconLoader"), QStringLiteral("org.kde.KIconLoader"), QStringLiteral("iconChanged")); 0531 message << 0; 0532 QDBusConnection::sessionBus().send(message); 0533 } else { 0534 m_pTimer->start(1000); 0535 } 0536 } 0537 0538 void Kded::readDirectory(const QString &_path) 0539 { 0540 QString path(_path); 0541 if (!path.endsWith(QLatin1Char('/'))) { 0542 path += QLatin1Char('/'); 0543 } 0544 0545 if (m_pDirWatch->contains(path)) { // Already seen this one? 0546 return; 0547 } 0548 0549 Q_ASSERT(path != QDir::homePath()); 0550 m_pDirWatch->addDir(path, KDirWatch::WatchFiles | KDirWatch::WatchSubDirs); // add watch on this dir 0551 } 0552 0553 void Kded::registerWindowId(qlonglong windowId, const QString &sender) 0554 { 0555 if (!m_windowIdList.contains(sender)) { 0556 m_serviceWatcher->addWatchedService(sender); 0557 } 0558 0559 m_globalWindowIdList.insert(windowId); 0560 QList<qlonglong> windowIds = m_windowIdList.value(sender); 0561 windowIds.append(windowId); 0562 m_windowIdList.insert(sender, windowIds); 0563 0564 for (KDEDModule *module : std::as_const(m_modules)) { 0565 qCDebug(KDED) << module->moduleName(); 0566 Q_EMIT module->windowRegistered(windowId); 0567 } 0568 } 0569 0570 void Kded::unregisterWindowId(qlonglong windowId, const QString &sender) 0571 { 0572 m_globalWindowIdList.remove(windowId); 0573 QList<qlonglong> windowIds = m_windowIdList.value(sender); 0574 if (!windowIds.isEmpty()) { 0575 windowIds.removeAll(windowId); 0576 if (windowIds.isEmpty()) { 0577 m_serviceWatcher->removeWatchedService(sender); 0578 m_windowIdList.remove(sender); 0579 } else { 0580 m_windowIdList.insert(sender, windowIds); 0581 } 0582 } 0583 0584 for (KDEDModule *module : std::as_const(m_modules)) { 0585 qCDebug(KDED) << module->moduleName(); 0586 Q_EMIT module->windowUnregistered(windowId); 0587 } 0588 } 0589 0590 static void sighandler(int /*sig*/) 0591 { 0592 if (qApp) { 0593 qApp->quit(); 0594 } 0595 } 0596 0597 KUpdateD::KUpdateD() 0598 { 0599 m_pDirWatch = new KDirWatch(this); 0600 m_pTimer = new QTimer(this); 0601 m_pTimer->setSingleShot(true); 0602 connect(m_pTimer, &QTimer::timeout, this, &KUpdateD::runKonfUpdate); 0603 QObject::connect(m_pDirWatch, &KDirWatch::dirty, this, &KUpdateD::slotNewUpdateFile); 0604 0605 QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kconf_update"), QStandardPaths::LocateDirectory); 0606 for (auto &path : dirs) { 0607 Q_ASSERT(path != QDir::homePath()); 0608 if (!path.endsWith(QLatin1Char('/'))) { 0609 path += QLatin1Char('/'); 0610 } 0611 0612 if (!m_pDirWatch->contains(path)) { 0613 m_pDirWatch->addDir(path, KDirWatch::WatchFiles); 0614 } 0615 } 0616 } 0617 0618 KUpdateD::~KUpdateD() 0619 { 0620 } 0621 0622 void KUpdateD::runKonfUpdate() 0623 { 0624 ::runKonfUpdate(); 0625 } 0626 0627 void KUpdateD::slotNewUpdateFile(const QString &dirty) 0628 { 0629 Q_UNUSED(dirty); 0630 qCDebug(KDED) << dirty; 0631 m_pTimer->start(500); 0632 } 0633 0634 KBuildsycocaAdaptor::KBuildsycocaAdaptor(QObject *parent) 0635 : QDBusAbstractAdaptor(parent) 0636 { 0637 } 0638 0639 void KBuildsycocaAdaptor::recreate() 0640 { 0641 Kded::self()->recreate(); 0642 } 0643 0644 // KF6: remove 0645 bool KBuildsycocaAdaptor::isTestModeEnabled() 0646 { 0647 return QStandardPaths::isTestModeEnabled(); 0648 } 0649 0650 // KF6: remove 0651 void KBuildsycocaAdaptor::setTestModeEnabled() 0652 { 0653 QStandardPaths::setTestModeEnabled(true); 0654 } 0655 0656 static void setupAppInfo(QApplication *app) 0657 { 0658 app->setApplicationName(QStringLiteral("kded5")); 0659 app->setApplicationDisplayName(QStringLiteral("KDE Daemon")); 0660 app->setOrganizationDomain(QStringLiteral("kde.org")); 0661 app->setApplicationVersion(QStringLiteral(KDED_VERSION_STRING)); 0662 } 0663 0664 static bool detectPlatform(int argc, char **argv) 0665 { 0666 if (qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) { 0667 return false; 0668 } 0669 for (int i = 0; i < argc; i++) { 0670 /* clang-format off */ 0671 if (qstrcmp(argv[i], "-platform") == 0 0672 || qstrcmp(argv[i], "--platform") == 0 0673 || QByteArray(argv[i]).startsWith("-platform=") 0674 || QByteArray(argv[i]).startsWith("--platform=")) { /* clang-format on */ 0675 return false; 0676 } 0677 } 0678 const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE"); 0679 if (sessionType.isEmpty()) { 0680 return false; 0681 } 0682 if (qstrcmp(sessionType.data(), "wayland") == 0) { 0683 qputenv("QT_QPA_PLATFORM", "wayland"); 0684 return true; 0685 } else if (qstrcmp(sessionType.data(), "x11") == 0) { 0686 qputenv("QT_QPA_PLATFORM", "xcb"); 0687 return true; 0688 } 0689 return false; 0690 } 0691 0692 int main(int argc, char *argv[]) 0693 { 0694 #ifdef Q_OS_OSX 0695 CFBundleRef mainBundle = CFBundleGetMainBundle(); 0696 if (mainBundle) { 0697 // get the application's Info Dictionary. For app bundles this would live in the bundle's Info.plist, 0698 // for regular executables it is obtained in another way. 0699 CFMutableDictionaryRef infoDict = (CFMutableDictionaryRef)CFBundleGetInfoDictionary(mainBundle); 0700 if (infoDict) { 0701 // Add or set the "LSUIElement" key with/to value "1". This can simply be a CFString. 0702 CFDictionarySetValue(infoDict, CFSTR("LSUIElement"), CFSTR("1")); 0703 // That's it. We're now considered as an "agent" by the window server, and thus will have 0704 // neither menubar nor presence in the Dock or App Switcher. 0705 } 0706 } 0707 #endif 0708 // options.add("check", qi18n("Check Sycoca database only once")); 0709 0710 // WABA: Make sure not to enable session management. 0711 qunsetenv("SESSION_MANAGER"); 0712 0713 const bool unsetQpa = detectPlatform(argc, argv); 0714 0715 // In older versions, QApplication creation was postponed until after 0716 // testing for --check, in which case, only a QCoreApplication was created. 0717 // Since that option is no longer used at startup, we removed that speed 0718 // optimization for code clarity and easier support of standard parameters. 0719 0720 // Fixes blurry icons with Fractional scaling 0721 QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); 0722 QApplication app(argc, argv); 0723 if (unsetQpa) { 0724 qunsetenv("QT_QPA_PLATFORM"); 0725 } 0726 setupAppInfo(&app); 0727 app.setQuitOnLastWindowClosed(false); 0728 0729 QCommandLineParser parser; 0730 parser.addHelpOption(); 0731 parser.addVersionOption(); 0732 parser.addOption(QCommandLineOption(QStringLiteral("check"), QStringLiteral("Check cache validity"))); 0733 QCommandLineOption replaceOption({QStringLiteral("replace")}, QStringLiteral("Replace an existing instance")); 0734 parser.addOption(replaceOption); 0735 parser.process(app); 0736 0737 // Parse command line before checking D-Bus 0738 if (parser.isSet(QStringLiteral("check"))) { 0739 // KDBusService not wanted here. 0740 KSycoca::self()->ensureCacheValid(); 0741 runKonfUpdate(); 0742 return 0; 0743 } 0744 0745 KDBusService service(KDBusService::Unique | KDBusService::StartupOption(parser.isSet(replaceOption) ? KDBusService::Replace : 0)); 0746 0747 QDBusConnectionInterface *bus = QDBusConnection::sessionBus().interface(); 0748 // Also register as all the names we should respond to (org.kde.kcookiejar, org.kde.khotkeys etc.) 0749 // so that the calling code is independent from the physical "location" of the service. 0750 const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/kded")); 0751 for (const KPluginMetaData &metaData : plugins) { 0752 const QString serviceName = metaData.value(QStringLiteral("X-KDE-DBus-ServiceName")); 0753 if (serviceName.isEmpty()) { 0754 continue; 0755 } 0756 if (!bus->registerService(serviceName)) { 0757 qCWarning(KDED) << "Couldn't register name" << serviceName << "with DBUS - another process owns it already!"; 0758 } 0759 } 0760 0761 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0762 KConfigGroup cg(config, "General"); 0763 0764 bCheckSycoca = cg.readEntry("CheckSycoca", true); 0765 bCheckUpdates = cg.readEntry("CheckUpdates", true); 0766 delayedCheck = cg.readEntry("DelayedCheck", false); 0767 0768 #ifndef Q_OS_WIN 0769 signal(SIGTERM, sighandler); 0770 signal(SIGHUP, sighandler); 0771 #endif 0772 0773 KCrash::setFlags(KCrash::AutoRestart); 0774 0775 std::unique_ptr<Kded> kded = std::make_unique<Kded>(); 0776 0777 kded->recreate(true); // initial 0778 0779 if (bCheckUpdates) { 0780 (void)new KUpdateD; // Watch for updates 0781 } 0782 0783 runKonfUpdate(); // Run it once. 0784 0785 return app.exec(); // keep running 0786 } 0787 0788 #include "moc_kded.cpp"