820 lines · 15.0 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <mouse.h>#include <keyboard.h>#include <plumb.h>#include <bio.h>#include "icons.h"#include "theme.h" extern void alert(const char *message, const char *err, Mousectl *mctl, Keyboardctl *kctl);extern int confirm(const char *message, Mousectl *mctl, Keyboardctl *kctl, Image *bg, Image *fg, Image *hi);void redraw(void); enum{	Toolpadding = 4,	Padding = 1,	Scrollwidth = 14,	Slowscroll = 10,}; enum{	Emouse,	Eresize,	Ekeyboard,	Eplumb,}; enum{	Mrename,	Mdelete,};char *menu2str[] = { "rename", "delete", nil };Menu menu2 = { menu2str }; const char ellipsis[] = "…"; int mainstacksize = 32768;char *home;char path[4096];Dir* dirs;long ndirs;Mousectl *mctl;Keyboardctl *kctl;Rectangle toolr;Rectangle homer;Rectangle upr;Rectangle cdr;Rectangle newdirr;Rectangle newfiler;Rectangle viewr;Rectangle scrollr;Rectangle scrposr;Rectangle pathr;Image *folder;Image *file;Image *ihome;Image *icd;Image *iup;Image *inewfile;Image *inewfolder;Image *toolbg;Image *toolfg;Image *viewbg;Image *viewfg;Image *selbg;Image *selfg;Image *scrollbg;Image *scrollfg;Image *high;int sizew;int lineh;int nlines;int offset;int plumbfd;int scrolling;int oldbuttons;int lastn; voidshowerrstr(char *msg){	char errbuf[ERRMAX]; 	errstr(errbuf, ERRMAX-1);	alert(msg, errbuf, mctl, kctl);} voidreadhome(void){	Biobuf *bp;		bp = Bopen("/env/home", OREAD);	home = Brdstr(bp, 0, 0);	Bterm(bp);} char*abspath(char *wd, char *p){	char *s; 	if(p[0]=='/')		s = cleanname(p);	else{		s = smprint("%s/%s", wd, p);		cleanname(s);	}	return s;} intdircmp(Dir *a, Dir *b){	if(a->qid.type==b->qid.type)		return strcmp(a->name, b->name);	if(a->qid.type&QTDIR)		return -1;	return 1;} voidloaddirs(void){	int fd, i;	vlong m; 	fd = open(path, OREAD);	if(fd<0){		showerrstr("Unable to load directory");		return;	}	if(dirs!=nil)		free(dirs);	ndirs = dirreadall(fd, &dirs);	if(ndirs > 0)		qsort(dirs, ndirs, sizeof *dirs, (int(*)(void*,void*))dircmp);	else{		if(ndirs < 0)			showerrstr("Unable to read directory");		ndirs = 0;	}	offset = 0;	close(fd);	m = 1;	for(i=0; i < ndirs; i++){		if(dirs[i].length>m)			m=dirs[i].length;	}	sizew = m == 0 ? 3 : 1+1+log(m)/log(10);} voidup(void){	snprint(path, sizeof path, abspath(path, ".."));	loaddirs();} voidcd(char *dir){	char newpath[4096] = {0}; 	if(dir == nil)		snprint(newpath, sizeof newpath, home);	else if(dir[0] == '/')		snprint(newpath, sizeof newpath, dir);	else		snprint(newpath, sizeof newpath, "%s/%s", path, dir);	if(access(newpath, 0)<0)		showerrstr("Directory does not exist");	else		snprint(path, sizeof path, abspath(path, newpath));	loaddirs();} voidmkdir(char *name){	char *p;	int fd; 	p = smprint("%s/%s", path, name);	if(access(p, 0)>=0){		showerrstr("Directory already exists");		goto cleanup;	}	fd = create(p, OREAD, DMDIR|0755);	if(fd<0){		showerrstr("Unable to create directory");		goto cleanup;	}	close(fd);	loaddirs();cleanup:	free(p);} voidtouch(char *name){	char *p;	int fd; 	p = smprint("%s/%s", path, name);	if(access(p, 0)>=0){		showerrstr("File already exists");		goto cleanup;	}	fd = create(p, OREAD, 0644);	if(fd<0){		showerrstr("Unable to create file");		goto cleanup;	}	close(fd);	loaddirs();cleanup:	free(p);} intdoexec(char *cmd){	int rc;	Waitmsg *msg;	char *p; 	rc = 0;	switch(rfork(RFPROC|RFFDG|RFREND)){	case -1:		rc = -1;		break;	case 0:		execl("/bin/rc", "rc", "-c", cmd, 0);		fprint(2, "execl failed: %r");		threadexitsall("execl");		break;	default:		msg = wait();		if(msg != nil && msg->msg[0] != 0){			rc = -1;			p = strchr(msg->msg, ':');			if(p != nil)				werrstr(p+2);			else				werrstr(msg->msg);		}		if(msg != nil)			free(msg);		break;	}	return rc;} voidrm(Dir d){	char cmd[300], buf[1024] = {0};	char *p, *qp; 	if(d.qid.type&QTDIR)		snprint(buf, sizeof buf, "Delete directory '%s' and its subdirectories ?", d.name);	else		snprint(buf, sizeof buf, "Delete file '%s' ?", d.name);	if(!confirm(buf, mctl, kctl, viewbg, viewfg, high))		return;	p = smprint("%s/%s", path, d.name);	qp = quotestrdup(p);	snprint(cmd, sizeof cmd, "rm -r %s >/dev/null >[2=1]", qp);	if(doexec(cmd) < 0)		showerrstr("Cannot remove file/directory");	else		loaddirs();	free(qp);	free(p);} voidmv(char *from, char *to){	char cmd[520];	char *fp, *tp, *qfp, *qtp; 	fp = smprint("%s/%s", path, from);	tp = smprint("%s/%s", path, to);	qfp = quotestrdup(fp);	qtp = quotestrdup(tp); 	snprint(cmd, sizeof cmd, "mv %s %s >/dev/null >[2=1]", qfp, qtp);	if(doexec(cmd) < 0)		showerrstr("Cannot rename file/directory");	else		loaddirs();	free(qtp);	free(qfp);	free(tp);	free(fp);} intplumbfile(char *path, char *name){	char *f;	int e; 	f = smprint("%s/%s", path, name);	e = access(f, 0)==0;	if(e)		plumbsendtext(plumbfd, "vdir", nil, path, name);	else{		alert("File does not exist anymore", nil, mctl, kctl);		loaddirs();		redraw();	}	free(f);	return e;} voidinitcolors(void){	Theme *theme; 	theme = loadtheme();	if(theme == nil){		toolbg = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEFEFEFFF);		toolfg = display->black;		viewbg = display->white;		viewfg = display->black;		selbg  = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEFEFEFFF);		selfg  = display->black;		scrollbg = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x999999FF);		scrollfg = display->white;		high = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DGreygreen);	}else{		toolbg = theme->back;		toolfg = theme->text;		viewbg = theme->back;		viewfg = theme->text;		selbg  = theme->border;		selfg  = theme->text;		scrollbg = theme->border;		scrollfg = theme->back;		high = theme->high;	}} Image*loadicon(Rectangle r, uchar *data, int ndata){	Image *i;	int n; 	i = allocimage(display, r, RGBA32, 0, DNofill);	if(i==nil)		sysfatal("allocimage: %r");	n = loadimage(i, r, data, ndata);	if(n<0)		sysfatal("loadimage: %r");	return i;} voidinitimages(void){	Rectangle small = Rect(0, 0, 12, 12);	Rectangle big   = Rect(0, 0, 16, 16); 	folder = loadicon(small, folderdata, sizeof folderdata);	file   = loadicon(small, filedata, sizeof filedata);	ihome  = loadicon(big, homedata, sizeof homedata);	icd    = loadicon(big, cddata, sizeof cddata);	iup    = loadicon(big, updata, sizeof updata);	inewfile = loadicon(big, newfiledata, sizeof newfiledata);	inewfolder = loadicon(big, newfolderdata, sizeof newfolderdata);} char*mdate(Dir d){	char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 			   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };	Tm *tm; 	tm = localtime(d.mtime);	return smprint("%s %02d %02d:%02d", months[tm->mon], tm->mday, tm->hour, tm->min);} Rectangledrawbutton(Point *p, Image *c, Image *i){	Rectangle r; 	p->x += Toolpadding;	r = Rect(p->x, p->y, p->x+16, p->y+16);	draw(screen, r, c, i, ZP);	p->x += 16+Toolpadding;	return r;} Pointdrawtext(Point p, Image *i, char* t, int n){	char *s;	Rune  rn; 	s = t;	if(*s && (p.x+stringwidth(font, s)) > n){		p = string(screen, p, i, ZP, font, ellipsis);		while (*s && (p.x+stringwidth(font, s)) > n) s++;	}	for( ; *s; s++){		s += chartorune(&rn, s) - 1;		p = runestringn(screen, p, i, ZP, font, &rn, 1);	}	return p;} voiddrawdir(int n, int selected){	char buf[255], *t;	Dir d;	Image *img, *bg, *fg;	Point p;	Rectangle r;	int dy; 	if(offset+n>=ndirs)		return;	bg = selected ? selbg : viewbg;	fg = selected ? selfg : viewfg;	d = dirs[offset+n];	p = addpt(viewr.min, Pt(Toolpadding, Toolpadding));	p.y += n*lineh;	r = Rpt(p, addpt(p, Pt(Dx(viewr)-2*Toolpadding, lineh)));	draw(screen, r, bg, nil, ZP);	t = mdate(d);	snprint(buf, sizeof buf, "%*lld  %s", sizew, d.length, t);	free(t);	img = (d.qid.type&QTDIR) ? folder : file;	p.y -= Padding;	dy = (lineh-12)/2;	draw(screen, Rect(p.x, p.y+dy, p.x+12, p.y+dy+12), fg, img, ZP);	p.x += 12+4+Padding;	p.y += Padding;	p = drawtext(p, fg, d.name, viewr.max.x - stringwidth(font, buf) - 2*Padding - Toolpadding);	p.x = viewr.max.x - stringwidth(font, buf) - 2*Padding - Toolpadding;	string(screen, p, fg, ZP, font, buf);} voidflash(int n){	int i; 	for(i=0; i<5; i++){		drawdir(n, i&1);		sleep(50);		flushimage(display, 1);	}} voidredraw(void){	Point p;	int i, h, y; 	draw(screen, screen->r, viewbg, nil, ZP);	p = addpt(screen->r.min, Pt(0, Toolpadding));	draw(screen, toolr, toolbg, nil, ZP);	line(screen, Pt(toolr.min.x, toolr.max.y), toolr.max, 0, 0, 0, toolfg, ZP);	homer = drawbutton(&p, toolfg, ihome);	cdr = drawbutton(&p, toolfg, icd);	upr = drawbutton(&p, toolfg, iup);	p.x += Toolpadding;	p.y = toolr.min.y + (Toolpadding+16+Toolpadding-font->height)/2;	pathr = Rect(p.x, p.y, p.x + stringwidth(font, path), p.y + font->height);	p = drawtext(p, toolfg, path, screen->r.max.x - 2*(Toolpadding+16+Toolpadding));	p.x = screen->r.max.x - 2*(Toolpadding+16+Toolpadding);	p.y = screen->r.min.y + Toolpadding;	newdirr = drawbutton(&p, toolfg, inewfolder);	newfiler = drawbutton(&p, toolfg, inewfile);	draw(screen, scrollr, scrollbg, nil, ZP);	if(ndirs>0){		h = ((double)nlines/ndirs)*Dy(scrollr);		y = ((double)offset/ndirs)*Dy(scrollr);		scrposr = Rect(scrollr.min.x, scrollr.min.y+y, scrollr.max.x-1, scrollr.min.y+y+h);	}else		scrposr = Rect(scrollr.min.x, scrollr.min.y, scrollr.max.x-1, scrollr.max.y);	draw(screen, scrposr, scrollfg, nil, ZP);	for(i = 0; i<nlines && offset+i<ndirs; i++){		drawdir(i, 0);

Lines 1–500 of 820.