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
29
30
32{
33 // Allow a command line variable KRITA_PLUGIN_PATH to override the automatic search
34 m_pluginPath = QProcessEnvironment::systemEnvironment().value("KRITA_PLUGIN_PATH");
35
36 if (m_pluginPath.isEmpty() ||
37 !(QFileInfo(m_pluginPath).exists() && QFileInfo(m_pluginPath).isDir())) {
38
39 QList<QDir> searchDirs;
40
41 QDir appDir(qApp->applicationDirPath());
42 appDir.cdUp();
43#ifdef Q_OS_MACOS
44 // Help Krita run without deployment
45 QDir d(appDir);
46 d.cd("../../../");
47 searchDirs << d;
48#endif
49
50#ifdef Q_OS_ANDROID
51 appDir.cdUp();
52#endif
53 searchDirs << appDir;
54
55 Q_FOREACH (const QDir& dir, searchDirs) {
56 const QStringList nameFilters = {
57#ifdef Q_OS_MACOS
58 "*PlugIns*",
59#endif
60 "lib*",
61 };
62 Q_FOREACH (const QFileInfo &info, dir.entryInfoList(nameFilters, QDir::Dirs | QDir::NoDotAndDotDot)) {
63#ifdef Q_OS_MACOS
64 if (info.fileName().contains("PlugIns")) {
65 m_pluginPath = info.absoluteFilePath();
66 break;
67 }
68 else if (info.fileName().contains("lib")) {
69#else
70 if (info.fileName().contains("lib")) {
71#endif
72 QDir libDir(info.absoluteFilePath());
73
74#ifdef Q_OS_ANDROID
75#if defined(Q_PROCESSOR_ARM_64)
76 libDir.cd("arm64-v8a");
77#elif defined(Q_PROCESSOR_ARM)
78 libDir.cd("armeabi-v7a");
79#elif defined(Q_PROCESSOR_X86_64)
80 libDir.cd("x86_64");
81#elif defined(Q_PROCESSOR_x86)
82 libDir.cd("x86");
83#endif
84 m_pluginPath = libDir.absolutePath();
85 break;
86#else
87 // on many systems this will be the actual lib dir (and krita subdir contains plugins)
88 if (libDir.cd("kritaplugins")) {
89 m_pluginPath = libDir.absolutePath();
90 break;
91 }
92
93 // on debian at least the actual libdir is a subdir named like "lib/x86_64-linux-gnu"
94 // so search there for the Krita subdir which will contain our plugins
95 // FIXME: what are the chances of there being more than one Krita install with different arch and compiler ABI?
96 Q_FOREACH (const QFileInfo &subInfo, libDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
97 QDir subDir(subInfo.absoluteFilePath());
98 if (subDir.cd("kritaplugins")) {
99 m_pluginPath = subDir.absolutePath();
100 break; // will only break inner loop so we need the extra check below
101 }
102 }
103
104 if (!m_pluginPath.isEmpty()) {
105 break;
106 }
107#endif
108 }
109 }
110
111 if (!m_pluginPath.isEmpty()) {
112 break;
113 }
114 }
115 dbgPlugins << "KoJsonTrader will load its plugins from" << m_pluginPath;
116 }
117
119}
120
124
125
126Q_GLOBAL_STATIC(KoJsonTrader, s_instance)
127
129{
130 return s_instance;
131}
132
134{
135 QMutexLocker l(&m_mutex);
136
138
140 QDirIterator dirIter(m_pluginPath, QDirIterator::Subdirectories);
141 while (dirIter.hasNext()) {
142 dirIter.next();
143#ifdef Q_OS_ANDROID
144 // files starting with lib_krita are plugins, it is needed because of the loading rules in NDK
145 if (dirIter.fileInfo().isFile() && dirIter.fileName().startsWith("lib_krita")) {
146#elif defined(_MSC_VER)
147 if (dirIter.fileInfo().isFile() && dirIter.fileName().startsWith("krita") && !dirIter.fileName().endsWith(".pdb") && !dirIter.fileName().endsWith(".lib")) {
148#else
149 if (dirIter.fileInfo().isFile() && dirIter.fileName().startsWith("krita") && !dirIter.fileName().endsWith(".debug")) {
150#endif
151
152 dbgPlugins << dirIter.fileName();
153 QScopedPointer<QPluginLoader> loader(new QPluginLoader(dirIter.filePath()));
154 QJsonObject json = loader->metaData().value("MetaData").toObject();
155
156 dbgPlugins << json << json.value("X-KDE-ServiceTypes");
157
158 if (json.isEmpty()) {
159 qWarning() << dirIter.filePath() << "has no json!";
160 continue;
161 } else {
162 QJsonArray serviceTypes = json.value("X-KDE-ServiceTypes").toArray();
163 if (serviceTypes.isEmpty()) {
164 qWarning() << dirIter.fileName() << "has no X-KDE-ServiceTypes";
165 continue;
166 }
167
168 QStringList mimeTypes = json.value("X-KDE-ExtraNativeMimeTypes").toString().split(',');
169 mimeTypes += json.value("MimeType").toString().split(';');
170 mimeTypes += json.value("X-KDE-NativeMimeType").toString();
171
172 PluginCacheEntry cacheEntry;
173 cacheEntry.filePath = dirIter.filePath();
174 cacheEntry.serviceTypes = serviceTypes;
175 cacheEntry.mimeTypes = mimeTypes;
176 cacheEntry.loader = toQShared(loader.take());
177 m_pluginLoaderCache << cacheEntry;
178 }
179 }
180 }
181}
182
183QList<KoJsonTrader::Plugin> KoJsonTrader::query(const QString &servicetype, const QString &mimetype)
184{
185 QMutexLocker l(&m_mutex);
186
187 QList<Plugin> list;
188 Q_FOREACH(const PluginCacheEntry &plugin, m_pluginLoaderCache) {
189 if (!plugin.serviceTypes.contains(QJsonValue(servicetype))) {
190 continue;
191 }
192
193 if (!mimetype.isEmpty() && !plugin.mimeTypes.contains(mimetype)) {
194 continue;
195 }
196
197 list << Plugin(plugin.loader, &m_mutex);
198 }
199
200 return list;
201}
202
204 : m_loader(loader),
206{
207}
208
212
214{
215 QMutexLocker l(m_mutex);
216 return m_loader->instance();
217}
218
220{
221 return m_loader->metaData();
222}
223
225{
226 return m_loader->fileName();
227}
228
230{
231 return m_loader->errorString();
232}
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