shithub: mongrel

ref: b34f062e8d33eb64593a959302f7377bd0abc11c
dir: mongrel/main.c

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <thread.h>
#include <plumb.h>
#include "theme.h"
#include "kbd.h"
#include "a.h"

enum
{
	Padding = 4,
};

enum
{
	Emouse,
	Eresize,
	Ekeyboard,
	Eseemail,
	Eshowmesg,
	Eselmesg,
};

enum
{
	BACK,
	TEXT,
	BORD,
	PBRD,
	PBCK,
	NCOLS,
};

Mousectl *mctl;
Kbdctl *kctl;
Channel *showc;
Channel *selc;
Channel *eventc;
Channel *loadc;
Mailbox *mboxes[16];
int nmboxes;
char *mbmenustr[16] = {0};
Menu mbmenu = { mbmenustr };
Mailbox *mbox;
static Image *cols[NCOLS];
Rectangle headr;
Rectangle indexr;
Rectangle pagerr;
int collapsed = 0;

void
drawheader(void)
{
	char buf[255] = {0};
	Point p;

	draw(screen, headr, cols[BACK], nil, ZP);
	p = headr.min;
	p.x += Padding;
	p.y += Padding / 2;
	if(mbox->unseen > 0)
		snprint(buf, sizeof buf, "» %s [total:%d - new:%d]", mbox->name, mbox->count, mbox->unseen);
	else
		snprint(buf, sizeof buf, "» %s [total:%d]", mbox->name, mbox->count);
	string(screen, p, cols[TEXT], ZP, font, buf);
	line(screen, Pt(headr.min.x, headr.max.y), headr.max, 0, 0, 0, cols[BORD], ZP);
}

void
redraw(void)
{
	draw(screen, screen->r, cols[BACK], nil, ZP);
	drawheader();
	indexdraw();
	if(collapsed){
		line(screen, Pt(indexr.min.x, indexr.max.y), indexr.max, 0, 0, 0, cols[BORD], ZP);
		pagerdraw();
	}
	flushimage(display, 1);
}

void
resize(void)
{
	headr = screen->r;
	headr.max.y = headr.min.y+Padding+font->height;
	indexr = screen->r;
	indexr.min.y = headr.max.y + 1;
	indexr = indexresize(indexr, collapsed);
	if(collapsed){
		pagerr = screen->r;
		pagerr.min.y = indexr.max.y + 1;
		pagerresize(pagerr);
	}
	redraw();
}

void
loadproc(void *v)
{
	Channel *c;

	c = v;
	mboxload(mbox, c);
}

void
drawprogress(Rectangle r, Rectangle pr)
{
	draw(screen, pr, cols[PBCK], nil, ZP);
	border(screen, r, 2, cols[PBRD], ZP);	
	flushimage(display, 1);
}

void
loadmbox(void)
{
	ulong total, count, n;
	Point sp, p;
	Rectangle r, pr;
	int pc;
	char buf[255] = {0};

	draw(screen, screen->r, cols[BACK], nil, ZP);
	p.x = (Dx(screen->r)-200)/2;
	p.y = (Dy(screen->r)-25)/2;
	r = rectaddpt(rectaddpt(Rect(0, 0, 200, 25), p), screen->r.min);
	snprint(buf, sizeof buf, "Loading %s...", mbox->name);
	sp.x = (Dx(screen->r)-stringwidth(font, buf))/2;
	sp.y = r.min.y - font->height - 12 - screen->r.min.y;
	string(screen, addpt(screen->r.min, sp), cols[TEXT], ZP, font, buf);
	replclipr(screen, 1, insetrect(r, -2));
	loadc = chancreate(sizeof(ulong), 1);
	proccreate(loadproc, loadc, 8192);
	total = recvul(loadc);
	count = 0;
	for(;;){
		n = recvul(loadc);
		if(n == 0)
			break;
		count += 1;
		pc = 200*((double)count/total);
		pr = rectaddpt(rectaddpt(Rect(0, 0, pc, 25), p), screen->r.min);
		if(count % (total/100) == 0)
			drawprogress(r, pr);
	}
	chanfree(loadc);
	replclipr(screen, 1, screen->r);
}

void
switchmbox(int n)
{
	if(mbox==mboxes[n])
		return;
	mbox = mboxes[n];
	if(!mbox->loaded)
		loadmbox();
	indexswitch(mbox);
	collapsed = 0;
	resize();
}

void
mouse(Mouse m)
{
	int n;

	if(ptinrect(m.xy, headr) && m.buttons==4){
		n = menuhit(3, mctl, &mbmenu, nil);
		if(n >= 0)
			switchmbox(n);
		return;
	}
	indexmouse(m);
	if(collapsed)
		pagermouse(m);
}

void
key(Key k)
{
	if(k.k == Kdel)
		threadexitsall(nil);
	else if(k.k == 'q'){
		if(collapsed){
			collapsed = 0;
			resize();
		}else
			threadexitsall(nil);
	}else if(k.mods == Malt){
		if(collapsed)
			pagerkey(k.k);
	}else
		indexkey(k.k);
}

