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

0001 /*
0002     SPDX-FileCopyrightText: 2014 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 "kwindowsystem.h"
0007 #include "kwindowsystem_debug.h"
0008 #include "kwindowsystem_dummy_p.h"
0009 #include "pluginwrapper_p.h"
0010 
0011 #include <config-kwindowsystem.h>
0012 
0013 #if KWINDOWSYSTEM_HAVE_X11
0014 #include "kstartupinfo.h"
0015 #endif
0016 
0017 #include <QGuiApplication>
0018 #include <QMetaMethod>
0019 #include <QPixmap>
0020 #include <QPluginLoader>
0021 #include <QTimer>
0022 #include <QWindow>
0023 #if KWINDOWSYSTEM_HAVE_X11
0024 #include <private/qtx11extras_p.h>
0025 #endif
0026 
0027 // QPoint and QSize all have handy / operators which are useful for scaling, positions and sizes for high DPI support
0028 // QRect does not, so we create one for internal purposes within this class
0029 inline QRect operator/(const QRect &rectangle, qreal factor)
0030 {
0031     return QRect(rectangle.topLeft() / factor, rectangle.size() / factor);
0032 }
0033 
0034 class KWindowSystemStaticContainer
0035 {
0036 public:
0037     KWindowSystemStaticContainer()
0038     {
0039         d.reset(KWindowSystemPluginWrapper::self().createWindowSystem());
0040 
0041         if (QCoreApplication::instance()) {
0042             kwm.moveToThread(QCoreApplication::instance()->thread());
0043         }
0044     }
0045     KWindowSystem kwm;
0046     std::unique_ptr<KWindowSystemPrivate> d;
0047 };
0048 
0049 Q_GLOBAL_STATIC(KWindowSystemStaticContainer, g_kwmInstanceContainer)
0050 
0051 KWindowSystemPrivate::~KWindowSystemPrivate()
0052 {
0053 }
0054 
0055 void KWindowSystemPrivateDummy::activateWindow(QWindow *win, long time)
0056 {
0057     Q_UNUSED(win)
0058     Q_UNUSED(time)
0059 }
0060 
0061 bool KWindowSystemPrivateDummy::showingDesktop()
0062 {
0063     return false;
0064 }
0065 
0066 void KWindowSystemPrivateDummy::setShowingDesktop(bool showing)
0067 {
0068     Q_UNUSED(showing);
0069 }
0070 
0071 KWindowSystem *KWindowSystem::self()
0072 {
0073     return &(g_kwmInstanceContainer()->kwm);
0074 }
0075 
0076 KWindowSystemPrivate *KWindowSystem::d_func()
0077 {
0078     return g_kwmInstanceContainer()->d.get();
0079 }
0080 
0081 void KWindowSystem::activateWindow(QWindow *win, long time)
0082 {
0083     Q_D(KWindowSystem);
0084     d->activateWindow(win, time);
0085 }
0086 
0087 void KWindowSystem::setMainWindow(QWindow *subWindow, WId mainWindowId)
0088 {
0089     QWindow *mainWindow = QWindow::fromWinId(mainWindowId);
0090     if (mainWindow) { // foreign windows not supported on all platforms
0091         subWindow->setTransientParent(mainWindow);
0092 
0093         // mainWindow is not the child of any object, so make sure it gets deleted at some point
0094         connect(subWindow, &QObject::destroyed, mainWindow, &QObject::deleteLater);
0095     }
0096 }
0097 
0098 void KWindowSystem::setMainWindow(QWindow *subWindow, const QString &mainWindowId)
0099 {
0100     Q_D(KWindowSystem);
0101     if (isPlatformWayland()) {
0102         if (auto dv2 = dynamic_cast<KWindowSystemPrivateV2 *>(d)) {
0103             dv2->setMainWindow(subWindow, mainWindowId);
0104         }
0105     } else {
0106         bool ok = false;
0107         // base 0 means "C style" parsing with 0x for base 16, 0b for base 2, etc.
0108         WId wid = mainWindowId.toULongLong(&ok, 0);
0109         if (ok) {
0110             setMainWindow(subWindow, wid);
0111         } else {
0112             qCWarning(LOG_KWINDOWSYSTEM) << "Failed to convert" << mainWindowId << "to WId";
0113         }
0114     }
0115 }
0116 
0117 bool KWindowSystem::showingDesktop()
0118 {
0119     Q_D(KWindowSystem);
0120     return d->showingDesktop();
0121 }
0122 
0123 void KWindowSystem::setShowingDesktop(bool showing)
0124 {
0125     Q_D(KWindowSystem);
0126     return d->setShowingDesktop(showing);
0127 }
0128 
0129 static inline KWindowSystem::Platform initPlatform()
0130 {
0131     auto platformName = QGuiApplication::platformName();
0132     if (platformName == QLatin1String("flatpak")) {
0133         // here we cannot know what is the actual windowing system, let's try it's env variable
0134         const auto flatpakPlatform = QString::fromLocal8Bit(qgetenv("QT_QPA_FLATPAK_PLATFORM"));
0135         if (!flatpakPlatform.isEmpty()) {
0136             platformName = flatpakPlatform;
0137         }
0138     }
0139 #if KWINDOWSYSTEM_HAVE_X11
0140     if (platformName == QLatin1String("xcb")) {
0141         return KWindowSystem::Platform::X11;
0142     }
0143 #endif
0144     if (platformName.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) {
0145         return KWindowSystem::Platform::Wayland;
0146     }
0147     return KWindowSystem::Platform::Unknown;
0148 }
0149 
0150 KWindowSystem::Platform KWindowSystem::platform()
0151 {
0152     static Platform s_platform = initPlatform();
0153     return s_platform;
0154 }
0155 
0156 bool KWindowSystem::isPlatformX11()
0157 {
0158     return platform() == Platform::X11;
0159 }
0160 
0161 bool KWindowSystem::isPlatformWayland()
0162 {
0163     return platform() == Platform::Wayland;
0164 }
0165 
0166 void KWindowSystem::updateStartupId(QWindow *window)
0167 {
0168     // clang-format off
0169     // TODO: move to a new KWindowSystemPrivate interface
0170 #if KWINDOWSYSTEM_HAVE_X11
0171     if (isPlatformX11()) {
0172         const QByteArray startupId = QX11Info::nextStartupId();
0173         if (!startupId.isEmpty()) {
0174             KStartupInfo::setNewStartupId(window, startupId);
0175         }
0176     } else
0177 #else
0178     Q_UNUSED(window);
0179 #endif
0180     if (isPlatformWayland()) {
0181         const QString token = qEnvironmentVariable("XDG_ACTIVATION_TOKEN");
0182         if (!token.isEmpty()) {
0183             setCurrentXdgActivationToken(token);
0184             qunsetenv("XDG_ACTIVATION_TOKEN");
0185         }
0186     }
0187     // clang-format on
0188 }
0189 
0190 void KWindowSystem::setCurrentXdgActivationToken(const QString &token)
0191 {
0192     Q_D(KWindowSystem);
0193     auto dv2 = dynamic_cast<KWindowSystemPrivateV2 *>(d);
0194     if (!dv2) {
0195         return;
0196     }
0197     dv2->setCurrentToken(token);
0198 }
0199 
0200 #include "moc_kwindowsystem.cpp"