File indexing completed on 2024-04-28 15:26:51
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 }