File indexing completed on 2024-11-10 04:56:48

0001 /*
0002     SPDX-FileCopyrightText: 2021 Dan Leinir Turthra Jensen <admin@leinir.dk>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "kwindecorationsettings.h"
0008 
0009 #include "decorationmodel.h"
0010 
0011 #include <KLocalizedString>
0012 
0013 #include <QCommandLineParser>
0014 #include <QCoreApplication>
0015 #include <QDBusConnection>
0016 #include <QDBusMessage>
0017 #include <QDebug>
0018 #include <QFileInfo>
0019 #include <QTimer>
0020 
0021 int main(int argc, char **argv)
0022 {
0023     QCoreApplication app(argc, argv);
0024     int exitCode{0};
0025     QCoreApplication::setApplicationName(QStringLiteral("kwin-applywindowdecoration"));
0026     QCoreApplication::setApplicationVersion(QStringLiteral("1.0"));
0027     QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
0028     KLocalizedString::setApplicationDomain(QByteArrayLiteral("kwin-applywindowdecoration"));
0029 
0030     QCommandLineParser *parser = new QCommandLineParser;
0031     parser->addHelpOption();
0032     parser->setApplicationDescription(i18n("This tool allows you to set the window decoration theme for the currently active session, without accidentally setting it to one that is either not available, or which is already set."));
0033     parser->addPositionalArgument(QStringLiteral("theme"), i18n("The name of the window decoration theme you wish to set for KWin. Passing a full path will attempt to find a theme in that directory, and then apply that if one can be deduced."));
0034     parser->addOption(QCommandLineOption(QStringLiteral("list-themes"), i18n("Show all the themes available on the system (and which is the current theme)")));
0035     parser->process(app);
0036 
0037     KDecoration2::Configuration::DecorationsModel *model = new KDecoration2::Configuration::DecorationsModel(&app);
0038     model->init();
0039     KWinDecorationSettings *settings = new KWinDecorationSettings(&app);
0040     QTextStream ts(stdout);
0041     if (!parser->positionalArguments().isEmpty()) {
0042         QString requestedTheme{parser->positionalArguments().constFirst()};
0043         if (requestedTheme.endsWith(QStringLiteral("/*"))) {
0044             // Themes installed through KNewStuff will commonly be given an installed files entry
0045             // which has the main directory name and an asterix to say the cursors are all in that directory,
0046             // and since one of the main purposes of this tool is to allow adopting things from a kns dialog,
0047             // we handle that little weirdness here.
0048             requestedTheme.remove(requestedTheme.length() - 2, 2);
0049         }
0050 
0051         bool themeResolved{true};
0052         if (requestedTheme.contains(QStringLiteral("/"))) {
0053             themeResolved = false;
0054             if (QFileInfo::exists(requestedTheme) && QFileInfo(requestedTheme).isDir()) {
0055                 // Since this is the name of a directory, let's do a bit of checking to see
0056                 // if we know enough about it to deduce that this is, in fact, a theme.
0057                 QStringList splitTheme = requestedTheme.split(QStringLiteral("/"), Qt::SkipEmptyParts);
0058                 if (splitTheme.count() > 3 && splitTheme[splitTheme.count() - 3] == QStringLiteral("aurorae") && splitTheme[splitTheme.count() - 2] == QStringLiteral("themes")) {
0059                     // We think this is an aurorae theme, but let's just make a little more certain...
0060                     QString file(QStringLiteral("aurorae/themes/%1/metadata.desktop").arg(splitTheme.last()));
0061                     QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, file);
0062                     if (!path.isEmpty() && path == QStringLiteral("%1/metadata.desktop").arg(requestedTheme)) {
0063                         requestedTheme = QString("__aurorae__svg__").append(splitTheme.last());
0064                         themeResolved = true;
0065                         ts << i18n("Resolved %1 to the KWin Aurorae theme \"%2\", and will attempt to set that as your current theme.")
0066                                   .arg(parser->positionalArguments().first(), requestedTheme)
0067                            << Qt::endl;
0068                     }
0069                 }
0070             } else {
0071                 ts << i18n("You attempted to pass a file path, but this could not be resolved to a theme, and we will have to abort, due to having no theme to set") << Qt::endl;
0072                 exitCode = -1;
0073             }
0074         }
0075 
0076         if (settings->theme() == requestedTheme) {
0077             ts << i18n("The requested theme \"%1\" is already set as the window decoration theme.", requestedTheme) << Qt::endl;
0078             // not an error condition, just nothing happens
0079         } else if (themeResolved) {
0080             int index{-1};
0081             QStringList availableThemes;
0082             for (int i = 0; i < model->rowCount(); ++i) {
0083                 const QString themeName = model->data(model->index(i), KDecoration2::Configuration::DecorationsModel::ThemeNameRole).toString();
0084                 if (requestedTheme == themeName) {
0085                     index = i;
0086                     break;
0087                 }
0088                 availableThemes << themeName;
0089             }
0090             if (index > -1) {
0091                 settings->setTheme(model->data(model->index(index), KDecoration2::Configuration::DecorationsModel::ThemeNameRole).toString());
0092                 settings->setPluginName(model->data(model->index(index), KDecoration2::Configuration::DecorationsModel::PluginNameRole).toString());
0093                 if (settings->save()) {
0094                     // Send a signal to all kwin instances
0095                     QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
0096                                                                       QStringLiteral("org.kde.KWin"),
0097                                                                       QStringLiteral("reloadConfig"));
0098                     QDBusConnection::sessionBus().send(message);
0099                     ts << i18n("Successfully applied the cursor theme %1 to your current Plasma session",
0100                                model->data(model->index(index), KDecoration2::Configuration::DecorationsModel::ThemeNameRole).toString())
0101                        << Qt::endl;
0102                 } else {
0103                     ts << i18n("Failed to save your theme settings - the reason is unknown, but this is an unrecoverable error. You may find that simply trying again will work.");
0104                     exitCode = -1;
0105                 }
0106             } else {
0107                 ts << i18n("Could not find theme \"%1\". The theme should be one of the following options: %2", requestedTheme, availableThemes.join(QStringLiteral(", "))) << Qt::endl;
0108                 exitCode = -1;
0109             }
0110         }
0111     } else if (parser->isSet(QStringLiteral("list-themes"))) {
0112         ts << i18n("You have the following KWin window decoration themes on your system:") << Qt::endl;
0113         for (int i = 0; i < model->rowCount(); ++i) {
0114             const QString displayName = model->data(model->index(i), Qt::DisplayRole).toString();
0115             const QString themeName = model->data(model->index(i), KDecoration2::Configuration::DecorationsModel::ThemeNameRole).toString();
0116             if (settings->theme() == themeName) {
0117                 ts << QStringLiteral(" * %1 (theme name: %2 - current theme for this Plasma session)").arg(displayName, themeName) << Qt::endl;
0118             } else {
0119                 ts << QStringLiteral(" * %1 (theme name: %2)").arg(displayName, themeName) << Qt::endl;
0120             }
0121         }
0122     } else {
0123         parser->showHelp();
0124     }
0125     QTimer::singleShot(0, &app, [&app, &exitCode]() {
0126         app.exit(exitCode);
0127     });
0128 
0129     return app.exec();
0130 }