diff --git a/src/gui/commandlauncherjob.cpp b/src/gui/commandlauncherjob.cpp --- a/src/gui/commandlauncherjob.cpp +++ b/src/gui/commandlauncherjob.cpp @@ -88,8 +88,18 @@ if (d->m_iconName.isEmpty()) { d->m_iconName = d->m_executable; } - d->m_processRunner = new KProcessRunner(d->m_command, d->m_desktopName, d->m_executable, - d->m_iconName, d->m_startupId, + + KService::Ptr service; + if (!d->m_desktopName.isEmpty()) { + KService::Ptr service = KService::serviceByDesktopName(d->m_desktopName); + } + if (!service) { + service = KService::Ptr(new KService(d->m_executable, d->m_command, d->m_iconName)); + } + service->setExec(d->m_command); + + d->m_processRunner = new KProcessRunner(service, + d->m_startupId, d->m_workingDirectory); connect(d->m_processRunner, &KProcessRunner::error, this, [this](const QString &errorText) { setError(KJob::UserDefinedError); diff --git a/src/gui/kprocessrunner.cpp b/src/gui/kprocessrunner.cpp --- a/src/gui/kprocessrunner.cpp +++ b/src/gui/kprocessrunner.cpp @@ -105,34 +105,24 @@ } } - init(service, service->name(), service->icon(), asn); + init(service, asn); } -KProcessRunner::KProcessRunner(const QString &cmd, const QString &desktopName, const QString &execName, const QString &iconName, const QByteArray &asn, const QString &workingDirectory) +KProcessRunner::KProcessRunner(const KService::Ptr &service, const QByteArray &asn, const QString &workingDirectory) : m_process{new KProcess}, - m_executable(execName) + m_executable(KIO::DesktopExecParser::executablePath(service->exec())) { ++s_instanceCount; - m_process->setShellCommand(cmd); + m_process->setShellCommand(service->exec()); if (!workingDirectory.isEmpty()) { m_process->setWorkingDirectory(workingDirectory); } - if (!desktopName.isEmpty()) { - KService::Ptr service = KService::serviceByDesktopName(desktopName); - if (service) { - if (m_executable.isEmpty()) { - m_executable = KIO::DesktopExecParser::executablePath(service->exec()); - } - init(service, service->name(), service->icon(), asn); - return; - } - } - init(KService::Ptr(), execName /*user-visible name*/, iconName, asn); + init(service, asn); } -void KProcessRunner::init(const KService::Ptr &service, const QString &userVisibleName, const QString &iconName, const QByteArray &asn) +void KProcessRunner::init(const KService::Ptr &service, const QByteArray &asn) { - if (service && !service->entryPath().isEmpty() + if (!service->entryPath().isEmpty() && !KDesktopFile::isAuthorizedDesktopFile(service->entryPath())) { qCWarning(KIO_GUI) << "No authorization to execute " << service->entryPath(); emitDelayedError(i18n("You are not authorized to execute this file.")); @@ -152,17 +142,13 @@ data.setHostname(); // When it comes from a desktop file, m_executable can be a full shell command, so here is not 100% reliable. // E.g. it could be "cd", which isn't an existing binary. It's just a heuristic anyway. - const QString bin = KIO::DesktopExecParser::executableName(m_executable); + const QString bin = KIO::DesktopExecParser::executableName(service->exec()); data.setBin(bin); - if (!userVisibleName.isEmpty()) { - data.setName(userVisibleName); - } else if (service && !service->name().isEmpty()) { + if (!service->name().isEmpty()) { data.setName(service->name()); } data.setDescription(i18n("Launching %1", data.name())); - if (!iconName.isEmpty()) { - data.setIcon(iconName); - } else if (service && !service->icon().isEmpty()) { + if (!service->icon().isEmpty()) { data.setIcon(service->icon()); } if (!wmclass.isEmpty()) { @@ -338,31 +324,18 @@ { bool silent = false; QByteArray wmclass; - if (service && service->property(QStringLiteral("StartupNotify")).isValid()) { + if (service->property(QStringLiteral("StartupNotify")).isValid()) { silent = !service->property(QStringLiteral("StartupNotify")).toBool(); wmclass = service->property(QStringLiteral("StartupWMClass")).toString().toLatin1(); - } else if (service && service->property(QStringLiteral("X-KDE-StartupNotify")).isValid()) { + } else if (service->property(QStringLiteral("X-KDE-StartupNotify")).isValid()) { silent = !service->property(QStringLiteral("X-KDE-StartupNotify")).toBool(); wmclass = service->property(QStringLiteral("X-KDE-WMClass")).toString().toLatin1(); } else { // non-compliant app - if (service) { if (service->isApplication()) { // doesn't have .desktop entries needed, start as non-compliant wmclass = "0"; // krazy:exclude=doublequote_chars } else { return false; // no startup notification at all } - } else { -#if 0 - // Create startup notification even for apps for which there shouldn't be any, - // just without any visual feedback. This will ensure they'll be positioned on the proper - // virtual desktop, and will get user timestamp from the ASN ID. - wmclass = '0'; - silent = true; -#else // That unfortunately doesn't work, when the launched non-compliant application - // launches another one that is compliant and there is any delay inbetween (bnc:#343359) - return false; -#endif - } } if (silent_arg) { *silent_arg = silent; diff --git a/src/gui/kprocessrunner_p.h b/src/gui/kprocessrunner_p.h --- a/src/gui/kprocessrunner_p.h +++ b/src/gui/kprocessrunner_p.h @@ -63,17 +63,13 @@ /** * Run a shell command - * @param cmd must be a shell command. No need to append "&" to it. - * @param desktopName name of the desktop file, if known. - * @param execName the name of the executable, if known. - * @param iconName icon for the startup notification + * @param service the service to run. A service should be created with known parameters if it does not exist on disk. * @param asn Application startup notification id, if any (otherwise ""). * @param workingDirectory the working directory for the started process. The default * (if passing an empty string) is the user's document path. * This allows a command like "kwrite file.txt" to find file.txt from the right place. */ - KProcessRunner(const QString &cmd, const QString &desktopName, const QString &execName, const QString &iconName, - const QByteArray &asn = {}, const QString &workingDirectory = {}); + KProcessRunner(const KService::Ptr &service, const QByteArray &asn = {}, const QString &workingDirectory = {}); /** * @return the PID of the process that was started, on success @@ -104,15 +100,14 @@ void slotProcessStarted(); private: - void init(const KService::Ptr &service, const QString &userVisibleName, - const QString &iconName, const QByteArray &asn); + void init(const KService::Ptr &service, const QByteArray &asn); void startProcess(); void registerCGroup(); void terminateStartupNotification(); void emitDelayedError(const QString &errorMsg); std::unique_ptr m_process; - QString m_executable; // can be a full path + QString m_executable; KStartupInfoId m_startupId; QString m_scopeId; qint64 m_pid = 0;