fix(engine): a reset or a lost focus commits the pending text

Clicking elsewhere, changing focus, or any client reset dropped the
composition in the GTK module and IBus (only XIM ResetIC handed it
back), so typing 안녕 and clicking Send lost 녕. The engine now returns
the pending text — a moved-to candidate first, as Enter would — on
Keyreset and Keyrelease; the GTK module asks for it before closing on
focus-out and commits it, IBus commits it on FocusOut, Reset and a
switch to a password field, and XIM commits it on focus loss and hands
it back on ResetIC without a separate capability probe.
This commit is contained in:
2026-08-16 21:05:31 +09:00
parent 4c8954b8ae
commit 11bf379ad3
10 changed files with 151 additions and 98 deletions

View File

@@ -163,14 +163,15 @@ allowrequest(Pump *p)
}
static int
readreply(struct ct *t, Testclient *client, int want, char *preedit)
readreply(struct ct *t, Testclient *client, int want, char *wantcommit,
char *preedit)
{
char commit[Ipcfieldmax+1];
Ipcresp resp;
if(ipcreadresp(client->peer, want, commit, preedit, &resp) < 0)
return CT_ERRORF(t, "response read failed: %s", strerror(errno));
CT_EQ_STR(t, "", commit);
CT_EQ_STR(t, wantcommit, commit);
return resp.eaten;
}
@@ -257,14 +258,14 @@ server_connection_ownership(struct ct *t)
req = nextrequest(t, &f.pump, Keypress);
aowner = req.owner;
allowrequest(&f.pump);
CT_CHECK(t, readreply(t, &a, 1, preedit));
CT_CHECK(t, readreply(t, &a, 1, "", preedit));
CT_EQ_STR(t, "k", preedit);
if(!sendkey(t, &a, 1, 0, 'a'))
goto cleanup;
req = nextrequest(t, &f.pump, Keypress);
CT_EQ_PTR(t, aowner, req.owner);
allowrequest(&f.pump);
CT_CHECK(t, readreply(t, &a, 1, preedit));
CT_CHECK(t, readreply(t, &a, 1, "", preedit));
CT_EQ_STR(t, "", preedit);
CT_EQ_PTR(t, aowner, testengineowner());
@@ -274,7 +275,7 @@ server_connection_ownership(struct ct *t)
bowner = req.owner;
CT_CHECK(t, bowner != aowner);
allowrequest(&f.pump);
CT_CHECK(t, readreply(t, &b, 1, preedit));
CT_CHECK(t, readreply(t, &b, 1, "", preedit));
CT_EQ_STR(t, "", preedit);
CT_EQ_PTR(t, bowner, testengineowner());
@@ -283,14 +284,14 @@ server_connection_ownership(struct ct *t)
req = nextrequest(t, &f.pump, Keyreset);
CT_EQ_PTR(t, aowner, req.owner);
allowrequest(&f.pump);
CT_CHECK(t, readreply(t, &a, 1, preedit));
CT_CHECK(t, readreply(t, &a, 1, "", preedit));
CT_EQ_STR(t, "", preedit);
CT_EQ_PTR(t, bowner, testengineowner());
if(!sendkey(t, &b, 1, 0, Kmodfirst))
goto cleanup;
req = nextrequest(t, &f.pump, Keypress);
allowrequest(&f.pump);
CT_CHECK(t, !readreply(t, &b, 1, preedit));
CT_CHECK(t, !readreply(t, &b, 1, "", preedit));
CT_EQ_STR(t, "", preedit);
disconnectclient(t, &f.pump, &a, aowner);
@@ -299,12 +300,12 @@ server_connection_ownership(struct ct *t)
goto cleanup;
req = nextrequest(t, &f.pump, Keypress);
allowrequest(&f.pump);
CT_CHECK(t, readreply(t, &b, 1, preedit));
CT_CHECK(t, readreply(t, &b, 1, "", preedit));
if(!sendkey(t, &b, 1, 0, 'a'))
goto cleanup;
req = nextrequest(t, &f.pump, Keypress);
allowrequest(&f.pump);
CT_CHECK(t, readreply(t, &b, 1, preedit));
CT_CHECK(t, readreply(t, &b, 1, "", preedit));
CT_EQ_STR(t, "にゃ", preedit);
if(!sendreset(t, &b, 1))
@@ -312,7 +313,7 @@ server_connection_ownership(struct ct *t)
req = nextrequest(t, &f.pump, Keyreset);
CT_EQ_PTR(t, bowner, req.owner);
allowrequest(&f.pump);
CT_CHECK(t, readreply(t, &b, 1, preedit));
CT_CHECK(t, readreply(t, &b, 1, "にゃ", preedit));
CT_EQ_STR(t, "", preedit);
CT_EQ_PTR(t, bowner, testengineowner());
@@ -321,7 +322,7 @@ server_connection_ownership(struct ct *t)
req = nextrequestcap(t, &f.pump, Keypress, 0);
CT_EQ_PTR(t, bowner, req.owner);
allowrequest(&f.pump);
CT_CHECK(t, readreply(t, &b, 0, preedit));
CT_CHECK(t, readreply(t, &b, 0, "", preedit));
errno = 0;
n = recv(b.peer, &byte, 1, MSG_PEEK|MSG_DONTWAIT);
CT_EQ_INT(t, -1, n);
@@ -331,7 +332,7 @@ server_connection_ownership(struct ct *t)
goto cleanup;
req = nextrequest(t, &f.pump, Keypress);
allowrequest(&f.pump);
CT_CHECK(t, readreply(t, &b, 1, preedit));
CT_CHECK(t, readreply(t, &b, 1, "", preedit));
CT_EQ_STR(t, "", preedit);
disconnectclient(t, &f.pump, &b, bowner);
@@ -393,7 +394,7 @@ server_extension_stream(struct ct *t)
aowner = req.owner;
CT_EQ_PTR(t, nil, testengineowner());
allowrequest(&f.pump);
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
CT_EQ_INT(t, 1, readreply(t, &a, 1, "", preedit));
CT_EQ_STR(t, "", preedit);
ipcpackcaret(frame, 1, -101, -7, 23);
@@ -419,7 +420,7 @@ server_extension_stream(struct ct *t)
CT_EQ_INT(t, -7, req.caret.y);
CT_EQ_INT(t, 23, req.caret.h);
allowrequest(&f.pump);
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
CT_EQ_INT(t, 1, readreply(t, &a, 1, "", preedit));
CT_EQ_STR(t, "k", preedit);
CT_EQ_PTR(t, aowner, testengineowner());
@@ -430,7 +431,7 @@ server_extension_stream(struct ct *t)
CT_EQ_PTR(t, aowner, req.owner);
CT_EQ_INT(t, 1, req.caret.valid);
allowrequest(&f.pump);
CT_EQ_INT(t, 1, readreply(t, &a, 0, preedit));
CT_EQ_INT(t, 1, readreply(t, &a, 0, "", preedit));
/* Reset is still the old six-byte frame and does not discard caret. */
ipcpackreset(frame, 0);
@@ -443,14 +444,14 @@ server_extension_stream(struct ct *t)
CT_EQ_INT(t, -7, req.caret.y);
CT_EQ_INT(t, 23, req.caret.h);
allowrequest(&f.pump);
CT_EQ_INT(t, 1, readreply(t, &a, 0, preedit));
CT_EQ_INT(t, 1, readreply(t, &a, 0, "k", preedit));
ipcpackcap(frame, Cclientpreedit);
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
goto cleanup;
req = nextrequest(t, &f.pump, Keycap);
allowrequest(&f.pump);
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
CT_EQ_INT(t, 1, readreply(t, &a, 1, "", preedit));
CT_EQ_STR(t, "", preedit);
ipcpackreq(frame, 1, 0, 'n');
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
@@ -459,7 +460,7 @@ server_extension_stream(struct ct *t)
CT_EQ_INT(t, 1, req.caret.valid);
CT_EQ_INT(t, -101, req.caret.x);
allowrequest(&f.pump);
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
CT_EQ_INT(t, 1, readreply(t, &a, 1, "", preedit));
CT_EQ_STR(t, "", preedit);
disconnectclient(t, &f.pump, &a, aowner);
@@ -471,7 +472,7 @@ server_extension_stream(struct ct *t)
bowner = req.owner;
CT_EQ_INT(t, 0, req.caret.valid);
allowrequest(&f.pump);
CT_EQ_INT(t, 1, readreply(t, &b, 1, preedit));
CT_EQ_INT(t, 1, readreply(t, &b, 1, "", preedit));
CT_EQ_STR(t, "k", preedit);
disconnectclient(t, &f.pump, &b, bowner);
@@ -532,7 +533,7 @@ server_rejects_unknown_extension(struct ct *t)
req = nextrequest(t, &f.pump, Keypress);
owner = req.owner;
allowrequest(&f.pump);
CT_EQ_INT(t, 1, readreply(t, &good, 1, preedit));
CT_EQ_INT(t, 1, readreply(t, &good, 1, "", preedit));
CT_EQ_STR(t, "k", preedit);
disconnectclient(t, &f.pump, &good, owner);