File indexing completed on 2024-05-19 05:39:08
0001 /* 0002 SPDX-FileCopyrightText: 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <config-workspace.h> 0008 0009 #include "main.h" 0010 0011 #include <unistd.h> 0012 0013 #include <KFileUtils> 0014 #include <QDBusConnection> 0015 #include <QDBusMessage> 0016 #include <QDBusPendingCall> 0017 #include <QDebug> 0018 #include <QFile> 0019 #include <QGuiApplication> 0020 #include <QLibrary> 0021 #include <QPluginLoader> 0022 #include <QTimer> 0023 0024 #include <KAboutData> 0025 #include <KConfig> 0026 #include <KConfigGroup> 0027 #include <KLocalizedString> 0028 0029 static int ready[2]; 0030 static bool startup = false; 0031 0032 static void sendReady() 0033 { 0034 if (ready[1] == -1) 0035 return; 0036 char c = 0; 0037 write(ready[1], &c, 1); 0038 close(ready[1]); 0039 ready[1] = -1; 0040 } 0041 0042 static void waitForReady() 0043 { 0044 char c = 1; 0045 close(ready[1]); 0046 read(ready[0], &c, 1); 0047 close(ready[0]); 0048 } 0049 0050 bool KCMInit::runModule(const KPluginMetaData &data) 0051 { 0052 QString path = QPluginLoader(data.fileName()).fileName(); 0053 0054 // get the kcminit_ function 0055 QFunctionPointer init = QLibrary::resolve(path, "kcminit"); 0056 if (!init) { 0057 qWarning() << "Module" << data.fileName() << "does not actually have a kcminit function"; 0058 return false; 0059 } 0060 0061 // initialize the module 0062 qDebug() << "Initializing " << data.fileName(); 0063 init(); 0064 return true; 0065 } 0066 0067 void KCMInit::runModules(int phase) 0068 { 0069 for (const KPluginMetaData &data : std::as_const(m_list)) { 0070 // see ksmserver's README for the description of the phases 0071 int libphase = data.value(QStringLiteral("X-KDE-Init-Phase"), 1); 0072 0073 if (libphase > 1) { 0074 libphase = 1; 0075 } 0076 0077 if (phase != -1 && libphase != phase) 0078 continue; 0079 0080 // try to load the library 0081 if (!m_alreadyInitialized.contains(data.pluginId())) { 0082 runModule(data); 0083 m_alreadyInitialized.append(data.pluginId()); 0084 } 0085 } 0086 } 0087 0088 KCMInit::KCMInit(const QCommandLineParser &args) 0089 { 0090 if (args.isSet(QStringLiteral("list"))) { 0091 m_list = KPluginMetaData::findPlugins(QStringLiteral("plasma/kcminit")); 0092 for (const KPluginMetaData &data : std::as_const(m_list)) { 0093 printf("%s\n", QFile::encodeName(data.fileName()).data()); 0094 } 0095 return; 0096 } 0097 0098 const auto positionalArguments = args.positionalArguments(); 0099 if (!positionalArguments.isEmpty()) { 0100 for (const auto &arg : positionalArguments) { 0101 KPluginMetaData data(arg); 0102 if (!data.isValid()) { 0103 data = KPluginMetaData::findPluginById(QStringLiteral("plasma/kcminit"), arg); 0104 } 0105 0106 if (data.isValid()) { 0107 m_list << data.fileName(); 0108 } else { 0109 qWarning() << "Could not find" << arg; 0110 } 0111 } 0112 } else { 0113 m_list = KPluginMetaData::findPlugins(QStringLiteral("plasma/kcminit")); 0114 } 0115 0116 if (startup) { 0117 runModules(0); 0118 // Tell KSplash that KCMInit has started 0119 QDBusMessage ksplashProgressMessage = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KSplash"), 0120 QStringLiteral("/KSplash"), 0121 QStringLiteral("org.kde.KSplash"), 0122 QStringLiteral("setStage")); 0123 ksplashProgressMessage.setArguments(QList<QVariant>() << QStringLiteral("kcminit")); 0124 QDBusConnection::sessionBus().asyncCall(ksplashProgressMessage); 0125 0126 sendReady(); 0127 QTimer::singleShot(300 * 1000, qApp, &QCoreApplication::quit); // just in case 0128 0129 QDBusConnection::sessionBus().registerObject(QStringLiteral("/kcminit"), this, QDBusConnection::ExportScriptableContents); 0130 QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.kcminit")); 0131 0132 qApp->exec(); // wait for runPhase1() 0133 } else 0134 runModules(-1); // all phases 0135 } 0136 0137 KCMInit::~KCMInit() 0138 { 0139 sendReady(); 0140 } 0141 0142 void KCMInit::runPhase1() 0143 { 0144 runModules(1); 0145 qApp->exit(0); 0146 } 0147 0148 int main(int argc, char *argv[]) 0149 { 0150 // plasma-session startup waits for kcminit to finish running phase 0 kcms 0151 // (theoretically that is only important kcms that need to be started very 0152 // early in the login process), the rest is delayed, so fork and make parent 0153 // return after the initial phase 0154 pipe(ready); 0155 if (fork() != 0) { 0156 waitForReady(); 0157 return 0; 0158 } 0159 close(ready[0]); 0160 0161 const QString executableName = QString::fromUtf8(argv[0]); 0162 startup = executableName.endsWith(QLatin1String("kcminit_startup")); // started from startkde? 0163 0164 QGuiApplication::setDesktopSettingsAware(false); 0165 QGuiApplication app(argc, argv); // gui is needed for several modules 0166 KLocalizedString::setApplicationDomain(QByteArrayLiteral("kcminit")); 0167 KAboutData about(QStringLiteral("kcminit"), 0168 i18n("KCMInit"), 0169 QString(), 0170 i18n("KCMInit - runs startup initialization for Control Modules."), 0171 KAboutLicense::GPL); 0172 KAboutData::setApplicationData(about); 0173 0174 QCommandLineParser parser; 0175 about.setupCommandLine(&parser); 0176 parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("list"), i18n("List modules that are run at startup"))); 0177 parser.addPositionalArgument(QStringLiteral("module"), i18n("Configuration module to run")); 0178 0179 parser.process(app); 0180 about.processCommandLine(&parser); 0181 0182 KCMInit kcminit(parser); 0183 return 0; 0184 }