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.
This commit is contained in:
parent
1763139834
commit
2019dcd0fe
2 changed files with 173 additions and 0 deletions
|
@ -24,6 +24,7 @@
|
|||
#include <QtConcurrentRun>
|
||||
#include <QDebug>
|
||||
#include <QFutureWatcher>
|
||||
#include <QStaticPlugin>
|
||||
#include <QStringList>
|
||||
|
||||
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<StaticPluginEffectLoader, QString>(this))
|
||||
{
|
||||
const QVector<QStaticPlugin> 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<EffectPluginFactory *>(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);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <QFlags>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
#include <QStaticPlugin>
|
||||
#include <QQueue>
|
||||
|
||||
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<QString, QStaticPlugin> m_staticPlugins;
|
||||
EffectLoadQueue<StaticPluginEffectLoader, QString> *m_queue;
|
||||
QStringList m_loadedEffects;
|
||||
};
|
||||
|
||||
class PluginEffectLoader : public AbstractEffectLoader
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
Loading…
Reference in a new issue