Plasma

pluginloader.cpp
1 /*
2  SPDX-FileCopyrightText: 2010 Ryan Rix <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "pluginloader.h"
8 
9 #include <QPointer>
10 #include <QStandardPaths>
11 
12 #include <KLazyLocalizedString>
13 #include <KRuntimePlatform>
14 #include <KService>
15 #include <KServiceTypeTrader>
16 #include <QDebug>
17 #include <QRegularExpression>
18 #include <kcoreaddons_export.h>
19 #include <kpackage/packageloader.h>
20 
21 #include "config-plasma.h"
22 
23 #include "applet.h"
24 #include "containment.h"
25 #include "containmentactions.h"
26 #include "dataengine.h"
27 #include "debug_p.h"
28 #include "package.h"
29 #include "private/applet_p.h"
30 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
31 #include "private/package_p.h"
32 #include "private/packagestructure_p.h"
33 #endif
34 #include "private/service_p.h" // for NullService
35 #include "private/storage_p.h"
36 
37 namespace Plasma
38 {
39 inline bool isContainmentMetaData(const KPluginMetaData &md)
40 {
41  return md.rawData().contains(QStringLiteral("X-Plasma-ContainmentType"))
42 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 89)
43  || md.serviceTypes().contains(QLatin1String("Plasma/Containment"))
44 #endif
45  ;
46 }
47 static PluginLoader *s_pluginLoader = nullptr;
48 
49 class PluginLoaderPrivate
50 {
51 public:
52  PluginLoaderPrivate()
53  : isDefaultLoader(false)
54  {
55  }
56 
57  static QSet<QString> s_customCategories;
58 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
60 #endif
61  bool isDefaultLoader;
62 
63  static QString s_dataEnginePluginDir;
64  static QString s_packageStructurePluginDir;
65  static QString s_plasmoidsPluginDir;
66  static QString s_servicesPluginDir;
67  static QString s_containmentActionsPluginDir;
68 
69  class Cache
70  {
71  // We only use this cache during start of the process to speed up many consecutive calls
72  // After that, we're too afraid to produce race conditions and it's not that time-critical anyway
73  // the 20 seconds here means that the cache is only used within 20sec during startup, after that,
74  // complexity goes up and we'd have to update the cache in order to avoid subtle bugs
75  // just not using the cache is way easier then, since it doesn't make *that* much of a difference,
76  // anyway
77  int maxCacheAge = 20;
78  qint64 pluginCacheAge = 0;
80 
81  public:
82  KPluginMetaData findPluginById(const QString &name, const QString &pluginNamespace);
83  };
84  Cache plasmoidCache;
85  Cache dataengineCache;
86  Cache containmentactionCache;
87 };
88 
89 QSet<QString> PluginLoaderPrivate::s_customCategories;
90 
91 QString PluginLoaderPrivate::s_dataEnginePluginDir = QStringLiteral("plasma/dataengine");
92 QString PluginLoaderPrivate::s_packageStructurePluginDir = QStringLiteral("plasma/packagestructure");
93 QString PluginLoaderPrivate::s_plasmoidsPluginDir = QStringLiteral("plasma/applets");
94 QString PluginLoaderPrivate::s_servicesPluginDir = QStringLiteral("plasma/services");
95 QString PluginLoaderPrivate::s_containmentActionsPluginDir = QStringLiteral("plasma/containmentactions");
96 
97 PluginLoader::PluginLoader()
98  : d(new PluginLoaderPrivate)
99 {
100 }
101 
102 PluginLoader::~PluginLoader()
103 {
104 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
105  for (const auto &wp : std::as_const(d->structures)) {
106  delete wp;
107  }
108 #endif
109  delete d;
110 }
111 
112 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86)
113 void PluginLoader::setPluginLoader(PluginLoader *loader)
114 {
115  if (!s_pluginLoader) {
116  s_pluginLoader = loader;
117  }
118 }
119 #endif
120 
121 PluginLoader *PluginLoader::self()
122 {
123  if (!s_pluginLoader) {
124  // we have been called before any PluginLoader was set, so just use the default
125  // implementation. this prevents plugins from nefariously injecting their own
126  // plugin loader if the app doesn't
127  s_pluginLoader = new PluginLoader;
128  s_pluginLoader->d->isDefaultLoader = true;
129  }
130 
131  return s_pluginLoader;
132 }
133 
134 Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVariantList &args)
135 {
136  if (name.isEmpty()) {
137  return nullptr;
138  }
139 
140 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86)
141  Applet *applet = d->isDefaultLoader ? nullptr : internalLoadApplet(name, appletId, args);
142  if (applet) {
143  return applet;
144  }
145 #else
146  Applet *applet = nullptr;
147 #endif
148 
149  if (appletId == 0) {
150  appletId = ++AppletPrivate::s_maxAppletId;
151  }
152 
153  auto plugin = d->plasmoidCache.findPluginById(name, PluginLoaderPrivate::s_plasmoidsPluginDir);
154  const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), name);
155 
156  // If the applet is using another applet package, search for the plugin of the other applet
157  if (!plugin.isValid()) {
158  const QString parentPlugin = p.metadata().value(QStringLiteral("X-Plasma-RootPath"));
159  if (!parentPlugin.isEmpty()) {
160  plugin = d->plasmoidCache.findPluginById(parentPlugin, PluginLoaderPrivate::s_plasmoidsPluginDir);
161  }
162  }
163 
164  if (plugin.isValid()) {
165  QPluginLoader loader(plugin.fileName());
166  QVariantList allArgs = {QVariant::fromValue(p), loader.metaData().toVariantMap(), appletId};
167  allArgs << args;
168  if (KPluginFactory *factory = KPluginFactory::loadFactory(plugin).plugin) {
169  if (factory->metaData().rawData().isEmpty()) {
170  factory->setMetaData(p.metadata());
171  }
172  applet = factory->create<Plasma::Applet>(nullptr, allArgs);
173  }
174  }
175  if (applet) {
176  return applet;
177  }
178 
179  QVariantList allArgs;
180  allArgs << QVariant::fromValue(p) << p.metadata().fileName() << appletId << args;
181 
182  if (isContainmentMetaData(p.metadata())) {
183  applet = new Containment(nullptr, p.metadata(), allArgs);
184  } else {
185  applet = new Applet(nullptr, p.metadata(), allArgs);
186  }
187 
188  const QString localePath = p.filePath("translations");
189  if (!localePath.isEmpty()) {
190  KLocalizedString::addDomainLocaleDir(QByteArray("plasma_applet_") + name.toLatin1(), localePath);
191  }
192  return applet;
193 }
194 
195 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 94)
196 DataEngine *PluginLoader::loadDataEngine(const QString &name)
197 {
198 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86)
199  DataEngine *engine = d->isDefaultLoader ? nullptr : internalLoadDataEngine(name);
200  if (engine) {
201  return engine;
202  }
203 #else
204  DataEngine *engine = nullptr;
205 #endif
206 
207  // Look for C++ plugins first
208  KPluginMetaData plugin = d->dataengineCache.findPluginById(name, PluginLoaderPrivate::s_dataEnginePluginDir);
209  if (plugin.isValid()) {
210  const QVariantList args{QVariant::fromValue(plugin)};
211  engine = KPluginFactory::instantiatePlugin<Plasma::DataEngine>(plugin, nullptr, args).plugin;
212  }
213  if (engine) {
214  return engine;
215  }
216 
217  const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/DataEngine"), name);
218  if (!p.isValid()) {
219  return nullptr;
220  }
221 
222  return new DataEngine(p.metadata(), nullptr);
223 }
224 #endif
225 
226 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 94)
227 QStringList PluginLoader::listAllEngines(const QString &parentApp)
228 {
229  QStringList engines;
230  // Look for C++ plugins first
231  auto filter = [&parentApp](const KPluginMetaData &md) -> bool {
232  return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp;
233  };
234  QVector<KPluginMetaData> plugins;
235  if (parentApp.isEmpty()) {
236  plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir);
237  } else {
238  plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filter);
239  }
240 
241  for (auto &plugin : std::as_const(plugins)) {
242  engines << plugin.pluginId();
243  }
244 
245  const QList<KPluginMetaData> packagePlugins = KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/DataEngine"));
246  for (const auto &plugin : packagePlugins) {
247  engines << plugin.pluginId();
248  }
249 
250  return engines;
251 }
252 #endif
253 
254 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 77)
255 KPluginInfo::List PluginLoader::listEngineInfo(const QString &parentApp)
256 {
257  return PluginLoader::self()->listDataEngineInfo(parentApp);
258 }
259 #endif
260 
261 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 81)
262 KPluginInfo::List PluginLoader::listEngineInfoByCategory(const QString &category, const QString &parentApp)
263 {
264  KPluginInfo::List list;
265 
266  // Look for C++ plugins first
267  auto filterNormal = [&category](const KPluginMetaData &md) -> bool {
268  return md.value(QStringLiteral("X-KDE-PluginInfo-Category")) == category;
269  };
270  auto filterParentApp = [&category, &parentApp](const KPluginMetaData &md) -> bool {
271  return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp //
272  && md.value(QStringLiteral("X-KDE-PluginInfo-Category")) == category;
273  };
274  QVector<KPluginMetaData> plugins;
275  if (parentApp.isEmpty()) {
276  plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filterNormal);
277  } else {
278  plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filterParentApp);
279  }
280 
281  list = KPluginInfo::fromMetaData(plugins);
282 
283  // TODO FIXME: PackageLoader needs to have a function to inject packageStructures
284  const QList<KPluginMetaData> packagePlugins = KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/DataEngine"));
285  list << KPluginInfo::fromMetaData(packagePlugins.toVector());
286 
287  return list;
288 }
289 #endif
290 
291 Service *PluginLoader::loadService(const QString &name, const QVariantList &args, QObject *parent)
292 {
293 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86)
294  Service *service = d->isDefaultLoader ? nullptr : internalLoadService(name, args, parent);
295  if (service) {
296  return service;
297  }
298 #else
299  Service *service = nullptr;
300 #endif
301 
302  // TODO: scripting API support
303  if (name.isEmpty()) {
304  return new NullService(QString(), parent);
305  } else if (name == QLatin1String("org.kde.servicestorage")) {
306  return new Storage(parent);
307  }
308 
309  // Look for C++ plugins first
310  KPluginMetaData plugin = KPluginMetaData::findPluginById(PluginLoaderPrivate::s_servicesPluginDir, name);
311  if (plugin.isValid()) {
312  service = KPluginFactory::instantiatePlugin<Plasma::Service>(plugin, parent, args).plugin;
313  }
314 
315  if (service) {
316  if (service->name().isEmpty()) {
317  service->setName(name);
318  }
319  return service;
320  } else {
321  return new NullService(name, parent);
322  }
323 }
324 
325 ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, const QString &name, const QVariantList &args)
326 {
327  if (name.isEmpty()) {
328  return nullptr;
329  }
330 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86)
331  ContainmentActions *actions = d->isDefaultLoader ? nullptr : internalLoadContainmentActions(parent, name, args);
332  if (actions) {
333  return actions;
334  }
335 #endif
336 
337  KPluginMetaData plugin = d->containmentactionCache.findPluginById(name, PluginLoaderPrivate::s_containmentActionsPluginDir);
338 
339  if (plugin.isValid()) {
340  if (auto res = KPluginFactory::instantiatePlugin<Plasma::ContainmentActions>(plugin, nullptr, {QVariant::fromValue(plugin)})) {
341  return res.plugin;
342  }
343  }
344 
345 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 88)
346  QString constraint = QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
347  KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("Plasma/ContainmentActions"), constraint);
348 
349  if (offers.isEmpty()) {
350 #ifndef NDEBUG
351  qCDebug(LOG_PLASMA) << "offers is empty for " << name;
352 #endif
353  return nullptr;
354  }
355 
356  KService::Ptr offer = offers.first();
357  qCWarning(LOG_PLASMA) << "Plugin" << name << "was loaded using deprecated KServiceTypeTrader."
358  << "Use embedded json metadata and install the plugin in plasma/containmentactions namespace instead";
359 
360  KPluginMetaData data(offer->library());
361  QVariantList allArgs;
362  allArgs << offer->storageId() << args;
363 
364  return KPluginFactory::instantiatePlugin<Plasma::ContainmentActions>(data, nullptr, allArgs).plugin;
365 #else
366  return nullptr;
367 #endif
368 }
369 
370 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
371 Package PluginLoader::loadPackage(const QString &packageFormat, const QString &specialization)
372 {
373  if (!d->isDefaultLoader) {
374  Package p = internalLoadPackage(packageFormat, specialization);
375  if (p.hasValidStructure()) {
376  return p;
377  }
378  }
379 
380  if (packageFormat.isEmpty()) {
381  return Package();
382  }
383 
384  const QString hashkey = packageFormat + QLatin1Char('%') + specialization;
385  PackageStructure *structure = d->structures.value(hashkey).data();
386 
387  if (structure) {
388  return Package(structure);
389  }
390 
392 
393  if (internalStructure) {
394  structure = new PackageStructure();
395  structure->d->internalStructure = internalStructure;
396  // fallback to old structures
397  } else {
398  auto filter = [packageFormat](const KPluginMetaData &md) -> bool {
399  return md.value(QStringLiteral("X-KDE-PluginInfo-Name")) == packageFormat;
400  };
401 
402  const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_packageStructurePluginDir, filter);
403 
404  if (!plugins.isEmpty()) {
405  if (auto res = KPluginFactory::instantiatePlugin<Plasma::PackageStructure>(plugins.first())) {
406  structure = res.plugin;
407  } else {
408  qWarning() << "Error loading plugin:" << res.errorString;
409  }
410 
411  if (structure) {
412  structure->d->internalStructure = new PackageStructureWrapper(structure);
413  }
414  }
415  }
416 
417  if (structure) {
418  d->structures.insert(hashkey, structure);
419  return Package(structure);
420  }
421 
422  return Package();
423 }
424 #endif
425 QList<KPluginMetaData> listAppletMetaDataInternal(const QString &category, const QString &parentApp)
426 {
427  auto platforms = KRuntimePlatform::runtimePlatform();
428  // For now desktop always lists everything
429  if (platforms.contains(QStringLiteral("desktop"))) {
430  platforms.clear();
431  }
432 
433  // FIXME: this assumes we are always use packages.. no pure c++
434  std::function<bool(const KPluginMetaData &)> filter;
435  if (category.isEmpty()) { // use all but the excluded categories
436  KConfigGroup group(KSharedConfig::openConfig(), "General");
437  QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
438 
439  filter = [excluded, parentApp, platforms](const KPluginMetaData &md) -> bool {
440  if (!platforms.isEmpty() && !md.formFactors().isEmpty()) {
441  bool found = false;
442  for (const auto &plat : platforms) {
443  if (md.formFactors().contains(plat)) {
444  found = true;
445  break;
446  }
447  }
448 
449  if (!found) {
450  return false;
451  }
452  }
453 
454  const QString pa = md.value(QStringLiteral("X-KDE-ParentApp"));
455  return (parentApp.isEmpty() || pa == parentApp) && !excluded.contains(md.category());
456  };
457  } else { // specific category (this could be an excluded one - is that bad?)
458 
459  filter = [category, parentApp, platforms](const KPluginMetaData &md) -> bool {
460  if (!platforms.isEmpty() && !md.formFactors().isEmpty()) {
461  bool found = false;
462  for (const auto &plat : platforms) {
463  if (md.formFactors().contains(plat)) {
464  found = true;
465  break;
466  }
467  }
468 
469  if (!found) {
470  return false;
471  }
472  }
473 
474  const QString pa = md.value(QStringLiteral("X-KDE-ParentApp"));
475 
476  if (category == QLatin1String("Miscellaneous")) {
477  return (parentApp.isEmpty() || pa == parentApp) && (md.category() == category || md.category().isEmpty());
478  } else {
479  return (parentApp.isEmpty() || pa == parentApp) && md.category() == category;
480  }
481  };
482  }
483 
484  return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
485 }
486 
487 QList<KPluginMetaData> PluginLoader::listAppletMetaData(const QString &category)
488 {
489  return listAppletMetaDataInternal(category, QString());
490 }
491 
492 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 88)
493 QList<KPluginMetaData> PluginLoader::listAppletMetaData(const QString &category, const QString &parentApp)
494 {
495  return listAppletMetaDataInternal(category, parentApp);
496 }
497 #endif
498 
499 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 28)
500 KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QString &parentApp)
501 {
502  const auto plugins = listAppletMetaData(category, parentApp);
503 
504 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0)
505  KPluginInfo::List list;
506  // NOTE: it still produces kplugininfos from KServices because some user code expects
507  // info.service() to be valid and would crash otherwise
508  for (const auto &md : plugins) {
509  QT_WARNING_PUSH
510  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
511  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
513  QT_WARNING_POP
514  if (!pi.isValid()) {
515  qCWarning(LOG_PLASMA) << "Could not load plugin info for plugin :" << md.pluginId() << "skipping plugin";
516  continue;
517  }
518  list << pi;
519  }
520  return list;
521 #else
522  return KPluginInfo::fromMetaData(plugins.toVector());
523 #endif
524 }
525 #endif
526 
527 QList<KPluginMetaData> PluginLoader::listAppletMetaDataForMimeType(const QString &mimeType)
528 {
529  auto filter = [&mimeType](const KPluginMetaData &md) -> bool {
530  return md.value(QStringLiteral("X-Plasma-DropMimeTypes"), QStringList()).contains(mimeType);
531  };
532  return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
533 }
534 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
535 KPluginInfo::List PluginLoader::listAppletInfoForMimeType(const QString &mimeType)
536 {
537  return KPluginInfo::fromMetaData(listAppletMetaDataForMimeType(mimeType).toVector());
538 }
539 #endif
540 
541 QList<KPluginMetaData> PluginLoader::listAppletMetaDataForUrl(const QUrl &url)
542 {
543  QString parentApp;
545  if (app) {
546  parentApp = app->applicationName();
547  }
548 
549  auto filter = [&parentApp](const KPluginMetaData &md) -> bool {
550  const QString pa = md.value(QStringLiteral("X-KDE-ParentApp"));
551  return (parentApp.isEmpty() || pa == parentApp) //
552  && !md.value(QStringLiteral("X-Plasma-DropUrlPatterns"), QStringList()).isEmpty();
553  };
554  const QList<KPluginMetaData> allApplets = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
555 
556  QList<KPluginMetaData> filtered;
557  for (const KPluginMetaData &md : allApplets) {
558  const QStringList urlPatterns = md.value(QStringLiteral("X-Plasma-DropUrlPatterns"), QStringList());
559  for (const QString &glob : urlPatterns) {
561  if (rx.match(url.toString()).hasMatch()) {
562  filtered << md;
563  }
564  }
565  }
566 
567  return filtered;
568 }
569 
570 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 36)
571 KPluginInfo::List PluginLoader::listAppletInfoForUrl(const QUrl &url)
572 {
573  return KPluginInfo::fromMetaData(listAppletMetaDataForUrl(url).toVector());
574 }
575 #endif
576 
577 QStringList PluginLoader::listAppletCategories(const QString &parentApp, bool visibleOnly)
578 {
579  KConfigGroup group(KSharedConfig::openConfig(), "General");
580  const QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
581  auto filter = [&parentApp, &excluded, visibleOnly](const KPluginMetaData &md) -> bool {
582  const QString pa = md.value(QStringLiteral("X-KDE-ParentApp"));
583  return (parentApp.isEmpty() || pa == parentApp) //
584  && (excluded.isEmpty() || excluded.contains(md.value(QStringLiteral("X-KDE-PluginInfo-Category")))) //
585  && (!visibleOnly || !md.isHidden());
586  };
587  const QList<KPluginMetaData> allApplets = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
588 
589  QStringList categories;
590  for (auto &plugin : allApplets) {
591  if (plugin.category().isEmpty()) {
592  if (!categories.contains(i18nc("misc category", "Miscellaneous"))) {
593  categories << i18nc("misc category", "Miscellaneous");
594  }
595  } else {
596  categories << plugin.category();
597  }
598  }
599  categories.sort();
600  return categories;
601 }
602 
603 void PluginLoader::setCustomAppletCategories(const QStringList &categories)
604 {
605  PluginLoaderPrivate::s_customCategories = QSet<QString>(categories.begin(), categories.end());
606 }
607 
608 QStringList PluginLoader::customAppletCategories() const
609 {
610  return PluginLoaderPrivate::s_customCategories.values();
611 }
612 
613 QString PluginLoader::appletCategory(const QString &appletName)
614 {
615  if (appletName.isEmpty()) {
616  return QString();
617  }
618 
619  const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), appletName);
620  if (!p.isValid()) {
621  return QString();
622  }
623 
624  return p.metadata().category();
625 }
626 
627 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
628 KPluginInfo::List PluginLoader::listContainments(const QString &category, const QString &parentApp)
629 {
630  return listContainmentsOfType(QString(), category, parentApp);
631 }
632 #endif
633 
634 QList<KPluginMetaData> PluginLoader::listContainmentsMetaData(std::function<bool(const KPluginMetaData &)> filter)
635 {
636  auto ownFilter = [filter](const KPluginMetaData &md) -> bool {
637  return isContainmentMetaData(md) && filter(md);
638  };
639 
640  return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), ownFilter);
641 }
642 
643 QList<KPluginMetaData> PluginLoader::listContainmentsMetaDataOfType(const QString &type)
644 {
645  auto filter = [type](const KPluginMetaData &md) -> bool {
646  return md.value(QStringLiteral("X-Plasma-ContainmentType")) == type;
647  };
648 
649  return listContainmentsMetaData(filter);
650 }
651 
652 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
653 KPluginInfo::List PluginLoader::listContainmentsOfType(const QString &type, const QString &category, const QString &parentApp)
654 {
655  auto filter = [&type, &category, &parentApp](const KPluginMetaData &md) -> bool {
656  if (isContainmentMetaData(md)) {
657  return false;
658  }
659  if (!parentApp.isEmpty() && md.value(QStringLiteral("X-KDE-ParentApp")) != parentApp) {
660  return false;
661  }
662 
663  if (!type.isEmpty() && md.value(QStringLiteral("X-Plasma-ContainmentType")) != type) {
664  return false;
665  }
666 
667  if (!category.isEmpty() && md.value(QStringLiteral("X-KDE-PluginInfo-Category")) != category) {
668  return false;
669  }
670 
671  return true;
672  };
673 
674  return KPluginInfo::fromMetaData(KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter).toVector());
675 }
676 #endif
677 
678 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
679 KPluginInfo::List PluginLoader::listContainmentsForMimeType(const QString &mimeType)
680 {
681  auto filter = [&mimeType](const KPluginMetaData &md) -> bool {
682  return isContainmentMetaData(md) && md.value(QStringLiteral("X-Plasma-DropMimeTypes"), QStringList()).contains(mimeType);
683  };
684 
685  return KPluginInfo::fromMetaData(KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter).toVector());
686 }
687 #endif
688 
689 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
690 QStringList PluginLoader::listContainmentTypes()
691 {
692  const KPluginInfo::List containmentInfos = listContainments();
693  QSet<QString> types;
694 
695  for (const KPluginInfo &containmentInfo : containmentInfos) {
696  const QStringList theseTypes = containmentInfo.property(QStringLiteral("X-Plasma-ContainmentType")).toStringList();
697  for (const QString &type : theseTypes) {
698  types.insert(type);
699  }
700  }
701 
702  return types.values();
703 }
704 #endif
705 
706 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 77)
707 KPluginInfo::List PluginLoader::listDataEngineInfo(const QString &parentApp)
708 {
709  return KPluginInfo::fromMetaData(listDataEngineMetaData(parentApp));
710 }
711 #endif
712 
713 QVector<KPluginMetaData> PluginLoader::listDataEngineMetaData(const QString &parentApp)
714 {
715  auto filter = [&parentApp](const KPluginMetaData &md) -> bool {
716  return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp;
717  };
718 
719  QVector<KPluginMetaData> plugins;
720  if (parentApp.isEmpty()) {
721  plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir);
722  } else {
723  plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filter);
724  }
725 
726  return plugins;
727 }
728 
729 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 77)
730 KPluginInfo::List PluginLoader::listContainmentActionsInfo(const QString &parentApp)
731 {
732  return KPluginInfo::fromMetaData(listContainmentActionsMetaData(parentApp));
733 }
734 #endif
735 
736 QVector<KPluginMetaData> PluginLoader::listContainmentActionsMetaData(const QString &parentApp)
737 {
738  auto filter = [&parentApp](const KPluginMetaData &md) -> bool {
739  return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp;
740  };
741 
742  QVector<KPluginMetaData> plugins;
743  if (parentApp.isEmpty()) {
744  plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_containmentActionsPluginDir);
745  } else {
746  plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_containmentActionsPluginDir, filter);
747  }
748 
749 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0)
750  QSet<QString> knownPlugins;
751  for (const KPluginMetaData &p : std::as_const(plugins)) {
752  knownPlugins.insert(p.pluginId());
753  }
754  QString constraint;
755  if (!parentApp.isEmpty()) {
756  constraint = QLatin1String("[X-KDE-ParentApp] == '") + parentApp + QLatin1Char('\'');
757  }
758  const KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("Plasma/ContainmentActions"), constraint);
759  for (KService::Ptr s : offers) {
760  if (!knownPlugins.contains(s->pluginKeyword())) {
761  QT_WARNING_PUSH
762  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
763  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
764  plugins.append(KPluginInfo(s).toMetaData());
765  QT_WARNING_POP
766  }
767  }
768 #endif
769 
770  return plugins;
771 }
772 
773 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86)
774 Applet *PluginLoader::internalLoadApplet(const QString &name, uint appletId, const QVariantList &args)
775 {
776  Q_UNUSED(name)
777  Q_UNUSED(appletId)
778  Q_UNUSED(args)
779  return nullptr;
780 }
781 
782 DataEngine *PluginLoader::internalLoadDataEngine(const QString &name)
783 {
784  Q_UNUSED(name)
785  return nullptr;
786 }
787 
788 ContainmentActions *PluginLoader::internalLoadContainmentActions(Containment *containment, const QString &name, const QVariantList &args)
789 {
790  Q_UNUSED(containment)
791  Q_UNUSED(name)
792  Q_UNUSED(args)
793  return nullptr;
794 }
795 
796 Service *PluginLoader::internalLoadService(const QString &name, const QVariantList &args, QObject *parent)
797 {
798  Q_UNUSED(name)
799  Q_UNUSED(args)
800  Q_UNUSED(parent)
801  return nullptr;
802 }
803 
804 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83)
805 Package PluginLoader::internalLoadPackage(const QString &name, const QString &specialization)
806 {
807  Q_UNUSED(name);
808  Q_UNUSED(specialization);
809  return Package();
810 }
811 #endif
812 
813 KPluginInfo::List PluginLoader::internalAppletInfo(const QString &category) const
814 {
815  Q_UNUSED(category)
816  return KPluginInfo::List();
817 }
818 
819 KPluginInfo::List PluginLoader::internalDataEngineInfo() const
820 {
821  return KPluginInfo::List();
822 }
823 
824 KPluginInfo::List PluginLoader::internalServiceInfo() const
825 {
826  return KPluginInfo::List();
827 }
828 
829 KPluginInfo::List PluginLoader::internalContainmentActionsInfo() const
830 {
831  return KPluginInfo::List();
832 }
833 #endif
834 
835 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 88)
836 static KPluginInfo::List standardInternalInfo(const QString &type, const QString &category = QString())
837 {
839  QLatin1String(PLASMA_RELATIVE_DATA_INSTALL_DIR "/internal/") + type + QLatin1String("/*.desktop"),
841 
842  const KPluginInfo::List allInfo = KPluginInfo::fromFiles(files);
843 
844  if (category.isEmpty() || allInfo.isEmpty()) {
845  return allInfo;
846  }
847 
848  KPluginInfo::List matchingInfo;
849  for (const KPluginInfo &info : allInfo) {
850  if (info.category().compare(category, Qt::CaseInsensitive) == 0) {
851  matchingInfo << info;
852  }
853  }
854 
855  return matchingInfo;
856 }
857 
858 KPluginInfo::List PluginLoader::standardInternalAppletInfo(const QString &category) const
859 {
860  return standardInternalInfo(QStringLiteral("applets"), category);
861 }
862 
863 KPluginInfo::List PluginLoader::standardInternalDataEngineInfo() const
864 {
865  return standardInternalInfo(QStringLiteral("dataengines"));
866 }
867 
868 KPluginInfo::List PluginLoader::standardInternalServiceInfo() const
869 {
870  return standardInternalInfo(QStringLiteral("services"));
871 }
872 #endif
873 
874 KPluginMetaData PluginLoaderPrivate::Cache::findPluginById(const QString &name, const QString &pluginNamespace)
875 {
876  const qint64 now = qRound64(QDateTime::currentMSecsSinceEpoch() / 1000.0);
877  bool useRuntimeCache = true;
878 
879  if (pluginCacheAge == 0) {
880  // Find all the plugins now, but only once
881  pluginCacheAge = now;
882 
883  const auto metaDataList = KPluginMetaData::findPlugins(pluginNamespace, {}, KPluginMetaData::AllowEmptyMetaData);
884  for (const KPluginMetaData &metadata : metaDataList) {
885  plugins.insert(metadata.pluginId(), metadata);
886  }
887  } else if (now - pluginCacheAge > maxCacheAge) {
888  // cache is old and we're not within a few seconds of startup anymore
889  useRuntimeCache = false;
890  plugins.clear();
891  }
892 
893  // if name wasn't a path, pluginName == name
894  const QString pluginName = name.section(QLatin1Char('/'), -1);
895 
896  if (useRuntimeCache) {
897  KPluginMetaData data = plugins.value(name);
898  qCDebug(LOG_PLASMA) << "loading applet by name" << name << useRuntimeCache << data.isValid();
899  return data;
900  } else {
902  pluginNamespace,
903  [&pluginName](const KPluginMetaData &data) {
904  return data.pluginId() == pluginName;
905  },
907  return offers.isEmpty() ? KPluginMetaData() : offers.first();
908  }
909 }
910 
911 } // Plasma Namespace
T & first()
QString anchoredPattern(const QString &expression)
QString readEntry(const char *key, const char *aDefault=nullptr) const
QJsonObject rawData() const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString wildcardToRegularExpression(const QString &pattern)
bool isEmpty() const const
QString section(QChar sep, int start, int end, QString::SectionFlags flags) const const
Data provider for plasmoids (Plasma plugins)
Definition: dataengine.h:50
Namespace for everything in libplasma.
Definition: datamodel.cpp:14
CaseInsensitive
Package loadPackage(const QString &packageFormat, const QString &packagePath=QString())
QVariant fromValue(const T &value)
KCOREADDONS_EXPORT QStringList runtimePlatform()
QString metaDataFileName() const
QStringList serviceTypes() const
void setName(const QString &name)
Sets the name of the Service; useful for Services not loaded from plugins, which use the plugin name ...
Definition: service.cpp:122
QVariantMap toVariantMap() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
void append(const T &value)
bool isValid() const
qint64 currentMSecsSinceEpoch()
QString fileName() const
QByteArray toLatin1() const const
static KPluginInfo::List fromFiles(const QStringList &files, const KConfigGroup &config=KConfigGroup())
static void addDomainLocaleDir(const QByteArray &domain, const QString &path)
static KPluginInfo fromMetaData(const KPluginMetaData &meta)
bool isHidden() const
T & first()
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
KPluginMetaData metadata() const
bool contains(const QString &key) const const
QJsonObject metaData() const const
The base ContainmentActions class.
QVector< T > toVector() const const
QString toString(QUrl::FormattingOptions options) const const
QList< KPluginMetaData > findPackages(const QString &packageFormat, const QString &packageRoot=QString(), std::function< bool(const KPluginMetaData &)> filter=std::function< bool(const KPluginMetaData &)>())
QString category() const
static PackageLoader * self()
QStringList formFactors() const
This class provides a generic API for write access to settings or services.
Definition: service.h:77
QList< KPluginMetaData > listPackages(const QString &packageFormat, const QString &packageRoot=QString())
bool isEmpty() const const
QCoreApplication * instance()
KPackage::PackageStructure * loadPackageStructure(const QString &packageFormat)
QFuture< void > filter(Sequence &sequence, KeepFunctor filterFunction)
bool isEmpty() const const
bool hasMatch() const const
static KServiceTypeTrader * self()
QRegularExpressionMatch match(const QString &subject, int offset, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions) const const
static Result< KPluginFactory > loadFactory(const KPluginMetaData &data)
void insert(int i, const T &value)
bool contains(const T &value) const const
bool value(const QString &key, bool defaultValue) const
static QVector< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter, KPluginMetaDataOption option)
bool hasValidStructure() const
Definition: package.cpp:95
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
static Ptr serviceByStorageId(const QString &_storageId)
QString filePath(const QByteArray &key, const QString &filename=QString()) const
bool isValid() const
QString name(StandardShortcut id)
QStringList locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QSet::iterator insert(const T &value)
QList::iterator begin()
QList< KPluginInfo > List
static KPluginMetaData findPluginById(const QString &directory, const QString &pluginId)
QChar * data()
KService::List query(const QString &servicetype, const QString &constraint=QString()) const
object representing an installed Plasma package
Definition: package.h:76
QList::iterator end()
QList< T > values() const const
QString pluginId() const
The base class for plugins that provide backgrounds and applet grouping containers.
Definition: containment.h:45
Category category(StandardShortcut id)
The base Applet class.
Definition: applet.h:71
void sort(Qt::CaseSensitivity cs)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Mar 26 2023 04:14:48 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.