1/*
2 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6#include "kwindoweffects_dummy_p.h"
7#include "kwindowshadow_dummy_p.h"
8#include "kwindowsystem_debug.h"
9#include "kwindowsystem_dummy_p.h"
10#include "kwindowsystemplugininterface_p.h"
11#include "pluginwrapper_p.h"
12
13#include <QDir>
14#include <QGuiApplication>
15#include <QJsonArray>
16#include <QLibrary>
17#include <QPluginLoader>
18
19Q_GLOBAL_STATIC(KWindowSystemPluginWrapper, s_pluginWrapper)
20
21static QStringList pluginCandidates()
22{
23 QStringList ret;
24 const auto paths = QCoreApplication::libraryPaths();
25 for (const QString &path : paths) {
26 static const QStringList searchFolders{
27 QStringLiteral("/kf6/org.kde.kwindowsystem.platforms"),
28 QStringLiteral("/kf6/kwindowsystem"),
29 };
30 for (const QString &searchFolder : searchFolders) {
31 QDir pluginDir(path + searchFolder);
32 if (!pluginDir.exists()) {
33 continue;
34 }
35 const auto entries = pluginDir.entryList(filters: QDir::Files | QDir::NoDotAndDotDot);
36 for (const QString &entry : entries) {
37 ret << pluginDir.absoluteFilePath(fileName: entry);
38 }
39 }
40 }
41 return ret;
42}
43
44static bool checkPlatform(const QJsonObject &metadata, const QString &platformName)
45{
46 const QJsonArray platforms = metadata.value(QStringLiteral("MetaData")).toObject().value(QStringLiteral("platforms")).toArray();
47 return std::any_of(first: platforms.begin(), last: platforms.end(), pred: [&platformName](const QJsonValue &value) {
48 return QString::compare(s1: platformName, s2: value.toString(), cs: Qt::CaseInsensitive) == 0;
49 });
50}
51
52static KWindowSystemPluginInterface *loadPlugin()
53{
54 if (!qobject_cast<QGuiApplication *>(object: QCoreApplication::instance())) {
55 qCWarning(LOG_KWINDOWSYSTEM) << "Cannot use KWindowSystem without a QGuiApplication";
56 return nullptr;
57 }
58
59 QString platformName = QGuiApplication::platformName();
60 if (platformName == QLatin1String("flatpak")) {
61 // here we cannot know what is the actual windowing system, let's try it's env variable
62 const auto flatpakPlatform = QString::fromLocal8Bit(ba: qgetenv(varName: "QT_QPA_FLATPAK_PLATFORM"));
63 if (!flatpakPlatform.isEmpty()) {
64 platformName = flatpakPlatform;
65 }
66 }
67
68 const QList<QStaticPlugin> staticPlugins = QPluginLoader::staticPlugins();
69 for (const QStaticPlugin &staticPlugin : staticPlugins) {
70 const QJsonObject metadata = staticPlugin.metaData();
71 if (metadata.value(key: QLatin1String("IID")) != QLatin1String(KWindowSystemPluginInterface_iid)) {
72 continue;
73 }
74 if (checkPlatform(metadata, platformName)) {
75 KWindowSystemPluginInterface *interface = qobject_cast<KWindowSystemPluginInterface *>(object: staticPlugin.instance());
76 if (interface) {
77 qCDebug(LOG_KWINDOWSYSTEM) << "Loaded a static plugin for platform" << platformName;
78 return interface;
79 }
80 }
81 }
82
83 const auto candidates = pluginCandidates();
84 for (const QString &candidate : candidates) {
85 if (!QLibrary::isLibrary(fileName: candidate)) {
86 continue;
87 }
88 QPluginLoader loader(candidate);
89 if (checkPlatform(metadata: loader.metaData(), platformName)) {
90 KWindowSystemPluginInterface *interface = qobject_cast<KWindowSystemPluginInterface *>(object: loader.instance());
91 if (interface) {
92 qCDebug(LOG_KWINDOWSYSTEM) << "Loaded plugin" << candidate << "for platform" << platformName;
93 return interface;
94 }
95 }
96 }
97
98 qCWarning(LOG_KWINDOWSYSTEM) << "Could not find any platform plugin";
99 return nullptr;
100}
101
102KWindowSystemPluginWrapper::KWindowSystemPluginWrapper()
103 : m_plugin(loadPlugin())
104 , m_effects()
105{
106 if (m_plugin) {
107 m_effects.reset(p: m_plugin->createEffects());
108 }
109 if (!m_effects) {
110 m_effects.reset(p: new KWindowEffectsPrivateDummy());
111 }
112}
113
114KWindowSystemPluginWrapper::~KWindowSystemPluginWrapper()
115{
116}
117
118KWindowEffectsPrivate *KWindowSystemPluginWrapper::effects() const
119{
120 return m_effects.get();
121}
122
123KWindowSystemPrivate *KWindowSystemPluginWrapper::createWindowSystem() const
124{
125 KWindowSystemPrivate *p = nullptr;
126 if (m_plugin) {
127 p = m_plugin->createWindowSystem();
128 }
129 if (!p) {
130 p = new KWindowSystemPrivateDummy();
131 }
132 return p;
133}
134
135KWindowShadowPrivate *KWindowSystemPluginWrapper::createWindowShadow() const
136{
137 KWindowShadowPrivate *p = nullptr;
138 if (m_plugin) {
139 p = m_plugin->createWindowShadow();
140 }
141 if (!p) {
142 p = new KWindowShadowPrivateDummy();
143 }
144 return p;
145}
146
147KWindowShadowTilePrivate *KWindowSystemPluginWrapper::createWindowShadowTile() const
148{
149 KWindowShadowTilePrivate *p = nullptr;
150 if (m_plugin) {
151 p = m_plugin->createWindowShadowTile();
152 }
153 if (!p) {
154 p = new KWindowShadowTilePrivateDummy();
155 }
156 return p;
157}
158
159const KWindowSystemPluginWrapper &KWindowSystemPluginWrapper::self()
160{
161 return *s_pluginWrapper;
162}
163

source code of kwindowsystem/src/pluginwrapper.cpp