summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@qt.io>2018-12-13 12:14:59 +0100
committerGatis Paeglis <gatis.paeglis@qt.io>2019-04-15 14:10:28 +0000
commit3aedd01271dc4f4a13103d632df224971ab2b6df (patch)
treec4e5b95e00fb1051ae26d151adfe80f9de19092d /tests
parent1b773df93f5bccb6b616d2a228cb15cffe8e32d5 (diff)
client: rework input method handling
The existing solution was parsing compose tables on startup, it is better to lazy initialize the compose table/state on a first key press, instead of doing it on an application startup. This logic is inside of the compose input plugin. The existing code did not utilize correctly how Qt handles complex text input. It used libxkbcommon-compose APIs to compose user input and then passed the same input again to QPlatformInputContext (from QWaylandInputDevice::Keyboard::sendKey), which was erroneous. This also means that code was forcing "xkb compose", and did not respect QT_IM_MODULE at client-side. From commit that added compose key handling (57c4af2b18c0fb1d266b245a107fa6cb876b9d9e): "We should expand on it in the future to handle things like resetting the compose state on text field switching". This is now handled by properly utilizing Qt IM framework. Converted QWaylandInputDevice::Keyboard::sendKey into a class member function to avoid adding one more arg (mXkbContext) to the already long argument list. That whole function should be simplified, but that is out-of-scope for this patch. The reworked code uses qxkbcommon support library to reduce code duplication between platforms and to unify behavior. Some users might mistakenly think that this patch introduces a regression with Qt on KDE, but it is actually a KWin/Wayland compositor bug: https://bugs.kde.org/show_bug.cgi?id=405388 The work around on KDE is to use QT_IM_MODULE at client-side to select input method, as KWin compositor over the wire supports only the qtvirtualkeyboard module. Setting this envvar is not someting out of the ordinary for users on Linux. Input method handling at compositor-side is new feature and clearly not very well supported yet. Task-number: QTBUG-65503 Change-Id: Ie511d950396fa2fb6cbe6672996cee9791f3ab11 Reviewed-by: Johan Helsing <johan.helsing@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/client/client.pro2
-rw-r--r--tests/auto/client/inputcontext/inputcontext.pro6
-rw-r--r--tests/auto/client/inputcontext/tst_inputcontext.cpp184
-rw-r--r--tests/auto/client/shared/shared.pri9
-rw-r--r--tests/auto/client/shared/textinput.cpp45
-rw-r--r--tests/auto/client/shared/textinput.h51
6 files changed, 294 insertions, 3 deletions
diff --git a/tests/auto/client/client.pro b/tests/auto/client/client.pro
index e99db20ba..051cb4e3d 100644
--- a/tests/auto/client/client.pro
+++ b/tests/auto/client/client.pro
@@ -12,3 +12,5 @@ SUBDIRS += \
xdgoutput \
xdgshell \
xdgshellv6
+
+qtConfig(im): SUBDIRS += inputcontext
diff --git a/tests/auto/client/inputcontext/inputcontext.pro b/tests/auto/client/inputcontext/inputcontext.pro
new file mode 100644
index 000000000..4419b3e77
--- /dev/null
+++ b/tests/auto/client/inputcontext/inputcontext.pro
@@ -0,0 +1,6 @@
+include (../shared/shared.pri)
+
+QT += waylandcompositor
+
+TARGET = tst_inputcontext
+SOURCES += tst_inputcontext.cpp
diff --git a/tests/auto/client/inputcontext/tst_inputcontext.cpp b/tests/auto/client/inputcontext/tst_inputcontext.cpp
new file mode 100644
index 000000000..b1a5a7f17
--- /dev/null
+++ b/tests/auto/client/inputcontext/tst_inputcontext.cpp
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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 "mockcompositor.h"
+#include "textinput.h"
+
+#include <QtCore/QString>
+#include <QtCore/QByteArray>
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatforminputcontext.h>
+#include <QtGui/qpa/qplatformintegration.h>
+#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
+
+#include <QtTest/QtTest>
+
+using namespace MockCompositor;
+
+class tst_inputcontext : public QObject, private DefaultCompositor
+{
+ Q_OBJECT
+private slots:
+ void initTestCase();
+ void selectingInputContext_data();
+ void selectingInputContext();
+ void inputContextReconfigurationWhenTogglingTextInputExtension();
+
+private:
+ QByteArray inputContextName() const;
+ void ensureTextInputPresentOnCompositor();
+ void ensureTextInputNotPresentOnCompositor();
+
+ QByteArray mComposeModule = QByteArray("QComposeInputContext"); // default input context
+ QByteArray mIbusModule = QByteArray("QIBusPlatformInputContext");
+ QByteArray mWaylandModule = QByteArray("QtWaylandClient::QWaylandInputContext");
+
+ TextInputManager *mTextInputManager = nullptr;
+};
+
+void tst_inputcontext::initTestCase()
+{
+ // Verify that plugins are present and valid
+ QPlatformInputContext *context = QPlatformInputContextFactory::create(QStringLiteral("compose"));
+ QVERIFY(context && context->isValid());
+
+ context = QPlatformInputContextFactory::create(QStringLiteral("ibus"));
+ // The ibus plugin depends on properly configured system services, if plugin is not valid
+ // verify that wayland qpa plugin properly fallbacks to default input context.
+ if (!context || !context->isValid())
+ mIbusModule = mComposeModule;
+}
+
+QByteArray tst_inputcontext::inputContextName() const
+{
+ QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ if (platformIntegration->inputContext())
+ return platformIntegration->inputContext()->metaObject()->className();
+
+ return QByteArray("");
+}
+
+void tst_inputcontext::ensureTextInputPresentOnCompositor()
+{
+ exec([&] {
+ QVector<TextInputManager *> extensions = getAll<TextInputManager>();
+ if (extensions.length() > 1)
+ QFAIL("TextInputManager is a singleton, hence there should not be more then one object returned");
+ if (extensions.length() == 0)
+ add<TextInputManager>();
+ });
+}
+
+void tst_inputcontext::ensureTextInputNotPresentOnCompositor()
+{
+ exec([&] {
+ QVector<TextInputManager *> extensions = getAll<TextInputManager>();
+ if (extensions.length() > 1)
+ QFAIL("TextInputManager is a singleton, hence there should not be more then one object returned");
+ if (extensions.length() == 1)
+ remove(extensions.first());
+ });
+}
+
+void tst_inputcontext::selectingInputContext_data()
+{
+ QTest::addColumn<QByteArray>("requestedModule");
+ QTest::addColumn<QByteArray>("expectedModule");
+
+ // Test compositor without Text Input extension
+ QTest::newRow("ibus") << QByteArray("ibus") << mIbusModule;
+ QTest::newRow("compose") << QByteArray("compose") << mComposeModule;
+ QTest::newRow("empty") << QByteArray("") << mComposeModule;
+ QTest::newRow("null") << QByteArray() << mComposeModule;
+ QTest::newRow("fake") << QByteArray("fake") << mComposeModule;
+
+ // Test compositor with Text Input extension
+ QTest::newRow("ibus:text-input") << QByteArray("ibus") << mIbusModule;
+ QTest::newRow("compose:text-input") << QByteArray("compose") << mComposeModule;
+ QTest::newRow("empty:text-input") << QByteArray("") << mComposeModule;
+ QTest::newRow("null:text-input") << QByteArray() << mWaylandModule;
+ QTest::newRow("fake:text-input") << QByteArray("fake") << mComposeModule;
+}
+
+void tst_inputcontext::selectingInputContext()
+{
+ QFETCH(QByteArray, requestedModule);
+ QFETCH(QByteArray, expectedModule);
+
+ if (requestedModule.isNull())
+ qunsetenv("QT_IM_MODULE");
+ else
+ qputenv("QT_IM_MODULE", requestedModule);
+
+ const bool withTextInputAtCompositorSide = QByteArray(QTest::currentDataTag()).endsWith(":text-input");
+
+ if (withTextInputAtCompositorSide)
+ ensureTextInputPresentOnCompositor();
+ else
+ ensureTextInputNotPresentOnCompositor();
+
+ int argc = 0;
+ QGuiApplication app(argc, nullptr); // loads the platform plugin
+
+ QCOMPARE(inputContextName(), expectedModule);
+}
+
+void tst_inputcontext::inputContextReconfigurationWhenTogglingTextInputExtension()
+{
+ qunsetenv("QT_IM_MODULE");
+
+ ensureTextInputPresentOnCompositor();
+ int argc = 0;
+ QGuiApplication app(argc, nullptr); // loads the platform plugin
+ QCOMPARE(inputContextName(), mWaylandModule);
+
+ // remove text input extension after the platform plugin has been loaded
+ ensureTextInputNotPresentOnCompositor();
+ // QTRY_* because we need to spin the event loop for wayland QPA plugin
+ // to handle registry_global_remove()
+ QTRY_COMPARE(inputContextName(), mComposeModule);
+
+ // add text input extension after the platform plugin has been loaded
+ ensureTextInputPresentOnCompositor();
+ // QTRY_* because we need to spin the event loop for wayland QPA plugin
+ // to handle registry_global()
+ QTRY_COMPARE(inputContextName(), mWaylandModule);
+}
+
+int main(int argc, char *argv[])
+{
+ qputenv("XDG_RUNTIME_DIR", ".");
+ qputenv("QT_QPA_PLATFORM", "wayland");
+
+ tst_inputcontext tc;
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_inputcontext.moc"
diff --git a/tests/auto/client/shared/shared.pri b/tests/auto/client/shared/shared.pri
index 303e13046..c86183b3d 100644
--- a/tests/auto/client/shared/shared.pri
+++ b/tests/auto/client/shared/shared.pri
@@ -4,7 +4,8 @@ QMAKE_USE += wayland-server
WAYLANDSERVERSOURCES += \
$$PWD/../../../../src/3rdparty/protocol/wayland.xml \
- $$PWD/../../../../src/3rdparty/protocol/xdg-shell.xml
+ $$PWD/../../../../src/3rdparty/protocol/xdg-shell.xml \
+ $$PWD/../../../../src/3rdparty/protocol/text-input-unstable-v2.xml
INCLUDEPATH += ../shared
@@ -13,11 +14,13 @@ HEADERS += \
$$PWD/coreprotocol.h \
$$PWD/datadevice.h \
$$PWD/mockcompositor.h \
- $$PWD/xdgshell.h
+ $$PWD/xdgshell.h \
+ $$PWD/textinput.h
SOURCES += \
$$PWD/corecompositor.cpp \
$$PWD/coreprotocol.cpp \
$$PWD/datadevice.cpp \
$$PWD/mockcompositor.cpp \
- $$PWD/xdgshell.cpp
+ $$PWD/xdgshell.cpp \
+ $$PWD/textinput.cpp
diff --git a/tests/auto/client/shared/textinput.cpp b/tests/auto/client/shared/textinput.cpp
new file mode 100644
index 000000000..f9fd287bb
--- /dev/null
+++ b/tests/auto/client/shared/textinput.cpp
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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 "textinput.h"
+
+namespace MockCompositor {
+
+TextInputManager::TextInputManager(CoreCompositor *compositor)
+{
+ init(compositor->m_display, 1);
+}
+
+void TextInputManager::zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, wl_resource *seatResource)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(id);
+ Q_UNUSED(seatResource);
+}
+
+} // namespace MockCompositor
diff --git a/tests/auto/client/shared/textinput.h b/tests/auto/client/shared/textinput.h
new file mode 100644
index 000000000..85072e74b
--- /dev/null
+++ b/tests/auto/client/shared/textinput.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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 MOCKCOMPOSITOR_TEXTINPUT_H
+#define MOCKCOMPOSITOR_TEXTINPUT_H
+
+#include "coreprotocol.h"
+#include <qwayland-server-text-input-unstable-v2.h>
+
+#include <QtGui/qpa/qplatformnativeinterface.h>
+
+namespace MockCompositor {
+
+class TextInputManager : public Global, public QtWaylandServer::zwp_text_input_manager_v2
+{
+ Q_OBJECT
+public:
+ TextInputManager(CoreCompositor *compositor);
+
+protected:
+ void zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seatResource) override;
+};
+
+} // namespace MockCompositor
+
+#endif // MOCKCOMPOSITOR_TEXTINPUT_H