shithub: fork

ref: 11e7bab1406c7f39c9b195367ecb5e36ddf3d472
dir: /sys/src/cmd/aux/statusmsg.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <bio.h>
#include <event.h>
#include <keyboard.h>

int newwin(char*);

int nokill;
int textmode;
char *title = nil;
char *message = nil;
Biobuf *bout;

Image *light;
Image *text;
Rectangle rtext;

void
initcolor(void)
{
	enum{
		Ctext,
		Clight,
		Ncols,
	};
	Theme th[Ncols] = {
		[Ctext] { "text",	DBlack },
		[Clight] { "back",	0xEAFFEAFF },
	};
	readtheme(th, nelem(th), nil);
	text = allocimage(display, Rect(0,0,1,1), screen->chan, 1, th[Ctext].c);
	light = allocimage(display, Rect(0,0,1,1), screen->chan, 1, th[Clight].c);
	if(text == nil || light == nil) sysfatal("initcolor: %r");
}

void
drawmsg(void)
{
	if(textmode){
		static int last = 0;

		while(last-- > 0)
			Bputc(bout, '\b');
		Bwrite(bout, message, strlen(message));
		Bflush(bout);
		last = utflen(message);
		return;
	}
	draw(screen, rtext, light, nil, ZP);
	string(screen, rtext.min, text, ZP, display->defaultfont, message);
	flushimage(display, 1);
}

void
eresized(int new)
{
	if(new && getwindow(display, Refnone) < 0)
		fprint(2,"can't reattach to window");
	rtext = screen->r;
	draw(screen, rtext, light, nil, ZP);
	rtext.min.x += 4;
	rtext.min.y += 4;
	if(title){
		string(screen, rtext.min, text, ZP, display->defaultfont, title);
		rtext.min.y += 8+display->defaultfont->height;
	}
	rtext.max.y = rtext.min.y + display->defaultfont->height;
	drawmsg();
}

void
msg(Biobuf *b)
{
	char *p;
	Event e;
	int k, die, parent, child;

	parent = getpid();

	die = 0;
	if(textmode){
		child = -1;
		if(title){
			Bwrite(bout, title, strlen(title));
			Bwrite(bout, ": ", 2);
			Bflush(bout);
		}
	} else
	switch(child = rfork(RFMEM|RFPROC)) {
	case 0:
		sleep(1000);
		while(!die && (k = eread(Ekeyboard|Emouse, &e))) {
			if(nokill==0 && k == Ekeyboard && (e.kbdc == Kdel || e.kbdc == Ketx)) {
				die = 1;
				postnote(PNPROC, parent, "interrupt");
				_exits("interrupt");
			}
		}
		_exits(0);
	}
	while(!die && (p = Brdline(b, '\n'))){
		snprint(message, Bsize, "%.*s", utfnlen(p, Blinelen(b)-1), p);
		drawmsg();
	}
	if(textmode){
		Bwrite(bout, "\n", 1);
		Bterm(bout);
	}
	postnote(PNPROC, child, "kill");
}


void
usage(void)
{
	fprint(2, "usage: %s [-kt] [-w minx,miny,maxx,maxy] [title]\n", argv0);
	exits("usage");
}

void
main(int argc, char **argv)
{
	Biobuf b;
	char *p, *q;
	int lfd;

	p = "0,0,200,60";
	
	ARGBEGIN{
	case 'w':
		p = ARGF();
		break;
	case 't':
		textmode = 1;
		break;
	case 'k':
		nokill = 1;
		break;
	default:
		usage();
	}ARGEND;

	switch(argc){
	default:
		usage();
	case 1:
		title = argv[0];
	case 0:
		break;
	}
	lfd = dup(0, -1);

	while(q = strchr(p, ','))
		*q = ' ';
	Binit(&b, lfd, OREAD);
	if((message = malloc(Bsize)) == nil)
		sysfatal("malloc: %r");
	memset(message, 0, Bsize);
	if(textmode || newwin(p) < 0){
		textmode = 1;
		if((bout = Bfdopen(1, OWRITE)) == nil)
			sysfatal("Bfdopen: %r");
	}else{
		if(initdraw(0, 0, title ? title : argv0) < 0)
			sysfatal("initdraw: %r");
		initcolor();
		einit(Emouse|Ekeyboard);
		eresized(0);
	}
	msg(&b);

	exits(0);
}

int
newwin(char *win)
{
	char spec[100];
	int cons;

	if(win != nil){
		snprint(spec, sizeof(spec), "-r %s", win);
		win = spec;
	}
	if(newwindow(win) < 0){
		fprint(2, "%s: newwindow: %r", argv0);
		return -1;
	}
	if((cons = open("/dev/cons", OREAD)) < 0){
	NoCons:
		fprint(2, "%s: can't open /dev/cons: %r", argv0);
		return -1;
	}
	dup(cons, 0);
	close(cons);
	if((cons = open("/dev/cons", OWRITE)) < 0)
		goto NoCons;
	dup(cons, 1);
	dup(cons, 2);
	close(cons);
	return 0;
}