diff --git a/strans.c b/strans.c index fba78c3..93aace9 100644 --- a/strans.c +++ b/strans.c @@ -2,11 +2,11 @@ #include "fn.h" static Im im; -static int visible = 0; static void *activeowner; static int activecap; static Caret caret; static int candidatechosen; +static Drawcmd lastdraw; static Emit transjp(Im*, Rune); static void backjp(Im*); static int maplookup(Trie*, Str*, Str*); @@ -167,18 +167,48 @@ snapshot(Drawcmd *dc) dc->kouho[i] = im.kouho[first + i]; } +static int +careteq(Caret *a, Caret *b) +{ + return a->valid == b->valid && a->x == b->x && a->y == b->y && + a->h == b->h; +} + +static int +shown(Drawcmd *dc) +{ + return dc->pre.n != 0 || dc->nkouho != 0; +} + +static int +samedraw(Drawcmd *a, Drawcmd *b) +{ + int i; + + if(!shown(a) && !shown(b)) + return 1; + if(a->nkouho != b->nkouho || a->sel != b->sel || + a->first != b->first || a->total != b->total || + scmp(&a->pre, &b->pre) != 0 || !careteq(&a->caret, &b->caret)) + return 0; + for(i = 0; i < a->nkouho; i++) + if(scmp(&a->kouho[i], &b->kouho[i]) != 0) + return 0; + return 1; +} + +/* Sends the popup a new picture only when it would look different. */ static void redraw(void) { - static Drawcmd old; - Drawcmd dc; + Drawcmd dc, junk; snapshot(&dc); - if(dc.pre.n == 0 && dc.nkouho == 0 && !visible) + if(samedraw(&dc, &lastdraw)) return; - visible = dc.pre.n != 0 || dc.nkouho != 0; + lastdraw = dc; /* imthread is the sole producer; keep only the newest pending draw. */ - while(channbrecv(drawc, &old) > 0) + while(channbrecv(drawc, &junk) > 0) ; channbsend(drawc, &dc); } @@ -744,63 +774,6 @@ transition(u32int ks, u32int mod, Str *com) return n; } -static int -samestate(Im *a, Search *as, Im *b, Search *bs) -{ - int i; - - if(a->l != b->l || scmp(&a->pre, &b->pre) != 0 || - scmp(&a->raw, &b->raw) != 0 || a->nkouho != b->nkouho || - a->sel != b->sel || as->lang != bs->lang || - scmp(&as->raw, &bs->raw) != 0 || scmp(&as->text, &bs->text) != 0) - return 0; - for(i = 0; i < a->nkouho; i++) - if(scmp(&a->kouho[i], &b->kouho[i]) != 0) - return 0; - return 1; -} - -static void -savestate(Im *p, Search *s) -{ - int i; - - memset(p, 0, sizeof *p); - memset(s, 0, sizeof *s); - p->l = im.l; - sappend(&p->pre, &im.pre); - sappend(&p->raw, &im.raw); - p->nkouho = im.nkouho; - p->sel = im.sel; - for(i = 0; i < im.nkouho; i++) - sappend(&p->kouho[i], &im.kouho[i]); - s->lang = search.lang; - sappend(&s->raw, &search.raw); - sappend(&s->text, &search.text); -} - -static int -keystrokeforce(u32int ks, u32int mod, Str *com, int force) -{ - Im oldim; - Search oldsearch; - int eaten, ncom; - - savestate(&oldim, &oldsearch); - ncom = com->n; - eaten = transition(ks, mod, com); - if(force || eaten || com->n != ncom || - !samestate(&oldim, &oldsearch, &im, &search)) - redraw(); - return eaten; -} - -static int -keystroke(u32int ks, u32int mod, Str *com) -{ - return keystrokeforce(ks, mod, com, 0); -} - static void init(void) { @@ -812,7 +785,7 @@ init(void) activeowner = nil; activecap = 0; candidatechosen = 0; - visible = 0; + memset(&lastdraw, 0, sizeof lastdraw); } static int @@ -821,30 +794,16 @@ meaningful(Keyreq *kr) return kr->ks != 0 && !ismodkey(kr->ks); } -static int -setactivecap(int cap) -{ - int old; - - old = activecap & Cclientpreedit; - activecap &= ~Cclientpreedit; - activecap |= cap & Cclientpreedit; - return old != (activecap & Cclientpreedit); -} - -static int -careteq(Caret *a, Caret *b) -{ - return a->valid == b->valid && a->x == b->x && a->y == b->y && - a->h == b->h; -} - +/* + * The engine belongs to whichever context last typed a real key; only + * the owner's requests change state. Every request ends in redraw(), + * which sends the popup a picture only if something visible changed. + */ static void imhandlekey(Keyreq *kr) { Keyres res; void *oldowner; - int changed; oldowner = activeowner; sclear(&res.commit); @@ -856,57 +815,38 @@ imhandlekey(Keyreq *kr) reset(); activeowner = nil; activecap = 0; - redraw(); } break; case Keyreset: - if(kr->owner == activeowner){ + if(kr->owner == activeowner) reset(); - redraw(); - } break; case Keycaret: - if(kr->owner == activeowner && !careteq(&caret, &kr->caret)){ + if(kr->owner == activeowner) caret = kr->caret; - if(visible) - redraw(); - } break; case Keycap: - res.eaten = 0; - if(activeowner != nil && kr->owner == activeowner){ - res.eaten = 1; - if(setactivecap(kr->cap)) - redraw(); - } + res.eaten = activeowner != nil && kr->owner == activeowner; + if(res.eaten) + activecap = kr->cap & Cclientpreedit; break; case Keypress: res.eaten = 0; - changed = 0; - if(activeowner != nil && kr->owner == activeowner && - setactivecap(kr->cap)) - changed = 1; + if(activeowner != nil && kr->owner == activeowner) + activecap = kr->cap & Cclientpreedit; if(meaningful(kr)){ if(kr->owner != activeowner){ reset(); activeowner = kr->owner; activecap = kr->cap & Cclientpreedit; caret = kr->caret; - changed = 1; - }else if(kr->caret.valid && - !careteq(&caret, &kr->caret)){ + }else if(kr->caret.valid) caret = kr->caret; - changed = 1; - } - if(changed) - res.eaten = keystrokeforce(kr->ks, kr->mod, - &res.commit, 1); - else - res.eaten = keystroke(kr->ks, kr->mod, &res.commit); - }else if(changed) - redraw(); + res.eaten = transition(kr->ks, kr->mod, &res.commit); + } break; } + redraw(); if(activeowner != oldowner) ximownernotify(); if(kr->owner == activeowner){ diff --git a/tests/engine_test.c b/tests/engine_test.c index 01047d1..25ac438 100644 --- a/tests/engine_test.c +++ b/tests/engine_test.c @@ -10,6 +10,17 @@ Str shownpre(Im*); static int typekeys(struct ct*, char*, Str*); static int draindraw(Drawcmd*); +/* One key from the owner, as imhandlekey drives the engine. */ +static int +keystroke(u32int ks, u32int mod, Str *com) +{ + int eaten; + + eaten = transition(ks, mod, com); + redraw(); + return eaten; +} + void testengineinit(int lang) { @@ -675,7 +686,7 @@ struct Searchfix Lang *dictlang; Trie *dict; int activecap; - int visible; + Drawcmd lastdraw; int candidatechosen; }; @@ -893,7 +904,7 @@ searchsave(Searchfix *f, int lang) f->dictlang = getlang(lang); f->dict = f->dictlang->dict; f->activecap = activecap; - f->visible = visible; + f->lastdraw = lastdraw; f->candidatechosen = candidatechosen; draindraw(nil); } @@ -936,7 +947,7 @@ searchend(Searchfix *f) im = f->im; search = f->search; activecap = f->activecap; - visible = f->visible; + lastdraw = f->lastdraw; candidatechosen = f->candidatechosen; }