~sirjofri/plumbto

b8ce27374966893fe7ee3b587051161421ff0173 — sirjofri 1 year, 7 months ago 0edad9c master
adds thanks and lots of adjustments (thanks phil9)
2 files changed, 211 insertions(+), 112 deletions(-)

M plumbto.c
A thanks
M plumbto.c => plumbto.c +208 -112
@@ 7,151 7,247 @@
#include <keyboard.h>
#include <control.h>

Controlset *cs;
int ctldeletequits = 1;

Control *items[] = {
	nil, /* pmhead */
	nil,
	nil, nil, nil, nil, nil,
	nil, nil, nil,
enum
{
	Maxchans = 16,
	Padding = 4,
};

enum
{
	BACK,
	TEXT,
	SEL,
	NCOLS,
};
int itemsize = 1;
int maxitems = 10;

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
resizecontrolset(Controlset*)
plumbto(char *chan)
{
	int i;
	Rectangle r;
	if (getwindow(display, Refnone) < 0)
		sysfatal("resize failed: %r");
	r = insetrect(screen->r, 10);
	for (i = 0; items[i]; i++){
		r = insetrect(screen->r, 10);
		r.min.y = r.min.y +  i   *(1+font->height+1);
		r.max.y = r.min.y +       (1+font->height+1);
		chanprint(cs->ctl, "%s rect %R\n%s show", items[i]->name, r, items[i]->name);
	}
	pm->attr = plumbdelattr(pm->attr, "channels");
	pm->dst = strdup(chan);
	plumbsend(plumbfd, pm);
	plumbfree(pm);
	pm = nil;
	nchans = 0;
}

int pfd, psfd;
Plumbmsg *pm;
char *channels;
void
drawwait(void)
{
	string(screen, headerp, cols[SEL], ZP, font, "waiting for plumb message...");
}

void
plumblisten(void *arg)
drawline(int index, int selected)
{
	while ((pm = plumbrecv(pfd)) != nil){
		channels = plumblookup(pm->attr, "channels");
		if (channels != nil && strcmp(channels, "") != 0)
			send((Channel*)arg, 0);
	}
	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
cleanup(void)
redraw(void)
{
	char *f, buf[1024] = {0};
	int i;
	for (i = 1; items[i]; i++){
		closecontrol(items[i]);
		items[i] = nil;

	lockdisplay(display);
	draw(screen, screen->r, cols[BACK], nil, ZP);
	if(pm == nil){
		drawwait();
		flushimage(display, 1);
		unlockdisplay(display);
		return;
	}
	resizecontrolset(cs);
	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
handleplumb(Channel *c)
evtresize(void)
{
	char *args[10]; // maxitems-1+1
	int n, i;

	cleanup();

	n = getfields(channels, args, 10, 1, ",");
	for (i = 0; i < n; i++){
		items[i+1] = createtextbutton(cs, args[i]);
		activate(items[i+1]);
		chanprint(cs->ctl, "%q text %q", args[i], args[i]);
		controlwire(items[i+1], "event", c);
		itemsize++;
	}
	resizecontrolset(cs);
	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
handleevent(char *c)
evtmouse(Mouse *m)
{
	char *args[10];
	int n;
	
	gettokens(c, args, 10, " \t:");
	
	if (atoi(args[2]) == 1){
		pm->attr = plumbdelattr(pm->attr, "channels");
		pm->dst = args[0];
		n = plumbsend(psfd, pm);
		if (!n)
			fprint(2, "plumbsend failed: %r\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");
		}
	}
	cleanup();
}

void
threadmain(int argc, char **argv)
evtkeyboard(Rune k)
{
	USED(argc, argv);
	int i;
	int wctlfd;
	char *chanval;
	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, &i, CHANRCV},
		{nil, &chanval, CHANRCV},
		{nil, nil, CHANEND},
		{ nil, &m,  CHANRCV },
		{ nil, nil, CHANRCV },
		{ nil, &k,  CHANRCV },
		{ nil, &p, CHANRCV },
		{ nil, nil, CHANEND },
	};
	
	pfd = plumbopen("chanselect", OREAD);
	if (!pfd)
		sysfatal("cannot open plumb channel: %r");
	psfd = plumbopen("send", OWRITE);
	if (!psfd)
		sysfatal("cannot open plumb send: %r");
	
	wctlfd = open("/dev/wctl", OWRITE);
	if (wctlfd)
		fprint(wctlfd, "hide\n");
	
	initdraw(0, 0, "plumbto!");
	initcontrols();
	
	a[0].c = chancreate(sizeof(int), 0);
	proccreate(plumblisten, a[0].c, 2048);
	
	cs = newcontrolset(screen, nil, nil, nil);
	cs->clicktotype = 1;
	
	items[0] = createlabel(cs, "pmhead");
	chanprint(cs->ctl, "pmhead value %q", "no message");
	
	a[1].c = chancreate(sizeof(char*), 0);
	
	resizecontrolset(cs);
	for (;;){
		switch (alt(a)){
		case 0: /* plumb event */
			chanprint(cs->ctl, "pmhead value %q", pm->wdir);
			handleplumb(a[1].c);
			if (wctlfd)
				fprint(wctlfd, "unhide\n");

	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 1: /* control event */
			handleevent(chanval);
		//	plumbfree(pm);
			if (wctlfd)
				fprint(wctlfd, "hide\n");
		case Eplumb:
			evtplumb(p);
			break;
		default:
			sysfatal("can't happen");
		}
	}
}

A thanks => thanks +3 -0
@@ 0,0 1,3 @@
Special thanks to:

- phil9