[wayland] Pass command line arguments to launched processes

Summary:
Since QProcess::setProgram() doesn't split the command, we need to do it
ourselves.

Test Plan: `dbus-run-session kwin_wayland "kate foo.txt"` works again.

Reviewers: #kwin, cblack, davidedmundson, apol

Reviewed By: #kwin, cblack, davidedmundson, apol

Subscribers: apol, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D29253
master
Vlad Zahorodnii 2020-04-28 15:45:34 +03:00
parent d3303bc407
commit 2fa5526f12
1 changed files with 64 additions and 39 deletions

View File

@ -33,11 +33,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Server/display.h>
#include <KWayland/Server/seat_interface.h>
// KDE
#include <KCrash>
#include <KLocalizedString>
#include <KPluginLoader>
#include <KPluginMetaData>
#include <KCrash>
#include <KQuickAddons/QtQuickSettings>
#include <KShell>
// Qt
#include <qplatformdefs.h>
@ -216,61 +217,85 @@ void ApplicationWayland::continueStartupWithScene()
void ApplicationWayland::startSession()
{
if (!m_inputMethodServerToStart.isEmpty()) {
int socket = dup(waylandServer()->createInputMethodConnection());
if (socket >= 0) {
QProcessEnvironment environment = processStartupEnvironment();
environment.insert(QStringLiteral("WAYLAND_SOCKET"), QByteArray::number(socket));
environment.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland"));
environment.remove("DISPLAY");
environment.remove("WAYLAND_DISPLAY");
QProcess *p = new Process(this);
p->setProcessChannelMode(QProcess::ForwardedErrorChannel);
connect(p, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
[p] {
if (waylandServer()) {
waylandServer()->destroyInputMethodConnection();
QStringList arguments = KShell::splitArgs(m_inputMethodServerToStart);
if (!arguments.isEmpty()) {
QString program = arguments.takeFirst();
int socket = dup(waylandServer()->createInputMethodConnection());
if (socket >= 0) {
QProcessEnvironment environment = processStartupEnvironment();
environment.insert(QStringLiteral("WAYLAND_SOCKET"), QByteArray::number(socket));
environment.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland"));
environment.remove("DISPLAY");
environment.remove("WAYLAND_DISPLAY");
QProcess *p = new Process(this);
p->setProcessChannelMode(QProcess::ForwardedErrorChannel);
connect(p, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
[p] {
if (waylandServer()) {
waylandServer()->destroyInputMethodConnection();
}
p->deleteLater();
}
p->deleteLater();
}
);
p->setProcessEnvironment(environment);
p->setProgram(m_inputMethodServerToStart);
p->start();
p->waitForStarted(); //do we really need to wait?
);
p->setProcessEnvironment(environment);
p->setProgram(program);
p->setArguments(arguments);
p->start();
p->waitForStarted(); //do we really need to wait?
}
} else {
qWarning("Failed to launch the input method server: %s is an invalid command",
qPrintable(m_inputMethodServerToStart));
}
}
// start session
if (!m_sessionArgument.isEmpty()) {
QProcess *p = new Process(this);
p->setProcessChannelMode(QProcess::ForwardedErrorChannel);
p->setProcessEnvironment(processStartupEnvironment());
connect(p, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, [p] (int code, QProcess::ExitStatus status) {
p->deleteLater();
if (status == QProcess::CrashExit) {
qWarning() << "Session process has crashed";
QCoreApplication::exit(-1);
return;
}
QStringList arguments = KShell::splitArgs(m_sessionArgument);
if (!arguments.isEmpty()) {
QString program = arguments.takeFirst();
QProcess *p = new Process(this);
p->setProcessChannelMode(QProcess::ForwardedErrorChannel);
p->setProcessEnvironment(processStartupEnvironment());
connect(p, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, [p] (int code, QProcess::ExitStatus status) {
p->deleteLater();
if (status == QProcess::CrashExit) {
qWarning() << "Session process has crashed";
QCoreApplication::exit(-1);
return;
}
if (code) {
qWarning() << "Session process exited with code" << code;
}
if (code) {
qWarning() << "Session process exited with code" << code;
}
QCoreApplication::exit(code);
});
p->setProgram(m_sessionArgument);
p->start();
QCoreApplication::exit(code);
});
p->setProgram(program);
p->setArguments(arguments);
p->start();
} else {
qWarning("Failed to launch the session process: %s is an invalid command",
qPrintable(m_sessionArgument));
}
}
// start the applications passed to us as command line arguments
if (!m_applicationsToStart.isEmpty()) {
for (const QString &application: m_applicationsToStart) {
QStringList arguments = KShell::splitArgs(application);
if (arguments.isEmpty()) {
qWarning("Failed to launch application: %s is an invalid command",
qPrintable(application));
continue;
}
QString program = arguments.takeFirst();
// note: this will kill the started process when we exit
// this is going to happen anyway as we are the wayland and X server the app connects to
QProcess *p = new Process(this);
p->setProcessChannelMode(QProcess::ForwardedErrorChannel);
p->setProcessEnvironment(processStartupEnvironment());
p->setProgram(application);
p->setProgram(program);
p->setArguments(arguments);
p->startDetached();
p->deleteLater();
}