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"
|
#include "fn.h"
|
||||||
|
|
||||||
static Im im;
|
static Im im;
|
||||||
static int visible = 0;
|
|
||||||
static void *activeowner;
|
static void *activeowner;
|
||||||
static int activecap;
|
static int activecap;
|
||||||
static Caret caret;
|
static Caret caret;
|
||||||
static int candidatechosen;
|
static int candidatechosen;
|
||||||
|
static Drawcmd lastdraw;
|
||||||
static Emit transjp(Im*, Rune);
|
static Emit transjp(Im*, Rune);
|
||||||
static void backjp(Im*);
|
static void backjp(Im*);
|
||||||
static int maplookup(Trie*, Str*, Str*);
|
static int maplookup(Trie*, Str*, Str*);
|
||||||
@@ -167,18 +167,48 @@ snapshot(Drawcmd *dc)
|
|||||||
dc->kouho[i] = im.kouho[first + i];
|
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
|
static void
|
||||||
redraw(void)
|
redraw(void)
|
||||||
{
|
{
|
||||||
static Drawcmd old;
|
Drawcmd dc, junk;
|
||||||
Drawcmd dc;
|
|
||||||
|
|
||||||
snapshot(&dc);
|
snapshot(&dc);
|
||||||
if(dc.pre.n == 0 && dc.nkouho == 0 && !visible)
|
if(samedraw(&dc, &lastdraw))
|
||||||
return;
|
return;
|
||||||
visible = dc.pre.n != 0 || dc.nkouho != 0;
|
lastdraw = dc;
|
||||||
/* imthread is the sole producer; keep only the newest pending draw. */
|
/* imthread is the sole producer; keep only the newest pending draw. */
|
||||||
while(channbrecv(drawc, &old) > 0)
|
while(channbrecv(drawc, &junk) > 0)
|
||||||
;
|
;
|
||||||
channbsend(drawc, &dc);
|
channbsend(drawc, &dc);
|
||||||
}
|
}
|
||||||
@@ -744,63 +774,6 @@ transition(u32int ks, u32int mod, Str *com)
|
|||||||
return n;
|
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
|
static void
|
||||||
init(void)
|
init(void)
|
||||||
{
|
{
|
||||||
@@ -812,7 +785,7 @@ init(void)
|
|||||||
activeowner = nil;
|
activeowner = nil;
|
||||||
activecap = 0;
|
activecap = 0;
|
||||||
candidatechosen = 0;
|
candidatechosen = 0;
|
||||||
visible = 0;
|
memset(&lastdraw, 0, sizeof lastdraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -821,30 +794,16 @@ meaningful(Keyreq *kr)
|
|||||||
return kr->ks != 0 && !ismodkey(kr->ks);
|
return kr->ks != 0 && !ismodkey(kr->ks);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/*
|
||||||
setactivecap(int cap)
|
* The engine belongs to whichever context last typed a real key; only
|
||||||
{
|
* the owner's requests change state. Every request ends in redraw(),
|
||||||
int old;
|
* which sends the popup a picture only if something visible changed.
|
||||||
|
*/
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
imhandlekey(Keyreq *kr)
|
imhandlekey(Keyreq *kr)
|
||||||
{
|
{
|
||||||
Keyres res;
|
Keyres res;
|
||||||
void *oldowner;
|
void *oldowner;
|
||||||
int changed;
|
|
||||||
|
|
||||||
oldowner = activeowner;
|
oldowner = activeowner;
|
||||||
sclear(&res.commit);
|
sclear(&res.commit);
|
||||||
@@ -856,57 +815,38 @@ imhandlekey(Keyreq *kr)
|
|||||||
reset();
|
reset();
|
||||||
activeowner = nil;
|
activeowner = nil;
|
||||||
activecap = 0;
|
activecap = 0;
|
||||||
redraw();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Keyreset:
|
case Keyreset:
|
||||||
if(kr->owner == activeowner){
|
if(kr->owner == activeowner)
|
||||||
reset();
|
reset();
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Keycaret:
|
case Keycaret:
|
||||||
if(kr->owner == activeowner && !careteq(&caret, &kr->caret)){
|
if(kr->owner == activeowner)
|
||||||
caret = kr->caret;
|
caret = kr->caret;
|
||||||
if(visible)
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Keycap:
|
case Keycap:
|
||||||
res.eaten = 0;
|
res.eaten = activeowner != nil && kr->owner == activeowner;
|
||||||
if(activeowner != nil && kr->owner == activeowner){
|
if(res.eaten)
|
||||||
res.eaten = 1;
|
activecap = kr->cap & Cclientpreedit;
|
||||||
if(setactivecap(kr->cap))
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Keypress:
|
case Keypress:
|
||||||
res.eaten = 0;
|
res.eaten = 0;
|
||||||
changed = 0;
|
if(activeowner != nil && kr->owner == activeowner)
|
||||||
if(activeowner != nil && kr->owner == activeowner &&
|
activecap = kr->cap & Cclientpreedit;
|
||||||
setactivecap(kr->cap))
|
|
||||||
changed = 1;
|
|
||||||
if(meaningful(kr)){
|
if(meaningful(kr)){
|
||||||
if(kr->owner != activeowner){
|
if(kr->owner != activeowner){
|
||||||
reset();
|
reset();
|
||||||
activeowner = kr->owner;
|
activeowner = kr->owner;
|
||||||
activecap = kr->cap & Cclientpreedit;
|
activecap = kr->cap & Cclientpreedit;
|
||||||
caret = kr->caret;
|
caret = kr->caret;
|
||||||
changed = 1;
|
}else if(kr->caret.valid)
|
||||||
}else if(kr->caret.valid &&
|
|
||||||
!careteq(&caret, &kr->caret)){
|
|
||||||
caret = kr->caret;
|
caret = kr->caret;
|
||||||
changed = 1;
|
res.eaten = transition(kr->ks, kr->mod, &res.commit);
|
||||||
}
|
}
|
||||||
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();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
redraw();
|
||||||
if(activeowner != oldowner)
|
if(activeowner != oldowner)
|
||||||
ximownernotify();
|
ximownernotify();
|
||||||
if(kr->owner == activeowner){
|
if(kr->owner == activeowner){
|
||||||
|
|||||||
@@ -10,6 +10,17 @@ Str shownpre(Im*);
|
|||||||
static int typekeys(struct ct*, char*, Str*);
|
static int typekeys(struct ct*, char*, Str*);
|
||||||
static int draindraw(Drawcmd*);
|
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
|
void
|
||||||
testengineinit(int lang)
|
testengineinit(int lang)
|
||||||
{
|
{
|
||||||
@@ -675,7 +686,7 @@ struct Searchfix
|
|||||||
Lang *dictlang;
|
Lang *dictlang;
|
||||||
Trie *dict;
|
Trie *dict;
|
||||||
int activecap;
|
int activecap;
|
||||||
int visible;
|
Drawcmd lastdraw;
|
||||||
int candidatechosen;
|
int candidatechosen;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -893,7 +904,7 @@ searchsave(Searchfix *f, int lang)
|
|||||||
f->dictlang = getlang(lang);
|
f->dictlang = getlang(lang);
|
||||||
f->dict = f->dictlang->dict;
|
f->dict = f->dictlang->dict;
|
||||||
f->activecap = activecap;
|
f->activecap = activecap;
|
||||||
f->visible = visible;
|
f->lastdraw = lastdraw;
|
||||||
f->candidatechosen = candidatechosen;
|
f->candidatechosen = candidatechosen;
|
||||||
draindraw(nil);
|
draindraw(nil);
|
||||||
}
|
}
|
||||||
@@ -936,7 +947,7 @@ searchend(Searchfix *f)
|
|||||||
im = f->im;
|
im = f->im;
|
||||||
search = f->search;
|
search = f->search;
|
||||||
activecap = f->activecap;
|
activecap = f->activecap;
|
||||||
visible = f->visible;
|
lastdraw = f->lastdraw;
|
||||||
candidatechosen = f->candidatechosen;
|
candidatechosen = f->candidatechosen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user