From 0ebe2ca1fa50670366cf130db66b5774b7249da6 Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Mon, 10 Oct 2016 16:27:50 +0200 Subject: [PATCH] Don't enforce metadata.desktop, cleanup constructor Makes it possible to use plugins that offer a metadata.json file. Define the service type when falling back to the desktop file parser, so the type system is proper. Don't destroy a KPluginMetadata tuple to instanciate it right away. REVIEW: 129102 --- src/plasma/applet.cpp | 35 ++++++++++------ src/plasma/containment.cpp | 4 +- src/plasma/containment.h | 2 +- src/plasma/pluginloader.cpp | 71 ++++++++++++++------------------- src/plasma/pluginloader.h | 25 +++++++++++- src/plasma/private/applet_p.cpp | 2 +- 6 files changed, 81 insertions(+), 58 deletions(-) diff --git a/src/plasma/applet.cpp b/src/plasma/applet.cpp index 5eb529cc3..dbd7e64f2 100644 --- a/src/plasma/applet.cpp +++ b/src/plasma/applet.cpp @@ -60,6 +60,13 @@ namespace Plasma { +static KPluginMetaData appletMetadataForDirectory(const QString &path) +{ + return QFile::exists(path + QLatin1String("/metadata.json")) + ? KPluginMetaData(path + QLatin1String("/metadata.json")) + : KPluginMetaData::fromDesktopFile(path + QLatin1String("/metadata.desktop"), { QStringLiteral("plasma-applet.desktop") }); +} + Applet::Applet(const KPluginMetaData &info, QObject *parent, uint appletId) : QObject(parent), d(new AppletPrivate(info, appletId, this)) @@ -88,14 +95,19 @@ Applet::Applet(QObject *parent, const QString &serviceID, uint appletId) Applet::Applet(QObject *parentObject, const QVariantList &args) : QObject(0), - d(new AppletPrivate( - KPluginMetaData(args.count() > 0 && args.first().canConvert() ? args[0].toString() : QString()), - args.count() > 1 ? args[1].toInt() : 0, this)) + d(new AppletPrivate(KPluginMetaData(), args.count() > 1 ? args[1].toInt() : 0, this)) { setParent(parentObject); - if (args.count() > 0 && args.first().canConvert()) { - d->appletDescription = KPluginInfo(args).toMetaData(); + if (args.count() > 0) { + const QVariant first = args.first(); + if (first.canConvert()) { + d->appletDescription = KPluginMetaData(first.toString()); + } else if (first.canConvert()) { + auto metadata = first.toMap().value(QStringLiteral("MetaData")).toMap(); + d->appletDescription = KPluginMetaData(QJsonObject::fromVariantMap(metadata), {}); + } } + d->icon = d->appletDescription.iconName(); if (args.contains("org.kde.plasma:force-create")) { setProperty("org.kde.plasma:force-create", true); @@ -109,7 +121,7 @@ Applet::Applet(QObject *parentObject, const QVariantList &args) Applet::Applet(const QString &packagePath, uint appletId) : QObject(0), - d(new AppletPrivate(KPluginMetaData(packagePath + QStringLiteral("/metadata.desktop")), appletId, this)) + d(new AppletPrivate(appletMetadataForDirectory(packagePath), appletId, this)) { d->init(packagePath); d->setupPackage(); @@ -767,15 +779,14 @@ bool Applet::hasValidAssociatedApplication() const Applet *Applet::loadPlasmoid(const QString &path, uint appletId) { - const QString metadataPath = path + QLatin1String("/metadata.desktop"); - if (QFile::exists(metadataPath)) { - KService service(metadataPath); - const QStringList &types = service.serviceTypes(); + const KPluginMetaData md = appletMetadataForDirectory(path); + if (md.isValid()) { + QStringList types = md.serviceTypes(); if (types.contains(QStringLiteral("Plasma/Containment"))) { - return new Containment(path, appletId); + return new Containment(md, appletId); } else { - return new Applet(path, appletId); + return new Applet(md, nullptr, appletId); } } diff --git a/src/plasma/containment.cpp b/src/plasma/containment.cpp index 1840f246f..eb6538500 100644 --- a/src/plasma/containment.cpp +++ b/src/plasma/containment.cpp @@ -79,8 +79,8 @@ Containment::Containment(QObject *parent, const QVariantList &args) setHasConfigurationInterface(true); } -Containment::Containment(const QString &packagePath, uint appletId) - : Applet(packagePath, appletId), +Containment::Containment(const KPluginMetaData &md, uint appletId) + : Applet(md, nullptr, appletId), d(new ContainmentPrivate(this)) { // WARNING: do not access config() OR globalConfig() in this method! diff --git a/src/plasma/containment.h b/src/plasma/containment.h index 0b7a3eff4..44902d714 100644 --- a/src/plasma/containment.h +++ b/src/plasma/containment.h @@ -330,7 +330,7 @@ private: * @param parent a QObject parent; you probably want to pass in 0 * @since 4.3 */ - Containment(const QString &packagePath, uint appletId); + Containment(const KPluginMetaData &md, uint appletId); Q_PRIVATE_SLOT(d, void appletDeleted(Plasma::Applet *)) Q_PRIVATE_SLOT(d, void triggerShowAddWidgets()) diff --git a/src/plasma/pluginloader.cpp b/src/plasma/pluginloader.cpp index db2b2c91d..15e0eadcf 100644 --- a/src/plasma/pluginloader.cpp +++ b/src/plasma/pluginloader.cpp @@ -221,7 +221,7 @@ Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVari p.setRequired("mainscript", false); p.setPath(name); - KPluginMetaData md(p.filePath("metadata")); + const KPluginMetaData md(p.metadata()); const KPackage::Package fp = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), md.value(QStringLiteral("X-Plasma-RootPath"))); p.setFallbackPackage(fp); @@ -234,8 +234,7 @@ Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVari if (!applet) { //qCDebug(LOG_PLASMA) << name << "not a C++ applet: Falling back to an empty one"; - QVariantList allArgs; - allArgs << p.metadata().fileName() << appletId << args; + QVariantList allArgs = { p.metadata().fileName(), appletId, args }; if (p.metadata().serviceTypes().contains(QStringLiteral("Plasma/Containment"))) { return new Containment(0, allArgs); @@ -499,42 +498,22 @@ Package PluginLoader::loadPackage(const QString &packageFormat, const QString &s return Package(); } -KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QString &parentApp) +QList PluginLoader::listAppletMetaData(const QString &category, const QString &parentApp) { - KPluginInfo::List list; - - if (!d->isDefaultLoader && (parentApp.isEmpty() || parentApp == QCoreApplication::instance()->applicationName())) { - list = internalAppletInfo(category); - } - //FIXME: this assumes we are always use packages.. no pure c++ + std::function filter; if (category.isEmpty()) { //use all but the excluded categories KConfigGroup group(KSharedConfig::openConfig(), "General"); QStringList excluded = group.readEntry("ExcludeCategories", QStringList()); - auto filter = [&excluded, &parentApp](const KPluginMetaData &md) -> bool + filter = [excluded, parentApp](const KPluginMetaData &md) -> bool { const QString pa = md.value(QStringLiteral("X-KDE-ParentApp")); return (pa.isEmpty() || pa == parentApp) && !excluded.contains(md.category()); }; - - //NOTE: it still produces kplugininfos from KServices because some user code expects - //info.sevice() to be valid and would crash ohtherwise - auto plugins = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter); - foreach (auto& md, plugins) { - auto pi = KPluginInfo(KService::serviceByStorageId(md.metaDataFileName())); - if (!pi.isValid()) { - qCWarning(LOG_PLASMA) << "Could not load plugin info for plugin :" << md.pluginId() << "skipping plugin"; - continue; - } - list << pi; - } - return list; - - } else { //specific category (this could be an excluded one - is that bad?) - auto filter = [&category, &parentApp](const KPluginMetaData &md) -> bool + filter = [category, parentApp](const KPluginMetaData &md) -> bool { const QString pa = md.value(QStringLiteral("X-KDE-ParentApp")); if (category == QLatin1String("Miscellaneous")) { @@ -543,21 +522,31 @@ KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QS return (pa.isEmpty() || pa == parentApp) && md.category() == category; } }; - - - //NOTE: it still produces kplugininfos from KServices because some user code expects - //info.sevice() to be valid and would crash ohtherwise - const auto plugins = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter); - foreach (auto& md, plugins) { - auto pi = KPluginInfo(KService::serviceByStorageId(md.metaDataFileName())); - if (!pi.isValid()) { - qCWarning(LOG_PLASMA) << "Could not load plugin info for plugin :" << md.pluginId() << "skipping plugin"; - continue; - } - list << pi; - } - return list; } + + QList list; + if (!d->isDefaultLoader && (parentApp.isEmpty() || parentApp == QCoreApplication::instance()->applicationName())) { + list = KPluginInfo::toMetaData(internalAppletInfo(category)).toList(); + } + return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter); +} + +KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QString &parentApp) +{ + KPluginInfo::List list; + const auto plugins = listAppletMetaData(category, parentApp); + + //NOTE: it still produces kplugininfos from KServices because some user code expects + //info.sevice() to be valid and would crash ohtherwise + foreach (auto& md, plugins) { + auto pi = md.metaDataFileName().endsWith(".json") ? KPluginInfo(md) : KPluginInfo(KService::serviceByStorageId(md.metaDataFileName())); + if (!pi.isValid()) { + qCWarning(LOG_PLASMA) << "Could not load plugin info for plugin :" << md.pluginId() << "skipping plugin"; + continue; + } + list << pi; + } + return list; } KPluginInfo::List PluginLoader::listAppletInfoForMimeType(const QString &mimeType) diff --git a/src/plasma/pluginloader.h b/src/plasma/pluginloader.h index 566461d9b..484767ac0 100644 --- a/src/plasma/pluginloader.h +++ b/src/plasma/pluginloader.h @@ -167,8 +167,31 @@ public: * list containing only applets not specifically * registered to an application. * @return list of applets + * + * @deprecated use listAppletMetaData. Doesn't support metadata.json packages. **/ - KPluginInfo::List listAppletInfo(const QString &category, const QString &parentApp = QString()); + PLASMA_DEPRECATED KPluginInfo::List listAppletInfo(const QString &category, const QString &parentApp = QString()); + + /** + * Returns a list of all known applets. + * This may skip applets based on security settings and ExcludeCategories in the application's config. + * + * @param category Only applets matchin this category will be returned. + * Useful in conjunction with knownCategories. + * If "Misc" is passed in, then applets without a + * Categories= entry are also returned. + * If an empty string is passed in, all applets are + * returned. + * @param parentApp the application to filter applets on. Uses the + * X-KDE-ParentApp entry (if any) in the plugin info. + * The default value of QString() will result in a + * list containing only applets not specifically + * registered to an application. + * @return list of applets + * + * @since 5.28 + **/ + QList listAppletMetaData(const QString &category, const QString &parentApp = QString()); /** * Returns a list of all known applets associated with a certain mimetype. diff --git a/src/plasma/private/applet_p.cpp b/src/plasma/private/applet_p.cpp index fafb4508c..624e4fe46 100644 --- a/src/plasma/private/applet_p.cpp +++ b/src/plasma/private/applet_p.cpp @@ -57,7 +57,7 @@ AppletPrivate::AppletPrivate(const KPluginMetaData &info, int uniqueID, Applet * immutability(Types::Mutable), oldImmutability(Types::Mutable), appletDescription(info), - icon(appletDescription.isValid() ? appletDescription.iconName() : QString()), + icon(appletDescription.iconName()), mainConfig(0), pendingConstraints(Types::NoConstraint), script(0),