KDED

kded.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 1999 David Faure <[email protected]>
4  SPDX-FileCopyrightText: 2000 Waldo Bastian <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #include "kded.h"
10 #include "kded_version.h"
11 #include "kdedadaptor.h"
12 
13 #include <KCrash>
14 
15 #include <qplatformdefs.h>
16 
17 #include <QApplication>
18 #include <QCommandLineParser>
19 #include <QDir>
20 #include <QLoggingCategory>
21 #include <QProcess>
22 
23 #include <QDBusConnection>
24 #include <QDBusConnectionInterface>
25 #include <QDBusServiceWatcher>
26 
27 #include <KConfigGroup>
28 #include <KDBusService>
29 #include <KDirWatch>
30 #include <KPluginFactory>
31 #include <KPluginInfo>
32 #include <KPluginMetaData>
33 #include <KServiceTypeTrader>
34 #include <KSharedConfig>
35 
36 #ifdef Q_OS_OSX
37 #include <CoreFoundation/CoreFoundation.h>
38 #endif
39 
40 #include <memory>
41 
42 Q_DECLARE_LOGGING_CATEGORY(KDED)
43 
44 Q_LOGGING_CATEGORY(KDED, "kf.kded", QtWarningMsg)
45 
46 Kded *Kded::_self = nullptr;
47 
48 static bool delayedCheck;
49 static bool bCheckSycoca;
50 static bool bCheckUpdates;
51 
52 #ifdef Q_DBUS_EXPORT
53 extern Q_DBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &));
54 #else
55 extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &));
56 #endif
57 
58 static void runKonfUpdate()
59 {
60  QProcess kconfUpdate;
61  kconfUpdate.start(QStringLiteral(KCONF_UPDATE_EXE), QStringList());
62  kconfUpdate.waitForFinished();
63 }
64 
65 Kded::Kded()
66  : m_pDirWatch(new KDirWatch(this))
67  , m_pTimer(new QTimer(this))
68  , m_needDelayedCheck(false)
69 {
70  _self = this;
71 
72  m_serviceWatcher = new QDBusServiceWatcher(this);
73  m_serviceWatcher->setConnection(QDBusConnection::sessionBus());
74  m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
75  QObject::connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &Kded::slotApplicationRemoved);
76 
77  new KBuildsycocaAdaptor(this);
78  new KdedAdaptor(this);
79 
81  session.registerObject(QStringLiteral("/kbuildsycoca"), this);
82  session.registerObject(QStringLiteral("/kded"), this);
83 
84  qDBusAddSpyHook(messageFilter);
85 
86  m_pTimer->setSingleShot(true);
87  connect(m_pTimer, &QTimer::timeout, this, static_cast<void (Kded::*)()>(&Kded::recreate));
88 }
89 
90 Kded::~Kded()
91 {
92  _self = nullptr;
93  m_pTimer->stop();
94 
95  for (auto it = m_modules.cbegin(); it != m_modules.cend(); ++it) {
96  KDEDModule *module(it.value());
97 
98  // first disconnect otherwise slotKDEDModuleRemoved() is called
99  // and changes m_modules while we're iterating over it
100  disconnect(module, &KDEDModule::moduleDeleted, this, &Kded::slotKDEDModuleRemoved);
101 
102  delete module;
103  }
104 }
105 
106 // on-demand module loading
107 // this function is called by the D-Bus message processing function before
108 // calls are delivered to objects
109 void Kded::messageFilter(const QDBusMessage &message)
110 {
111  // This happens when kded goes down and some modules try to clean up.
112  if (!self()) {
113  return;
114  }
115 
117  if (obj.isEmpty() || obj == QLatin1String("ksycoca")) {
118  return;
119  }
120 
121  if (self()->m_dontLoad.value(obj, nullptr)) {
122  return;
123  }
124 
125  self()->loadModule(obj, true);
126 }
127 
128 static int phaseForModule(const KPluginMetaData &module)
129 {
130  return module.value(QStringLiteral("X-KDE-Kded-phase"), 2);
131 }
132 
133 QVector<KPluginMetaData> Kded::availableModules() const
134 {
135  QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/kded"));
136  QSet<QString> moduleIds;
137  for (const KPluginMetaData &md : std::as_const(plugins)) {
138  moduleIds.insert(md.pluginId());
139  }
140 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0)
141  // also search for old .desktop based kded modules
142  QT_WARNING_PUSH
143  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
144  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
145  const KPluginInfo::List oldStylePlugins = KPluginInfo::fromServices(KServiceTypeTrader::self()->query(QStringLiteral("KDEDModule")));
146  QT_WARNING_POP
147  for (const KPluginInfo &info : oldStylePlugins) {
148  if (moduleIds.contains(info.pluginName())) {
149  qCWarning(KDED).nospace() << "kded module " << info.pluginName()
150  << " has already been found using "
151  "JSON metadata, please don't install the now unneeded .desktop file ("
152  << info.entryPath() << ").";
153  } else {
154  qCDebug(KDED).nospace() << "kded module " << info.pluginName() << " still uses .desktop files (" << info.entryPath()
155  << "). Please port it to JSON metadata.";
156  plugins.append(info.toMetaData());
157  }
158  }
159 #endif
160  return plugins;
161 }
162 
163 static KPluginMetaData findModule(const QString &id)
164 {
165  KPluginMetaData module(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/kded/") + id);
166  if (module.isValid()) {
167  return module;
168  }
169 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0)
170  // TODO KF6: remove the .desktop fallback code
171  KService::Ptr oldStyleModule = KService::serviceByDesktopPath(QStringLiteral("kded/") + id + QStringLiteral(".desktop"));
172  if (oldStyleModule) {
173  qCDebug(KDED).nospace() << "kded module " << oldStyleModule->desktopEntryName() << " still uses .desktop files (" << oldStyleModule->entryPath()
174  << "). Please port it to JSON metadata.";
175  QT_WARNING_PUSH
176  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
177  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
178  return KPluginInfo(oldStyleModule).toMetaData();
179  QT_WARNING_POP
180  }
181 #endif
182  qCWarning(KDED) << "could not find kded module with id" << id;
183  return KPluginMetaData();
184 }
185 
186 void Kded::initModules()
187 {
188  m_dontLoad.clear();
189 #ifdef Q_OS_OSX
190  // it seems there is no reason to honour KDE_FULL_SESSION on OS X even if it's set for some reason.
191  // That way kdeinit5 is always auto-started if required (and the kded is as good a candidate
192  // for starting this service as any other application).
193  bool kde_running = false;
194 #else
195  bool kde_running = !qEnvironmentVariableIsEmpty("KDE_FULL_SESSION");
196 #endif
197  if (kde_running) {
198 #ifndef Q_OS_WIN
199  // not the same user like the one running the session (most likely we're run via sudo or something)
200  const QByteArray sessionUID = qgetenv("KDE_SESSION_UID");
201  if (!sessionUID.isEmpty() && uid_t(sessionUID.toInt()) != getuid()) {
202  kde_running = false;
203  }
204 #endif
205  // TODO: Change 5 to KDED_VERSION_MAJOR the moment KF5 are stable
206  // not the same kde version as the current desktop
207  const QByteArray kdeSession = qgetenv("KDE_SESSION_VERSION");
208  if (kdeSession.toInt() != 5) {
209  kde_running = false;
210  }
211  }
212 
213  // Preload kded modules.
214  const QVector<KPluginMetaData> kdedModules = availableModules();
215  for (const KPluginMetaData &module : kdedModules) {
216  // Should the service load on startup?
217  const bool autoload = isModuleAutoloaded(module);
218  if (!platformSupportsModule(module)) {
219  continue;
220  }
221 
222  // see ksmserver's README for description of the phases
223  bool prevent_autoload = false;
224  switch (phaseForModule(module)) {
225  case 0: // always autoload
226  break;
227  case 1: // autoload only in KDE
228  if (!kde_running) {
229  prevent_autoload = true;
230  }
231  break;
232  case 2: // autoload delayed, only in KDE
233  default:
234  if (!kde_running) {
235  prevent_autoload = true;
236  }
237  break;
238  }
239 
240  // Load the module if necessary and allowed
241  if (autoload && !prevent_autoload) {
242  if (!loadModule(module, false)) {
243  continue;
244  }
245  }
246 
247  // Remember if the module is allowed to load on demand
248  bool loadOnDemand = isModuleLoadedOnDemand(module);
249  if (!loadOnDemand) {
250  noDemandLoad(module.pluginId());
251  }
252 
253  // In case of reloading the configuration it is possible for a module
254  // to run even if it is now allowed to. Stop it then.
255  if (!loadOnDemand && !autoload) {
256  unloadModule(module.pluginId());
257  }
258  }
259 }
260 
261 void Kded::loadSecondPhase()
262 {
263  qCDebug(KDED) << "Second phase autoload is deprecated";
264 }
265 
266 void Kded::noDemandLoad(const QString &obj)
267 {
268  m_dontLoad.insert(obj, this);
269 }
270 
271 void Kded::setModuleAutoloading(const QString &obj, bool autoload)
272 {
273  KSharedConfig::Ptr config = KSharedConfig::openConfig();
274  // Ensure the service exists.
275  KPluginMetaData module = findModule(obj);
276  if (!module.isValid()) {
277  return;
278  }
279  KConfigGroup cg(config, QStringLiteral("Module-").append(module.pluginId()));
280  cg.writeEntry("autoload", autoload);
281  cg.sync();
282 }
283 
284 bool Kded::isModuleAutoloaded(const QString &obj) const
285 {
286  return isModuleAutoloaded(findModule(obj));
287 }
288 
289 bool Kded::isModuleAutoloaded(const KPluginMetaData &module) const
290 {
291  if (!module.isValid()) {
292  return false;
293  }
294  KSharedConfig::Ptr config = KSharedConfig::openConfig();
295  bool autoload = module.value(QStringLiteral("X-KDE-Kded-autoload"), false);
296  KConfigGroup cg(config, QStringLiteral("Module-").append(module.pluginId()));
297  autoload = cg.readEntry("autoload", autoload);
298  return autoload;
299 }
300 
301 bool Kded::platformSupportsModule(const KPluginMetaData &module) const
302 {
303  const QStringList supportedPlatforms = module.value(QStringLiteral("X-KDE-OnlyShowOnQtPlatforms"), QStringList());
304 
305  return supportedPlatforms.isEmpty() || supportedPlatforms.contains(qApp->platformName());
306 }
307 
308 bool Kded::isModuleLoadedOnDemand(const QString &obj) const
309 {
310  return isModuleLoadedOnDemand(findModule(obj));
311 }
312 
313 bool Kded::isModuleLoadedOnDemand(const KPluginMetaData &module) const
314 {
315  if (!module.isValid()) {
316  return false;
317  }
318  KSharedConfig::Ptr config = KSharedConfig::openConfig();
319  return module.value(QStringLiteral("X-KDE-Kded-load-on-demand"), true);
320 }
321 
322 KDEDModule *Kded::loadModule(const QString &obj, bool onDemand)
323 {
324  // Make sure this method is only called with valid module names.
325  if (obj.contains(QLatin1Char('/'))) {
326  qCWarning(KDED) << "attempting to load invalid kded module name:" << obj;
327  return nullptr;
328  }
329  KDEDModule *module = m_modules.value(obj, nullptr);
330  if (module) {
331  return module;
332  }
333  return loadModule(findModule(obj), onDemand);
334 }
335 
336 KDEDModule *Kded::loadModule(const KPluginMetaData &module, bool onDemand)
337 {
338  if (!module.isValid() || module.fileName().isEmpty()) {
339  qCWarning(KDED) << "attempted to load an invalid module.";
340  return nullptr;
341  }
342  const QString moduleId = module.pluginId();
343  KDEDModule *oldModule = m_modules.value(moduleId, nullptr);
344  if (oldModule) {
345  qCDebug(KDED) << "kded module" << moduleId << "is already loaded.";
346  return oldModule;
347  }
348 
349  if (onDemand) {
350  if (!module.value(QStringLiteral("X-KDE-Kded-load-on-demand"), true)) {
351  noDemandLoad(moduleId);
352  return nullptr;
353  }
354  }
355 
356  KDEDModule *kdedModule = nullptr;
357 
358  auto factoryResult = KPluginFactory::loadFactory(module);
359  if (factoryResult) {
360  kdedModule = factoryResult.plugin->create<KDEDModule>(this);
361  } else {
362  // TODO: remove this fallback code, the kded modules should all be fixed instead
363  factoryResult = KPluginFactory::loadFactory(KPluginMetaData(QStringLiteral("kded_") + module.fileName()));
364  if (factoryResult) {
365  qCWarning(KDED).nospace() << "found kded module " << moduleId << " by prepending 'kded_' to the library path, please fix your metadata.";
366  kdedModule = factoryResult.plugin->create<KDEDModule>(this);
367  } else {
368  qCWarning(KDED).nospace() << "Could not load kded module " << moduleId << ":" << factoryResult.errorText
369  << " (library path was:" << module.fileName() << ")";
370  }
371  }
372 
373  if (kdedModule) {
374  kdedModule->setModuleName(moduleId);
375  m_modules.insert(moduleId, kdedModule);
376  // m_libs.insert(moduleId, lib);
377  connect(kdedModule, &KDEDModule::moduleDeleted, this, &Kded::slotKDEDModuleRemoved);
378  qCDebug(KDED) << "Successfully loaded module" << moduleId;
379  return kdedModule;
380  }
381  return nullptr;
382 }
383 
384 bool Kded::unloadModule(const QString &obj)
385 {
386  KDEDModule *module = m_modules.value(obj, nullptr);
387  if (!module) {
388  return false;
389  }
390  qCDebug(KDED) << "Unloading module" << obj;
391  m_modules.remove(obj);
392  delete module;
393  return true;
394 }
395 
396 QStringList Kded::loadedModules()
397 {
398  return m_modules.keys();
399 }
400 
401 void Kded::slotKDEDModuleRemoved(KDEDModule *module)
402 {
403  m_modules.remove(module->moduleName());
404 }
405 
406 void Kded::slotApplicationRemoved(const QString &name)
407 {
408 #if 0 // see kdedmodule.cpp (KDED_OBJECTS)
409  foreach (KDEDModule *module, m_modules) {
410  module->removeAll(appId);
411  }
412 #endif
413  m_serviceWatcher->removeWatchedService(name);
414  const QList<qlonglong> windowIds = m_windowIdList.value(name);
415  for (const auto id : windowIds) {
416  m_globalWindowIdList.remove(id);
417  for (KDEDModule *module : std::as_const(m_modules)) {
418  Q_EMIT module->windowUnregistered(id);
419  }
420  }
421  m_windowIdList.remove(name);
422 }
423 
424 void Kded::updateDirWatch()
425 {
426  if (!bCheckUpdates) {
427  return;
428  }
429 
430  delete m_pDirWatch;
431  m_pDirWatch = new KDirWatch(this);
432 
433  QObject::connect(m_pDirWatch, &KDirWatch::dirty, this, &Kded::update);
434  QObject::connect(m_pDirWatch, &KDirWatch::created, this, &Kded::update);
435  QObject::connect(m_pDirWatch, &KDirWatch::deleted, this, &Kded::dirDeleted);
436 
437  // For each resource
438  for (const QString &dir : std::as_const(m_allResourceDirs)) {
439  readDirectory(dir);
440  }
441 
443  for (auto &dir : dataDirs) {
444  dir += QLatin1String("/icons");
445  if (!m_pDirWatch->contains(dir)) {
446  m_pDirWatch->addDir(dir, KDirWatch::WatchDirOnly);
447  }
448  }
449 }
450 
451 void Kded::updateResourceList()
452 {
453  KSycoca::clearCaches();
454 
455  if (!bCheckUpdates) {
456  return;
457  }
458 
459  if (delayedCheck) {
460  return;
461  }
462 
464  // For each resource
465  for (const auto &dir : dirs) {
466  if (!m_allResourceDirs.contains(dir)) {
467  m_allResourceDirs.append(dir);
468  readDirectory(dir);
469  }
470  }
471 }
472 
473 void Kded::recreate()
474 {
475  recreate(false);
476 }
477 
478 void Kded::runDelayedCheck()
479 {
480  if (m_needDelayedCheck) {
481  recreate(false);
482  }
483  m_needDelayedCheck = false;
484 }
485 
486 void Kded::recreate(bool initial)
487 {
488  // Using KLauncher here is difficult since we might not have a
489  // database
490 
491  if (!initial) {
492  updateDirWatch(); // Update tree first, to be sure to miss nothing.
494  recreateDone();
495  } else {
496  if (!delayedCheck) {
497  updateDirWatch(); // this would search all the directories
498  }
499  if (bCheckSycoca) {
501  }
502  recreateDone();
503  if (delayedCheck) {
504  // do a proper ksycoca check after a delay
505  QTimer::singleShot(60000, this, &Kded::runDelayedCheck);
506  m_needDelayedCheck = true;
507  delayedCheck = false;
508  } else {
509  m_needDelayedCheck = false;
510  }
511  }
512 }
513 
514 void Kded::recreateDone()
515 {
516  updateResourceList();
517 
518  initModules();
519 }
520 
521 void Kded::dirDeleted(const QString &path)
522 {
523  update(path);
524 }
525 
526 void Kded::update(const QString &path)
527 {
528  if (path.endsWith(QLatin1String("/icons")) && m_pDirWatch->contains(path)) {
529  // If the dir was created or updated there could be new folders to merge into the active theme(s)
530  QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KIconLoader"), QStringLiteral("org.kde.KIconLoader"), QStringLiteral("iconChanged"));
531  message << 0;
533  } else {
534  m_pTimer->start(1000);
535  }
536 }
537 
538 void Kded::readDirectory(const QString &_path)
539 {
540  QString path(_path);
541  if (!path.endsWith(QLatin1Char('/'))) {
542  path += QLatin1Char('/');
543  }
544 
545  if (m_pDirWatch->contains(path)) { // Already seen this one?
546  return;
547  }
548 
549  Q_ASSERT(path != QDir::homePath());
550  m_pDirWatch->addDir(path, KDirWatch::WatchFiles | KDirWatch::WatchSubDirs); // add watch on this dir
551 }
552 
553 void Kded::registerWindowId(qlonglong windowId, const QString &sender)
554 {
555  if (!m_windowIdList.contains(sender)) {
556  m_serviceWatcher->addWatchedService(sender);
557  }
558 
559  m_globalWindowIdList.insert(windowId);
560  QList<qlonglong> windowIds = m_windowIdList.value(sender);
561  windowIds.append(windowId);
562  m_windowIdList.insert(sender, windowIds);
563 
564  for (KDEDModule *module : std::as_const(m_modules)) {
565  qCDebug(KDED) << module->moduleName();
566  Q_EMIT module->windowRegistered(windowId);
567  }
568 }
569 
570 void Kded::unregisterWindowId(qlonglong windowId, const QString &sender)
571 {
572  m_globalWindowIdList.remove(windowId);
573  QList<qlonglong> windowIds = m_windowIdList.value(sender);
574  if (!windowIds.isEmpty()) {
575  windowIds.removeAll(windowId);
576  if (windowIds.isEmpty()) {
577  m_serviceWatcher->removeWatchedService(sender);
578  m_windowIdList.remove(sender);
579  } else {
580  m_windowIdList.insert(sender, windowIds);
581  }
582  }
583 
584  for (KDEDModule *module : std::as_const(m_modules)) {
585  qCDebug(KDED) << module->moduleName();
586  Q_EMIT module->windowUnregistered(windowId);
587  }
588 }
589 
590 static void sighandler(int /*sig*/)
591 {
592  if (qApp) {
593  qApp->quit();
594  }
595 }
596 
597 KUpdateD::KUpdateD()
598 {
599  m_pDirWatch = new KDirWatch(this);
600  m_pTimer = new QTimer(this);
601  m_pTimer->setSingleShot(true);
602  connect(m_pTimer, &QTimer::timeout, this, &KUpdateD::runKonfUpdate);
603  QObject::connect(m_pDirWatch, &KDirWatch::dirty, this, &KUpdateD::slotNewUpdateFile);
604 
606  for (auto &path : dirs) {
607  Q_ASSERT(path != QDir::homePath());
608  if (!path.endsWith(QLatin1Char('/'))) {
609  path += QLatin1Char('/');
610  }
611 
612  if (!m_pDirWatch->contains(path)) {
613  m_pDirWatch->addDir(path, KDirWatch::WatchFiles);
614  }
615  }
616 }
617 
618 KUpdateD::~KUpdateD()
619 {
620 }
621 
622 void KUpdateD::runKonfUpdate()
623 {
624  ::runKonfUpdate();
625 }
626 
627 void KUpdateD::slotNewUpdateFile(const QString &dirty)
628 {
629  Q_UNUSED(dirty);
630  qCDebug(KDED) << dirty;
631  m_pTimer->start(500);
632 }
633 
634 KBuildsycocaAdaptor::KBuildsycocaAdaptor(QObject *parent)
635  : QDBusAbstractAdaptor(parent)
636 {
637 }
638 
639 void KBuildsycocaAdaptor::recreate()
640 {
641  Kded::self()->recreate();
642 }
643 
644 // KF6: remove
645 bool KBuildsycocaAdaptor::isTestModeEnabled()
646 {
647  return QStandardPaths::isTestModeEnabled();
648 }
649 
650 // KF6: remove
651 void KBuildsycocaAdaptor::setTestModeEnabled()
652 {
654 }
655 
656 static void setupAppInfo(QApplication *app)
657 {
658  app->setApplicationName(QStringLiteral("kded5"));
659  app->setApplicationDisplayName(QStringLiteral("KDE Daemon"));
660  app->setOrganizationDomain(QStringLiteral("kde.org"));
661  app->setApplicationVersion(QStringLiteral(KDED_VERSION_STRING));
662 }
663 
664 static bool detectPlatform(int argc, char **argv)
665 {
666  if (qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) {
667  return false;
668  }
669  for (int i = 0; i < argc; i++) {
670  /* clang-format off */
671  if (qstrcmp(argv[i], "-platform") == 0
672  || qstrcmp(argv[i], "--platform") == 0
673  || QByteArray(argv[i]).startsWith("-platform=")
674  || QByteArray(argv[i]).startsWith("--platform=")) { /* clang-format on */
675  return false;
676  }
677  }
678  const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
679  if (sessionType.isEmpty()) {
680  return false;
681  }
682  if (qstrcmp(sessionType.data(), "wayland") == 0) {
683  qputenv("QT_QPA_PLATFORM", "wayland");
684  return true;
685  } else if (qstrcmp(sessionType.data(), "x11") == 0) {
686  qputenv("QT_QPA_PLATFORM", "xcb");
687  return true;
688  }
689  return false;
690 }
691 
692 int main(int argc, char *argv[])
693 {
694 #ifdef Q_OS_OSX
695  CFBundleRef mainBundle = CFBundleGetMainBundle();
696  if (mainBundle) {
697  // get the application's Info Dictionary. For app bundles this would live in the bundle's Info.plist,
698  // for regular executables it is obtained in another way.
699  CFMutableDictionaryRef infoDict = (CFMutableDictionaryRef)CFBundleGetInfoDictionary(mainBundle);
700  if (infoDict) {
701  // Add or set the "LSUIElement" key with/to value "1". This can simply be a CFString.
702  CFDictionarySetValue(infoDict, CFSTR("LSUIElement"), CFSTR("1"));
703  // That's it. We're now considered as an "agent" by the window server, and thus will have
704  // neither menubar nor presence in the Dock or App Switcher.
705  }
706  }
707 #endif
708  // options.add("check", qi18n("Check Sycoca database only once"));
709 
710  // WABA: Make sure not to enable session management.
711  qunsetenv("SESSION_MANAGER");
712 
713  const bool unsetQpa = detectPlatform(argc, argv);
714 
715  // In older versions, QApplication creation was postponed until after
716  // testing for --check, in which case, only a QCoreApplication was created.
717  // Since that option is no longer used at startup, we removed that speed
718  // optimization for code clarity and easier support of standard parameters.
719 
720  // Fixes blurry icons with Fractional scaling
722  QApplication app(argc, argv);
723  if (unsetQpa) {
724  qunsetenv("QT_QPA_PLATFORM");
725  }
726  setupAppInfo(&app);
727  app.setQuitOnLastWindowClosed(false);
728 
729  QCommandLineParser parser;
730  parser.addHelpOption();
731  parser.addVersionOption();
732  parser.addOption(QCommandLineOption(QStringLiteral("check"), QStringLiteral("Check cache validity")));
733  QCommandLineOption replaceOption({QStringLiteral("replace")}, QStringLiteral("Replace an existing instance"));
734  parser.addOption(replaceOption);
735  parser.process(app);
736 
737  // Parse command line before checking D-Bus
738  if (parser.isSet(QStringLiteral("check"))) {
739  // KDBusService not wanted here.
741  runKonfUpdate();
742  return 0;
743  }
744 
746 
748  // Also register as all the names we should respond to (org.kde.kcookiejar, org.kde.khotkeys etc.)
749  // so that the calling code is independent from the physical "location" of the service.
750  const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/kded"));
751  for (const KPluginMetaData &metaData : plugins) {
752  const QString serviceName = metaData.value(QStringLiteral("X-KDE-DBus-ServiceName"));
753  if (serviceName.isEmpty()) {
754  continue;
755  }
756  if (!bus->registerService(serviceName)) {
757  qCWarning(KDED) << "Couldn't register name" << serviceName << "with DBUS - another process owns it already!";
758  }
759  }
760 
761  KSharedConfig::Ptr config = KSharedConfig::openConfig();
762  KConfigGroup cg(config, "General");
763 
764  bCheckSycoca = cg.readEntry("CheckSycoca", true);
765  bCheckUpdates = cg.readEntry("CheckUpdates", true);
766  delayedCheck = cg.readEntry("DelayedCheck", false);
767 
768 #ifndef Q_OS_WIN
769  signal(SIGTERM, sighandler);
770  signal(SIGHUP, sighandler);
771 #endif
772 
774 
775  std::unique_ptr<Kded> kded = std::make_unique<Kded>();
776 
777  kded->recreate(true); // initial
778 
779  if (bCheckUpdates) {
780  (void)new KUpdateD; // Watch for updates
781  }
782 
783  runKonfUpdate(); // Run it once.
784 
785  return app.exec(); // keep running
786 }
787 
788 #include "moc_kded.cpp"
static KSycoca * self()
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
void append(const T &value)
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
void windowRegistered(qlonglong windowId)
void ensureCacheValid()
KCMUTILS_EXPORT void unloadModule(const KCModuleInfo &mod)
bool waitForFinished(int msecs)
int removeAll(const T &value)
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
AA_UseHighDpiPixmaps
void append(const T &value)
void setQuitOnLastWindowClosed(bool quit)
bool isValid() const
QString fileName() const
void setApplicationVersion(const QString &version)
bool registerObject(const QString &path, QObject *object, QDBusConnection::RegisterOptions options)
QString homePath()
KCRASH_EXPORT void setFlags(KCrash::CrashFlags flags)
void serviceUnregistered(const QString &serviceName)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setOrganizationDomain(const QString &orgDomain)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
KCMUTILS_EXPORT KCModule * loadModule(const KCModuleInfo &module, ErrorReporting report, QWidget *parent=nullptr, const QStringList &args=QStringList())
bool send(const QDBusMessage &message) const const
static QString moduleForMessage(const QDBusMessage &message)
QStringList standardLocations(QStandardPaths::StandardLocation type)
void setApplicationDisplayName(const QString &name)
QString pluginName() const
QDBusConnection sessionBus()
void process(const QStringList &arguments)
QCommandLineOption addVersionOption()
void timeout()
bool isEmpty() const const
static Ptr serviceByDesktopPath(const QString &_path)
bool isEmpty() const const
QDBusMessage createSignal(const QString &path, const QString &interface, const QString &name)
KSharedConfigPtr config()
void setApplicationName(const QString &application)
bool isSet(const QString &name) const const
static Result< KPluginFactory > loadFactory(const KPluginMetaData &data)
QDBusConnectionInterface * interface() const const
bool contains(const T &value) const const
bool value(const QString &key, bool defaultValue) const
QString & remove(int position, int n)
static QVector< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter, KPluginMetaDataOption option)
QStringList allResourceDirs()
void windowUnregistered(qlonglong windowId)
int toInt(bool *ok, int base) const const
bool isEmpty() const const
KIOFILEWIDGETS_EXPORT QString dir(const QString &fileClass)
void setAttribute(Qt::ApplicationAttribute attribute, bool on)
QString path(const QString &relativePath)
void setModuleName(const QString &name)
KStandardDirs * dirs()
void dirty(const QString &path)
QStringList locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
void update(Part *part, const QByteArray &data, qint64 dataSize)
void deleted(const QString &path)
QSet::iterator insert(const T &value)
void created(const QString &path)
bool addOption(const QCommandLineOption &option)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString pluginId() const
void setTestModeEnabled(bool testMode)
QCommandLineOption addHelpOption()
void moduleDeleted(KDEDModule *)
QString message
T value(int i) const const
char * data()
QDBusReply< QDBusConnectionInterface::RegisterServiceReply > registerService(const QString &serviceName, QDBusConnectionInterface::ServiceQueueOptions qoption, QDBusConnectionInterface::ServiceReplacementOptions roption)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Dec 5 2023 03:57:19 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.