1/*
2 * SPDX-FileCopyrightText: 2017 by Marco Martin <mart@kde.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "platformpluginfactory.h"
8
9#include <QCoreApplication>
10#include <QDebug>
11#include <QDir>
12#include <QPluginLoader>
13#include <QQuickStyle>
14
15#include "kirigamiplatform_logging.h"
16
17namespace Kirigami
18{
19namespace Platform
20{
21
22PlatformPluginFactory::PlatformPluginFactory(QObject *parent)
23 : QObject(parent)
24{
25}
26
27PlatformPluginFactory::~PlatformPluginFactory() = default;
28
29PlatformPluginFactory *PlatformPluginFactory::findPlugin(const QString &preferredName)
30{
31 static QHash<QString, PlatformPluginFactory *> factories = QHash<QString, PlatformPluginFactory *>();
32
33 QString pluginName = preferredName.isEmpty() ? QQuickStyle::name() : preferredName;
34 // check for the plugin only once: it's an heavy operation
35 if (auto it = factories.constFind(key: pluginName); it != factories.constEnd()) {
36 return it.value();
37 }
38
39 // Even plugins that aren't found are in the map, so we know we shouldn't check again withthis expensive operation
40 factories[pluginName] = nullptr;
41
42#ifdef KIRIGAMI_BUILD_TYPE_STATIC
43 for (QObject *staticPlugin : QPluginLoader::staticInstances()) {
44 PlatformPluginFactory *factory = qobject_cast<PlatformPluginFactory *>(staticPlugin);
45 if (factory) {
46 factories[pluginName] = factory;
47 break;
48 }
49 }
50#else
51 const auto libraryPaths = QCoreApplication::libraryPaths();
52 for (const QString &path : libraryPaths) {
53
54#ifdef Q_OS_ANDROID
55 const QDir dir(path);
56#else
57 const QDir dir(path + QStringLiteral("/kf6/kirigami/platform"));
58#endif
59
60 const auto fileNames = dir.entryList(filters: QDir::Files);
61
62 for (const QString &fileName : fileNames) {
63
64#ifdef Q_OS_ANDROID
65 if (fileName.startsWith(QStringLiteral("libplugins_kf6_kirigami_platform_")) && QLibrary::isLibrary(fileName)) {
66#endif
67 if (!pluginName.isEmpty() && fileName.contains(s: pluginName)) {
68 // TODO: env variable too?
69 QPluginLoader loader(dir.absoluteFilePath(fileName));
70 QObject *plugin = loader.instance();
71 // TODO: load actually a factory as plugin
72
73 qCDebug(KirigamiPlatform) << "Loading style plugin from" << dir.absoluteFilePath(fileName);
74
75 if (auto factory = qobject_cast<PlatformPluginFactory *>(object: plugin)) {
76 factories[pluginName] = factory;
77 break;
78 }
79 }
80#ifdef Q_OS_ANDROID
81 }
82#endif
83 }
84
85 // Ensure we only load the first plugin from the first plugin location.
86 // If we do not break here, we may end up loading a different plugin
87 // in place of the first one.
88 if (factories.value(key: pluginName) != nullptr) {
89 break;
90 }
91 }
92#endif
93
94 PlatformPluginFactory *factory = factories.value(key: pluginName);
95
96 if (factory == nullptr) {
97 qWarning(catFunc: KirigamiPlatform) << "Failed to find a Kirigami platform plugin for style" << QQuickStyle::name();
98 }
99
100 return factory;
101}
102
103}
104}
105
106#include "moc_platformpluginfactory.cpp"
107

source code of kirigami/src/platform/platformpluginfactory.cpp