ref: bac60f84fa0916fdeb2a0165cd1738404e825438
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; ARGBEGIN{ case 's': Binit(&bin, 0, OREAD); Binit(&bout, 1, OWRITE); break; case 'f': if (open(argv[1], OREAD) == -1){ sysfatal("File \"%s\" does not exist", argv[1]); } bin = *Bopen(argv[1], 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("%s: We need more memory\n%r", argv0); 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); }