port libplasma away from sycoca as much as possible

this ports most of libplasma away from sycoca, using instead
a combination of KPluginLoader and KPackage::PackageLoader instead
(so eventually using their own little caches instead of the
global sycoca cache)
a kservicetypetrader call is left in the loading of
containmentactions since is the only way to make an older
workspace still work, but is only a fallback, so containmentactions
in plasma-workspace can be ported eventually as well

Change-Id: Ie9579c3e01284f6d97043e22d01bbe63d3c3f45a
REVIEW:123626
This commit is contained in:
Marco Martin 2015-05-07 16:26:37 +02:00
parent 02f124b120
commit ea924b1469
22 changed files with 400 additions and 381 deletions

View File

@ -8,6 +8,11 @@ set(Plasma_INSTALL_PREFIX "@PACKAGE_CMAKE_INSTALL_PREFIX@")
set(Plasma_LIBRARIES KF5::Plasma)
set(PLASMA_DATAENGINES_PLUGINDIR ${KDE_INSTALL_PLUGINDIR}/plasma/dataengine)
set(PLASMA_PLASMOIDS_PLUGINDIR ${KDE_INSTALL_PLUGINDIR}/plasma/plasmoids)
set(PLASMA_SCRIPTENGINES_PLUGINDIR ${KDE_INSTALL_PLUGINDIR}/plasma/scriptengines)
set(PLASMA_CONTAINMENTACTIONS_PLUGINDIR ${KDE_INSTALL_PLUGINDIR}/plasma/containmentactions)
find_dependency(KF5Package "@KF5_DEP_VERSION@")
find_dependency(KF5Service "@KF5_DEP_VERSION@")

View File

