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; }; }