File indexing completed on 2024-05-12 04:45:34
0001 /* 0002 SnoreNotify is a Notification Framework based on Qt 0003 Copyright (C) 2013-2015 Hannah von Reth <vonreth@kde.org> 0004 0005 SnoreNotify is free software: you can redistribute it and/or modify 0006 it under the terms of the GNU Lesser General Public License as published by 0007 the Free Software Foundation, either version 3 of the License, or 0008 (at your option) any later version. 0009 0010 SnoreNotify is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 GNU Lesser General Public License for more details. 0014 0015 You should have received a copy of the GNU Lesser General Public License 0016 along with SnoreNotify. If not, see <http://www.gnu.org/licenses/>. 0017 */ 0018 0019 #include "plugincontainer.h" 0020 #include "libsnore/snore.h" 0021 #include "libsnore/snore_p.h" 0022 #include "plugins.h" 0023 #include "snorebackend.h" 0024 #include "snorefrontend.h" 0025 #include "libsnore/version.h" 0026 0027 #define SNORE_CONFIG_ONLY 0028 #include "libsnore/snore_static_plugins.h" 0029 0030 #include <QDir> 0031 #include <QGuiApplication> 0032 #include <QTime> 0033 0034 namespace Snore { 0035 0036 QHash<SnorePlugin::PluginTypes, QHash<QString, PluginContainer *> > PluginContainer::s_pluginCache; 0037 0038 0039 PluginContainer::PluginContainer(const QString &pluginName, SnorePlugin::PluginTypes type, SnorePlugin *plugin): 0040 m_pluginName(pluginName), 0041 m_pluginType(type), 0042 m_plugin(plugin) 0043 { 0044 m_plugin->m_name = pluginName; 0045 } 0046 0047 PluginContainer::PluginContainer(const QString &fileName, const QString &pluginName, SnorePlugin::PluginTypes type): 0048 m_pluginFile(fileName), 0049 m_pluginName(pluginName), 0050 m_pluginType(type), 0051 m_loader(pluginDir().absoluteFilePath(file())) 0052 { 0053 } 0054 0055 PluginContainer::~PluginContainer() 0056 { 0057 m_loader.unload(); 0058 } 0059 0060 SnorePlugin *PluginContainer::load() 0061 { 0062 if (!m_plugin && !m_loader.isLoaded() && !m_loader.load()) { 0063 qCWarning(SNORE) << "Failed loading plugin: " << m_loader.errorString(); 0064 return nullptr; 0065 } 0066 if (!m_plugin) { 0067 m_plugin = qobject_cast<SnorePlugin *> (m_loader.instance()); 0068 m_plugin->m_name = name(); 0069 m_plugin->setDefaultSettings(); 0070 } 0071 return m_plugin; 0072 } 0073 0074 const QString &PluginContainer::file() 0075 { 0076 return m_pluginFile; 0077 } 0078 0079 const QString &PluginContainer::name() 0080 { 0081 return m_pluginName; 0082 } 0083 0084 SnorePlugin::PluginTypes PluginContainer::type() 0085 { 0086 return m_pluginType; 0087 } 0088 0089 bool PluginContainer::isLoaded() const 0090 { 0091 return m_loader.isLoaded(); 0092 } 0093 0094 void PluginContainer::updatePluginCache() 0095 { 0096 qCDebug(SNORE) << "Updating plugin cache"; 0097 foreach(PluginContaienrHash list, s_pluginCache.values()) { 0098 qDeleteAll(list); 0099 list.clear(); 0100 } 0101 0102 #if !SNORE_STATIC 0103 foreach(const SnorePlugin::PluginTypes type, SnorePlugin::types()) { 0104 foreach(const QFileInfo & file, pluginDir().entryInfoList(pluginFileFilters(type), QDir::Files)) { 0105 qCDebug(SNORE) << "adding" << file.absoluteFilePath(); 0106 QPluginLoader loader(file.absoluteFilePath()); 0107 QJsonObject data = loader.metaData()[QStringLiteral("MetaData")].toObject(); 0108 QString name = data.value(QStringLiteral("name")).toString(); 0109 if (!name.isEmpty()) { 0110 PluginContainer *info = new PluginContainer(file.fileName(), name, type); 0111 s_pluginCache[type].insert(name, info); 0112 qCDebug(SNORE) << "added" << type << ":" << name << "to cache"; 0113 } 0114 } 0115 } 0116 #else 0117 foreach (const QStaticPlugin plugin, QPluginLoader::staticPlugins()) { 0118 QJsonObject data = plugin.metaData()[QStringLiteral("MetaData")].toObject(); 0119 QString name = data.value(QStringLiteral("name")).toString(); 0120 if (!name.isEmpty()) { 0121 SnorePlugin *sp = qobject_cast<SnorePlugin*>(plugin.instance()); 0122 PluginContainer *info = new PluginContainer(name, sp->type(), sp); 0123 s_pluginCache[sp->type()].insert(name, info); 0124 qCDebug(SNORE) << "added" << sp->type() << ":" << name << "to cache"; 0125 } 0126 } 0127 #endif 0128 } 0129 0130 const QHash<QString, PluginContainer *> PluginContainer::pluginCache(SnorePlugin::PluginTypes type) 0131 { 0132 if (s_pluginCache.isEmpty()) { 0133 QTime time; 0134 time.start(); 0135 updatePluginCache(); 0136 qCDebug(SNORE) << "Plugins loaded in:" << time.elapsed(); 0137 } 0138 0139 QHash<QString, PluginContainer *> out; 0140 for (auto &t : SnorePlugin::types()) { 0141 if (t & type) { 0142 out.unite(s_pluginCache.value(t)); 0143 } 0144 } 0145 return out; 0146 } 0147 0148 const QDir &PluginContainer::pluginDir() 0149 { 0150 static bool isLoaded = false; 0151 static QDir path; 0152 if (!isLoaded) { 0153 isLoaded = true; 0154 QString appDir = qApp->applicationDirPath(); 0155 #ifdef Q_OS_MAC 0156 if (appDir == QLatin1String("MacOS")) { 0157 list << appDir; 0158 QDir dir(appDir); 0159 // Development convenience-hack 0160 dir.cdUp(); 0161 dir.cdUp(); 0162 dir.cdUp(); 0163 appDir = dir.absolutePath(); 0164 } 0165 #endif 0166 const auto suffix = QStringLiteral("/libsnore" SNORE_SUFFIX); 0167 QStringList list { appDir }; 0168 for (const QString &s : qApp->libraryPaths()) { 0169 list << s + suffix; 0170 } 0171 list<< appDir + suffix 0172 << appDir + QStringLiteral("/../lib/plugins") + suffix 0173 << appDir + QStringLiteral("/../lib64/plugins") + suffix 0174 << QStringLiteral(LIBSNORE_PLUGIN_PATH); 0175 0176 qCDebug(SNORE) << "Plugin locations:" << list; 0177 foreach(const QString & p, list) { 0178 path = QDir(p); 0179 0180 if (!path.entryInfoList(pluginFileFilters()).isEmpty()) { 0181 break; 0182 } else { 0183 qCDebug(SNORE) << "Possible pluginpath:" << path.absolutePath() << "does not contain plugins."; 0184 } 0185 } 0186 if (path.entryInfoList(pluginFileFilters()).isEmpty()) { 0187 qCWarning(SNORE) << "Couldnt find any plugins"; 0188 } 0189 qCDebug(SNORE) << "PluginPath is :" << path.absolutePath(); 0190 } 0191 return path; 0192 } 0193 0194 }