KCMUtils

main.cpp
1/*
2 SPDX-FileCopyrightText: 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
3 SPDX-FileCopyrightText: 2000 Matthias Elter <elter@kde.org>
4 SPDX-FileCopyrightText: 2004 Frans Englich <frans.englich@telia.com>
5 SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8
9*/
10
11#include <QApplication>
12#include <QCommandLineOption>
13#include <QCommandLineParser>
14#include <QDebug>
15#include <QIcon>
16#include <QRegularExpression>
17#include <QStandardPaths>
18
19#include <KAboutData>
20#include <KAuthorized>
21#include <KCModule>
22#include <KCMultiDialog>
23#include <KLocalizedString>
24#include <KPageDialog>
25#include <KPluginMetaData>
26#include <KShell>
27#include <kcmutils_debug.h>
28
29#if __has_include(<KStartupInfo>)
30#include <KStartupInfo>
31#include <private/qtx11extras_p.h>
32#define HAVE_X11 1
33#endif
34
35#if !defined(Q_OS_WINDOWS) && !defined(Q_OS_MAC)
36#include <QDBusConnection>
37#include <QDBusConnectionInterface>
38#endif
39
40#include <algorithm>
41#include <iostream>
42
43inline QList<KPluginMetaData> findKCMsMetaData()
44{
45 QList<KPluginMetaData> metaDataList = KPluginMetaData::findPlugins(QStringLiteral("plasma/kcms"));
46 metaDataList << KPluginMetaData::findPlugins(QStringLiteral("plasma/kcms/systemsettings"));
47 metaDataList << KPluginMetaData::findPlugins(QStringLiteral("plasma/kcms/systemsettings_qwidgets"));
48 metaDataList << KPluginMetaData::findPlugins(QStringLiteral("plasma/kcms/kinfocenter"));
49 return metaDataList;
50}
51
52class KCMShellMultiDialog : public KCMultiDialog
53{
55
56public:
57 /**
58 * Constructor. Parameter @p dialogFace is passed to KCMultiDialog
59 * unchanged.
60 */
61 explicit KCMShellMultiDialog(KPageDialog::FaceType dialogFace)
63 {
65 setModal(false);
66
67#if !defined(Q_OS_WINDOWS) && !defined(Q_OS_MAC)
69 if (KCModule *activeModule = newPage->widget()->findChild<KCModule *>()) {
70 if (QDBusConnection::sessionBus().isConnected()
71 && QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.ActivityManager"))) {
72 QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.ActivityManager"),
73 QStringLiteral("/ActivityManager/Resources"),
74 QStringLiteral("org.kde.ActivityManager.Resources"),
75 QStringLiteral("RegisterResourceEvent"));
76
77 const QString appId = QStringLiteral("org.kde.systemsettings");
78 const uint winId = 0;
79 const QString url = QLatin1String("kcm:") + activeModule->metaData().pluginId();
80 const uint eventType = 0; // Accessed
81
82 msg.setArguments({appId, winId, url, eventType});
83
84 QDBusConnection::sessionBus().asyncCall(msg);
85 }
86 }
87 });
88#endif
89 }
90};
91
92int main(int argc, char *argv[])
93{
94 const bool qpaVariable = qEnvironmentVariableIsSet("QT_QPA_PLATFORM");
95 QApplication app(argc, argv);
96 if (!qpaVariable) {
97 // don't leak the env variable to processes we start
98 qunsetenv("QT_QPA_PLATFORM");
99 }
101 KAboutData aboutData(QStringLiteral("kcmshell6"),
102 QString(),
103 QLatin1String(PROJECT_VERSION),
104 i18n("A tool to start single system settings modules"),
106 i18n("(c) 1999-2023, The KDE Developers"));
107
108 aboutData.addAuthor(i18n("Frans Englich"), i18n("Maintainer"), QStringLiteral("frans.englich@kde.org"));
109 aboutData.addAuthor(i18n("Daniel Molkentin"), QString(), QStringLiteral("molkentin@kde.org"));
110 aboutData.addAuthor(i18n("Matthias Hoelzer-Kluepfel"), QString(), QStringLiteral("hoelzer@kde.org"));
111 aboutData.addAuthor(i18n("Matthias Elter"), QString(), QStringLiteral("elter@kde.org"));
112 aboutData.addAuthor(i18n("Matthias Ettrich"), QString(), QStringLiteral("ettrich@kde.org"));
113 aboutData.addAuthor(i18n("Waldo Bastian"), QString(), QStringLiteral("bastian@kde.org"));
115
116 QCommandLineParser parser;
117 aboutData.setupCommandLine(&parser);
118
119 parser.addOption(QCommandLineOption(QStringLiteral("list"), i18n("List all possible modules")));
120 parser.addPositionalArgument(QStringLiteral("module"), i18n("Configuration module to open"));
121 parser.addOption(QCommandLineOption(QStringLiteral("args"), i18n("Space separated arguments for the module"), QLatin1String("arguments")));
122 parser.addOption(QCommandLineOption(QStringLiteral("icon"), i18n("Use a specific icon for the window"), QLatin1String("icon")));
123 parser.addOption(QCommandLineOption(QStringLiteral("caption"), i18n("Use a specific caption for the window"), QLatin1String("caption")));
124 parser.addOption(QCommandLineOption(QStringLiteral("highlight"), i18n("Show an indicator when settings have changed from their default value")));
125
126 parser.parse(app.arguments());
127 aboutData.processCommandLine(&parser);
128
129 parser.process(app);
130
131 if (parser.isSet(QStringLiteral("list"))) {
132 std::cout << i18n("The following modules are available:").toLocal8Bit().constData() << '\n';
133
134 QList<KPluginMetaData> plugins = findKCMsMetaData();
135 int maxLen = 0;
136
137 for (const auto &plugin : plugins) {
138 const int len = plugin.pluginId().size();
139 maxLen = std::max(maxLen, len);
140 }
141
142 for (const auto &plugin : plugins) {
143 QString comment = plugin.description();
144 if (comment.isEmpty()) {
145 comment = i18n("No description available");
146 }
147
148 const QString entry = QStringLiteral("%1 - %2").arg(plugin.pluginId().leftJustified(maxLen, QLatin1Char(' ')), comment);
149
150 std::cout << entry.toLocal8Bit().constData() << '\n';
151 }
152
153 std::cout << std::endl;
154
155 return 0;
156 }
157
158 if (parser.positionalArguments().isEmpty()) {
159 parser.showHelp();
160 return -1;
161 }
162
163 QList<KPluginMetaData> metaDataList;
164
165 QStringList args = parser.positionalArguments();
166 args.removeDuplicates();
167 for (const QString &arg : args) {
169 metaDataList << data;
170 } else {
171 // Look in the namespaces for systemsettings/kinfocenter
172 const static auto knownKCMs = findKCMsMetaData();
173 const QStringList possibleIds{arg, QStringLiteral("kcm_") + arg, QStringLiteral("kcm") + arg};
174 bool found = std::any_of(knownKCMs.begin(), knownKCMs.end(), [&possibleIds, &metaDataList](const KPluginMetaData &data) {
175 bool idMatches = possibleIds.contains(data.pluginId());
176 if (idMatches) {
177 metaDataList << data;
178 }
179 return idMatches;
180 });
181 if (!found) {
182 metaDataList << KPluginMetaData(arg); // So that we show an error message in the dialog
183 qCWarning(KCMUTILS_LOG) << "Could not find KCM with given Id" << arg;
184 }
185 }
186 }
187 if (metaDataList.isEmpty()) {
188 return -1;
189 }
190
191 const bool multipleKCMs = metaDataList.size() > 1;
193 auto dlg = new KCMShellMultiDialog(ftype);
194 dlg->setAttribute(Qt::WA_DeleteOnClose);
195
196 if (parser.isSet(QStringLiteral("caption"))) {
197 dlg->setWindowTitle(parser.value(QStringLiteral("caption")));
198 } else if (!multipleKCMs) { // We will have the "Configure" window title set by KCMultiDialog
199 dlg->setWindowTitle(metaDataList.constFirst().name());
200 }
201
202 const QStringList argSplit = KShell::splitArgs(parser.value(QStringLiteral("args")));
203 QVariantList pluginArgs(argSplit.begin(), argSplit.end());
204 if (metaDataList.size() == 1) {
205 KPageWidgetItem *item = dlg->addModule(*metaDataList.cbegin(), pluginArgs);
206 // This makes sure the content area is focused by default
208 } else {
209 for (const KPluginMetaData &m : std::as_const(metaDataList)) {
210 dlg->addModule(m, pluginArgs);
211 }
212 }
213
214 if (parser.isSet(QStringLiteral("icon"))) {
215 dlg->setWindowIcon(QIcon::fromTheme(parser.value(QStringLiteral("icon"))));
216 } else {
217 dlg->setWindowIcon(QIcon::fromTheme(metaDataList.constFirst().iconName()));
218 }
219
220 if (parser.isSet(QStringLiteral("highlight"))) {
221 dlg->setDefaultsIndicatorsVisible(true);
222 }
223
224 if (app.desktopFileName() == QLatin1String("org.kde.kcmshell6")) {
225 const QString path = metaDataList.constFirst().fileName();
226
227 if (path.endsWith(QLatin1String(".desktop"))) {
228 app.setDesktopFileName(path);
229 } else {
230 app.setDesktopFileName(metaDataList.constFirst().pluginId());
231 }
232 }
233
234 dlg->show();
235
236 app.exec();
237
238 return 0;
239}
240
241#include "main.moc"
static void setApplicationData(const KAboutData &aboutData)
The base class for QWidgets configuration modules.
Definition kcmodule.h:59
A class that offers a KPageDialog containing config modules.
static void setApplicationDomain(const QByteArray &domain)
void currentPageChanged(KPageWidgetItem *current, KPageWidgetItem *before)
void setFaceType(FaceType faceType)
QWidget * widget() const
static QList< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter={}, KPluginMetaDataOptions options={})
bool isValid() const
QString i18n(const char *text, const TYPE &arg...)
QString path(const QString &relativePath)
KCOREADDONS_EXPORT QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=nullptr)
const char * constData() const const
bool addOption(const QCommandLineOption &option)
void addPositionalArgument(const QString &name, const QString &description, const QString &syntax)
bool isSet(const QCommandLineOption &option) const const
bool parse(const QStringList &arguments)
QStringList positionalArguments() const const
void process(const QCoreApplication &app)
void showHelp(int exitCode)
QString value(const QCommandLineOption &option) const const
void setModal(bool modal)
QIcon fromTheme(const QString &name)
iterator begin()
const_iterator cbegin() const const
const T & constFirst() const const
iterator end()
bool isEmpty() const const
qsizetype size() const const
Q_OBJECTQ_OBJECT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T findChild(const QString &name, Qt::FindChildOptions options) const const
QList< T > findChildren(Qt::FindChildOptions options) const const
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QByteArray toLocal8Bit() const const
qsizetype removeDuplicates()
MouseFocusReason
WA_DeleteOnClose
void setFocus()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:56 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.