/* * Warren - Plan 9 Collaboration Framework * */ #include #include #include #include #include #include /* for support routines only */ #include #include "faces.h" void scandir(void); enum { Facesep = 6, /* must be even to avoid damaging background stipple */ Infolines = 9, HhmmTime = 90, /* max age of face to display hh:mm time */ }; char path[255]; char myname[255]; enum { Mainp, Timep, Mousep, NPROC }; int pids[NPROC]; char *procnames[] = { "main", "time", "mouse" }; Rectangle leftright = {0, 0, 20, 15}; uchar leftdata[] = { 0x00, 0x80, 0x00, 0x01, 0x80, 0x00, 0x03, 0x80, 0x00, 0x07, 0x80, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0xff, 0xf0, 0x3f, 0xff, 0xf0, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x0f, 0x00, 0x00, 0x07, 0x80, 0x00, 0x03, 0x80, 0x00, 0x01, 0x80, 0x00, 0x00, 0x80, 0x00 }; uchar rightdata[] = { 0x00, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x0f, 0x00, 0xff, 0xff, 0x80, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xc0, 0xff, 0xff, 0x80, 0x00, 0x0f, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x10, 0x00 }; Image *blue; /* full arrow */ Image *bgrnd; /* pale blue background color */ Image *left; /* left-pointing arrow mask */ Image *right; /* right-pointing arrow mask */ Font *tinyfont; Font *mediumfont; Font *datefont; int first, last; /* first and last visible face; last is first invisible */ int nfaces; int nacross; int ndown; char date[64]; Face **faces; ulong now; Point datep = { 8, 6 }; Point facep = { 8, 6+0+4 }; /* 0 updated to datefont->height in init() */ Point enddate; /* where date ends on display; used to place arrows */ Rectangle leftr; /* location of left arrow on display */ Rectangle rightr; /* location of right arrow on display */ void updatetimes(void); void setdate(void) { now = time(nil); strcpy(date, ctime(now)); date[4+4+3+5] = '\0'; /* change from Thu Jul 22 14:28:43 EDT 1999\n to Thu Jul 22 14:28 */ } void init(void) { initplumb(); /* make background color */ bgrnd = allocimagemix(display, DPalebluegreen, DWhite); blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x008888FF); /* blue-green */ left = allocimage(display, leftright, GREY1, 0, DWhite); right = allocimage(display, leftright, GREY1, 0, DWhite); if(bgrnd==nil || blue==nil || left==nil || right==nil){ fprint(2, "faces: can't create images: %r\n"); exits("image"); } loadimage(left, leftright, leftdata, sizeof leftdata); loadimage(right, leftright, rightdata, sizeof rightdata); /* initialize little fonts */ tinyfont = openfont(display, "/lib/font/bit/misc/ascii.5x7.font"); if(tinyfont == nil) tinyfont = font; mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font"); if(mediumfont == nil) mediumfont = font; datefont = font; facep.y += datefont->height; if(datefont->height & 1) /* stipple parity */ facep.y++; faces = nil; } void drawtime(void) { Rectangle r; r.min = addpt(screen->r.min, datep); if(eqpt(enddate, ZP)){ enddate = r.min; enddate.x += stringwidth(datefont, "Wed May 30 22:54"); /* nice wide string */ enddate.x += Facesep; /* for safety */ } r.max.x = enddate.x; r.max.y = enddate.y+datefont->height; draw(screen, r, bgrnd, nil, ZP); string(screen, r.min, display->black, ZP, datefont, date); } void updateme(void) { Dir stbuff; int fd, ret; nulldir(&stbuff); stbuff.mtime = time(nil); if(dirwstat(myname, &stbuff) >= 0) return; if((fd = create(myname, OREAD|OEXCL, DMDIR|0666)) < 0) return; dirfwstat(fd, &stbuff); close(fd); } void timeproc(void) { for(;;){ updateme(); scandir(); lockdisplay(display); drawtime(); flushimage(display, 1); unlockdisplay(display); now = time(nil); sleep(10*1000); setdate(); } } int torune(Rune *r, char *s, int nr) { int i; for(i=0; i Facesize){ n = torune(rbuf, s, nelem(rbuf)); for(i=0; i Facesize) break; } sprint(sbuf, "%.*S", i, rbuf); s = sbuf; dx = stringwidth(f, s); } p.x += (Facesize-dx)/2; string(screen, p, color, ZP, f, s); } Rectangle facerect(int index) /* index is geometric; 0 is always upper left face */ { Rectangle r; int x, y; x = index % nacross; y = index / nacross; r.min = addpt(screen->r.min, facep); r.min.x += x*(Facesize+Facesep); r.min.y += y*(Facesize+Facesep+2*mediumfont->height); r.max = addpt(r.min, Pt(Facesize, Facesize)); r.max.y += 2*mediumfont->height; /* simple fix to avoid drawing off screen, allowing customers to use position */ if(index<0 || index>=nacross*ndown) r.max.x = r.min.x; return r; } void drawface(Face *f, int i) { Rectangle r; Point p; if(f == nil) return; if(i=last) return; r = facerect(i-first); draw(screen, r, bgrnd, nil, ZP); draw(screen, r, f->bit, f->mask, ZP); r.min.y += Facesize; center(mediumfont, r.min, f->str[Suser], display->black); r.min.y += mediumfont->height; if(f->unknown){ r.min.y -= mediumfont->height + tinyfont->height + 2; for(p.x=-1; p.x<=1; p.x++) for(p.y=-1; p.y<=1; p.y++) center(tinyfont, addpt(r.min, p), f->str[Sdomain], display->white); center(tinyfont, r.min, f->str[Sdomain], display->black); } } void setlast(void) { last = first+nacross*ndown; if(last > nfaces) last = nfaces; } void drawarrows(void) { Point p; p = enddate; p.x += Facesep; if(p.x & 1) p.x++; /* align background texture */ leftr = rectaddpt(leftright, p); p.x += Dx(leftright) + Facesep; rightr = rectaddpt(leftright, p); draw(screen, leftr, first>0? blue : bgrnd, left, leftright.min); draw(screen, rightr, last=0; y--){ /* move them along */ r0 = facerect(y*nx+0); r1 = facerect(y*nx+1); r = r1; r.max.x = r.min.x + (nx - 1)*(Facesize+Facesep); draw(screen, r, screen, nil, r0.min); /* copy one down from row above */ if(y != 0){ r = facerect((y-1)*nx+nx-1); draw(screen, r0, screen, nil, r.min); } } ofaces = faces; faces = emalloc((nfaces+1)*sizeof(Face*)); memmove(faces+1, ofaces, nfaces*(sizeof(Face*))); free(ofaces); nfaces++; setlast(); drawarrows(); faces[0] = f; drawface(f, 0); flushimage(display, 1); unlockdisplay(display); } void freeface(Face *f) { int i; if(f->file!=nil && f->bit!=f->file->image) freeimage(f->bit); freefacefile(f->file); for(i=0; istr[i]); free(f); } void delface(int j) { Rectangle r0, r1, r; int nx, ny, x, y; if(j < first) first--; else if(j < last){ nx = nacross; ny = (nfaces+(nx-1)) / nx; x = (j-first)%nx; for(y=(j-first)/nx; yr)-2*facep.x+Facesep)/(Facesize+Facesep); for(ndown=1; rectinrect(facerect(ndown*nacross), screen->r); ndown++) ; setlast(); draw(screen, screen->r, bgrnd, nil, ZP); enddate = ZP; drawtime(); for(i=0; i0){ if(but == 2) delta = -first; else{ delta = nacross; if(delta > first) delta = first; delta = -delta; } }else if(ptinrect(p, rightr) && last nfaces-last) delta = nfaces-last; } } first += delta; last += delta; unlockdisplay(display); if(delta) eresized(0); return delta; } void click(int button, Mouse *m) { Point p; int i, mi; enum Menu2 { Mmail, Mchat, Mblog, Msee, Mfiles, Nmenu2, }; char *menu2str[Nmenu2+1] = { "mail", "chat", "blog", "see", "files", nil, }; Menu menu2 = {menu2str, nil}; p = m->xy; switch(button){ case 1: scroll(1, p); break; case 2: scroll(2, p); break; case 3: scroll(3, p); lockdisplay(display); for(i=first; i= 0){ while((n = dirread(dirfd, &d)) > 0){ for(i=0; istr[Sshow],d[i].name)) { if((now - d[i].mtime) > HhmmTime) delface(i); break; } } if((x==nfaces)&&((now-d[i].mtime) < HhmmTime)) addface(dirface(d[i].name, d[i].mtime)); } free(d); } close(dirfd); } } void killall(char *s) { int i, pid; pid = getpid(); for(i=0; i= 0) killall("process died"); exits(nil); } if(index >= 0) pids[index] = pid; } void usage(void) { fprint(2, "usage: warren [-n face-name] [-p collabdir]\n"); exits("usage"); } void main(int argc, char *argv[]) { ARGBEGIN{ case 'p': strcpy(path, EARGF(usage())); chdir(path); break; case 'n': strcpy(myname, EARGF(usage())); break; default: usage(); }ARGEND print("Hello %s - %s\n", myname, path); if(initdraw(nil, nil, "warren") < 0){ fprint(2, "warren: initdraw failed: %r\n"); exits("initdraw"); } init(); unlockdisplay(display); /* initdraw leaves it locked */ display->locking = 1; /* tell library we're using the display lock */ setdate(); eresized(0); pids[Mainp] = getpid(); startproc(mouseproc, Mousep); timeproc(); fprint(2, "warren: %s process exits\n", procnames[Mainp]); killall(nil); }