[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.
This commit is contained in:
Boudewijn Rempt 2015-06-13 04:06:12 +02:00
parent 1d78430acc
commit 98bcdbe70a
5 changed files with 54 additions and 0 deletions

View file

@ -174,6 +174,22 @@ void ApplicationWayland::continueStartupWithX()
::exit(1); ::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 // start the applications passed to us as command line arguments
if (!m_applicationsToStart.isEmpty()) { if (!m_applicationsToStart.isEmpty()) {
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
@ -418,6 +434,7 @@ KWIN_EXPORT int kdemain(int argc, char * argv[])
#endif #endif
qunsetenv("QT_DEVICE_PIXEL_RATIO"); qunsetenv("QT_DEVICE_PIXEL_RATIO");
qunsetenv("QT_IM_MODULE");
qputenv("WAYLAND_SOCKET", QByteArray::number(server->createQtConnection())); qputenv("WAYLAND_SOCKET", QByteArray::number(server->createQtConnection()));
qputenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1"); qputenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1");
KWin::ApplicationWayland a(argc, argv); 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.")); QCommandLineOption drmOption(QStringLiteral("drm"), i18n("Render through drm node."));
parser.addOption(drmOption); parser.addOption(drmOption);
#endif #endif
QCommandLineOption inputMethodOption(QStringLiteral("inputmethod"),
i18n("Input method that KWin starts."),
QStringLiteral("path/to/imserver"));
parser.addOption(inputMethodOption);
parser.addPositionalArgument(QStringLiteral("applications"), parser.addPositionalArgument(QStringLiteral("applications"),
i18n("Applications to start once Wayland and Xwayland server are started"), i18n("Applications to start once Wayland and Xwayland server are started"),
QStringLiteral("[/path/to/application...]")); QStringLiteral("[/path/to/application...]"));
@ -576,6 +599,7 @@ KWIN_EXPORT int kdemain(int argc, char * argv[])
a.setStartXwayland(parser.isSet(xwaylandOption)); a.setStartXwayland(parser.isSet(xwaylandOption));
a.setApplicationsToStart(parser.positionalArguments()); a.setApplicationsToStart(parser.positionalArguments());
a.setInputMethodServerToStart(parser.value(inputMethodOption));
a.start(); a.start();
return a.exec(); return a.exec();

View file

@ -40,6 +40,9 @@ public:
void setApplicationsToStart(const QStringList &applications) { void setApplicationsToStart(const QStringList &applications) {
m_applicationsToStart = applications; m_applicationsToStart = applications;
} }
void setInputMethodServerToStart(const QString &inputMethodServer) {
m_inputMethodServerToStart = inputMethodServer;
}
bool notify(QObject *o, QEvent *e) override; bool notify(QObject *o, QEvent *e) override;
@ -56,6 +59,7 @@ private:
bool m_startXWayland = false; bool m_startXWayland = false;
int m_xcbConnectionFd = -1; int m_xcbConnectionFd = -1;
QStringList m_applicationsToStart; QStringList m_applicationsToStart;
QString m_inputMethodServerToStart;
QProcess *m_xwaylandProcess = nullptr; QProcess *m_xwaylandProcess = nullptr;
}; };

View file

@ -62,6 +62,9 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface)
setGeometry(QRect(QPoint(0, 0), m_clientSize)); setGeometry(QRect(QPoint(0, 0), m_clientSize));
setDesktop(VirtualDesktopManager::self()->current()); setDesktop(VirtualDesktopManager::self()->current());
} }
if (waylandServer()->inputMethodConnection() == m_shellSurface->client()) {
m_windowType = NET::OnScreenDisplay;
}
connect(surface->surface(), &SurfaceInterface::sizeChanged, this, connect(surface->surface(), &SurfaceInterface::sizeChanged, this,
[this] { [this] {
@ -420,6 +423,9 @@ bool ShellClient::wantsInput() const
if (isInternal()) { if (isInternal()) {
return false; return false;
} }
if (waylandServer()->inputMethodConnection() == m_shellSurface->client()) {
return false;
}
// if the window is not visible it doesn't get input // if the window is not visible it doesn't get input
return isShown(true); return isShown(true);
} }

View file

@ -189,6 +189,17 @@ int WaylandServer::createXWaylandConnection()
return sx[1]; 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 WaylandServer::createQtConnection()
{ {
int sx[2]; int sx[2];

View file

@ -95,6 +95,11 @@ public:
**/ **/
int createXWaylandConnection(); int createXWaylandConnection();
/**
* @returns file descriptor to the input method server's socket.
**/
int createInputMethodConnection();
/** /**
* @returns file descriptor for QtWayland * @returns file descriptor for QtWayland
**/ **/
@ -108,6 +113,9 @@ public:
KWayland::Server::ClientConnection *qtConnection() const { KWayland::Server::ClientConnection *qtConnection() const {
return m_qtConnection; return m_qtConnection;
} }
KWayland::Server::ClientConnection *inputMethodConnection() const {
return m_inputMethodServerConnection;
}
KWayland::Server::ClientConnection *internalConnection() const { KWayland::Server::ClientConnection *internalConnection() const {
return m_internalConnection.server; return m_internalConnection.server;
} }
@ -134,6 +142,7 @@ private:
KWayland::Server::PlasmaShellInterface *m_plasmaShell = nullptr; KWayland::Server::PlasmaShellInterface *m_plasmaShell = nullptr;
KWayland::Server::QtSurfaceExtensionInterface *m_qtExtendedSurface = nullptr; KWayland::Server::QtSurfaceExtensionInterface *m_qtExtendedSurface = nullptr;
KWayland::Server::ClientConnection *m_xwaylandConnection = nullptr; KWayland::Server::ClientConnection *m_xwaylandConnection = nullptr;
KWayland::Server::ClientConnection *m_inputMethodServerConnection = nullptr;
KWayland::Server::ClientConnection *m_qtConnection = nullptr; KWayland::Server::ClientConnection *m_qtConnection = nullptr;
KWayland::Client::ConnectionThread *m_qtClientConnection = nullptr; KWayland::Client::ConnectionThread *m_qtClientConnection = nullptr;
struct { struct {