File indexing completed on 2024-12-01 11:10:05
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 0017 namespace KWin 0018 { 0019 0020 static const QString s_pluginDirectory = QStringLiteral("kwin/plugins"); 0021 0022 static QJsonValue readPluginInfo(const QJsonObject &metadata, const QString &key) 0023 { 0024 return metadata.value(QLatin1String("KPlugin")).toObject().value(key); 0025 } 0026 0027 PluginManager::PluginManager() 0028 { 0029 const KConfigGroup config(kwinApp()->config(), QStringLiteral("Plugins")); 0030 0031 auto checkEnabled = [&config](const QString &pluginId, const QJsonObject &metadata) { 0032 const QString configKey = pluginId + QLatin1String("Enabled"); 0033 if (config.hasKey(configKey)) { 0034 return config.readEntry(configKey, false); 0035 } 0036 return readPluginInfo(metadata, QStringLiteral("EnabledByDefault")).toBool(false); 0037 }; 0038 0039 const QVector<QStaticPlugin> staticPlugins = QPluginLoader::staticPlugins(); 0040 for (const QStaticPlugin &staticPlugin : staticPlugins) { 0041 const QJsonObject rootMetaData = staticPlugin.metaData(); 0042 if (rootMetaData.value(QLatin1String("IID")) != QLatin1String(PluginFactory_iid)) { 0043 continue; 0044 } 0045 0046 const QJsonObject pluginMetaData = rootMetaData.value(QLatin1String("MetaData")).toObject(); 0047 const QString pluginId = readPluginInfo(pluginMetaData, QStringLiteral("Id")).toString(); 0048 if (pluginId.isEmpty()) { 0049 continue; 0050 } 0051 if (m_staticPlugins.contains(pluginId)) { 0052 qCWarning(KWIN_CORE) << "Conflicting plugin id" << pluginId; 0053 continue; 0054 } 0055 0056 m_staticPlugins.insert(pluginId, staticPlugin); 0057 0058 if (checkEnabled(pluginId, pluginMetaData)) { 0059 loadStaticPlugin(pluginId); 0060 } 0061 } 0062 0063 const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(s_pluginDirectory); 0064 for (const KPluginMetaData &metadata : plugins) { 0065 if (m_plugins.find(metadata.pluginId()) != m_plugins.end()) { 0066 qCWarning(KWIN_CORE) << "Conflicting plugin id" << metadata.pluginId(); 0067 continue; 0068 } 0069 if (checkEnabled(metadata.pluginId(), metadata.rawData())) { 0070 loadDynamicPlugin(metadata); 0071 } 0072 } 0073 0074 new PluginManagerDBusInterface(this); 0075 } 0076 0077 PluginManager::~PluginManager() = default; 0078 0079 QStringList PluginManager::loadedPlugins() const 0080 { 0081 QStringList ret; 0082 ret.reserve(m_plugins.size()); 0083 for (const auto &[key, _] : m_plugins) { 0084 ret.push_back(key); 0085 } 0086 return ret; 0087 } 0088 0089 QStringList PluginManager::availablePlugins() const 0090 { 0091 QStringList ret = m_staticPlugins.keys(); 0092 0093 const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(s_pluginDirectory); 0094 for (const KPluginMetaData &metadata : plugins) { 0095 ret.append(metadata.pluginId()); 0096 } 0097 0098 return ret; 0099 } 0100 0101 bool PluginManager::loadPlugin(const QString &pluginId) 0102 { 0103 if (m_plugins.find(pluginId) != m_plugins.end()) { 0104 qCDebug(KWIN_CORE) << "Plugin with id" << pluginId << "is already loaded"; 0105 return false; 0106 } 0107 return loadStaticPlugin(pluginId) || loadDynamicPlugin(pluginId); 0108 } 0109 0110 bool PluginManager::loadStaticPlugin(const QString &pluginId) 0111 { 0112 auto staticIt = m_staticPlugins.find(pluginId); 0113 if (staticIt == m_staticPlugins.end()) { 0114 return false; 0115 } 0116 0117 std::unique_ptr<PluginFactory> factory(qobject_cast<PluginFactory *>(staticIt->instance())); 0118 if (!factory) { 0119 qCWarning(KWIN_CORE) << "Failed to get plugin factory for" << pluginId; 0120 return false; 0121 } 0122 0123 return instantiatePlugin(pluginId, factory.get()); 0124 } 0125 0126 bool PluginManager::loadDynamicPlugin(const QString &pluginId) 0127 { 0128 const KPluginMetaData metadata = KPluginMetaData::findPluginById(s_pluginDirectory, pluginId); 0129 if (metadata.isValid()) { 0130 if (loadDynamicPlugin(metadata)) { 0131 return true; 0132 } 0133 } 0134 return false; 0135 } 0136 0137 bool PluginManager::loadDynamicPlugin(const KPluginMetaData &metadata) 0138 { 0139 if (!metadata.isValid()) { 0140 qCDebug(KWIN_CORE) << "PluginManager::loadPlugin needs a valid plugin metadata"; 0141 return false; 0142 } 0143 0144 const QString pluginId = metadata.pluginId(); 0145 QPluginLoader pluginLoader(metadata.fileName()); 0146 if (pluginLoader.metaData().value("IID").toString() != PluginFactory_iid) { 0147 qCWarning(KWIN_CORE) << pluginId << "has mismatching plugin version"; 0148 return false; 0149 } 0150 0151 std::unique_ptr<PluginFactory> factory(qobject_cast<PluginFactory *>(pluginLoader.instance())); 0152 if (!factory) { 0153 qCWarning(KWIN_CORE) << "Failed to get plugin factory for" << pluginId; 0154 return false; 0155 } 0156 0157 return instantiatePlugin(pluginId, factory.get()); 0158 } 0159 0160 bool PluginManager::instantiatePlugin(const QString &pluginId, PluginFactory *factory) 0161 { 0162 if (std::unique_ptr<Plugin> plugin = factory->create()) { 0163 m_plugins[pluginId] = std::move(plugin); 0164 return true; 0165 } else { 0166 return false; 0167 } 0168 } 0169 0170 void PluginManager::unloadPlugin(const QString &pluginId) 0171 { 0172 auto it = m_plugins.find(pluginId); 0173 if (it != m_plugins.end()) { 0174 m_plugins.erase(it); 0175 } else { 0176 qCWarning(KWIN_CORE) << "No plugin with the specified id:" << pluginId; 0177 } 0178 } 0179 0180 } // namespace KWin