File indexing completed on 2024-04-21 03:59:29

0001 /*
0002     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "kwindoweffects_dummy_p.h"
0007 #include "kwindowshadow_dummy_p.h"
0008 #include "kwindowsystem_debug.h"
0009 #include "kwindowsystem_dummy_p.h"
0010 #include "kwindowsystemplugininterface_p.h"
0011 #include "pluginwrapper_p.h"
0012 
0013 #include <QDir>
0014 #include <QGuiApplication>
0015 #include <QJsonArray>
0016 #include <QLibrary>
0017 #include <QPluginLoader>
0018 
0019 Q_GLOBAL_STATIC(KWindowSystemPluginWrapper, s_pluginWrapper)
0020 
0021 static QStringList pluginCandidates()
0022 {
0023     QStringList ret;
0024     const auto paths = QCoreApplication::libraryPaths();
0025     for (const QString &path : paths) {
0026         static const QStringList searchFolders{
0027             QStringLiteral("/kf6/org.kde.kwindowsystem.platforms"),
0028             QStringLiteral("/kf6/kwindowsystem"),
0029         };
0030         for (const QString &searchFolder : searchFolders) {
0031             QDir pluginDir(path + searchFolder);
0032             if (!pluginDir.exists()) {
0033                 continue;
0034             }
0035             const auto entries = pluginDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
0036             for (const QString &entry : entries) {
0037                 ret << pluginDir.absoluteFilePath(entry);
0038             }
0039         }
0040     }
0041     return ret;
0042 }
0043 
0044 static bool checkPlatform(const QJsonObject &metadata, const QString &platformName)
0045 {
0046     const QJsonArray platforms = metadata.value(QStringLiteral("MetaData")).toObject().value(QStringLiteral("platforms")).toArray();
0047     return std::any_of(platforms.begin(), platforms.end(), [&platformName](const QJsonValue &value) {
0048         return QString::compare(platformName, value.toString(), Qt::CaseInsensitive) == 0;
0049     });
0050 }
0051 
0052 static KWindowSystemPluginInterface *loadPlugin()
0053 {
0054     if (!qobject_cast<QGuiApplication *>(QCoreApplication::instance())) {
0055         qCWarning(LOG_KWINDOWSYSTEM) << "Cannot use KWindowSystem without a QGuiApplication";
0056         return nullptr;
0057     }
0058 
0059     QString platformName = QGuiApplication::platformName();
0060     if (platformName == QLatin1String("flatpak")) {
0061         // here we cannot know what is the actual windowing system, let's try it's env variable
0062         const auto flatpakPlatform = QString::fromLocal8Bit(qgetenv("QT_QPA_FLATPAK_PLATFORM"));
0063         if (!flatpakPlatform.isEmpty()) {
0064             platformName = flatpakPlatform;
0065         }
0066     }
0067 
0068     const QList<QStaticPlugin> staticPlugins = QPluginLoader::staticPlugins();
0069     for (const QStaticPlugin &staticPlugin : staticPlugins) {
0070         const QJsonObject metadata = staticPlugin.metaData();
0071         if (metadata.value(QLatin1String("IID")) != QLatin1String(KWindowSystemPluginInterface_iid)) {
0072             continue;
0073         }
0074         if (checkPlatform(metadata, platformName)) {
0075             KWindowSystemPluginInterface *interface = qobject_cast<KWindowSystemPluginInterface *>(staticPlugin.instance());
0076             if (interface) {
0077                 qCDebug(LOG_KWINDOWSYSTEM) << "Loaded a static plugin for platform" << platformName;
0078                 return interface;
0079             }
0080         }
0081     }
0082 
0083     const auto candidates = pluginCandidates();
0084     for (const QString &candidate : candidates) {
0085         if (!QLibrary::isLibrary(candidate)) {
0086             continue;
0087         }
0088         QPluginLoader loader(candidate);
0089         if (checkPlatform(loader.metaData(), platformName)) {
0090             KWindowSystemPluginInterface *interface = qobject_cast<KWindowSystemPluginInterface *>(loader.instance());
0091             if (interface) {
0092                 qCDebug(LOG_KWINDOWSYSTEM) << "Loaded plugin" << candidate << "for platform" << platformName;
0093                 return interface;
0094             }
0095         }
0096     }
0097 
0098     qCWarning(LOG_KWINDOWSYSTEM) << "Could not find any platform plugin";
0099     return nullptr;
0100 }
0101 
0102 KWindowSystemPluginWrapper::KWindowSystemPluginWrapper()
0103     : m_plugin(loadPlugin())
0104     , m_effects()
0105 {
0106     if (m_plugin) {
0107         m_effects.reset(m_plugin->createEffects());
0108     }
0109     if (!m_effects) {
0110         m_effects.reset(new KWindowEffectsPrivateDummy());
0111     }
0112 }
0113 
0114 KWindowSystemPluginWrapper::~KWindowSystemPluginWrapper()
0115 {
0116 }
0117 
0118 KWindowEffectsPrivate *KWindowSystemPluginWrapper::effects() const
0119 {
0120     return m_effects.get();
0121 }
0122 
0123 KWindowSystemPrivate *KWindowSystemPluginWrapper::createWindowSystem() const
0124 {
0125     KWindowSystemPrivate *p = nullptr;
0126     if (m_plugin) {
0127         p = m_plugin->createWindowSystem();
0128     }
0129     if (!p) {
0130         p = new KWindowSystemPrivateDummy();
0131     }
0132     return p;
0133 }
0134 
0135 KWindowShadowPrivate *KWindowSystemPluginWrapper::createWindowShadow() const
0136 {
0137     KWindowShadowPrivate *p = nullptr;
0138     if (m_plugin) {
0139         p = m_plugin->createWindowShadow();
0140     }
0141     if (!p) {
0142         p = new KWindowShadowPrivateDummy();
0143     }
0144     return p;
0145 }
0146 
0147 KWindowShadowTilePrivate *KWindowSystemPluginWrapper::createWindowShadowTile() const
0148 {
0149     KWindowShadowTilePrivate *p = nullptr;
0150     if (m_plugin) {
0151         p = m_plugin->createWindowShadowTile();
0152     }
0153     if (!p) {
0154         p = new KWindowShadowTilePrivateDummy();
0155     }
0156     return p;
0157 }
0158 
0159 const KWindowSystemPluginWrapper &KWindowSystemPluginWrapper::self()
0160 {
0161     return *s_pluginWrapper;
0162 }