URI:
       tmain.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tmain.c (13479B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <draw.h>
            4 #include <plumb.h>
            5 #include <regexp.h>
            6 #include <bio.h>
            7 #include <thread.h>
            8 #include <mouse.h>
            9 #include <cursor.h>
           10 #include <9pclient.h>
           11 #include "faces.h"
           12 
           13 int        history = 0;        /* use old interface, showing history of mailbox rather than current state */
           14 int        initload = 0;        /* initialize program with contents of mail box */
           15 
           16 enum
           17 {
           18         Facesep = 6,        /* must be even to avoid damaging background stipple */
           19         Infolines = 9,
           20 
           21         HhmmTime = 18*60*60,        /* max age of face to display hh:mm time */
           22 
           23         STACK = 32768
           24 };
           25 
           26 enum
           27 {
           28         Mainp,
           29         Timep,
           30         Mousep,
           31         Resizep,
           32         NPROC
           33 };
           34 
           35 char *procnames[] = {
           36         "main",
           37         "time",
           38         "mouse",
           39         "resize"
           40 };
           41 
           42 Rectangle leftright = {0, 0, 20, 15};
           43 
           44 uchar leftdata[] = {
           45         0x00, 0x80, 0x00, 0x01, 0x80, 0x00, 0x03, 0x80,
           46         0x00, 0x07, 0x80, 0x00, 0x0f, 0x00, 0x00, 0x1f,
           47         0xff, 0xf0, 0x3f, 0xff, 0xf0, 0xff, 0xff, 0xf0,
           48         0x3f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x0f, 0x00,
           49         0x00, 0x07, 0x80, 0x00, 0x03, 0x80, 0x00, 0x01,
           50         0x80, 0x00, 0x00, 0x80, 0x00
           51 };
           52 
           53 uchar rightdata[] = {
           54         0x00, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1c,
           55         0x00, 0x00, 0x1e, 0x00, 0x00, 0x0f, 0x00, 0xff,
           56         0xff, 0x80, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xf0,
           57         0xff, 0xff, 0xc0, 0xff, 0xff, 0x80, 0x00, 0x0f,
           58         0x00, 0x00, 0x1e, 0x00, 0x00, 0x1c, 0x00, 0x00,
           59         0x18, 0x00, 0x00, 0x10, 0x00
           60 };
           61 
           62 CFsys        *mailfs;
           63 Mousectl        *mousectl;
           64 Image        *blue;                /* full arrow */
           65 Image        *bgrnd;                /* pale blue background color */
           66 Image        *left;                /* left-pointing arrow mask */
           67 Image        *right;                /* right-pointing arrow mask */
           68 Font        *tinyfont;
           69 Font        *mediumfont;
           70 Font        *datefont;
           71 int        first, last;        /* first and last visible face; last is first invisible */
           72 int        nfaces;
           73 int        mousefd;
           74 int        nacross;
           75 int        ndown;
           76 
           77 char        date[64];
           78 Face        **faces;
           79 char        *maildir = "mbox";
           80 ulong        now;
           81 
           82 Point        datep = { 8, 6 };
           83 Point        facep = { 8, 6+0+4 };        /* 0 updated to datefont->height in init() */
           84 Point        enddate;                        /* where date ends on display; used to place arrows */
           85 Rectangle        leftr;                        /* location of left arrow on display */
           86 Rectangle        rightr;                /* location of right arrow on display */
           87 void updatetimes(void);
           88 void eresized(int);
           89 
           90 void
           91 setdate(void)
           92 {
           93         now = time(nil);
           94         strcpy(date, ctime(now));
           95         date[4+4+3+5] = '\0';        /* change from Thu Jul 22 14:28:43 EDT 1999\n to Thu Jul 22 14:28 */
           96 }
           97 
           98 void
           99 init(void)
          100 {
          101         mailfs = nsmount("mail", nil);
          102         if(mailfs == nil)
          103                 sysfatal("mount mail: %r");
          104         mousectl = initmouse(nil, screen);
          105         if(mousectl == nil)
          106                 sysfatal("initmouse: %r");
          107         initplumb();
          108 
          109         /* make background color */
          110         bgrnd = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DWhite);
          111         blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x008888FF);        /* blue-green */
          112         left = allocimage(display, leftright, GREY1, 0, DWhite);
          113         right = allocimage(display, leftright, GREY1, 0, DWhite);
          114         if(bgrnd==nil || blue==nil || left==nil || right==nil){
          115                 fprint(2, "faces: can't create images: %r\n");
          116                 threadexitsall("image");
          117         }
          118 
          119         loadimage(left, leftright, leftdata, sizeof leftdata);
          120         loadimage(right, leftright, rightdata, sizeof rightdata);
          121 
          122         /* initialize little fonts */
          123         tinyfont = openfont(display, "/lib/font/bit/misc/ascii.5x7.font");
          124         if(tinyfont == nil)
          125                 tinyfont = font;
          126         mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
          127         if(mediumfont == nil)
          128                 mediumfont = font;
          129         datefont = font;
          130 
          131         facep.y += datefont->height;
          132         if(datefont->height & 1)        /* stipple parity */
          133                 facep.y++;
          134         faces = nil;
          135 }
          136 
          137 void
          138 drawtime(void)
          139 {
          140         Rectangle r;
          141 
          142         r.min = addpt(screen->r.min, datep);
          143         if(eqpt(enddate, ZP)){
          144                 enddate = r.min;
          145                 enddate.x += stringwidth(datefont, "Wed May 30 22:54");        /* nice wide string */
          146                 enddate.x += Facesep;        /* for safety */
          147         }
          148         r.max.x = enddate.x;
          149         r.max.y = enddate.y+datefont->height;
          150         draw(screen, r, bgrnd, nil, ZP);
          151         string(screen, r.min, display->black, ZP, datefont, date);
          152 }
          153 
          154 void
          155 timeproc(void *dummy)
          156 {
          157         for(;;){
          158                 lockdisplay(display);
          159                 drawtime();
          160                 updatetimes();
          161                 flushimage(display, 1);
          162                 unlockdisplay(display);
          163                 sleep(60000);
          164                 setdate();
          165         }
          166 }
          167 
          168 int
          169 alreadyseen(char *digest)
          170 {
          171         int i;
          172         Face *f;
          173 
          174         if(!digest)
          175                 return 0;
          176 
          177         /* can do accurate check */
          178         for(i=0; i<nfaces; i++){
          179                 f = faces[i];
          180                 if(f->str[Sdigest]!=nil && strcmp(digest, f->str[Sdigest])==0)
          181                         return 1;
          182         }
          183         return 0;
          184 }
          185 
          186 int
          187 torune(Rune *r, char *s, int nr)
          188 {
          189         int i;
          190 
          191         for(i=0; i<nr-1 && *s!='\0'; i++)
          192                 s += chartorune(r+i, s);
          193         r[i] = L'\0';
          194         return i;
          195 }
          196 
          197 void
          198 center(Font *f, Point p, char *s, Image *color)
          199 {
          200         int i, n, dx;
          201         Rune rbuf[32];
          202         char sbuf[32*UTFmax+1];
          203 
          204         dx = stringwidth(f, s);
          205         if(dx > Facesize){
          206                 n = torune(rbuf, s, nelem(rbuf));
          207                 for(i=0; i<n; i++){
          208                         dx = runestringnwidth(f, rbuf, i+1);
          209                         if(dx > Facesize)
          210                                 break;
          211                 }
          212                 sprint(sbuf, "%.*S", i, rbuf);
          213                 s = sbuf;
          214                 dx = stringwidth(f, s);
          215         }
          216         p.x += (Facesize-dx)/2;
          217         string(screen, p, color, ZP, f, s);
          218 }
          219 
          220 Rectangle
          221 facerect(int index)        /* index is geometric; 0 is always upper left face */
          222 {
          223         Rectangle r;
          224         int x, y;
          225 
          226         x = index % nacross;
          227         y = index / nacross;
          228         r.min = addpt(screen->r.min, facep);
          229         r.min.x += x*(Facesize+Facesep);
          230         r.min.y += y*(Facesize+Facesep+2*mediumfont->height);
          231         r.max = addpt(r.min, Pt(Facesize, Facesize));
          232         r.max.y += 2*mediumfont->height;
          233         /* simple fix to avoid drawing off screen, allowing customers to use position */
          234         if(index<0 || index>=nacross*ndown)
          235                 r.max.x = r.min.x;
          236         return r;
          237 }
          238 
          239 static char *mon = "JanFebMarAprMayJunJulAugSepOctNovDec";
          240 char*
          241 facetime(Face *f, int *recent)
          242 {
          243         static char buf[30];
          244 
          245         if((long)(now - f->time) > HhmmTime){
          246                 *recent = 0;
          247                 sprint(buf, "%.3s %2d", mon+3*f->tm.mon, f->tm.mday);
          248                 return buf;
          249         }else{
          250                 *recent = 1;
          251                 sprint(buf, "%02d:%02d", f->tm.hour, f->tm.min);
          252                 return buf;
          253         }
          254 }
          255 
          256 void
          257 drawface(Face *f, int i)
          258 {
          259         char *tstr;
          260         Rectangle r;
          261         Point p;
          262 
          263         if(f == nil)
          264                 return;
          265         if(i<first || i>=last)
          266                 return;
          267         r = facerect(i-first);
          268         draw(screen, r, bgrnd, nil, ZP);
          269         draw(screen, r, f->bit, f->mask, ZP);
          270         r.min.y += Facesize;
          271         center(mediumfont, r.min, f->str[Suser], display->black);
          272         r.min.y += mediumfont->height;
          273         tstr = facetime(f, &f->recent);
          274         center(mediumfont, r.min, tstr, display->black);
          275         if(f->unknown){
          276                 r.min.y -= mediumfont->height + tinyfont->height + 2;
          277                 for(p.x=-1; p.x<=1; p.x++)
          278                         for(p.y=-1; p.y<=1; p.y++)
          279                                 center(tinyfont, addpt(r.min, p), f->str[Sdomain], display->white);
          280                 center(tinyfont, r.min, f->str[Sdomain], display->black);
          281         }
          282 }
          283 
          284 void
          285 updatetimes(void)
          286 {
          287         int i;
          288         Face *f;
          289 
          290         for(i=0; i<nfaces; i++){
          291                 f = faces[i];
          292                 if(f == nil)
          293                         continue;
          294                 if(((long)(now - f->time) <= HhmmTime) != f->recent)
          295                         drawface(f, i);
          296         }
          297 }
          298 
          299 void
          300 setlast(void)
          301 {
          302         last = first+nacross*ndown;
          303         if(last > nfaces)
          304                 last = nfaces;
          305 }
          306 
          307 void
          308 drawarrows(void)
          309 {
          310         Point p;
          311 
          312         p = enddate;
          313         p.x += Facesep;
          314         if(p.x & 1)
          315                 p.x++;        /* align background texture */
          316         leftr = rectaddpt(leftright, p);
          317         p.x += Dx(leftright) + Facesep;
          318         rightr = rectaddpt(leftright, p);
          319         draw(screen, leftr, first>0? blue : bgrnd, left, leftright.min);
          320         draw(screen, rightr, last<nfaces? blue : bgrnd, right, leftright.min);
          321 }
          322 
          323 void
          324 addface(Face *f)        /* always adds at 0 */
          325 {
          326         Face **ofaces;
          327         Rectangle r0, r1, r;
          328         int y, nx, ny;
          329 
          330         if(f == nil)
          331                 return;
          332         if(first != 0){
          333                 first = 0;
          334                 eresized(0);
          335         }
          336         findbit(f);
          337 
          338         nx = nacross;
          339         ny = (nfaces+(nx-1)) / nx;
          340 
          341         lockdisplay(display);
          342         for(y=ny; y>=0; y--){
          343                 /* move them along */
          344                 r0 = facerect(y*nx+0);
          345                 r1 = facerect(y*nx+1);
          346                 r = r1;
          347                 r.max.x = r.min.x + (nx - 1)*(Facesize+Facesep);
          348                 draw(screen, r, screen, nil, r0.min);
          349                 /* copy one down from row above */
          350                 if(y != 0){
          351                         r = facerect((y-1)*nx+nx-1);
          352                         draw(screen, r0, screen, nil, r.min);
          353                 }
          354         }
          355 
          356         ofaces = faces;
          357         faces = emalloc((nfaces+1)*sizeof(Face*));
          358         memmove(faces+1, ofaces, nfaces*(sizeof(Face*)));
          359         free(ofaces);
          360         nfaces++;
          361         setlast();
          362         drawarrows();
          363         faces[0] = f;
          364         drawface(f, 0);
          365         flushimage(display, 1);
          366         unlockdisplay(display);
          367 }
          368 
          369 void
          370 loadmboxfaces(char *maildir)
          371 {
          372         CFid *dirfd;
          373         Dir *d;
          374         int i, n;
          375 
          376         dirfd = fsopen(mailfs, maildir, OREAD);
          377         if(dirfd != nil){
          378                 while((n = fsdirread(dirfd, &d)) > 0){
          379                         for(i=0; i<n; i++)
          380                                 addface(dirface(maildir, d[i].name));
          381                         free(d);
          382                 }
          383                 fsclose(dirfd);
          384         }else
          385                 sysfatal("open %s: %r", maildir);
          386 }
          387 
          388 void
          389 freeface(Face *f)
          390 {
          391         int i;
          392 
          393         if(f->file!=nil && f->bit!=f->file->image)
          394                 freeimage(f->bit);
          395         freefacefile(f->file);
          396         for(i=0; i<Nstring; i++)
          397                 free(f->str[i]);
          398         free(f);
          399 }
          400 
          401 void
          402 delface(int j)
          403 {
          404         Rectangle r0, r1, r;
          405         int nx, ny, x, y;
          406 
          407         if(j < first)
          408                 first--;
          409         else if(j < last){
          410                 nx = nacross;
          411                 ny = (nfaces+(nx-1)) / nx;
          412                 x = (j-first)%nx;
          413                 for(y=(j-first)/nx; y<ny; y++){
          414                         if(x != nx-1){
          415                                 /* move them along */
          416                                 r0 = facerect(y*nx+x);
          417                                 r1 = facerect(y*nx+x+1);
          418                                 r = r0;
          419                                 r.max.x = r.min.x + (nx - x - 1)*(Facesize+Facesep);
          420                                 draw(screen, r, screen, nil, r1.min);
          421                         }
          422                         if(y != ny-1){
          423                                 /* copy one up from row below */
          424                                 r = facerect((y+1)*nx);
          425                                 draw(screen, facerect(y*nx+nx-1), screen, nil, r.min);
          426                         }
          427                         x = 0;
          428                 }
          429                 if(last < nfaces)        /* first off-screen becomes visible */
          430                         drawface(faces[last], last-1);
          431                 else{
          432                         /* clear final spot */
          433                         r = facerect(last-first-1);
          434                         draw(screen, r, bgrnd, nil, r.min);
          435                 }
          436         }
          437         freeface(faces[j]);
          438         memmove(faces+j, faces+j+1, (nfaces-(j+1))*sizeof(Face*));
          439         nfaces--;
          440         setlast();
          441         drawarrows();
          442 }
          443 
          444 void
          445 dodelete(int i)
          446 {
          447         Face *f;
          448 
          449         f = faces[i];
          450         if(history){
          451                 free(f->str[Sshow]);
          452                 f->str[Sshow] = estrdup("");
          453         }else{
          454                 delface(i);
          455                 flushimage(display, 1);
          456         }
          457 }
          458 
          459 void
          460 delete(char *s, char *digest)
          461 {
          462         int i;
          463         Face *f;
          464 
          465         lockdisplay(display);
          466         for(i=0; i<nfaces; i++){
          467                 f = faces[i];
          468                 if(digest != nil){
          469                         if(f->str[Sdigest]!=nil && strcmp(digest, f->str[Sdigest]) == 0){
          470                                 dodelete(i);
          471                                 break;
          472                         }
          473                 }else{
          474                         if(f->str[Sshow] && strcmp(s, f->str[Sshow]) == 0){
          475                                 dodelete(i);
          476                                 break;
          477                         }
          478                 }
          479         }
          480         unlockdisplay(display);
          481 }
          482 
          483 void
          484 faceproc(void)
          485 {
          486         for(;;)
          487                 addface(nextface());
          488 }
          489 
          490 void
          491 resized(void)
          492 {
          493         int i;
          494 
          495         nacross = (Dx(screen->r)-2*facep.x+Facesep)/(Facesize+Facesep);
          496         for(ndown=1; rectinrect(facerect(ndown*nacross), screen->r); ndown++)
          497                 ;
          498         setlast();
          499         draw(screen, screen->r, bgrnd, nil, ZP);
          500         enddate = ZP;
          501         drawtime();
          502         for(i=0; i<nfaces; i++)
          503                 drawface(faces[i], i);
          504         drawarrows();
          505         flushimage(display, 1);
          506 }
          507 
          508 void
          509 eresized(int new)
          510 {
          511         lockdisplay(display);
          512         if(new && getwindow(display, Refnone) < 0) {
          513                 fprint(2, "can't reattach to window\n");
          514                 killall("reattach");
          515         }
          516         resized();
          517         unlockdisplay(display);
          518 }
          519 
          520 void
          521 resizeproc(void *v)
          522 {
          523         USED(v);
          524 
          525         while(recv(mousectl->resizec, 0) == 1)
          526                 eresized(1);
          527 }
          528 
          529 int
          530 getmouse(Mouse *m)
          531 {
          532         static int eof;
          533 
          534         if(eof)
          535                 return 0;
          536         if(readmouse(mousectl) < 0){
          537                 eof = 1;
          538                 m->buttons = 0;
          539                 return 0;
          540         }
          541         *m = mousectl->m;
          542         return 1;
          543 }
          544 
          545 enum
          546 {
          547         Clicksize        = 3,                /* pixels */
          548 };
          549 
          550 int
          551 scroll(int but, Point p)
          552 {
          553         int delta;
          554 
          555         delta = 0;
          556         lockdisplay(display);
          557         if(ptinrect(p, leftr) && first>0){
          558                 if(but == 2)
          559                         delta = -first;
          560                 else{
          561                         delta = nacross;
          562                         if(delta > first)
          563                                 delta = first;
          564                         delta = -delta;
          565                 }
          566         }else if(ptinrect(p, rightr) && last<nfaces){
          567                 if(but == 2)
          568                         delta = (nfaces-nacross*ndown) - first;
          569                 else{
          570                         delta = nacross;
          571                         if(delta > nfaces-last)
          572                                 delta = nfaces-last;
          573                 }
          574         }
          575         first += delta;
          576         last += delta;
          577         unlockdisplay(display);
          578         if(delta)
          579                 eresized(0);
          580         return delta;
          581 }
          582 
          583 void
          584 click(int button, Mouse *m)
          585 {
          586         Point p;
          587         int i;
          588 
          589         p = m->xy;
          590         while(m->buttons == (1<<(button-1)))
          591                 getmouse(m);
          592         if(m->buttons)
          593                 return;
          594         if(abs(p.x-m->xy.x)>Clicksize || abs(p.y-m->xy.y)>Clicksize)
          595                 return;
          596         switch(button){
          597         case 1:
          598                 if(scroll(1, p))
          599                         break;
          600                 if(history){
          601                         /* click clears display */
          602                         lockdisplay(display);
          603                         for(i=0; i<nfaces; i++)
          604                                 freeface(faces[i]);
          605                         free(faces);
          606                         faces=nil;
          607                         nfaces = 0;
          608                         unlockdisplay(display);
          609                         eresized(0);
          610                         return;
          611                 }else{
          612                         for(i=first; i<last; i++)        /* clear vwhois faces */
          613                                 if(ptinrect(p, facerect(i-first))
          614                                 && strstr(faces[i]->str[Sshow], "/XXXvwhois")){
          615                                         lockdisplay(display);
          616                                         delface(i);
          617                                         flushimage(display, 1);
          618                                         unlockdisplay(display);
          619                                         break;
          620                                 }
          621                 }
          622                 break;
          623         case 2:
          624                 scroll(2, p);
          625                 break;
          626         case 3:
          627                 scroll(3, p);
          628                 lockdisplay(display);
          629                 for(i=first; i<last; i++)
          630                         if(ptinrect(p, facerect(i-first))){
          631                                 showmail(faces[i]);
          632                                 break;
          633                         }
          634                 unlockdisplay(display);
          635                 break;
          636         }
          637 }
          638 
          639 void
          640 mouseproc(void *v)
          641 {
          642         Mouse mouse;
          643         USED(v);
          644 
          645         while(getmouse(&mouse)){
          646                 if(mouse.buttons == 1)
          647                         click(1, &mouse);
          648                 else if(mouse.buttons == 2)
          649                         click(2, &mouse);
          650                 else if(mouse.buttons == 4)
          651                         click(3, &mouse);
          652 
          653                 while(mouse.buttons)
          654                         getmouse(&mouse);
          655         }
          656 }
          657 
          658 void
          659 killall(char *s)
          660 {
          661         threadexitsall(s);
          662 }
          663 
          664 void
          665 usage(void)
          666 {
          667         fprint(2, "usage: faces [-hi] [-m maildir] -W winsize\n");
          668         threadexitsall("usage");
          669 }
          670 
          671 void
          672 threadmain(int argc, char *argv[])
          673 {
          674         int i;
          675 
          676         rfork(RFNOTEG);
          677 
          678         ARGBEGIN{
          679         case 'h':
          680                 history++;
          681                 break;
          682         case 'i':
          683                 initload++;
          684                 break;
          685         case 'm':
          686                 addmaildir(EARGF(usage()));
          687                 maildir = nil;
          688                 break;
          689         case 'W':
          690                 winsize = EARGF(usage());
          691                 break;
          692         default:
          693                 usage();
          694         }ARGEND
          695 
          696         if(initdraw(nil, nil, "faces") < 0){
          697                 fprint(2, "faces: initdraw failed: %r\n");
          698                 threadexitsall("initdraw");
          699         }
          700         if(maildir)
          701                 addmaildir(maildir);
          702         init();
          703         unlockdisplay(display);        /* initdraw leaves it locked */
          704         display->locking = 1;        /* tell library we're using the display lock */
          705         setdate();
          706         eresized(0);
          707 
          708         proccreate(timeproc, nil, STACK);
          709         proccreate(mouseproc, nil, STACK);
          710         proccreate(resizeproc, nil, STACK);
          711         if(initload)
          712                 for(i = 0; i < nmaildirs; i++)
          713                         loadmboxfaces(maildirs[i]);
          714         faceproc();
          715         killall(nil);
          716 }