From 2019dcd0fec8e4fa9098061cfade3df737e7261a Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Fri, 8 Oct 2021 20:27:56 +0300 Subject: [PATCH] Add support for static effect plugins With static effect plugins, builtin effects can be linked to executables. It also makes libkwin one step closer to being more reusable. --- src/effectloader.cpp | 147 +++++++++++++++++++++++++++++++++++++++++++ src/effectloader.h | 26 ++++++++ 2 files changed, 173 insertions(+) diff --git a/src/effectloader.cpp b/src/effectloader.cpp index 4e10a91394..74c834c89b 100644 --- a/src/effectloader.cpp +++ b/src/effectloader.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace KWin @@ -302,6 +303,151 @@ void ScriptedEffectLoader::clear() m_queue->clear(); } +static QJsonValue readPluginInfo(const QJsonObject &metadata, const QString &key) +{ + return metadata.value(QLatin1String("KPlugin")).toObject().value(key); +} + +StaticPluginEffectLoader::StaticPluginEffectLoader(QObject *parent) + : AbstractEffectLoader(parent) + , m_queue(new EffectLoadQueue(this)) +{ + const QVector staticPlugins = QPluginLoader::staticPlugins(); + for (const QStaticPlugin &staticPlugin : staticPlugins) { + const QJsonObject rootMetaData = staticPlugin.metaData(); + if (rootMetaData.value(QLatin1String("IID")) != QLatin1String(EffectPluginFactory_iid)) { + continue; + } + + const QJsonObject pluginMetaData = rootMetaData.value(QLatin1String("MetaData")).toObject(); + const QString pluginId = readPluginInfo(pluginMetaData, QStringLiteral("Id")).toString(); + if (pluginId.isEmpty()) { + continue; + } + if (m_staticPlugins.contains(pluginId)) { + qCWarning(KWIN_CORE) << "Conflicting plugin id" << pluginId; + continue; + } + + m_staticPlugins.insert(pluginId, staticPlugin); + } +} + +StaticPluginEffectLoader::~StaticPluginEffectLoader() +{ +} + +bool StaticPluginEffectLoader::hasEffect(const QString &name) const +{ + return m_staticPlugins.contains(name); +} + +bool StaticPluginEffectLoader::isEffectSupported(const QString &name) const +{ + auto it = m_staticPlugins.constFind(name); + if (it == m_staticPlugins.constEnd()) { + return false; + } + if (EffectPluginFactory *effectFactory = factory(*it)) { + return effectFactory->isSupported(); + } + return false; +} + +QStringList StaticPluginEffectLoader::listOfKnownEffects() const +{ + return m_staticPlugins.keys(); +} + +void StaticPluginEffectLoader::clear() +{ + m_queue->clear(); +} + +bool StaticPluginEffectLoader::checkEnabledByDefault(const QStaticPlugin &staticPlugin) const +{ + const QJsonObject metadata = staticPlugin.metaData().value("MetaData").toObject(); + if (metadata.value("org.kde.kwin.effect").toObject().value("enabledByDefaultMethod").toBool()) { + if (EffectPluginFactory *effectFactory = factory(staticPlugin)) { + return effectFactory->enabledByDefault(); + } + } else if (metadata.value("KPlugin").toObject().value("EnabledByDefault").toBool()) { + return true; + } + + return false; +} + +void StaticPluginEffectLoader::queryAndLoadAll() +{ + for (auto it = m_staticPlugins.constBegin(); it != m_staticPlugins.constEnd(); ++it) { + const LoadEffectFlags flags = readConfig(it.key(), checkEnabledByDefault(it.value())); + if (flags.testFlag(LoadEffectFlag::Load)) { + m_queue->enqueue(qMakePair(it.key(), flags)); + } + } +} + +bool StaticPluginEffectLoader::loadEffect(const QString &name) +{ + return loadEffect(name, LoadEffectFlag::Load); +} + +bool StaticPluginEffectLoader::loadEffect(const QString &name, LoadEffectFlags flags) +{ + if (m_loadedEffects.contains(name)) { + qCDebug(KWIN_CORE) << name << "is already loaded"; + return false; + } + + auto staticPlugin = m_staticPlugins.constFind(name); + if (staticPlugin == m_staticPlugins.constEnd()) { + return false; + } + + EffectPluginFactory *effectFactory = factory(*staticPlugin); + if (!effectFactory) { + qCDebug(KWIN_CORE) << "Couldn't get an EffectPluginFactory for: " << name; + return false; + } + +#ifndef KWIN_UNIT_TEST + effects->makeOpenGLContextCurrent(); +#endif + if (!effectFactory->isSupported()) { + qCDebug(KWIN_CORE) << "Effect is not supported: " << name; + return false; + } + + if (flags & LoadEffectFlag::CheckDefaultFunction) { + if (!checkEnabledByDefault(*staticPlugin)) { + qCDebug(KWIN_CORE) << "Enabled by default function disables effect: " << name; + return false; + } + } + + Effect *effect = effectFactory->createEffect(); + if (!effect) { + qCDebug(KWIN_CORE) << "Failed to create effect: " << name; + return false; + } + + // insert in our loaded effects + m_loadedEffects << name; + connect(effect, &Effect::destroyed, this, [this, name]() { + m_loadedEffects.removeAll(name); + }); + + qCDebug(KWIN_CORE) << "Successfully loaded plugin effect: " << name; + Q_EMIT effectLoaded(effect, name); + return true; +} + +EffectPluginFactory *StaticPluginEffectLoader::factory(const QStaticPlugin &staticPlugin) const +{ + return qobject_cast(staticPlugin.instance()); +} + PluginEffectLoader::PluginEffectLoader(QObject *parent) : AbstractEffectLoader(parent) , m_queue(new EffectLoadQueue< PluginEffectLoader, KPluginMetaData>(this)) @@ -477,6 +623,7 @@ EffectLoader::EffectLoader(QObject *parent) { m_loaders << new BuiltInEffectLoader(this) << new ScriptedEffectLoader(this) + << new StaticPluginEffectLoader(this) << new PluginEffectLoader(this); for (auto it = m_loaders.constBegin(); it != m_loaders.constEnd(); ++it) { connect(*it, &AbstractEffectLoader::effectLoaded, this, &AbstractEffectLoader::effectLoaded); diff --git a/src/effectloader.h b/src/effectloader.h index aea1582b40..4d312fd624 100644 --- a/src/effectloader.h +++ b/src/effectloader.h @@ -17,6 +17,7 @@ #include #include #include +#include #include namespace KWin @@ -320,6 +321,31 @@ private: QMetaObject::Connection m_queryConnection; }; +class StaticPluginEffectLoader : public AbstractEffectLoader +{ + Q_OBJECT +public: + explicit StaticPluginEffectLoader(QObject *parent = nullptr); + ~StaticPluginEffectLoader() override; + + bool hasEffect(const QString &name) const override; + bool isEffectSupported(const QString &name) const override; + QStringList listOfKnownEffects() const override; + + void clear() override; + void queryAndLoadAll() override; + bool loadEffect(const QString &name) override; + bool loadEffect(const QString &name, LoadEffectFlags flags); + +private: + EffectPluginFactory *factory(const QStaticPlugin &staticPlugin) const; + bool checkEnabledByDefault(const QStaticPlugin &staticPlugin) const; + + QHash m_staticPlugins; + EffectLoadQueue *m_queue; + QStringList m_loadedEffects; +}; + class PluginEffectLoader : public AbstractEffectLoader { Q_OBJECT