Introduce a setting to specify an input method

At the moment we are getting the input method from the command line
which is not very handy (but very secure).
This patch changes it so it can be specified from a configuration
setting.

CCBUG: 427972
This commit is contained in:
Aleix Pol 2020-12-23 01:41:47 +01:00 committed by Aleix Pol Gonzalez
parent 59b1dee55a
commit 05ebe676d2
3 changed files with 77 additions and 33 deletions

View file

@ -314,6 +314,9 @@
<min>0</min>
</entry>
</group>
<group name="Wayland">
<entry name="InputMethod" type="Path" />
</group>
<group name="Xwayland">
<entry name="XwaylandCrashPolicy" type="Enum">
<choices name="KWin::XwaylandCrashPolicy">

View file

@ -25,6 +25,7 @@
// KDE
#include <KCrash>
#include <KDesktopFile>
#include <KLocalizedString>
#include <KPluginLoader>
#include <KPluginMetaData>
@ -112,6 +113,7 @@ void gainRealTime(RealTimeFlags flags = RealTimeFlags::DontReset)
ApplicationWayland::ApplicationWayland(int &argc, char **argv)
: ApplicationWaylandAbstract(OperationModeWaylandOnly, argc, argv)
{
connect(waylandServer(), &WaylandServer::terminatingInternalClientConnection, this, &ApplicationWayland::stopInputMethod);
}
ApplicationWayland::~ApplicationWayland()
@ -216,42 +218,75 @@ void ApplicationWayland::continueStartupWithScene()
m_xwayland->start();
}
void ApplicationWayland::stopInputMethod()
{
if (!m_inputMethodProcess) {
return;
}
m_inputMethodProcess->kill();
m_inputMethodProcess->waitForFinished();
if (waylandServer()) {
waylandServer()->destroyInputMethodConnection();
}
m_inputMethodProcess->deleteLater();
m_inputMethodProcess = nullptr;
}
void ApplicationWayland::startInputMethod(const QString &executable)
{
stopInputMethod();
if (executable.isEmpty()) {
return;
}
QStringList arguments = KShell::splitArgs(executable);
if (arguments.isEmpty()) {
qWarning("Failed to launch the input method server: %s is an invalid command", qPrintable(m_inputMethodServerToStart));
return;
}
const QString program = arguments.takeFirst();
int socket = dup(waylandServer()->createInputMethodConnection());
if (socket >= 0) {
qWarning("Failed to create the input method connection");
return;
}
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");
m_inputMethodProcess = new Process(this);
m_inputMethodProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel);
m_inputMethodProcess->setProcessEnvironment(environment);
m_inputMethodProcess->setProgram(program);
m_inputMethodProcess->setArguments(arguments);
m_inputMethodProcess->start();
}
void ApplicationWayland::refreshSettings(const KConfigGroup &group, const QByteArrayList &names)
{
if (group.name() != "Wayland" || !names.contains("InputMethod")) {
return;
}
startInputMethod(group.readEntry("InputMethod", QString()));
}
void ApplicationWayland::startSession()
{
if (!m_inputMethodServerToStart.isEmpty()) {
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->setProcessEnvironment(environment);
p->setProgram(program);
p->setArguments(arguments);
p->start();
connect(waylandServer(), &WaylandServer::terminatingInternalClientConnection, p, [p] {
p->kill();
p->waitForFinished();
});
}
} else {
qWarning("Failed to launch the input method server: %s is an invalid command",
qPrintable(m_inputMethodServerToStart));
}
startInputMethod(m_inputMethodServerToStart);
} else {
KSharedConfig::Ptr kwinSettings = kwinApp()->config();
m_settingsWatcher = KConfigWatcher::create(kwinSettings);
connect(m_settingsWatcher.data(), &KConfigWatcher::configChanged, this, &ApplicationWayland::refreshSettings);
KConfigGroup group = kwinSettings->group("Wayland");
KDesktopFile file(group.readEntry("InputMethod", QString()));
startInputMethod(file.desktopGroup().readEntry("Exec", QString()));
}
// start session

View file

@ -9,6 +9,7 @@
#ifndef KWIN_MAIN_WAYLAND_H
#define KWIN_MAIN_WAYLAND_H
#include "main.h"
#include <KConfigWatcher>
#include <QProcessEnvironment>
namespace KWin
@ -54,14 +55,19 @@ private:
void continueStartupWithScene();
void finalizeStartup();
void startSession() override;
void startInputMethod(const QString &executable);
void refreshSettings(const KConfigGroup &group, const QByteArrayList &names);
void stopInputMethod();
bool m_startXWayland = false;
QStringList m_applicationsToStart;
QString m_inputMethodServerToStart;
QProcessEnvironment m_environment;
QString m_sessionArgument;
QProcess *m_inputMethodProcess = nullptr;
Xwl::Xwayland *m_xwayland = nullptr;
KConfigWatcher::Ptr m_settingsWatcher;
};
}