ref: 74df3901c04f70c1ba89e71b78dee9dc2882e116
dir: /src/optshow.c/
/* optshow
*******************************************************************************
* Author: Ethan Long
* Licence: Public Domain
* Email: ethandavidlong@gmail.com, u7281759@anu.edu.au
* Description: optshow is a program for overlaying the convertion options for a
* IME over the input, it should work with existing IMEs like
* ktrans, but also for nIME's core.
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <cursor.h>
#include <mouse.h>
#include <keyboard.h>
#include <frame.h>
#include <bio.h>
void clockproc(void*);
void optdraw(Image*, Image*, Point, Rune*);
void readinproc(void*);
void resize(Point);
void usage(void);
enum
{
STACK = 2048,
};
Channel *timer;
Biobuf bin, bout;
void
usage(void)
{
fprint(2, "usage: %s [-s]\n", argv0);
}
void
threadmain(int argc, char *argv[])
{
ulong bgco, textco;
Image *bg, *text;
Mousectl *mctl;
Mouse mouse;
Point textpos;
int disp;
Rune *buf;
Rune input[64];
int clock;
bgco = 0xFFFFFFFF;
textco = 0x000000FF;
char *f;
ARGBEGIN{
case 's':
Binit(&bin, 0, OREAD);
Binit(&bout, 1, OWRITE);
break;
case 'f':
f = ARGF();
if (open(f, OREAD) == -1)
sysfatal("File \"%s\" does not exist", f);
bin = *Bopen(f, OREAD);
//Binit(&bin, 0, OREAD);
Binit(&bout, 1, OWRITE);
break;
default:
usage();
exits("usage");
}ARGEND;
if(initdraw(nil, nil, argv0) < 0)
sysfatal("%r");
bg = allocimage(display, Rect(0,0,1,1), RGB24, 1, bgco);
text = allocimage(display, Rect(0,0,screen->r.max.x,font->height), RGB24, 0, textco);
if(bg == nil || text == nil)
sysfatal("We need more memory\n%r");
textpos.x = screen->r.min.x;
textpos.y = screen->r.min.y;
buf = L"No input recieved";
optdraw(bg, text, textpos, buf);
if((mctl = initmouse(nil, display->image)) == nil)
sysfatal("%s: %r", argv0);
enum{INPUT, MOUSE, CLOCK, NONE};
Alt alts[4] = {
/* c v op */
{nil, input, CHANRCV},
{mctl->c, &mouse, CHANRCV},
{timer, &clock, CHANRCV},
{nil, nil, CHANEND},
};
alts[2].c = chancreate(sizeof(ulong), 0);
timer = alts[2].c;
proccreate(clockproc, alts[2].c, STACK);
alts[0].c = chancreate(sizeof input, 0);
proccreate(readinproc, alts[0].c, STACK);
disp = 1;
while(disp){
switch(alt(alts)){
case CLOCK:
optdraw(bg, text, textpos, buf);
break;
case INPUT:
if(!(recv(alts[0].c, input))){
sysfatal("%s: Unsuccessful retrieval of input\n%r", argv0);
}
buf = input;
optdraw(bg, text, textpos, buf);
break;
case MOUSE:
if(getwindow(display, Refnone) < 0)
sysfatal("%s: %r", argv0);
textpos.x = screen->r.min.x;
textpos.y = screen->r.min.y;
freeimage(text);
text = allocimage(display, Rect(0,0,screen->r.max.x,font->height), RGB24, 0, textco);
optdraw(bg, text, textpos, buf);
break;
case NONE:
break;
}
}
}
void
clockproc(void *arg)
{
int o;
Channel *c;
c = arg;
o = 1;
while(o){
if(!(send(c, &o))){
o = 0;
sysfatal("%s: Clock broke can't fix\n%r", argv0);
}
sleep(1000);
}
}
void
optdraw(Image *bg, Image *text, Point textpos, Rune *opt)
{
Point p;
int ht, textht, row, col, textwid;
ulong textco;
Rune items[5][64];
textco = text->chan;
draw(screen, screen->r, bg, nil, ZP);
freeimage(text);
ht = 0;
col = 0;
for(int i=col; opt[i] != 0; i++){
if (opt[i] == '\n'){
//items[ht][col] = 0;
items[ht+1][0] = 0;
ht ++;
col = 0;
}else{
items[ht][col] = opt[i];
items[ht][col+1] = 0;
col++;
}
}
ht ++;
textht = ht * font->height;
text = allocimage(display, Rect(0,0,screen->r.max.x,textht), RGB24, 0, textco);
row = 0;
textwid = 0;
while(ht - row > 0){
p = runestring(screen, textpos, text, ZP, font, items[row]);
if (p.x > textwid)
textwid = p.x;
row ++;
textpos.y = textpos.y + font->height + 2;
}
flushimage(display, Refnone);
resize(Pt(textwid + 20, screen->r.min.y + textht));
}
void
readinproc(void *arg)
{
Rune input[64];
Rune r;
Channel *mc;
mc = arg;
for(int i=0; (r=Bgetrune(&bin)) != Beof; i++){
input[i] = r;
input[i+1] = 0;
}
while(recv(timer, nil)){
send(mc, nil);
send(mc, input);
}
}
void
resize(Point p)
{
Point min, max;
int wp;
if ((p.x < screen->r.min.x) || (p.y < screen->r.min.y))
sysfatal("%s: resize given invalid dimensions\n%r", argv0);
if((wp = open("/dev/wctl", ORDWR)) < 0)
sysfatal("%s: Couldn't open wctl\n %r", argv0);
min = screen->r.min;
min = Pt(min.x - 4, min.y - 4);
max = p;
if((max.x - min.x) < 100)
max.x = min.x + 100;
fprint(wp, "resize -r %d %d %d %d", min.x, min.y, max.x, max.y);
close(wp);
}