From 98bcdbe70a9106bdcbe2bdf93746c4375b2b3346 Mon Sep 17 00:00:00 2001 From: Boudewijn Rempt Date: Sat, 13 Jun 2015 04:06:12 +0200 Subject: [PATCH] [wayland] Add a command-line option to start an input method server Input-method servers, like maliit, need to be known to KWin since KWin needs to know about virtual keyboards. Virtual keyboards should be shown as OSD layers, and they are one of the types of windows that actually should be showable when the lock screen is active. kwin_wayland --inputmethod /path/to/your/input-server tries to start the input server. The input-server's window never gets keyboard focus and is shown on top of all windows except for KWin's internal clients. --- main_wayland.cpp | 24 ++++++++++++++++++++++++ main_wayland.h | 4 ++++ shell_client.cpp | 6 ++++++ wayland_server.cpp | 11 +++++++++++ wayland_server.h | 9 +++++++++ 5 files changed, 54 insertions(+) diff --git a/main_wayland.cpp b/main_wayland.cpp index d354736817..4411cb6524 100644 --- a/main_wayland.cpp +++ b/main_wayland.cpp @@ -174,6 +174,22 @@ void ApplicationWayland::continueStartupWithX() ::exit(1); } + if (!m_inputMethodServerToStart.isEmpty()) { + int socket = dup(waylandServer()->createInputMethodConnection()); + if (socket >= 0) { + QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); + environment.insert(QStringLiteral("WAYLAND_SOCKET"), QByteArray::number(socket)); + environment.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland")); + environment.insert(QStringLiteral("QT_IM_MODULE"), QStringLiteral("maliit")); + environment.remove("DISPLAY"); + environment.remove("WAYLAND_DISPLAY"); + QProcess *p = new QProcess(this); + p->setProcessEnvironment(environment); + p->start(m_inputMethodServerToStart); + p->waitForStarted(); + } + } + // start the applications passed to us as command line arguments if (!m_applicationsToStart.isEmpty()) { QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); @@ -418,6 +434,7 @@ KWIN_EXPORT int kdemain(int argc, char * argv[]) #endif qunsetenv("QT_DEVICE_PIXEL_RATIO"); + qunsetenv("QT_IM_MODULE"); qputenv("WAYLAND_SOCKET", QByteArray::number(server->createQtConnection())); qputenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1"); KWin::ApplicationWayland a(argc, argv); @@ -479,6 +496,12 @@ KWIN_EXPORT int kdemain(int argc, char * argv[]) QCommandLineOption drmOption(QStringLiteral("drm"), i18n("Render through drm node.")); parser.addOption(drmOption); #endif + + QCommandLineOption inputMethodOption(QStringLiteral("inputmethod"), + i18n("Input method that KWin starts."), + QStringLiteral("path/to/imserver")); + parser.addOption(inputMethodOption); + parser.addPositionalArgument(QStringLiteral("applications"), i18n("Applications to start once Wayland and Xwayland server are started"), QStringLiteral("[/path/to/application...]")); @@ -576,6 +599,7 @@ KWIN_EXPORT int kdemain(int argc, char * argv[]) a.setStartXwayland(parser.isSet(xwaylandOption)); a.setApplicationsToStart(parser.positionalArguments()); + a.setInputMethodServerToStart(parser.value(inputMethodOption)); a.start(); return a.exec(); diff --git a/main_wayland.h b/main_wayland.h index f77ebd62b1..b6ef584e22 100644 --- a/main_wayland.h +++ b/main_wayland.h @@ -40,6 +40,9 @@ public: void setApplicationsToStart(const QStringList &applications) { m_applicationsToStart = applications; } + void setInputMethodServerToStart(const QString &inputMethodServer) { + m_inputMethodServerToStart = inputMethodServer; + } bool notify(QObject *o, QEvent *e) override; @@ -56,6 +59,7 @@ private: bool m_startXWayland = false; int m_xcbConnectionFd = -1; QStringList m_applicationsToStart; + QString m_inputMethodServerToStart; QProcess *m_xwaylandProcess = nullptr; }; diff --git a/shell_client.cpp b/shell_client.cpp index 805d72bf76..7420ec5fa5 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -62,6 +62,9 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface) setGeometry(QRect(QPoint(0, 0), m_clientSize)); setDesktop(VirtualDesktopManager::self()->current()); } + if (waylandServer()->inputMethodConnection() == m_shellSurface->client()) { + m_windowType = NET::OnScreenDisplay; + } connect(surface->surface(), &SurfaceInterface::sizeChanged, this, [this] { @@ -420,6 +423,9 @@ bool ShellClient::wantsInput() const if (isInternal()) { return false; } + if (waylandServer()->inputMethodConnection() == m_shellSurface->client()) { + return false; + } // if the window is not visible it doesn't get input return isShown(true); } diff --git a/wayland_server.cpp b/wayland_server.cpp index c1172bf232..bb03996c77 100644 --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -189,6 +189,17 @@ int WaylandServer::createXWaylandConnection() return sx[1]; } +int WaylandServer::createInputMethodConnection() +{ + int sx[2]; + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) { + qCWarning(KWIN_CORE) << "Could not create socket"; + return -1; + } + m_inputMethodServerConnection = m_display->createClient(sx[0]); + return sx[1]; +} + int WaylandServer::createQtConnection() { int sx[2]; diff --git a/wayland_server.h b/wayland_server.h index e33ef79b48..8fcd380caa 100644 --- a/wayland_server.h +++ b/wayland_server.h @@ -95,6 +95,11 @@ public: **/ int createXWaylandConnection(); + /** + * @returns file descriptor to the input method server's socket. + **/ + int createInputMethodConnection(); + /** * @returns file descriptor for QtWayland **/ @@ -108,6 +113,9 @@ public: KWayland::Server::ClientConnection *qtConnection() const { return m_qtConnection; } + KWayland::Server::ClientConnection *inputMethodConnection() const { + return m_inputMethodServerConnection; + } KWayland::Server::ClientConnection *internalConnection() const { return m_internalConnection.server; } @@ -134,6 +142,7 @@ private: KWayland::Server::PlasmaShellInterface *m_plasmaShell = nullptr; KWayland::Server::QtSurfaceExtensionInterface *m_qtExtendedSurface = nullptr; KWayland::Server::ClientConnection *m_xwaylandConnection = nullptr; + KWayland::Server::ClientConnection *m_inputMethodServerConnection = nullptr; KWayland::Server::ClientConnection *m_qtConnection = nullptr; KWayland::Client::ConnectionThread *m_qtClientConnection = nullptr; struct {