void
seemail(Mailevent e)
{
	Mailbox *mb;
	char *s;
	int i;

	for(mb = nil, i = 0; i < nmboxes; i++){
		if(strncmp(mboxes[i]->path, e.path, strlen(mboxes[i]->path))==0){
			mb = mboxes[i];
			break;
		}
	}
	if(mb==nil)
		return;
	s = e.path;
	switch(e.type){
		case Enew:
			i = mboxadd(mb, s);
			if(mb==mbox){
				indexadded(i);
				redraw();
			}
			break;
		case Edelete:
			i = mboxdel(mb, s);
			if(mb==mbox){
				indexremoved(i);
				redraw();
			}
			break;
		case Emodify:
			i = mboxmod(mb, s);
			if(i >= 0 && mb==mbox)
				redraw();
			break;
	}
	free(s);
}

void
init(Channel *selc)
{
	Theme *theme;
	Rectangle r;

	theme = loadtheme();
	if(theme != nil){
		cols[BACK] = theme->back;
		cols[TEXT] = theme->text;
		cols[BORD] = theme->title;
		cols[PBRD] = theme->menubord;
		cols[PBCK] = theme->menuback;
	}else{
		r = Rect(0, 0, 1, 1);
		cols[BACK] = allocimage(display, r, screen->chan, 1, 0xFFFFFFFF);
		cols[TEXT] = allocimage(display, r, screen->chan, 1, 0x000000FF);
		cols[BORD] = allocimage(display, r, screen->chan, 1, DGreygreen);
		cols[PBRD] = allocimage(display, r, screen->chan, 1, 0x88CC88FF);
		cols[PBCK] = allocimage(display, r, screen->chan, 1, 0xEAFFEAFF);
		/*
		cols[BACK] = allocimage(display, r, screen->chan, 1, 0x282828FF);
		cols[TEXT] = allocimage(display, r, screen->chan, 1, 0xA89984FF);
		cols[BORD] = allocimage(display, r, screen->chan, 1, 0x98971AFF);
		*/
	}
	indexinit(mctl, showc, selc, theme);
	pagerinit(mctl, kctl, theme);
}

void
plumbmsg(Message *m)
{
	int fd;

	fd = plumbopen("send", OWRITE|OCEXEC);
	if(fd<0)
		return;
	plumbsendtext(fd, "mongrel", nil, nil, m->path);
	close(fd);
}

void
showmsg(Message *m)
{
	if(collapsed == 0){
		collapsed = 1;
		resize();
	}
	pagershow(m);
	if(mesgmarkseen(mbox, m))
		redraw();
}

void
selchanged(Message *m)
{
	if(collapsed == 0)
		return;
	showmsg(m);
}


void
usage(void)
{
	fprint(2, "usage: %s [-m maildir]\n", argv0);
	exits("usage");
}

void
threadmain(int argc, char *argv[])
{
	Mouse m;
	Key k;
	Mailevent e;
	Message *msg;
	Alt alts[] = 
	{
		{ nil, &m,   CHANRCV },
		{ nil, nil,  CHANRCV },
		{ nil, &k,   CHANRCV },
		{ nil, &e,   CHANRCV },
		{ nil, &msg, CHANRCV },
		{ nil, &msg, CHANRCV },
		{ nil, nil,  CHANEND },
	};
	char *s;

	nmboxes = 0;
	ARGBEGIN{
	case 'm':
		s = EARGF(usage());
		mboxes[nmboxes] = mboxinit(s);
		mbmenustr[nmboxes] = mboxes[nmboxes]->name;
		nmboxes++;
		break;
	default:
		fprint(2, "unknown flag '%c'\n", ARGC());
		usage();
	}ARGEND
	if(nmboxes==0){
		fprint(2, "no maildir specified\n");
		usage();
	}
	tmfmtinstall();
	if(initdraw(nil, nil, "mongrel")<0)
		sysfatal("initdraw: %r");
	display->locking = 0;
	if((mctl = initmouse(nil, screen)) == nil)
		sysfatal("initmouse: %r");
	if((kctl = initkbd()) == nil)
		sysfatal("initkbd: %r");
	if((eventc = chancreate(sizeof(Mailevent), 0))==nil)
		sysfatal("chancreate: %r");
	if((showc = chancreate(sizeof(Message*), 1))==nil)
		sysfatal("chancreate: %r");
	if((selc = chancreate(sizeof(Message*), 1))==nil)
		sysfatal("chancreate: %r");
	alts[0].c = mctl->c;
	alts[1].c = mctl->resizec;
	alts[2].c = kctl->c;
	alts[3].c = eventc;
	alts[4].c = showc;
	alts[5].c = selc;
	proccreate(seemailproc, eventc, 8192);
	init(selc);
	switchmbox(0);
	resize();
	for(;;){
		switch(alt(alts)){
		case Emouse:
			mouse(m);
			break;
		case Eresize:
			if(getwindow(display, Refnone)<0)
				sysfatal("cannot reattach: %r");
			resize();
			break;
		case Ekeyboard:
			key(k);
			break;
		case Eseemail:
			seemail(e);
			break;
		case Eshowmesg:
			showmsg(msg);
			break;
		case Eselmesg:
			//plumbmsg(msg);
			selchanged(msg);
			break;
		}
	}
}