From b0e892e359c1b760cdf7f2e98bd525c6987d2c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Tue, 25 Mar 2014 13:43:56 +0100 Subject: [PATCH] [kwin] Add a new EffectLoader The EffectLoader is a subclass of AbstractEffectLoader delegating all methods to instances of: * BuiltInEffectLoader * ScriptedEffectLoader * PluginEffectLoader It's used by the EffectsHandlerImpl and replaces the complete Effect loading mechanism we so far found in it. This also means that KLibrary is no longer needed to load the Effects as the PluginEffectLoader uses the KPluginTrader, which removes lots of deprecated functionality. REVIEW: 117054 --- effectloader.cpp | 65 +++++++ effectloader.h | 17 ++ effects.cpp | 351 ++--------------------------------- effects.h | 29 +-- libkwineffects/kwineffects.h | 2 - org.kde.kwin.Effects.xml | 5 - 6 files changed, 98 insertions(+), 371 deletions(-) diff --git a/effectloader.cpp b/effectloader.cpp index 5025cf25d..e2a02b1a4 100644 --- a/effectloader.cpp +++ b/effectloader.cpp @@ -453,4 +453,69 @@ void PluginEffectLoader::setPluginSubDirectory(const QString &directory) m_pluginSubDirectory = directory; } +EffectLoader::EffectLoader(QObject *parent) + : AbstractEffectLoader(parent) +{ + m_loaders << new BuiltInEffectLoader(this) + << new ScriptedEffectLoader(this) + << new PluginEffectLoader(this); + for (auto it = m_loaders.constBegin(); it != m_loaders.constEnd(); ++it) { + connect(*it, &AbstractEffectLoader::effectLoaded, this, &AbstractEffectLoader::effectLoaded); + } +} + +EffectLoader::~EffectLoader() +{ +} + +#define BOOL_MERGE( method ) \ + bool EffectLoader::method(const QString &name) const \ + { \ + for (auto it = m_loaders.constBegin(); it != m_loaders.constEnd(); ++it) { \ + if ((*it)->method(name)) { \ + return true; \ + } \ + } \ + return false; \ + } + +BOOL_MERGE(hasEffect) +BOOL_MERGE(isEffectSupported) + +#undef BOOL_MERGE + +QStringList EffectLoader::listOfKnownEffects() const +{ + QStringList result; + for (auto it = m_loaders.constBegin(); it != m_loaders.constEnd(); ++it) { + result << (*it)->listOfKnownEffects(); + } + return result; +} + +bool EffectLoader::loadEffect(const QString &name) +{ + for (auto it = m_loaders.constBegin(); it != m_loaders.constEnd(); ++it) { + if ((*it)->loadEffect(name)) { + return true; + } + } + return false; +} + +void EffectLoader::queryAndLoadAll() +{ + for (auto it = m_loaders.constBegin(); it != m_loaders.constEnd(); ++it) { + (*it)->queryAndLoadAll(); + } +} + +void EffectLoader::setConfig(KSharedConfig::Ptr config) +{ + AbstractEffectLoader::setConfig(config); + for (auto it = m_loaders.constBegin(); it != m_loaders.constEnd(); ++it) { + (*it)->setConfig(config); + } +} + } // namespace KWin diff --git a/effectloader.h b/effectloader.h index a820816b1..ad6552a06 100644 --- a/effectloader.h +++ b/effectloader.h @@ -339,6 +339,23 @@ private: QString m_pluginSubDirectory; }; +class EffectLoader : public AbstractEffectLoader +{ + Q_OBJECT +public: + explicit EffectLoader(QObject *parent = nullptr); + ~EffectLoader() override; + bool hasEffect(const QString &name) const override; + bool isEffectSupported(const QString &name) const override; + QStringList listOfKnownEffects() const override; + bool loadEffect(const QString &name) override; + void queryAndLoadAll() override; + void setConfig(KSharedConfig::Ptr config) override; + +private: + QList m_loaders; +}; + } Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::LoadEffectFlags) diff --git a/effects.cpp b/effects.cpp index 82a50fbce..c7c8caef9 100644 --- a/effects.cpp +++ b/effects.cpp @@ -22,6 +22,7 @@ along with this program. If not, see . #include "effects.h" #include "effectsadaptor.h" +#include "effectloader.h" #ifdef KWIN_BUILD_ACTIVITIES #include "activities.h" #endif @@ -45,22 +46,13 @@ along with this program. If not, see . #include "virtualdesktops.h" #include "workspace.h" #include "kwinglutils.h" -#include "effects/effect_builtins.h" #include -#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -168,41 +160,6 @@ void ScreenLockerWatcher::setLocked(bool activated) emit locked(m_locked); } -EffectLoader::EffectLoader(EffectsHandlerImpl *parent) - : QObject(parent) - , m_effects(parent) - , m_dequeueScheduled(false) -{ -} - -EffectLoader::~EffectLoader() -{ -} - -void EffectLoader::queue(const QString &effect, bool checkDefault) -{ - m_queue.enqueue(qMakePair(effect, checkDefault)); - scheduleDequeue(); -} - -void EffectLoader::dequeue() -{ - Q_ASSERT(!m_queue.isEmpty()); - m_dequeueScheduled = false; - const auto pair = m_queue.dequeue(); - m_effects->loadEffect(pair.first, pair.second); - scheduleDequeue(); -} - -void EffectLoader::scheduleDequeue() -{ - if (m_queue.isEmpty() || m_dequeueScheduled) { - return; - } - m_dequeueScheduled = true; - QMetaObject::invokeMethod(this, "dequeue", Qt::QueuedConnection); -} - //--------------------- // Static @@ -249,6 +206,14 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene) , m_currentRenderedDesktop(0) , m_effectLoader(new EffectLoader(this)) { + connect(m_effectLoader, &AbstractEffectLoader::effectLoaded, this, + [this](Effect *effect, const QString &name) { + effect_order.insert(effect->requestedEffectChainPosition(), EffectPair(name, effect)); + loaded_effects << EffectPair(name, effect); + effectsChanged(); + } + ); + m_effectLoader->setConfig(KSharedConfig::openConfig(QStringLiteral(KWIN_CONFIG))); new EffectsAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/Effects"), this); @@ -348,7 +313,6 @@ EffectsHandlerImpl::~EffectsHandlerImpl() ungrabKeyboard(); setActiveFullScreenEffect(nullptr); for (auto it = loaded_effects.begin(); it != loaded_effects.end(); ++it) { - const QString &name = (*it).first; Effect *effect = (*it).second; stopMouseInterception(effect); // remove support properties for the effect @@ -357,9 +321,6 @@ EffectsHandlerImpl::~EffectsHandlerImpl() removeSupportProperty(property, effect); } delete effect; - if (effect_libraries.contains(name)) { - effect_libraries[ name ]->unload(); - } } loaded_effects.clear(); } @@ -420,57 +381,7 @@ void EffectsHandlerImpl::setupUnmanagedConnections(Unmanaged* u) void EffectsHandlerImpl::reconfigure() { - // perform querying for the services in a thread - QFutureWatcher *watcher = new QFutureWatcher(this); - connect(watcher, SIGNAL(finished()), this, SLOT(slotEffectsQueried())); - watcher->setFuture(QtConcurrent::run(KServiceTypeTrader::self(), &KServiceTypeTrader::query, QStringLiteral("KWin/Effect"), QString())); -} - -void EffectsHandlerImpl::slotEffectsQueried() -{ - QFutureWatcher *watcher = dynamic_cast< QFutureWatcher* >(sender()); - if (!watcher) { - // slot invoked not from a FutureWatcher - return; - } - - KService::List offers = watcher->result(); - QStringList effectsToBeLoaded; - QStringList checkDefault; - KConfigGroup conf(KSharedConfig::openConfig(), "Plugins"); - - makeOpenGLContextCurrent(); - // First unload necessary effects - for (const KService::Ptr & service : offers) { - KPluginInfo plugininfo(service); - plugininfo.load(conf); - - if (plugininfo.isPluginEnabledByDefault()) { - const QString key = plugininfo.pluginName() + QString::fromLatin1("Enabled"); - if (!conf.hasKey(key)) - checkDefault.append(plugininfo.pluginName()); - } - - bool isloaded = isEffectLoaded(plugininfo.pluginName()); - bool shouldbeloaded = plugininfo.isPluginEnabled(); - if (!shouldbeloaded && isloaded) - unloadEffect(plugininfo.pluginName()); - if (shouldbeloaded) - effectsToBeLoaded.append(plugininfo.pluginName()); - } - QStringList newLoaded; - // Then load those that should be loaded - for (const QString & effectName : effectsToBeLoaded) { - if (!isEffectLoaded(effectName)) { - m_effectLoader->queue(effectName, checkDefault.contains(effectName)); - newLoaded.append(effectName); - } - } - for (const EffectPair & ep : loaded_effects) { - if (!newLoaded.contains(ep.first)) // don't reconfigure newly loaded effects - ep.second->reconfigure(Effect::ReconfigureAll); - } - watcher->deleteLater(); + m_effectLoader->queryAndLoadAll(); } // the idea is that effects call this function again which calls the next one @@ -1387,25 +1298,6 @@ QPainter *EffectsHandlerImpl::scenePainter() } } -KLibrary* EffectsHandlerImpl::findEffectLibrary(KService* service) -{ - QString libname = service->library(); -#ifdef KWIN_HAVE_OPENGLES - if (libname.startsWith(QStringLiteral("kwin4_effect_"))) { - libname.replace(QStringLiteral("kwin4_effect_"), QStringLiteral("kwin4_effect_gles_")); - } -#endif - libname.replace(QStringLiteral("kwin"), QStringLiteral(KWIN_NAME)); - KLibrary* library = new KLibrary(libname); - if (!library) { - qCritical() << "couldn't open library for effect '" << - service->name() << "'" << endl; - return 0; - } - - return library; -} - void EffectsHandlerImpl::toggleEffect(const QString& name) { if (isEffectLoaded(name)) @@ -1425,189 +1317,15 @@ QStringList EffectsHandlerImpl::loadedEffects() const QStringList EffectsHandlerImpl::listOfEffects() const { - KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("KWin/Effect")); - QStringList listOfModules; - // First unload necessary effects - for (const KService::Ptr & service : offers) { - KPluginInfo plugininfo(service); - listOfModules << plugininfo.pluginName(); - } - return listOfModules; + return m_effectLoader->listOfKnownEffects(); } -KService::Ptr EffectsHandlerImpl::findEffectService(const QString &internalName) const -{ - QString constraint = QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(internalName); - KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("KWin/Effect"), constraint); - if (offers.isEmpty()) { - return KService::Ptr(); - } - return offers.first(); -} - -bool EffectsHandlerImpl::isScriptedEffect(KService::Ptr service) const -{ - return service->property(QStringLiteral("X-Plasma-API")).toString() == QStringLiteral("javascript"); -} - -bool EffectsHandlerImpl::loadEffect(const QString& name, bool checkDefault) +bool EffectsHandlerImpl::loadEffect(const QString& name) { makeOpenGLContextCurrent(); m_compositor->addRepaintFull(); - if (!name.startsWith(QLatin1String("kwin4_effect_"))) - qWarning() << "Effect names usually have kwin4_effect_ prefix" ; - - // Make sure a single effect won't be loaded multiple times - for (QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) { - if ((*it).first == name) { - qDebug() << "EffectsHandler::loadEffect : Effect already loaded : " << name; - return true; - } - } - - - qDebug() << "Trying to load " << name; - QString internalname = name.toLower(); - - KService::Ptr service = findEffectService(internalname); - if (!service) { - qCritical() << "Couldn't find effect " << name << endl; - return false; - } - - if (isScriptedEffect(service)) { - // this is a scripted effect - use different loader - return loadScriptedEffect(name, service.data()); - } - - if (Effect *e = loadBuiltInEffect(internalname.remove(QStringLiteral("kwin4_effect_")).toUtf8(), checkDefault)) { - effect_order.insert(e->requestedEffectChainPosition(), EffectPair(name, e)); - effectsChanged(); - return true; - } - - KLibrary* library = findEffectLibrary(service.data()); - if (!library) { - return false; - } - - QString version_symbol = QStringLiteral("effect_version_") + name; - KLibrary::void_function_ptr version_func = library->resolveFunction(version_symbol.toAscii().constData()); - if (version_func == NULL) { - qWarning() << "Effect " << name << " does not provide required API version, ignoring."; - delete library; - return false; - } - typedef int (*t_versionfunc)(); - int version = reinterpret_cast< t_versionfunc >(version_func)(); // call it - // Version must be the same or less, but major must be the same. - // With major 0 minor must match exactly. - if (version > KWIN_EFFECT_API_VERSION - || (version >> 8) != KWIN_EFFECT_API_VERSION_MAJOR - || (KWIN_EFFECT_API_VERSION_MAJOR == 0 && version != KWIN_EFFECT_API_VERSION)) { - qWarning() << "Effect " << name << " requires unsupported API version " << version; - delete library; - return false; - } - - const QString enabledByDefault_symbol = QStringLiteral("effect_enabledbydefault_") + name; - KLibrary::void_function_ptr enabledByDefault_func = library->resolveFunction(enabledByDefault_symbol.toAscii().data()); - - const QString supported_symbol = QStringLiteral("effect_supported_") + name; - KLibrary::void_function_ptr supported_func = library->resolveFunction(supported_symbol.toAscii().data()); - - const QString create_symbol = QStringLiteral("effect_create_") + name; - KLibrary::void_function_ptr create_func = library->resolveFunction(create_symbol.toAscii().data()); - - if (supported_func) { - typedef bool (*t_supportedfunc)(); - t_supportedfunc supported = reinterpret_cast(supported_func); - if (!supported()) { - qWarning() << "EffectsHandler::loadEffect : Effect " << name << " is not supported" ; - library->unload(); - return false; - } - } - - if (checkDefault && enabledByDefault_func) { - typedef bool (*t_enabledByDefaultfunc)(); - t_enabledByDefaultfunc enabledByDefault = reinterpret_cast(enabledByDefault_func); - - if (!enabledByDefault()) { - library->unload(); - return false; - } - } - - if (!create_func) { - qCritical() << "EffectsHandler::loadEffect : effect_create function not found" << endl; - library->unload(); - return false; - } - - typedef Effect*(*t_createfunc)(); - t_createfunc create = reinterpret_cast(create_func); - - // Make sure all depenedencies have been loaded - // TODO: detect circular deps - KPluginInfo plugininfo(service); - QStringList dependencies = plugininfo.dependencies(); - for (const QString & depName : dependencies) { - if (!loadEffect(depName)) { - qCritical() << "EffectsHandler::loadEffect : Couldn't load dependencies for effect " << name << endl; - library->unload(); - return false; - } - } - - Effect* e = create(); - - effect_order.insert(e->requestedEffectChainPosition(), EffectPair(name, e)); - effectsChanged(); - effect_libraries[ name ] = library; - - return true; -} - -Effect *EffectsHandlerImpl::loadBuiltInEffect(const QByteArray &name, bool checkDefault) -{ - if (!BuiltInEffects::available(name)) { - return nullptr; - } - if (!BuiltInEffects::supported(name)) { - qWarning() << "Effect " << name << " is not supported" ; - return nullptr; - } - if (checkDefault) { - if (!BuiltInEffects::checkEnabledByDefault(name)) { - return nullptr; - } - } - return BuiltInEffects::create(name); -} - -bool EffectsHandlerImpl::loadScriptedEffect(const QString& name, KService *service) -{ - const KDesktopFile df(QStandardPaths::GenericDataLocation, QStringLiteral("kde5/services/") + service->entryPath()); - const QString scriptName = df.desktopGroup().readEntry(QStringLiteral("X-Plasma-MainScript"), QString()); - if (scriptName.isEmpty()) { - qDebug() << "X-Plasma-MainScript not set"; - return false; - } - const QString scriptFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral(KWIN_NAME) + QStringLiteral("/effects/") + name + QStringLiteral("/contents/") + scriptName); - if (scriptFile.isNull()) { - qDebug() << "Could not locate the effect script"; - return false; - } - ScriptedEffect *effect = ScriptedEffect::create(name, scriptFile, service->property(QStringLiteral("X-KDE-Ordering")).toInt()); - if (!effect) { - qDebug() << "Could not initialize scripted effect: " << name; - return false; - } - effect_order.insert(effect->requestedEffectChainPosition(), EffectPair(name, effect)); - effectsChanged(); - return true; + return m_effectLoader->loadEffect(name); } void EffectsHandlerImpl::unloadEffect(const QString& name) @@ -1630,9 +1348,6 @@ void EffectsHandlerImpl::unloadEffect(const QString& name) delete it.value().second; effect_order.erase(it); effectsChanged(); - if (effect_libraries.contains(name)) { - effect_libraries[ name ]->unload(); - } return; } } @@ -1671,48 +1386,12 @@ bool EffectsHandlerImpl::isEffectSupported(const QString &name) return true; } - const QString internalName = name.toLower(); - KService::Ptr service = findEffectService(name.toLower()); - if (!service) { - // effect not found - return false; - } - - if (isScriptedEffect(service)) { - // scripted effects are generally supported - return true; - } - // next checks might require a context makeOpenGLContextCurrent(); m_compositor->addRepaintFull(); - // try builtin effects - const QByteArray builtInName = internalName.mid(13).toUtf8(); // drop kwin4_effect_ - if (BuiltInEffects::available(builtInName)) { - return BuiltInEffects::supported(builtInName); - } + return m_effectLoader->isEffectSupported(name); - // try remaining effects - KLibrary* library = findEffectLibrary(service.data()); - if (!library) { - return false; - } - - const QString supported_symbol = QStringLiteral("effect_supported_") + name; - KLibrary::void_function_ptr supported_func = library->resolveFunction(supported_symbol.toAscii().data()); - - bool supported = true; - - if (supported_func) { - typedef bool (*t_supportedfunc)(); - t_supportedfunc supportedFunction = reinterpret_cast(supported_func); - supported = supportedFunction(); - } - - library->unload(); - - return supported; } QList< bool > EffectsHandlerImpl::areEffectsSupported(const QStringList &names) @@ -1735,7 +1414,7 @@ void EffectsHandlerImpl::reloadEffect(Effect *effect) } if (!effectName.isNull()) { unloadEffect(effectName); - m_effectLoader->queue(effectName); + m_effectLoader->loadEffect(effectName); } } diff --git a/effects.h b/effects.h index 2bcc8bdfc..0c42fa44c 100644 --- a/effects.h +++ b/effects.h @@ -27,9 +27,7 @@ along with this program. If not, see . #include "scene.h" #include "xcbutils.h" -#include #include -#include #include #include @@ -221,7 +219,7 @@ public Q_SLOTS: // slots for D-Bus interface Q_SCRIPTABLE void reconfigureEffect(const QString& name); - Q_SCRIPTABLE bool loadEffect(const QString& name, bool checkDefault = false); + Q_SCRIPTABLE bool loadEffect(const QString& name); Q_SCRIPTABLE void toggleEffect(const QString& name); Q_SCRIPTABLE void unloadEffect(const QString& name); Q_SCRIPTABLE bool isEffectLoaded(const QString& name) const; @@ -243,8 +241,6 @@ protected Q_SLOTS: void slotPropertyNotify(KWin::Toplevel *t, long atom); protected: - bool loadScriptedEffect(const QString &name, KService *service); - KLibrary* findEffectLibrary(KService* service); void effectsChanged(); void setupClientConnections(KWin::Client *c); void setupUnmanagedConnections(KWin::Unmanaged *u); @@ -256,15 +252,9 @@ protected: QHash< long, int > registered_atoms; int next_window_quad_type; -private Q_SLOTS: - void slotEffectsQueried(); - private: - KService::Ptr findEffectService(const QString &internalName) const; - bool isScriptedEffect(KService::Ptr service) const; typedef QVector< Effect*> EffectsList; typedef EffectsList::const_iterator EffectsIterator; - Effect *loadBuiltInEffect(const QByteArray &name, bool checkDefault); EffectsList m_activeEffects; EffectsIterator m_currentDrawWindowIterator; EffectsIterator m_currentPaintWindowIterator; @@ -462,23 +452,6 @@ private: bool m_locked; }; -class EffectLoader : public QObject -{ - Q_OBJECT -public: - explicit EffectLoader(EffectsHandlerImpl *parent); - virtual ~EffectLoader(); - - void queue(const QString &effect, bool checkDefault = false); -private Q_SLOTS: - void dequeue(); -private: - void scheduleDequeue(); - EffectsHandlerImpl *m_effects; - QQueue> m_queue; - bool m_dequeueScheduled; -}; - inline QList EffectsHandlerImpl::elevatedWindows() const { diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h index fbdfe270c..1f978cd8b 100644 --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -47,7 +47,6 @@ along with this program. If not, see . #include #include -class KLibrary; class KConfigGroup; class QFont; class QGraphicsScale; @@ -1397,7 +1396,6 @@ Q_SIGNALS: protected: QVector< EffectPair > loaded_effects; - QHash< QString, KLibrary* > effect_libraries; //QHash< QString, EffectFactory* > effect_factories; CompositingType compositing_type; }; diff --git a/org.kde.kwin.Effects.xml b/org.kde.kwin.Effects.xml index c96aa84b5..ebb88984e 100644 --- a/org.kde.kwin.Effects.xml +++ b/org.kde.kwin.Effects.xml @@ -7,11 +7,6 @@ - - - - -