[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
icc-effect-5.14.5
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
)
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
decorationplugin.cpp
@ -41,7 +43,6 @@ install(TARGETS decorationplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/kwin/dec
########### install files ###############
install( FILES aurorae.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin )
install( FILES aurorae.knsrc DESTINATION ${CONFIG_INSTALL_DIR} )
install( FILES
qml/aurorae.qml

View File

@ -37,8 +37,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KPluginInfo>
#include <KServiceTypeTrader>
K_PLUGIN_FACTORY(AuroraePluginFactory,
registerPlugin<Aurorae::AuroraeFactory>(QString(), &Aurorae::AuroraeFactory::createInstance);)
K_PLUGIN_FACTORY_WITH_JSON(AuroraePluginFactory,
"aurorae.json",
registerPlugin<Aurorae::AuroraeFactory>(QString(), &Aurorae::AuroraeFactory::createInstance);)
K_EXPORT_PLUGIN_VERSION(KWIN_DECORATION_API_VERSION)
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[zh_CN]=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)
kservice_desktop_to_json(kwin3_oxygen oxygenclient.desktop)
if(X11_FOUND)
target_link_libraries(kwin3_oxygen XCB::XCB)
endif()
install(TARGETS kwin3_oxygen DESTINATION ${PLUGIN_INSTALL_DIR})
########### install files ###############
install(FILES oxygenclient.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin/)
install(TARGETS kwin3_oxygen DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/kdecorations)

View File

@ -34,4 +34,4 @@ if(X11_FOUND)
target_link_libraries(kwin_oxygen_config Qt5::X11Extras)
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
{

View File

@ -169,8 +169,6 @@ Comment[x-test]=xxStyling of the next generation desktopxx
Comment[zh_CN]=下一代桌面的风格
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-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

View File

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

View File

@ -39,9 +39,9 @@ DecorationPlugin::DecorationPlugin(QObject *parent)
, KDecorationPlugins(KSharedConfig::openConfig())
, m_disabled(false)
{
defaultPlugin = QStringLiteral("kwin3_oxygen");
defaultPlugin = QStringLiteral("Oxygen");
#ifndef KWIN_BUILD_OXYGEN
defaultPlugin = QStringLiteral("kwin3_aurorae");
defaultPlugin = QStringLiteral("aurorae");
#endif
#ifdef KWIN_BUILD_DECORATIONS
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 <KLocalizedString>
#include <KConfigGroup>
#include <KPluginFactory>
#include <KPluginLoader>
#include <KPluginTrader>
#include <QDialogButtonBox>
#include <QPushButton>
@ -89,25 +88,24 @@ KWinDecorationConfigDialog::KWinDecorationConfigDialog(QString deco, const QList
connect(m_buttons, SIGNAL(accepted()), SLOT(accept()));
connect(m_buttons, SIGNAL(rejected()), SLOT(reject()));
KPluginLoader loader(styleToConfigLib(deco));
KPluginFactory *factory = loader.factory();
if (factory) {
m_pluginConfigWidget = new QWidget(this);
m_pluginConfigWidget->setLayout(new QVBoxLayout);
m_pluginObject = factory->create<QObject>(m_pluginConfigWidget, m_pluginConfigWidget, QString(),
QVariantList() << QStringLiteral("kwinrc") << QStringLiteral("Style"));
m_pluginConfigWidget = new QWidget(this);
m_pluginConfigWidget->setLayout(new QVBoxLayout);
m_pluginObject = KPluginTrader::self()->createInstanceFromQuery<QObject>(QStringLiteral("kf5/kwin/kdecorations/config"),
QString(),
QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(deco),
m_pluginConfigWidget,
m_pluginConfigWidget,
QVariantList() << QStringLiteral("kwinrc") << QStringLiteral("Style"));
if (m_pluginObject) {
// connect required signals and slots together...
connect(this, SIGNAL(accepted()), this, SLOT(slotAccepted()));
connect(m_pluginObject, SIGNAL(changed()), this, SLOT(slotSelectionChanged()));
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)), SLOT(slotDefault()));
}
if (m_pluginConfigWidget) {
layout->addWidget(m_pluginConfigWidget);
}
layout->addWidget(m_buttons);
if (borderSizes.count() >= 2) {
@ -160,14 +158,6 @@ void KWinDecorationConfigDialog::slotSelectionChanged()
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()
{
if (m_borderSizes.count() >= 2)

View File

@ -70,7 +70,6 @@ private Q_SLOTS:
private:
int borderSizeToIndex(KDecorationDefines::BorderSize size, const QList<QVariant>& sizes);
QString styleToConfigLib(const QString& styleLib) const;
private:
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 <KServiceTypeTrader>
#include <KPluginInfo>
#include <KPluginTrader>
#include "kwindecoration.h"
/* WARNING -------------------------------------------------------------------------
@ -47,6 +48,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* (which is invoked on deco deconstruction)
* WARNING ------------------------------------------------------------------------ */
static const QString s_auroraePluginName = QStringLiteral("aurorae");
namespace KWin
{
@ -87,41 +90,33 @@ void DecorationModel::reload()
void DecorationModel::findDecorations()
{
beginResetModel();
const QStringList dirList = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kwin", QStandardPaths::LocateDirectory);
foreach (const QString & dir, dirList) {
QDir d(dir);
if (d.exists()) {
foreach (const QFileInfo & fi, d.entryInfoList()) {
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);
}
}
}
const auto decorations = KPluginTrader::self()->query(QStringLiteral("kf5/kwin/kdecorations"));
for (const KPluginInfo &plugin : decorations) {
if (plugin.pluginName() == s_auroraePluginName) {
// read the Aurorae themes
findAuroraeThemes();
continue;
}
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");
foreach (KService::Ptr service, offers) {
DecorationModelData data;
data.name = service->name();
data.libraryName = "kwin3_aurorae";
data.pluginName = s_auroraePluginName;
data.type = DecorationModelData::QmlDecoration;
data.auroraeName = service->property("X-KDE-PluginInfo-Name").toString();
QString scriptName = service->property("X-Plasma-MainScript").toString();
@ -178,7 +173,7 @@ void DecorationModel::findAuroraeThemes()
DecorationModelData data;
data.name = name;
data.libraryName = "kwin3_aurorae";
data.pluginName = s_auroraePluginName;
data.type = DecorationModelData::AuroraeDecoration;
data.auroraeName = packageName;
KConfigGroup config(m_config, data.auroraeName);
@ -216,7 +211,7 @@ QVariant DecorationModel::data(const QModelIndex& index, int role) const
case NameRole:
return m_decorations[ index.row()].name;
case LibraryNameRole:
return m_decorations[ index.row()].libraryName;
return m_decorations[ index.row()].pluginName;
case TypeRole:
return m_decorations[ index.row()].type;
case AuroraeNameRole:
@ -238,7 +233,7 @@ QVariant DecorationModel::data(const QModelIndex& index, int role) const
case BorderSizesRole: {
QList< QVariant > sizes;
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
sizes << int(size);
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
{
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 QModelIndex();

View File

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

View File

@ -62,6 +62,8 @@ K_PLUGIN_FACTORY(KWinDecoFactory,
namespace KWin
{
static const QString s_defaultPluginName = QStringLiteral("Oxygen");
KWinDecorationForm::KWinDecorationForm(QWidget* parent)
: QWidget(parent)
{
@ -183,18 +185,18 @@ void KWinDecorationModule::readConfig(const KConfigGroup & conf)
// Find the corresponding decoration name to that of
// the current plugin library name
QString libraryName = conf.readEntry("PluginLib", "kwin3_oxygen");
QString libraryName = conf.readEntry("PluginLib", s_defaultPluginName);
if (libraryName.isEmpty()) {
// Selected decoration doesn't exist, use the default
libraryName = "kwin3_oxygen";
libraryName = s_defaultPluginName;
}
const int bsize = conf.readEntry("BorderSize", (int)BorderNormal);
BorderSize borderSize = BorderNormal;
if (bsize >= BorderTiny && bsize < BordersCount)
borderSize = static_cast< BorderSize >(bsize);
if (libraryName == "kwin3_aurorae") {
if (libraryName == "aurorae") {
KConfig auroraeConfig("auroraerc");
KConfigGroup group(&auroraeConfig, "Engine");
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.
*
* @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
*
* Example:
* @code
* KWIN_DECORATION(MyDecoPluginFactory, MyDeco::Factory)
* KWIN_DECORATION(MyDecoPluginFactory, "mydeco.json", MyDeco::Factory)
* @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)
* 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
@ -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.
**/
#define KWIN_DECORATION( pluginfactoryname, classname ) \
#define KWIN_DECORATION( pluginfactoryname, json, 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)
#define KWIN_DECORATION_BRIDGE_API_VERSION 1

View File

@ -31,6 +31,7 @@ DEALINGS IN THE SOFTWARE.
#include <klibrary.h>
#include <KPluginFactory>
#include <KPluginLoader>
#include <KPluginTrader>
#include <kconfiggroup.h>
#include <KDE/KLocalizedString>
#include <assert.h>
@ -44,7 +45,7 @@ DEALINGS IN THE SOFTWARE.
KDecorationPlugins::KDecorationPlugins(const KSharedConfigPtr &cfg)
: fact(nullptr),
old_fact(nullptr),
pluginStr(QStringLiteral("kwin3_undefined ")),
pluginStr(QStringLiteral("undefined ")),
config(cfg)
{
}
@ -105,7 +106,13 @@ bool KDecorationPlugins::loadPlugin(QString nameStr)
auto createFactory = [](const QString &pluginName) -> KDecorationFactory* {
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) {
qWarning() << i18n("The library %1 has wrong API version %2", loader.pluginName(), loader.pluginVersion());
return nullptr;