File indexing completed on 2024-12-08 07:59:35

0001 /*
0002     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "pluginmanager.h"
0008 #include "dbusinterface.h"
0009 #include "main.h"
0010 #include "plugin.h"
0011 #include "utils/common.h"
0012 
0013 #include <KConfigGroup>
0014 #include <KPluginFactory>
0015 #include <KPluginMetaData>
0016 #include <QPluginLoader>
0017 
0018 namespace KWin
0019 {
0020 
0021 static const QString s_pluginDirectory = QStringLiteral("kwin/plugins");
0022 
0023 static QJsonValue readPluginInfo(const QJsonObject &metadata, const QString &key)
0024 {
0025     return metadata.value(QLatin1String("KPlugin")).toObject().value(key);
0026 }
0027 
0028 PluginManager::PluginManager()
0029 {
0030     const KConfigGroup config(kwinApp()->config(), QStringLiteral("Plugins"));
0031 
0032     auto checkEnabled = [&config](const QString &pluginId, const QJsonObject &metadata) {
0033         const QString configKey = pluginId + QLatin1String("Enabled");
0034         if (config.hasKey(configKey)) {
0035             return config.readEntry(configKey, false);
0036         }
0037         return readPluginInfo(metadata, QStringLiteral("EnabledByDefault")).toBool(false);
0038     };
0039 
0040     const QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(s_pluginDirectory);
0041     for (const KPluginMetaData &metadata : plugins) {
0042         if (m_plugins.find(metadata.pluginId()) != m_plugins.end()) {
0043             qCWarning(KWIN_CORE) << "Conflicting plugin id" << metadata.pluginId();
0044             continue;
0045         }
0046         if (checkEnabled(metadata.pluginId(), metadata.rawData())) {
0047             loadPlugin(metadata);
0048         }
0049     }
0050 
0051     new PluginManagerDBusInterface(this);
0052 }
0053 
0054 PluginManager::~PluginManager() = default;
0055 
0056 QStringList PluginManager::loadedPlugins() const
0057 {
0058     QStringList ret;
0059     ret.reserve(m_plugins.size());
0060     for (const auto &[key, _] : m_plugins) {
0061         ret.push_back(key);
0062     }
0063     return ret;
0064 }
0065 
0066 QStringList PluginManager::availablePlugins() const
0067 {
0068     const QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(s_pluginDirectory);
0069 
0070     QStringList ret;
0071     ret.reserve(plugins.size());
0072 
0073     for (const KPluginMetaData &metadata : plugins) {
0074         ret.append(metadata.pluginId());
0075     }
0076 
0077     return ret;
0078 }
0079 
0080 bool PluginManager::loadPlugin(const QString &pluginId)
0081 {
0082     if (m_plugins.find(pluginId) != m_plugins.end()) {
0083         qCDebug(KWIN_CORE) << "Plugin with id" << pluginId << "is already loaded";
0084         return false;
0085     }
0086     const KPluginMetaData metadata = KPluginMetaData::findPluginById(s_pluginDirectory, pluginId);
0087     if (metadata.isValid()) {
0088         if (loadPlugin(metadata)) {
0089             return true;
0090         }
0091     }
0092     return false;
0093 }
0094 
0095 bool PluginManager::loadPlugin(const KPluginMetaData &metadata)
0096 {
0097     if (!metadata.isValid()) {
0098         qCDebug(KWIN_CORE) << "PluginManager::loadPlugin needs a valid plugin metadata";
0099         return false;
0100     }
0101 
0102     const QString pluginId = metadata.pluginId();
0103     QPluginLoader pluginLoader(metadata.fileName());
0104     if (pluginLoader.metaData().value("IID").toString() != PluginFactory_iid) {
0105         qCWarning(KWIN_CORE) << pluginId << "has mismatching plugin version";
0106         return false;
0107     }
0108 
0109     std::unique_ptr<PluginFactory> factory(qobject_cast<PluginFactory *>(pluginLoader.instance()));
0110     if (!factory) {
0111         qCWarning(KWIN_CORE) << "Failed to get plugin factory for" << pluginId;
0112         return false;
0113     }
0114 
0115     if (std::unique_ptr<Plugin> plugin = factory->create()) {
0116         m_plugins[pluginId] = std::move(plugin);
0117         return true;
0118     } else {
0119         return false;
0120     }
0121 }
0122 
0123 void PluginManager::unloadPlugin(const QString &pluginId)
0124 {
0125     auto it = m_plugins.find(pluginId);
0126     if (it != m_plugins.end()) {
0127         m_plugins.erase(it);
0128     } else {
0129         qCWarning(KWIN_CORE) << "No plugin with the specified id:" << pluginId;
0130     }
0131 }
0132 
0133 } // namespace KWin
0134 
0135 #include "moc_pluginmanager.cpp"