File indexing completed on 2024-05-12 05:37:59

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 "debug.h"
0010 #include "splashwindow.h"
0011 
0012 #include <QCommandLineParser>
0013 #include <QCursor>
0014 #include <QDBusConnection>
0015 #include <QLoggingCategory>
0016 #include <QPixmap>
0017 #include <qscreen.h>
0018 
0019 #include <KWindowSystem>
0020 
0021 #include <KConfigGroup>
0022 #include <KSharedConfig>
0023 
0024 #include <LayerShellQt/Shell>
0025 
0026 #define TEST_STEP_INTERVAL 2000
0027 
0028 /**
0029  * There are 7 stages in ksplash
0030  *  - initial (from this class)
0031  *  - startPlasma (from startplasma)
0032  *  - kcminit
0033  *  - ksmserver
0034  *  - wm (for X11 from KWin, for Wayland from this class)
0035  *  - ready (from plasma-session startup)
0036  *  - desktop (from shellcorona)
0037  */
0038 
0039 SplashApp::SplashApp(int &argc, char **argv)
0040     : QGuiApplication(argc, argv)
0041     , m_stage(0)
0042     , m_testing(false)
0043     , m_window(false)
0044 {
0045     QCommandLineParser parser;
0046     parser.addOption(QCommandLineOption(QStringLiteral("test"), QStringLiteral("Run in test mode")));
0047     parser.addOption(QCommandLineOption(QStringLiteral("window"), QStringLiteral("Run in windowed mode")));
0048     parser.addOption(QCommandLineOption(QStringLiteral("nofork"), QStringLiteral("Don't fork")));
0049     parser.addOption(QCommandLineOption(QStringLiteral("pid"), QStringLiteral("Print the pid of the child process")));
0050     parser.addPositionalArgument(QStringLiteral("theme"), QStringLiteral("Path to the theme to test"));
0051     parser.addHelpOption();
0052 
0053     parser.process(*this);
0054     m_testing = parser.isSet(QStringLiteral("test"));
0055     m_window = parser.isSet(QStringLiteral("window"));
0056     m_theme = parser.positionalArguments().value(0);
0057     if (m_theme.isEmpty()) {
0058         KConfigGroup ksplashCfg = KSharedConfig::openConfig()->group(QStringLiteral("KSplash"));
0059         if (ksplashCfg.readEntry("Engine", QStringLiteral("KSplashQML")) == QLatin1String("KSplashQML")) {
0060             m_theme = ksplashCfg.readEntry("Theme", QStringLiteral("Breeze"));
0061         }
0062     }
0063 
0064     QDBusConnection dbus = QDBusConnection::sessionBus();
0065     dbus.registerObject(QStringLiteral("/KSplash"), this, QDBusConnection::ExportScriptableSlots);
0066     dbus.registerService(QStringLiteral("org.kde.KSplash"));
0067 
0068     setupWaylandIntegration();
0069 
0070     for (const auto screenList{screens()}; QScreen * screen : screenList) {
0071         adoptScreen(screen);
0072     }
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_DEBUG) << "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     for (SplashWindow *w : std::as_const(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 }