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 | |
17 | namespace Kirigami |
18 | { |
19 | namespace Platform |
20 | { |
21 | |
22 | PlatformPluginFactory::PlatformPluginFactory(QObject *parent) |
23 | : QObject(parent) |
24 | { |
25 | } |
26 | |
27 | PlatformPluginFactory::~PlatformPluginFactory() = default; |
28 | |
29 | PlatformPluginFactory *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 | |