File indexing completed on 2025-01-12 03:39:37
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_workingDirectory; 0023 QStringList m_arguments; 0024 QByteArray m_startupId; 0025 QPointer<KProcessRunner> m_processRunner; 0026 QProcessEnvironment m_environment{QProcessEnvironment::InheritFromParent}; 0027 qint64 m_pid = 0; 0028 }; 0029 0030 KIO::CommandLauncherJob::CommandLauncherJob(const QString &command, QObject *parent) 0031 : KJob(parent) 0032 , d(new CommandLauncherJobPrivate()) 0033 { 0034 d->m_command = command; 0035 } 0036 0037 KIO::CommandLauncherJob::CommandLauncherJob(const QString &executable, const QStringList &args, QObject *parent) 0038 : KJob(parent) 0039 , d(new CommandLauncherJobPrivate()) 0040 { 0041 d->m_executable = executable; 0042 d->m_arguments = args; 0043 } 0044 0045 KIO::CommandLauncherJob::~CommandLauncherJob() 0046 { 0047 // Do *NOT* delete the KProcessRunner instances here. 0048 // We need it to keep running so it can terminate startup notification on process exit. 0049 } 0050 0051 void KIO::CommandLauncherJob::setCommand(const QString &command) 0052 { 0053 d->m_command = command; 0054 } 0055 0056 QString KIO::CommandLauncherJob::command() const 0057 { 0058 if (d->m_command.isEmpty()) { 0059 return KShell::quoteArg(d->m_executable) + QLatin1Char(' ') + KShell::joinArgs(d->m_arguments); 0060 } 0061 return d->m_command; 0062 } 0063 0064 void KIO::CommandLauncherJob::setExecutable(const QString &executable) 0065 { 0066 d->m_executable = executable; 0067 } 0068 0069 void KIO::CommandLauncherJob::setDesktopName(const QString &desktopName) 0070 { 0071 d->m_desktopName = desktopName; 0072 } 0073 0074 void KIO::CommandLauncherJob::setStartupId(const QByteArray &startupId) 0075 { 0076 d->m_startupId = startupId; 0077 } 0078 0079 void KIO::CommandLauncherJob::setWorkingDirectory(const QString &workingDirectory) 0080 { 0081 d->m_workingDirectory = workingDirectory; 0082 } 0083 0084 QString KIO::CommandLauncherJob::workingDirectory() const 0085 { 0086 return d->m_workingDirectory; 0087 } 0088 0089 void KIO::CommandLauncherJob::setProcessEnvironment(const QProcessEnvironment &environment) 0090 { 0091 d->m_environment = environment; 0092 } 0093 0094 void KIO::CommandLauncherJob::start() 0095 { 0096 // Some fallback for lazy callers, not 100% accurate though 0097 if (d->m_executable.isEmpty()) { 0098 const QStringList args = KShell::splitArgs(d->m_command); 0099 if (!args.isEmpty()) { 0100 d->m_executable = args.first(); 0101 } 0102 } 0103 0104 QString displayName = d->m_executable; 0105 KService::Ptr service = KService::serviceByDesktopName(d->m_desktopName); 0106 if (service) { 0107 displayName = service->name(); 0108 } 0109 Q_EMIT description(this, i18nc("Launching application", "Launching %1", displayName), {}, {}); 0110 0111 if (d->m_command.isEmpty() && !d->m_executable.isEmpty()) { 0112 d->m_processRunner = 0113 KProcessRunner::fromExecutable(d->m_executable, d->m_arguments, d->m_desktopName, d->m_startupId, d->m_workingDirectory, d->m_environment); 0114 } else { 0115 d->m_processRunner = 0116 KProcessRunner::fromCommand(d->m_command, d->m_desktopName, d->m_executable, d->m_startupId, d->m_workingDirectory, d->m_environment); 0117 } 0118 connect(d->m_processRunner, &KProcessRunner::error, this, [this](const QString &errorText) { 0119 setError(KJob::UserDefinedError); 0120 setErrorText(errorText); 0121 emitResult(); 0122 }); 0123 connect(d->m_processRunner, &KProcessRunner::processStarted, this, [this](qint64 pid) { 0124 d->m_pid = pid; 0125 emitResult(); 0126 }); 0127 } 0128 0129 bool KIO::CommandLauncherJob::waitForStarted() 0130 { 0131 if (d->m_processRunner.isNull()) { 0132 return false; 0133 } 0134 const bool ret = d->m_processRunner->waitForStarted(); 0135 if (!d->m_processRunner.isNull()) { 0136 qApp->sendPostedEvents(d->m_processRunner); // so slotStarted gets called 0137 } 0138 return ret; 0139 } 0140 0141 qint64 KIO::CommandLauncherJob::pid() const 0142 { 0143 return d->m_pid; 0144 }