File indexing completed on 2023-10-01 04:11:45
0001 /* 0002 SPDX-FileCopyrightText: 2010 Ryan Rix <ry@n.rix.si> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "pluginloader.h" 0008 0009 #include <QPointer> 0010 #include <QStandardPaths> 0011 0012 #include <KLazyLocalizedString> 0013 #include <KRuntimePlatform> 0014 #include <KService> 0015 #include <KServiceTypeTrader> 0016 #include <QDebug> 0017 #include <QRegularExpression> 0018 #include <kcoreaddons_export.h> 0019 #include <kpackage/packageloader.h> 0020 0021 #include "config-plasma.h" 0022 0023 #include "applet.h" 0024 #include "containment.h" 0025 #include "containmentactions.h" 0026 #include "dataengine.h" 0027 #include "debug_p.h" 0028 #include "package.h" 0029 #include "private/applet_p.h" 0030 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0031 #include "private/package_p.h" 0032 #include "private/packagestructure_p.h" 0033 #endif 0034 #include "private/service_p.h" // for NullService 0035 #include "private/storage_p.h" 0036 0037 namespace Plasma 0038 { 0039 inline bool isContainmentMetaData(const KPluginMetaData &md) 0040 { 0041 return md.rawData().contains(QStringLiteral("X-Plasma-ContainmentType")) 0042 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 89) 0043 || md.serviceTypes().contains(QLatin1String("Plasma/Containment")) 0044 #endif 0045 ; 0046 } 0047 static PluginLoader *s_pluginLoader = nullptr; 0048 0049 class PluginLoaderPrivate 0050 { 0051 public: 0052 PluginLoaderPrivate() 0053 : isDefaultLoader(false) 0054 { 0055 } 0056 0057 static QSet<QString> s_customCategories; 0058 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0059 QHash<QString, QPointer<PackageStructure>> structures; 0060 #endif 0061 bool isDefaultLoader; 0062 0063 static QString s_dataEnginePluginDir; 0064 static QString s_packageStructurePluginDir; 0065 static QString s_plasmoidsPluginDir; 0066 static QString s_servicesPluginDir; 0067 static QString s_containmentActionsPluginDir; 0068 0069 class Cache 0070 { 0071 // We only use this cache during start of the process to speed up many consecutive calls 0072 // After that, we're too afraid to produce race conditions and it's not that time-critical anyway 0073 // the 20 seconds here means that the cache is only used within 20sec during startup, after that, 0074 // complexity goes up and we'd have to update the cache in order to avoid subtle bugs 0075 // just not using the cache is way easier then, since it doesn't make *that* much of a difference, 0076 // anyway 0077 int maxCacheAge = 20; 0078 qint64 pluginCacheAge = 0; 0079 QHash<QString, KPluginMetaData> plugins; 0080 0081 public: 0082 KPluginMetaData findPluginById(const QString &name, const QString &pluginNamespace); 0083 }; 0084 Cache plasmoidCache; 0085 Cache dataengineCache; 0086 Cache containmentactionCache; 0087 }; 0088 0089 QSet<QString> PluginLoaderPrivate::s_customCategories; 0090 0091 QString PluginLoaderPrivate::s_dataEnginePluginDir = QStringLiteral("plasma/dataengine"); 0092 QString PluginLoaderPrivate::s_packageStructurePluginDir = QStringLiteral("plasma/packagestructure"); 0093 QString PluginLoaderPrivate::s_plasmoidsPluginDir = QStringLiteral("plasma/applets"); 0094 QString PluginLoaderPrivate::s_servicesPluginDir = QStringLiteral("plasma/services"); 0095 QString PluginLoaderPrivate::s_containmentActionsPluginDir = QStringLiteral("plasma/containmentactions"); 0096 0097 PluginLoader::PluginLoader() 0098 : d(new PluginLoaderPrivate) 0099 { 0100 } 0101 0102 PluginLoader::~PluginLoader() 0103 { 0104 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0105 for (const auto &wp : std::as_const(d->structures)) { 0106 delete wp; 0107 } 0108 #endif 0109 delete d; 0110 } 0111 0112 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86) 0113 void PluginLoader::setPluginLoader(PluginLoader *loader) 0114 { 0115 if (!s_pluginLoader) { 0116 s_pluginLoader = loader; 0117 } 0118 } 0119 #endif 0120 0121 PluginLoader *PluginLoader::self() 0122 { 0123 if (!s_pluginLoader) { 0124 // we have been called before any PluginLoader was set, so just use the default 0125 // implementation. this prevents plugins from nefariously injecting their own 0126 // plugin loader if the app doesn't 0127 s_pluginLoader = new PluginLoader; 0128 s_pluginLoader->d->isDefaultLoader = true; 0129 } 0130 0131 return s_pluginLoader; 0132 } 0133 0134 Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVariantList &args) 0135 { 0136 if (name.isEmpty()) { 0137 return nullptr; 0138 } 0139 0140 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86) 0141 Applet *applet = d->isDefaultLoader ? nullptr : internalLoadApplet(name, appletId, args); 0142 if (applet) { 0143 return applet; 0144 } 0145 #else 0146 Applet *applet = nullptr; 0147 #endif 0148 0149 if (appletId == 0) { 0150 appletId = ++AppletPrivate::s_maxAppletId; 0151 } 0152 0153 auto plugin = d->plasmoidCache.findPluginById(name, PluginLoaderPrivate::s_plasmoidsPluginDir); 0154 const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), name); 0155 0156 // If the applet is using another applet package, search for the plugin of the other applet 0157 if (!plugin.isValid()) { 0158 const QString parentPlugin = p.metadata().value(QStringLiteral("X-Plasma-RootPath")); 0159 if (!parentPlugin.isEmpty()) { 0160 plugin = d->plasmoidCache.findPluginById(parentPlugin, PluginLoaderPrivate::s_plasmoidsPluginDir); 0161 } 0162 } 0163 0164 if (plugin.isValid()) { 0165 QPluginLoader loader(plugin.fileName()); 0166 QVariantList allArgs = {QVariant::fromValue(p), loader.metaData().toVariantMap(), appletId}; 0167 allArgs << args; 0168 if (KPluginFactory *factory = KPluginFactory::loadFactory(plugin).plugin) { 0169 if (factory->metaData().rawData().isEmpty()) { 0170 factory->setMetaData(p.metadata()); 0171 } 0172 applet = factory->create<Plasma::Applet>(nullptr, allArgs); 0173 } 0174 } 0175 if (applet) { 0176 return applet; 0177 } 0178 0179 QVariantList allArgs; 0180 allArgs << QVariant::fromValue(p) << p.metadata().fileName() << appletId << args; 0181 0182 if (isContainmentMetaData(p.metadata())) { 0183 applet = new Containment(nullptr, p.metadata(), allArgs); 0184 } else { 0185 applet = new Applet(nullptr, p.metadata(), allArgs); 0186 } 0187 0188 const QString localePath = p.filePath("translations"); 0189 if (!localePath.isEmpty()) { 0190 KLocalizedString::addDomainLocaleDir(QByteArray("plasma_applet_") + name.toLatin1(), localePath); 0191 } 0192 return applet; 0193 } 0194 0195 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 94) 0196 DataEngine *PluginLoader::loadDataEngine(const QString &name) 0197 { 0198 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86) 0199 DataEngine *engine = d->isDefaultLoader ? nullptr : internalLoadDataEngine(name); 0200 if (engine) { 0201 return engine; 0202 } 0203 #else 0204 DataEngine *engine = nullptr; 0205 #endif 0206 0207 // Look for C++ plugins first 0208 KPluginMetaData plugin = d->dataengineCache.findPluginById(name, PluginLoaderPrivate::s_dataEnginePluginDir); 0209 if (plugin.isValid()) { 0210 const QVariantList args{QVariant::fromValue(plugin)}; 0211 engine = KPluginFactory::instantiatePlugin<Plasma::DataEngine>(plugin, nullptr, args).plugin; 0212 } 0213 if (engine) { 0214 return engine; 0215 } 0216 0217 const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/DataEngine"), name); 0218 if (!p.isValid()) { 0219 return nullptr; 0220 } 0221 0222 return new DataEngine(p.metadata(), nullptr); 0223 } 0224 #endif 0225 0226 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 94) 0227 QStringList PluginLoader::listAllEngines(const QString &parentApp) 0228 { 0229 QStringList engines; 0230 // Look for C++ plugins first 0231 auto filter = [&parentApp](const KPluginMetaData &md) -> bool { 0232 return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp; 0233 }; 0234 QVector<KPluginMetaData> plugins; 0235 if (parentApp.isEmpty()) { 0236 plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir); 0237 } else { 0238 plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filter); 0239 } 0240 0241 for (auto &plugin : std::as_const(plugins)) { 0242 engines << plugin.pluginId(); 0243 } 0244 0245 const QList<KPluginMetaData> packagePlugins = KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/DataEngine")); 0246 for (const auto &plugin : packagePlugins) { 0247 engines << plugin.pluginId(); 0248 } 0249 0250 return engines; 0251 } 0252 #endif 0253 0254 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 77) 0255 KPluginInfo::List PluginLoader::listEngineInfo(const QString &parentApp) 0256 { 0257 return PluginLoader::self()->listDataEngineInfo(parentApp); 0258 } 0259 #endif 0260 0261 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 81) 0262 KPluginInfo::List PluginLoader::listEngineInfoByCategory(const QString &category, const QString &parentApp) 0263 { 0264 KPluginInfo::List list; 0265 0266 // Look for C++ plugins first 0267 auto filterNormal = [&category](const KPluginMetaData &md) -> bool { 0268 return md.value(QStringLiteral("X-KDE-PluginInfo-Category")) == category; 0269 }; 0270 auto filterParentApp = [&category, &parentApp](const KPluginMetaData &md) -> bool { 0271 return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp // 0272 && md.value(QStringLiteral("X-KDE-PluginInfo-Category")) == category; 0273 }; 0274 QVector<KPluginMetaData> plugins; 0275 if (parentApp.isEmpty()) { 0276 plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filterNormal); 0277 } else { 0278 plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filterParentApp); 0279 } 0280 0281 list = KPluginInfo::fromMetaData(plugins); 0282 0283 // TODO FIXME: PackageLoader needs to have a function to inject packageStructures 0284 const QList<KPluginMetaData> packagePlugins = KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/DataEngine")); 0285 list << KPluginInfo::fromMetaData(packagePlugins.toVector()); 0286 0287 return list; 0288 } 0289 #endif 0290 0291 Service *PluginLoader::loadService(const QString &name, const QVariantList &args, QObject *parent) 0292 { 0293 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86) 0294 Service *service = d->isDefaultLoader ? nullptr : internalLoadService(name, args, parent); 0295 if (service) { 0296 return service; 0297 } 0298 #else 0299 Service *service = nullptr; 0300 #endif 0301 0302 // TODO: scripting API support 0303 if (name.isEmpty()) { 0304 return new NullService(QString(), parent); 0305 } else if (name == QLatin1String("org.kde.servicestorage")) { 0306 return new Storage(parent); 0307 } 0308 0309 // Look for C++ plugins first 0310 KPluginMetaData plugin = KPluginMetaData::findPluginById(PluginLoaderPrivate::s_servicesPluginDir, name); 0311 if (plugin.isValid()) { 0312 service = KPluginFactory::instantiatePlugin<Plasma::Service>(plugin, parent, args).plugin; 0313 } 0314 0315 if (service) { 0316 if (service->name().isEmpty()) { 0317 service->setName(name); 0318 } 0319 return service; 0320 } else { 0321 return new NullService(name, parent); 0322 } 0323 } 0324 0325 ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, const QString &name, const QVariantList &args) 0326 { 0327 if (name.isEmpty()) { 0328 return nullptr; 0329 } 0330 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86) 0331 ContainmentActions *actions = d->isDefaultLoader ? nullptr : internalLoadContainmentActions(parent, name, args); 0332 if (actions) { 0333 return actions; 0334 } 0335 #endif 0336 0337 KPluginMetaData plugin = d->containmentactionCache.findPluginById(name, PluginLoaderPrivate::s_containmentActionsPluginDir); 0338 0339 if (plugin.isValid()) { 0340 if (auto res = KPluginFactory::instantiatePlugin<Plasma::ContainmentActions>(plugin, nullptr, {QVariant::fromValue(plugin)})) { 0341 return res.plugin; 0342 } 0343 } 0344 0345 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 88) 0346 QString constraint = QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(name); 0347 KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("Plasma/ContainmentActions"), constraint); 0348 0349 if (offers.isEmpty()) { 0350 #ifndef NDEBUG 0351 qCDebug(LOG_PLASMA) << "offers is empty for " << name; 0352 #endif 0353 return nullptr; 0354 } 0355 0356 KService::Ptr offer = offers.first(); 0357 qCWarning(LOG_PLASMA) << "Plugin" << name << "was loaded using deprecated KServiceTypeTrader." 0358 << "Use embedded json metadata and install the plugin in plasma/containmentactions namespace instead"; 0359 0360 KPluginMetaData data(offer->library()); 0361 QVariantList allArgs; 0362 allArgs << offer->storageId() << args; 0363 0364 return KPluginFactory::instantiatePlugin<Plasma::ContainmentActions>(data, nullptr, allArgs).plugin; 0365 #else 0366 return nullptr; 0367 #endif 0368 } 0369 0370 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0371 Package PluginLoader::loadPackage(const QString &packageFormat, const QString &specialization) 0372 { 0373 if (!d->isDefaultLoader) { 0374 Package p = internalLoadPackage(packageFormat, specialization); 0375 if (p.hasValidStructure()) { 0376 return p; 0377 } 0378 } 0379 0380 if (packageFormat.isEmpty()) { 0381 return Package(); 0382 } 0383 0384 const QString hashkey = packageFormat + QLatin1Char('%') + specialization; 0385 PackageStructure *structure = d->structures.value(hashkey).data(); 0386 0387 if (structure) { 0388 return Package(structure); 0389 } 0390 0391 KPackage::PackageStructure *internalStructure = KPackage::PackageLoader::self()->loadPackageStructure(packageFormat); 0392 0393 if (internalStructure) { 0394 structure = new PackageStructure(); 0395 structure->d->internalStructure = internalStructure; 0396 // fallback to old structures 0397 } else { 0398 auto filter = [packageFormat](const KPluginMetaData &md) -> bool { 0399 return md.value(QStringLiteral("X-KDE-PluginInfo-Name")) == packageFormat; 0400 }; 0401 0402 const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_packageStructurePluginDir, filter); 0403 0404 if (!plugins.isEmpty()) { 0405 if (auto res = KPluginFactory::instantiatePlugin<Plasma::PackageStructure>(plugins.first())) { 0406 structure = res.plugin; 0407 } else { 0408 qWarning() << "Error loading plugin:" << res.errorString; 0409 } 0410 0411 if (structure) { 0412 structure->d->internalStructure = new PackageStructureWrapper(structure); 0413 } 0414 } 0415 } 0416 0417 if (structure) { 0418 d->structures.insert(hashkey, structure); 0419 return Package(structure); 0420 } 0421 0422 return Package(); 0423 } 0424 #endif 0425 QList<KPluginMetaData> listAppletMetaDataInternal(const QString &category, const QString &parentApp) 0426 { 0427 auto platforms = KRuntimePlatform::runtimePlatform(); 0428 // For now desktop always lists everything 0429 if (platforms.contains(QStringLiteral("desktop"))) { 0430 platforms.clear(); 0431 } 0432 0433 // FIXME: this assumes we are always use packages.. no pure c++ 0434 std::function<bool(const KPluginMetaData &)> filter; 0435 if (category.isEmpty()) { // use all but the excluded categories 0436 KConfigGroup group(KSharedConfig::openConfig(), "General"); 0437 QStringList excluded = group.readEntry("ExcludeCategories", QStringList()); 0438 0439 filter = [excluded, parentApp, platforms](const KPluginMetaData &md) -> bool { 0440 if (!platforms.isEmpty() && !md.formFactors().isEmpty()) { 0441 bool found = false; 0442 for (const auto &plat : platforms) { 0443 if (md.formFactors().contains(plat)) { 0444 found = true; 0445 break; 0446 } 0447 } 0448 0449 if (!found) { 0450 return false; 0451 } 0452 } 0453 0454 const QString pa = md.value(QStringLiteral("X-KDE-ParentApp")); 0455 return (parentApp.isEmpty() || pa == parentApp) && !excluded.contains(md.category()); 0456 }; 0457 } else { // specific category (this could be an excluded one - is that bad?) 0458 0459 filter = [category, parentApp, platforms](const KPluginMetaData &md) -> bool { 0460 if (!platforms.isEmpty() && !md.formFactors().isEmpty()) { 0461 bool found = false; 0462 for (const auto &plat : platforms) { 0463 if (md.formFactors().contains(plat)) { 0464 found = true; 0465 break; 0466 } 0467 } 0468 0469 if (!found) { 0470 return false; 0471 } 0472 } 0473 0474 const QString pa = md.value(QStringLiteral("X-KDE-ParentApp")); 0475 0476 if (category == QLatin1String("Miscellaneous")) { 0477 return (parentApp.isEmpty() || pa == parentApp) && (md.category() == category || md.category().isEmpty()); 0478 } else { 0479 return (parentApp.isEmpty() || pa == parentApp) && md.category() == category; 0480 } 0481 }; 0482 } 0483 0484 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter); 0485 } 0486 0487 QList<KPluginMetaData> PluginLoader::listAppletMetaData(const QString &category) 0488 { 0489 return listAppletMetaDataInternal(category, QString()); 0490 } 0491 0492 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 88) 0493 QList<KPluginMetaData> PluginLoader::listAppletMetaData(const QString &category, const QString &parentApp) 0494 { 0495 return listAppletMetaDataInternal(category, parentApp); 0496 } 0497 #endif 0498 0499 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 28) 0500 KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QString &parentApp) 0501 { 0502 const auto plugins = listAppletMetaData(category, parentApp); 0503 0504 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0505 KPluginInfo::List list; 0506 // NOTE: it still produces kplugininfos from KServices because some user code expects 0507 // info.service() to be valid and would crash otherwise 0508 for (const auto &md : plugins) { 0509 QT_WARNING_PUSH 0510 QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") 0511 QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") 0512 auto pi = md.metaDataFileName().endsWith(QLatin1String(".json")) ? KPluginInfo(md) : KPluginInfo(KService::serviceByStorageId(md.metaDataFileName())); 0513 QT_WARNING_POP 0514 if (!pi.isValid()) { 0515 qCWarning(LOG_PLASMA) << "Could not load plugin info for plugin :" << md.pluginId() << "skipping plugin"; 0516 continue; 0517 } 0518 list << pi; 0519 } 0520 return list; 0521 #else 0522 return KPluginInfo::fromMetaData(plugins.toVector()); 0523 #endif 0524 } 0525 #endif 0526 0527 QList<KPluginMetaData> PluginLoader::listAppletMetaDataForMimeType(const QString &mimeType) 0528 { 0529 auto filter = [&mimeType](const KPluginMetaData &md) -> bool { 0530 return md.value(QStringLiteral("X-Plasma-DropMimeTypes"), QStringList()).contains(mimeType); 0531 }; 0532 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter); 0533 } 0534 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0535 KPluginInfo::List PluginLoader::listAppletInfoForMimeType(const QString &mimeType) 0536 { 0537 return KPluginInfo::fromMetaData(listAppletMetaDataForMimeType(mimeType).toVector()); 0538 } 0539 #endif 0540 0541 QList<KPluginMetaData> PluginLoader::listAppletMetaDataForUrl(const QUrl &url) 0542 { 0543 QString parentApp; 0544 QCoreApplication *app = QCoreApplication::instance(); 0545 if (app) { 0546 parentApp = app->applicationName(); 0547 } 0548 0549 auto filter = [&parentApp](const KPluginMetaData &md) -> bool { 0550 const QString pa = md.value(QStringLiteral("X-KDE-ParentApp")); 0551 return (parentApp.isEmpty() || pa == parentApp) // 0552 && !md.value(QStringLiteral("X-Plasma-DropUrlPatterns"), QStringList()).isEmpty(); 0553 }; 0554 const QList<KPluginMetaData> allApplets = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter); 0555 0556 QList<KPluginMetaData> filtered; 0557 for (const KPluginMetaData &md : allApplets) { 0558 const QStringList urlPatterns = md.value(QStringLiteral("X-Plasma-DropUrlPatterns"), QStringList()); 0559 for (const QString &glob : urlPatterns) { 0560 QRegularExpression rx(QRegularExpression::anchoredPattern(QRegularExpression::wildcardToRegularExpression(glob))); 0561 if (rx.match(url.toString()).hasMatch()) { 0562 filtered << md; 0563 } 0564 } 0565 } 0566 0567 return filtered; 0568 } 0569 0570 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 36) 0571 KPluginInfo::List PluginLoader::listAppletInfoForUrl(const QUrl &url) 0572 { 0573 return KPluginInfo::fromMetaData(listAppletMetaDataForUrl(url).toVector()); 0574 } 0575 #endif 0576 0577 QStringList PluginLoader::listAppletCategories(const QString &parentApp, bool visibleOnly) 0578 { 0579 KConfigGroup group(KSharedConfig::openConfig(), "General"); 0580 const QStringList excluded = group.readEntry("ExcludeCategories", QStringList()); 0581 auto filter = [&parentApp, &excluded, visibleOnly](const KPluginMetaData &md) -> bool { 0582 const QString pa = md.value(QStringLiteral("X-KDE-ParentApp")); 0583 return (parentApp.isEmpty() || pa == parentApp) // 0584 && (excluded.isEmpty() || excluded.contains(md.value(QStringLiteral("X-KDE-PluginInfo-Category")))) // 0585 && (!visibleOnly || !md.isHidden()); 0586 }; 0587 const QList<KPluginMetaData> allApplets = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter); 0588 0589 QStringList categories; 0590 for (auto &plugin : allApplets) { 0591 if (plugin.category().isEmpty()) { 0592 if (!categories.contains(i18nc("misc category", "Miscellaneous"))) { 0593 categories << i18nc("misc category", "Miscellaneous"); 0594 } 0595 } else { 0596 categories << plugin.category(); 0597 } 0598 } 0599 categories.sort(); 0600 return categories; 0601 } 0602 0603 void PluginLoader::setCustomAppletCategories(const QStringList &categories) 0604 { 0605 PluginLoaderPrivate::s_customCategories = QSet<QString>(categories.begin(), categories.end()); 0606 } 0607 0608 QStringList PluginLoader::customAppletCategories() const 0609 { 0610 return PluginLoaderPrivate::s_customCategories.values(); 0611 } 0612 0613 QString PluginLoader::appletCategory(const QString &appletName) 0614 { 0615 if (appletName.isEmpty()) { 0616 return QString(); 0617 } 0618 0619 const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), appletName); 0620 if (!p.isValid()) { 0621 return QString(); 0622 } 0623 0624 return p.metadata().category(); 0625 } 0626 0627 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0628 KPluginInfo::List PluginLoader::listContainments(const QString &category, const QString &parentApp) 0629 { 0630 return listContainmentsOfType(QString(), category, parentApp); 0631 } 0632 #endif 0633 0634 QList<KPluginMetaData> PluginLoader::listContainmentsMetaData(std::function<bool(const KPluginMetaData &)> filter) 0635 { 0636 auto ownFilter = [filter](const KPluginMetaData &md) -> bool { 0637 return isContainmentMetaData(md) && filter(md); 0638 }; 0639 0640 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), ownFilter); 0641 } 0642 0643 QList<KPluginMetaData> PluginLoader::listContainmentsMetaDataOfType(const QString &type) 0644 { 0645 auto filter = [type](const KPluginMetaData &md) -> bool { 0646 return md.value(QStringLiteral("X-Plasma-ContainmentType")) == type; 0647 }; 0648 0649 return listContainmentsMetaData(filter); 0650 } 0651 0652 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0653 KPluginInfo::List PluginLoader::listContainmentsOfType(const QString &type, const QString &category, const QString &parentApp) 0654 { 0655 auto filter = [&type, &category, &parentApp](const KPluginMetaData &md) -> bool { 0656 if (isContainmentMetaData(md)) { 0657 return false; 0658 } 0659 if (!parentApp.isEmpty() && md.value(QStringLiteral("X-KDE-ParentApp")) != parentApp) { 0660 return false; 0661 } 0662 0663 if (!type.isEmpty() && md.value(QStringLiteral("X-Plasma-ContainmentType")) != type) { 0664 return false; 0665 } 0666 0667 if (!category.isEmpty() && md.value(QStringLiteral("X-KDE-PluginInfo-Category")) != category) { 0668 return false; 0669 } 0670 0671 return true; 0672 }; 0673 0674 return KPluginInfo::fromMetaData(KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter).toVector()); 0675 } 0676 #endif 0677 0678 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0679 KPluginInfo::List PluginLoader::listContainmentsForMimeType(const QString &mimeType) 0680 { 0681 auto filter = [&mimeType](const KPluginMetaData &md) -> bool { 0682 return isContainmentMetaData(md) && md.value(QStringLiteral("X-Plasma-DropMimeTypes"), QStringList()).contains(mimeType); 0683 }; 0684 0685 return KPluginInfo::fromMetaData(KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter).toVector()); 0686 } 0687 #endif 0688 0689 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0690 QStringList PluginLoader::listContainmentTypes() 0691 { 0692 const KPluginInfo::List containmentInfos = listContainments(); 0693 QSet<QString> types; 0694 0695 for (const KPluginInfo &containmentInfo : containmentInfos) { 0696 const QStringList theseTypes = containmentInfo.property(QStringLiteral("X-Plasma-ContainmentType")).toStringList(); 0697 for (const QString &type : theseTypes) { 0698 types.insert(type); 0699 } 0700 } 0701 0702 return types.values(); 0703 } 0704 #endif 0705 0706 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 77) 0707 KPluginInfo::List PluginLoader::listDataEngineInfo(const QString &parentApp) 0708 { 0709 return KPluginInfo::fromMetaData(listDataEngineMetaData(parentApp)); 0710 } 0711 #endif 0712 0713 QVector<KPluginMetaData> PluginLoader::listDataEngineMetaData(const QString &parentApp) 0714 { 0715 auto filter = [&parentApp](const KPluginMetaData &md) -> bool { 0716 return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp; 0717 }; 0718 0719 QVector<KPluginMetaData> plugins; 0720 if (parentApp.isEmpty()) { 0721 plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir); 0722 } else { 0723 plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filter); 0724 } 0725 0726 return plugins; 0727 } 0728 0729 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 77) 0730 KPluginInfo::List PluginLoader::listContainmentActionsInfo(const QString &parentApp) 0731 { 0732 return KPluginInfo::fromMetaData(listContainmentActionsMetaData(parentApp)); 0733 } 0734 #endif 0735 0736 QVector<KPluginMetaData> PluginLoader::listContainmentActionsMetaData(const QString &parentApp) 0737 { 0738 auto filter = [&parentApp](const KPluginMetaData &md) -> bool { 0739 return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp; 0740 }; 0741 0742 QVector<KPluginMetaData> plugins; 0743 if (parentApp.isEmpty()) { 0744 plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_containmentActionsPluginDir); 0745 } else { 0746 plugins = KPluginMetaData::findPlugins(PluginLoaderPrivate::s_containmentActionsPluginDir, filter); 0747 } 0748 0749 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0750 QSet<QString> knownPlugins; 0751 for (const KPluginMetaData &p : std::as_const(plugins)) { 0752 knownPlugins.insert(p.pluginId()); 0753 } 0754 QString constraint; 0755 if (!parentApp.isEmpty()) { 0756 constraint = QLatin1String("[X-KDE-ParentApp] == '") + parentApp + QLatin1Char('\''); 0757 } 0758 const KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("Plasma/ContainmentActions"), constraint); 0759 for (KService::Ptr s : offers) { 0760 if (!knownPlugins.contains(s->pluginKeyword())) { 0761 QT_WARNING_PUSH 0762 QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") 0763 QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") 0764 plugins.append(KPluginInfo(s).toMetaData()); 0765 QT_WARNING_POP 0766 } 0767 } 0768 #endif 0769 0770 return plugins; 0771 } 0772 0773 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 86) 0774 Applet *PluginLoader::internalLoadApplet(const QString &name, uint appletId, const QVariantList &args) 0775 { 0776 Q_UNUSED(name) 0777 Q_UNUSED(appletId) 0778 Q_UNUSED(args) 0779 return nullptr; 0780 } 0781 0782 DataEngine *PluginLoader::internalLoadDataEngine(const QString &name) 0783 { 0784 Q_UNUSED(name) 0785 return nullptr; 0786 } 0787 0788 ContainmentActions *PluginLoader::internalLoadContainmentActions(Containment *containment, const QString &name, const QVariantList &args) 0789 { 0790 Q_UNUSED(containment) 0791 Q_UNUSED(name) 0792 Q_UNUSED(args) 0793 return nullptr; 0794 } 0795 0796 Service *PluginLoader::internalLoadService(const QString &name, const QVariantList &args, QObject *parent) 0797 { 0798 Q_UNUSED(name) 0799 Q_UNUSED(args) 0800 Q_UNUSED(parent) 0801 return nullptr; 0802 } 0803 0804 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 83) 0805 Package PluginLoader::internalLoadPackage(const QString &name, const QString &specialization) 0806 { 0807 Q_UNUSED(name); 0808 Q_UNUSED(specialization); 0809 return Package(); 0810 } 0811 #endif 0812 0813 KPluginInfo::List PluginLoader::internalAppletInfo(const QString &category) const 0814 { 0815 Q_UNUSED(category) 0816 return KPluginInfo::List(); 0817 } 0818 0819 KPluginInfo::List PluginLoader::internalDataEngineInfo() const 0820 { 0821 return KPluginInfo::List(); 0822 } 0823 0824 KPluginInfo::List PluginLoader::internalServiceInfo() const 0825 { 0826 return KPluginInfo::List(); 0827 } 0828 0829 KPluginInfo::List PluginLoader::internalContainmentActionsInfo() const 0830 { 0831 return KPluginInfo::List(); 0832 } 0833 #endif 0834 0835 #if PLASMA_BUILD_DEPRECATED_SINCE(5, 88) 0836 static KPluginInfo::List standardInternalInfo(const QString &type, const QString &category = QString()) 0837 { 0838 QStringList files = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, 0839 QLatin1String(PLASMA_RELATIVE_DATA_INSTALL_DIR "/internal/") + type + QLatin1String("/*.desktop"), 0840 QStandardPaths::LocateFile); 0841 0842 const KPluginInfo::List allInfo = KPluginInfo::fromFiles(files); 0843 0844 if (category.isEmpty() || allInfo.isEmpty()) { 0845 return allInfo; 0846 } 0847 0848 KPluginInfo::List matchingInfo; 0849 for (const KPluginInfo &info : allInfo) { 0850 if (info.category().compare(category, Qt::CaseInsensitive) == 0) { 0851 matchingInfo << info; 0852 } 0853 } 0854 0855 return matchingInfo; 0856 } 0857 0858 KPluginInfo::List PluginLoader::standardInternalAppletInfo(const QString &category) const 0859 { 0860 return standardInternalInfo(QStringLiteral("applets"), category); 0861 } 0862 0863 KPluginInfo::List PluginLoader::standardInternalDataEngineInfo() const 0864 { 0865 return standardInternalInfo(QStringLiteral("dataengines")); 0866 } 0867 0868 KPluginInfo::List PluginLoader::standardInternalServiceInfo() const 0869 { 0870 return standardInternalInfo(QStringLiteral("services")); 0871 } 0872 #endif 0873 0874 KPluginMetaData PluginLoaderPrivate::Cache::findPluginById(const QString &name, const QString &pluginNamespace) 0875 { 0876 const qint64 now = qRound64(QDateTime::currentMSecsSinceEpoch() / 1000.0); 0877 bool useRuntimeCache = true; 0878 0879 if (pluginCacheAge == 0) { 0880 // Find all the plugins now, but only once 0881 pluginCacheAge = now; 0882 0883 const auto metaDataList = KPluginMetaData::findPlugins(pluginNamespace, {}, KPluginMetaData::AllowEmptyMetaData); 0884 for (const KPluginMetaData &metadata : metaDataList) { 0885 plugins.insert(metadata.pluginId(), metadata); 0886 } 0887 } else if (now - pluginCacheAge > maxCacheAge) { 0888 // cache is old and we're not within a few seconds of startup anymore 0889 useRuntimeCache = false; 0890 plugins.clear(); 0891 } 0892 0893 // if name wasn't a path, pluginName == name 0894 const QString pluginName = name.section(QLatin1Char('/'), -1); 0895 0896 if (useRuntimeCache) { 0897 KPluginMetaData data = plugins.value(name); 0898 qCDebug(LOG_PLASMA) << "loading applet by name" << name << useRuntimeCache << data.isValid(); 0899 return data; 0900 } else { 0901 const QVector<KPluginMetaData> offers = KPluginMetaData::findPlugins( 0902 pluginNamespace, 0903 [&pluginName](const KPluginMetaData &data) { 0904 return data.pluginId() == pluginName; 0905 }, 0906 KPluginMetaData::AllowEmptyMetaData); 0907 return offers.isEmpty() ? KPluginMetaData() : offers.first(); 0908 } 0909 } 0910 0911 } // Plasma Namespace