File indexing completed on 2024-07-14 14:38:32

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