File indexing completed on 2024-05-12 17:09:55

0001 /*
0002     SPDX-FileCopyrightText: 2010 Ivan Cukic <ivan.cukic(at)kde.org>
0003     SPDX-FileCopyrightText: 2013 Martin Klapetek <mklapetek(at)kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "splashapp.h"
0009 #include "splashwindow.h"
0010 
0011 #include <QLoggingCategory>
0012 #include <QCommandLineParser>
0013 #include <QCursor>
0014 #include <QDBusConnection>
0015 #include <QPixmap>
0016 #include <qscreen.h>
0017 
0018 #include <KWindowSystem>
0019 
0020 #include <KConfigGroup>
0021 #include <KSharedConfig>
0022 
0023 #include <LayerShellQt/Shell>
0024 
0025 Q_LOGGING_CATEGORY(ksplashqml, "org.kde.plasma.ksplashqml", QtWarningMsg)
0026 
0027 #define TEST_STEP_INTERVAL 2000
0028 
0029 /**
0030  * There are 7 stages in ksplash
0031  *  - initial (from this class)
0032  *  - startPlasma (from startplasma)
0033  *  - kcminit
0034  *  - ksmserver
0035  *  - wm (for X11 from KWin, for Wayland from this class)
0036  *  - ready (from plasma-session startup)
0037  *  - desktop (from shellcorona)
0038  */
0039 
0040 SplashApp::SplashApp(int &argc, char **argv)
0041     : QGuiApplication(argc, argv)
0042     , m_stage(0)
0043     , m_testing(false)
0044     , m_window(false)
0045 {
0046     QCommandLineParser parser;
0047     parser.addOption(QCommandLineOption(QStringLiteral("test"), QStringLiteral("Run in test mode")));
0048     parser.addOption(QCommandLineOption(QStringLiteral("window"), QStringLiteral("Run in windowed mode")));
0049     parser.addOption(QCommandLineOption(QStringLiteral("nofork"), QStringLiteral("Don't fork")));
0050     parser.addOption(QCommandLineOption(QStringLiteral("pid"), QStringLiteral("Print the pid of the child process")));
0051     parser.addPositionalArgument(QStringLiteral("theme"), QStringLiteral("Path to the theme to test"));
0052     parser.addHelpOption();
0053 
0054     parser.process(*this);
0055     m_testing = parser.isSet(QStringLiteral("test"));
0056     m_window = parser.isSet(QStringLiteral("window"));
0057     m_theme = parser.positionalArguments().value(0);
0058     if (m_theme.isEmpty()) {
0059         KConfigGroup ksplashCfg = KSharedConfig::openConfig()->group("KSplash");
0060         if (ksplashCfg.readEntry("Engine", QStringLiteral("KSplashQML")) == QLatin1String("KSplashQML")) {
0061             m_theme = ksplashCfg.readEntry("Theme", QStringLiteral("Breeze"));
0062         }
0063     }
0064 
0065     QDBusConnection dbus = QDBusConnection::sessionBus();
0066     dbus.registerObject(QStringLiteral("/KSplash"), this, QDBusConnection::ExportScriptableSlots);
0067     dbus.registerService(QStringLiteral("org.kde.KSplash"));
0068 
0069     setupWaylandIntegration();
0070 
0071     foreach (QScreen *screen, screens())
0072         adoptScreen(screen);
0073 
0074     setStage(QStringLiteral("initial"));
0075 
0076     if (KWindowSystem::isPlatformWayland()) {
0077         setStage(QStringLiteral("wm"));
0078     }
0079 
0080     if (m_testing) {
0081         m_timer.start(TEST_STEP_INTERVAL, this);
0082     }
0083 
0084     connect(this, &QGuiApplication::screenAdded, this, &SplashApp::adoptScreen);
0085 }
0086 
0087 SplashApp::~SplashApp()
0088 {
0089     qDeleteAll(m_windows);
0090 }
0091 
0092 void SplashApp::timerEvent(QTimerEvent *event)
0093 {
0094     if (event->timerId() == m_timer.timerId()) {
0095         m_timer.stop();
0096 
0097         setStage(m_stage + 1);
0098 
0099         m_timer.start(TEST_STEP_INTERVAL, this);
0100     }
0101 }
0102 
0103 void SplashApp::setStage(const QString &stage)
0104 {
0105     qCDebug(ksplashqml) << "Loading stage " << stage << ", current count " << m_stages.count();
0106 
0107     if (m_stages.contains(stage)) {
0108         return;
0109     }
0110     m_stages.append(stage);
0111     setStage(m_stages.count());
0112 }
0113 
0114 void SplashApp::setStage(int stage)
0115 {
0116     m_stage = stage;
0117     if (m_stage == 7) {
0118         QGuiApplication::exit(EXIT_SUCCESS);
0119     }
0120     foreach (SplashWindow *w, m_windows) {
0121         w->setStage(stage);
0122     }
0123 }
0124 
0125 void SplashApp::adoptScreen(QScreen *screen)
0126 {
0127     if (screen->geometry().isNull()) {
0128         return;
0129     }
0130     SplashWindow *w = new SplashWindow(m_testing, m_window, m_theme, screen);
0131     w->setGeometry(screen->geometry());
0132     w->setStage(m_stage);
0133     w->setVisible(true);
0134     m_windows << w;
0135 
0136     connect(screen, &QScreen::geometryChanged, w, &SplashWindow::setGeometry);
0137     connect(screen, &QObject::destroyed, w, [this, w]() {
0138         m_windows.removeAll(w);
0139         w->deleteLater();
0140     });
0141 }
0142 
0143 void SplashApp::setupWaylandIntegration()
0144 {
0145     if (!KWindowSystem::isPlatformWayland()) {
0146         return;
0147     }
0148     LayerShellQt::Shell::useLayerShell();
0149 }