File indexing completed on 2024-04-28 11:41:28

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "commandlauncherjob.h"
0009 #include "kiogui_debug.h"
0010 #include "kprocessrunner_p.h"
0011 #include <KLocalizedString>
0012 #include <KShell>
0013 
0014 #include <QPointer>
0015 
0016 class KIO::CommandLauncherJobPrivate
0017 {
0018 public:
0019     QString m_command;
0020     QString m_desktopName;
0021     QString m_executable;
0022     QString m_iconName;
0023     QString m_workingDirectory;
0024     QStringList m_arguments;
0025     QByteArray m_startupId;
0026     QPointer<KProcessRunner> m_processRunner;
0027     QProcessEnvironment m_environment;
0028     qint64 m_pid = 0;
0029 };
0030 
0031 KIO::CommandLauncherJob::CommandLauncherJob(const QString &command, QObject *parent)
0032     : KJob(parent)
0033     , d(new CommandLauncherJobPrivate())
0034 {
0035     d->m_command = command;
0036 }
0037 
0038 KIO::CommandLauncherJob::CommandLauncherJob(const QString &executable, const QStringList &args, QObject *parent)
0039     : KJob(parent)
0040     , d(new CommandLauncherJobPrivate())
0041 {
0042     d->m_executable = executable;
0043     d->m_arguments = args;
0044 }
0045 
0046 KIO::CommandLauncherJob::~CommandLauncherJob()
0047 {
0048     // Do *NOT* delete the KProcessRunner instances here.
0049     // We need it to keep running so it can terminate startup notification on process exit.
0050 }
0051 
0052 void KIO::CommandLauncherJob::setCommand(const QString &command)
0053 {
0054     d->m_command = command;
0055 }
0056 
0057 QString KIO::CommandLauncherJob::command() const
0058 {
0059     if (d->m_command.isEmpty()) {
0060         return KShell::quoteArg(d->m_executable) + QLatin1Char(' ') + KShell::joinArgs(d->m_arguments);
0061     }
0062     return d->m_command;
0063 }
0064 
0065 void KIO::CommandLauncherJob::setExecutable(const QString &executable)
0066 {
0067     d->m_executable = executable;
0068 }
0069 
0070 #if KIOGUI_BUILD_DEPRECATED_SINCE(5, 103)
0071 void KIO::CommandLauncherJob::setIcon(const QString &iconName)
0072 {
0073     d->m_iconName = iconName;
0074 }
0075 #endif
0076 
0077 void KIO::CommandLauncherJob::setDesktopName(const QString &desktopName)
0078 {
0079     d->m_desktopName = desktopName;
0080 }
0081 
0082 void KIO::CommandLauncherJob::setStartupId(const QByteArray &startupId)
0083 {
0084     d->m_startupId = startupId;
0085 }
0086 
0087 void KIO::CommandLauncherJob::setWorkingDirectory(const QString &workingDirectory)
0088 {
0089     d->m_workingDirectory = workingDirectory;
0090 }
0091 
0092 QString KIO::CommandLauncherJob::workingDirectory() const
0093 {
0094     return d->m_workingDirectory;
0095 }
0096 
0097 void KIO::CommandLauncherJob::setProcessEnvironment(const QProcessEnvironment &environment)
0098 {
0099     d->m_environment = environment;
0100 }
0101 
0102 void KIO::CommandLauncherJob::start()
0103 {
0104     // Some fallback for lazy callers, not 100% accurate though
0105     if (d->m_executable.isEmpty()) {
0106         const QStringList args = KShell::splitArgs(d->m_command);
0107         if (!args.isEmpty()) {
0108             d->m_executable = args.first();
0109         }
0110     }
0111 
0112     QString displayName = d->m_executable;
0113     KService::Ptr service = KService::serviceByDesktopName(d->m_desktopName);
0114     if (service) {
0115         displayName = service->name();
0116     }
0117     Q_EMIT description(this, i18nc("Launching application", "Launching %1", displayName), {}, {});
0118 
0119     if (d->m_iconName.isEmpty()) {
0120         d->m_iconName = d->m_executable;
0121     }
0122     if (d->m_command.isEmpty() && !d->m_executable.isEmpty()) {
0123         d->m_processRunner = KProcessRunner::fromExecutable(d->m_executable,
0124                                                             d->m_arguments,
0125                                                             d->m_desktopName,
0126                                                             d->m_iconName,
0127                                                             d->m_startupId,
0128                                                             d->m_workingDirectory,
0129                                                             d->m_environment);
0130     } else {
0131         d->m_processRunner = KProcessRunner::fromCommand(d->m_command,
0132                                                          d->m_desktopName,
0133                                                          d->m_executable,
0134                                                          d->m_iconName,
0135                                                          d->m_startupId,
0136                                                          d->m_workingDirectory,
0137                                                          d->m_environment);
0138     }
0139     connect(d->m_processRunner, &KProcessRunner::error, this, [this](const QString &errorText) {
0140         setError(KJob::UserDefinedError);
0141         setErrorText(errorText);
0142         emitResult();
0143     });
0144     connect(d->m_processRunner, &KProcessRunner::processStarted, this, [this](qint64 pid) {
0145         d->m_pid = pid;
0146         emitResult();
0147     });
0148 }
0149 
0150 bool KIO::CommandLauncherJob::waitForStarted()
0151 {
0152     if (d->m_processRunner.isNull()) {
0153         return false;
0154     }
0155     const bool ret = d->m_processRunner->waitForStarted();
0156     if (!d->m_processRunner.isNull()) {
0157         qApp->sendPostedEvents(d->m_processRunner); // so slotStarted gets called
0158     }
0159     return ret;
0160 }
0161 
0162 qint64 KIO::CommandLauncherJob::pid() const
0163 {
0164     return d->m_pid;
0165 }