summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2020-08-14 09:51:07 +0200
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2020-08-26 08:49:12 +0200
commitf7885bb4eb2660ff4e287996061c9c1d987e5c60 (patch)
tree0474204dab9a896a3bb2f5ccae0bd62794c42739
parent0a4ce63b6177538a9abed89daefc43cc47247fc1 (diff)
New input method protocol for use with Qt clients
We introduce an alternative input-method protocol, which is a one-to-one mapping to Qt's input method API. Input methods such as the virtual keyboard's hunspell integration is quite sensitive to the inner workings of the input method handling, both in terms of when state is updated and which updates are delivered when. With a one-to-one mapping we are able to match these expectations and keep a well-synchronized state. Task-number: QTBUG-85135 Task-number: QTBUG-85134 Change-Id: Id69c22a7b0885ea59f39fdcc8d663749af56c7ce Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
-rw-r--r--examples/wayland/pure-qml/qml/main.qml2
-rw-r--r--src/client/.prev_CMakeLists.txt3
-rw-r--r--src/client/CMakeLists.txt2
-rw-r--r--src/client/client.pro3
-rw-r--r--src/client/qwaylanddisplay.cpp13
-rw-r--r--src/client/qwaylanddisplay_p.h3
-rw-r--r--src/client/qwaylandinputdevice.cpp14
-rw-r--r--src/client/qwaylandinputdevice_p.h5
-rw-r--r--src/client/qwaylandinputmethodcontext.cpp421
-rw-r--r--src/client/qwaylandinputmethodcontext_p.h152
-rw-r--r--src/client/qwaylandintegration.cpp11
-rw-r--r--src/compositor/.prev_CMakeLists.txt3
-rw-r--r--src/compositor/CMakeLists.txt3
-rw-r--r--src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h2
-rw-r--r--src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp43
-rw-r--r--src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h2
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.cpp16
-rw-r--r--src/compositor/compositor_api/qwaylandseat.cpp7
-rw-r--r--src/compositor/extensions/extensions.pri7
-rw-r--r--src/compositor/extensions/qwaylandqttextinputmethod.cpp459
-rw-r--r--src/compositor/extensions/qwaylandqttextinputmethod.h81
-rw-r--r--src/compositor/extensions/qwaylandqttextinputmethod_p.h105
-rw-r--r--src/compositor/extensions/qwaylandqttextinputmethodmanager.cpp115
-rw-r--r--src/compositor/extensions/qwaylandqttextinputmethodmanager.h57
-rw-r--r--src/compositor/extensions/qwaylandqttextinputmethodmanager_p.h62
-rw-r--r--src/extensions/qt-text-input-method-unstable-v1.xml301
-rw-r--r--sync.profile4
27 files changed, 1881 insertions, 15 deletions
diff --git a/examples/wayland/pure-qml/qml/main.qml b/examples/wayland/pure-qml/qml/main.qml
index 448c5ff8f..5a21735b2 100644
--- a/examples/wayland/pure-qml/qml/main.qml
+++ b/examples/wayland/pure-qml/qml/main.qml
@@ -70,5 +70,5 @@ WaylandCompositor {
}
// Extension for Input Method (QT_IM_MODULE) support at compositor-side
- TextInputManager {}
+ QtTextInputMethodManager {}
}
diff --git a/src/client/.prev_CMakeLists.txt b/src/client/.prev_CMakeLists.txt
index ac323a56f..454b06ae3 100644
--- a/src/client/.prev_CMakeLists.txt
+++ b/src/client/.prev_CMakeLists.txt
@@ -30,6 +30,7 @@ qt_add_module(WaylandClient
qwaylandextendedsurface.cpp qwaylandextendedsurface_p.h
qwaylandinputcontext.cpp qwaylandinputcontext_p.h
qwaylandinputdevice.cpp qwaylandinputdevice_p.h
+ qwaylandinputmethodcontext.cpp qwaylandinputmethodcontext_p.h
qwaylandintegration.cpp qwaylandintegration_p.h
qwaylandnativeinterface.cpp qwaylandnativeinterface_p.h
qwaylandqtkey.cpp qwaylandqtkey_p.h
@@ -56,7 +57,6 @@ qt_add_module(WaylandClient
LIBRARIES
Qt::CorePrivate
Qt::GuiPrivate
- Qt::PlatformHeadersPrivate
PUBLIC_LIBRARIES
Qt::Core
Qt::Gui
@@ -74,6 +74,7 @@ qt6_generate_wayland_protocol_client_sources(WaylandClient
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/wp-primary-selection-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-output-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-key-unstable-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-text-input-method-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-windowmanager.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/surface-extension.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/touch-extension.xml
diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt
index 88b27b5f3..01957eacd 100644
--- a/src/client/CMakeLists.txt
+++ b/src/client/CMakeLists.txt
@@ -30,6 +30,7 @@ qt_add_module(WaylandClient
qwaylandextendedsurface.cpp qwaylandextendedsurface_p.h
qwaylandinputcontext.cpp qwaylandinputcontext_p.h
qwaylandinputdevice.cpp qwaylandinputdevice_p.h
+ qwaylandinputmethodcontext.cpp qwaylandinputmethodcontext_p.h
qwaylandintegration.cpp qwaylandintegration_p.h
qwaylandnativeinterface.cpp qwaylandnativeinterface_p.h
qwaylandqtkey.cpp qwaylandqtkey_p.h
@@ -73,6 +74,7 @@ qt6_generate_wayland_protocol_client_sources(WaylandClient
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/wp-primary-selection-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-output-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-key-unstable-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-text-input-method-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-windowmanager.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/surface-extension.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/touch-extension.xml
diff --git a/src/client/client.pro b/src/client/client.pro
index d6df946b5..da6a926dc 100644
--- a/src/client/client.pro
+++ b/src/client/client.pro
@@ -22,6 +22,7 @@ WAYLANDCLIENTSOURCES += \
../extensions/touch-extension.xml \
../extensions/qt-key-unstable-v1.xml \
../extensions/qt-windowmanager.xml \
+ ../extensions/qt-text-input-method-unstable-v1.xml \
../3rdparty/protocol/wp-primary-selection-unstable-v1.xml \
../3rdparty/protocol/tablet-unstable-v2.xml \
../3rdparty/protocol/text-input-unstable-v2.xml \
@@ -50,6 +51,7 @@ SOURCES += qwaylandintegration.cpp \
qwaylanddecorationplugin.cpp \
qwaylandwindowmanagerintegration.cpp \
qwaylandinputcontext.cpp \
+ qwaylandinputmethodcontext.cpp \
qwaylandshm.cpp \
qwaylandbuffer.cpp \
@@ -74,6 +76,7 @@ HEADERS += qwaylandintegration_p.h \
qwaylanddecorationplugin_p.h \
qwaylandwindowmanagerintegration_p.h \
qwaylandinputcontext_p.h \
+ qwaylandinputmethodcontext_p.h \
qwaylandshm_p.h \
qtwaylandclientglobal.h \
qtwaylandclientglobal_p.h \
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index 9e5359357..e39f91280 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -61,6 +61,7 @@
#endif
#include "qwaylandhardwareintegration_p.h"
#include "qwaylandinputcontext_p.h"
+#include "qwaylandinputmethodcontext_p.h"
#include "qwaylandwindowmanagerintegration_p.h"
#include "qwaylandshellintegration_p.h"
@@ -74,6 +75,7 @@
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
#include <QtWaylandClient/private/qwayland-wp-primary-selection-unstable-v1.h>
+#include <QtWaylandClient/private/qwayland-qt-text-input-method-unstable-v1.h>
#include <QtCore/private/qcore_unix_p.h>
@@ -339,6 +341,11 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
} else if (interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
#endif
+ } else if (interface == QStringLiteral("qt_text_input_method_manager_v1") && !mClientSideInputContextRequested) {
+ mTextInputMethodManager.reset(new QtWayland::qt_text_input_method_manager_v1(registry, id, 1));
+ for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ inputDevice->setTextInputMethod(new QWaylandTextInputMethod(this, mTextInputMethodManager->get_text_input_method(inputDevice->wl_seat())));
+ mWaylandIntegration->reconfigureInputContext();
} else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) {
mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1));
for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
@@ -396,6 +403,12 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
inputDevice->setTextInput(nullptr);
mWaylandIntegration->reconfigureInputContext();
}
+ if (global.interface == QStringLiteral("qt_text_input_method_manager_v1")) {
+ mTextInputMethodManager.reset();
+ for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ inputDevice->setTextInputMethod(nullptr);
+ mWaylandIntegration->reconfigureInputContext();
+ }
mGlobals.removeAt(i);
break;
}
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index d386c66ac..68d72812f 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -81,6 +81,7 @@ class QPlatformPlaceholderScreen;
namespace QtWayland {
class qt_surface_extension;
class zwp_text_input_manager_v2;
+ class qt_text_input_method_manager_v1;
}
namespace QtWaylandClient {
@@ -163,6 +164,7 @@ public:
QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); }
QWaylandTabletManagerV2 *tabletManager() const { return mTabletManager.data(); }
QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); }
+ QtWayland::qt_text_input_method_manager_v1 *textInputMethodManager() const { return mTextInputMethodManager.data(); }
QtWayland::zwp_text_input_manager_v2 *textInputManager() const { return mTextInputManager.data(); }
QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); }
QWaylandXdgOutputManagerV1 *xdgOutputManager() const { return mXdgOutputManager.data(); }
@@ -268,6 +270,7 @@ private:
#if QT_CONFIG(wayland_client_primary_selection)
QScopedPointer<QWaylandPrimarySelectionDeviceManagerV1> mPrimarySelectionManager;
#endif
+ QScopedPointer<QtWayland::qt_text_input_method_manager_v1> mTextInputMethodManager;
QScopedPointer<QtWayland::zwp_text_input_manager_v2> mTextInputManager;
QScopedPointer<QWaylandHardwareIntegration> mHardwareIntegration;
QScopedPointer<QWaylandXdgOutputManagerV1> mXdgOutputManager;
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index e86274276..343ccc8d7 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -57,6 +57,7 @@
#include "qwaylanddisplay_p.h"
#include "qwaylandshmbackingstore_p.h"
#include "qwaylandinputcontext_p.h"
+#include "qwaylandinputmethodcontext_p.h"
#include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/private/qguiapplication_p.h>
@@ -420,6 +421,9 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version,
if (mQDisplay->textInputManager())
mTextInput.reset(new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat())));
+ if (mQDisplay->textInputMethodManager())
+ mTextInputMethod.reset(new QWaylandTextInputMethod(mQDisplay, mQDisplay->textInputMethodManager()->get_text_input_method(wl_seat())));
+
if (auto *tm = mQDisplay->tabletManager())
mTabletSeat.reset(new QWaylandTabletSeatV2(tm, this));
}
@@ -535,11 +539,21 @@ void QWaylandInputDevice::setTextInput(QWaylandTextInput *textInput)
mTextInput.reset(textInput);
}
+void QWaylandInputDevice::setTextInputMethod(QWaylandTextInputMethod *textInputMethod)
+{
+ mTextInputMethod.reset(textInputMethod);
+}
+
QWaylandTextInput *QWaylandInputDevice::textInput() const
{
return mTextInput.data();
}
+QWaylandTextInputMethod *QWaylandInputDevice::textInputMethod() const
+{
+ return mTextInputMethod.data();
+}
+
void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button)
{
if (mPointer)
diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h
index 31bd30088..53691e682 100644
--- a/src/client/qwaylandinputdevice_p.h
+++ b/src/client/qwaylandinputdevice_p.h
@@ -91,6 +91,7 @@ class QWaylandPrimarySelectionDeviceV1;
#endif
class QWaylandTabletSeatV2;
class QWaylandTextInput;
+class QWaylandTextInputMethod;
#if QT_CONFIG(cursor)
class QWaylandCursorTheme;
class CursorSurface;
@@ -134,6 +135,9 @@ public:
void setTextInput(QWaylandTextInput *textInput);
QWaylandTextInput *textInput() const;
+ void setTextInputMethod(QWaylandTextInputMethod *textInputMethod);
+ QWaylandTextInputMethod *textInputMethod() const;
+
void removeMouseButtonFromState(Qt::MouseButton button);
QWaylandWindow *pointerFocus() const;
@@ -187,6 +191,7 @@ private:
Touch *mTouch = nullptr;
QScopedPointer<QWaylandTextInput> mTextInput;
+ QScopedPointer<QWaylandTextInputMethod> mTextInputMethod;
QScopedPointer<QWaylandTabletSeatV2> mTabletSeat;
uint32_t mTime = 0;
diff --git a/src/client/qwaylandinputmethodcontext.cpp b/src/client/qwaylandinputmethodcontext.cpp
new file mode 100644
index 000000000..e6ab1da4f
--- /dev/null
+++ b/src/client/qwaylandinputmethodcontext.cpp
@@ -0,0 +1,421 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandinputmethodcontext_p.h"
+#include "qwaylanddisplay_p.h"
+#include "qwaylandinputdevice_p.h"
+
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qtextformat.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(qLcQpaInputMethods)
+
+namespace QtWaylandClient {
+
+static constexpr int maxStringSize = 1000; // actual max is 4096/3
+
+QWaylandTextInputMethod::QWaylandTextInputMethod(QWaylandDisplay *display, struct ::qt_text_input_method_v1 *textInputMethod)
+ : QtWayland::qt_text_input_method_v1(textInputMethod)
+ , m_display(display)
+{
+}
+
+QWaylandTextInputMethod::~QWaylandTextInputMethod()
+{
+}
+
+void QWaylandTextInputMethod::text_input_method_v1_visible_changed(int32_t visible)
+{
+ m_isVisible = visible;
+}
+
+void QWaylandTextInputMethod::text_input_method_v1_locale_changed(const QString &localeName)
+{
+ m_locale = QLocale(localeName);
+}
+
+void QWaylandTextInputMethod::text_input_method_v1_input_direction_changed(int32_t inputDirection)
+{
+ m_layoutDirection = Qt::LayoutDirection(inputDirection);
+}
+
+void QWaylandTextInputMethod::text_input_method_v1_keyboard_rectangle_changed(wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height)
+{
+ m_keyboardRect = QRectF(wl_fixed_to_double(x),
+ wl_fixed_to_double(y),
+ wl_fixed_to_double(width),
+ wl_fixed_to_double(height));
+}
+
+void QWaylandTextInputMethod::text_input_method_v1_start_input_method_event(uint32_t serial, int32_t surrounding_text_offset)
+{
+ if (m_pendingInputMethodEvents.contains(serial)) {
+ qCWarning(qLcQpaInputMethods) << "Input method event with serial" << serial << "already started";
+ return;
+ }
+
+ m_pendingInputMethodEvents[serial] = QList<QInputMethodEvent::Attribute>{};
+ m_offsetFromCompositor[serial] = surrounding_text_offset;
+}
+
+// We need to keep surrounding text below maxStringSize characters, with cursorPos centered in that substring
+
+static int calculateOffset(const QString &text, int cursorPos)
+{
+ int size = text.size();
+ int halfSize = maxStringSize/2;
+ if (size <= maxStringSize || cursorPos < halfSize)
+ return 0;
+ if (cursorPos > size - halfSize)
+ return size - maxStringSize;
+ return cursorPos - halfSize;
+}
+
+static QString mapSurroundingTextToCompositor(const QString &s, int offset)
+{
+ return s.mid(offset, maxStringSize);
+}
+
+static int mapPositionToCompositor(int pos, int offset)
+{
+ return pos - offset;
+}
+
+static int mapPositionFromCompositor(int pos, int offset)
+{
+ return pos + offset;
+}
+
+void QWaylandTextInputMethod::text_input_method_v1_input_method_event_attribute(uint32_t serial, int32_t type, int32_t start, int32_t length, const QString &value)
+{
+ if (!m_pendingInputMethodEvents.contains(serial)) {
+ qCWarning(qLcQpaInputMethods) << "Input method event with serial" << serial << "does not exist";
+ return;
+ }
+
+ int startMapped = mapPositionFromCompositor(start, m_offsetFromCompositor[serial]);
+ QList<QInputMethodEvent::Attribute> &attributes = m_pendingInputMethodEvents[serial];
+ switch (type) {
+ case QInputMethodEvent::Selection:
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::AttributeType(type), startMapped, length));
+ break;
+ case QInputMethodEvent::Cursor:
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::AttributeType(type), start, length, QColor(value)));
+ break;
+ case QInputMethodEvent::TextFormat:
+ {
+ QTextCharFormat textFormat;
+ textFormat.setProperty(QTextFormat::FontUnderline, true);
+ textFormat.setProperty(QTextFormat::TextUnderlineStyle, QTextCharFormat::SingleUnderline);
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::AttributeType(type), start, length, textFormat));
+ break;
+ }
+ case QInputMethodEvent::Language:
+ case QInputMethodEvent::Ruby:
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::AttributeType(type), start, length, value));
+ break;
+ };
+}
+
+void QWaylandTextInputMethod::sendInputState(QInputMethodQueryEvent *event, Qt::InputMethodQueries queries)
+{
+ int cursorPosition = event->value(Qt::ImCursorPosition).toInt();
+ int anchorPosition = event->value(Qt::ImAnchorPosition).toInt();
+ QString surroundingText = event->value(Qt::ImSurroundingText).toString();
+ int offset = calculateOffset(surroundingText, cursorPosition);
+
+ if (queries & Qt::ImCursorPosition)
+ update_cursor_position(mapPositionToCompositor(cursorPosition, offset));
+ if (queries & Qt::ImSurroundingText)
+ update_surrounding_text(mapSurroundingTextToCompositor(surroundingText, offset), offset);
+ if (queries & Qt::ImAnchorPosition)
+ update_anchor_position(mapPositionToCompositor(anchorPosition, offset));
+ if (queries & Qt::ImAbsolutePosition)
+ update_absolute_position(event->value(Qt::ImAbsolutePosition).toInt()); // do not map: this is the position in the whole document
+}
+
+
+void QWaylandTextInputMethod::text_input_method_v1_end_input_method_event(uint32_t serial, const QString &commitString, const QString &preeditString, int32_t replacementStart, int32_t replacementLength)
+{
+ if (!m_pendingInputMethodEvents.contains(serial)) {
+ qCWarning(qLcQpaInputMethods) << "Input method event with serial" << serial << "does not exist";
+ return;
+ }
+
+ QList<QInputMethodEvent::Attribute> attributes = m_pendingInputMethodEvents.take(serial);
+ m_offsetFromCompositor.remove(serial);
+ if (QGuiApplication::focusObject() != nullptr) {
+ QInputMethodEvent event(preeditString, attributes);
+ event.setCommitString(commitString, replacementStart, replacementLength);
+ QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event);
+ }
+
+ // Send current state to make sure it matches
+ if (QGuiApplication::focusObject() != nullptr) {
+ QInputMethodQueryEvent event(Qt::ImCursorPosition | Qt::ImSurroundingText | Qt::ImAnchorPosition | Qt::ImAbsolutePosition);
+ QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event);
+ sendInputState(&event);
+ }
+
+ acknowledge_input_method();
+}
+
+void QWaylandTextInputMethod::text_input_method_v1_key(int32_t type,
+ int32_t key,
+ int32_t modifiers,
+ int32_t autoRepeat,
+ int32_t count,
+ int32_t nativeScanCode,
+ int32_t nativeVirtualKey,
+ int32_t nativeModifiers,
+ const QString &text)
+{
+ if (QGuiApplication::focusObject() != nullptr) {
+ QKeyEvent event(QKeyEvent::Type(type),
+ key,
+ Qt::KeyboardModifiers(modifiers),
+ nativeScanCode,
+ nativeVirtualKey,
+ nativeModifiers,
+ text,
+ autoRepeat,
+ count);
+ QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event);
+ }
+}
+
+void QWaylandTextInputMethod::text_input_method_v1_enter(struct ::wl_surface *surface)
+{
+ m_surface = surface;
+}
+
+void QWaylandTextInputMethod::text_input_method_v1_leave(struct ::wl_surface *surface)
+{
+ if (surface != m_surface) {
+ qCWarning(qLcQpaInputMethods) << "Got leave event for surface without corresponding enter";
+ } else {
+ m_surface = nullptr;
+ }
+}
+
+QWaylandInputMethodContext::QWaylandInputMethodContext(QWaylandDisplay *display)
+ : m_display(display)
+{
+}
+
+QWaylandInputMethodContext::~QWaylandInputMethodContext()
+{
+}
+
+bool QWaylandInputMethodContext::isValid() const
+{
+ return m_display->textInputMethodManager() != nullptr;
+}
+
+void QWaylandInputMethodContext::reset()
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr)
+ inputMethod->reset();
+}
+
+void QWaylandInputMethodContext::commit()
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr)
+ inputMethod->commit();
+
+ m_display->forceRoundTrip();
+}
+
+void QWaylandInputMethodContext::update(Qt::InputMethodQueries queries)
+{
+ wl_surface *currentSurface = m_currentWindow != nullptr && m_currentWindow->handle() != nullptr
+ ? static_cast<QWaylandWindow *>(m_currentWindow->handle())->wlSurface()
+ : nullptr;
+ if (currentSurface != nullptr && !inputMethodAccepted()) {
+ textInputMethod()->disable(currentSurface);
+ m_currentWindow.clear();
+ } else if (currentSurface == nullptr && inputMethodAccepted()) {
+ QWindow *window = QGuiApplication::focusWindow();
+ currentSurface = window != nullptr && window->handle() != nullptr
+ ? static_cast<QWaylandWindow *>(window->handle())->wlSurface()
+ : nullptr;
+ if (currentSurface != nullptr) {
+ textInputMethod()->disable(currentSurface);
+ m_currentWindow = window;
+ }
+ }
+
+ queries &= (Qt::ImEnabled
+ | Qt::ImHints
+ | Qt::ImCursorRectangle
+ | Qt::ImCursorPosition
+ | Qt::ImSurroundingText
+ | Qt::ImCurrentSelection
+ | Qt::ImAnchorPosition
+ | Qt::ImTextAfterCursor
+ | Qt::ImTextBeforeCursor
+ | Qt::ImPreferredLanguage);
+
+ const Qt::InputMethodQueries queriesNeedingOffset = Qt::ImCursorPosition | Qt::ImSurroundingText | Qt::ImAnchorPosition;
+ if (queries & queriesNeedingOffset)
+ queries |= queriesNeedingOffset;
+
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr && QGuiApplication::focusObject() != nullptr) {
+ QInputMethodQueryEvent event(queries);
+ QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event);
+
+ inputMethod->start_update(int(queries));
+
+ if (queries & Qt::ImHints)
+ inputMethod->update_hints(event.value(Qt::ImHints).toInt());
+
+ if (queries & Qt::ImCursorRectangle) {
+ QRect rect = event.value(Qt::ImCursorRectangle).toRect();
+ inputMethod->update_cursor_rectangle(rect.x(), rect.y(), rect.width(), rect.height());
+ }
+
+ inputMethod->sendInputState(&event, queries);
+
+ if (queries & Qt::ImPreferredLanguage)
+ inputMethod->update_preferred_language(event.value(Qt::ImPreferredLanguage).toString());
+
+ inputMethod->end_update();
+
+ // ### Should we do a display sync here and ignore all events until it is received?
+ }
+}
+
+void QWaylandInputMethodContext::invokeAction(QInputMethod::Action action, int cursorPosition)
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr)
+ inputMethod->invoke_action(int(action), cursorPosition);
+}
+
+void QWaylandInputMethodContext::showInputPanel()
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr)
+ inputMethod->show_input_panel();
+}
+
+void QWaylandInputMethodContext::hideInputPanel()
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr)
+ inputMethod->hide_input_panel();
+}
+
+bool QWaylandInputMethodContext::isInputPanelVisible() const
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr)
+ return inputMethod->isVisible();
+ else
+ return false;
+}
+
+QRectF QWaylandInputMethodContext::keyboardRect() const
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr)
+ return inputMethod->keyboardRect();
+ else
+ return QRectF();
+}
+
+QLocale QWaylandInputMethodContext::locale() const
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr)
+ return inputMethod->locale();
+ else
+ return QLocale();
+}
+
+Qt::LayoutDirection QWaylandInputMethodContext::inputDirection() const
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod != nullptr)
+ return inputMethod->inputDirection();
+ else
+ return Qt::LeftToRight;
+}
+
+void QWaylandInputMethodContext::setFocusObject(QObject *)
+{
+ QWaylandTextInputMethod *inputMethod = textInputMethod();
+ if (inputMethod == nullptr)
+ return;
+
+ QWindow *window = QGuiApplication::focusWindow();
+
+ if (m_currentWindow != nullptr && m_currentWindow->handle() != nullptr) {
+ if (m_currentWindow.data() != window || !inputMethodAccepted()) {
+ auto *surface = static_cast<QWaylandWindow *>(m_currentWindow->handle())->wlSurface();
+ if (surface)
+ inputMethod->disable(surface);
+ m_currentWindow.clear();
+ }
+ }
+
+ if (window != nullptr && window->handle() != nullptr && inputMethodAccepted()) {
+ if (m_currentWindow.data() != window) {
+ auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface();
+ if (surface != nullptr) {
+ inputMethod->enable(surface);
+ m_currentWindow = window;
+ }
+ }
+ }
+}
+
+QWaylandTextInputMethod *QWaylandInputMethodContext::textInputMethod() const
+{
+ return m_display->defaultInputDevice()->textInputMethod();
+}
+
+} // QtWaylandClient
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandinputmethodcontext_p.h b/src/client/qwaylandinputmethodcontext_p.h
new file mode 100644
index 000000000..8be65f447
--- /dev/null
+++ b/src/client/qwaylandinputmethodcontext_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDINPUTMETHODCONTEXT_P_H
+#define QWAYLANDINPUTMETHODCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qpa/qplatforminputcontext.h>
+#include <QtGui/qevent.h>
+#include <QtCore/qlocale.h>
+#include <QtCore/qpointer.h>
+
+#include <QtWaylandClient/private/qwayland-qt-text-input-method-unstable-v1.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+ class QWaylandDisplay;
+
+class QWaylandTextInputMethod : public QtWayland::qt_text_input_method_v1
+{
+public:
+ QWaylandTextInputMethod(QWaylandDisplay *display, struct ::qt_text_input_method_v1 *textInputMethod);
+ ~QWaylandTextInputMethod() override;
+
+ void text_input_method_v1_visible_changed(int32_t visible) override;
+ void text_input_method_v1_enter(struct ::wl_surface *surface) override;
+ void text_input_method_v1_leave(struct ::wl_surface *surface) override;
+ void text_input_method_v1_locale_changed(const QString &localeName) override;
+ void text_input_method_v1_input_direction_changed(int32_t inputDirection) override;
+ void text_input_method_v1_keyboard_rectangle_changed(wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) override;
+ void text_input_method_v1_key(int32_t type, int32_t key, int32_t modifiers, int32_t autoRepeat, int32_t count, int32_t nativeScanCode, int32_t nativeVirtualKey, int32_t nativeModifiers, const QString &text) override;
+ void text_input_method_v1_start_input_method_event(uint32_t serial, int32_t surrounding_text_offset) override;
+ void text_input_method_v1_end_input_method_event(uint32_t serial, const QString &commitString, const QString &preeditString, int32_t replacementStart, int32_t replacementLength) override;
+ void text_input_method_v1_input_method_event_attribute(uint32_t serial, int32_t type, int32_t start, int32_t length, const QString &value) override;
+
+ inline bool isVisible() const
+ {
+ return m_isVisible;
+ }
+
+ inline QRectF keyboardRect() const
+ {
+ return m_keyboardRect;
+ }
+
+ inline QLocale locale() const
+ {
+ return m_locale;
+ }
+
+ inline Qt::LayoutDirection inputDirection() const
+ {
+ return m_layoutDirection;
+ }
+
+ void sendInputState(QInputMethodQueryEvent *state, Qt::InputMethodQueries queries = Qt::ImQueryInput);
+
+private:
+ QWaylandDisplay *m_display;
+
+ QHash<int, QList<QInputMethodEvent::Attribute> > m_pendingInputMethodEvents;
+ QHash<int,int> m_offsetFromCompositor;
+
+ struct ::wl_surface *m_surface;
+
+ // Cached state
+ bool m_isVisible = false;
+ QRectF m_keyboardRect;
+ QLocale m_locale;
+ Qt::LayoutDirection m_layoutDirection;
+};
+
+class QWaylandInputMethodContext : public QPlatformInputContext
+{
+public:
+ QWaylandInputMethodContext(QWaylandDisplay *display);
+ ~QWaylandInputMethodContext() override;
+
+ bool isValid() const override;
+ void reset() override;
+ void commit() override;
+ void update(Qt::InputMethodQueries) override;
+ void invokeAction(QInputMethod::Action, int cursorPosition) override;
+ void showInputPanel() override;
+ void hideInputPanel() override;
+
+ bool isInputPanelVisible() const override;
+ QRectF keyboardRect() const override;
+ QLocale locale() const override;
+ Qt::LayoutDirection inputDirection() const override;
+
+ void setFocusObject(QObject *object) override;
+
+private:
+ QWaylandTextInputMethod *textInputMethod() const;
+
+ QWaylandDisplay *m_display;
+ QPointer<QWindow> m_currentWindow;
+};
+
+} // QtWaylandClient
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDINPUTMETHODCONTEXT_P_H
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
index 0aa18f098..764acc2d9 100644
--- a/src/client/qwaylandintegration.cpp
+++ b/src/client/qwaylandintegration.cpp
@@ -43,6 +43,7 @@
#include "qwaylandshmwindow_p.h"
#include "qwaylandinputdevice_p.h"
#include "qwaylandinputcontext_p.h"
+#include "qwaylandinputmethodcontext_p.h"
#include "qwaylandshmbackingstore_p.h"
#include "qwaylandnativeinterface_p.h"
#if QT_CONFIG(clipboard)
@@ -465,10 +466,14 @@ void QWaylandIntegration::reconfigureInputContext()
qCWarning(lcQpaWayland) << "qtvirtualkeyboard currently is not supported at client-side,"
" use QT_IM_MODULE=qtvirtualkeyboard at compositor-side.";
- if (requested.isNull())
- mInputContext.reset(new QWaylandInputContext(mDisplay.data()));
- else
+ if (requested.isNull()) {
+ if (mDisplay->textInputMethodManager() != nullptr)
+ mInputContext.reset(new QWaylandInputMethodContext(mDisplay.data()));
+ else
+ mInputContext.reset(new QWaylandInputContext(mDisplay.data()));
+ } else {
mInputContext.reset(QPlatformInputContextFactory::create(requested));
+ }
const QString defaultInputContext(QStringLiteral("compose"));
if ((!mInputContext || !mInputContext->isValid()) && requested != defaultInputContext)
diff --git a/src/compositor/.prev_CMakeLists.txt b/src/compositor/.prev_CMakeLists.txt
index 8e0abb80d..9d3d49b2e 100644
--- a/src/compositor/.prev_CMakeLists.txt
+++ b/src/compositor/.prev_CMakeLists.txt
@@ -32,6 +32,8 @@ qt_add_module(WaylandCompositor
extensions/qwaylandidleinhibitv1.cpp extensions/qwaylandidleinhibitv1.h extensions/qwaylandidleinhibitv1_p.h
extensions/qwaylandiviapplication.cpp extensions/qwaylandiviapplication.h extensions/qwaylandiviapplication_p.h
extensions/qwaylandivisurface.cpp extensions/qwaylandivisurface.h extensions/qwaylandivisurface_p.h
+ extensions/qwaylandqttextinputmethod.cpp extensions/qwaylandqttextinputmethod.h extensions/qwaylandqttextinputmethod_p.h
+ extensions/qwaylandqttextinputmethodmanager.cpp extensions/qwaylandqttextinputmethodmanager.h extensions/qwaylandqttextinputmethodmanager_p.h
extensions/qwaylandqtwindowmanager.cpp extensions/qwaylandqtwindowmanager.h extensions/qwaylandqtwindowmanager_p.h
extensions/qwaylandshell.cpp extensions/qwaylandshell.h extensions/qwaylandshell_p.h
extensions/qwaylandshellsurface.cpp extensions/qwaylandshellsurface.h
@@ -99,6 +101,7 @@ qt6_generate_wayland_protocol_server_sources(WaylandCompositor
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-output-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-shell.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-key-unstable-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-text-input-method-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-windowmanager.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/touch-extension.xml
)
diff --git a/src/compositor/CMakeLists.txt b/src/compositor/CMakeLists.txt
index 47ce055db..f727f0a1c 100644
--- a/src/compositor/CMakeLists.txt
+++ b/src/compositor/CMakeLists.txt
@@ -32,6 +32,8 @@ qt_add_module(WaylandCompositor
extensions/qwaylandidleinhibitv1.cpp extensions/qwaylandidleinhibitv1.h extensions/qwaylandidleinhibitv1_p.h
extensions/qwaylandiviapplication.cpp extensions/qwaylandiviapplication.h extensions/qwaylandiviapplication_p.h
extensions/qwaylandivisurface.cpp extensions/qwaylandivisurface.h extensions/qwaylandivisurface_p.h
+ extensions/qwaylandqttextinputmethod.cpp extensions/qwaylandqttextinputmethod.h extensions/qwaylandqttextinputmethod_p.h
+ extensions/qwaylandqttextinputmethodmanager.cpp extensions/qwaylandqttextinputmethodmanager.h extensions/qwaylandqttextinputmethodmanager_p.h
extensions/qwaylandqtwindowmanager.cpp extensions/qwaylandqtwindowmanager.h extensions/qwaylandqtwindowmanager_p.h
extensions/qwaylandshell.cpp extensions/qwaylandshell.h extensions/qwaylandshell_p.h
extensions/qwaylandshellsurface.cpp extensions/qwaylandshellsurface.h
@@ -99,6 +101,7 @@ qt6_generate_wayland_protocol_server_sources(WaylandCompositor
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-output-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-shell.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-key-unstable-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-text-input-method-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-windowmanager.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/touch-extension.xml
)
diff --git a/src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h b/src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h
index 901ce30c7..4a1763884 100644
--- a/src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h
+++ b/src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h
@@ -49,6 +49,7 @@
#include <QtWaylandCompositor/qwaylandquickcompositor.h>
#include <QtWaylandCompositor/qwaylandqtwindowmanager.h>
#include <QtWaylandCompositor/qwaylandtextinputmanager.h>
+#include <QtWaylandCompositor/qwaylandqttextinputmethodmanager.h>
#include <QtWaylandCompositor/qwaylandidleinhibitv1.h>
QT_BEGIN_NAMESPACE
@@ -106,6 +107,7 @@ private:
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandQtWindowManager, QtWindowManager)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandIdleInhibitManagerV1, IdleInhibitManagerV1)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandTextInputManager, TextInputManager)
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandQtTextInputMethodManager, QtTextInputMethodManager)
QT_END_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp b/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp
index 1925d2123..31d6757b5 100644
--- a/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp
+++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp
@@ -35,6 +35,7 @@
#include "qwaylandsurface.h"
#include "qwaylandview.h"
#include "qwaylandtextinput.h"
+#include "qwaylandqttextinputmethod.h"
#include <QtGui/QInputMethodEvent>
@@ -49,6 +50,13 @@ QWaylandInputMethodControl::QWaylandInputMethodControl(QWaylandSurface *surface)
connect(textInput, &QWaylandTextInput::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
connect(textInput, &QWaylandTextInput::updateInputMethod, this, &QWaylandInputMethodControl::updateInputMethod);
}
+
+ QWaylandQtTextInputMethod *textInputMethod = d_func()->textInputMethod();
+ if (textInputMethod) {
+ connect(textInputMethod, &QWaylandQtTextInputMethod::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled);
+ connect(textInputMethod, &QWaylandQtTextInputMethod::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
+ connect(textInputMethod, &QWaylandQtTextInputMethod::updateInputMethod, this, &QWaylandInputMethodControl::updateInputMethod);
+ }
}
QVariant QWaylandInputMethodControl::inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const
@@ -56,10 +64,12 @@ QVariant QWaylandInputMethodControl::inputMethodQuery(Qt::InputMethodQuery query
Q_D(const QWaylandInputMethodControl);
QWaylandTextInput *textInput = d->textInput();
-
- if (textInput && textInput->focus() == d->surface) {
+ if (textInput != nullptr && textInput->focus() == d->surface)
return textInput->inputMethodQuery(query, argument);
- }
+
+ QWaylandQtTextInputMethod *textInputMethod = d_func()->textInputMethod();
+ if (textInputMethod && textInputMethod->focusedSurface() == d->surface)
+ return textInputMethod->inputMethodQuery(query, argument);
return QVariant();
}
@@ -71,6 +81,8 @@ void QWaylandInputMethodControl::inputMethodEvent(QInputMethodEvent *event)
QWaylandTextInput *textInput = d->textInput();
if (textInput) {
textInput->sendInputMethodEvent(event);
+ } else if (QWaylandQtTextInputMethod *textInputMethod = d->textInputMethod()) {
+ textInputMethod->sendInputMethodEvent(event);
} else {
event->ignore();
}
@@ -121,7 +133,9 @@ void QWaylandInputMethodControl::setSurface(QWaylandSurface *surface)
d->surface = surface;
QWaylandTextInput *textInput = d->textInput();
- setEnabled(textInput && textInput->isSurfaceEnabled(d->surface));
+ QWaylandQtTextInputMethod *textInputMethod = d->textInputMethod();
+ setEnabled((textInput && textInput->isSurfaceEnabled(d->surface))
+ || (textInputMethod && textInputMethod->isSurfaceEnabled(d->surface)));
}
void QWaylandInputMethodControl::defaultSeatChanged()
@@ -129,14 +143,24 @@ void QWaylandInputMethodControl::defaultSeatChanged()
Q_D(QWaylandInputMethodControl);
disconnect(d->textInput(), nullptr, this, nullptr);
+ disconnect(d->textInputMethod(), nullptr, this, nullptr);
d->seat = d->compositor->defaultSeat();
QWaylandTextInput *textInput = d->textInput();
+ QWaylandQtTextInputMethod *textInputMethod = d->textInputMethod();
+
+ if (textInput) {
+ connect(textInput, &QWaylandTextInput::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled);
+ connect(textInput, &QWaylandTextInput::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
+ }
- connect(textInput, &QWaylandTextInput::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled);
- connect(textInput, &QWaylandTextInput::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
+ if (textInputMethod) {
+ connect(textInputMethod, &QWaylandQtTextInputMethod::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled);
+ connect(textInputMethod, &QWaylandQtTextInputMethod::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
+ }
- setEnabled(textInput && textInput->isSurfaceEnabled(d->surface));
+ setEnabled((textInput && textInput->isSurfaceEnabled(d->surface))
+ || (textInputMethod && textInputMethod->isSurfaceEnabled(d->surface)));
}
QWaylandInputMethodControlPrivate::QWaylandInputMethodControlPrivate(QWaylandSurface *surface)
@@ -146,6 +170,11 @@ QWaylandInputMethodControlPrivate::QWaylandInputMethodControlPrivate(QWaylandSur
{
}
+QWaylandQtTextInputMethod *QWaylandInputMethodControlPrivate::textInputMethod() const
+{
+ return QWaylandQtTextInputMethod::findIn(seat);
+}
+
QWaylandTextInput *QWaylandInputMethodControlPrivate::textInput() const
{
return QWaylandTextInput::findIn(seat);
diff --git a/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h b/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h
index 4c20f3e3c..e25ac48c5 100644
--- a/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h
+++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h
@@ -52,6 +52,7 @@ class QWaylandCompositor;
class QWaylandSeat;
class QWaylandSurface;
class QWaylandTextInput;
+class QWaylandQtTextInputMethod;
class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandInputMethodControlPrivate : public QObjectPrivate
{
@@ -61,6 +62,7 @@ public:
explicit QWaylandInputMethodControlPrivate(QWaylandSurface *surface);
QWaylandTextInput *textInput() const;
+ QWaylandQtTextInputMethod *textInputMethod() const;
QWaylandCompositor *compositor = nullptr;
QWaylandSeat *seat = nullptr;
diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp
index 0b00a6edc..bffa358b2 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.cpp
+++ b/src/compositor/compositor_api/qwaylandquickitem.cpp
@@ -32,6 +32,7 @@
#include "qwaylandquicksurface.h"
#include "qwaylandinputmethodcontrol.h"
#include "qwaylandtextinput.h"
+#include "qwaylandqttextinputmethod.h"
#include "qwaylandquickoutput.h"
#include <QtWaylandCompositor/qwaylandcompositor.h>
#include <QtWaylandCompositor/qwaylandseat.h>
@@ -983,9 +984,18 @@ void QWaylandQuickItem::takeFocus(QWaylandSeat *device)
target = compositor()->defaultSeat();
}
target->setKeyboardFocus(surface());
- QWaylandTextInput *textInput = QWaylandTextInput::findIn(target);
- if (textInput)
- textInput->setFocus(surface());
+
+ {
+ QWaylandTextInput *textInput = QWaylandTextInput::findIn(target);
+ if (textInput)
+ textInput->setFocus(surface());
+ }
+
+ {
+ QWaylandQtTextInputMethod *textInputMethod = QWaylandQtTextInputMethod::findIn(target);
+ if (textInputMethod)
+ textInputMethod->setFocus(surface());
+ }
}
/*!
diff --git a/src/compositor/compositor_api/qwaylandseat.cpp b/src/compositor/compositor_api/qwaylandseat.cpp
index 83d0335c4..b0db245eb 100644
--- a/src/compositor/compositor_api/qwaylandseat.cpp
+++ b/src/compositor/compositor_api/qwaylandseat.cpp
@@ -48,6 +48,7 @@
#include "extensions/qwlqtkey_p.h"
#include "extensions/qwaylandtextinput.h"
+#include "extensions/qwaylandqttextinputmethod.h"
QT_BEGIN_NAMESPACE
@@ -469,6 +470,12 @@ void QWaylandSeat::sendFullKeyEvent(QKeyEvent *event)
textInput->sendKeyEvent(event);
return;
}
+
+ QWaylandQtTextInputMethod *textInputMethod = QWaylandQtTextInputMethod::findIn(this);
+ if (textInputMethod) {
+ textInputMethod->sendKeyEvent(event);
+ return;
+ }
}
#endif
diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri
index d7729a191..5c3ab0f4f 100644
--- a/src/compositor/extensions/extensions.pri
+++ b/src/compositor/extensions/extensions.pri
@@ -8,6 +8,7 @@ WAYLANDSERVERSOURCES += \
../extensions/touch-extension.xml \
../extensions/qt-key-unstable-v1.xml \
../extensions/qt-windowmanager.xml \
+ ../extensions/qt-text-input-method-unstable-v1.xml \
../3rdparty/protocol/text-input-unstable-v2.xml \
../3rdparty/protocol/viewporter.xml \
../3rdparty/protocol/scaler.xml \
@@ -28,6 +29,10 @@ HEADERS += \
extensions/qwaylandtextinput_p.h \
extensions/qwaylandtextinputmanager.h \
extensions/qwaylandtextinputmanager_p.h \
+ extensions/qwaylandqttextinputmethodmanager.h \
+ extensions/qwaylandqttextinputmethodmanager_p.h \
+ extensions/qwaylandqttextinputmethod.h \
+ extensions/qwaylandqttextinputmethod_p.h \
extensions/qwaylandqtwindowmanager.h \
extensions/qwaylandqtwindowmanager_p.h \
extensions/qwaylandviewporter.h \
@@ -53,6 +58,8 @@ SOURCES += \
extensions/qwaylandwlshell.cpp \
extensions/qwaylandtextinput.cpp \
extensions/qwaylandtextinputmanager.cpp \
+ extensions/qwaylandqttextinputmethodmanager.cpp \
+ extensions/qwaylandqttextinputmethod.cpp \
extensions/qwaylandqtwindowmanager.cpp \
extensions/qwaylandviewporter.cpp \
extensions/qwaylandxdgshell.cpp \
diff --git a/src/compositor/extensions/qwaylandqttextinputmethod.cpp b/src/compositor/extensions/qwaylandqttextinputmethod.cpp
new file mode 100644
index 000000000..5119373a6
--- /dev/null
+++ b/src/compositor/extensions/qwaylandqttextinputmethod.cpp
@@ -0,0 +1,459 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandqttextinputmethod.h"
+#include "qwaylandqttextinputmethod_p.h"
+
+#include <QtGui/qevent.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qinputmethod.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qtextformat.h>
+
+#include <QtWaylandCompositor/qwaylandcompositor.h>
+#include <QtWaylandCompositor/qwaylandsurface.h>
+
+QT_BEGIN_NAMESPACE
+
+QWaylandQtTextInputMethodPrivate::QWaylandQtTextInputMethodPrivate(QWaylandCompositor *c)
+ : compositor(c)
+{
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_enable(Resource *resource, struct ::wl_resource *surface)
+{
+ Q_Q(QWaylandQtTextInputMethod);
+ if (this->resource == resource) {
+ QWaylandSurface *waylandSurface = QWaylandSurface::fromResource(surface);
+ if (surface != nullptr) {
+ enabledSurfaces[resource] = waylandSurface;
+ emit q->surfaceEnabled(waylandSurface);
+ }
+ }
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_disable(Resource *resource, struct ::wl_resource *surface)
+{
+ Q_Q(QWaylandQtTextInputMethod);
+ if (this->resource == resource) {
+ QWaylandSurface *waylandSurface = QWaylandSurface::fromResource(surface);
+ QWaylandSurface *enabledSurface = enabledSurfaces.take(resource);
+
+ if (Q_UNLIKELY(enabledSurface != waylandSurface))
+ qCWarning(qLcWaylandCompositorInputMethods) << "Disabled surface does not match the one currently enabled";
+
+ emit q->surfaceEnabled(waylandSurface);
+ }
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_destroy(Resource *resource)
+{
+ if (this->resource == resource)
+ wl_resource_destroy(resource->handle);
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_reset(Resource *resource)
+{
+ if (this->resource == resource)
+ qApp->inputMethod()->reset();
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_commit(Resource *resource)
+{
+ if (this->resource == resource)
+ qApp->inputMethod()->commit();
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_show_input_panel(Resource *resource)
+{
+ if (this->resource == resource)
+ qApp->inputMethod()->show();
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_hide_input_panel(Resource *resource)
+{
+ if (this->resource == resource)
+ qApp->inputMethod()->hide();
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_invoke_action(Resource *resource, int32_t type, int32_t cursorPosition)
+{
+ if (this->resource == resource)
+ qApp->inputMethod()->invokeAction(QInputMethod::Action(type), cursorPosition);
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_update_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ if (this->resource == resource)
+ cursorRectangle = QRect(x, y, width, height);
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_start_update(Resource *resource, int32_t queries)
+{
+ if (this->resource == resource)
+ updatingQueries = Qt::InputMethodQueries(queries);
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_update_hints(Resource *resource, int32_t hints)
+{
+ if (this->resource == resource)
+ hints = Qt::InputMethodHints(hints);
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_update_anchor_position(Resource *resource, int32_t anchorPosition)
+{
+ if (this->resource == resource)
+ this->anchorPosition = anchorPosition;
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_update_cursor_position(Resource *resource, int32_t cursorPosition)
+{
+ if (this->resource == resource)
+ this->cursorPosition = cursorPosition;
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_update_surrounding_text(Resource *resource, const QString &surroundingText, int32_t surroundingTextOffset)
+{
+ if (this->resource == resource) {
+ this->surroundingText = surroundingText;
+ this->surroundingTextOffset = surroundingTextOffset;
+ }
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_update_absolute_position(Resource *resource, int32_t absolutePosition)
+{
+ if (this->resource == resource)
+ this->absolutePosition = absolutePosition;
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_update_preferred_language(Resource *resource, const QString &preferredLanguage)
+{
+ if (this->resource == resource)
+ this->preferredLanguage = preferredLanguage;
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_end_update(Resource *resource)
+{
+ Q_Q(QWaylandQtTextInputMethod);
+ if (this->resource == resource && updatingQueries != 0) {
+ Qt::InputMethodQueries queries = updatingQueries;
+ updatingQueries = Qt::InputMethodQueries();
+ emit q->updateInputMethod(queries);
+ }
+}
+
+void QWaylandQtTextInputMethodPrivate::text_input_method_v1_acknowledge_input_method(Resource *resource)
+{
+ if (this->resource == resource)
+ waitingForSync = false;
+}
+
+QWaylandQtTextInputMethod::QWaylandQtTextInputMethod(QWaylandObject *container, QWaylandCompositor *compositor)
+ : QWaylandCompositorExtensionTemplate(container, *new QWaylandQtTextInputMethodPrivate(compositor))
+{
+ connect(&d_func()->focusDestroyListener, &QWaylandDestroyListener::fired,
+ this, &QWaylandQtTextInputMethod::focusSurfaceDestroyed);
+
+ connect(qGuiApp->inputMethod(), &QInputMethod::visibleChanged, this, &QWaylandQtTextInputMethod::sendVisibleChanged);
+ connect(qGuiApp->inputMethod(), &QInputMethod::keyboardRectangleChanged, this, &QWaylandQtTextInputMethod::sendKeyboardRectangleChanged);
+ connect(qGuiApp->inputMethod(), &QInputMethod::inputDirectionChanged, this, &QWaylandQtTextInputMethod::sendInputDirectionChanged);
+ connect(qGuiApp->inputMethod(), &QInputMethod::localeChanged, this, &QWaylandQtTextInputMethod::sendLocaleChanged);
+}
+
+
+QWaylandQtTextInputMethod::~QWaylandQtTextInputMethod()
+{
+}
+
+void QWaylandQtTextInputMethod::focusSurfaceDestroyed()
+{
+ Q_D(QWaylandQtTextInputMethod);
+ d->focusDestroyListener.reset();
+ d->waitingForSync = false;
+ d->resource = nullptr;
+ d->focusedSurface = nullptr;
+}
+
+QWaylandSurface *QWaylandQtTextInputMethod::focusedSurface() const
+{
+ Q_D(const QWaylandQtTextInputMethod);
+ return d->focusedSurface;
+}
+
+QVariant QWaylandQtTextInputMethod::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
+{
+ Q_D(const QWaylandQtTextInputMethod);
+ switch (property) {
+ case Qt::ImHints:
+ return int(d->hints);
+ case Qt::ImCursorRectangle:
+ return d->cursorRectangle;
+ case Qt::ImCursorPosition:
+ return d->cursorPosition;
+ case Qt::ImSurroundingText:
+ return d->surroundingText;
+ case Qt::ImAbsolutePosition:
+ return d->absolutePosition;
+ case Qt::ImCurrentSelection:
+ return d->surroundingText.mid(qMin(d->cursorPosition, d->anchorPosition),
+ qAbs(d->anchorPosition - d->cursorPosition));
+ case Qt::ImAnchorPosition:
+ return d->anchorPosition;
+ case Qt::ImTextAfterCursor:
+ if (argument.isValid())
+ return d->surroundingText.mid(d->cursorPosition, argument.toInt());
+ return d->surroundingText.mid(d->cursorPosition);
+ case Qt::ImTextBeforeCursor:
+ if (argument.isValid())
+ return d->surroundingText.left(d->cursorPosition).right(argument.toInt());
+ return d->surroundingText.left(d->cursorPosition);
+ case Qt::ImPreferredLanguage:
+ return d->preferredLanguage;
+
+ default:
+ return QVariant();
+ }
+}
+
+void QWaylandQtTextInputMethod::sendKeyEvent(QKeyEvent *event)
+{
+ Q_D(QWaylandQtTextInputMethod);
+ if (d->resource == nullptr || d->resource->handle == nullptr)
+ return;
+
+ d->send_key(d->resource->handle,
+ int(event->type()),
+ event->key(),
+ event->modifiers(),
+ event->isAutoRepeat(),
+ event->count(),
+ event->nativeScanCode(),
+ event->nativeVirtualKey(),
+ event->nativeModifiers(),
+ event->text());
+}
+
+void QWaylandQtTextInputMethod::sendInputMethodEvent(QInputMethodEvent *event)
+{
+ Q_D(QWaylandQtTextInputMethod);
+ if (d->resource == nullptr || d->resource->handle == nullptr || d->compositor == nullptr)
+ return;
+
+ if (d->updatingQueries != 0) {
+ qCWarning(qLcWaylandCompositorInputMethods) << "Input method event sent while client is updating. Ignored.";
+ return;
+ }
+
+ Q_ASSERT(!d->waitingForSync);
+
+ QString oldSurroundText = d->surroundingText;
+ int oldCursorPosition = d->cursorPosition;
+ int oldAnchorPosition = d->anchorPosition;
+ int oldAbsolutePosition = d->absolutePosition;
+ QRect oldCursorRectangle = d->cursorRectangle;
+ QString oldPreferredLanguage = d->preferredLanguage;
+ Qt::InputMethodHints oldHints = d->hints;
+
+ uint serial = d->compositor->nextSerial(); // ### Not needed if we block on this?
+ d->send_start_input_method_event(d->resource->handle, serial, d->surroundingTextOffset);
+ for (const QInputMethodEvent::Attribute &attribute : event->attributes()) {
+ switch (attribute.type) {
+ case QInputMethodEvent::TextFormat:
+ {
+ auto properties = attribute.value.value<QTextFormat>().properties();
+ if (properties.size() != 2 || properties.firstKey() != QTextFormat::FontUnderline || properties.lastKey() != QTextFormat::TextUnderlineStyle) {
+ qCWarning(qLcWaylandCompositorInputMethods()) << "Only underline text formats currently supported";
+ }
+
+ d->send_input_method_event_attribute(d->resource->handle,
+ serial,
+ attribute.type,
+ attribute.start,
+ attribute.length,
+ QString());
+ break;
+ }
+ case QInputMethodEvent::Cursor:
+ d->cursorPosition = attribute.start;
+ d->send_input_method_event_attribute(d->resource->handle,
+ serial,
+ attribute.type,
+ attribute.start,
+ attribute.length,
+ attribute.value.type() == QVariant::Color ? attribute.value.value<QColor>().name() : QString());
+ break;
+ case QInputMethodEvent::Language: // ### What is the type of value? Is it string?
+ Q_FALLTHROUGH();
+ case QInputMethodEvent::Ruby:
+ d->send_input_method_event_attribute(d->resource->handle,
+ serial,
+ attribute.type,
+ attribute.start,
+ attribute.length,
+ attribute.value.toString());
+ break;
+ case QInputMethodEvent::Selection:
+ d->send_input_method_event_attribute(d->resource->handle,
+ serial,
+ attribute.type,
+ attribute.start,
+ attribute.length,
+ QString());
+ break;
+ }
+ }
+
+ d->waitingForSync = true;
+ d->send_end_input_method_event(d->resource->handle,
+ serial,
+ event->commitString(),
+ event->preeditString(),
+ event->replacementStart(),
+ event->replacementLength());
+
+ while (d->waitingForSync)
+ d->compositor->processWaylandEvents();
+
+ Qt::InputMethodQueries queries;
+ if (d->surroundingText != oldSurroundText)
+ queries |= Qt::ImSurroundingText;
+ if (d->cursorPosition != oldCursorPosition)
+ queries |= Qt::ImCursorPosition;
+ if (d->anchorPosition != oldAnchorPosition)
+ queries |= Qt::ImAnchorPosition;
+ if (d->absolutePosition != oldAbsolutePosition)
+ queries |= Qt::ImAbsolutePosition;
+ if (d->cursorRectangle != oldCursorRectangle)
+ queries |= Qt::ImCursorRectangle;
+ if (d->preferredLanguage != oldPreferredLanguage)
+ queries |= Qt::ImPreferredLanguage;
+ if (d->hints != oldHints)
+ queries |= Qt::ImHints;
+ if (queries != 0)
+ emit updateInputMethod(queries);
+}
+
+bool QWaylandQtTextInputMethod::isSurfaceEnabled(QWaylandSurface *surface) const
+{
+ Q_D(const QWaylandQtTextInputMethod);
+ return d->enabledSurfaces.values().contains(surface);
+}
+
+void QWaylandQtTextInputMethod::setFocus(QWaylandSurface *surface)
+{
+ Q_D(QWaylandQtTextInputMethod);
+
+ QWaylandQtTextInputMethodPrivate::Resource *resource = surface != nullptr ? d->resourceMap().value(surface->waylandClient()) : nullptr;
+ if (d->resource == resource)
+ return;
+
+ if (d->resource != nullptr && d->focusedSurface != nullptr) {
+ d->send_leave(d->resource->handle, d->focusedSurface->resource());
+ d->focusDestroyListener.reset();
+ }
+
+ d->resource = resource;
+ d->focusedSurface = surface;
+
+ if (d->resource != nullptr && d->focusedSurface != nullptr) {
+ d->surroundingText.clear();
+ d->cursorPosition = 0;
+ d->anchorPosition = 0;
+ d->absolutePosition = 0;
+ d->cursorRectangle = QRect();
+ d->preferredLanguage.clear();
+ d->hints = Qt::InputMethodHints();
+ d->send_enter(d->resource->handle, d->focusedSurface->resource());
+ sendInputDirectionChanged();
+ sendLocaleChanged();
+ sendInputDirectionChanged();
+ d->focusDestroyListener.listenForDestruction(surface->resource());
+ if (d->inputPanelVisible && d->enabledSurfaces.values().contains(surface))
+ qGuiApp->inputMethod()->show();
+ }
+}
+
+void QWaylandQtTextInputMethod::sendLocaleChanged()
+{
+ Q_D(QWaylandQtTextInputMethod);
+ if (d->resource == nullptr || d->resource->handle == nullptr)
+ return;
+
+ d->send_locale_changed(d->resource->handle, qGuiApp->inputMethod()->locale().bcp47Name());
+}
+
+void QWaylandQtTextInputMethod::sendInputDirectionChanged()
+{
+ Q_D(QWaylandQtTextInputMethod);
+ if (d->resource == nullptr || d->resource->handle == nullptr)
+ return;
+
+ d->send_input_direction_changed(d->resource->handle, int(qGuiApp->inputMethod()->inputDirection()));
+}
+
+void QWaylandQtTextInputMethod::sendKeyboardRectangleChanged()
+{
+ Q_D(QWaylandQtTextInputMethod);
+ if (d->resource == nullptr || d->resource->handle == nullptr)
+ return;
+
+ QRectF keyboardRectangle = qGuiApp->inputMethod()->keyboardRectangle();
+ d->send_keyboard_rectangle_changed(d->resource->handle,
+ wl_fixed_from_double(keyboardRectangle.x()),
+ wl_fixed_from_double(keyboardRectangle.y()),
+ wl_fixed_from_double(keyboardRectangle.width()),
+ wl_fixed_from_double(keyboardRectangle.height()));
+}
+
+void QWaylandQtTextInputMethod::sendVisibleChanged()
+{
+ Q_D(QWaylandQtTextInputMethod);
+ if (d->resource == nullptr || d->resource->handle == nullptr)
+ return;
+
+ d->send_visible_changed(d->resource->handle, int(qGuiApp->inputMethod()->isVisible()));
+}
+
+void QWaylandQtTextInputMethod::add(::wl_client *client, uint32_t id, int version)
+{
+ Q_D(QWaylandQtTextInputMethod);
+ d->add(client, id, version);
+}
+
+const struct wl_interface *QWaylandQtTextInputMethod::interface()
+{
+ return QWaylandQtTextInputMethodPrivate::interface();
+}
+
+QByteArray QWaylandQtTextInputMethod::interfaceName()
+{
+ return QWaylandQtTextInputMethodPrivate::interfaceName();
+}
+
+QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandqttextinputmethod.h b/src/compositor/extensions/qwaylandqttextinputmethod.h
new file mode 100644
index 000000000..734eb6adc
--- /dev/null
+++ b/src/compositor/extensions/qwaylandqttextinputmethod.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDQTTEXTINPUTMETHOD_H
+#define QWAYLANDQTTEXTINPUTMETHOD_H
+
+#include <QtWaylandCompositor/qwaylandcompositorextension.h>
+
+struct wl_client;
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandSurface;
+class QWaylandQtTextInputMethodPrivate;
+class QInputMethodEvent;
+class QKeyEvent;
+
+class QWaylandQtTextInputMethod : public QWaylandCompositorExtensionTemplate<QWaylandQtTextInputMethod>
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandQtTextInputMethod)
+public:
+ explicit QWaylandQtTextInputMethod(QWaylandObject *container, QWaylandCompositor *compositor);
+ ~QWaylandQtTextInputMethod() override;
+
+ QWaylandSurface *focusedSurface() const;
+ void setFocus(QWaylandSurface *surface);
+
+ bool isSurfaceEnabled(QWaylandSurface *surface) const;
+
+ void add(::wl_client *client, uint32_t id, int version);
+
+ static const struct wl_interface *interface();
+ static QByteArray interfaceName();
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const;
+ void sendInputMethodEvent(QInputMethodEvent *event);
+ void sendKeyEvent(QKeyEvent *event);
+
+Q_SIGNALS:
+ void updateInputMethod(Qt::InputMethodQueries queries);
+ void surfaceEnabled(QWaylandSurface *surface);
+ void surfaceDisabled(QWaylandSurface *surface);
+
+private Q_SLOTS:
+ void sendVisibleChanged();
+ void sendKeyboardRectangleChanged();
+ void sendInputDirectionChanged();
+ void sendLocaleChanged();
+ void focusSurfaceDestroyed();
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQTTEXTINPUTMETHOD_H
diff --git a/src/compositor/extensions/qwaylandqttextinputmethod_p.h b/src/compositor/extensions/qwaylandqttextinputmethod_p.h
new file mode 100644
index 000000000..9be085996
--- /dev/null
+++ b/src/compositor/extensions/qwaylandqttextinputmethod_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDQTTEXTINPUTMETHOD_P_H
+#define QWAYLANDQTTEXTINPUTMETHOD_P_H
+
+
+#include "qwaylandqttextinputmethod.h"
+
+#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include <QtWaylandCompositor/private/qwayland-server-qt-text-input-method-unstable-v1.h>
+#include <QtWaylandCompositor/qwaylanddestroylistener.h>
+
+#include <QtCore/qrect.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandCompositor;
+class QWaylandSurface;
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQtTextInputMethodPrivate : public QWaylandCompositorExtensionPrivate, public QtWaylandServer::qt_text_input_method_v1
+{
+ Q_DECLARE_PUBLIC(QWaylandQtTextInputMethod)
+public:
+ explicit QWaylandQtTextInputMethodPrivate(QWaylandCompositor *compositor);
+
+ QWaylandCompositor *compositor;
+ QWaylandSurface *focusedSurface = nullptr;
+ Resource *resource = nullptr;
+ QHash<Resource * , QWaylandSurface *> enabledSurfaces;
+ QWaylandDestroyListener focusDestroyListener;
+ bool inputPanelVisible = false;
+ bool waitingForSync = false;
+
+ Qt::InputMethodQueries updatingQueries;
+ Qt::InputMethodHints hints;
+ QString surroundingText;
+ QString preferredLanguage;
+ QRect cursorRectangle;
+ int cursorPosition = 0;
+ int anchorPosition = 0;
+ int absolutePosition = 0;
+ int surroundingTextOffset = 0;
+
+private:
+ void text_input_method_v1_enable(Resource *resource, struct ::wl_resource *surface) override;
+ void text_input_method_v1_disable(Resource *resource, struct ::wl_resource *surface) override;
+ void text_input_method_v1_destroy(Resource *resource) override;
+ void text_input_method_v1_reset(Resource *resource) override;
+ void text_input_method_v1_commit(Resource *resource) override;
+ void text_input_method_v1_show_input_panel(Resource *resource) override;
+ void text_input_method_v1_hide_input_panel(Resource *resource) override;
+ void text_input_method_v1_update_hints(Resource *resource, int32_t hints) override;
+ void text_input_method_v1_update_surrounding_text(Resource *resource, const QString &surroundingText, int32_t surroundingTextOffset) override;
+ void text_input_method_v1_update_anchor_position(Resource *resource, int32_t anchorPosition) override;
+ void text_input_method_v1_update_cursor_position(Resource *resource, int32_t cursorPosition) override;
+ void text_input_method_v1_update_absolute_position(Resource *resource, int32_t absolutePosition) override;
+ void text_input_method_v1_invoke_action(Resource *resource, int32_t type, int32_t cursorPosition) override;
+ void text_input_method_v1_update_preferred_language(Resource *resource, const QString &preferredLanguage) override;
+ void text_input_method_v1_update_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override;
+ void text_input_method_v1_start_update(Resource *resource, int32_t queries) override;
+ void text_input_method_v1_end_update(Resource *resource) override;
+ void text_input_method_v1_acknowledge_input_method(Resource *resource) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQTTEXTINPUTMETHOD_P_H
diff --git a/src/compositor/extensions/qwaylandqttextinputmethodmanager.cpp b/src/compositor/extensions/qwaylandqttextinputmethodmanager.cpp
new file mode 100644
index 000000000..b37c1a9b8
--- /dev/null
+++ b/src/compositor/extensions/qwaylandqttextinputmethodmanager.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandqttextinputmethodmanager.h"
+#include "qwaylandqttextinputmethodmanager_p.h"
+
+#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/QWaylandSeat>
+
+#include "qwaylandqttextinputmethod.h"
+
+QT_BEGIN_NAMESPACE
+
+QWaylandQtTextInputMethodManagerPrivate::QWaylandQtTextInputMethodManagerPrivate()
+{
+}
+
+void QWaylandQtTextInputMethodManagerPrivate::text_input_method_manager_v1_get_text_input_method(Resource *resource, uint32_t id, struct ::wl_resource *seatResource)
+{
+ Q_Q(QWaylandQtTextInputMethodManager);
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(q->extensionContainer());
+ QWaylandSeat *seat = QWaylandSeat::fromSeatResource(seatResource);
+ QWaylandQtTextInputMethod *textInput = QWaylandQtTextInputMethod::findIn(seat);
+ if (textInput == nullptr)
+ textInput = new QWaylandQtTextInputMethod(seat, compositor);
+ textInput->add(resource->client(), id, wl_resource_get_version(resource->handle));
+}
+
+/*!
+ \qmltype QtTextInputMethodManager
+ \inqmlmodule QtWayland.Compositor
+ \since 6.0
+ \brief Provides access to input methods in the compositor.
+
+ The \c QtTextInputMethodManager corresponds to the \c qt-text-input-method-manager interface
+ in the \c qt-text-input-method-unstable-v1 extension protocol. It is specifically designed
+ to be used with a Qt-based input method, such as Qt Virtual Keyboard.
+
+ To use it, simply instanitate a \c QtTextInputMethodManager object inside the \l WaylandCompositor.
+*/
+
+/*!
+ \class QWaylandQtTextInputMethodManager
+ \inmodule QtWaylandCompositor
+ \since 6.0
+ \brief Provides access to input methods in the compositor.
+
+ The \c QWaylandQtTextInputMethodManager class corresponds to the \c qt-text-input-method-manager interface
+ in the \c qt-text-input-method-unstable-v1 extension protocol. It is specifically designed
+ to be used with a Qt-based input method, such as Qt Virtual Keyboard.
+
+ To use it, simply instanitate a \c QtTextInputMethodManager object as a child of the \l QWaylandCompositor.
+*/
+
+QWaylandQtTextInputMethodManager::QWaylandQtTextInputMethodManager()
+ : QWaylandCompositorExtensionTemplate<QWaylandQtTextInputMethodManager>(*new QWaylandQtTextInputMethodManagerPrivate)
+{
+}
+
+QWaylandQtTextInputMethodManager::QWaylandQtTextInputMethodManager(QWaylandCompositor *compositor)
+ : QWaylandCompositorExtensionTemplate<QWaylandQtTextInputMethodManager>(compositor, *new QWaylandQtTextInputMethodManagerPrivate)
+{
+}
+
+void QWaylandQtTextInputMethodManager::initialize()
+{
+ Q_D(QWaylandQtTextInputMethodManager);
+
+ QWaylandCompositorExtensionTemplate::initialize();
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ if (compositor == nullptr) {
+ qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandQtTextInputMethodManager";
+ return;
+ }
+
+ d->init(compositor->display(), 1);
+}
+
+const wl_interface *QWaylandQtTextInputMethodManager::interface()
+{
+ return QWaylandQtTextInputMethodManagerPrivate::interface();
+}
+
+QByteArray QWaylandQtTextInputMethodManager::interfaceName()
+{
+ return QWaylandQtTextInputMethodManagerPrivate::interfaceName();
+}
+
+QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandqttextinputmethodmanager.h b/src/compositor/extensions/qwaylandqttextinputmethodmanager.h
new file mode 100644
index 000000000..6e0751a2e
--- /dev/null
+++ b/src/compositor/extensions/qwaylandqttextinputmethodmanager.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDQTTEXTINPUTMETHODMANAGER_H
+#define QWAYLANDQTTEXTINPUTMETHODMANAGER_H
+
+#include <QtWaylandCompositor/QWaylandCompositorExtension>
+
+#include <QtCore/QSize>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandQtTextInputMethodManagerPrivate;
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQtTextInputMethodManager : public QWaylandCompositorExtensionTemplate<QWaylandQtTextInputMethodManager>
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandQtTextInputMethodManager)
+public:
+ QWaylandQtTextInputMethodManager();
+ QWaylandQtTextInputMethodManager(QWaylandCompositor *compositor);
+
+ void initialize() override;
+
+ static const struct wl_interface *interface();
+ static QByteArray interfaceName();
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQTTEXTINPUTMETHODMANAGER_H
diff --git a/src/compositor/extensions/qwaylandqttextinputmethodmanager_p.h b/src/compositor/extensions/qwaylandqttextinputmethodmanager_p.h
new file mode 100644
index 000000000..c730a402b
--- /dev/null
+++ b/src/compositor/extensions/qwaylandqttextinputmethodmanager_p.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDQTTEXTINPUTMETHODMANAGER_P_H
+#define QWAYLANDQTTEXTINPUTMETHODMANAGER_P_H
+
+#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+
+#include <QtWaylandCompositor/private/qwayland-server-qt-text-input-method-unstable-v1.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQtTextInputMethodManagerPrivate : public QWaylandCompositorExtensionPrivate, public QtWaylandServer::qt_text_input_method_manager_v1
+{
+ Q_DECLARE_PUBLIC(QWaylandQtTextInputMethodManager)
+public:
+ QWaylandQtTextInputMethodManagerPrivate();
+
+protected:
+ void text_input_method_manager_v1_get_text_input_method(Resource *resource, uint32_t id, struct ::wl_resource *seat) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQTTEXTINPUTMETHODMANAGER_P_H
diff --git a/src/extensions/qt-text-input-method-unstable-v1.xml b/src/extensions/qt-text-input-method-unstable-v1.xml
new file mode 100644
index 000000000..2e8cd4ec3
--- /dev/null
+++ b/src/extensions/qt-text-input-method-unstable-v1.xml
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<protocol name="qt_text_input_method_unstable_v1">
+ <copyright>
+ Copyright © 2020 The Qt Company Ltd.
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <interface name="qt_text_input_method_v1" version="1">
+ <description summary="text input">
+ The qt_text_input_method interface represents input method events
+ associated with a seat, and is intended to exactly match the
+ internal events of the Qt framework.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="Destroy the qt_text_input_method">
+ Destroy the qt_text_input_method object.
+ </description>
+ </request>
+
+ <request name="enable">
+ <description summary="enable input methods for surface">
+ Enable text input in a surface (usually when a text entry inside of it
+ has focus).
+
+ This can be called before or after a surface gets text (or keyboard)
+ focus via the enter event. Text input to a surface is only active
+ when it has the current text (or keyboard) focus and is enabled.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ </request>
+
+ <request name="disable">
+ <description summary="disable input methods for surface">
+ Disable text input in a surface (typically when there is no focus on any
+ text entry inside the surface).
+ </description>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ </request>
+
+ <event name="enter">
+ <description summary="enter event">
+ Notification that this seat's text-input focus is on a certain surface.
+
+ When the seat has the keyboard capability the text-input focus follows
+ the keyboard focus.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ </event>
+
+ <event name="leave">
+ <description summary="leave event">
+ Notification that this seat's text-input focus is no longer on
+ a certain surface.
+
+ The leave notification is sent before the enter notification
+ for the new focus.
+
+ When the seat has the keyboard capability the text-input focus follows
+ the keyboard focus.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ </event>
+
+ <event name="key">
+ <description summary="key event">
+ A QKeyEvent has been sent from the input method.
+ </description>
+ <arg name="type" type="int" />
+ <arg name="key" type="int" />
+ <arg name="modifiers" type="int" />
+ <arg name="auto_repeat" type="int" />
+ <arg name="count" type="int" />
+ <arg name="native_scan_code" type="int" />
+ <arg name="native_virtual_key" type="int" />
+ <arg name="native_modifiers" type="int" />
+ <arg name="text" type="string" />
+ </event>
+
+ <event name="start_input_method_event">
+ <description summary="input method event">
+ Starts an input method event. This can be followed by
+ any number of input_method_event_attribute events
+ and will always be finished by an end_input_method_event.
+ </description>
+ <arg name="serial" type="uint" />
+ <arg name="surrounding_text_offset" type="int" />
+ </event>
+
+ <event name="input_method_event_attribute">
+ <description summary="input method event attribute">
+ Appends an attribute to the input method event with
+ the given serial. Must be preceded by a start_input_method_event
+ and concluded by a an end_input_method_event. See documentation
+ of QInputMethodEvent for details on the attributes.
+ </description>
+ <arg name="serial" type="uint" />
+ <arg name="type" type="int" />
+ <arg name="start" type="int" />
+ <arg name="length" type="int" />
+ <arg name="value" type="string" />
+ </event>
+
+ <event name="end_input_method_event">
+ <description summary="input method event end">
+ Concludes a previously started input method event. Together with
+ the preceding input_method_event_attribute events with the same
+ serial, this should be converted into a QInputMethodEvent.
+ </description>
+ <arg name="serial" type="uint" />
+ <arg name="commit_string" type="string" />
+ <arg name="preedit_string" type="string" />
+ <arg name="replacement_start" type="int" />
+ <arg name="replacement_length" type="int" />
+ </event>
+
+ <event name="visible_changed">
+ <description summary="visible changed">
+ Event to notify client that the visibility of the input method has
+ been changed.
+ </description>
+ <arg name="visible" type="int" />
+ </event>
+
+ <event name="keyboard_rectangle_changed">
+ <description summary="keyboard rectangle changed">
+ Event to notify client that the keyboard rectangle of the input method
+ has been changed.
+ </description>
+ <arg name="x" type="fixed" />
+ <arg name="y" type="fixed" />
+ <arg name="width" type="fixed" />
+ <arg name="height" type="fixed" />
+ </event>
+
+ <event name="locale_changed">
+ <description summary="keyboard rectangle changed">
+ Event to notify client that the locale of the input method
+ has been changed.
+ </description>
+ <arg name="locale_name" type="string" />
+ </event>
+
+ <event name="input_direction_changed">
+ <description summary="input direction changed">
+ Event to notify client that the input direction of the input method
+ has been changed.
+ </description>
+ <arg name="input_direction" type="int" />
+ </event>
+
+ <request name="reset">
+ <description summary="reset">
+ Request for the input method to reset. Corresponds to QInputMethod::reset().
+ </description>
+ </request>
+
+ <request name="commit">
+ <description summary="commit">
+ Request for the input method to commit its current content. Corresponds to QInputMethod::commit().
+ </description>
+ </request>
+
+ <request name="invoke_action">
+ <description summary="invoke action">
+ Passes a mouse click or context menu request from the client to the server. Corresponds to QInputMethod::invokeAction().
+ </description>
+ <arg name="type" type="int" />
+ <arg name="cursor_position" type="int" />
+ </request>
+
+ <request name="update_hints">
+ <description summary="update hints">
+ Notifies the server of the client's current input method hints.
+ </description>
+ <arg name="hints" type="int" />
+ </request>
+
+ <request name="update_cursor_rectangle">
+ <description summary="update cursor rectangle">
+ Notifies the server of the client's current cursor rectangle.
+ </description>
+ <arg name="x" type="int" />
+ <arg name="y" type="int" />
+ <arg name="width" type="int" />
+ <arg name="height" type="int" />
+ </request>
+
+ <request name="update_cursor_position">
+ <description summary="update cursor position">
+ Notifies the server of the client's current cursor position.
+ </description>
+ <arg name="cursor_position" type="int" />
+ </request>
+
+ <request name="update_surrounding_text">
+ <description summary="update surrounding text">
+ Notifies the server of the client's current surrounding text and its offset in the
+ complete text.
+ </description>
+ <arg name="surrounding_text" type="string" />
+ <arg name="text_offset" type="int" />
+ </request>
+
+ <request name="update_anchor_position">
+ <description summary="update anchor position">
+ Notifies the server of the client's current anchor position.
+ </description>
+ <arg name="anchor_position" type="int" />
+ </request>
+
+ <request name="update_absolute_position">
+ <description summary="update absolute position">
+ Notifies the server of the client's current absolute cursor position.
+ </description>
+ <arg name="absolute_position" type="int" />
+ </request>
+
+ <request name="update_preferred_language">
+ <description summary="update preferred language">
+ Notifies the server of the client's current preferred language.
+ </description>
+ <arg name="preferred_language" type="string" />
+ </request>
+
+ <request name="start_update">
+ <description summary="start update">
+ Starts an update sequence to notify the server that the client's state has
+ changed. This is followed by any number of update requests for specific
+ parts of the state and concluded by an end_update request.
+ </description>
+ <arg name="queries" type="int" />
+ </request>
+
+ <request name="end_update">
+ <description summary="end update">
+ Concludes the previously started update request.
+ </description>
+ </request>
+
+ <request name="show_input_panel">
+ <description summary="show input panel">
+ Requests that the input panel of the input method is visible.
+ </description>
+ </request>
+
+ <request name="hide_input_panel">
+ <description summary="hide input panel">
+ Requests that the input panel of the input method is not visible.
+ </description>
+ </request>
+
+ <request name="acknowledge_input_method">
+ <description summary="acknowledge input method">
+ Sent on receipt of an end_input_method_event to acknowledge that
+ the client has received and handled the event.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="qt_text_input_method_manager_v1" version="1">
+ <description summary="qt text input method manager">
+ Manages qt_text_input_method objects.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="Destroy the qt_text_input_method_manager">
+ Destroy the qt_text_input_method_manager object.
+ </description>
+ </request>
+
+ <request name="get_text_input_method">
+ <description summary="create a new text input method object">
+ Creates a new text-input-method object for a given seat.
+ </description>
+ <arg name="id" type="new_id" interface="qt_text_input_method_v1" />
+ <arg name="seat" type="object" interface="wl_seat" />
+ </request>
+ </interface>
+</protocol>
diff --git a/sync.profile b/sync.profile
index cab4a2527..8578c0c2b 100644
--- a/sync.profile
+++ b/sync.profile
@@ -26,6 +26,7 @@
"^qwayland-surface-extension.h",
"^qwayland-tablet-unstable-v2.h",
"^qwayland-text-input-unstable-v2.h",
+ "^qwayland-qt-text-input-method-unstable-v1.h",
"^qwayland-touch-extension.h",
"^qwayland-wayland.h",
"^qwayland-wp-primary-selection-unstable-v1.h",
@@ -37,6 +38,7 @@
"^wayland-surface-extension-client-protocol.h",
"^wayland-tablet-unstable-v2-client-protocol.h",
"^wayland-text-input-unstable-v2-client-protocol.h",
+ "^wayland-qt-text-input-method-unstable-v1-client-protocol.h",
"^wayland-touch-extension-client-protocol.h",
"^wayland-wayland-client-protocol.h",
"^wayland-wp-primary-selection-unstable-v1-client-protocol.h",
@@ -63,6 +65,7 @@
"^qwayland-server-scaler.h",
"^qwayland-server-server-buffer-extension.h",
"^qwayland-server-text-input-unstable-v2.h",
+ "^qwayland-server-qt-text-input-method-unstable-v1.h",
"^qwayland-server-touch-extension.h",
"^qwayland-server-viewporter.h",
"^qwayland-server-xdg-decoration-unstable-v1.h",
@@ -77,6 +80,7 @@
"^wayland-scaler-server-protocol.h",
"^wayland-server-buffer-extension-server-protocol.h",
"^wayland-text-input-unstable-v2-server-protocol.h",
+ "^wayland-qt-text-input-method-unstable-v1-server-protocol.h",
"^wayland-viewporter-server-protocol.h",
"^wayland-touch-extension-server-protocol.h",
"^wayland-wayland-server-protocol.h",