xim: clear callback preedit on owner loss

This commit is contained in:
2026-08-14 19:17:37 +09:00
parent 76f9e1a21f
commit 2e6d7d8e48
6 changed files with 237 additions and 15 deletions

View File

@@ -659,7 +659,7 @@ xim_adapter_placement(struct ct *t)
{XCB_IM_PreeditPosition | XCB_IM_StatusNothing,
XCB_XIM_XNSpotLocation_MASK, 1, 1, 1, 1, 1, 103, 204},
{XCB_IM_PreeditPosition | XCB_IM_StatusNothing,
XCB_XIM_XNSpotLocation_MASK, 1, 0, 1, 1, 1, 303, 404},
XCB_XIM_XNSpotLocation_MASK, 1, 0, 1, 1, 1, 300, 440},
{XCB_IM_PreeditPosition | XCB_IM_StatusNothing,
0, 1, 1, 1, 1, 1, 100, 230},
{XCB_IM_PreeditNothing | XCB_IM_StatusNothing,
@@ -1022,6 +1022,110 @@ cleanup:
ximend(&f);
}
void
xim_adapter_callback_owner_loss(struct ct *t)
{
Ximfix f;
Ic state;
xcb_im_input_context_t *ic;
xcb_im_packet_header_fr_t hdr;
Keyreq req;
Keyreq trace;
Keyres res;
uchar token;
int foreign, i, n;
ic = (xcb_im_input_context_t*)(uintptr)51;
memset(&state, 0, sizeof state);
foreign = 0;
if(!ximbegin(t, &f, LangJP))
goto cleanup;
if(!CT_CHECK(t, wakeinit() == 0))
goto cleanup;
wakedrain();
wireclear();
wirebind(0, ic, &state);
state.xic = ic;
state.style = XCB_IM_PreeditCallbacks | XCB_IM_StatusNothing;
state.cap = Cclientpreedit;
state.encoding = Eutf8;
keypress(&state, 'k', 0, &res);
nexttrace(t, &f, Keypress, &state);
updatepreedit(&state, &res.preedit);
CT_EQ_INT(t, Wstart, wirecalls[0].op);
CT_EQ_INT(t, Wdraw, wirecalls[1].op);
CT_EQ_PTR(t, &state, preowner);
checkownerwake();
nexttrace(t, &f, Keycap, &state);
CT_EQ_PTR(t, &state, preowner);
memset(&req, 0, sizeof req);
req.owner = &foreign;
req.op = Keypress;
req.ks = 'n';
req.reply = replyc;
chansend(keyc, &req);
chanrecv(replyc, &res);
memset(&trace, 0, sizeof trace);
CT_CHECK(t, channbrecv(f.trace, &trace) > 0);
CT_EQ_INT(t, Keypress, trace.op);
CT_EQ_PTR(t, &foreign, trace.owner);
CT_EQ_PTR(t, &foreign, testengineowner());
/* A full pipe cannot block imthread; all bytes coalesce into one probe. */
token = 0;
for(i = 0; i < 1<<20; i++){
n = write(wakefd[1], &token, 1);
if(n < 0 && errno == EINTR){
i--;
continue;
}
if(n < 0)
break;
}
CT_CHECK(t, i < 1<<20);
CT_CHECK(t, errno == EAGAIN || errno == EWOULDBLOCK);
ximownernotify();
CT_CHECK(t, wakedrain() > 0);
checkpreowner();
nexttrace(t, &f, Keycap, &state);
CT_EQ_PTR(t, &foreign, testengineowner());
CT_EQ_INT(t, 4, nwirecalls);
CT_EQ_INT(t, Wdraw, wirecalls[2].op);
CT_EQ_UINT(t, 1, wirecalls[2].changed);
CT_EQ_INT(t, Wdone, wirecalls[3].op);
CT_CHECK(t, !state.prestarted);
CT_EQ_PTR(t, nil, preowner);
/* Late XIM lifecycle messages remain idempotent after owner cleanup. */
release(&state);
nexttrace(t, &f, Keyrelease, &state);
release(&state);
notrace(t, &f);
memset(&hdr, 0, sizeof hdr);
hdr.major_opcode = XCB_XIM_RESET_IC;
callback(nil, nil, ic, &hdr, nil, nil, nil);
notrace(t, &f);
hdr.major_opcode = XCB_XIM_DESTROY_IC;
callback(nil, nil, ic, &hdr, nil, nil, nil);
notrace(t, &f);
CT_EQ_INT(t, 4, nwirecalls);
memset(&req, 0, sizeof req);
req.owner = &foreign;
req.op = Keyrelease;
req.reply = replyc;
chansend(keyc, &req);
chanrecv(replyc, &res);
memset(&trace, 0, sizeof trace);
CT_CHECK(t, channbrecv(f.trace, &trace) > 0);
CT_EQ_INT(t, Keyrelease, trace.op);
CT_EQ_PTR(t, &foreign, trace.owner);
wakedrain();
cleanup:
preowner = nil;
ximend(&f);
}
void
xim_adapter_commit_encoding(struct ct *t)
{