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