diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d4d1f26..f667429f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,10 @@ set(CONNECTION_SOURCES if(enable-wayland) list(APPEND CONNECTION_SOURCES connection/waylandinputmethodconnection.cpp - connection/waylandinputmethodconnection.h) + connection/waylandinputmethodconnection.h + connection/waylandinputmethodtransport.h + connection/dbuswaylandinputcontextconnection.cpp + connection/dbuswaylandinputcontextconnection.h) ecm_add_qtwayland_client_protocol(CONNECTION_SOURCES PROTOCOL ${WAYLANDPROTOCOLS_PATH}/unstable/input-method/input-method-unstable-v1.xml BASENAME input-method-unstable-v1) diff --git a/connection/connectionfactory.cpp b/connection/connectionfactory.cpp index 3dec7270..87d34049 100644 --- a/connection/connectionfactory.cpp +++ b/connection/connectionfactory.cpp @@ -16,8 +16,12 @@ #include "minputcontextconnection.h" #include "dbusinputcontextconnection.h" +#include +#include + #ifdef HAVE_WAYLAND #include "waylandinputmethodconnection.h" +#include "dbuswaylandinputcontextconnection.h" #endif namespace Maliit { @@ -43,6 +47,45 @@ MInputContextConnection *createWestonIMProtocolConnection() { return new WaylandInputMethodConnection; } + +MInputContextConnection *createDBusAndWaylandConnectionWithDynamicAddress() +{ + QSharedPointer address(new Maliit::Server::DBus::DynamicAddress); + return new DBusWaylandInputContextConnection(address); +} + +MInputContextConnection *createDBusAndWaylandConnectionWithFixedAddress(const QString &fixedAddress, bool allowAnonymous) +{ + Q_UNUSED(allowAnonymous); + QSharedPointer address(new Maliit::Server::DBus::FixedAddress(fixedAddress)); + return new DBusWaylandInputContextConnection(address); +} +#endif + +ConnectionMode connectionModeFromEnvironment() +{ +#ifdef HAVE_WAYLAND + const bool onWayland = QGuiApplication::platformName().startsWith("wayland"); + const QByteArray mode = qgetenv("MALIIT_CONNECTION"); + + if (mode == "dbus") { + return ConnectionMode::DBus; + } else if (mode == "wayland" || mode == "both") { + if (!onWayland) { + qWarning() << "MALIIT_CONNECTION=" << mode << "needs a Wayland platform, using D-Bus only"; + return ConnectionMode::DBus; + } + return mode == "both" ? ConnectionMode::DBusAndWayland : ConnectionMode::Wayland; + } else if (!mode.isEmpty()) { + qWarning() << "Unknown MALIIT_CONNECTION value" << mode << ", expected dbus, wayland or both"; + } + + const QByteArray forceDbus = qgetenv("MALIIT_FORCE_DBUS_CONNECTION"); + if (onWayland && (forceDbus.isEmpty() || forceDbus == "0")) { + return ConnectionMode::Wayland; + } #endif + return ConnectionMode::DBus; +} } // namespace Maliit diff --git a/connection/connectionfactory.h b/connection/connectionfactory.h index 25f41880..5867ca6f 100644 --- a/connection/connectionfactory.h +++ b/connection/connectionfactory.h @@ -28,8 +28,24 @@ MInputContextConnection *createInputContextConnectionWithFixedAddress(const QStr #ifdef HAVE_WAYLAND MInputContextConnection *createWestonIMProtocolConnection(); +MInputContextConnection *createDBusAndWaylandConnectionWithDynamicAddress(); +MInputContextConnection *createDBusAndWaylandConnectionWithFixedAddress(const QString &fixedAddress, bool allowAnonymous); #endif +enum class ConnectionMode { + DBus, + Wayland, + DBusAndWayland +}; + +/*! Picks the input context connection from the environment. + * + * MALIIT_CONNECTION=dbus|wayland|both selects the connection explicitly. + * Without it, MALIIT_FORCE_DBUS_CONNECTION keeps its old meaning. Wayland + * connections are only used when running on a Wayland Qt platform. + */ +ConnectionMode connectionModeFromEnvironment(); + } // namespace Maliit #endif // MALIIT_DBUS_CONNECTIONFACTORY_H diff --git a/connection/dbuswaylandinputcontextconnection.cpp b/connection/dbuswaylandinputcontextconnection.cpp new file mode 100644 index 00000000..0242d984 --- /dev/null +++ b/connection/dbuswaylandinputcontextconnection.cpp @@ -0,0 +1,140 @@ +/* * This file is part of Maliit framework * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * and appearing in the file LICENSE.LGPL included in the packaging + * of this file. + */ + +#include "dbuswaylandinputcontextconnection.h" +#include "waylandinputmethodtransport.h" + +#include + +namespace { + +// TODO: Deduplicate it. Same values as in minputcontextconnection.cpp. +const char * const SurroundingTextAttribute = "surroundingText"; +const char * const CursorPositionAttribute = "cursorPosition"; + +} // unnamed namespace + +DBusWaylandInputContextConnection::DBusWaylandInputContextConnection(const QSharedPointer &address) + : DBusInputContextConnection(address) + , m_transport(new Maliit::Wayland::InputMethodTransport(this)) +{ +} + +DBusWaylandInputContextConnection::~DBusWaylandInputContextConnection() +{ +} + +bool DBusWaylandInputContextConnection::waylandClientActive() const +{ + return activeConnection == Maliit::Wayland::ConnectionId; +} + +void DBusWaylandInputContextConnection::sendPreeditString(const QString &string, + const QList &preeditFormats, + int replacementStart, + int replacementLength, + int cursorPos) +{ + if (!waylandClientActive()) { + DBusInputContextConnection::sendPreeditString(string, preeditFormats, + replacementStart, replacementLength, + cursorPos); + return; + } + + if (!m_transport->context()) + return; + + MInputContextConnection::sendPreeditString(string, preeditFormats, + replacementStart, replacementLength, + cursorPos); + + m_transport->sendPreeditString(string, preeditFormats, replacementStart, replacementLength, cursorPos, + widgetState().value(CursorPositionAttribute).toInt()); +} + +void DBusWaylandInputContextConnection::sendCommitString(const QString &string, + int replaceStart, + int replaceLength, + int cursorPos) +{ + if (!waylandClientActive()) { + DBusInputContextConnection::sendCommitString(string, replaceStart, replaceLength, cursorPos); + return; + } + + if (!m_transport->context()) + return; + + MInputContextConnection::sendCommitString(string, replaceStart, replaceLength, cursorPos); + + m_transport->sendCommitString(string, replaceStart, replaceLength, cursorPos, + widgetState().value(CursorPositionAttribute).toInt()); +} + +void DBusWaylandInputContextConnection::sendKeyEvent(const QKeyEvent &keyEvent, + Maliit::EventRequestType requestType) +{ + if (!waylandClientActive()) { + DBusInputContextConnection::sendKeyEvent(keyEvent, requestType); + return; + } + + if (!m_transport->context()) + return; + + Maliit::Wayland::InputMethodTransport::Key key; + if (!Maliit::Wayland::InputMethodTransport::keyFromQKeyEvent(keyEvent, &key)) + return; + + MInputContextConnection::sendKeyEvent(keyEvent, requestType); + + m_transport->sendKey(key, keyEvent.timestamp()); +} + +void DBusWaylandInputContextConnection::setSelection(int start, int length) +{ + if (!waylandClientActive()) { + DBusInputContextConnection::setSelection(start, length); + return; + } + + m_transport->setSelection(start, length, + widgetState().value(SurroundingTextAttribute).toString()); +} + +QString DBusWaylandInputContextConnection::selection(bool &valid) +{ + if (!waylandClientActive()) + return DBusInputContextConnection::selection(valid); + + return m_transport->selection(valid); +} + +void DBusWaylandInputContextConnection::setLanguage(const QString &language) +{ + // Always let the D-Bus side record the language: it is sent to the next + // D-Bus client that becomes active. + DBusInputContextConnection::setLanguage(language); + + if (waylandClientActive()) + m_transport->setLanguage(language); +} + +void DBusWaylandInputContextConnection::sendActivationLostEvent() +{ + if (!waylandClientActive()) { + DBusInputContextConnection::sendActivationLostEvent(); + return; + } + + // Another client takes over while the Wayland client may still be + // focused: don't leave a half-typed word behind as preedit. + m_transport->sendPreeditString(QString(), QList(), 0, 0, 0, 0); +} diff --git a/connection/dbuswaylandinputcontextconnection.h b/connection/dbuswaylandinputcontextconnection.h new file mode 100644 index 00000000..c45ac507 --- /dev/null +++ b/connection/dbuswaylandinputcontextconnection.h @@ -0,0 +1,64 @@ +/* * This file is part of Maliit framework * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * and appearing in the file LICENSE.LGPL included in the packaging + * of this file. + */ + +#ifndef DBUSWAYLANDINPUTCONTEXTCONNECTION_H +#define DBUSWAYLANDINPUTCONTEXTCONNECTION_H + +#include "dbusinputcontextconnection.h" + +#include + +namespace Maliit { +namespace Wayland { +class InputMethodTransport; +} +} + +/*! \internal + * \ingroup maliitserver + * \brief Serves D-Bus input contexts and a zwp_input_method_v1 client at once. + * + * Both kinds of clients share one activeConnection, so the base class decides + * which one is active; outbound calls are routed to the active client only. + */ +class DBusWaylandInputContextConnection : public DBusInputContextConnection +{ + Q_OBJECT + Q_DISABLE_COPY(DBusWaylandInputContextConnection) + +public: + explicit DBusWaylandInputContextConnection(const QSharedPointer &address); + virtual ~DBusWaylandInputContextConnection(); + + //! \reimp + virtual void sendPreeditString(const QString &string, + const QList &preeditFormats, + int replacementStart = 0, + int replacementLength = 0, + int cursorPos = -1); + virtual void sendCommitString(const QString &string, + int replaceStart = 0, + int replaceLength = 0, + int cursorPos = -1); + virtual void sendKeyEvent(const QKeyEvent &keyEvent, + Maliit::EventRequestType requestType); + virtual void setSelection(int start, int length); + virtual QString selection(bool &valid); + virtual void setLanguage(const QString &language); + virtual void sendActivationLostEvent(); + //! \reimp_end + +private: + bool waylandClientActive() const; + + const QScopedPointer m_transport; +}; +//! \internal_end + +#endif // DBUSWAYLANDINPUTCONTEXTCONNECTION_H diff --git a/connection/waylandinputmethodconnection.cpp b/connection/waylandinputmethodconnection.cpp index 25e6fbfa..41364973 100644 --- a/connection/waylandinputmethodconnection.cpp +++ b/connection/waylandinputmethodconnection.cpp @@ -23,6 +23,7 @@ #include #include "waylandinputmethodconnection.h" +#include "waylandinputmethodtransport.h" Q_LOGGING_CATEGORY(lcWaylandConnection, "maliit.connection.wayland") @@ -156,7 +157,7 @@ bool matchesFlag(int value, return ((value & flag) == flag); } -const unsigned int wayland_connection_id(1); +const unsigned int wayland_connection_id(Maliit::Wayland::ConnectionId); } // unnamed namespace @@ -206,29 +207,6 @@ class InputMethodContext : public QtWayland::zwp_input_method_context_v1 QString m_selection; }; -} -} - -struct WaylandInputMethodConnectionPrivate -{ - Q_DECLARE_PUBLIC(WaylandInputMethodConnection) - - WaylandInputMethodConnectionPrivate(WaylandInputMethodConnection *connection); - ~WaylandInputMethodConnectionPrivate(); - - void handleRegistryGlobal(uint32_t name, - const char *interface, - uint32_t version); - void handleRegistryGlobalRemove(uint32_t name); - - Maliit::Wayland::InputMethodContext *context(); - - WaylandInputMethodConnection *q_ptr; - wl_display *display; - wl_registry *registry; - QScopedPointer input_method; -}; - namespace { void registryGlobal(void *data, @@ -237,8 +215,8 @@ void registryGlobal(void *data, const char *interface, uint32_t version) { - WaylandInputMethodConnectionPrivate *d = - static_cast(data); + InputMethodTransport *d = + static_cast(data); Q_UNUSED(registry); d->handleRegistryGlobal(name, interface, version); @@ -248,8 +226,8 @@ void registryGlobalRemove(void *data, wl_registry *registry, uint32_t name) { - WaylandInputMethodConnectionPrivate *d = - static_cast(data); + InputMethodTransport *d = + static_cast(data); Q_UNUSED(registry); d->handleRegistryGlobalRemove(name); @@ -260,11 +238,10 @@ const wl_registry_listener maliit_registry_listener = { registryGlobalRemove }; - } // unnamed namespace -WaylandInputMethodConnectionPrivate::WaylandInputMethodConnectionPrivate(WaylandInputMethodConnection *connection) - : q_ptr(connection), +InputMethodTransport::InputMethodTransport(MInputContextConnection *owner) + : owner(owner), display(0), registry(0), input_method() @@ -278,7 +255,7 @@ WaylandInputMethodConnectionPrivate::WaylandInputMethodConnectionPrivate(Wayland wl_registry_add_listener(registry, &maliit_registry_listener, this); } -WaylandInputMethodConnectionPrivate::~WaylandInputMethodConnectionPrivate() +InputMethodTransport::~InputMethodTransport() { input_method.reset(); if (registry) { @@ -286,61 +263,41 @@ WaylandInputMethodConnectionPrivate::~WaylandInputMethodConnectionPrivate() } } -void WaylandInputMethodConnectionPrivate::handleRegistryGlobal(uint32_t name, - const char *interface, - uint32_t version) +void InputMethodTransport::handleRegistryGlobal(uint32_t name, + const char *interface, + uint32_t version) { Q_UNUSED(version); - Q_Q(WaylandInputMethodConnection); if (!strcmp(interface, "zwp_input_method_v1")) { - input_method.reset(new Maliit::Wayland::InputMethod(q, registry, name)); + input_method.reset(new InputMethod(owner, registry, name)); } } -void WaylandInputMethodConnectionPrivate::handleRegistryGlobalRemove(uint32_t name) +void InputMethodTransport::handleRegistryGlobalRemove(uint32_t name) { qCDebug(lcWaylandConnection) << Q_FUNC_INFO << name; } -Maliit::Wayland::InputMethodContext *WaylandInputMethodConnectionPrivate::context() +InputMethodContext *InputMethodTransport::context() { return input_method ? input_method->context() : 0; } -// MInputContextWestonIMProtocolConnection - -WaylandInputMethodConnection::WaylandInputMethodConnection() - : d_ptr(new WaylandInputMethodConnectionPrivate(this)) +void InputMethodTransport::sendPreeditString(const QString &string, + const QList &preedit_formats, + int replace_start, + int replace_length, + int cursor_pos, + int widget_cursor) { -} - -WaylandInputMethodConnection::~WaylandInputMethodConnection() -{ -} - -void WaylandInputMethodConnection::sendPreeditString(const QString &string, - const QList &preedit_formats, - int replace_start, - int replace_length, - int cursor_pos) -{ - Q_D(WaylandInputMethodConnection); - - qCDebug(lcWaylandConnection) << Q_FUNC_INFO << string << replace_start << replace_length << cursor_pos; - - if (!d->context()) + if (!context()) return; - MInputContextConnection::sendPreeditString(string, preedit_formats, - replace_start, replace_length, - cursor_pos); - if (replace_length > 0) { - int cursor = widgetState().value(CursorPositionAttribute).toInt(); - uint32_t index = string.midRef(qMin(cursor + replace_start, cursor), qAbs(replace_start)).toUtf8().size(); - uint32_t length = string.midRef(cursor + replace_start, replace_length).toUtf8().size(); - d->context()->delete_surrounding_text(index, length); + uint32_t index = string.midRef(qMin(widget_cursor + replace_start, widget_cursor), qAbs(replace_start)).toUtf8().size(); + uint32_t length = string.midRef(widget_cursor + replace_start, replace_length).toUtf8().size(); + context()->delete_surrounding_text(index, length); } Q_FOREACH (const Maliit::PreeditTextFormat& format, preedit_formats) { @@ -348,7 +305,7 @@ void WaylandInputMethodConnection::sendPreeditString(const QString &string, uint32_t index = string.leftRef(format.start).toUtf8().size(); uint32_t length = string.leftRef(format.start + format.length).toUtf8().size() - index; qCDebug(lcWaylandConnection) << Q_FUNC_INFO << "preedit_styling" << index << length; - d->context()->preedit_styling(index, length, style); + context()->preedit_styling(index, length, style); } // TODO check if defined like that/required @@ -357,124 +314,187 @@ void WaylandInputMethodConnection::sendPreeditString(const QString &string, } qCDebug(lcWaylandConnection) << Q_FUNC_INFO << "preedit_cursor" << string.leftRef(cursor_pos).toUtf8().size(); - d->context()->preedit_cursor(string.leftRef(cursor_pos).toUtf8().size()); + context()->preedit_cursor(string.leftRef(cursor_pos).toUtf8().size()); qCDebug(lcWaylandConnection) << Q_FUNC_INFO << "preedit_string" << string; - d->context()->preedit_string(d->context()->serial(), string, string); + context()->preedit_string(context()->serial(), string, string); } - -void WaylandInputMethodConnection::sendCommitString(const QString &string, - int replace_start, - int replace_length, - int cursor_pos) +void InputMethodTransport::sendCommitString(const QString &string, + int replace_start, + int replace_length, + int cursor_pos, + int widget_cursor) { - Q_D(WaylandInputMethodConnection); - - qCDebug(lcWaylandConnection) << Q_FUNC_INFO << string << replace_start << replace_length << cursor_pos; - - if (!d->context()) + if (!context()) return; - MInputContextConnection::sendCommitString(string, replace_start, replace_length, cursor_pos); - if (cursor_pos != 0) { qCWarning(lcWaylandConnection) << Q_FUNC_INFO << "cursor_pos:" << cursor_pos << "!= 0 not supported yet"; cursor_pos = 0; } if (replace_length > 0) { - int cursor = widgetState().value(CursorPositionAttribute).toInt(); - uint32_t index = string.midRef(qMin(cursor + replace_start, cursor), qAbs(replace_start)).toUtf8().size(); - uint32_t length = string.midRef(cursor + replace_start, replace_length).toUtf8().size(); - d->context()->delete_surrounding_text(index, length); + uint32_t index = string.midRef(qMin(widget_cursor + replace_start, widget_cursor), qAbs(replace_start)).toUtf8().size(); + uint32_t length = string.midRef(widget_cursor + replace_start, replace_length).toUtf8().size(); + context()->delete_surrounding_text(index, length); } cursor_pos = string.leftRef(cursor_pos).toUtf8().size(); - d->context()->cursor_position(cursor_pos, cursor_pos); - d->context()->commit_string(d->context()->serial(), string); + context()->cursor_position(cursor_pos, cursor_pos); + context()->commit_string(context()->serial(), string); } -void WaylandInputMethodConnection::sendKeyEvent(const QKeyEvent &keyEvent, - Maliit::EventRequestType requestType) +bool InputMethodTransport::keyFromQKeyEvent(const QKeyEvent &keyEvent, Key *key) { - Q_D(WaylandInputMethodConnection); - - qCDebug(lcWaylandConnection) << Q_FUNC_INFO; - - if (!d->context()) - return; - - xkb_keysym_t sym(keyFromQt(keyEvent.key())); + key->sym = keyFromQt(keyEvent.key()); - if (sym == XKB_KEY_NoSymbol) { + if (key->sym == XKB_KEY_NoSymbol) { qCWarning(lcWaylandConnection) << "No conversion from Qt::Key:" << keyEvent.key() << "to XKB key. Update the keyFromQt() function."; - return; + return false; } - wl_keyboard_key_state state; - switch (keyEvent.type()) { case QEvent::KeyPress: - state = WL_KEYBOARD_KEY_STATE_PRESSED; + key->state = WL_KEYBOARD_KEY_STATE_PRESSED; break; case QEvent::KeyRelease: - state = WL_KEYBOARD_KEY_STATE_RELEASED; + key->state = WL_KEYBOARD_KEY_STATE_RELEASED; break; default: qCWarning(lcWaylandConnection) << "Unknown QKeyEvent type:" << keyEvent.type(); - return; + return false; } - xkb_mod_mask_t modifiers(modifiersFromQt(keyEvent.modifiers())); + key->modifiers = modifiersFromQt(keyEvent.modifiers()); + return true; +} - MInputContextConnection::sendKeyEvent(keyEvent, requestType); +void InputMethodTransport::sendKey(const Key &key, uint32_t timestamp) +{ + if (!context()) + return; - d->context()->keysym(d->context()->serial(), - keyEvent.timestamp(), - sym, state, modifiers); + context()->keysym(context()->serial(), timestamp, + key.sym, key.state, key.modifiers); } -QString WaylandInputMethodConnection::selection(bool &valid) +QString InputMethodTransport::selection(bool &valid) { - Q_D(WaylandInputMethodConnection); + InputMethodContext *ctx = context(); - qCDebug(lcWaylandConnection) << Q_FUNC_INFO; + valid = ctx && !ctx->selection().isEmpty(); + return ctx ? ctx->selection() : QString(); +} - Maliit::Wayland::InputMethodContext *context = d->input_method->context(); +void InputMethodTransport::setLanguage(const QString &language) +{ + if (!context()) + return; - valid = context && !context->selection().isEmpty(); - return context ? context->selection() : QString(); + context()->language(context()->serial(), language); } -void WaylandInputMethodConnection::setLanguage(const QString &language) +void InputMethodTransport::setSelection(int start, int length, const QString &surrounding) { - Q_D(WaylandInputMethodConnection); + if (!context()) + return; - qCDebug(lcWaylandConnection) << Q_FUNC_INFO; + uint32_t index(surrounding.leftRef(start + length).toUtf8().size()); + uint32_t anchor(surrounding.leftRef(start).toUtf8().size()); + + context()->cursor_position(index, anchor); + context()->commit_string(context()->serial(), QString()); +} - if (!d->context()) +} // namespace Wayland +} // namespace Maliit + +// MInputContextWestonIMProtocolConnection + +WaylandInputMethodConnection::WaylandInputMethodConnection() + : m_transport(new Maliit::Wayland::InputMethodTransport(this)) +{ +} + +WaylandInputMethodConnection::~WaylandInputMethodConnection() +{ +} + +void WaylandInputMethodConnection::sendPreeditString(const QString &string, + const QList &preedit_formats, + int replace_start, + int replace_length, + int cursor_pos) +{ + qCDebug(lcWaylandConnection) << Q_FUNC_INFO << string << replace_start << replace_length << cursor_pos; + + if (!m_transport->context()) return; - d->context()->language(d->context()->serial(), language); + MInputContextConnection::sendPreeditString(string, preedit_formats, + replace_start, replace_length, + cursor_pos); + + m_transport->sendPreeditString(string, preedit_formats, replace_start, replace_length, cursor_pos, + widgetState().value(CursorPositionAttribute).toInt()); } -void WaylandInputMethodConnection::setSelection(int start, int length) + +void WaylandInputMethodConnection::sendCommitString(const QString &string, + int replace_start, + int replace_length, + int cursor_pos) { - Q_D (WaylandInputMethodConnection); + qCDebug(lcWaylandConnection) << Q_FUNC_INFO << string << replace_start << replace_length << cursor_pos; + if (!m_transport->context()) + return; + + MInputContextConnection::sendCommitString(string, replace_start, replace_length, cursor_pos); + + m_transport->sendCommitString(string, replace_start, replace_length, cursor_pos, + widgetState().value(CursorPositionAttribute).toInt()); +} + +void WaylandInputMethodConnection::sendKeyEvent(const QKeyEvent &keyEvent, + Maliit::EventRequestType requestType) +{ qCDebug(lcWaylandConnection) << Q_FUNC_INFO; - if (!d->context()) + if (!m_transport->context()) return; - QString surrounding = widgetState().value(SurroundingTextAttribute).toString(); - uint32_t index(surrounding.leftRef(start + length).toUtf8().size()); - uint32_t anchor(surrounding.leftRef(start).toUtf8().size()); + Maliit::Wayland::InputMethodTransport::Key key; + if (!Maliit::Wayland::InputMethodTransport::keyFromQKeyEvent(keyEvent, &key)) + return; + + MInputContextConnection::sendKeyEvent(keyEvent, requestType); + + m_transport->sendKey(key, keyEvent.timestamp()); +} + +QString WaylandInputMethodConnection::selection(bool &valid) +{ + qCDebug(lcWaylandConnection) << Q_FUNC_INFO; + + return m_transport->selection(valid); +} + +void WaylandInputMethodConnection::setLanguage(const QString &language) +{ + qCDebug(lcWaylandConnection) << Q_FUNC_INFO; + + m_transport->setLanguage(language); +} + +void WaylandInputMethodConnection::setSelection(int start, int length) +{ + qCDebug(lcWaylandConnection) << Q_FUNC_INFO; - d->context()->cursor_position(index, anchor); - d->context()->commit_string(d->context()->serial(), QString()); + m_transport->setSelection(start, length, + widgetState().value(SurroundingTextAttribute).toString()); } namespace Maliit { diff --git a/connection/waylandinputmethodconnection.h b/connection/waylandinputmethodconnection.h index d436be4b..1628f472 100644 --- a/connection/waylandinputmethodconnection.h +++ b/connection/waylandinputmethodconnection.h @@ -20,7 +20,11 @@ Q_DECLARE_LOGGING_CATEGORY(lcWaylandConnection) -class WaylandInputMethodConnectionPrivate; +namespace Maliit { +namespace Wayland { +class InputMethodTransport; +} +} /*! \internal * \ingroup maliitserver @@ -31,7 +35,6 @@ class WaylandInputMethodConnection : public MInputContextConnection { Q_OBJECT Q_DISABLE_COPY(WaylandInputMethodConnection) - Q_DECLARE_PRIVATE(WaylandInputMethodConnection) public: explicit WaylandInputMethodConnection(); @@ -54,7 +57,7 @@ class WaylandInputMethodConnection : public MInputContextConnection virtual void setLanguage(const QString &language); private: - const QScopedPointer d_ptr; + const QScopedPointer m_transport; }; //! \internal_end diff --git a/connection/waylandinputmethodtransport.h b/connection/waylandinputmethodtransport.h new file mode 100644 index 00000000..2d491029 --- /dev/null +++ b/connection/waylandinputmethodtransport.h @@ -0,0 +1,82 @@ +/* * This file is part of Maliit framework * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * and appearing in the file LICENSE.LGPL included in the packaging + * of this file. + */ + +#ifndef WAYLAND_INPUT_METHOD_TRANSPORT_H +#define WAYLAND_INPUT_METHOD_TRANSPORT_H + +#include +#include "minputcontextconnection.h" + +#include "wayland-client.h" +#include + +#include + +#include + +class QKeyEvent; + +namespace Maliit { +namespace Wayland { + +// D-Bus connection ids count up from 1 (0 means "no active connection"), so the +// Wayland client uses the top of the range to keep both id spaces disjoint. +const unsigned int ConnectionId = std::numeric_limits::max(); + +class InputMethod; +class InputMethodContext; + +// Speaks zwp_input_method_v1 on behalf of MInputContextConnection. +class InputMethodTransport +{ +public: + struct Key { + xkb_keysym_t sym; + wl_keyboard_key_state state; + xkb_mod_mask_t modifiers; + }; + + explicit InputMethodTransport(MInputContextConnection *owner); + ~InputMethodTransport(); + + void handleRegistryGlobal(uint32_t name, + const char *interface, + uint32_t version); + void handleRegistryGlobalRemove(uint32_t name); + + InputMethodContext *context(); + + void sendPreeditString(const QString &string, + const QList &preedit_formats, + int replace_start, + int replace_length, + int cursor_pos, + int widget_cursor); + void sendCommitString(const QString &string, + int replace_start, + int replace_length, + int cursor_pos, + int widget_cursor); + static bool keyFromQKeyEvent(const QKeyEvent &keyEvent, Key *key); + void sendKey(const Key &key, uint32_t timestamp); + QString selection(bool &valid); + void setLanguage(const QString &language); + void setSelection(int start, int length, const QString &surrounding); + +private: + MInputContextConnection *owner; + wl_display *display; + wl_registry *registry; + QScopedPointer input_method; +}; + +} // namespace Wayland +} // namespace Maliit + +#endif // WAYLAND_INPUT_METHOD_TRANSPORT_H diff --git a/passthroughserver/main.cpp b/passthroughserver/main.cpp index a8c287a6..59364a46 100644 --- a/passthroughserver/main.cpp +++ b/passthroughserver/main.cpp @@ -48,12 +48,22 @@ void loggingCategoryFilter(QLoggingCategory *category) QSharedPointer createConnection(const MImServerConnectionOptions &options) { + const Maliit::ConnectionMode mode = Maliit::connectionModeFromEnvironment(); + #ifdef HAVE_WAYLAND - auto forceDbus = qgetenv("MALIIT_FORCE_DBUS_CONNECTION"); - if (QGuiApplication::platformName().startsWith("wayland") && (forceDbus.isEmpty() || forceDbus == "0")) { + if (mode == Maliit::ConnectionMode::Wayland) { return QSharedPointer(Maliit::createWestonIMProtocolConnection()); - } else + } else if (mode == Maliit::ConnectionMode::DBusAndWayland) { + if (options.overriddenAddress.isEmpty()) { + return QSharedPointer(Maliit::createDBusAndWaylandConnectionWithDynamicAddress()); + } + return QSharedPointer(Maliit::createDBusAndWaylandConnectionWithFixedAddress(options.overriddenAddress, + options.allowAnonymous)); + } +#else + Q_UNUSED(mode); #endif + if (options.overriddenAddress.isEmpty()) { return QSharedPointer(Maliit::DBus::createInputContextConnectionWithDynamicAddress()); } else { diff --git a/src/maliit/standaloneinputmethod.cpp b/src/maliit/standaloneinputmethod.cpp index 0ef25b33..b70e6a16 100644 --- a/src/maliit/standaloneinputmethod.cpp +++ b/src/maliit/standaloneinputmethod.cpp @@ -129,14 +129,16 @@ void StandaloneInputMethod::handleWidgetStateChanged(unsigned int, std::unique_ptr createConnection() { + switch (Maliit::connectionModeFromEnvironment()) { #ifdef HAVE_WAYLAND - auto forceDbus = qgetenv("MALIIT_FORCE_DBUS_CONNECTION"); - if (QGuiApplication::platformName().startsWith("wayland") && (forceDbus.isEmpty() || forceDbus == "0")) { + case Maliit::ConnectionMode::Wayland: return std::unique_ptr(Maliit::createWestonIMProtocolConnection()); - } else + case Maliit::ConnectionMode::DBusAndWayland: + return std::unique_ptr(Maliit::createDBusAndWaylandConnectionWithDynamicAddress()); #endif + default: return std::unique_ptr(Maliit::DBus::createInputContextConnectionWithDynamicAddress()); - + } } }