File indexing completed on 2025-01-19 03:41:34
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 #ifndef KPROCESSRUNNER_P_H 0009 #define KPROCESSRUNNER_P_H 0010 0011 #include "applicationlauncherjob.h" 0012 #include "config-kiogui.h" 0013 #include "kiogui_export.h" 0014 0015 #include <KProcess> 0016 0017 #if HAVE_X11 0018 #include <KStartupInfo> 0019 #endif 0020 #include <QObject> 0021 #include <memory> 0022 0023 namespace KIOGuiPrivate 0024 { 0025 /** 0026 * @internal DO NOT USE 0027 */ 0028 bool KIOGUI_EXPORT checkStartupNotify(const KService *service, bool *silent_arg, QByteArray *wmclass_arg); 0029 } 0030 0031 /** 0032 * @internal (exported for KIO GUI job unit tests) 0033 * This class runs a KService or a shell command, using QProcess internally. 0034 * It creates a startup notification and finishes it on success or on error (for the taskbar) 0035 * It also shows an error message if necessary (e.g. "program not found"). 0036 */ 0037 class KIOGUI_EXPORT KProcessRunner : public QObject 0038 { 0039 Q_OBJECT 0040 0041 public: 0042 enum LaunchMode { 0043 Forking, 0044 SystemdAsScope, 0045 SystemdAsService, 0046 }; 0047 Q_ENUM(LaunchMode) 0048 0049 /** 0050 * Run a KService (application desktop file) to open @p urls. 0051 * @param service the service to run 0052 * @param urls the list of URLs, can be empty 0053 * @param flags various flags 0054 * @param suggestedFileName see KRun::setSuggestedFileName 0055 * @param asn Application startup notification id, if any (otherwise "") 0056 * @param serviceEntryPath the KService entryPath(), passed as an argument 0057 * because in some cases it could become an empty string, e.g. if an 0058 * ApplicationLauncherJob is created from a @c KServiceAction, the 0059 * ApplicationLauncherJob will call KService::setExec() which clears the 0060 * entryPath() of the KService 0061 */ 0062 static KProcessRunner *fromApplication(const KService::Ptr &service, 0063 const QString &serviceEntryPath, 0064 const QList<QUrl> &urls, 0065 KIO::ApplicationLauncherJob::RunFlags flags = {}, 0066 const QString &suggestedFileName = {}, 0067 const QByteArray &asn = {}); 0068 0069 /** 0070 * Run a shell command 0071 * @param cmd must be a shell command. No need to append "&" to it. 0072 * @param desktopName name of the desktop file, if known. 0073 * @param execName the name of the executable, if known. 0074 * @param asn Application startup notification id, if any (otherwise ""). 0075 * @param workingDirectory the working directory for the started process. The default 0076 * (if passing an empty string) is the user's document path. 0077 * This allows a command like "kwrite file.txt" to find file.txt from the right place. 0078 */ 0079 static KProcessRunner *fromCommand(const QString &cmd, 0080 const QString &desktopName, 0081 const QString &execName, 0082 const QByteArray &asn, 0083 const QString &workingDirectory, 0084 const QProcessEnvironment &environment); 0085 0086 /** 0087 * Run an executable with arguments (without invoking a shell, by starting a new process). 0088 * 0089 * @note: Starting from 5.92, if an actual executable named @p executable cannot be found 0090 * in PATH, this will return a nullptr. 0091 * 0092 * @param executable the name of (or full path to) the executable, mandatory 0093 * @param args the arguments to pass to the executable 0094 * @param desktopName name of the desktop file, if known. 0095 * @param asn Application startup notification id, if any (otherwise ""). 0096 * @param workingDirectory the working directory for the started process. The default 0097 * (if passing an empty string) is the user's document path. 0098 * This allows a command like "kwrite file.txt" to find file.txt from the right place. 0099 */ 0100 static KProcessRunner *fromExecutable(const QString &executable, 0101 const QStringList &args, 0102 const QString &desktopName, 0103 const QByteArray &asn, 0104 const QString &workingDirectory, 0105 const QProcessEnvironment &environment); 0106 0107 /** 0108 * Blocks until the process has started. Only exists for KRun via Command/ApplicationLauncherJob, will disappear in KF6. 0109 */ 0110 virtual bool waitForStarted(int timeout = 30000) = 0; 0111 0112 ~KProcessRunner() override; 0113 0114 static int instanceCount(); // for the unittest 0115 0116 Q_SIGNALS: 0117 /** 0118 * @brief Emitted on error. In that case, finished() is not emitted. 0119 * @param errorString the error message 0120 */ 0121 void error(const QString &errorString); 0122 0123 /** 0124 * @brief emitted when the process was successfully started 0125 * @param pid PID of the process that was started 0126 */ 0127 void processStarted(qint64 pid); 0128 0129 protected: 0130 KProcessRunner(); 0131 virtual void startProcess() = 0; 0132 void setPid(qint64 pid); 0133 void terminateStartupNotification(); 0134 QString name() const; 0135 QString resolveServiceAlias() const; 0136 static QString escapeUnitName(const QString &input); 0137 void emitDelayedError(const QString &errorMsg); 0138 0139 std::unique_ptr<KProcess> m_process; 0140 QString m_executable; // can be a full path 0141 QString m_desktopName; 0142 QString m_desktopFilePath; 0143 QString m_description; 0144 QString m_cmd; 0145 qint64 m_pid = 0; 0146 KService::Ptr m_service; 0147 QString m_serviceEntryPath; 0148 bool m_waitingForXdgToken = false; 0149 QList<QUrl> m_urls; 0150 #if HAVE_X11 0151 KStartupInfoId m_startupId; 0152 #endif 0153 0154 private: 0155 void initFromDesktopName(const QString &desktopName, 0156 const QString &execName, 0157 const QByteArray &asn, 0158 const QString &workingDirectory, 0159 const QProcessEnvironment &environment); 0160 void init(const KService::Ptr &service, const QString &serviceEntryPath, const QString &userVisibleName, const QByteArray &asn); 0161 0162 Q_DISABLE_COPY(KProcessRunner) 0163 }; 0164 0165 class ForkingProcessRunner : public KProcessRunner 0166 { 0167 Q_OBJECT 0168 0169 public: 0170 explicit ForkingProcessRunner(); 0171 0172 void startProcess() override; 0173 bool waitForStarted(int timeout) override; 0174 0175 protected Q_SLOTS: 0176 void slotProcessExited(int, QProcess::ExitStatus); 0177 void slotProcessError(QProcess::ProcessError error); 0178 virtual void slotProcessStarted(); 0179 }; 0180 0181 #endif