cleanup: simplify frontend request ownership

This commit is contained in:
2026-08-13 21:57:32 +09:00
parent 13f0b436b8
commit b6a9ccd9d9
9 changed files with 74 additions and 79 deletions

3
dat.h
View File

@@ -154,12 +154,11 @@ struct Keyres
struct Keyreq struct Keyreq
{ {
uvlong owner; void *owner; /* stable until the context's release is acknowledged */
int op; int op;
u32int ks; u32int ks;
u32int mod; u32int mod;
Caret caret; Caret caret;
int want; /* nonzero: include preedit in reply */
Channel *reply; Channel *reply;
}; };

2
fn.h
View File

@@ -36,8 +36,6 @@ Emit transko(Im*, Rune);
Emit transvi(Im*, Rune); Emit transvi(Im*, Rune);
void backko(Im*); void backko(Im*);
void backvi(Im*); void backvi(Im*);
void dictsend(Im*, Str*);
uvlong ownernew(void);
void srvthread(void*); void srvthread(void*);
void ibusthread(void*); void ibusthread(void*);

5
ibus.c
View File

@@ -30,7 +30,6 @@ struct Ictx
{ {
DBusConnection *conn; DBusConnection *conn;
char path[64]; char path[64];
uvlong owner;
int focused; int focused;
Caret caret; Caret caret;
}; };
@@ -282,7 +281,6 @@ newcontext(DBusConnection *conn, const char *path)
if(contexts[i].conn == nil){ if(contexts[i].conn == nil){
memset(&contexts[i], 0, sizeof contexts[i]); memset(&contexts[i], 0, sizeof contexts[i]);
contexts[i].conn = conn; contexts[i].conn = conn;
contexts[i].owner = ownernew();
strncpy(contexts[i].path, path, sizeof contexts[i].path); strncpy(contexts[i].path, path, sizeof contexts[i].path);
contexts[i].path[sizeof contexts[i].path-1] = '\0'; contexts[i].path[sizeof contexts[i].path-1] = '\0';
return &contexts[i]; return &contexts[i];
@@ -296,12 +294,11 @@ sendrequest(Ictx *ctx, int op, u32int ks, u32int mod, Keyres *res)
Keyreq kr; Keyreq kr;
memset(&kr, 0, sizeof kr); memset(&kr, 0, sizeof kr);
kr.owner = ctx->owner; kr.owner = ctx;
kr.op = op; kr.op = op;
kr.ks = ks; kr.ks = ks;
kr.mod = mod; kr.mod = mod;
kr.caret = ctx->caret; kr.caret = ctx->caret;
kr.want = op == Keypress;
kr.reply = replyc; kr.reply = replyc;
chansend(keyc, &kr); chansend(keyc, &kr);
chanrecv(replyc, res); chanrecv(replyc, res);

4
ipc.h
View File

@@ -4,8 +4,8 @@
/* /*
* Request: [flags, modifiers, key byte 0, ..., key byte 3]. * Request: [flags, modifiers, key byte 0, ..., key byte 3].
* Flags request preedit and distinguish lifecycle reset from physical Escape. * Flags request preedit and distinguish lifecycle reset from physical Escape.
* The server assigns the connection's owner generation; it is not sent on * The server identifies the connection as the engine owner; that identity is
* the wire. * not sent on the wire.
* Only Mmask modifier bits are retained. * Only Mmask modifier bits are retained.
* Response: [eaten, commit-length-low, commit-length-high, commit...], * Response: [eaten, commit-length-low, commit-length-high, commit...],
* followed, when requested, by * followed, when requested, by

14
srv.c
View File

@@ -11,7 +11,6 @@ typedef struct Client Client;
struct Client struct Client
{ {
int fd; int fd;
uvlong owner;
}; };
static int static int
@@ -27,9 +26,8 @@ srvreadkey(int fd, Keyreq *kr)
kr->op = ipcreqreset(req) ? Keyreset : Keypress; kr->op = ipcreqreset(req) ? Keyreset : Keypress;
kr->ks = ks; kr->ks = ks;
kr->mod = mod; kr->mod = mod;
kr->want = want;
memset(&kr->caret, 0, sizeof kr->caret); memset(&kr->caret, 0, sizeof kr->caret);
return 0; return want;
} }
static void static void
@@ -42,7 +40,7 @@ clientthread(void *arg)
Keyres res; Keyres res;
uchar out[Ipcmaxresp]; uchar out[Ipcmaxresp];
char commit[Maxutf], preedit[Maxutf]; char commit[Maxutf], preedit[Maxutf];
int n, ncommit, npreedit; int n, ncommit, npreedit, want;
uchar token; uchar token;
client = arg; client = arg;
@@ -50,19 +48,18 @@ clientthread(void *arg)
threadsetname("client %d", fd); threadsetname("client %d", fd);
reply = chancreate(sizeof(Keyres), 0); reply = chancreate(sizeof(Keyres), 0);
kr.reply = reply; kr.reply = reply;
kr.owner = client->owner; kr.owner = client;
while(srvreadkey(fd, &kr) == 0){ while((want = srvreadkey(fd, &kr)) >= 0){
chansend(keyc, &kr); chansend(keyc, &kr);
chanrecv(reply, &res); chanrecv(reply, &res);
ncommit = stoutf(&res.commit, commit, sizeof commit); ncommit = stoutf(&res.commit, commit, sizeof commit);
npreedit = stoutf(&res.preedit, preedit, sizeof preedit); npreedit = stoutf(&res.preedit, preedit, sizeof preedit);
n = ipcpackresp(out, sizeof out, res.eaten, n = ipcpackresp(out, sizeof out, res.eaten,
commit, ncommit, preedit, npreedit, kr.want); commit, ncommit, preedit, npreedit, want);
if(n < 0 || ipcsend(fd, out, n) < 0) if(n < 0 || ipcsend(fd, out, n) < 0)
break; break;
} }
kr.op = Keyrelease; kr.op = Keyrelease;
kr.want = 0;
chansend(keyc, &kr); chansend(keyc, &kr);
chanrecv(reply, &res); chanrecv(reply, &res);
chanfree(reply); chanfree(reply);
@@ -110,7 +107,6 @@ srvthread(void*)
} }
client = emalloc(sizeof *client); client = emalloc(sizeof *client);
client->fd = fd; client->fd = fd;
client->owner = ownernew();
if(proccreate(clientthread, client, 8192) < 0){ if(proccreate(clientthread, client, 8192) < 0){
chanrecv(clientc, &token); chanrecv(clientc, &token);
close(fd); close(fd);

View File

@@ -4,9 +4,7 @@
static Im im; static Im im;
static int popup = 0; static int popup = 0;
static int visible = 0; static int visible = 0;
static Lock ownerlock; static void *activeowner;
static uvlong ownerctr;
static uvlong activeowner;
static Caret caret; static Caret caret;
static void dictqmap(Im*); static void dictqmap(Im*);
static void dictqjp(Im*); static void dictqjp(Im*);
@@ -22,19 +20,6 @@ struct Search
}; };
static Search search; static Search search;
uvlong
ownernew(void)
{
uvlong n;
lock(&ownerlock);
n = ++ownerctr;
if(n == 0)
n = ++ownerctr;
unlock(&ownerlock);
return n;
}
Lang langs[] = { Lang langs[] = {
{LangEN, nil, nil, nil, nil, nil, nil, nil}, {LangEN, nil, nil, nil, nil, nil, nil, nil},
{LangJP, "hira", "kanji", transmap, backjp, dictqjp, nil, nil}, {LangJP, "hira", "kanji", transmap, backjp, dictqjp, nil, nil},
@@ -155,7 +140,7 @@ reset(void)
show(); show();
} }
void static void
dictsend(Im *im, Str *key) dictsend(Im *im, Str *key)
{ {
Dictreq old, req; Dictreq old, req;
@@ -792,7 +777,7 @@ init(void)
im.l = getlang(LangEN); im.l = getlang(LangEN);
memset(&search, 0, sizeof search); memset(&search, 0, sizeof search);
memset(&caret, 0, sizeof caret); memset(&caret, 0, sizeof caret);
activeowner = 0; activeowner = nil;
visible = 0; visible = 0;
} }
@@ -814,7 +799,7 @@ imhandlekey(Keyreq *kr)
case Keyrelease: case Keyrelease:
if(kr->owner == activeowner){ if(kr->owner == activeowner){
reset(); reset();
activeowner = 0; activeowner = nil;
} }
break; break;
case Keyreset: case Keyreset:
@@ -827,7 +812,7 @@ imhandlekey(Keyreq *kr)
show(); show();
} }
break; break;
default: case Keypress:
res.eaten = 0; res.eaten = 0;
if(meaningful(kr)){ if(meaningful(kr)){
if(kr->owner != activeowner){ if(kr->owner != activeowner){
@@ -840,7 +825,7 @@ imhandlekey(Keyreq *kr)
} }
break; break;
} }
if(kr->want && kr->owner == activeowner){ if(kr->owner == activeowner){
if(search.lang) if(search.lang)
res.preedit = search.text; res.preedit = search.text;
else else

View File

@@ -161,7 +161,7 @@ engine_dictionary_queue_latest_wins(struct ct *t)
} }
static Keyres static Keyres
ownerrequestat(uvlong owner, int op, Rune key, u32int mod, Caret *caret) ownerrequestat(void *owner, int op, Rune key, u32int mod, Caret *caret)
{ {
Channel *reply; Channel *reply;
Keyreq req; Keyreq req;
@@ -175,7 +175,6 @@ ownerrequestat(uvlong owner, int op, Rune key, u32int mod, Caret *caret)
req.mod = mod; req.mod = mod;
if(caret != nil) if(caret != nil)
req.caret = *caret; req.caret = *caret;
req.want = 1;
req.reply = reply; req.reply = reply;
imhandlekey(&req); imhandlekey(&req);
chanrecv(reply, &res); chanrecv(reply, &res);
@@ -184,7 +183,7 @@ ownerrequestat(uvlong owner, int op, Rune key, u32int mod, Caret *caret)
} }
static Keyres static Keyres
ownerrequest(uvlong owner, int op, Rune key, u32int mod) ownerrequest(void *owner, int op, Rune key, u32int mod)
{ {
return ownerrequestat(owner, op, key, mod, nil); return ownerrequestat(owner, op, key, mod, nil);
} }
@@ -194,57 +193,75 @@ engine_active_owner_lifecycle(struct ct *t)
{ {
Keyres res; Keyres res;
Str shown; Str shown;
uvlong a, b, c; char a, b, c;
a = ownernew();
b = ownernew();
c = ownernew();
CT_CHECK(t, a != 0 && b != 0 && c != 0);
CT_CHECK(t, a != b && b != c && a != c);
init(); init();
im.l = getlang(LangJP); im.l = getlang(LangJP);
res = ownerrequest(a, Keypress, 'k', 0); res = ownerrequest(&a, Keypress, 'k', 0);
CT_CHECK(t, res.eaten); CT_CHECK(t, res.eaten);
res = ownerrequest(a, Keypress, 'a', 0); res = ownerrequest(&a, Keypress, 'a', 0);
checkstr(t, "first owner preedit", "", &res.preedit); checkstr(t, "first owner preedit", "", &res.preedit);
CT_EQ_UINT(t, a, activeowner); CT_EQ_PTR(t, &a, activeowner);
res = ownerrequest(b, Keypress, 'n', 0); res = ownerrequest(&b, Keypress, 'n', 0);
checkstr(t, "takeover resets old preedit", "", &res.preedit); checkstr(t, "takeover resets old preedit", "", &res.preedit);
CT_EQ_UINT(t, b, activeowner); CT_EQ_PTR(t, &b, activeowner);
res = ownerrequest(a, Keyreset, 0, 0); res = ownerrequest(&a, Keyreset, 0, 0);
CT_EQ_INT(t, 0, res.preedit.n); CT_EQ_INT(t, 0, res.preedit.n);
shown = shownpre(&im); shown = shownpre(&im);
checkstr(t, "stale reset preserves owner", "", &shown); checkstr(t, "stale reset preserves owner", "", &shown);
CT_EQ_UINT(t, b, activeowner); CT_EQ_PTR(t, &b, activeowner);
res = ownerrequest(b, Keypress, 'y', 0); res = ownerrequest(&b, Keypress, 'y', 0);
res = ownerrequest(b, Keypress, 'a', 0); res = ownerrequest(&b, Keypress, 'a', 0);
checkstr(t, "current owner continues", "にゃ", &res.preedit); checkstr(t, "current owner continues", "にゃ", &res.preedit);
ownerrequest(a, Keyrelease, 0, 0); ownerrequest(&a, Keyrelease, 0, 0);
shown = shownpre(&im); shown = shownpre(&im);
checkstr(t, "stale release preserves owner", "にゃ", &shown); checkstr(t, "stale release preserves owner", "にゃ", &shown);
CT_EQ_UINT(t, b, activeowner); CT_EQ_PTR(t, &b, activeowner);
ownerrequest(b, Keyrelease, 0, 0); ownerrequest(&b, Keyrelease, 0, 0);
CT_EQ_UINT(t, 0, activeowner); CT_EQ_PTR(t, nil, activeowner);
CT_EQ_INT(t, 0, im.pre.n); CT_EQ_INT(t, 0, im.pre.n);
CT_EQ_INT(t, 0, im.raw.n); CT_EQ_INT(t, 0, im.raw.n);
ownerrequest(c, Keypress, Kmodfirst, 0); ownerrequest(&c, Keypress, Kmodfirst, 0);
CT_EQ_UINT(t, 0, activeowner); CT_EQ_PTR(t, nil, activeowner);
res = ownerrequest(c, Keypress, 'k', 0); res = ownerrequest(&c, Keypress, 'k', 0);
CT_EQ_UINT(t, c, activeowner); CT_EQ_PTR(t, &c, activeowner);
checkstr(t, "next owner first key", "k", &res.preedit); checkstr(t, "next owner first key", "k", &res.preedit);
} }
void
engine_active_owner_reset(struct ct *t)
{
Caret at;
Keyres res;
char owner;
memset(&at, 0, sizeof at);
at.valid = 1;
at.x = 10;
at.y = 20;
at.h = 14;
init();
im.l = getlang(LangJP);
ownerrequestat(&owner, Keypress, 'k', 0, &at);
res = ownerrequest(&owner, Keypress, 'a', 0);
checkstr(t, "preedit before reset", "", &res.preedit);
res = ownerrequest(&owner, Keyreset, 0, 0);
CT_EQ_PTR(t, &owner, activeowner);
CT_EQ_INT(t, 0, res.preedit.n);
CT_CHECK(t, !caret.valid);
res = ownerrequest(&owner, Keypress, 'n', 0);
checkstr(t, "same owner after reset", "", &res.preedit);
}
void void
engine_active_owner_caret(struct ct *t) engine_active_owner_caret(struct ct *t)
{ {
Caret a, moved; Caret a, moved;
uvlong one, two; char one, two;
one = ownernew();
two = ownernew();
memset(&a, 0, sizeof a); memset(&a, 0, sizeof a);
a.valid = 1; a.valid = 1;
a.x = 10; a.x = 10;
@@ -254,15 +271,15 @@ engine_active_owner_caret(struct ct *t)
moved.x = 80; moved.x = 80;
init(); init();
im.l = getlang(LangJP); im.l = getlang(LangJP);
ownerrequestat(one, Keypress, 'k', 0, &a); ownerrequestat(&one, Keypress, 'k', 0, &a);
CT_CHECK(t, caret.valid); CT_CHECK(t, caret.valid);
CT_EQ_INT(t, 10, caret.x); CT_EQ_INT(t, 10, caret.x);
ownerrequestat(two, Keycaret, 0, 0, &moved); ownerrequestat(&two, Keycaret, 0, 0, &moved);
CT_EQ_INT(t, 10, caret.x); CT_EQ_INT(t, 10, caret.x);
ownerrequestat(one, Keycaret, 0, 0, &moved); ownerrequestat(&one, Keycaret, 0, 0, &moved);
CT_EQ_INT(t, 80, caret.x); CT_EQ_INT(t, 80, caret.x);
ownerrequest(two, Keypress, 'n', 0); ownerrequest(&two, Keypress, 'n', 0);
CT_EQ_UINT(t, two, activeowner); CT_EQ_PTR(t, &two, activeowner);
CT_CHECK(t, !caret.valid); CT_CHECK(t, !caret.valid);
} }
@@ -1430,7 +1447,8 @@ engine_randomized_stress(struct ct *t)
Keyres res; Keyres res;
Caret pos; Caret pos;
u32int rnd, mod; u32int rnd, mod;
uvlong owners[3], owner; char contexts[3];
void *owner, *owners[3];
int i, j, op; int i, j, op;
vi = getlang(LangVI); vi = getlang(LangVI);
@@ -1439,9 +1457,9 @@ engine_randomized_stress(struct ct *t)
vimap = vi->map; vimap = vi->map;
vi->map = testvi.map; vi->map = testvi.map;
emojibegin(&f, 0); emojibegin(&f, 0);
owners[0] = ownernew(); owners[0] = &contexts[0];
owners[1] = ownernew(); owners[1] = &contexts[1];
owners[2] = ownernew(); owners[2] = &contexts[2];
rnd = 0x5eed1234U; rnd = 0x5eed1234U;
for(i = 0; i < 16000; i++){ for(i = 0; i < 16000; i++){
rnd = stressrand(&rnd); rnd = stressrand(&rnd);
@@ -1506,7 +1524,7 @@ engine_randomized_stress(struct ct *t)
i = 16000; i = 16000;
break; break;
} }
if(activeowner != 0 && activeowner != owners[0] && if(activeowner != nil && activeowner != owners[0] &&
activeowner != owners[1] && activeowner != owners[2]){ activeowner != owners[1] && activeowner != owners[2]){
CT_ERRORF(t, "unknown active owner after stress operation %d", i); CT_ERRORF(t, "unknown active owner after stress operation %d", i);
break; break;

View File

@@ -34,6 +34,7 @@ void engine_selects_visible_candidate(struct ct*);
void engine_candidate_shortcut_modifiers(struct ct*); void engine_candidate_shortcut_modifiers(struct ct*);
void engine_dictionary_queue_latest_wins(struct ct*); void engine_dictionary_queue_latest_wins(struct ct*);
void engine_active_owner_lifecycle(struct ct*); void engine_active_owner_lifecycle(struct ct*);
void engine_active_owner_reset(struct ct*);
void engine_active_owner_caret(struct ct*); void engine_active_owner_caret(struct ct*);
void engine_commit_contract(struct ct*); void engine_commit_contract(struct ct*);
void engine_language_switch_state(struct ct*); void engine_language_switch_state(struct ct*);

View File

@@ -88,6 +88,7 @@ static const struct ct_test tests[] = {
{ "engine/candidate-shortcut-modifiers", engine_candidate_shortcut_modifiers }, { "engine/candidate-shortcut-modifiers", engine_candidate_shortcut_modifiers },
{ "engine/dictionary-queue-latest", engine_dictionary_queue_latest_wins }, { "engine/dictionary-queue-latest", engine_dictionary_queue_latest_wins },
{ "engine/active-owner-lifecycle", engine_active_owner_lifecycle }, { "engine/active-owner-lifecycle", engine_active_owner_lifecycle },
{ "engine/active-owner-reset", engine_active_owner_reset },
{ "engine/active-owner-caret", engine_active_owner_caret }, { "engine/active-owner-caret", engine_active_owner_caret },
{ "engine/commit-contract", engine_commit_contract }, { "engine/commit-contract", engine_commit_contract },
{ "engine/language-switch-state", engine_language_switch_state }, { "engine/language-switch-state", engine_language_switch_state },