diff --git a/src/wayland/autotests/server/test_textinputv3_interface.cpp b/src/wayland/autotests/server/test_textinputv3_interface.cpp index efe09b5833..bb6bbf2ec8 100644 --- a/src/wayland/autotests/server/test_textinputv3_interface.cpp +++ b/src/wayland/autotests/server/test_textinputv3_interface.cpp @@ -292,6 +292,7 @@ void TestTextInputV3Interface::testEvents() QSignalSpy focusedSurfaceChangedSpy(m_seat, &SeatInterface::focusedTextInputSurfaceChanged); QSignalSpy textInputEnabledSpy(m_serverTextInputV3, &TextInputV3Interface::enabledChanged); + QSignalSpy doneSpy(m_clientTextInputV3, &TextInputV3::done); // Enter the textinput QVERIFY(focusedSurfaceChangedSpy.isValid()); @@ -308,11 +309,12 @@ void TestTextInputV3Interface::testEvents() m_clientTextInputV3->commit(); m_totalCommits++; QVERIFY(textInputEnabledSpy.wait()); + QVERIFY(doneSpy.wait()); + QCOMPARE(doneSpy.count(), 1); QSignalSpy preEditSpy(m_clientTextInputV3, &TextInputV3::preedit_string); QSignalSpy commitStringSpy(m_clientTextInputV3, &TextInputV3::commit_string); QSignalSpy deleteSurroundingSpy(m_clientTextInputV3, &TextInputV3::delete_surrounding_text); - QSignalSpy doneSpy(m_clientTextInputV3, &TextInputV3::done); m_serverTextInputV3->sendPreEditString("Hello KDE community!", 1, 2); m_serverTextInputV3->deleteSurroundingText(6, 10); @@ -320,7 +322,7 @@ void TestTextInputV3Interface::testEvents() m_serverTextInputV3->done(); QVERIFY(doneSpy.wait()); - QCOMPARE(doneSpy.count(), 1); + QCOMPARE(doneSpy.count(), 2); QCOMPARE(preEditSpy.count(), 1); QCOMPARE(commitStringSpy.count(), 1); QCOMPARE(deleteSurroundingSpy.count(), 1); diff --git a/src/wayland/textinput_v3_interface.cpp b/src/wayland/textinput_v3_interface.cpp index 48bd139ea2..3d1ddaf967 100644 --- a/src/wayland/textinput_v3_interface.cpp +++ b/src/wayland/textinput_v3_interface.cpp @@ -209,6 +209,11 @@ void TextInputV3InterfacePrivate::sendPreEdit(const QString &text, const quint32 if (!surface) { return; } + + pending.preeditText = text; + pending.preeditCursorBegin = cursorBegin; + pending.preeditCursorEnd = cursorEnd; + const QList textInputs = enabledTextInputsForClient(surface->client()); for (auto resource : textInputs) { send_preedit_string(resource->handle, text, cursorBegin, cursorEnd); @@ -244,6 +249,11 @@ void TextInputV3InterfacePrivate::done() } const QList textInputs = enabledTextInputsForClient(surface->client()); + preeditText = pending.preeditText; + preeditCursorBegin = pending.preeditCursorBegin; + preeditCursorEnd = pending.preeditCursorEnd; + defaultPendingPreedit(); + for (auto resource : textInputs) { // zwp_text_input_v3.done takes the serial argument which is equal to number of commit requests issued send_done(resource->handle, serialHash[resource]); @@ -291,6 +301,9 @@ void TextInputV3InterfacePrivate::zwp_text_input_v3_disable(Resource *resource) // reset pending state to default Q_UNUSED(resource) defaultPending(); + preeditText = QString(); + preeditCursorBegin = 0; + preeditCursorEnd = 0; } void TextInputV3InterfacePrivate::zwp_text_input_v3_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor) @@ -377,6 +390,14 @@ void TextInputV3InterfacePrivate::zwp_text_input_v3_commit(Resource *resource) } Q_EMIT q->stateCommitted(serialHash[resource]); + + // Gtk text input implementation expect done to be sent after every commit to synchronize the serial value between commit() and done(). + // So we need to send the current preedit text with done(). + // If current preedit is empty, there is no need to send it. + if (!preeditText.isEmpty() || preeditCursorBegin != 0 || preeditCursorEnd != 0) { + send_preedit_string(resource->handle, preeditText, preeditCursorBegin, preeditCursorEnd); + } + send_done(resource->handle, serialHash[resource]); } void TextInputV3InterfacePrivate::defaultPending() @@ -389,6 +410,14 @@ void TextInputV3InterfacePrivate::defaultPending() pending.surroundingText = QString(); pending.surroundingTextCursorPosition = 0; pending.surroundingTextSelectionAnchor = 0; + defaultPendingPreedit(); +} + +void TextInputV3InterfacePrivate::defaultPendingPreedit() +{ + pending.preeditText = QString(); + pending.preeditCursorBegin = 0; + pending.preeditCursorEnd = 0; } TextInputV3Interface::TextInputV3Interface(SeatInterface *seat) diff --git a/src/wayland/textinput_v3_interface_p.h b/src/wayland/textinput_v3_interface_p.h index c404f33e10..50b383d3ce 100644 --- a/src/wayland/textinput_v3_interface_p.h +++ b/src/wayland/textinput_v3_interface_p.h @@ -63,6 +63,10 @@ public: qint32 surroundingTextSelectionAnchor = 0; TextInputChangeCause surroundingTextChangeCause = TextInputChangeCause::InputMethod; + QString preeditText; + quint32 preeditCursorBegin = 0; + quint32 preeditCursorEnd = 0; + struct { QRect cursorRectangle; @@ -73,12 +77,16 @@ public: QString surroundingText; qint32 surroundingTextCursorPosition = 0; qint32 surroundingTextSelectionAnchor = 0; + QString preeditText; + quint32 preeditCursorBegin = 0; + quint32 preeditCursorEnd = 0; } pending; QHash serialHash; QHash enabled; void defaultPending(); + void defaultPendingPreedit(); TextInputV3Interface *q;