engine: redraw when the picture changes, not when the state might have
Every key copied the whole Im and Search rune by rune, compared them after the transition, and combined the answer with 'eaten', a commit count that is always zero, and a force flag for caret and owner changes, while redraw() kept a separate 'visible' bit to know when to send an empty popup. redraw() now compares the snapshot with the last one sent and treats two empty popups as equal, so imhandlekey just ends in redraw(). keystroke() was only a test entry point and moves there.
This commit is contained in:
166
strans.c
166
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){
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user