diff options
-rw-r--r-- | examples/wayland/pure-qml/qml/main.qml | 2 | ||||
-rw-r--r-- | src/client/client.pro | 5 | ||||
-rw-r--r-- | src/client/qwaylanddisplay.cpp | 12 | ||||
-rw-r--r-- | src/client/qwaylanddisplay_p.h | 8 | ||||
-rw-r--r-- | src/client/qwaylandinputdevice.cpp | 85 | ||||
-rw-r--r-- | src/client/qwaylandinputdevice_p.h | 16 | ||||
-rw-r--r-- | src/client/qwaylandintegration.cpp | 56 | ||||
-rw-r--r-- | src/client/qwaylandintegration_p.h | 2 | ||||
-rw-r--r-- | tests/auto/client/client.pro | 2 | ||||
-rw-r--r-- | tests/auto/client/inputcontext/inputcontext.pro | 6 | ||||
-rw-r--r-- | tests/auto/client/inputcontext/tst_inputcontext.cpp | 184 | ||||
-rw-r--r-- | tests/auto/client/shared/shared.pri | 9 | ||||
-rw-r--r-- | tests/auto/client/shared/textinput.cpp | 45 | ||||
-rw-r--r-- | tests/auto/client/shared/textinput.h | 51 |
14 files changed, 378 insertions, 105 deletions
diff --git a/examples/wayland/pure-qml/qml/main.qml b/examples/wayland/pure-qml/qml/main.qml index 69be7cf1..483de751 100644 --- a/examples/wayland/pure-qml/qml/main.qml +++ b/examples/wayland/pure-qml/qml/main.qml @@ -72,6 +72,6 @@ WaylandCompositor { onWlShellSurfaceCreated: screen.handleShellSurface(shellSurface) } - // Extension for Virtual keyboard support + // Extension for Input Method (QT_IM_MODULE) support at compositor-side TextInputManager {} } diff --git a/src/client/client.pro b/src/client/client.pro index 38d0ac3e..9f7d979d 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -15,8 +15,9 @@ use_gold_linker: CONFIG += no_linker_version_script CONFIG -= precompile_header CONFIG += link_pkgconfig wayland-scanner -qtConfig(xkbcommon): \ - QMAKE_USE_PRIVATE += xkbcommon +qtConfig(xkbcommon) { + QT_PRIVATE += xkbcommon_support-private +} qtHaveModule(linuxaccessibility_support_private): \ QT += linuxaccessibility_support_private diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 5b1b9bff..22a79124 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -266,11 +266,11 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin mTouchExtension.reset(new QWaylandTouchExtension(this, id)); } else if (interface == QStringLiteral("zqt_key_v1")) { mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id)); - } else if (interface == QStringLiteral("zwp_text_input_manager_v2")) { + } else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) { mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1)); - foreach (QWaylandInputDevice *inputDevice, mInputDevices) { + for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices)) inputDevice->setTextInput(new QWaylandTextInput(this, mTextInputManager->get_text_input(inputDevice->wl_seat()))); - } + mWaylandIntegration->reconfigureInputContext(); } else if (interface == QStringLiteral("qt_hardware_integration")) { bool disableHardwareIntegration = qEnvironmentVariableIntValue("QT_WAYLAND_DISABLE_HW_INTEGRATION"); if (!disableHardwareIntegration) { @@ -306,6 +306,12 @@ void QWaylandDisplay::registry_global_remove(uint32_t id) } } } + if (global.interface == QStringLiteral("zwp_text_input_manager_v2")) { + mTextInputManager.reset(); + for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices)) + inputDevice->setTextInput(nullptr); + mWaylandIntegration->reconfigureInputContext(); + } mGlobals.removeAt(i); break; } diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 4a98b935..836ee0f9 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -63,6 +63,8 @@ #include <QtWaylandClient/private/qtwaylandclientglobal_p.h> #include <QtWaylandClient/private/qwaylandshm_p.h> +#include <qpa/qplatforminputcontextfactory_p.h> + struct wl_cursor_image; QT_BEGIN_NAMESPACE @@ -144,6 +146,7 @@ public: QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); } QtWayland::zxdg_output_manager_v1 *xdgOutputManager() const { return mXdgOutputManager.data(); } + bool usingInputContextFromCompositor() const { return mUsingInputContextFromCompositor; } struct RegistryGlobal { uint32_t id; @@ -237,8 +240,13 @@ private: struct wl_callback *mSyncCallback = nullptr; static const wl_callback_listener syncCallbackListener; + bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull(); + bool mUsingInputContextFromCompositor = false; + void registry_global(uint32_t id, const QString &interface, uint32_t version) override; void registry_global_remove(uint32_t id) override; + + friend class QWaylandIntegration; }; } diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 2ae2caca..f31ab274 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -71,7 +71,7 @@ #include <QtGui/QGuiApplication> #if QT_CONFIG(xkbcommon) -#include <xkbcommon/xkbcommon-compose.h> +#include <xkbcommon/xkbcommon.h> #endif QT_BEGIN_NAMESPACE @@ -110,7 +110,7 @@ bool QWaylandInputDevice::Keyboard::createDefaultKeyMap() qWarning() << "xkb_map_new_from_names failed, no key input"; return false; } - createComposeState(); + return true; } @@ -123,41 +123,11 @@ void QWaylandInputDevice::Keyboard::releaseKeyMap() if (mXkbContext) xkb_context_unref(mXkbContext); } - -void QWaylandInputDevice::Keyboard::createComposeState() -{ - static const char *locale = nullptr; - if (!locale) { - locale = getenv("LC_ALL"); - if (!locale) - locale = getenv("LC_CTYPE"); - if (!locale) - locale = getenv("LANG"); - if (!locale) - locale = "C"; - } - - mXkbComposeTable = xkb_compose_table_new_from_locale(mXkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); - if (mXkbComposeTable) - mXkbComposeState = xkb_compose_state_new(mXkbComposeTable, XKB_COMPOSE_STATE_NO_FLAGS); -} - -void QWaylandInputDevice::Keyboard::releaseComposeState() -{ - if (mXkbComposeState) - xkb_compose_state_unref(mXkbComposeState); - if (mXkbComposeTable) - xkb_compose_table_unref(mXkbComposeTable); - mXkbComposeState = nullptr; - mXkbComposeTable = nullptr; -} - #endif QWaylandInputDevice::Keyboard::~Keyboard() { #if QT_CONFIG(xkbcommon) - releaseComposeState(); releaseKeyMap(); #endif if (mFocus) @@ -396,9 +366,9 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, } #endif - if (mQDisplay->textInputManager()) { - mTextInput = new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat())); - } + if (mQDisplay->textInputManager()) + mTextInput.reset(new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat()))); + } QWaylandInputDevice::~QWaylandInputDevice() @@ -481,12 +451,12 @@ QWaylandDataDevice *QWaylandInputDevice::dataDevice() const void QWaylandInputDevice::setTextInput(QWaylandTextInput *textInput) { - mTextInput = textInput; + mTextInput.reset(textInput); } QWaylandTextInput *QWaylandInputDevice::textInput() const { - return mTextInput; + return mTextInput.data(); } void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button) @@ -793,7 +763,6 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, // Release the old keymap resources in the case they were already created in // the key event or when the compositor issues a new map - releaseComposeState(); releaseKeyMap(); mXkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); @@ -802,8 +771,6 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, close(fd); mXkbState = xkb_state_new(mXkbMap); - createComposeState(); - #else Q_UNUSED(format); Q_UNUSED(fd); @@ -852,16 +819,17 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf handleFocusLost(); } -static void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, - quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString& text = QString(), bool autorep = false, ushort count = 1) +void QWaylandInputDevice::Keyboard::sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, + Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, + quint32 nativeVirtualKey, quint32 nativeModifiers, + const QString& text, bool autorep, ushort count) { QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); bool filtered = false; - if (inputContext) { - QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, - text, autorep, count); + if (inputContext && !mParent->mQDisplay->usingInputContextFromCompositor()) { + QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey, + nativeModifiers, text, autorep, count); event.setTimestamp(timestamp); filtered = inputContext->filterEvent(&event); } @@ -896,37 +864,12 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, return; } - QString composedText; xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, code); - if (mXkbComposeState) { - if (isDown) - xkb_compose_state_feed(mXkbComposeState, sym); - xkb_compose_status status = xkb_compose_state_get_status(mXkbComposeState); - - switch (status) { - case XKB_COMPOSE_COMPOSED: { - int size = xkb_compose_state_get_utf8(mXkbComposeState, nullptr, 0); - QVarLengthArray<char, 32> buffer(size + 1); - xkb_compose_state_get_utf8(mXkbComposeState, buffer.data(), buffer.size()); - composedText = QString::fromUtf8(buffer.constData()); - sym = xkb_compose_state_get_one_sym(mXkbComposeState); - xkb_compose_state_reset(mXkbComposeState); - } break; - case XKB_COMPOSE_COMPOSING: - case XKB_COMPOSE_CANCELLED: - return; - case XKB_COMPOSE_NOTHING: - break; - } - } Qt::KeyboardModifiers modifiers = mParent->modifiers(); std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers); - if (!composedText.isNull()) - text = composedText; - sendKey(window->window(), time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); #else // Generic fallback for single hard keys: Assume 'key' is a Qt key code. diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 50b1af38..4149e500 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -54,6 +54,7 @@ #include <QtWaylandClient/private/qtwaylandclientglobal_p.h> #include <QtWaylandClient/private/qwaylandwindow_p.h> +#include <QtCore/QScopedPointer> #include <QSocketNotifier> #include <QObject> #include <QTimer> @@ -75,11 +76,6 @@ struct wl_cursor_image; #endif -#if QT_CONFIG(xkbcommon) -struct xkb_compose_state; -struct xkb_compose_table; -#endif - QT_BEGIN_NAMESPACE namespace QtWaylandClient { @@ -164,7 +160,7 @@ private: Pointer *mPointer = nullptr; Touch *mTouch = nullptr; - QWaylandTextInput *mTextInput = nullptr; + QScopedPointer<QWaylandTextInput> mTextInput; uint32_t mTime = 0; uint32_t mSerial = 0; @@ -217,8 +213,6 @@ public: xkb_context *mXkbContext = nullptr; xkb_keymap *mXkbMap = nullptr; xkb_state *mXkbState = nullptr; - xkb_compose_table *mXkbComposeTable = nullptr; - xkb_compose_state *mXkbComposeState = nullptr; #endif uint32_t mNativeModifiers = 0; @@ -244,10 +238,10 @@ private: #if QT_CONFIG(xkbcommon) bool createDefaultKeyMap(); void releaseKeyMap(); - void createComposeState(); - void releaseComposeState(); #endif - + void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, + quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, + const QString& text = QString(), bool autorep = false, ushort count = 1); }; class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp index 45957629..8bfe3b6f 100644 --- a/src/client/qwaylandintegration.cpp +++ b/src/client/qwaylandintegration.cpp @@ -90,6 +90,10 @@ #include <QtLinuxAccessibilitySupport/private/bridge_p.h> #endif +#if QT_CONFIG(xkbcommon) +#include <QtXkbCommonSupport/private/qxkbcommon_p.h> +#endif + QT_BEGIN_NAMESPACE namespace QtWaylandClient { @@ -146,20 +150,8 @@ QWaylandIntegration::QWaylandIntegration() #if QT_CONFIG(draganddrop) mDrag.reset(new QWaylandDrag(mDisplay.data())); #endif - QString icStr = QPlatformInputContextFactory::requested(); - if (!icStr.isNull()) { - mInputContext.reset(QPlatformInputContextFactory::create(icStr)); - } else { - //try to use the input context using the wl_text_input interface - QPlatformInputContext *ctx = new QWaylandInputContext(mDisplay.data()); - mInputContext.reset(ctx); - - //use the traditional way for on screen keyboards for now - if (!mInputContext.data()->isValid()) { - ctx = QPlatformInputContextFactory::create(); - mInputContext.reset(ctx); - } - } + + reconfigureInputContext(); } QWaylandIntegration::~QWaylandIntegration() @@ -462,6 +454,42 @@ void QWaylandIntegration::initializeInputDeviceIntegration() } } +void QWaylandIntegration::reconfigureInputContext() +{ + if (!mDisplay) { + // This function can be called from QWaylandDisplay::registry_global() when we + // are in process of constructing QWaylandDisplay. Configuring input context + // in that case is done by calling reconfigureInputContext() from QWaylandIntegration + // constructor, after QWaylandDisplay has been constructed. + return; + } + + const QString &requested = QPlatformInputContextFactory::requested(); + if (requested == QLatin1String("qtvirtualkeyboard")) + 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 + mInputContext.reset(QPlatformInputContextFactory::create(requested)); + + const QString defaultInputContext(QStringLiteral("compose")); + if ((!mInputContext || !mInputContext->isValid()) && requested != defaultInputContext) + mInputContext.reset(QPlatformInputContextFactory::create(defaultInputContext)); + +#if QT_CONFIG(xkbcommon) + QXkbCommon::setXkbContext(mInputContext.data(), xkb_context_new(XKB_CONTEXT_NO_FLAGS)); +#endif + + // Even if compositor-side input context handling has been requested, we fallback to + // client-side handling if compositor does not provide the text-input extension. This + // is why we need to check here which input context actually is being used. + mDisplay->mUsingInputContextFromCompositor = qobject_cast<QWaylandInputContext *>(mInputContext.data()); + + qCDebug(lcQpaWayland) << "using input method:" << inputContext()->metaObject()->className(); +} + QWaylandShellIntegration *QWaylandIntegration::createShellIntegration(const QString &integrationName) { if (QWaylandShellIntegrationFactory::keys().contains(integrationName)) { diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h index 944f635b..5e6f16d0 100644 --- a/src/client/qwaylandintegration_p.h +++ b/src/client/qwaylandintegration_p.h @@ -116,6 +116,8 @@ public: virtual QWaylandServerBufferIntegration *serverBufferIntegration() const; virtual QWaylandShellIntegration *shellIntegration() const; + void reconfigureInputContext(); + private: // NOTE: mDisplay *must* be destructed after mDrag and mClientBufferIntegration // and mShellIntegration. diff --git a/tests/auto/client/client.pro b/tests/auto/client/client.pro index e99db20b..051cb4e3 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 00000000..4419b3e7 --- /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 00000000..b1a5a7f1 --- /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 303e1304..c86183b3 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 00000000..f9fd287b --- /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 00000000..85072e74 --- /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 |