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 <KPluginInfo>
31 #include <KPluginMetaData>
32 #include <KServiceTypeTrader>
33 #include <KSharedConfig>
34 
35 #ifdef Q_OS_OSX
36 #include <CoreFoundation/CoreFoundation.h>
37 #endif
38 
39 Q_DECLARE_LOGGING_CATEGORY(KDED)
40 
41 Q_LOGGING_CATEGORY(KDED, "kf.kded", QtWarningMsg)
42 
43 Kded *Kded::_self = nullptr;
44 
45 static bool delayedCheck;
46 static bool bCheckSycoca;
47 static bool bCheckUpdates;
48 
49 #ifdef Q_DBUS_EXPORT
50 extern Q_DBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &));
51 #else
52 extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &));
53 #endif
54 
55 static void runKonfUpdate()
56 {
57  QProcess kconfUpdate;
58  kconfUpdate.start(QStringLiteral(KCONF_UPDATE_EXE), QStringList());
59  kconfUpdate.waitForFinished();
60 }
61 
62 Kded::Kded()
63  : m_pDirWatch(nullptr)
64  , m_pTimer(new QTimer(this))
65  , m_needDelayedCheck(false)
66 {
67  _self = this;
68 
69  m_serviceWatcher = new QDBusServiceWatcher(this);
70  m_serviceWatcher->setConnection(QDBusConnection::sessionBus());
71  m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
72  QObject::connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &Kded::slotApplicationRemoved);
73 
74  new KBuildsycocaAdaptor(this);
75  new KdedAdaptor(this);
76 
78  session.registerObject(QStringLiteral("/kbuildsycoca"), this);
79  session.registerObject(QStringLiteral("/kded"), this);
80 
81  qDBusAddSpyHook(messageFilter);
82 
83  m_pTimer->setSingleShot(true);
84  connect(m_pTimer, &QTimer::timeout, this, static_cast<void (Kded::*)()>(&Kded::recreate));
85 }
86 
87 Kded::~Kded()
88 {
89  _self = nullptr;
90  m_pTimer->stop();
91  delete m_pTimer;
92  delete m_pDirWatch;
93 
94  for (QHash<QString, KDEDModule *>::const_iterator it(m_modules.constBegin()), itEnd(m_modules.constEnd()); it != itEnd; ++it) {
95  KDEDModule *module(it.value());
96 
97  // first disconnect otherwise slotKDEDModuleRemoved() is called
98  // and changes m_modules while we're iterating over it
99  disconnect(module, &KDEDModule::moduleDeleted, this, &Kded::slotKDEDModuleRemoved);
100 
101  delete module;
102  }
103 }
104 
105 // on-demand module loading
106 // this function is called by the D-Bus message processing function before
107 // calls are delivered to objects
108 void Kded::messageFilter(const QDBusMessage &message)
109 {
110  // This happens when kded goes down and some modules try to clean up.
111  if (!self()) {
112  return;
113  }
114 
115  QString obj = KDEDModule::moduleForMessage(message);
116  if (obj.isEmpty() || obj == QLatin1String("ksycoca")) {
117  return;
118  }
119 
120  if (self()->m_dontLoad.value(obj, nullptr)) {
121  return;
122  }
123 
124  self()->loadModule(obj, true);
125 }
126 
127 static int phaseForModule(const KPluginMetaData &module)
128 {
129  const QVariant phasev = module.rawData().value(QStringLiteral("X-KDE-Kded-phase")).toVariant();
130  return phasev.isValid() ? phasev.toInt() : 2;
131 }
132 
133 QVector<KPluginMetaData> Kded::availableModules() const
134 {
135  QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("kf5/kded"));
136  QSet<QString> moduleIds;
137  for (const KPluginMetaData &md : qAsConst(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("kf5/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.rawData().value(QStringLiteral("X-KDE-Kded-autoload")).toVariant().toBool();
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 = KPluginMetaData::readStringList(module.rawData(), QStringLiteral("X-KDE-OnlyShowOnQtPlatforms"));
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  bool loadOnDemand = true;
320  // use toVariant() since it could be string or bool in the json and QJsonObject does not convert
321  QVariant p = module.rawData().value(QStringLiteral("X-KDE-Kded-load-on-demand")).toVariant();
322  if (p.isValid() && (p.toBool() == false)) {
323  loadOnDemand = false;
324  }
325  return loadOnDemand;
326 }
327 
328 KDEDModule *Kded::loadModule(const QString &obj, bool onDemand)
329 {
330  // Make sure this method is only called with valid module names.
331  if (obj.contains(QLatin1Char('/'))) {
332  qCWarning(KDED) << "attempting to load invalid kded module name:" << obj;
333  return nullptr;
334  }
335  KDEDModule *module = m_modules.value(obj, nullptr);
336  if (module) {
337  return module;
338  }
339  return loadModule(findModule(obj), onDemand);
340 }
341 
342 KDEDModule *Kded::loadModule(const KPluginMetaData &module, bool onDemand)
343 {
344  if (!module.isValid() || module.fileName().isEmpty()) {
345  qCWarning(KDED) << "attempted to load an invalid module.";
346  return nullptr;
347  }
348  const QString moduleId = module.pluginId();
349  KDEDModule *oldModule = m_modules.value(moduleId, nullptr);
350  if (oldModule) {
351  qCDebug(KDED) << "kded module" << moduleId << "is already loaded.";
352  return oldModule;
353  }
354 
355  if (onDemand) {
356  // use toVariant() since it could be string or bool in the json and QJsonObject does not convert
357  QVariant p = module.rawData().value(QStringLiteral("X-KDE-Kded-load-on-demand")).toVariant();
358  if (p.isValid() && (p.toBool() == false)) {
359  noDemandLoad(moduleId);
360  return nullptr;
361  }
362  }
363 
364  KDEDModule *kdedModule = nullptr;
365 
366  KPluginLoader loader(module.fileName());
367  KPluginFactory *factory = loader.factory();
368  if (factory) {
369  kdedModule = factory->create<KDEDModule>(this);
370  } else {
371  // TODO: remove this fallback code, the kded modules should all be fixed instead
372  KPluginLoader loader2(QStringLiteral("kded_") + module.fileName());
373  factory = loader2.factory();
374  if (factory) {
375  qCWarning(KDED).nospace() << "found kded module " << moduleId << " by prepending 'kded_' to the library path, please fix your metadata.";
376  kdedModule = factory->create<KDEDModule>(this);
377  } else {
378  qCWarning(KDED).nospace() << "Could not load kded module " << moduleId << ":" << loader.errorString() << " (library path was:" << module.fileName()
379  << ")";
380  }
381  }
382 
383  if (kdedModule) {
384  kdedModule->setModuleName(moduleId);
385  m_modules.insert(moduleId, kdedModule);
386  // m_libs.insert(moduleId, lib);
387  connect(kdedModule, &KDEDModule::moduleDeleted, this, &Kded::slotKDEDModuleRemoved);
388  qCDebug(KDED) << "Successfully loaded module" << moduleId;
389  return kdedModule;
390  }
391  return nullptr;
392 }
393 
394 bool Kded::unloadModule(const QString &obj)
395 {
396  KDEDModule *module = m_modules.value(obj, nullptr);
397  if (!module) {
398  return false;
399  }
400  qCDebug(KDED) << "Unloading module" << obj;
401  m_modules.remove(obj);
402  delete module;
403  return true;
404 }
405 
406 QStringList Kded::loadedModules()
407 {
408  return m_modules.keys();
409 }
410 
411 void Kded::slotKDEDModuleRemoved(KDEDModule *module)
412 {
413  m_modules.remove(module->moduleName());
414 }
415 
416 void Kded::slotApplicationRemoved(const QString &name)
417 {
418 #if 0 // see kdedmodule.cpp (KDED_OBJECTS)
419  foreach (KDEDModule *module, m_modules) {
420  module->removeAll(appId);
421  }
422 #endif
423  m_serviceWatcher->removeWatchedService(name);
424  const QList<qlonglong> windowIds = m_windowIdList.value(name);
425  for (QList<qlonglong>::ConstIterator it = windowIds.begin(); it != windowIds.end(); ++it) {
426  qlonglong windowId = *it;
427  m_globalWindowIdList.remove(windowId);
428  for (KDEDModule *module : qAsConst(m_modules)) {
429  Q_EMIT module->windowUnregistered(windowId);
430  }
431  }
432  m_windowIdList.remove(name);
433 }
434 
435 void Kded::updateDirWatch()
436 {
437  if (!bCheckUpdates) {
438  return;
439  }
440 
441  delete m_pDirWatch;
442  m_pDirWatch = new KDirWatch;
443 
444  QObject::connect(m_pDirWatch, &KDirWatch::dirty, this, &Kded::update);
445  QObject::connect(m_pDirWatch, &KDirWatch::created, this, &Kded::update);
446  QObject::connect(m_pDirWatch, &KDirWatch::deleted, this, &Kded::dirDeleted);
447 
448  // For each resource
449  for (QStringList::ConstIterator it = m_allResourceDirs.constBegin(); it != m_allResourceDirs.constEnd(); ++it) {
450  readDirectory(*it);
451  }
452 }
453 
454 void Kded::updateResourceList()
455 {
456  KSycoca::clearCaches();
457 
458  if (!bCheckUpdates) {
459  return;
460  }
461 
462  if (delayedCheck) {
463  return;
464  }
465 
467  // For each resource
468  for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) {
469  if (!m_allResourceDirs.contains(*it)) {
470  m_allResourceDirs.append(*it);
471  readDirectory(*it);
472  }
473  }
474 }
475 
476 void Kded::recreate()
477 {
478  recreate(false);
479 }
480 
481 void Kded::runDelayedCheck()
482 {
483  if (m_needDelayedCheck) {
484  recreate(false);
485  }
486  m_needDelayedCheck = false;
487 }
488 
489 void Kded::recreate(bool initial)
490 {
491  // Using KLauncher here is difficult since we might not have a
492  // database
493 
494  if (!initial) {
495  updateDirWatch(); // Update tree first, to be sure to miss nothing.
497  recreateDone();
498  } else {
499  if (!delayedCheck) {
500  updateDirWatch(); // this would search all the directories
501  }
502  if (bCheckSycoca) {
504  }
505  recreateDone();
506  if (delayedCheck) {
507  // do a proper ksycoca check after a delay
508  QTimer::singleShot(60000, this, &Kded::runDelayedCheck);
509  m_needDelayedCheck = true;
510  delayedCheck = false;
511  } else {
512  m_needDelayedCheck = false;
513  }
514  }
515 }
516 
517 void Kded::recreateDone()
518 {
519  updateResourceList();
520 
521  initModules();
522 }
523 
524 void Kded::dirDeleted(const QString &path)
525 {
526  update(path);
527 }
528 
529 void Kded::update(const QString &)
530 {
531  m_pTimer->start(10000);
532 }
533 
534 void Kded::readDirectory(const QString &_path)
535 {
536  QString path(_path);
537  if (!path.endsWith(QLatin1Char('/'))) {
538  path += QLatin1Char('/');
539  }
540 
541  if (m_pDirWatch->contains(path)) { // Already seen this one?
542  return;
543  }
544 
545  Q_ASSERT(path != QDir::homePath());
546  m_pDirWatch->addDir(path, KDirWatch::WatchFiles | KDirWatch::WatchSubDirs); // add watch on this dir
547 }
548 
549 void Kded::registerWindowId(qlonglong windowId, const QString &sender)
550 {
551  if (!m_windowIdList.contains(sender)) {
552  m_serviceWatcher->addWatchedService(sender);
553  }
554 
555  m_globalWindowIdList.insert(windowId);
556  QList<qlonglong> windowIds = m_windowIdList.value(sender);
557  windowIds.append(windowId);
558  m_windowIdList.insert(sender, windowIds);
559 
560  for (KDEDModule *module : qAsConst(m_modules)) {
561  qCDebug(KDED) << module->moduleName();
562  Q_EMIT module->windowRegistered(windowId);
563  }
564 }
565 
566 void Kded::unregisterWindowId(qlonglong windowId, const QString &sender)
567 {
568  m_globalWindowIdList.remove(windowId);
569  QList<qlonglong> windowIds = m_windowIdList.value(sender);
570  if (!windowIds.isEmpty()) {
571  windowIds.removeAll(windowId);
572  if (windowIds.isEmpty()) {
573  m_serviceWatcher->removeWatchedService(sender);
574  m_windowIdList.remove(sender);
575  } else {
576  m_windowIdList.insert(sender, windowIds);
577  }
578  }
579 
580  for (KDEDModule *module : qAsConst(m_modules)) {
581  qCDebug(KDED) << module->moduleName();
582  Q_EMIT module->windowUnregistered(windowId);
583  }
584 }
585 
586 static void sighandler(int /*sig*/)
587 {
588  if (qApp) {
589  qApp->quit();
590  }
591 }
592 
593 KUpdateD::KUpdateD()
594 {
595  m_pDirWatch = new KDirWatch(this);
596  m_pTimer = new QTimer(this);
597  m_pTimer->setSingleShot(true);
598  connect(m_pTimer, &QTimer::timeout, this, &KUpdateD::runKonfUpdate);
599  QObject::connect(m_pDirWatch, &KDirWatch::dirty, this, &KUpdateD::slotNewUpdateFile);
600 
602  for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) {
603  QString path = *it;
604  Q_ASSERT(path != QDir::homePath());
605  if (path[path.length() - 1] != QLatin1Char('/')) {
606  path += QLatin1Char('/');
607  }
608 
609  if (!m_pDirWatch->contains(path)) {
610  m_pDirWatch->addDir(path, KDirWatch::WatchFiles);
611  }
612  }
613 }
614 
615 KUpdateD::~KUpdateD()
616 {
617 }
618 
619 void KUpdateD::runKonfUpdate()
620 {
621  ::runKonfUpdate();
622 }
623 
624 void KUpdateD::slotNewUpdateFile(const QString &dirty)
625 {
626  Q_UNUSED(dirty);
627  qCDebug(KDED) << dirty;
628  m_pTimer->start(500);
629 }
630 
631 KBuildsycocaAdaptor::KBuildsycocaAdaptor(QObject *parent)
632  : QDBusAbstractAdaptor(parent)
633 {
634 }
635 
636 void KBuildsycocaAdaptor::recreate()
637 {
638  Kded::self()->recreate();
639 }
640 
641 // KF6: remove
642 bool KBuildsycocaAdaptor::isTestModeEnabled()
643 {
644  return QStandardPaths::isTestModeEnabled();
645 }
646 
647 // KF6: remove
648 void KBuildsycocaAdaptor::setTestModeEnabled()
649 {
651 }
652 
653 static void setupAppInfo(QApplication *app)
654 {
655  app->setApplicationName(QStringLiteral("kded5"));
656  app->setApplicationDisplayName(QStringLiteral("KDE Daemon"));
657  app->setOrganizationDomain(QStringLiteral("kde.org"));
658  app->setApplicationVersion(QStringLiteral(KDED_VERSION_STRING));
659 }
660 
661 static bool detectPlatform(int argc, char **argv)
662 {
663  if (qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) {
664  return false;
665  }
666  for (int i = 0; i < argc; i++) {
667  /* clang-format off */
668  if (qstrcmp(argv[i], "-platform") == 0
669  || qstrcmp(argv[i], "--platform") == 0
670  || QByteArray(argv[i]).startsWith("-platform=")
671  || QByteArray(argv[i]).startsWith("--platform=")) { /* clang-format on */
672  return false;
673  }
674  }
675  const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
676  if (sessionType.isEmpty()) {
677  return false;
678  }
679  if (qstrcmp(sessionType.data(), "wayland") == 0) {
680  qputenv("QT_QPA_PLATFORM", "wayland");
681  return true;
682  } else if (qstrcmp(sessionType.data(), "x11") == 0) {
683  qputenv("QT_QPA_PLATFORM", "xcb");
684  return true;
685  }
686  return false;
687 }
688 
689 int main(int argc, char *argv[])
690 {
691 #ifdef Q_OS_OSX
692  CFBundleRef mainBundle = CFBundleGetMainBundle();
693  if (mainBundle) {
694  // get the application's Info Dictionary. For app bundles this would live in the bundle's Info.plist,
695  // for regular executables it is obtained in another way.
696  CFMutableDictionaryRef infoDict = (CFMutableDictionaryRef)CFBundleGetInfoDictionary(mainBundle);
697  if (infoDict) {
698  // Add or set the "LSUIElement" key with/to value "1". This can simply be a CFString.
699  CFDictionarySetValue(infoDict, CFSTR("LSUIElement"), CFSTR("1"));
700  // That's it. We're now considered as an "agent" by the window server, and thus will have
701  // neither menubar nor presence in the Dock or App Switcher.
702  }
703  }
704 #endif
705  // options.add("check", qi18n("Check Sycoca database only once"));
706 
707  // WABA: Make sure not to enable session management.
708  qunsetenv("SESSION_MANAGER");
709 
710  const bool unsetQpa = detectPlatform(argc, argv);
711 
712  // In older versions, QApplication creation was postponed until after
713  // testing for --check, in which case, only a QCoreApplication was created.
714  // Since that option is no longer used at startup, we removed that speed
715  // optimization for code clarity and easier support of standard parameters.
716 
717  // Fixes blurry icons with Fractional scaling
719  QApplication app(argc, argv);
720  if (unsetQpa) {
721  qunsetenv("QT_QPA_PLATFORM");
722  }
723  setupAppInfo(&app);
724  app.setQuitOnLastWindowClosed(false);
725 
726  QCommandLineParser parser;
727  parser.addHelpOption();
728  parser.addVersionOption();
729  parser.addOption(QCommandLineOption(QStringLiteral("check"), QStringLiteral("Check cache validity")));
730  QCommandLineOption replaceOption({QStringLiteral("replace")}, QStringLiteral("Replace an existing instance"));
731  parser.addOption(replaceOption);
732  parser.process(app);
733 
734  // Parse command line before checking D-Bus
735  if (parser.isSet(QStringLiteral("check"))) {
736  // KDBusService not wanted here.
738  runKonfUpdate();
739  return 0;
740  }
741 
743 
745  // Also register as all the names we should respond to (org.kde.kcookiejar, org.kde.khotkeys etc.)
746  // so that the calling code is independent from the physical "location" of the service.
747  const QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("kf5/kded"));
748  for (const KPluginMetaData &metaData : plugins) {
749  const QString serviceName = metaData.rawData().value(QStringLiteral("X-KDE-DBus-ServiceName")).toString();
750  if (serviceName.isEmpty()) {
751  continue;
752  }
753  if (!bus->registerService(serviceName)) {
754  qCWarning(KDED) << "Couldn't register name" << serviceName << "with DBUS - another process owns it already!";
755  }
756  }
757 
758  KSharedConfig::Ptr config = KSharedConfig::openConfig();
759  KConfigGroup cg(config, "General");
760 
761  bCheckSycoca = cg.readEntry("CheckSycoca", true);
762  bCheckUpdates = cg.readEntry("CheckUpdates", true);
763  delayedCheck = cg.readEntry("DelayedCheck", false);
764 
765 #ifndef Q_OS_WIN
766  signal(SIGTERM, sighandler);
767  signal(SIGHUP, sighandler);
768 #endif
769 
771 
772  Kded *kded = new Kded();
773 
774  kded->recreate(true); // initial
775 
776  if (bCheckUpdates) {
777  (void)new KUpdateD; // Watch for updates
778  }
779 
780  runKonfUpdate(); // Run it once.
781 
782  int result = app.exec(); // keep running
783 
784  delete kded;
785 
786  return result;
787 }
KCMUTILS_EXPORT void unloadModule(const KCModuleInfo &mod)
KCMUTILS_EXPORT KCModule * loadModule(const KCModuleInfo &module, ErrorReporting report, QWidget *parent=nullptr, const QStringList &args=QStringList())
QString value(const QString &key, const QString &defaultValue=QString()) const
QString fileName() const
int toInt(bool *ok, int base) const const
QStringList locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
void append(const T &value)
QDBusConnectionInterface * interface() const const
bool registerObject(const QString &path, QObject *object, QDBusConnection::RegisterOptions options)
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QCommandLineOption addVersionOption()
void windowUnregistered(qlonglong windowId)
QDBusConnection sessionBus()
void setOrganizationDomain(const QString &orgDomain)
void setAttribute(Qt::ApplicationAttribute attribute, bool on)
QSet::iterator insert(const T &value)
QString & remove(int position, int n)
QString homePath()
void setModuleName(const QString &name)
KSharedConfigPtr config()
void deleted(const QString &path)
KCRASH_EXPORT void setFlags(KCrash::CrashFlags flags)
T value(int i) const const
void timeout()
void setApplicationVersion(const QString &version)
void append(const T &value)
void windowRegistered(qlonglong windowId)
int toInt(bool *ok) const const
void moduleDeleted(KDEDModule *)
bool isEmpty() const const
bool isEmpty() const const
AA_UseHighDpiPixmaps
int removeAll(const T &value)
void serviceUnregistered(const QString &serviceName)
QCommandLineOption addHelpOption()
QJsonObject rawData() const
static QStringList readStringList(const QJsonObject &jo, const QString &key)
bool isSet(const QString &name) const const
void created(const QString &path)
static Ptr serviceByDesktopPath(const QString &_path)
QVariant toVariant() const const
QList::iterator end()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
void setQuitOnLastWindowClosed(bool quit)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
bool contains(const T &value) const const
void process(const QStringList &arguments)
KPluginFactory * factory()
static QString moduleForMessage(const QDBusMessage &message)
typedef ConstIterator
int length() const const
bool toBool() const const
bool addOption(const QCommandLineOption &option)
char * data()
void update(Part *part, const QByteArray &data, qint64 dataSize)
bool isValid() const const
QJsonValue value(const QString &key) const const
QDBusReply< QDBusConnectionInterface::RegisterServiceReply > registerService(const QString &serviceName, QDBusConnectionInterface::ServiceQueueOptions qoption, QDBusConnectionInterface::ServiceReplacementOptions roption)
void dirty(const QString &path)
static QVector< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter=std::function< bool(const KPluginMetaData &)>())
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setTestModeEnabled(bool testMode)
void setApplicationDisplayName(const QString &name)
static KSycoca * self()
QList::iterator begin()
QStringList allResourceDirs()
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
bool isValid() const
QString pluginId() const
void setApplicationName(const QString &application)
QString pluginName() const
KStandardDirs * dirs()
bool waitForFinished(int msecs)
void ensureCacheValid()
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue May 11 2021 22:50:53 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.