File indexing completed on 2024-11-10 04:57:05

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0006     SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "integration.h"
0012 #include "backingstore.h"
0013 #include "eglplatformcontext.h"
0014 #include "logging.h"
0015 #include "offscreensurface.h"
0016 #include "screen.h"
0017 #include "window.h"
0018 
0019 #include "core/output.h"
0020 #include "core/outputbackend.h"
0021 #include "main.h"
0022 #include "workspace.h"
0023 
0024 #include <QCoreApplication>
0025 #include <QTimer>
0026 #include <QtConcurrentRun>
0027 
0028 #include <qpa/qplatformaccessibility.h>
0029 #include <qpa/qplatformnativeinterface.h>
0030 #include <qpa/qplatformwindow.h>
0031 #include <qpa/qwindowsysteminterface.h>
0032 
0033 #include <QtGui/private/qgenericunixeventdispatcher_p.h>
0034 #include <QtGui/private/qgenericunixfontdatabase_p.h>
0035 #include <QtGui/private/qgenericunixthemes_p.h>
0036 #include <QtGui/private/qspiaccessiblebridge_p.h>
0037 #include <QtGui/private/qunixeventdispatcher_qpa_p.h>
0038 
0039 namespace KWin
0040 {
0041 
0042 namespace QPA
0043 {
0044 
0045 Integration::Integration()
0046     : QObject()
0047     , QPlatformIntegration()
0048     , m_fontDb(new QGenericUnixFontDatabase())
0049     , m_nativeInterface(new QPlatformNativeInterface())
0050     , m_services(new QGenericUnixServices())
0051 {
0052 }
0053 
0054 Integration::~Integration()
0055 {
0056     for (QPlatformScreen *platformScreen : std::as_const(m_screens)) {
0057         QWindowSystemInterface::handleScreenRemoved(platformScreen);
0058     }
0059     if (m_dummyScreen) {
0060         QWindowSystemInterface::handleScreenRemoved(m_dummyScreen);
0061     }
0062 }
0063 
0064 QHash<Output *, Screen *> Integration::screens() const
0065 {
0066     return m_screens;
0067 }
0068 
0069 bool Integration::hasCapability(Capability cap) const
0070 {
0071     switch (cap) {
0072     case ThreadedPixmaps:
0073         return true;
0074     case OpenGL:
0075         return true;
0076     case ThreadedOpenGL:
0077         return false;
0078     case BufferQueueingOpenGL:
0079         return false;
0080     case MultipleWindows:
0081     case NonFullScreenWindows:
0082         return true;
0083     case RasterGLSurface:
0084         return false;
0085     default:
0086         return QPlatformIntegration::hasCapability(cap);
0087     }
0088 }
0089 
0090 void Integration::initialize()
0091 {
0092     // This method is called from QGuiApplication's constructor, before kwinApp is built
0093     QTimer::singleShot(0, this, [this] {
0094         // The QPA is initialized before the workspace is created.
0095         if (workspace()) {
0096             handleWorkspaceCreated();
0097         } else {
0098             connect(kwinApp(), &Application::workspaceCreated, this, &Integration::handleWorkspaceCreated);
0099         }
0100     });
0101 
0102     QPlatformIntegration::initialize();
0103 
0104     m_dummyScreen = new PlaceholderScreen();
0105     QWindowSystemInterface::handleScreenAdded(m_dummyScreen);
0106 }
0107 
0108 QAbstractEventDispatcher *Integration::createEventDispatcher() const
0109 {
0110     return new QUnixEventDispatcherQPA;
0111 }
0112 
0113 QPlatformBackingStore *Integration::createPlatformBackingStore(QWindow *window) const
0114 {
0115     return new BackingStore(window);
0116 }
0117 
0118 QPlatformWindow *Integration::createPlatformWindow(QWindow *window) const
0119 {
0120     return new Window(window);
0121 }
0122 
0123 QPlatformOffscreenSurface *Integration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
0124 {
0125     return new OffscreenSurface(surface);
0126 }
0127 
0128 QPlatformFontDatabase *Integration::fontDatabase() const
0129 {
0130     return m_fontDb.get();
0131 }
0132 
0133 QPlatformTheme *Integration::createPlatformTheme(const QString &name) const
0134 {
0135     return QGenericUnixTheme::createUnixTheme(name);
0136 }
0137 
0138 QStringList Integration::themeNames() const
0139 {
0140     if (qEnvironmentVariableIsSet("KDE_FULL_SESSION")) {
0141         return QStringList({QStringLiteral("kde")});
0142     }
0143     return QStringList({QLatin1String(QGenericUnixTheme::name)});
0144 }
0145 
0146 QPlatformOpenGLContext *Integration::createPlatformOpenGLContext(QOpenGLContext *context) const
0147 {
0148     if (kwinApp()->outputBackend()->sceneEglGlobalShareContext() == EGL_NO_CONTEXT) {
0149         qCWarning(KWIN_QPA) << "Attempting to create a QOpenGLContext before the scene is initialized";
0150         return nullptr;
0151     }
0152     EglDisplay *const eglDisplay = kwinApp()->outputBackend()->sceneEglDisplayObject();
0153     if (eglDisplay) {
0154         EGLPlatformContext *platformContext = new EGLPlatformContext(context, eglDisplay);
0155         return platformContext;
0156     }
0157     return nullptr;
0158 }
0159 
0160 QPlatformAccessibility *Integration::accessibility() const
0161 {
0162     if (!m_accessibility) {
0163         m_accessibility.reset(new QSpiAccessibleBridge());
0164     }
0165     return m_accessibility.get();
0166 }
0167 
0168 void Integration::handleWorkspaceCreated()
0169 {
0170     connect(workspace(), &Workspace::outputAdded,
0171             this, &Integration::handleOutputEnabled);
0172     connect(workspace(), &Workspace::outputRemoved,
0173             this, &Integration::handleOutputDisabled);
0174 
0175     const QList<Output *> outputs = workspace()->outputs();
0176     for (Output *output : outputs) {
0177         handleOutputEnabled(output);
0178     }
0179 }
0180 
0181 void Integration::handleOutputEnabled(Output *output)
0182 {
0183     Screen *platformScreen = new Screen(output, this);
0184     QWindowSystemInterface::handleScreenAdded(platformScreen);
0185     m_screens.insert(output, platformScreen);
0186 
0187     if (m_dummyScreen) {
0188         QWindowSystemInterface::handleScreenRemoved(m_dummyScreen);
0189         m_dummyScreen = nullptr;
0190     }
0191 }
0192 
0193 void Integration::handleOutputDisabled(Output *output)
0194 {
0195     Screen *platformScreen = m_screens.take(output);
0196     if (!platformScreen) {
0197         qCWarning(KWIN_QPA) << "Unknown output" << output;
0198         return;
0199     }
0200 
0201     if (m_screens.isEmpty()) {
0202         m_dummyScreen = new PlaceholderScreen();
0203         QWindowSystemInterface::handleScreenAdded(m_dummyScreen);
0204     }
0205 
0206     QWindowSystemInterface::handleScreenRemoved(platformScreen);
0207 }
0208 
0209 QPlatformNativeInterface *Integration::nativeInterface() const
0210 {
0211     return m_nativeInterface.get();
0212 }
0213 
0214 QPlatformServices *Integration::services() const
0215 {
0216     return m_services.get();
0217 }
0218 
0219 }
0220 }
0221 
0222 #include "moc_integration.cpp"