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 }