File indexing completed on 2024-05-05 05:38:20

0001 /*
0002     SPDX-FileCopyrightText: 2012 Marco Martin <mart@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include <KLocalizedString>
0008 #include <QApplication>
0009 
0010 #include <QAction>
0011 #include <QCommandLineParser>
0012 #include <QDBusConnection>
0013 #include <QDBusMessage>
0014 #include <QDebug>
0015 #include <QQuickWindow>
0016 #include <QSessionManager>
0017 #include <QSurfaceFormat>
0018 #include <QUrl>
0019 
0020 #include <KAboutData>
0021 #include <KAuthorized>
0022 #include <KDBusService>
0023 #include <KRunner/RunnerManager>
0024 
0025 #include <PlasmaQuick/SharedQmlEngine>
0026 
0027 #include <iostream>
0028 #include <qqmlengine.h>
0029 
0030 #include "view.h"
0031 
0032 using namespace Qt::StringLiterals;
0033 
0034 int main(int argc, char **argv)
0035 {
0036     auto format = QSurfaceFormat::defaultFormat();
0037     format.setOption(QSurfaceFormat::ResetNotification);
0038     QSurfaceFormat::setDefaultFormat(format);
0039 
0040     QCommandLineParser parser;
0041 
0042     // this is needed to fake window position so Plasma Dialog sets correct borders
0043     qputenv("QT_WAYLAND_DISABLE_FIXED_POSITIONS", {});
0044     // this variable controls whether to reconnect or exit if the compositor dies, given plasmashell does a lot of
0045     // bespoke wayland code disable for now. Consider re-enabling when layer-shell support lands
0046     qunsetenv("QT_WAYLAND_RECONNECT");
0047     QQuickWindow::setDefaultAlphaBuffer(true);
0048     QApplication app(argc, argv);
0049     qunsetenv("QT_WAYLAND_DISABLE_FIXED_POSITIONS");
0050     qputenv("QT_WAYLAND_RECONNECT", "1");
0051 
0052     KLocalizedString::setApplicationDomain(QByteArrayLiteral("krunner"));
0053 
0054     //     TODO: Make it a QGuiApplication once we don't depend on KDELibs4Support
0055     //     QGuiApplication app(argc, argv);
0056 
0057     KAboutData aboutData(u"krunner"_s, i18n("KRunner"), QStringLiteral(PROJECT_VERSION), i18n("Run Command interface"), KAboutLicense::GPL);
0058 
0059     KAboutData::setApplicationData(aboutData);
0060     app.setQuitOnLastWindowClosed(false);
0061     app.setQuitLockEnabled(false);
0062 
0063     QCommandLineOption clipboardOption({u"c"_s, u"clipboard"_s}, i18n("Use the clipboard contents as query for KRunner"));
0064     QCommandLineOption daemonOption({u"d"_s, u"daemon"_s}, i18n("Start KRunner in the background, don't show it."));
0065     QCommandLineOption replaceOption({u"replace"_s}, i18n("Replace an existing instance"));
0066     QCommandLineOption runnerId({u"runner"_s}, i18n("Show only results from the given plugin"), u"runner"_s);
0067     QCommandLineOption listOption({u"list"_s}, i18n("List available plugins"));
0068 
0069     parser.addOption(clipboardOption);
0070     parser.addOption(daemonOption);
0071     parser.addOption(replaceOption);
0072     parser.addOption(runnerId);
0073     parser.addOption(listOption);
0074     parser.addPositionalArgument(u"query"_s, i18n("The query to run, only used if -c is not provided"));
0075 
0076     aboutData.setupCommandLine(&parser);
0077 
0078     parser.process(app);
0079     aboutData.processCommandLine(&parser);
0080 
0081     if (parser.isSet(listOption)) {
0082         const auto runners = KRunner::RunnerManager::runnerMetaDataList();
0083         const QString headline = i18nc("Header for command line output", "Available KRunner plugins, pluginId");
0084         QString separator;
0085         separator.fill(u'-', headline.length());
0086         std::cout << qPrintable(headline) << std::endl << qPrintable(separator) << std::endl;
0087         for (const auto &data : runners) {
0088             std::cout << qPrintable(data.name()) << ": " << qPrintable(data.pluginId()) << std::endl;
0089         }
0090         return 0;
0091     }
0092 
0093     if (!KAuthorized::authorize(u"run_command"_s)) {
0094         return -1;
0095     }
0096 
0097     KDBusService service(KDBusService::Unique | KDBusService::StartupOption(parser.isSet(replaceOption) ? KDBusService::Replace : 0));
0098 
0099     auto disableSessionManagement = [](QSessionManager &sm) {
0100         sm.setRestartHint(QSessionManager::RestartNever);
0101     };
0102     QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement);
0103     QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement);
0104 
0105     PlasmaQuick::SharedQmlEngine sharedEngine;
0106     // It is important this to be done before the view is created, as it creates internally a framesvgitem for the background
0107     // that needs to use the current plasma theme
0108     sharedEngine.engine()->setProperty("_kirigamiTheme", u"KirigamiPlasmaStyle"_s);
0109     sharedEngine.setInitializationDelayed(true);
0110     View view(&sharedEngine);
0111 
0112     auto updateVisibility = [&]() {
0113         const QString query = parser.positionalArguments().value(0);
0114         const bool hasSingleRunnerModeId = parser.isSet(runnerId);
0115 
0116         if (parser.isSet(daemonOption)) {
0117             view.setVisible(false);
0118         } else if (parser.isSet(clipboardOption)) {
0119             view.displayWithClipboardContents();
0120         } else if (!query.isEmpty()) {
0121             if (hasSingleRunnerModeId) {
0122                 view.querySingleRunner(parser.value(runnerId), query);
0123             } else {
0124                 view.query(query);
0125             }
0126         } else if (hasSingleRunnerModeId) {
0127             view.displaySingleRunner(parser.value(runnerId));
0128         } else {
0129             view.toggleDisplay();
0130         }
0131     };
0132 
0133     updateVisibility();
0134 
0135     QObject::connect(&service, &KDBusService::activateRequested, &view, [&](const QStringList &arguments) {
0136         parser.parse(arguments);
0137         updateVisibility();
0138     });
0139     QObject::connect(&service, &KDBusService::activateActionRequested, &view, [&view](const QString &action) {
0140         if (action == QLatin1String("RunClipboard")) {
0141             view.displayWithClipboardContents();
0142         }
0143     });
0144 
0145     return app.exec();
0146 }