1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#include "commandlauncherjob.h"
9#include "kiogui_debug.h"
10#include "kprocessrunner_p.h"
11#include <KLocalizedString>
12#include <KShell>
13
14#include <QPointer>
15
16class KIO::CommandLauncherJobPrivate
17{
18public:
19 QString m_command;
20 QString m_desktopName;
21 QString m_executable;
22 QString m_workingDirectory;
23 QStringList m_arguments;
24 QByteArray m_startupId;
25 QPointer<KProcessRunner> m_processRunner;
26 QProcessEnvironment m_environment{QProcessEnvironment::InheritFromParent};
27 qint64 m_pid = 0;
28};
29
30KIO::CommandLauncherJob::CommandLauncherJob(const QString &command, QObject *parent)
31 : KJob(parent)
32 , d(new CommandLauncherJobPrivate())
33{
34 d->m_command = command;
35}
36
37KIO::CommandLauncherJob::CommandLauncherJob(const QString &executable, const QStringList &args, QObject *parent)
38 : KJob(parent)
39 , d(new CommandLauncherJobPrivate())
40{
41 d->m_executable = executable;
42 d->m_arguments = args;
43}
44
45KIO::CommandLauncherJob::~CommandLauncherJob()
46{
47 // Do *NOT* delete the KProcessRunner instances here.
48 // We need it to keep running so it can terminate startup notification on process exit.
49}
50
51void KIO::CommandLauncherJob::setCommand(const QString &command)
52{
53 d->m_command = command;
54}
55
56QString KIO::CommandLauncherJob::command() const
57{
58 if (d->m_command.isEmpty()) {
59 return KShell::quoteArg(arg: d->m_executable) + QLatin1Char(' ') + KShell::joinArgs(args: d->m_arguments);
60 }
61 return d->m_command;
62}
63
64void KIO::CommandLauncherJob::setExecutable(const QString &executable)
65{
66 d->m_executable = executable;
67}
68
69void KIO::CommandLauncherJob::setDesktopName(const QString &desktopName)
70{
71 d->m_desktopName = desktopName;
72}
73
74void KIO::CommandLauncherJob::setStartupId(const QByteArray &startupId)
75{
76 d->m_startupId = startupId;
77}
78
79void KIO::CommandLauncherJob::setWorkingDirectory(const QString &workingDirectory)
80{
81 d->m_workingDirectory = workingDirectory;
82}
83
84QString KIO::CommandLauncherJob::workingDirectory() const
85{
86 return d->m_workingDirectory;
87}
88
89void KIO::CommandLauncherJob::setProcessEnvironment(const QProcessEnvironment &environment)
90{
91 d->m_environment = environment;
92}
93
94void KIO::CommandLauncherJob::start()
95{
96 // Some fallback for lazy callers, not 100% accurate though
97 if (d->m_executable.isEmpty()) {
98 const QStringList args = KShell::splitArgs(cmd: d->m_command);
99 if (!args.isEmpty()) {
100 d->m_executable = args.first();
101 }
102 }
103
104 QString displayName = d->m_executable;
105 KService::Ptr service = KService::serviceByDesktopName(name: d->m_desktopName);
106 if (service) {
107 displayName = service->name();
108 }
109 Q_EMIT description(job: this, i18nc("Launching application", "Launching %1", displayName), field1: {}, field2: {});
110
111 if (d->m_command.isEmpty() && !d->m_executable.isEmpty()) {
112 d->m_processRunner =
113 KProcessRunner::fromExecutable(executable: d->m_executable, args: d->m_arguments, desktopName: d->m_desktopName, asn: d->m_startupId, workingDirectory: d->m_workingDirectory, environment: d->m_environment);
114 } else {
115 d->m_processRunner =
116 KProcessRunner::fromCommand(cmd: d->m_command, desktopName: d->m_desktopName, execName: d->m_executable, asn: d->m_startupId, workingDirectory: d->m_workingDirectory, environment: d->m_environment);
117 }
118 connect(sender: d->m_processRunner, signal: &KProcessRunner::error, context: this, slot: [this](const QString &errorText) {
119 setError(KJob::UserDefinedError);
120 setErrorText(errorText);
121 emitResult();
122 });
123 connect(sender: d->m_processRunner, signal: &KProcessRunner::processStarted, context: this, slot: [this](qint64 pid) {
124 d->m_pid = pid;
125 emitResult();
126 });
127}
128
129bool KIO::CommandLauncherJob::waitForStarted()
130{
131 if (d->m_processRunner.isNull()) {
132 return false;
133 }
134 const bool ret = d->m_processRunner->waitForStarted();
135 if (!d->m_processRunner.isNull()) {
136 qApp->sendPostedEvents(receiver: d->m_processRunner); // so slotStarted gets called
137 }
138 return ret;
139}
140
141qint64 KIO::CommandLauncherJob::pid() const
142{
143 return d->m_pid;
144}
145

source code of kio/src/gui/commandlauncherjob.cpp