shithub: plumbto

ref: b8ce27374966893fe7ee3b587051161421ff0173
dir: /plumbto.c/

View raw version
#include <u.h>
#include <libc.h>
#include <plumb.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <keyboard.h>
#include <control.h>

enum
{
	Maxchans = 16,
	Padding = 4,
};

enum
{
	BACK,
	TEXT,
	SEL,
	NCOLS,
};

int wfd;
Mousectl *mc;
Keyboardctl *kc;
Image *cols[NCOLS];
Point headerp;
Rectangle listr;
int sel = -1;
int plumbfd;
Channel *plumbc;
Plumbmsg *pm;
char *chans[Maxchans];
usize nchans;

void
plumbto(char *chan)
{
	pm->attr = plumbdelattr(pm->attr, "channels");
	pm->dst = strdup(chan);
	plumbsend(plumbfd, pm);
	plumbfree(pm);
	pm = nil;
	nchans = 0;
}

void
drawwait(void)
{
	string(screen, headerp, cols[SEL], ZP, font, "waiting for plumb message...");
}

void
drawline(int index, int selected)
{
	Point p, q;
	Image *c;

	p = Pt(listr.min.x, listr.min.y + index*font->height);
	q = addpt(p, Pt(Dx(listr), font->height));
	c = selected ? cols[SEL] : cols[BACK];
	draw(screen, Rpt(p, q), c, nil, ZP);
	p = string(screen, p, cols[TEXT], ZP, font, "» ");
	string(screen, p, cols[TEXT], ZP, font, chans[index]);
}

void
redraw(void)
{
	char *f, buf[1024] = {0};
	int i;

	lockdisplay(display);
	draw(screen, screen->r, cols[BACK], nil, ZP);
	if(pm == nil){
		drawwait();
		flushimage(display, 1);
		unlockdisplay(display);
		return;
	}
	f = plumblookup(pm->attr, "filename");
	if(f != nil)
		snprint(buf, sizeof buf, "Plumb '%s' to:", f);
	else
		snprint(buf, sizeof buf, "Plumb data to:");
	string(screen, headerp, cols[TEXT], ZP, font, buf);
	for(i = 0; i < nchans; i++){
		drawline(i, 0);
	}
	flushimage(display, 1);
	unlockdisplay(display);
}

void
evtresize(void)
{
	headerp = addpt(screen->r.min, Pt(Padding, Padding));
	listr = Rect(screen->r.min.x + Padding,
				 screen->r.min.y + Padding + font->height + Padding,
				 screen->r.max.x - Padding,
				 screen->r.max.y - Padding);
	redraw();
}

void
evtmouse(Mouse *m)
{
	int n;

	if(!ptinrect(m->xy, listr)){
		if(sel != -1){
			sel = -1;
			redraw();
		}
		return;
	}
	n = (m->xy.y - listr.min.y) / font->height;
	if(m->buttons == 0){
		if(n >= nchans){
			sel = -1;
			redraw();
		}else if(n != sel){
			if(sel != -1)
				drawline(sel, 0);
			drawline(n, 1);
			flushimage(display, 1);
			sel = n;
		}
	}else if(m->buttons == 1){
		if(sel != -1){
			sel = -1;
			plumbto(chans[n]);
			redraw();
			fprint(wfd, "hide\n");
		}
	}
}

void
evtkeyboard(Rune k)
{
	if(k == Kdel)
		threadexitsall(nil);
}

void
evtplumb(Plumbmsg *p)
{
	fprint(wfd, "unhide\n");
	pm = p;
	redraw();
}

void
initcols(void)
{
	cols[BACK] = display->white;
	cols[TEXT] = display->black;
	cols[SEL]  = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xccccccff);
}

void
plumbproc(void *v)
{
	Channel *c;
	Plumbmsg *p;
	int fd;
	char *s;

	c = v;
	fd = plumbopen("chanselect", OREAD);
	if(fd < 0)
		sysfatal("plumbopen: %r");
	for(;;){
		p = plumbrecv(fd);
		if(p == nil)
			break;
		s = plumblookup(p->attr, "channels");
		if(s == nil || s[0] == 0){
			plumbfree(p);
			continue;
		}
		nchans = getfields(s, chans, nelem(chans), 0, ",");
		if(nchans != 0)
			sendp(c, p);
		else
			plumbfree(p);
	}
	threadexits(nil);
}

void
threadmain(int argc, char *argv[])
{
	enum { Emouse, Eresize, Ekeyboard, Eplumb, };
	Mouse m;
	Rune k;
	Plumbmsg *p;
	Alt a[] = {
		{ nil, &m,  CHANRCV },
		{ nil, nil, CHANRCV },
		{ nil, &k,  CHANRCV },
		{ nil, &p, CHANRCV },
		{ nil, nil, CHANEND },
	};

	ARGBEGIN{
	}ARGEND;

	nchans = 0;
	if(initdraw(nil, nil, argv0) < 0)
		sysfatal("initdisplay: %r");
	unlockdisplay(display);
	if((wfd = open("/dev/wctl", OWRITE)) < 0)
		sysfatal("open: %r");
	fprint(wfd, "hide\n");
	if((mc = initmouse(nil, screen)) == nil)
		sysfatal("initmouse: %r");
	if((kc = initkeyboard(nil)) == nil)
		sysfatal("initkeyboard: %r");
	plumbfd = plumbopen("send", OWRITE);
	if(plumbfd < 0)
		sysfatal("plumbopen: %r");
	plumbc = chancreate(sizeof(Plumbmsg*), 0);
	if(plumbc == nil)
		sysfatal("initchan: %r");
	proccreate(plumbproc, plumbc, 8192);
	a[Emouse].c = mc->c;
	a[Eresize].c = mc->resizec;
	a[Ekeyboard].c = kc->c;
	a[Eplumb].c = plumbc;
	initcols();
	evtresize();
	for(;;){
		switch(alt(a)){
		case Emouse:
			evtmouse(&m);
			break;
		case Eresize:
			if(getwindow(display, Refnone) < 0)
				sysfatal("getwindow: %r");
			evtresize();
			break;
		case Ekeyboard:
			evtkeyboard(k);
			break;
		case Eplumb:
			evtplumb(p);
			break;
		}
	}
}