[kwin] Use KPluginTrader and json metadata to find KDecorations

* A KDecoration needs to include json metadata
* A KDecoration needs to be installed to kwin/kdecorations
* Aurorae and Oxygen adjusted
* kcmdeco locates all decorations through the KPluginTrader
* libkdecoration uses KPluginTrader to find the plugin
* config plugins also need to include json metadata with
  X-KDE-PluginInfo-Name being the same as the decoration
* config plugins need to get installed to kwin/kdecorations/config
* kcmdeco locates the config plugin for a deco through the name
  and KPluginTrader

REVIEW: 116765
This commit is contained in:
Martin Gräßlin 2014-03-12 14:53:43 +01:00
parent 5e5b1100b2
commit f74df28450
17 changed files with 81 additions and 80 deletions

View file

@ -22,7 +22,9 @@ target_link_libraries(kwin3_aurorae
kdecorations kdecorations
) )
install(TARGETS kwin3_aurorae DESTINATION ${PLUGIN_INSTALL_DIR} ) kservice_desktop_to_json(kwin3_aurorae aurorae.desktop)
install(TARGETS kwin3_aurorae DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/kdecorations )
set(decoration_plugin_SRCS set(decoration_plugin_SRCS
decorationplugin.cpp decorationplugin.cpp
@ -41,7 +43,6 @@ install(TARGETS decorationplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/kwin/dec
########### install files ############### ########### install files ###############
install( FILES aurorae.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin )
install( FILES aurorae.knsrc DESTINATION ${CONFIG_INSTALL_DIR} ) install( FILES aurorae.knsrc DESTINATION ${CONFIG_INSTALL_DIR} )
install( FILES install( FILES
qml/aurorae.qml qml/aurorae.qml

View file

@ -37,8 +37,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KPluginInfo> #include <KPluginInfo>
#include <KServiceTypeTrader> #include <KServiceTypeTrader>
K_PLUGIN_FACTORY(AuroraePluginFactory, K_PLUGIN_FACTORY_WITH_JSON(AuroraePluginFactory,
registerPlugin<Aurorae::AuroraeFactory>(QString(), &Aurorae::AuroraeFactory::createInstance);) "aurorae.json",
registerPlugin<Aurorae::AuroraeFactory>(QString(), &Aurorae::AuroraeFactory::createInstance);)
K_EXPORT_PLUGIN_VERSION(KWIN_DECORATION_API_VERSION) K_EXPORT_PLUGIN_VERSION(KWIN_DECORATION_API_VERSION)
namespace Aurorae namespace Aurorae

View file

@ -65,4 +65,4 @@ Name[wa]=Moteur di tinme di gåyotaedje Aurorae
Name[x-test]=xxAurorae Decoration Theme Enginexx Name[x-test]=xxAurorae Decoration Theme Enginexx
Name[zh_CN]=Aurorae Name[zh_CN]=Aurorae
Name[zh_TW]=Aurorae Name[zh_TW]=Aurorae
X-KDE-Library=kwin3_aurorae X-KDE-PluginInfo-Name=aurorae

View file

@ -30,11 +30,10 @@ target_link_libraries(kwin3_oxygen kdecorations)
target_link_libraries(kwin3_oxygen oxygenstyle) target_link_libraries(kwin3_oxygen oxygenstyle)
kservice_desktop_to_json(kwin3_oxygen oxygenclient.desktop)
if(X11_FOUND) if(X11_FOUND)
target_link_libraries(kwin3_oxygen XCB::XCB) target_link_libraries(kwin3_oxygen XCB::XCB)
endif() endif()
install(TARGETS kwin3_oxygen DESTINATION ${PLUGIN_INSTALL_DIR}) install(TARGETS kwin3_oxygen DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/kdecorations)
########### install files ###############
install(FILES oxygenclient.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin/)

View file

@ -34,4 +34,4 @@ if(X11_FOUND)
target_link_libraries(kwin_oxygen_config Qt5::X11Extras) target_link_libraries(kwin_oxygen_config Qt5::X11Extras)
endif() endif()
install(TARGETS kwin_oxygen_config DESTINATION ${QT_PLUGIN_INSTALL_DIR}/kf5) install(TARGETS kwin_oxygen_config DESTINATION ${QT_PLUGIN_INSTALL_DIR}/kf5/kwin/kdecorations/config)

View file

@ -0,0 +1,3 @@
{
"X-KDE-PluginInfo-Name": "Oxygen"
}

View file

@ -44,7 +44,9 @@
//_______________________________________________________________________ //_______________________________________________________________________
K_PLUGIN_FACTORY(OxygenConfigPlugin, registerPlugin<Oxygen::Config>(QString(), &Oxygen::Config::create); ) K_PLUGIN_FACTORY_WITH_JSON(OxygenConfigPlugin,
"config.json",
registerPlugin<Oxygen::Config>(QString(), &Oxygen::Config::create); )
namespace Oxygen namespace Oxygen
{ {

View file

@ -169,8 +169,6 @@ Comment[x-test]=xxStyling of the next generation desktopxx
Comment[zh_CN]= Comment[zh_CN]=
Comment[zh_TW]= Comment[zh_TW]=
X-KDE-Library=kwin3_oxygen
X-KDE-PluginInfo-Author=Nuno Pinheiro, Casper Boemann, Riccardo Iaconelli, Huynh Huu Long, Thomas Luebking, Hugo Pereira Da Costa, Matthew Woehlke X-KDE-PluginInfo-Author=Nuno Pinheiro, Casper Boemann, Riccardo Iaconelli, Huynh Huu Long, Thomas Luebking, Hugo Pereira Da Costa, Matthew Woehlke
X-KDE-PluginInfo-Email=nuno@oxygen-icons.org, cbr@boemann.dk, riccardo@kde.org, long.upcase@googlemail.com, thomas.luebking@web.de, hugo.pereira@free.fr, mw_triad@users.sourceforge.net X-KDE-PluginInfo-Email=nuno@oxygen-icons.org, cbr@boemann.dk, riccardo@kde.org, long.upcase@googlemail.com, thomas.luebking@web.de, hugo.pereira@free.fr, mw_triad@users.sourceforge.net
X-KDE-PluginInfo-Name=Oxygen X-KDE-PluginInfo-Name=Oxygen

View file

@ -33,7 +33,7 @@
#include <KWindowInfo> #include <KWindowInfo>
#include <kdeversion.h> #include <kdeversion.h>
KWIN_DECORATION(OxygenPluginFactory, Oxygen::Factory) KWIN_DECORATION(OxygenPluginFactory, "oxygenclient.json", Oxygen::Factory)
namespace Oxygen namespace Oxygen
{ {

View file

@ -39,9 +39,9 @@ DecorationPlugin::DecorationPlugin(QObject *parent)
, KDecorationPlugins(KSharedConfig::openConfig()) , KDecorationPlugins(KSharedConfig::openConfig())
, m_disabled(false) , m_disabled(false)
{ {
defaultPlugin = QStringLiteral("kwin3_oxygen"); defaultPlugin = QStringLiteral("Oxygen");
#ifndef KWIN_BUILD_OXYGEN #ifndef KWIN_BUILD_OXYGEN
defaultPlugin = QStringLiteral("kwin3_aurorae"); defaultPlugin = QStringLiteral("aurorae");
#endif #endif
#ifdef KWIN_BUILD_DECORATIONS #ifdef KWIN_BUILD_DECORATIONS
loadPlugin(QString()); // load the plugin specified in cfg file loadPlugin(QString()); // load the plugin specified in cfg file

View file

@ -25,8 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KSharedConfig> #include <KSharedConfig>
#include <KLocalizedString> #include <KLocalizedString>
#include <KConfigGroup> #include <KConfigGroup>
#include <KPluginFactory> #include <KPluginTrader>
#include <KPluginLoader>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QPushButton> #include <QPushButton>
@ -89,25 +88,24 @@ KWinDecorationConfigDialog::KWinDecorationConfigDialog(QString deco, const QList
connect(m_buttons, SIGNAL(accepted()), SLOT(accept())); connect(m_buttons, SIGNAL(accepted()), SLOT(accept()));
connect(m_buttons, SIGNAL(rejected()), SLOT(reject())); connect(m_buttons, SIGNAL(rejected()), SLOT(reject()));
KPluginLoader loader(styleToConfigLib(deco)); m_pluginConfigWidget = new QWidget(this);
KPluginFactory *factory = loader.factory(); m_pluginConfigWidget->setLayout(new QVBoxLayout);
if (factory) { m_pluginObject = KPluginTrader::self()->createInstanceFromQuery<QObject>(QStringLiteral("kf5/kwin/kdecorations/config"),
m_pluginConfigWidget = new QWidget(this); QString(),
m_pluginConfigWidget->setLayout(new QVBoxLayout); QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(deco),
m_pluginObject = factory->create<QObject>(m_pluginConfigWidget, m_pluginConfigWidget, QString(), m_pluginConfigWidget,
QVariantList() << QStringLiteral("kwinrc") << QStringLiteral("Style")); m_pluginConfigWidget,
QVariantList() << QStringLiteral("kwinrc") << QStringLiteral("Style"));
if (m_pluginObject) {
// connect required signals and slots together... // connect required signals and slots together...
connect(this, SIGNAL(accepted()), this, SLOT(slotAccepted())); connect(this, SIGNAL(accepted()), this, SLOT(slotAccepted()));
connect(m_pluginObject, SIGNAL(changed()), this, SLOT(slotSelectionChanged())); connect(m_pluginObject, SIGNAL(changed()), this, SLOT(slotSelectionChanged()));
connect(this, SIGNAL(pluginSave(KConfigGroup&)), m_pluginObject, SLOT(save(KConfigGroup&))); connect(this, SIGNAL(pluginSave(KConfigGroup&)), m_pluginObject, SLOT(save(KConfigGroup&)));
connect(m_buttons->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), m_pluginObject, SLOT(defaults())); connect(m_buttons->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), m_pluginObject, SLOT(defaults()));
connect(m_buttons->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), SLOT(slotDefault())); connect(m_buttons->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), SLOT(slotDefault()));
}
if (m_pluginConfigWidget) {
layout->addWidget(m_pluginConfigWidget); layout->addWidget(m_pluginConfigWidget);
} }
layout->addWidget(m_buttons); layout->addWidget(m_buttons);
if (borderSizes.count() >= 2) { if (borderSizes.count() >= 2) {
@ -160,14 +158,6 @@ void KWinDecorationConfigDialog::slotSelectionChanged()
m_buttons->button(QDialogButtonBox::Reset)->setEnabled(true); m_buttons->button(QDialogButtonBox::Reset)->setEnabled(true);
} }
QString KWinDecorationConfigDialog::styleToConfigLib(const QString& styleLib) const
{
if (styleLib.startsWith(QLatin1String("kwin3_")))
return "kwin_" + styleLib.mid(6) + "_config";
else
return styleLib + "_config";
}
void KWinDecorationConfigDialog::slotDefault() void KWinDecorationConfigDialog::slotDefault()
{ {
if (m_borderSizes.count() >= 2) if (m_borderSizes.count() >= 2)

View file

@ -70,7 +70,6 @@ private Q_SLOTS:
private: private:
int borderSizeToIndex(KDecorationDefines::BorderSize size, const QList<QVariant>& sizes); int borderSizeToIndex(KDecorationDefines::BorderSize size, const QList<QVariant>& sizes);
QString styleToConfigLib(const QString& styleLib) const;
private: private:
KWinDecorationConfigForm* m_ui; KWinDecorationConfigForm* m_ui;

View file

@ -33,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KDE/KLocalizedString> #include <KDE/KLocalizedString>
#include <KServiceTypeTrader> #include <KServiceTypeTrader>
#include <KPluginInfo> #include <KPluginInfo>
#include <KPluginTrader>
#include "kwindecoration.h" #include "kwindecoration.h"
/* WARNING ------------------------------------------------------------------------- /* WARNING -------------------------------------------------------------------------
@ -47,6 +48,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* (which is invoked on deco deconstruction) * (which is invoked on deco deconstruction)
* WARNING ------------------------------------------------------------------------ */ * WARNING ------------------------------------------------------------------------ */
static const QString s_auroraePluginName = QStringLiteral("aurorae");
namespace KWin namespace KWin
{ {
@ -87,41 +90,33 @@ void DecorationModel::reload()
void DecorationModel::findDecorations() void DecorationModel::findDecorations()
{ {
beginResetModel(); beginResetModel();
const QStringList dirList = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kwin", QStandardPaths::LocateDirectory); const auto decorations = KPluginTrader::self()->query(QStringLiteral("kf5/kwin/kdecorations"));
for (const KPluginInfo &plugin : decorations) {
foreach (const QString & dir, dirList) { if (plugin.pluginName() == s_auroraePluginName) {
QDir d(dir); // read the Aurorae themes
if (d.exists()) { findAuroraeThemes();
foreach (const QFileInfo & fi, d.entryInfoList()) { continue;
const QString filename(fi.absoluteFilePath());
if (KDesktopFile::isDesktopFile(filename)) {
const KDesktopFile desktopFile(filename);
const QString libName = desktopFile.desktopGroup().readEntry("X-KDE-Library");
if (!libName.isEmpty() && libName.startsWith(QLatin1String("kwin3_"))) {
if (libName == "kwin3_aurorae") {
// read the Aurorae themes
findAuroraeThemes();
continue;
}
DecorationModelData data;
data.name = desktopFile.readName();
data.libraryName = libName;
data.type = DecorationModelData::NativeDecoration;
data.borderSize = KDecorationDefines::BorderNormal;
data.closeDblClick = false;
metaData(data, desktopFile);
m_decorations.append(data);
}
}
}
} }
DecorationModelData data;
data.name = plugin.name();
data.pluginName = plugin.pluginName();
data.type = DecorationModelData::NativeDecoration;
data.borderSize = KDecorationDefines::BorderNormal;
data.closeDblClick = false;
data.comment = plugin.comment();
data.author = plugin.author();
data.email = plugin.email();
data.version = plugin.version();
data.license = plugin.license();
data.website = plugin.website();
m_decorations.append(data);
} }
KService::List offers = KServiceTypeTrader::self()->query("KWin/Decoration"); KService::List offers = KServiceTypeTrader::self()->query("KWin/Decoration");
foreach (KService::Ptr service, offers) { foreach (KService::Ptr service, offers) {
DecorationModelData data; DecorationModelData data;
data.name = service->name(); data.name = service->name();
data.libraryName = "kwin3_aurorae"; data.pluginName = s_auroraePluginName;
data.type = DecorationModelData::QmlDecoration; data.type = DecorationModelData::QmlDecoration;
data.auroraeName = service->property("X-KDE-PluginInfo-Name").toString(); data.auroraeName = service->property("X-KDE-PluginInfo-Name").toString();
QString scriptName = service->property("X-Plasma-MainScript").toString(); QString scriptName = service->property("X-Plasma-MainScript").toString();
@ -178,7 +173,7 @@ void DecorationModel::findAuroraeThemes()
DecorationModelData data; DecorationModelData data;
data.name = name; data.name = name;
data.libraryName = "kwin3_aurorae"; data.pluginName = s_auroraePluginName;
data.type = DecorationModelData::AuroraeDecoration; data.type = DecorationModelData::AuroraeDecoration;
data.auroraeName = packageName; data.auroraeName = packageName;
KConfigGroup config(m_config, data.auroraeName); KConfigGroup config(m_config, data.auroraeName);
@ -216,7 +211,7 @@ QVariant DecorationModel::data(const QModelIndex& index, int role) const
case NameRole: case NameRole:
return m_decorations[ index.row()].name; return m_decorations[ index.row()].name;
case LibraryNameRole: case LibraryNameRole:
return m_decorations[ index.row()].libraryName; return m_decorations[ index.row()].pluginName;
case TypeRole: case TypeRole:
return m_decorations[ index.row()].type; return m_decorations[ index.row()].type;
case AuroraeNameRole: case AuroraeNameRole:
@ -238,7 +233,7 @@ QVariant DecorationModel::data(const QModelIndex& index, int role) const
case BorderSizesRole: { case BorderSizesRole: {
QList< QVariant > sizes; QList< QVariant > sizes;
const bool mustDisablePreview = m_plugins->factory() && m_plugins->factory() == m_preview->factory(); const bool mustDisablePreview = m_plugins->factory() && m_plugins->factory() == m_preview->factory();
if (m_plugins->loadPlugin(m_decorations[index.row()].libraryName) && m_plugins->factory()) { if (m_plugins->loadPlugin(m_decorations[index.row()].pluginName) && m_plugins->factory()) {
foreach (KDecorationDefines::BorderSize size, m_plugins->factory()->borderSizes()) // krazy:exclude=foreach foreach (KDecorationDefines::BorderSize size, m_plugins->factory()->borderSizes()) // krazy:exclude=foreach
sizes << int(size); sizes << int(size);
if (mustDisablePreview) // it's nuked with destroyPreviousPlugin() if (mustDisablePreview) // it's nuked with destroyPreviousPlugin()
@ -321,7 +316,7 @@ void DecorationModel::setButtons(bool custom, const QList<KDecorationDefines::De
QModelIndex DecorationModel::indexOfLibrary(const QString& libraryName) const QModelIndex DecorationModel::indexOfLibrary(const QString& libraryName) const
{ {
for (int i = 0; i < m_decorations.count(); i++) { for (int i = 0; i < m_decorations.count(); i++) {
if (m_decorations.at(i).libraryName.compare(libraryName) == 0) if (m_decorations.at(i).pluginName.compare(libraryName) == 0)
return index(i); return index(i);
} }
return QModelIndex(); return QModelIndex();

View file

@ -45,7 +45,7 @@ public:
QmlDecoration = 2 QmlDecoration = 2
}; };
QString name; QString name;
QString libraryName; QString pluginName;
DecorationType type; DecorationType type;
QString comment; QString comment;
QString author; QString author;

View file

@ -62,6 +62,8 @@ K_PLUGIN_FACTORY(KWinDecoFactory,
namespace KWin namespace KWin
{ {
static const QString s_defaultPluginName = QStringLiteral("Oxygen");
KWinDecorationForm::KWinDecorationForm(QWidget* parent) KWinDecorationForm::KWinDecorationForm(QWidget* parent)
: QWidget(parent) : QWidget(parent)
{ {
@ -183,18 +185,18 @@ void KWinDecorationModule::readConfig(const KConfigGroup & conf)
// Find the corresponding decoration name to that of // Find the corresponding decoration name to that of
// the current plugin library name // the current plugin library name
QString libraryName = conf.readEntry("PluginLib", "kwin3_oxygen"); QString libraryName = conf.readEntry("PluginLib", s_defaultPluginName);
if (libraryName.isEmpty()) { if (libraryName.isEmpty()) {
// Selected decoration doesn't exist, use the default // Selected decoration doesn't exist, use the default
libraryName = "kwin3_oxygen"; libraryName = s_defaultPluginName;
} }
const int bsize = conf.readEntry("BorderSize", (int)BorderNormal); const int bsize = conf.readEntry("BorderSize", (int)BorderNormal);
BorderSize borderSize = BorderNormal; BorderSize borderSize = BorderNormal;
if (bsize >= BorderTiny && bsize < BordersCount) if (bsize >= BorderTiny && bsize < BordersCount)
borderSize = static_cast< BorderSize >(bsize); borderSize = static_cast< BorderSize >(bsize);
if (libraryName == "kwin3_aurorae") { if (libraryName == "aurorae") {
KConfig auroraeConfig("auroraerc"); KConfig auroraeConfig("auroraerc");
KConfigGroup group(&auroraeConfig, "Engine"); KConfigGroup group(&auroraeConfig, "Engine");
const QString themeName = group.readEntry("ThemeName", "example-deco"); const QString themeName = group.readEntry("ThemeName", "example-deco");

View file

@ -43,13 +43,17 @@ DEALINGS IN THE SOFTWARE.
* The KPluginFactory sub class returns a new instance of the specified KDecorationFactory. * 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 pluginfactoryname The name to be used for the KPluginFactory, passed to K_PLUGIN_FACTORY
* @param jsonFile Name of the json file to be compiled into the decoration plugin as metadata
* @param classname The class name of the KDecorationFactory subclass * @param classname The class name of the KDecorationFactory subclass
* *
* Example: * Example:
* @code * @code
* KWIN_DECORATION(MyDecoPluginFactory, MyDeco::Factory) * KWIN_DECORATION(MyDecoPluginFactory, "mydeco.json", MyDeco::Factory)
* @endcode * @endcode
* *
* Please refer to the documentation of K_PLUGIN_FACTORY_WITH_JSON in KF5::Service for how to
* create and use the json file.
*
* In case the decoration plugin wants to have more control over the created factory (e.g. a singleton) * 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 * 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 * case it is also required to add
@ -59,9 +63,9 @@ DEALINGS IN THE SOFTWARE.
* *
* to add the correct plugin version. This is also handled by this macro in the default case. * to add the correct plugin version. This is also handled by this macro in the default case.
**/ **/
#define KWIN_DECORATION( pluginfactoryname, classname ) \ #define KWIN_DECORATION( pluginfactoryname, json, classname ) \
QObject *createDecorationFactory(QWidget *, QObject *, const QList<QVariant> &) { return new classname(); } \ QObject *createDecorationFactory(QWidget *, QObject *, const QList<QVariant> &) { return new classname(); } \
K_PLUGIN_FACTORY(pluginfactoryname, registerPlugin<classname>(QString(), &createDecorationFactory);) \ K_PLUGIN_FACTORY_WITH_JSON(pluginfactoryname, json, registerPlugin<classname>(QString(), &createDecorationFactory);) \
K_EXPORT_PLUGIN_VERSION(KWIN_DECORATION_API_VERSION) K_EXPORT_PLUGIN_VERSION(KWIN_DECORATION_API_VERSION)
#define KWIN_DECORATION_BRIDGE_API_VERSION 1 #define KWIN_DECORATION_BRIDGE_API_VERSION 1

View file

@ -31,6 +31,7 @@ DEALINGS IN THE SOFTWARE.
#include <klibrary.h> #include <klibrary.h>
#include <KPluginFactory> #include <KPluginFactory>
#include <KPluginLoader> #include <KPluginLoader>
#include <KPluginTrader>
#include <kconfiggroup.h> #include <kconfiggroup.h>
#include <KDE/KLocalizedString> #include <KDE/KLocalizedString>
#include <assert.h> #include <assert.h>
@ -44,7 +45,7 @@ DEALINGS IN THE SOFTWARE.
KDecorationPlugins::KDecorationPlugins(const KSharedConfigPtr &cfg) KDecorationPlugins::KDecorationPlugins(const KSharedConfigPtr &cfg)
: fact(nullptr), : fact(nullptr),
old_fact(nullptr), old_fact(nullptr),
pluginStr(QStringLiteral("kwin3_undefined ")), pluginStr(QStringLiteral("undefined ")),
config(cfg) config(cfg)
{ {
} }
@ -105,7 +106,13 @@ bool KDecorationPlugins::loadPlugin(QString nameStr)
auto createFactory = [](const QString &pluginName) -> KDecorationFactory* { auto createFactory = [](const QString &pluginName) -> KDecorationFactory* {
qDebug() << "Trying to load decoration plugin" << pluginName; qDebug() << "Trying to load decoration plugin" << pluginName;
KPluginLoader loader(pluginName); const QString query = QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(pluginName);
const auto offers = KPluginTrader::self()->query(QStringLiteral("kf5/kwin/kdecorations"), QString(), query);
if (offers.isEmpty()) {
qDebug() << "Decoration plugin not found";
return nullptr;
}
KPluginLoader loader(offers.first().libraryPath());
if (loader.pluginVersion() != KWIN_DECORATION_API_VERSION) { if (loader.pluginVersion() != KWIN_DECORATION_API_VERSION) {
qWarning() << i18n("The library %1 has wrong API version %2", loader.pluginName(), loader.pluginVersion()); qWarning() << i18n("The library %1 has wrong API version %2", loader.pluginName(), loader.pluginVersion());
return nullptr; return nullptr;