Always send a done after commit for text input v3.

In Gtk's text-input-v3 implementation it expect done to update the
client serial after every commit. Though it is unclear whether this is a
protocol requirements, do the same thing like mutter for more
compatiblity, especially Gtk3 is in EOL not likely to be patched any
time soon.

To do so, we will need to keep track of the last active preedit,
otherwise only send_done() will clear the preedit.
This commit is contained in:
Weng Xuetian 2022-06-10 16:23:52 -07:00 committed by Xuetian Weng
parent dc9c431fe3
commit a74c436156
3 changed files with 41 additions and 2 deletions

View file

@ -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);

View file

@ -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<Resource *> 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<Resource *> 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)

View file

@ -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<Resource *, quint32> serialHash;
QHash<Resource *, bool> enabled;
void defaultPending();
void defaultPendingPreedit();
TextInputV3Interface *q;