From 05ebe676d2f6c5cabd4979b849e09703a55c93d2 Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Wed, 23 Dec 2020 01:41:47 +0100 Subject: [PATCH] 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 --- kwin.kcfg | 3 ++ main_wayland.cpp | 101 +++++++++++++++++++++++++++++++---------------- main_wayland.h | 6 +++ 3 files changed, 77 insertions(+), 33 deletions(-) diff --git a/kwin.kcfg b/kwin.kcfg index 4a0effc51c..7485efc7f4 100644 --- a/kwin.kcfg +++ b/kwin.kcfg @@ -314,6 +314,9 @@ 0 + + + diff --git a/main_wayland.cpp b/main_wayland.cpp index 0e606e2bad..44ce88fc5d 100644 --- a/main_wayland.cpp +++ b/main_wayland.cpp @@ -25,6 +25,7 @@ // KDE #include +#include #include #include #include @@ -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(&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 diff --git a/main_wayland.h b/main_wayland.h index c55c66ef1f..d34d3a67f3 100644 --- a/main_wayland.h +++ b/main_wayland.h @@ -9,6 +9,7 @@ #ifndef KWIN_MAIN_WAYLAND_H #define KWIN_MAIN_WAYLAND_H #include "main.h" +#include #include 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; }; }