Krita Source Code Documentation
Loading...
Searching...
No Matches
KoJsonTrader.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org>
3 SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "KoJsonTrader.h"
9
10#include "kis_debug.h"
11
12#include <QCoreApplication>
13#include <QPluginLoader>
14#include <QJsonObject>
15#include <QJsonArray>
16#include <QDirIterator>
17#include <QDir>
18#include <QProcessEnvironment>
19#include <QGlobalStatic>
20#include <QMutexLocker>
21
22#include <memory>
23
31
32
34{
35 // Allow a command line variable KRITA_PLUGIN_PATH to override the automatic search
36 m_pluginPath = QProcessEnvironment::systemEnvironment().value("KRITA_PLUGIN_PATH");
37
38 if (m_pluginPath.isEmpty() ||
39 !(QFileInfo(m_pluginPath).exists() && QFileInfo(m_pluginPath).isDir())) {
40
41 QList<QDir> searchDirs;
42
43 QDir appDir(qApp->applicationDirPath());
44 appDir.cdUp();
45#ifdef Q_OS_MACOS
46 // Help Krita run without deployment
47 QDir d(appDir);
48 d.cd("../../../");
49 searchDirs << d;
50#endif
51
52#ifdef Q_OS_ANDROID
53 appDir.cdUp();
54#endif
55 searchDirs << appDir;
56
57 Q_FOREACH (const QDir& dir, searchDirs) {
58 const QStringList nameFilters = {
59#ifdef Q_OS_MACOS
60 "*PlugIns*",
61#endif
62 "lib*",
63 };
64 Q_FOREACH (const QFileInfo &info, dir.entryInfoList(nameFilters, QDir::Dirs | QDir::NoDotAndDotDot)) {
65#ifdef Q_OS_MACOS
66 if (info.fileName().contains("PlugIns")) {
67 m_pluginPath = info.absoluteFilePath();
68 break;
69 }
70 else if (info.fileName().contains("lib")) {
71#else
72 if (info.fileName().contains("lib")) {
73#endif
74 QDir libDir(info.absoluteFilePath());
75
76#ifdef Q_OS_ANDROID
77#if defined(Q_PROCESSOR_ARM_64)
78 libDir.cd("arm64-v8a");
79#elif defined(Q_PROCESSOR_ARM)
80 libDir.cd("armeabi-v7a");
81#elif defined(Q_PROCESSOR_X86_64)
82 libDir.cd("x86_64");
83#elif defined(Q_PROCESSOR_x86)
84 libDir.cd("x86");
85#endif
86 m_pluginPath = libDir.absolutePath();
87 break;
88#else
89 // on many systems this will be the actual lib dir (and krita subdir contains plugins)
90 if (libDir.cd("kritaplugins")) {
91 m_pluginPath = libDir.absolutePath();
92 break;
93 }
94
95 // on debian at least the actual libdir is a subdir named like "lib/x86_64-linux-gnu"
96 // so search there for the Krita subdir which will contain our plugins
97 // FIXME: what are the chances of there being more than one Krita install with different arch and compiler ABI?
98 Q_FOREACH (const QFileInfo &subInfo, libDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
99 QDir subDir(subInfo.absoluteFilePath());
100 if (subDir.cd("kritaplugins")) {
101 m_pluginPath = subDir.absolutePath();
102 break; // will only break inner loop so we need the extra check below
103 }
104 }
105
106 if (!m_pluginPath.isEmpty()) {
107 break;
108 }
109#endif
110 }
111 }
112
113 if (!m_pluginPath.isEmpty()) {
114 break;
115 }
116 }
117 dbgPlugins << "KoJsonTrader will load its plugins from" << m_pluginPath;
118 }
119
121}
122
126
127
128Q_GLOBAL_STATIC(KoJsonTrader, s_instance)
129
131{
132 return s_instance;
133}
134
136{
137 QMutexLocker l(&m_mutex);
138
140
142 QDirIterator dirIter(m_pluginPath, QDirIterator::Subdirectories);
143 while (dirIter.hasNext()) {
144 dirIter.next();
145#ifdef Q_OS_ANDROID
146 // files starting with lib_krita are plugins, it is needed because of the loading rules in NDK
147 if (dirIter.fileInfo().isFile() && dirIter.fileName().startsWith("lib_krita")) {
148#elif defined(_MSC_VER)
149 if (dirIter.fileInfo().isFile() && dirIter.fileName().startsWith("krita") && !dirIter.fileName().endsWith(".pdb") && !dirIter.fileName().endsWith(".lib")) {
150#else
151 if (dirIter.fileInfo().isFile() && dirIter.fileName().startsWith("krita") && !dirIter.fileName().endsWith(".debug")) {
152#endif
153
154 dbgPlugins << dirIter.fileName();
155 std::unique_ptr<QPluginLoader> loader(new QPluginLoader(dirIter.filePath()));
156 QJsonObject json = loader->metaData().value("MetaData").toObject();
157
158 dbgPlugins << json << json.value("X-KDE-ServiceTypes");
159
160 if (json.isEmpty()) {
161 qWarning() << dirIter.filePath() << "has no json!";
162 continue;
163 } else {
164 QJsonArray serviceTypes = json.value("X-KDE-ServiceTypes").toArray();
165 if (serviceTypes.isEmpty()) {
166 qWarning() << dirIter.fileName() << "has no X-KDE-ServiceTypes";
167 continue;
168 }
169
170 QStringList mimeTypes = json.value("X-KDE-ExtraNativeMimeTypes").toString().split(',');
171 mimeTypes += json.value("MimeType").toString().split(';');
172 mimeTypes += json.value("X-KDE-NativeMimeType").toString();
173
174 PluginCacheEntry cacheEntry;
175 cacheEntry.filePath = dirIter.filePath();
176 cacheEntry.serviceTypes = serviceTypes;
177 cacheEntry.mimeTypes = mimeTypes;
178 cacheEntry.loader = toQShared(loader.release());
179 m_pluginLoaderCache << cacheEntry;
180 }
181 }
182 }
183}
184
185QList<KoJsonTrader::Plugin> KoJsonTrader::query(const QString &servicetype, const QString &mimetype)
186{
187 QMutexLocker l(&m_mutex);
188
189 QList<Plugin> list;
190 Q_FOREACH(const PluginCacheEntry &plugin, m_pluginLoaderCache) {
191 if (!plugin.serviceTypes.contains(QJsonValue(servicetype))) {
192 continue;
193 }
194
195 if (!mimetype.isEmpty() && !plugin.mimeTypes.contains(mimetype)) {
196 continue;
197 }
198
199 list << Plugin(plugin.loader, &m_mutex);
200 }
201
202 return list;
203}
204
206 : m_loader(loader),
208{
209}
210
214
216{
217 QMutexLocker l(m_mutex);
218 return m_loader->instance();
219}
220
222{
223 return m_loader->metaData();
224}
225
227{
228 return m_loader->fileName();
229}
230
232{
233 return m_loader->errorString();
234}
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
static KoJsonTrader * instance()
void initializePluginLoaderCache()
QList< Plugin > query(const QString &servicetype, const QString &mimetype)
QList< PluginCacheEntry > m_pluginLoaderCache
QString m_pluginPath
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define dbgPlugins
Definition kis_debug.h:51
static QMutex mutex
QSharedPointer< T > toQShared(T *ptr)
QSharedPointer< QPluginLoader > loader
QObject * instance() const
QString fileName() const
QJsonObject metaData() const
QString errorString() const