engine: a takeover keeps the text it took for the context it took it from
Two applications' focus events cross — ibus-daemon documents the case — so the first key of the new one can arrive before the old one says it lost focus. The engine dropped whatever that context was composing; it now keeps it and hands it back with the reset or release that follows, which every frontend already commits. Normal ordering is unchanged.
This commit is contained in:
23
strans.c
23
strans.c
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
static Im im;
|
static Im im;
|
||||||
static void *activeowner;
|
static void *activeowner;
|
||||||
|
static void *lostowner; /* the context the engine was taken from */
|
||||||
|
static Str lost;
|
||||||
static int clientpre; /* the owner draws its own preedit */
|
static int clientpre; /* the owner draws its own preedit */
|
||||||
static Caret caret;
|
static Caret caret;
|
||||||
static Drawcmd lastdraw;
|
static Drawcmd lastdraw;
|
||||||
@@ -663,6 +665,20 @@ flush(Str *com)
|
|||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Focus can be lost after the next context's keys arrive, so the engine
|
||||||
|
* changes hands with text still pending. The context it was taken from
|
||||||
|
* gets that text back when it is next heard from.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
takelost(void *owner, Str *com)
|
||||||
|
{
|
||||||
|
if(owner != lostowner)
|
||||||
|
return;
|
||||||
|
sappend(com, &lost);
|
||||||
|
lostowner = nil;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A search takes over the keys. Hanja converts the pending syllable, so
|
* A search takes over the keys. Hanja converts the pending syllable, so
|
||||||
* it becomes the query; anything else pending is committed.
|
* it becomes the query; anything else pending is committed.
|
||||||
@@ -881,6 +897,7 @@ init(void)
|
|||||||
memset(&search, 0, sizeof search);
|
memset(&search, 0, sizeof search);
|
||||||
memset(&caret, 0, sizeof caret);
|
memset(&caret, 0, sizeof caret);
|
||||||
activeowner = nil;
|
activeowner = nil;
|
||||||
|
lostowner = nil;
|
||||||
clientpre = 0;
|
clientpre = 0;
|
||||||
memset(&lastdraw, 0, sizeof lastdraw);
|
memset(&lastdraw, 0, sizeof lastdraw);
|
||||||
}
|
}
|
||||||
@@ -902,6 +919,7 @@ imhandlekey(Keyreq *kr)
|
|||||||
res.eaten = 1;
|
res.eaten = 1;
|
||||||
switch(kr->op){
|
switch(kr->op){
|
||||||
case Keyrelease:
|
case Keyrelease:
|
||||||
|
takelost(kr->owner, &res.commit);
|
||||||
if(kr->owner == activeowner){
|
if(kr->owner == activeowner){
|
||||||
flush(&res.commit);
|
flush(&res.commit);
|
||||||
activeowner = nil;
|
activeowner = nil;
|
||||||
@@ -909,6 +927,7 @@ imhandlekey(Keyreq *kr)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Keyreset:
|
case Keyreset:
|
||||||
|
takelost(kr->owner, &res.commit);
|
||||||
if(kr->owner == activeowner)
|
if(kr->owner == activeowner)
|
||||||
flush(&res.commit);
|
flush(&res.commit);
|
||||||
break;
|
break;
|
||||||
@@ -927,7 +946,9 @@ imhandlekey(Keyreq *kr)
|
|||||||
clientpre = kr->clientpre;
|
clientpre = kr->clientpre;
|
||||||
if(keymeaningful(kr->ks)){
|
if(keymeaningful(kr->ks)){
|
||||||
if(kr->owner != activeowner){
|
if(kr->owner != activeowner){
|
||||||
reset();
|
sclear(&lost);
|
||||||
|
flush(&lost);
|
||||||
|
lostowner = lost.n > 0 ? activeowner : nil;
|
||||||
activeowner = kr->owner;
|
activeowner = kr->owner;
|
||||||
clientpre = kr->clientpre;
|
clientpre = kr->clientpre;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,6 +234,7 @@ engine_active_owner_lifecycle(struct ct *t)
|
|||||||
checkstr(t, "takeover resets old preedit", "ん", &res.preedit);
|
checkstr(t, "takeover resets old preedit", "ん", &res.preedit);
|
||||||
CT_EQ_PTR(t, &b, activeowner);
|
CT_EQ_PTR(t, &b, activeowner);
|
||||||
res = ownerrequest(&a, Keyreset, 0, 0);
|
res = ownerrequest(&a, Keyreset, 0, 0);
|
||||||
|
checkstr(t, "the taken owner gets its reading back", "か", &res.commit);
|
||||||
CT_EQ_INT(t, 0, res.preedit.n);
|
CT_EQ_INT(t, 0, res.preedit.n);
|
||||||
impre(&im, &shown);
|
impre(&im, &shown);
|
||||||
checkstr(t, "stale reset preserves owner", "ん", &shown);
|
checkstr(t, "stale reset preserves owner", "ん", &shown);
|
||||||
|
|||||||
@@ -284,7 +284,8 @@ server_connection_ownership(struct ct *t)
|
|||||||
req = nextrequest(t, &f.pump, Keyreset);
|
req = nextrequest(t, &f.pump, Keyreset);
|
||||||
CT_EQ_PTR(t, aowner, req.owner);
|
CT_EQ_PTR(t, aowner, req.owner);
|
||||||
allowrequest(&f.pump);
|
allowrequest(&f.pump);
|
||||||
CT_CHECK(t, readreply(t, &a, 1, "", preedit));
|
/* The reset hands back what the takeover took from this client. */
|
||||||
|
CT_CHECK(t, readreply(t, &a, 1, "か", preedit));
|
||||||
CT_EQ_STR(t, "", preedit);
|
CT_EQ_STR(t, "", preedit);
|
||||||
CT_EQ_PTR(t, bowner, testengineowner());
|
CT_EQ_PTR(t, bowner, testengineowner());
|
||||||
if(!sendkey(t, &b, 1, 0, 0))
|
if(!sendkey(t, &b, 1, 0, 0))
|
||||||
|
|||||||
@@ -1059,9 +1059,12 @@ xim_adapter_callback_owner_loss(struct ct *t)
|
|||||||
checkpreowner();
|
checkpreowner();
|
||||||
notrace(t, &f);
|
notrace(t, &f);
|
||||||
|
|
||||||
/* Late XIM lifecycle messages remain idempotent after owner cleanup. */
|
/* The release hands back the reading the takeover took. */
|
||||||
release(&state);
|
release(&state);
|
||||||
nexttrace(t, &f, Keyrelease, &state);
|
nexttrace(t, &f, Keyrelease, &state);
|
||||||
|
CT_EQ_INT(t, 5, nwirecalls);
|
||||||
|
CT_EQ_INT(t, Wcommit, wirecalls[4].op);
|
||||||
|
/* Late XIM lifecycle messages remain idempotent after owner cleanup. */
|
||||||
release(&state);
|
release(&state);
|
||||||
notrace(t, &f);
|
notrace(t, &f);
|
||||||
memset(&hdr, 0, sizeof hdr);
|
memset(&hdr, 0, sizeof hdr);
|
||||||
@@ -1071,7 +1074,7 @@ xim_adapter_callback_owner_loss(struct ct *t)
|
|||||||
hdr.major_opcode = XCB_XIM_DESTROY_IC;
|
hdr.major_opcode = XCB_XIM_DESTROY_IC;
|
||||||
callback(nil, nil, ic, &hdr, nil, nil, nil);
|
callback(nil, nil, ic, &hdr, nil, nil, nil);
|
||||||
notrace(t, &f);
|
notrace(t, &f);
|
||||||
CT_EQ_INT(t, 4, nwirecalls);
|
CT_EQ_INT(t, 5, nwirecalls);
|
||||||
|
|
||||||
memset(&req, 0, sizeof req);
|
memset(&req, 0, sizeof req);
|
||||||
req.owner = &foreign;
|
req.owner = &foreign;
|
||||||
|
|||||||
Reference in New Issue
Block a user