@ -42,7 +42,6 @@
#include <kplugininfo.h>
#include <klocalizedstring.h>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <KConfigLoader>
#include <kwindowsystem.h>
@ -84,10 +83,13 @@ Applet::Applet(QObject *parent, const QString &serviceID, uint appletId)
Applet::Applet(QObject *parentObject, const QVariantList &args)
: QObject(0),
d(new AppletPrivate(
KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()), 0,
KService::serviceByStorageId(args.count() > 0 && args.first().canConvert<QString>() ? args[0].toString() : QString()), 0,
args.count() > 1 ? args[1].toInt() : 0, this))
{
setParent(parentObject);
if (args.count() > 0 && args.first().canConvert<QVariantMap>()) {
d->appletDescription = KPluginInfo(args);
}
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point

View File

@ -37,7 +37,6 @@
#include <QDebug>
#include <kauthorized.h>
#include <klocalizedstring.h>
#include <kservicetypetrader.h>
#include <KConfigSkeleton>
#include <KConfigLoader>

View File

@ -33,7 +33,6 @@
#include <QDebug>
#include <klocalizedstring.h>
#include <kservicetypetrader.h>
#include "version.h"

View File

@ -33,7 +33,6 @@
#include <kplugininfo.h>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <klocalizedstring.h>
#include "datacontainer.h"

View File

@ -27,7 +27,6 @@
#include <karchive.h>
#include <QDebug>
#include <kdesktopfile.h>
#include <kservicetypetrader.h>
#include <ktar.h>
#include <kzip.h>
#include <KJob>

View File

@ -129,7 +129,7 @@ void PackageStructurePrivate::installPathChanged(const QString &path)
// used by the installing app in any case, and the
// package is properly installed - aseigo
//TODO: reduce code duplication with registerPackage below
//TODO: remove installation of the desktop file in kservices5 when possible
const QString serviceName = servicePrefix + pluginName + ".desktop";

View File

@ -56,10 +56,13 @@ class PluginLoaderPrivate
public:
PluginLoaderPrivate()
: isDefaultLoader(false),
dataEnginePluginDir("plasma/dataengine"),
packageStructurePluginDir("plasma/packagestructure"),
packageRE("[^a-zA-Z0-9\\-_]")
{
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/Applet", new PlasmoidPackage());
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/DataEngine", new DataEnginePackage());
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/Theme", new ThemePackage());
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/ContainmentActions", new ContainmentActionsPackage());
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/Generic", new GenericPackage());
}
static QSet<QString> knownCategories();
@ -68,13 +71,23 @@ public:
static QSet<QString> s_customCategories;
QHash<QString, QWeakPointer<PackageStructure> > structures;
bool isDefaultLoader;
QString dataEnginePluginDir;
QString packageStructurePluginDir;
static QString s_dataEnginePluginDir;
static QString s_packageStructurePluginDir;
static QString s_plasmoidsPluginDir;
static QString s_servicesPluginDir;
static QString s_containmentActionsPluginDir;
QRegExp packageRE;
};
QSet<QString> PluginLoaderPrivate::s_customCategories;
QString PluginLoaderPrivate::s_dataEnginePluginDir("plasma/dataengine");
QString PluginLoaderPrivate::s_packageStructurePluginDir("plasma/packagestructure");
QString PluginLoaderPrivate::s_plasmoidsPluginDir("plasma/applets");
QString PluginLoaderPrivate::s_servicesPluginDir("plasma/services");
QString PluginLoaderPrivate::s_containmentActionsPluginDir("plasma/containmentactions");
QSet<QString> PluginLoaderPrivate::knownCategories()
{
// this is to trick the tranlsation tools into making the correct
@ -167,79 +180,85 @@ Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVari
return applet;
}
// the application-specific appletLoader failed to create an applet, here we try with our own logic.
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
bool isContainment = false;
if (offers.isEmpty()) {
//TODO: what would be -really- cool is offer to try and download the applet
// from the network at this point
offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
if (offers.count() > 0) {
isContainment = true;
}
}
if (offers.isEmpty()) {
#ifndef NDEBUG
// qDebug() << "offers is empty for " << name;
#endif
return 0;
}
#ifndef NDEBUG
if (offers.count() > 1) {
// qDebug() << "hey! we got more than one! let's blindly take the first one";
}
#endif
KService::Ptr offer = offers.first();
if (appletId == 0) {
appletId = ++AppletPrivate::s_maxAppletId;
}
QVariantList allArgs;
allArgs << offer->storageId() << appletId << args;
if (!offer->property("X-Plasma-API").toString().isEmpty() &&
offer->property("Library").toString().isEmpty()) {
#ifndef NDEBUG
// qDebug() << "we have a script using the"
// << offer->property("X-Plasma-API").toString() << "API";
#endif
if (isContainment) {
return new Containment(0, allArgs);
} else {
if (offer->serviceTypes().contains("Plasma/Containment")) {
return new Containment(0, allArgs);
} else {
return new Applet(0, allArgs);
}
}
}
KPluginLoader plugin(*offer);
if (!Plasma::isPluginVersionCompatible(plugin.pluginVersion())) {
// Look for C++ plugins first
auto filter = [&name](const KPluginMetaData &md) -> bool
{
return md.pluginId() == name;
};
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_plasmoidsPluginDir, filter);
if (plugins.count()) {
KPluginInfo::List lst = KPluginInfo::fromMetaData(plugins);
KPluginLoader loader(lst.first().libraryPath());
if (!Plasma::isPluginVersionCompatible(loader.pluginVersion())) {
return 0;
}
KPluginFactory *factory = loader.factory();
if (factory) {
QVariantList allArgs;
allArgs << loader.metaData().toVariantMap() << appletId << args;
applet = factory->create<Plasma::Applet>(0, allArgs);
}
}
if (applet) {
return applet;
}
KPackage::Package p = KPackage::PackageLoader::self()->loadPackage("Plasma/Applet", name);
if (!p.isValid()) {
//some applets have actually the root path from another package, such as icontasks
//try to do a fallback package with X-Plasma-RootPath root
p.setRequired("mainscript", false);
p.setPath(name);
KPluginMetaData md(p.filePath("metadata"));
const KPackage::Package fp = KPackage::PackageLoader::self()->loadPackage("Plasma/Applet", md.value("X-Plasma-RootPath"));
p.setFallbackPackage(fp);
if (!fp.isValid()) {
return 0;
}
}
// backwards compatibility: search in the root plugins directory
// TODO: remove when Plasma 5.4 is released
{
KPluginInfo info = KPluginInfo::fromMetaData(p.metadata());
KPluginLoader loader(info.libraryPath());
if (!Plasma::isPluginVersionCompatible(loader.pluginVersion())) {
return 0;
}
KPluginFactory *factory = loader.factory();
if (factory) {
QVariantList allArgs;
allArgs << loader.metaData().toVariantMap() << appletId << args;
applet = factory->create<Plasma::Applet>(0, allArgs);
}
if (applet) {
return applet;
}
}
QString error;
applet = offer->createInstance<Plasma::Applet>(0, allArgs, &error);
if (!applet) {
qWarning() << "Could not load applet" << name << "! reason given:" << error <<"Falling back to an empty one";
qWarning() << "Could not load applet" << name << "Falling back to an empty one";
if (isContainment) {
return new Containment(0, allArgs);
} else {
if (offer->serviceTypes().contains("Plasma/Containment")) {
QVariantList allArgs;
allArgs << p.metadata().fileName() << appletId << args;
if (p.metadata().serviceTypes().contains("Plasma/Containment")) {
return new Containment(0, allArgs);
} else {
return new Applet(0, allArgs);
}
}
}
return applet;
@ -257,7 +276,7 @@ DataEngine *PluginLoader::loadDataEngine(const QString &name)
{
return md.pluginId() == name;
};
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(d->dataEnginePluginDir, filter);
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filter);
if (plugins.count()) {
KPluginInfo::List lst = KPluginInfo::fromMetaData(plugins);
@ -272,41 +291,40 @@ DataEngine *PluginLoader::loadDataEngine(const QString &name)
return engine;
}
// Fall back to querying scripted plugins
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
// First check with KServiceTypeTrader as that is where scripted engines will be
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
if (!offers.isEmpty()) {
const QString api = offers.first()->property("X-Plasma-API").toString();
if (!api.isEmpty()) {
// it is a scripted plugin, load it via a package
engine = new DataEngine(KPluginInfo(offers.first()), 0);
}
const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage("Plasma/DataEngine", name);
if (!p.isValid()) {
return 0;
}
return engine;
return new DataEngine(KPluginInfo(p.metadata().fileName()), 0);
}
QStringList PluginLoader::listAllEngines(const QString &parentApp)
{
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
if (!KPackage::PackageLoader::self()->loadPackageStructure("Plasma/DataEngine")) {
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/DataEngine", new DataEnginePackage());
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
QStringList engines;
foreach (const KService::Ptr &service, offers) {
QString name = service->property("X-KDE-PluginInfo-Name").toString();
if (!name.isEmpty()) {
engines.append(name);
// Look for C++ plugins first
auto filter = [&parentApp](const KPluginMetaData &md) -> bool
{
return md.value("X-KDE-ParentApp") == parentApp;
};
QVector<KPluginMetaData> plugins;
if (parentApp.isEmpty()) {
plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir);
} else {
plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filter);
}
for (auto plugin : plugins) {
engines << plugin.pluginId();
}
const QList<KPluginMetaData> packagePlugins = KPackage::PackageLoader::self()->listPackages("Plasma/DataEngine");
for (auto plugin : packagePlugins) {
engines << plugin.pluginId();
}
return engines;
@ -314,21 +332,44 @@ QStringList PluginLoader::listAllEngines(const QString &parentApp)
KPluginInfo::List PluginLoader::listEngineInfo(const QString &parentApp)
{
if (!KPackage::PackageLoader::self()->loadPackageStructure("Plasma/DataEngine")) {
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/DataEngine", new DataEnginePackage());
}
return PluginLoader::self()->listDataEngineInfo(parentApp);
}
KPluginInfo::List PluginLoader::listEngineInfoByCategory(const QString &category, const QString &parentApp)
{
QString constraint = QString("[X-KDE-PluginInfo-Category] == '%1'").arg(category);
if (parentApp.isEmpty()) {
constraint.append(" and not exist [X-KDE-ParentApp]");
} else {
constraint.append(" and [X-KDE-ParentApp] == '").append(parentApp).append("'");
if (!KPackage::PackageLoader::self()->loadPackageStructure("Plasma/DataEngine")) {
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/DataEngine", new DataEnginePackage());
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
return KPluginInfo::fromServices(offers);
KPluginInfo::List list;
// Look for C++ plugins first
auto filterNormal = [&category](const KPluginMetaData &md) -> bool
{
return md.value("X-KDE-PluginInfo-Category") == category;
};
auto filterParentApp = [&category, &parentApp](const KPluginMetaData &md) -> bool
{
return md.value("X-KDE-ParentApp") == parentApp && md.value("X-KDE-PluginInfo-Category") == category;
};
QVector<KPluginMetaData> plugins;
if (parentApp.isEmpty()) {
plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filterNormal);
} else {
plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filterParentApp);
}
list = KPluginInfo::fromMetaData(plugins);
//TODO FIXME: PackageLoader needs to have a function to inject packageStructures
const QList<KPluginMetaData> packagePlugins = KPackage::PackageLoader::self()->listPackages("Plasma/DataEngine");
list << KPluginInfo::fromMetaData(packagePlugins.toVector());
return list;
}
Service *PluginLoader::loadService(const QString &name, const QVariantList &args, QObject *parent)
@ -345,35 +386,34 @@ Service *PluginLoader::loadService(const QString &name, const QVariantList &args
return new Storage(parent);
}
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Service", constraint);
if (offers.isEmpty()) {
#ifndef NDEBUG
// qDebug() << "offers is empty for " << name;
#endif
return new NullService(name, parent);
}
KService::Ptr offer = offers.first();
QString error;
if (Plasma::isPluginVersionCompatible(KPluginLoader(*offer).pluginVersion())) {
service = offer->createInstance<Plasma::Service>(parent, args, &error);
}
if (!service) {
#ifndef NDEBUG
// qDebug() << "Couldn't load Service \"" << name << "\"! reason given: " << error;
#endif
return new NullService(name, parent);
// Look for C++ plugins first
auto filter = [&name](const KPluginMetaData &md) -> bool
{
return md.pluginId() == name;
};
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_servicesPluginDir, filter);
if (plugins.count()) {
KPluginInfo::List lst = KPluginInfo::fromMetaData(plugins);
KPluginLoader loader(lst.first().libraryPath());
if (!Plasma::isPluginVersionCompatible(loader.pluginVersion())) {
return 0;
}
KPluginFactory *factory = loader.factory();
if (factory) {
service = factory->create<Plasma::Service>(0, args);
}
}
if (service) {
if (service->name().isEmpty()) {
service->setName(name);
}
return service;
} else {
return new NullService(name, parent);
}
}
ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, const QString &name, const QVariantList &args)
@ -387,6 +427,29 @@ ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, co
return actions;
}
// Look for C++ plugins first
auto filter = [&name](const KPluginMetaData &md) -> bool
{
return md.pluginId() == name;
};
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_containmentActionsPluginDir, filter);
if (plugins.count()) {
KPluginInfo::List lst = KPluginInfo::fromMetaData(plugins);
KPluginLoader loader(lst.first().libraryPath());
const QVariantList argsWithMetaData = QVariantList() << loader.metaData().toVariantMap();
KPluginFactory *factory = loader.factory();
if (factory) {
actions = factory->create<Plasma::ContainmentActions>(0, argsWithMetaData);
}
}
if (actions) {
return actions;
}
//FIXME: this is only for backwards compatibility, but probably will have to stay
//for the time being
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ContainmentActions", constraint);
@ -468,7 +531,7 @@ Package PluginLoader::loadPackage(const QString &packageFormat, const QString &s
//fallback to old structures
} else {
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
structure = KPluginTrader::createInstanceFromQuery<Plasma::PackageStructure>(d->packageStructurePluginDir, "Plasma/PackageStructure", constraint, 0);
structure = KPluginTrader::createInstanceFromQuery<Plasma::PackageStructure>(PluginLoaderPrivate::s_packageStructurePluginDir, "Plasma/PackageStructure", constraint, 0);
if (structure) {
structure->d->internalStructure = new PackageStructureWrapper(structure);
}
@ -495,45 +558,70 @@ KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QS
list = internalAppletInfo(category);
}
QString constraint = PluginLoaderPrivate::parentAppConstraint(parentApp);
//note: constraint guaranteed non-empty from here down
//FIXME: this assumes we are always use packages.. no pure c++
if (category.isEmpty()) { //use all but the excluded categories
KConfigGroup group(KSharedConfig::openConfig(), "General");
QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
foreach (const QString &category, excluded) {
constraint.append(" and [X-KDE-PluginInfo-Category] != '").append(category).append("'");
auto filter = [&excluded, &parentApp](const KPluginMetaData &md) -> bool
{
const QString pa = md.value("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
for (auto md : KPackage::PackageLoader::self()->findPackages("Plasma/Applet", QString(), filter)) {
list << KPluginInfo(KService::serviceByStorageId(md.metaDataFileName()));
}
return list;
} else { //specific category (this could be an excluded one - is that bad?)
constraint.append(" and ").append("[X-KDE-PluginInfo-Category] == '").append(category).append("'");
auto filter = [&category, &parentApp](const KPluginMetaData &md) -> bool
{
const QString pa = md.value("X-KDE-ParentApp");
if (category == "Miscellaneous") {
constraint.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
return (pa.isEmpty() || pa == parentApp) && (md.category() == category || md.category().isEmpty());
} else {
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
for (auto md : KPackage::PackageLoader::self()->findPackages("Plasma/Applet", QString(), filter)) {
list << KPluginInfo(KService::serviceByStorageId(md.metaDataFileName()));
}
return list;
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
//qDebug() << "Applet::listAppletInfo constraint was '" << constraint
// << "' which got us " << offers.count() << " matches";
return KPluginInfo::fromServices(offers);
}
KPluginInfo::List PluginLoader::listAppletInfoForMimeType(const QString &mimeType)
{
QString constraint = PluginLoaderPrivate::parentAppConstraint();
constraint.append(QString(" and '%1' in [X-Plasma-DropMimeTypes]").arg(mimeType));
//qDebug() << "listAppletInfoForMimetype with" << mimeType << constraint;
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
return KPluginInfo::fromServices(offers);
auto filter = [&mimeType](const KPluginMetaData &md) -> bool
{
return md.value("X-Plasma-DropMimeTypes").contains(mimeType);
};
return KPluginInfo::fromMetaData(KPackage::PackageLoader::self()->findPackages("Plasma/Applet", QString(), filter).toVector());
}
KPluginInfo::List PluginLoader::listAppletInfoForUrl(const QUrl &url)
{
QString constraint = PluginLoaderPrivate::parentAppConstraint();
constraint.append(" and exist [X-Plasma-DropUrlPatterns]");
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
QString parentApp;
QCoreApplication *app = QCoreApplication::instance();
if (app) {
parentApp = app->applicationName();
}
auto filter = [&parentApp](const KPluginMetaData &md) -> bool
{
const QString pa = md.value("X-KDE-ParentApp");
return (pa.isEmpty() || pa == parentApp) && !md.value("X-Plasma-DropUrlPatterns").isEmpty();
};
KPluginInfo::List allApplets = KPluginInfo::fromMetaData(KPackage::PackageLoader::self()->findPackages("Plasma/Applet", QString(), filter).toVector());
KPluginInfo::List allApplets = KPluginInfo::fromServices(offers);
KPluginInfo::List filtered;
foreach (const KPluginInfo &info, allApplets) {
QStringList urlPatterns = info.property("X-Plasma-DropUrlPatterns").toStringList();
@ -554,44 +642,26 @@ KPluginInfo::List PluginLoader::listAppletInfoForUrl(const QUrl &url)
QStringList PluginLoader::listAppletCategories(const QString &parentApp, bool visibleOnly)
{
QString constraint = PluginLoaderPrivate::parentAppConstraint(parentApp);
constraint.append(" and exist [X-KDE-PluginInfo-Category]");
KConfigGroup group(KSharedConfig::openConfig(), "General");
const QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
foreach (const QString &category, excluded) {
constraint.append(" and [X-KDE-PluginInfo-Category] != '").append(category).append("'");
}
auto filter = [&parentApp, &excluded, visibleOnly](const KPluginMetaData &md) -> bool
{
const QString pa = md.value("X-KDE-ParentApp");
return (pa.isEmpty() || pa == parentApp) && (excluded.isEmpty() || excluded.contains(md.value("X-KDE-PluginInfo-Category"))) && (!visibleOnly || !md.isHidden());
};
QList<KPluginMetaData> allApplets = KPackage::PackageLoader::self()->findPackages("Plasma/Applet", QString(), filter);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
QStringList categories;
QSet<QString> known = PluginLoaderPrivate::knownCategories();
foreach (const KService::Ptr &applet, offers) {
QString appletCategory = applet->property("X-KDE-PluginInfo-Category").toString();
if (visibleOnly && applet->noDisplay()) {
// we don't want to show the hidden category
continue;
}
//qDebug() << " and we have " << appletCategory;
if (!appletCategory.isEmpty() && !known.contains(appletCategory.toLower())) {
#ifndef NDEBUG
// qDebug() << "Unknown category: " << applet->name() << "says it is in the"
// << appletCategory << "category which is unknown to us";
#endif
appletCategory.clear();
}
if (appletCategory.isEmpty()) {
for (auto plugin : allApplets) {
if (plugin.category().isEmpty()) {
if (!categories.contains(i18nc("misc category", "Miscellaneous"))) {
categories << i18nc("misc category", "Miscellaneous");
}
} else if (!categories.contains(appletCategory)) {
categories << appletCategory;
} else {
categories << plugin.category();
}
}
categories.sort();
return categories;
}
@ -612,14 +682,12 @@ QString PluginLoader::appletCategory(const QString &appletName)
return QString();
}
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(appletName);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
if (offers.isEmpty()) {
const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage("Plasma/Applet", appletName);
if (!p.isValid()) {
return QString();
}
return offers.first()->property("X-KDE-PluginInfo-Category").toString();
return p.metadata().category();
}
KPluginInfo::List PluginLoader::listContainments(const QString &category,
@ -632,53 +700,54 @@ KPluginInfo::List PluginLoader::listContainmentsOfType(const QString &type,
const QString &category,
const QString &parentApp)
{
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
if (!KPackage::PackageLoader::self()->loadPackageStructure("Plasma/Applet")) {
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/Applet", new DataEnginePackage());
}
if (!type.isEmpty()) {
if (!constraint.isEmpty()) {
constraint.append(" and (");
KConfigGroup group(KSharedConfig::openConfig(), "General");
const QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
auto filter = [&type, &category, &parentApp](const KPluginMetaData &md) -> bool
{
if (!md.serviceTypes().contains("Plasma/Containment")) {
return false;
}
const QString pa = md.value("X-KDE-ParentApp");
if (!pa.isEmpty() && pa != parentApp) {
return false;
}
//constraint.append("'").append(type).append("' == [X-Plasma-ContainmentType]");
if (type == "Desktop") {
constraint += "not exist [X-Plasma-ContainmentType] or ";
}
constraint += "[X-Plasma-ContainmentType] == '" + type + "')";
//by default containments are Desktop, so is not mandatory to specify it
if (!type.isEmpty() && md.value("X-Plasma-ContainmentType") != type) {
return false;
}
if (!category.isEmpty()) {
if (!constraint.isEmpty()) {
constraint.append(" and ");
if (!category.isEmpty() && md.value("X-KDE-PluginInfo-Category") != category) {
return false;
}
constraint.append("[X-KDE-PluginInfo-Category] == '").append(category).append("'");
if (category == "Miscellaneous") {
constraint.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
}
}
return true;
};
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
// qDebug() << "constraint was" << constraint << "which got us" << offers.count() << "matches";
return KPluginInfo::fromServices(offers);
return KPluginInfo::fromMetaData(KPackage::PackageLoader::self()->findPackages("Plasma/Applet", QString(), filter).toVector());
}
KPluginInfo::List PluginLoader::listContainmentsForMimeType(const QString &mimeType)
{
const QString constraint = QString("'%1' in [X-Plasma-DropMimeTypes]").arg(mimeType);
//qDebug() << mimeType << constraint;
const KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
return KPluginInfo::fromServices(offers);
if (!KPackage::PackageLoader::self()->loadPackageStructure("Plasma/Applet")) {
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/Applet", new DataEnginePackage());
}
auto filter = [&mimeType](const KPluginMetaData &md) -> bool
{
return md.value("X-KDE-ServiceTypes").contains("Plasma/Containment") && md.value("X-Plasma-DropMimeTypes").contains(mimeType);
};
return KPluginInfo::fromMetaData(KPackage::PackageLoader::self()->findPackages("Plasma/Applet", QString(), filter).toVector());
}
QStringList PluginLoader::listContainmentTypes()
{
if (!KPackage::PackageLoader::self()->loadPackageStructure("Plasma/Applet")) {
KPackage::PackageLoader::self()->addKnownPackageStructure("Plasma/Applet", new DataEnginePackage());
}
KPluginInfo::List containmentInfos = listContainments();
QSet<QString> types;
@ -707,7 +776,7 @@ KPluginInfo::List PluginLoader::listDataEngineInfo(const QString &parentApp)
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
list.append(KPluginTrader::self()->query(d->dataEnginePluginDir, "Plasma/DataEngine", constraint));
list.append(KPluginTrader::self()->query(PluginLoaderPrivate::s_dataEnginePluginDir, "Plasma/DataEngine", constraint));
return list;
}
@ -726,8 +795,22 @@ KPluginInfo::List PluginLoader::listContainmentActionsInfo(const QString &parent
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
list.append(KPluginTrader::self()->query(PluginLoaderPrivate::s_containmentActionsPluginDir, "Plasma/ContainmentActions", constraint));
QSet<QString> knownPlugins;
foreach (const KPluginInfo &p, list) {
knownPlugins.insert(p.pluginName());
}
//FIXME: this is only for backwards compatibility, but probably will have to stay
//for the time being
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ContainmentActions", constraint);
return KPluginInfo::fromServices(offers);
foreach (KService::Ptr s, offers) {
if (!knownPlugins.contains(s->pluginKeyword())) {
list.append(KPluginInfo(s));
}
}
return list;
}
Applet *PluginLoader::internalLoadApplet(const QString &name, uint appletId, const QVariantList &args)

View File

@ -35,7 +35,8 @@
#include <kkeysequencewidget.h>
#include <kglobalaccel.h>
#include <KConfigLoader>
#include <KServiceTypeTrader>
#include <KPluginTrader>
#include <kpackage/packageloader.h>
#include "containment.h"
#include "corona.h"
@ -176,16 +177,17 @@ void AppletPrivate::init(const QString &packagePath, const QVariantList &args)
QString constraint;
QStringList provides = q->pluginInfo().property("X-Plasma-Provides").value<QStringList>();
if (!provides.isEmpty()) {
bool first = true;
foreach (const QString &prov, provides) {
if (!first) {
constraint += " or ";
auto filter = [&provides](const KPluginMetaData &md) -> bool
{
foreach (const QString &p, provides) {
if (md.value("X-Plasma-Provides").contains(p)) {
return true;
}
first = false;
constraint += "'" + prov + "' in [X-Plasma-Provides]";
}
return false;
};
QList<KPluginMetaData> applets = KPackage::PackageLoader::self()->findPackages("Plasma/Applet", QString(), filter);
KPluginInfo::List applets = KPluginInfo::fromServices(KServiceTypeTrader::self()->query("Plasma/Applet", constraint));
if (applets.count() > 1) {
QAction *a = new QAction(QIcon::fromTheme("preferences-desktop-default-applications"), i18n("Alternatives..."), q);
q->actions()->addAction("alternatives", a);
@ -457,7 +459,7 @@ QString AppletPrivate::globalName() const
return QString();
}
return appletDescription.service()->library();
return appletDescription.pluginName();
}
void AppletPrivate::scheduleConstraintsUpdate(Plasma::Types::Constraints c)

View File

@ -24,7 +24,6 @@
#include <QDebug>
#include <kservicetypetrader.h>
#include <qstandardpaths.h>
#include "datacontainer.h"

View File

@ -170,6 +170,9 @@ private:
#define K_EXPORT_PLASMA_APPLETSCRIPTENGINE(libname, classname) \
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();)
#define K_EXPORT_PLASMA_APPLETSCRIPTENGINE_WITH_JSON(libname, classname, jsonFile) \
K_PLUGIN_FACTORY_WITH_JSON(factory, jsonFile, registerPlugin<classname>();) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
} //Plasma namespace
#endif

View File

@ -146,6 +146,9 @@ private:
#define K_EXPORT_PLASMA_DATAENGINESCRIPTENGINE(libname, classname) \
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();)
#define K_EXPORT_PLASMA_DATAENGINESCRIPTENGINE_WITH_JSON(libname, classname, jsonFile) \
K_PLUGIN_FACTORY_WITH_JSON(factory, jsonFile, registerPlugin<classname>();) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
} //Plasma namespace
#endif

View File

@ -21,7 +21,6 @@
#include <QDebug>
#include <kservice.h>
#include <kservicetypetrader.h>
#include "applet.h"
#include "dataengine.h"
@ -61,119 +60,50 @@ QString ScriptEngine::mainScript() const
QStringList knownLanguages(Types::ComponentTypes types)
{
QString constraintTemplate = "'%1' in [X-Plasma-ComponentTypes]";
QString constraint;
if (types & Types::AppletComponent) {
// currently this if statement is not needed, but this future proofs
// the code against someone initializing constraint to something
// before we get here.
if (!constraint.isEmpty()) {
constraint.append(" or ");
}
constraint.append(constraintTemplate.arg("Applet"));
}
if (types & Types::DataEngineComponent) {
if (!constraint.isEmpty()) {
constraint.append(" or ");
}
constraint.append(constraintTemplate.arg("DataEngine"));
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ScriptEngine", constraint);
//qDebug() << "Applet::knownApplets constraint was '" << constraint
// << "' which got us " << offers.count() << " matches";
QStringList languages;
foreach (const KService::Ptr &service, offers) {
QString language = service->property("X-Plasma-API").toString();
if (!languages.contains(language)) {
languages.append(language);
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins("plasma/scriptengines");
for (auto plugin : plugins) {
if ((types & Types::AppletComponent) &&
plugin.value("X-Plasma-ComponentTypes") == "Applet") {
languages << plugin.value("X-Plasma-API");
} else if ((types & Types::DataEngineComponent) &&
plugin.value("X-Plasma-ComponentTypes") == "DataEngine") {
languages << plugin.value("X-Plasma-API");
}
}
return languages;
}
KService::List engineOffers(const QString &language, Types::ComponentType type)
{
if (language.isEmpty()) {
return KService::List();
}
QRegExp re("[^a-zA-Z0-9\\-_]");
if (re.indexIn(language) != -1) {
#ifndef NDEBUG
// qDebug() << "invalid language attempted:" << language;
#endif
return KService::List();
}
QString component;
switch (type) {
case Types::AppletComponent:
component = "Applet";
break;
case Types::DataEngineComponent:
component = "DataEngine";
break;
default:
return KService::List();
break;
}
QString constraint = QString("[X-Plasma-API] == '%1' and "
"'%2' in [X-Plasma-ComponentTypes]").arg(language, component);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ScriptEngine", constraint);
/* // qDebug() << "********************* loadingApplet with Plasma/ScriptEngine" << constraint
<< "resulting in" << offers.count() << "results";*/
if (offers.isEmpty()) {
#ifndef NDEBUG
// qDebug() << "No offers for \"" << language << "\"";
#endif
}
return offers;
}
ScriptEngine *loadEngine(const QString &language, Types::ComponentType type, QObject *parent,
const QVariantList &args = QVariantList())
{
KService::List offers = engineOffers(language, type);
QString error;
ScriptEngine *engine = 0;
foreach (const KService::Ptr &service, offers) {
switch (type) {
case Types::AppletComponent:
engine = service->createInstance<Plasma::AppletScript>(parent, args, &error);
break;
case Types::DataEngineComponent:
engine = service->createInstance<Plasma::DataEngineScript>(parent, args, &error);
break;
default:
auto filter = [&language](const KPluginMetaData &md) -> bool
{
return md.value("X-Plasma-API") == language;
};
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins("plasma/scriptengines", filter);
if (plugins.count()) {
if ((type & Types::AppletComponent) &&
plugins.first().value("X-Plasma-ComponentTypes") != "Applet") {
return 0;
break;
} else if ((type & Types::DataEngineComponent) &&
plugins.first().value("X-Plasma-ComponentTypes") != "DataEngine") {
return 0;
}
KPluginInfo::List lst = KPluginInfo::fromMetaData(plugins);
KPluginLoader loader(lst.first().libraryPath());
KPluginFactory *factory = loader.factory();
if (factory) {
engine = factory->create<Plasma::ScriptEngine>(0, args);
}
}
if (engine) {
return engine;
}
#ifndef NDEBUG
// qDebug() << "Couldn't load script engine for language " << language
// << "! error reported: " << error;
#endif
}
// Try installing the engine. However, it's too late for this request.
ComponentInstaller::self()->installMissingComponent("scriptengine", language);
return 0;
}
AppletScript *loadScriptEngine(const QString &language, Applet *applet, const QVariantList &args)

View File

@ -27,7 +27,6 @@
#include <QDebug>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <ksharedconfig.h>
#include <KConfigLoader>
#include <KConfigSkeleton>

View File

@ -232,5 +232,9 @@ Q_DECLARE_METATYPE(Plasma::Service *)
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
#define K_EXPORT_PLASMA_SERVICE_WITH_JSON(libname, classname, jsonFile) \
K_PLUGIN_FACTORY_WITH_JSON(factory, jsonFile, registerPlugin<classname>();) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
#endif // multiple inclusion guard

View File

@ -22,15 +22,17 @@
#include <QDebug>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <kplugintrader.h>
#include <kshell.h>
#include <kconfig.h>
#include <ksycoca.h>
#include <klocalizedstring.h>
#include <KPluginMetaData>
#include <plasma/packagestructure.h>
#include <plasma/package.h>
#include <plasma/pluginloader.h>
#include <kpackage/packageloader.h>
#include <kjob.h>
#include <qcommandlineparser.h>
@ -254,28 +256,20 @@ void PlasmaPkg::runMain()
d->packageRoot = "kwin/scripts/";
d->servicePrefix = "kwin-script-";
d->pluginTypes << "KWin/Script";
} else { /* if (KSycoca::isAvailable()) */
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(type);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/PackageStructure", constraint);
if (offers.isEmpty()) {
//do it trough normal plugin loading
} else {
Plasma::Package p = Plasma::PluginLoader::self()->loadPackage(type);
if (!p.hasValidStructure()) {
d->coutput(i18n("Could not find a suitable installer for package of type %1", type));
exit(5);
return;
}
qWarning() << "custom PackageStructure plugins not ported";
KService::Ptr offer = offers.first();
QString error;
d->installer = new Plasma::Package(offer->createInstance<Plasma::PackageStructure>(0, QVariantList(), &error));
if (!d->installer) {
d->coutput(i18n("Could not load installer for package of type %1. Error reported was: %2",
d->parser->value("type"), error));
return;
}
d->installer = new Plasma::Package(p);
//d->packageRoot = d->installer->defaultPackageRoot();
//pluginTypes << d->installer->type();
d->pluginTypes << type;
}
if (d->parser->isSet("show")) {
const QString pluginName = d->package;
@ -442,9 +436,9 @@ QStringList PlasmaPkgPrivate::packages(const QStringList &types)
}
}
const KService::List services = KServiceTypeTrader::self()->query(type);
foreach (const KService::Ptr &service, services) {
const QString _plugin = service->property("X-KDE-PluginInfo-Name", QVariant::String).toString();
const QList<KPluginMetaData> plugins = KPackage::PackageLoader::self()->listPackages(type);
for (auto plugin : plugins) {
const QString _plugin = plugin.pluginId();
if (!result.contains(_plugin)) {
result << _plugin;
}
@ -584,17 +578,14 @@ void PlasmaPkgPrivate::listTypes()
builtIns.insert(i18n("KWin Script"), QStringList() << "KWin/Script" << "kwin/scripts/" << "kwinscript");
renderTypeTable(builtIns);
KService::List offers;
//if (KSycoca::isAvailable()) {
offers = KServiceTypeTrader::self()->query("Plasma/PackageStructure");
//}
const KPluginInfo::List offers = KPluginTrader::self()->query("kpackage/packagestructure", "KPackage/PackageStructure");
if (!offers.isEmpty()) {
std::cout << std::endl;
coutput(i18n("Provided by plugins:"));
QMap<QString, QStringList> plugins;
foreach (const KService::Ptr service, offers) {
KPluginInfo info(service);
for (auto info : offers) {
//const QString proot = "";
//Plasma::PackageStructure* structure = Plasma::PackageStructure::load(info.pluginName());
QString name = info.name();
@ -602,7 +593,7 @@ void PlasmaPkgPrivate::listTypes()
QString plugin = info.pluginName();
//QString path = structure->defaultPackageRoot();
//QString path = defaultPackageRoot;
plugins.insert(name, QStringList() << plugin);
plugins.insert(name, QStringList() << name << plugin << comment);
//qDebug() << "KService stuff:" << name << plugin << comment;
}

View File

@ -1,6 +1,6 @@
add_subdirectory(qml)
add_subdirectory(ruby)
#add_subdirectory(ruby)
# Re-enable when we have Python bindings for libplasma
#if (PYTHONLIBRARY_FOUND AND NOT WIN32)

View File

@ -19,6 +19,8 @@ set(declarative_appletscript_SRCS
add_library(plasma_appletscript_declarative MODULE ${declarative_appletscript_SRCS} )
set_target_properties(plasma_appletscript_declarative PROPERTIES PREFIX "")
kcoreaddons_desktop_to_json(plasma_appletscript_declarative data/plasma-scriptengine-applet-declarative.desktop)
target_link_libraries(plasma_appletscript_declarative
Qt5::Quick
Qt5::Qml
@ -35,7 +37,7 @@ target_link_libraries(plasma_appletscript_declarative
)
install(TARGETS plasma_appletscript_declarative DESTINATION ${KDE_INSTALL_PLUGINDIR})
install(TARGETS plasma_appletscript_declarative DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/scriptengines)
install(FILES data/plasma-scriptengine-applet-declarative.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
install(FILES data/plasma-wallpaper.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR})

View File

@ -30,7 +30,6 @@
#include <kactioncollection.h>
#include <QDebug>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <klocalizedstring.h>
#include <KConfigLoader>
@ -498,13 +497,17 @@ bool AppletInterface::userConfiguring() const
int AppletInterface::apiVersion() const
{
const QString constraint("[X-Plasma-API] == 'declarative' and 'Applet' in [X-Plasma-ComponentTypes]");
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ScriptEngine", constraint);
if (offers.isEmpty()) {
// Look for C++ plugins first
auto filter = [](const KPluginMetaData &md) -> bool
{
return md.value("X-Plasma-API") == "declarativeappletscript" && md.value("X-Plasma-ComponentTypes").contains("Applet");
};
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins("plasma/scriptengines", filter);
if (plugins.isEmpty()) {
return -1;
}
return offers.first()->property("X-KDE-PluginInfo-Version", QVariant::Int).toInt();
return plugins.first().value("X-KDE-PluginInfo-Version").toInt();
}
void AppletInterface::setAssociatedApplication(const QString &string)

View File

@ -428,10 +428,11 @@ QPointF ContainmentInterface::adjustToAvailableScreenRegion(int x, int y, int w,
void ContainmentInterface::processMimeData(QObject *mimeDataProxy, int x, int y)
{
QMimeData* mime = qobject_cast<QMimeData*>(mimeDataProxy);
if (mime)
if (mime) {
processMimeData(mime, x, y);
else
} else {
processMimeData(mimeDataProxy->property("mimeData").value<QMimeData*>(), x, y);
}
}
void ContainmentInterface::processMimeData(QMimeData *mimeData, int x, int y)

View File

@ -46,17 +46,11 @@
#include <kdeclarative/qmlobject.h>
#include <kdeclarative/configpropertymap.h>
K_EXPORT_PLASMA_APPLETSCRIPTENGINE(declarativeappletscript, DeclarativeAppletScript)
DeclarativeAppletScript::DeclarativeAppletScript(QObject *parent, const QVariantList &args)
: Plasma::AppletScript(parent),
m_interface(0),
m_args(args)
{
// Chop off list entry added by KService::createInstance() before we
// hand this to the applet via externalData() later.
m_args.removeLast();
//qmlRegisterType<AppletInterface>();
//FIXME: use this if/when will be possible to have properties of attached items subclasses on the left hand of expressions
/*qmlRegisterUncreatableType<AppletLoader>("org.kde.plasma.plasmoid", 2, 0, "Plasmoid",
@ -132,5 +126,7 @@ QList<QAction *> DeclarativeAppletScript::contextualActions()
return m_interface->contextualActions();
}
K_EXPORT_PLASMA_APPLETSCRIPTENGINE_WITH_JSON(plasma_appletscript_declarative, DeclarativeAppletScript, "plasma-scriptengine-applet-declarative.json")
#include "declarativeappletscript.moc"

View File

@ -24,7 +24,6 @@
#include <kdeclarative/qmlobject.h>
#include <kactioncollection.h>
#include <kservicetypetrader.h>
#include <kdesktopfile.h>
#include <KConfigLoader>
@ -35,6 +34,7 @@
#include <QSignalMapper>
#include <Plasma/PluginLoader>
#include <kpackage/packageloader.h>
QHash<QObject *, WallpaperInterface *> WallpaperInterface::s_rootObjects = QHash<QObject *, WallpaperInterface *>();
@ -71,14 +71,14 @@ WallpaperInterface::~WallpaperInterface()
KPluginInfo::List WallpaperInterface::listWallpaperInfoForMimetype(const QString &mimetype, const QString &formFactor)
{
QString constraint = QString("'%1' in [X-Plasma-DropMimeTypes]").arg(mimetype);
if (!formFactor.isEmpty()) {
constraint.append("[X-Plasma-FormFactors] ~~ '").append(formFactor).append("'");
auto filter = [&mimetype, &formFactor](const KPluginMetaData &md) -> bool
{
if (!formFactor.isEmpty() && !md.value("X-Plasma-FormFactors").contains(formFactor)) {
return false;
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Wallpaper", constraint);
qDebug() << offers.count() << constraint;
return KPluginInfo::fromServices(offers);
return md.value("X-Plasma-DropMimeTypes").contains(mimetype);
};
return KPluginInfo::fromMetaData(KPackage::PackageLoader::self()->findPackages("Plasma/Wallpaper", QString(), filter).toVector());
}
Plasma::Package WallpaperInterface::package() const