File indexing completed on 2024-05-05 03:56:26

0001 /*
0002  *  SPDX-FileCopyrightText: 2017 by Marco Martin <mart@kde.org>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "platformpluginfactory.h"
0008 
0009 #include <QCoreApplication>
0010 #include <QDebug>
0011 #include <QDir>
0012 #include <QPluginLoader>
0013 #include <QQuickStyle>
0014 
0015 #include "kirigamiplatform_logging.h"
0016 
0017 namespace Kirigami
0018 {
0019 namespace Platform
0020 {
0021 
0022 PlatformPluginFactory::PlatformPluginFactory(QObject *parent)
0023     : QObject(parent)
0024 {
0025 }
0026 
0027 PlatformPluginFactory::~PlatformPluginFactory() = default;
0028 
0029 PlatformPluginFactory *PlatformPluginFactory::findPlugin(const QString &preferredName)
0030 {
0031     static QHash<QString, PlatformPluginFactory *> factories = QHash<QString, PlatformPluginFactory *>();
0032 
0033     QString pluginName = preferredName.isEmpty() ? QQuickStyle::name() : preferredName;
0034     // check for the plugin only once: it's an heavy operation
0035     if (auto it = factories.constFind(pluginName); it != factories.constEnd()) {
0036         return it.value();
0037     }
0038 
0039     // Even plugins that aren't found are in the map, so we know we shouldn't check again withthis expensive operation
0040     factories[pluginName] = nullptr;
0041 
0042 #ifdef KIRIGAMI_BUILD_TYPE_STATIC
0043     for (QObject *staticPlugin : QPluginLoader::staticInstances()) {
0044         PlatformPluginFactory *factory = qobject_cast<PlatformPluginFactory *>(staticPlugin);
0045         if (factory) {
0046             factories[pluginName] = factory;
0047             break;
0048         }
0049     }
0050 #else
0051     const auto libraryPaths = QCoreApplication::libraryPaths();
0052     for (const QString &path : libraryPaths) {
0053 
0054 #ifdef Q_OS_ANDROID
0055         const QDir dir(path);
0056 #else
0057         const QDir dir(path + QStringLiteral("/kf6/kirigami/platform"));
0058 #endif
0059 
0060         const auto fileNames = dir.entryList(QDir::Files);
0061 
0062         for (const QString &fileName : fileNames) {
0063 
0064 #ifdef Q_OS_ANDROID
0065             if (fileName.startsWith(QStringLiteral("libplugins_kf6_kirigami_platform_")) && QLibrary::isLibrary(fileName)) {
0066 #endif
0067                 if (!pluginName.isEmpty() && fileName.contains(pluginName)) {
0068                     // TODO: env variable too?
0069                     QPluginLoader loader(dir.absoluteFilePath(fileName));
0070                     QObject *plugin = loader.instance();
0071                     // TODO: load actually a factory as plugin
0072 
0073                     qCDebug(KirigamiPlatform) << "Loading style plugin from" << dir.absoluteFilePath(fileName);
0074 
0075                     if (auto factory = qobject_cast<PlatformPluginFactory *>(plugin)) {
0076                         factories[pluginName] = factory;
0077                         break;
0078                     }
0079                 }
0080 #ifdef Q_OS_ANDROID
0081             }
0082 #endif
0083         }
0084 
0085         // Ensure we only load the first plugin from the first plugin location.
0086         // If we do not break here, we may end up loading a different plugin
0087         // in place of the first one.
0088         if (factories.value(pluginName) != nullptr) {
0089             break;
0090         }
0091     }
0092 #endif
0093 
0094     PlatformPluginFactory *factory = factories.value(pluginName);
0095 
0096     if (factory == nullptr) {
0097         qWarning(KirigamiPlatform) << "Failed to find a Kirigami platform plugin for style" << QQuickStyle::name();
0098     }
0099 
0100     return factory;
0101 }
0102 
0103 }
0104 }
0105 
0106 #include "moc_platformpluginfactory.cpp"