diff --git a/clients/aurorae/src/aurorae.cpp b/clients/aurorae/src/aurorae.cpp index 1c31b41889..9601f38d04 100644 --- a/clients/aurorae/src/aurorae.cpp +++ b/clients/aurorae/src/aurorae.cpp @@ -37,6 +37,10 @@ along with this program. If not, see . #include #include +K_PLUGIN_FACTORY(AuroraePluginFactory, + registerPlugin(QString(), &Aurorae::AuroraeFactory::createInstance);) +K_EXPORT_PLUGIN_VERSION(KWIN_DECORATION_API_VERSION) + namespace Aurorae { @@ -158,6 +162,11 @@ AuroraeFactory *AuroraeFactory::instance() return s_instance; } +QObject *AuroraeFactory::createInstance(QWidget*, QObject*, const QList< QVariant >&) +{ + return instance(); +} + void AuroraeFactory::updateConfiguration() { const KConfig conf(QStringLiteral("auroraerc")); @@ -562,15 +571,4 @@ void AuroraeClient::render(QPaintDevice *device, const QRegion &sourceRegion) } // namespace Aurorae -extern "C" -{ - KDECORATIONS_EXPORT KDecorationFactory *create_factory() { - return Aurorae::AuroraeFactory::instance(); - } - KDECORATIONS_EXPORT int decoration_version() { - return KWIN_DECORATION_API_VERSION; - } -} - - #include "aurorae.moc" diff --git a/clients/aurorae/src/aurorae.h b/clients/aurorae/src/aurorae.h index 1d105bd6b7..a85467a062 100644 --- a/clients/aurorae/src/aurorae.h +++ b/clients/aurorae/src/aurorae.h @@ -44,6 +44,7 @@ public: ~AuroraeFactory(); static AuroraeFactory* instance(); + static QObject *createInstance(QWidget *, QObject *, const QList &); KDecoration *createDecoration(KDecorationBridge*); bool supports(Ability ability) const; virtual QList< BorderSize > borderSizes() const; diff --git a/clients/oxygen/CMakeLists.txt b/clients/oxygen/CMakeLists.txt index bb5484aef9..9e6dcdfe1a 100644 --- a/clients/oxygen/CMakeLists.txt +++ b/clients/oxygen/CMakeLists.txt @@ -24,7 +24,7 @@ kconfig_add_kcfg_files(kwin_oxygen_SRCS oxygenconfiguration.kcfgc ) add_library(kwin3_oxygen MODULE ${kwin_oxygen_SRCS}) target_link_libraries(kwin3_oxygen Qt5::Widgets ) -target_link_libraries(kwin3_oxygen KF5::I18n KF5::WindowSystem KF5::Style) +target_link_libraries(kwin3_oxygen KF5::I18n KF5::WindowSystem KF5::Style KF5::Service) target_link_libraries(kwin3_oxygen kdecorations) diff --git a/clients/oxygen/oxygenfactory.cpp b/clients/oxygen/oxygenfactory.cpp index 2f44a6a16d..19559dbeda 100644 --- a/clients/oxygen/oxygenfactory.cpp +++ b/clients/oxygen/oxygenfactory.cpp @@ -25,7 +25,6 @@ ////////////////////////////////////////////////////////////////////////////// #include "oxygenfactory.h" -#include "oxygenfactory.moc" #include "oxygenclient.h" #include "oxygenexceptionlist.h" @@ -34,7 +33,7 @@ #include #include -KWIN_DECORATION(Oxygen::Factory) +KWIN_DECORATION(OxygenPluginFactory, Oxygen::Factory) namespace Oxygen { @@ -202,3 +201,5 @@ namespace Oxygen } } + +#include "oxygenfactory.moc" diff --git a/kcmkwin/kwindecoration/decorationmodel.cpp b/kcmkwin/kwindecoration/decorationmodel.cpp index 351e47013b..9e8b1365a6 100644 --- a/kcmkwin/kwindecoration/decorationmodel.cpp +++ b/kcmkwin/kwindecoration/decorationmodel.cpp @@ -104,8 +104,6 @@ void DecorationModel::findDecorations() findAuroraeThemes(); continue; } - if (!m_plugins->canLoad(libName)) - continue; DecorationModelData data; data.name = desktopFile.readName(); data.libraryName = libName; diff --git a/libkdecorations/kdecoration.h b/libkdecorations/kdecoration.h index 99ece35033..d7118cd762 100644 --- a/libkdecorations/kdecoration.h +++ b/libkdecorations/kdecoration.h @@ -33,19 +33,36 @@ DEALINGS IN THE SOFTWARE. #include #include #include +#include #define KWIN_DECORATION_API_VERSION 1 /** - * Defines the class to be used for decoration factory. - * The class must be namespace complete. - * E.g. KWIN_EFFECT( Oxygen::Factory ) + * Defines the KDecorationFactory implementation provided by the + * decoration plugin and defines a KPluginFactory sub class. + * The KPluginFactory sub class returns a new instance of the specified KDecorationFactory. + * + * @param pluginfactoryname The name to be used for the KPluginFactory, passed to K_PLUGIN_FACTORY + * @param classname The class name of the KDecorationFactory subclass + * + * Example: + * @code + * KWIN_DECORATION(MyDecoPluginFactory, MyDeco::Factory) + * @endcode + * + * In case the decoration plugin wants to have more control over the created factory (e.g. a singleton) + * it is recommended to not use this convenience macro, but specify an own K_PLUGIN_FACTORY. In that + * case it is also required to add + * @code + * K_EXPORT_PLUGIN_VERSION(KWIN_DECORATION_API_VERSION) + * @endcode + * + * to add the correct plugin version. This is also handled by this macro in the default case. **/ -#define KWIN_DECORATION( classname ) \ - extern "C" { \ - KDECORATIONS_EXPORT KDecorationFactory* create_factory() { return new classname(); } \ - KDECORATIONS_EXPORT int decoration_version() { return KWIN_DECORATION_API_VERSION; } \ - } +#define KWIN_DECORATION( pluginfactoryname, classname ) \ + QObject *createDecorationFactory(QWidget *, QObject *, const QList &) { return new classname(); } \ + K_PLUGIN_FACTORY(pluginfactoryname, registerPlugin(QString(), &createDecorationFactory);) \ + K_EXPORT_PLUGIN_VERSION(KWIN_DECORATION_API_VERSION) #define KWIN_DECORATION_BRIDGE_API_VERSION 1 extern "C" { diff --git a/libkdecorations/kdecoration_plugins_p.cpp b/libkdecorations/kdecoration_plugins_p.cpp index 325dae9a5b..03b8595751 100644 --- a/libkdecorations/kdecoration_plugins_p.cpp +++ b/libkdecorations/kdecoration_plugins_p.cpp @@ -29,6 +29,8 @@ DEALINGS IN THE SOFTWARE. #include #include #include +#include +#include #include #include #include @@ -40,10 +42,7 @@ DEALINGS IN THE SOFTWARE. #include "kdecorationfactory.h" KDecorationPlugins::KDecorationPlugins(const KSharedConfigPtr &cfg) - : create_ptr(nullptr), - library(nullptr), - fact(nullptr), - old_library(nullptr), + : fact(nullptr), old_fact(nullptr), pluginStr(QStringLiteral("kwin3_undefined ")), config(cfg) @@ -52,16 +51,8 @@ KDecorationPlugins::KDecorationPlugins(const KSharedConfigPtr &cfg) KDecorationPlugins::~KDecorationPlugins() { - if (library) { - assert(fact != nullptr); - delete fact; - library->unload(); - } - if (old_library) { - assert(old_fact != nullptr); - delete old_fact; - old_library->unload(); - } + delete fact; + delete old_fact; } QString KDecorationPlugins::currentPlugin() @@ -95,90 +86,6 @@ KDecoration* KDecorationPlugins::createDecoration(KDecorationBridge* bridge) return nullptr; } -// tests whether the plugin can be loaded -bool KDecorationPlugins::canLoad(QString nameStr, KLibrary **loadedLib) -{ - if (nameStr.isEmpty()) - return false; // we can't load that - - // Check if this library is not already loaded. - if (pluginStr == nameStr) { - if (loadedLib) { - *loadedLib = library; - } - return true; - } - - KConfigGroup group(config, QStringLiteral("Style")); - if (group.readEntry("NoPlugin", false)) { - error(i18n("Loading of window decoration plugin library disabled in configuration.")); - return false; - } - - KLibrary libToFind(nameStr); - QString path = libToFind.fileName(); - qDebug() << "kwin : path " << path << " for " << nameStr; - - if (path.isEmpty()) { - return false; - } - - // Try loading the requested plugin - KLibrary *lib = new KLibrary(path); - - if (!lib) - return false; - - // TODO this would be a nice shortcut, but for "some" reason QtCurve with wrong ABI slips through - // TODO figure where it's loaded w/o being unloaded and check whether that can be fixed. -#if 0 - if (lib->isLoaded()) { - if (loadedLib) { - *loadedLib = lib; - } - return true; - } -#endif - // so we check whether this lib was loaded before and don't unload it in case - bool wasLoaded = lib->isLoaded(); - - KDecorationFactory*(*cptr)() = nullptr; - int (*vptr)() = nullptr; - int deco_version = 0; - KLibrary::void_function_ptr version_func = lib->resolveFunction("decoration_version"); - if (version_func) { - vptr = (int(*)())version_func; - deco_version = vptr(); - } - if (deco_version != KWIN_DECORATION_API_VERSION) { - if (version_func) - qWarning() << i18n("The library %1 has wrong API version %2", path, deco_version); - lib->unload(); - delete lib; - return false; - } - - KLibrary::void_function_ptr create_func = lib->resolveFunction("create_factory"); - if (create_func) - cptr = (KDecorationFactory * (*)())create_func; - - if (!cptr) { - qDebug() << i18n("The library %1 is not a KWin plugin.", path); - lib->unload(); - delete lib; - return false; - } - - if (loadedLib) { - *loadedLib = lib; - } else { - if (!wasLoaded) - lib->unload(); - delete lib; - } - return true; -} - // returns true if plugin was loaded successfully bool KDecorationPlugins::loadPlugin(QString nameStr) { @@ -191,30 +98,31 @@ bool KDecorationPlugins::loadPlugin(QString nameStr) if (pluginStr == nameStr) return true; - KLibrary *oldLibrary = library; - KDecorationFactory* oldFactory = fact; - - if (!canLoad(nameStr, &library)) { - // If that fails, fall back to the default plugin - nameStr = defaultPlugin; - if (!canLoad(nameStr, &library)) { - // big time trouble! - // -> exit kwin with an error message - error(i18n("The default decoration plugin is corrupt and could not be loaded.")); - return false; - } + if (group.readEntry("NoPlugin", false)) { + error(i18n("Loading of window decoration plugin library disabled in configuration.")); + return false; } - // guarded by "canLoad" - KLibrary::void_function_ptr create_func = library->resolveFunction("create_factory"); - if (create_func) - create_ptr = (KDecorationFactory * (*)())create_func; - if (!create_ptr) { // this means someone probably attempted to load "some" kwin plugin/lib as deco - // and thus cheated on the "isLoaded" shortcut -> try the default and yell a warning - if (nameStr != defaultPlugin) { - qWarning() << i18n("The library %1 was attempted to be loaded as a decoration plugin but it is NOT", nameStr); - return loadPlugin(defaultPlugin); + auto createFactory = [](const QString &pluginName) -> KDecorationFactory* { + qDebug() << "Trying to load decoration plugin" << pluginName; + KPluginLoader loader(pluginName); + if (loader.pluginVersion() != KWIN_DECORATION_API_VERSION) { + qWarning() << i18n("The library %1 has wrong API version %2", loader.pluginName(), loader.pluginVersion()); + return nullptr; + } + KPluginFactory *factory = loader.factory(); + if (!factory) { + qWarning() << "Error loading decoration library: " << loader.errorString(); + return nullptr; } else { + return factory->create(); + } + }; + KDecorationFactory *factory = createFactory(nameStr); + if (!factory) { + // If that fails, fall back to the default plugin + factory = createFactory(defaultPlugin); + if (!factory) { // big time trouble! // -> exit kwin with an error message error(i18n("The default decoration plugin is corrupt and could not be loaded.")); @@ -222,8 +130,7 @@ bool KDecorationPlugins::loadPlugin(QString nameStr) } } - fact = create_ptr(); - fact->checkRequirements(this); // let it check what is supported + factory->checkRequirements(this); // let it check what is supported pluginStr = nameStr; @@ -241,8 +148,8 @@ bool KDecorationPlugins::loadPlugin(QString nameStr) KGlobal::locale()->insertCatalog("kwin_art_clients"); #endif - old_library = oldLibrary; // save for delayed destroying - old_fact = oldFactory; + old_fact = fact; + fact = factory; return true; } @@ -250,13 +157,8 @@ bool KDecorationPlugins::loadPlugin(QString nameStr) void KDecorationPlugins::destroyPreviousPlugin() { // Destroy the old plugin - if (old_library) { - delete old_fact; - old_fact = nullptr; - old_library->unload(); - delete old_library; - old_library = nullptr; - } + delete old_fact; + old_fact = nullptr; } void KDecorationPlugins::error(const QString&) diff --git a/libkdecorations/kdecoration_plugins_p.h b/libkdecorations/kdecoration_plugins_p.h index bf36fc4860..8d737ad1fd 100644 --- a/libkdecorations/kdecoration_plugins_p.h +++ b/libkdecorations/kdecoration_plugins_p.h @@ -38,7 +38,6 @@ DEALINGS IN THE SOFTWARE. #include "kdecoration.h" #include -class KLibrary; class KDecoration; class KDecorationBridge; class KDecorationFactory; @@ -49,10 +48,6 @@ class KDECORATIONS_EXPORT KDecorationPlugins public: explicit KDecorationPlugins(const KSharedConfigPtr &cfg); virtual ~KDecorationPlugins(); - /** Whether the plugin with @p name can be loaded - * if @p loadedLib is passed, the library is NOT unloaded and freed - * what is now your resposibility (intended for and used by below loadPlugin mainly) */ - bool canLoad(QString name, KLibrary ** loadedLib = 0); bool loadPlugin(QString name); void destroyPreviousPlugin(); KDecorationFactory* factory(); @@ -64,10 +59,7 @@ protected: virtual void error(const QString& error_msg); QString defaultPlugin; // FRAME normalne protected? private: - KDecorationFactory*(*create_ptr)(); - KLibrary *library; KDecorationFactory* fact; - KLibrary *old_library; KDecorationFactory* old_fact; QString pluginStr; KSharedConfigPtr config;