devdraw.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       devdraw.c (45970B)
       ---
            1 #include        "u.h"
            2 #include        "lib.h"
            3 #include        "mem.h"
            4 #include        "dat.h"
            5 #include        "fns.h"
            6 #include        "error.h"
            7 
            8 #define        Image        IMAGE
            9 #include        "draw.h"
           10 #include        "memdraw.h"
           11 #include        "memlayer.h"
           12 #include        "cursor.h"
           13 #include        "screen.h"
           14 
           15 #define blankscreen(x)
           16 #define ishwimage(x) (0)
           17 
           18 enum
           19 {
           20         Qtopdir                = 0,
           21         Qnew,
           22         Qwinname,
           23         Q3rd,
           24         Q2nd,
           25         Qcolormap,
           26         Qctl,
           27         Qdata,
           28         Qrefresh,
           29 };
           30 
           31 /*
           32  * Qid path is:
           33  *         4 bits of file type (qids above)
           34  *        24 bits of mux slot number +1; 0 means not attached to client
           35  */
           36 #define        QSHIFT        4        /* location in qid of client # */
           37 
           38 #define        QID(q)                ((((ulong)(q).path)&0x0000000F)>>0)
           39 #define        CLIENTPATH(q)        ((((ulong)q)&0x7FFFFFF0)>>QSHIFT)
           40 #define        CLIENT(q)        CLIENTPATH((q).path)
           41 
           42 #define        NHASH                (1<<5)
           43 #define        HASHMASK        (NHASH-1)
           44 #define        IOUNIT                (64*1024)
           45 
           46 typedef struct Client Client;
           47 typedef struct Draw Draw;
           48 typedef struct DImage DImage;
           49 typedef struct DScreen DScreen;
           50 typedef struct CScreen CScreen;
           51 typedef struct FChar FChar;
           52 typedef struct Refresh Refresh;
           53 typedef struct Refx Refx;
           54 typedef struct DName DName;
           55 
           56 ulong blanktime = 30;        /* in minutes; a half hour */
           57 
           58 struct Draw
           59 {
           60         int                clientid;
           61         int                nclient;
           62         Client**        client;
           63         int                nname;
           64         DName*                name;
           65         int                vers;
           66         int                softscreen;
           67         int                blanked;        /* screen turned off */
           68         ulong                blanktime;        /* time of last operation */
           69         ulong                savemap[3*256];
           70 };
           71 
           72 struct Client
           73 {
           74         Ref                r;
           75         DImage*                dimage[NHASH];
           76         CScreen*        cscreen;
           77         Refresh*        refresh;
           78         Rendez                refrend;
           79         uchar*                readdata;
           80         int                nreaddata;
           81         int                busy;
           82         int                clientid;
           83         int                slot;
           84         int                refreshme;
           85         int                infoid;
           86         int                op;
           87 };
           88 
           89 struct Refresh
           90 {
           91         DImage*                dimage;
           92         Rectangle        r;
           93         Refresh*        next;
           94 };
           95 
           96 struct Refx
           97 {
           98         Client*                client;
           99         DImage*                dimage;
          100 };
          101 
          102 struct DName
          103 {
          104         char                *name;
          105         Client                *client;
          106         DImage*                dimage;
          107         int                vers;
          108 };
          109 
          110 struct FChar
          111 {
          112         int                minx;        /* left edge of bits */
          113         int                maxx;        /* right edge of bits */
          114         uchar                miny;        /* first non-zero scan-line */
          115         uchar                maxy;        /* last non-zero scan-line + 1 */
          116         schar                left;        /* offset of baseline */
          117         uchar                width;        /* width of baseline */
          118 };
          119 
          120 /*
          121  * Reference counts in DImages:
          122  *        one per open by original client
          123  *        one per screen image or fill
          124  *         one per image derived from this one by name
          125  */
          126 struct DImage
          127 {
          128         int                id;
          129         int                ref;
          130         char                *name;
          131         int                vers;
          132         Memimage*        image;
          133         int                ascent;
          134         int                nfchar;
          135         FChar*                fchar;
          136         DScreen*        dscreen;        /* 0 if not a window */
          137         DImage*                fromname;        /* image this one is derived from, by name */
          138         DImage*                next;
          139 };
          140 
          141 struct CScreen
          142 {
          143         DScreen*        dscreen;
          144         CScreen*        next;
          145 };
          146 
          147 struct DScreen
          148 {
          149         int                id;
          150         int                public;
          151         int                ref;
          152         DImage                *dimage;
          153         DImage                *dfill;
          154         Memscreen*        screen;
          155         Client*                owner;
          156         DScreen*        next;
          157 };
          158 
          159 static        Draw                sdraw;
          160         QLock        drawlock;
          161 
          162 static        Memimage        *screenimage;
          163 static        DImage*        screendimage;
          164 static        char        screenname[40];
          165 static        int        screennameid;
          166 
          167 static        Rectangle        flushrect;
          168 static        int                waste;
          169 static        DScreen*        dscreen;
          170 extern        void                flushmemscreen(Rectangle);
          171         void                drawmesg(Client*, void*, int);
          172         void                drawuninstall(Client*, int);
          173         void                drawfreedimage(DImage*);
          174         Client*                drawclientofpath(ulong);
          175         DImage*        allocdimage(Memimage*);
          176 
          177 static        char Enodrawimage[] =        "unknown id for draw image";
          178 static        char Enodrawscreen[] =        "unknown id for draw screen";
          179 static        char Eshortdraw[] =        "short draw message";
          180 static        char Eshortread[] =        "draw read too short";
          181 static        char Eimageexists[] =        "image id in use";
          182 static        char Escreenexists[] =        "screen id in use";
          183 static        char Edrawmem[] =        "image memory allocation failed";
          184 static        char Ereadoutside[] =        "readimage outside image";
          185 static        char Ewriteoutside[] =        "writeimage outside image";
          186 static        char Enotfont[] =        "image not a font";
          187 static        char Eindex[] =                "character index out of range";
          188 static        char Enoclient[] =        "no such draw client";
          189 static        char Enameused[] =        "image name in use";
          190 static        char Enoname[] =        "no image with that name";
          191 static        char Eoldname[] =        "named image no longer valid";
          192 static        char Enamed[] =         "image already has name";
          193 static        char Ewrongname[] =         "wrong name for image";
          194 
          195 void
          196 drawqlock(void)
          197 {
          198         qlock(&drawlock);
          199 }
          200 
          201 int
          202 drawcanqlock(void)
          203 {
          204         return canqlock(&drawlock);
          205 }
          206 
          207 void
          208 drawqunlock(void)
          209 {
          210         qunlock(&drawlock);
          211 }
          212 
          213 static int
          214 drawgen(Chan *c, char *_, Dirtab *__, int ___, int s, Dir *dp)
          215 {
          216         int t;
          217         Qid q;
          218         ulong path;
          219         Client *cl;
          220 
          221         q.vers = 0;
          222 
          223         if(s == DEVDOTDOT){
          224                 switch(QID(c->qid)){
          225                 case Qtopdir:
          226                 case Q2nd:
          227                         mkqid(&q, Qtopdir, 0, QTDIR);
          228                         devdir(c, q, "#i", 0, eve, 0500, dp);
          229                         break;
          230                 case Q3rd:
          231                         cl = drawclientofpath(c->qid.path);
          232                         if(cl == nil)
          233                                 strcpy(up->genbuf, "??");
          234                         else
          235                                 sprint(up->genbuf, "%d", cl->clientid);
          236                         mkqid(&q, Q2nd, 0, QTDIR);
          237                         devdir(c, q, up->genbuf, 0, eve, 0500, dp);
          238                         break;
          239                 default:
          240                         panic("drawwalk %llux", c->qid.path);
          241                 }
          242                 return 1;
          243         }
          244 
          245         /*
          246          * Top level directory contains the name of the device.
          247          */
          248         t = QID(c->qid);
          249         if(t == Qtopdir){
          250                 switch(s){
          251                 case 0:
          252                         mkqid(&q, Q2nd, 0, QTDIR);
          253                         devdir(c, q, "draw", 0, eve, 0555, dp);
          254                         break;
          255                 case 1:
          256                         mkqid(&q, Qwinname, 0, 0);
          257                         devdir(c, q, "winname", 0, eve, 0444, dp);
          258                         break;
          259                 default:
          260                         return -1;
          261                 }
          262                 return 1;
          263         }
          264 
          265         /*
          266          * Second level contains "new" plus all the clients.
          267          */
          268         if(t == Q2nd || t == Qnew){
          269                 if(s == 0){
          270                         mkqid(&q, Qnew, 0, QTFILE);
          271                         devdir(c, q, "new", 0, eve, 0666, dp);
          272                 }
          273                 else if(s <= sdraw.nclient){
          274                         cl = sdraw.client[s-1];
          275                         if(cl == 0)
          276                                 return 0;
          277                         sprint(up->genbuf, "%d", cl->clientid);
          278                         mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR);
          279                         devdir(c, q, up->genbuf, 0, eve, 0555, dp);
          280                         return 1;
          281                 }
          282                 else
          283                         return -1;
          284                 return 1;
          285         }
          286 
          287         /*
          288          * Third level.
          289          */
          290         path = c->qid.path&~((1<<QSHIFT)-1);        /* slot component */
          291         q.vers = c->qid.vers;
          292         q.type = QTFILE;
          293         switch(s){
          294         case 0:
          295                 q.path = path|Qcolormap;
          296                 devdir(c, q, "colormap", 0, eve, 0600, dp);
          297                 break;
          298         case 1:
          299                 q.path = path|Qctl;
          300                 devdir(c, q, "ctl", 0, eve, 0600, dp);
          301                 break;
          302         case 2:
          303                 q.path = path|Qdata;
          304                 devdir(c, q, "data", 0, eve, 0600, dp);
          305                 break;
          306         case 3:
          307                 q.path = path|Qrefresh;
          308                 devdir(c, q, "refresh", 0, eve, 0400, dp);
          309                 break;
          310         default:
          311                 return -1;
          312         }
          313         return 1;
          314 }
          315 
          316 static
          317 int
          318 drawrefactive(void *a)
          319 {
          320         Client *c;
          321 
          322         c = a;
          323         return c->refreshme || c->refresh!=0;
          324 }
          325 
          326 static
          327 void
          328 drawrefreshscreen(DImage *l, Client *client)
          329 {
          330         while(l != nil && l->dscreen == nil)
          331                 l = l->fromname;
          332         if(l != nil && l->dscreen->owner != client)
          333                 l->dscreen->owner->refreshme = 1;
          334 }
          335 
          336 static
          337 void
          338 drawrefresh(Memimage *m, Rectangle r, void *v)
          339 {
          340         Refx *x;
          341         DImage *d;
          342         Client *c;
          343         Refresh *ref;
          344 
          345         if(v == 0)
          346                 return;
          347         x = v;
          348         c = x->client;
          349         d = x->dimage;
          350         for(ref=c->refresh; ref; ref=ref->next)
          351                 if(ref->dimage == d){
          352                         combinerect(&ref->r, r);
          353                         return;
          354                 }
          355         ref = malloc(sizeof(Refresh));
          356         if(ref){
          357                 ref->dimage = d;
          358                 ref->r = r;
          359                 ref->next = c->refresh;
          360                 c->refresh = ref;
          361         }
          362 }
          363 
          364 static void
          365 addflush(Rectangle r)
          366 {
          367         int abb, ar, anbb;
          368         Rectangle nbb;
          369 
          370         if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
          371                 return;
          372 
          373         if(flushrect.min.x >= flushrect.max.x){
          374                 flushrect = r;
          375                 waste = 0;
          376                 return;
          377         }
          378         nbb = flushrect;
          379         combinerect(&nbb, r);
          380         ar = Dx(r)*Dy(r);
          381         abb = Dx(flushrect)*Dy(flushrect);
          382         anbb = Dx(nbb)*Dy(nbb);
          383         /*
          384          * Area of new waste is area of new bb minus area of old bb,
          385          * less the area of the new segment, which we assume is not waste.
          386          * This could be negative, but that's OK.
          387          */
          388         waste += anbb-abb - ar;
          389         if(waste < 0)
          390                 waste = 0;
          391         /*
          392          * absorb if:
          393          *        total area is small
          394          *        waste is less than half total area
          395          *         rectangles touch
          396          */
          397         if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){
          398                 flushrect = nbb;
          399                 return;
          400         }
          401         /* emit current state */
          402         if(flushrect.min.x < flushrect.max.x)
          403                 flushmemscreen(flushrect);
          404         flushrect = r;
          405         waste = 0;
          406 }
          407 
          408 static
          409 void
          410 dstflush(int dstid, Memimage *dst, Rectangle r)
          411 {
          412         Memlayer *l;
          413 
          414         if(dstid == 0){
          415                 combinerect(&flushrect, r);
          416                 return;
          417         }
          418         /* how can this happen? -rsc, dec 12 2002 */
          419         if(dst == 0){
          420                 print("nil dstflush\n");
          421                 return;
          422         }
          423         l = dst->layer;
          424         if(l == nil)
          425                 return;
          426         do{
          427                 if(l->screen->image->data != screenimage->data)
          428                         return;
          429                 r = rectaddpt(r, l->delta);
          430                 l = l->screen->image->layer;
          431         }while(l);
          432         addflush(r);
          433 }
          434 
          435 void
          436 drawflush(void)
          437 {
          438         if(flushrect.min.x < flushrect.max.x)
          439                 flushmemscreen(flushrect);
          440         flushrect = Rect(10000, 10000, -10000, -10000);
          441 }
          442 
          443 static
          444 int
          445 drawcmp(char *a, char *b, int n)
          446 {
          447         if(strlen(a) != n)
          448                 return 1;
          449         return memcmp(a, b, n);
          450 }
          451 
          452 DName*
          453 drawlookupname(int n, char *str)
          454 {
          455         DName *name, *ename;
          456 
          457         name = sdraw.name;
          458         ename = &name[sdraw.nname];
          459         for(; name<ename; name++)
          460                 if(drawcmp(name->name, str, n) == 0)
          461                         return name;
          462         return 0;
          463 }
          464 
          465 int
          466 drawgoodname(DImage *d)
          467 {
          468         DName *n;
          469 
          470         /* if window, validate the screen's own images */
          471         if(d->dscreen)
          472                 if(drawgoodname(d->dscreen->dimage) == 0
          473                 || drawgoodname(d->dscreen->dfill) == 0)
          474                         return 0;
          475         if(d->name == nil)
          476                 return 1;
          477         n = drawlookupname(strlen(d->name), d->name);
          478         if(n==nil || n->vers!=d->vers)
          479                 return 0;
          480         return 1;
          481 }
          482 
          483 DImage*
          484 drawlookup(Client *client, int id, int checkname)
          485 {
          486         DImage *d;
          487 
          488         d = client->dimage[id&HASHMASK];
          489         while(d){
          490                 if(d->id == id){
          491                         if(checkname && !drawgoodname(d))
          492                                 error(Eoldname);
          493                         return d;
          494                 }
          495                 d = d->next;
          496         }
          497         return 0;
          498 }
          499 
          500 DScreen*
          501 drawlookupdscreen(int id)
          502 {
          503         DScreen *s;
          504 
          505         s = dscreen;
          506         while(s){
          507                 if(s->id == id)
          508                         return s;
          509                 s = s->next;
          510         }
          511         return 0;
          512 }
          513 
          514 DScreen*
          515 drawlookupscreen(Client *client, int id, CScreen **cs)
          516 {
          517         CScreen *s;
          518 
          519         s = client->cscreen;
          520         while(s){
          521                 if(s->dscreen->id == id){
          522                         *cs = s;
          523                         return s->dscreen;
          524                 }
          525                 s = s->next;
          526         }
          527         error(Enodrawscreen);
          528         for(;;);
          529 }
          530 
          531 DImage*
          532 allocdimage(Memimage *i)
          533 {
          534         DImage *d;
          535 
          536         d = malloc(sizeof(DImage));
          537         if(d == 0)
          538                 return 0;
          539         d->ref = 1;
          540         d->name = 0;
          541         d->vers = 0;
          542         d->image = i;
          543         d->nfchar = 0;
          544         d->fchar = 0;
          545         d->fromname = 0;
          546         return d;
          547 }
          548 
          549 Memimage*
          550 drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
          551 {
          552         DImage *d;
          553 
          554         d = allocdimage(i);
          555         if(d == 0)
          556                 return 0;
          557         d->id = id;
          558         d->dscreen = dscreen;
          559         d->next = client->dimage[id&HASHMASK];
          560         client->dimage[id&HASHMASK] = d;
          561         return i;
          562 }
          563 
          564 Memscreen*
          565 drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
          566 {
          567         Memscreen *s;
          568         CScreen *c;
          569 
          570         c = malloc(sizeof(CScreen));
          571         if(dimage && dimage->image && dimage->image->chan == 0)
          572                 panic("bad image %p in drawinstallscreen", dimage->image);
          573 
          574         if(c == 0)
          575                 return 0;
          576         if(d == 0){
          577                 d = malloc(sizeof(DScreen));
          578                 if(d == 0){
          579                         free(c);
          580                         return 0;
          581                 }
          582                 s = malloc(sizeof(Memscreen));
          583                 if(s == 0){
          584                         free(c);
          585                         free(d);
          586                         return 0;
          587                 }
          588                 s->frontmost = 0;
          589                 s->rearmost = 0;
          590                 d->dimage = dimage;
          591                 if(dimage){
          592                         s->image = dimage->image;
          593                         dimage->ref++;
          594                 }
          595                 d->dfill = dfill;
          596                 if(dfill){
          597                         s->fill = dfill->image;
          598                         dfill->ref++;
          599                 }
          600                 d->ref = 0;
          601                 d->id = id;
          602                 d->screen = s;
          603                 d->public = public;
          604                 d->next = dscreen;
          605                 d->owner = client;
          606                 dscreen = d;
          607         }
          608         c->dscreen = d;
          609         d->ref++;
          610         c->next = client->cscreen;
          611         client->cscreen = c;
          612         return d->screen;
          613 }
          614 
          615 void
          616 drawdelname(DName *name)
          617 {
          618         int i;
          619 
          620         i = name-sdraw.name;
          621         memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
          622         sdraw.nname--;
          623 }
          624 
          625 void
          626 drawfreedscreen(DScreen *this)
          627 {
          628         DScreen *ds, *next;
          629 
          630         this->ref--;
          631         if(this->ref < 0)
          632                 print("negative ref in drawfreedscreen\n");
          633         if(this->ref > 0)
          634                 return;
          635         ds = dscreen;
          636         if(ds == this){
          637                 dscreen = this->next;
          638                 goto Found;
          639         }
          640         while((next = ds->next)){        /* assign = */
          641                 if(next == this){
          642                         ds->next = this->next;
          643                         goto Found;
          644                 }
          645                 ds = next;
          646         }
          647         error(Enodrawimage);
          648 
          649     Found:
          650         if(this->dimage)
          651                 drawfreedimage(this->dimage);
          652         if(this->dfill)
          653                 drawfreedimage(this->dfill);
          654         free(this->screen);
          655         free(this);
          656 }
          657 
          658 void
          659 drawfreedimage(DImage *dimage)
          660 {
          661         int i;
          662         Memimage *l;
          663         DScreen *ds;
          664 
          665         dimage->ref--;
          666         if(dimage->ref < 0)
          667                 print("negative ref in drawfreedimage\n");
          668         if(dimage->ref > 0)
          669                 return;
          670 
          671         /* any names? */
          672         for(i=0; i<sdraw.nname; )
          673                 if(sdraw.name[i].dimage == dimage)
          674                         drawdelname(sdraw.name+i);
          675                 else
          676                         i++;
          677         if(dimage->fromname){        /* acquired by name; owned by someone else*/
          678                 drawfreedimage(dimage->fromname);
          679                 goto Return;
          680         }
          681 //        if(dimage->image == screenimage)        /* don't free the display */
          682 //                goto Return;
          683         ds = dimage->dscreen;
          684         l = dimage->image;
          685         dimage->dscreen = nil;        /* paranoia */
          686         dimage->image = nil;
          687         if(ds){
          688                 if(l->data == screenimage->data)
          689                         addflush(l->layer->screenr);
          690                 if(l->layer->refreshfn == drawrefresh)        /* else true owner will clean up */
          691                         free(l->layer->refreshptr);
          692                 l->layer->refreshptr = nil;
          693                 if(drawgoodname(dimage))
          694                         memldelete(l);
          695                 else
          696                         memlfree(l);
          697                 drawfreedscreen(ds);
          698         }else
          699                 freememimage(l);
          700     Return:
          701         free(dimage->fchar);
          702         free(dimage);
          703 }
          704 
          705 void
          706 drawuninstallscreen(Client *client, CScreen *this)
          707 {
          708         CScreen *cs, *next;
          709 
          710         cs = client->cscreen;
          711         if(cs == this){
          712                 client->cscreen = this->next;
          713                 drawfreedscreen(this->dscreen);
          714                 free(this);
          715                 return;
          716         }
          717         while((next = cs->next)){        /* assign = */
          718                 if(next == this){
          719                         cs->next = this->next;
          720                         drawfreedscreen(this->dscreen);
          721                         free(this);
          722                         return;
          723                 }
          724                 cs = next;
          725         }
          726 }
          727 
          728 void
          729 drawuninstall(Client *client, int id)
          730 {
          731         DImage *d, *next;
          732 
          733         d = client->dimage[id&HASHMASK];
          734         if(d == 0)
          735                 error(Enodrawimage);
          736         if(d->id == id){
          737                 client->dimage[id&HASHMASK] = d->next;
          738                 drawfreedimage(d);
          739                 return;
          740         }
          741         while((next = d->next)){        /* assign = */
          742                 if(next->id == id){
          743                         d->next = next->next;
          744                         drawfreedimage(next);
          745                         return;
          746                 }
          747                 d = next;
          748         }
          749         error(Enodrawimage);
          750 }
          751 
          752 void
          753 drawaddname(Client *client, DImage *di, int n, char *str)
          754 {
          755         DName *name, *ename, *new, *t;
          756 
          757         name = sdraw.name;
          758         ename = &name[sdraw.nname];
          759         for(; name<ename; name++)
          760                 if(drawcmp(name->name, str, n) == 0)
          761                         error(Enameused);
          762         t = smalloc((sdraw.nname+1)*sizeof(DName));
          763         memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
          764         free(sdraw.name);
          765         sdraw.name = t;
          766         new = &sdraw.name[sdraw.nname++];
          767         new->name = smalloc(n+1);
          768         memmove(new->name, str, n);
          769         new->name[n] = 0;
          770         new->dimage = di;
          771         new->client = client;
          772         new->vers = ++sdraw.vers;
          773 }
          774 
          775 Client*
          776 drawnewclient(void)
          777 {
          778         Client *cl, **cp;
          779         int i;
          780 
          781         for(i=0; i<sdraw.nclient; i++){
          782                 cl = sdraw.client[i];
          783                 if(cl == 0)
          784                         break;
          785         }
          786         if(i == sdraw.nclient){
          787                 cp = malloc((sdraw.nclient+1)*sizeof(Client*));
          788                 if(cp == 0)
          789                         return 0;
          790                 memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));
          791                 free(sdraw.client);
          792                 sdraw.client = cp;
          793                 sdraw.nclient++;
          794                 cp[i] = 0;
          795         }
          796         cl = malloc(sizeof(Client));
          797         if(cl == 0)
          798                 return 0;
          799         memset(cl, 0, sizeof(Client));
          800         cl->slot = i;
          801         cl->clientid = ++sdraw.clientid;
          802         cl->op = SoverD;
          803         sdraw.client[i] = cl;
          804         return cl;
          805 }
          806 
          807 static int
          808 drawclientop(Client *cl)
          809 {
          810         int op;
          811 
          812         op = cl->op;
          813         cl->op = SoverD;
          814         return op;
          815 }
          816 
          817 int
          818 drawhasclients(void)
          819 {
          820         /*
          821          * if draw has ever been used, we can't resize the frame buffer,
          822          * even if all clients have exited (nclients is cumulative); it's too
          823          * hard to make work.
          824          */
          825         return sdraw.nclient != 0;
          826 }
          827 
          828 Client*
          829 drawclientofpath(ulong path)
          830 {
          831         Client *cl;
          832         int slot;
          833 
          834         slot = CLIENTPATH(path);
          835         if(slot == 0)
          836                 return nil;
          837         cl = sdraw.client[slot-1];
          838         if(cl==0 || cl->clientid==0)
          839                 return nil;
          840         return cl;
          841 }
          842 
          843 
          844 Client*
          845 drawclient(Chan *c)
          846 {
          847         Client *client;
          848 
          849         client = drawclientofpath(c->qid.path);
          850         if(client == nil)
          851                 error(Enoclient);
          852         return client;
          853 }
          854 
          855 Memimage*
          856 drawimage(Client *client, uchar *a)
          857 {
          858         DImage *d;
          859 
          860         d = drawlookup(client, BGLONG(a), 1);
          861         if(d == nil)
          862                 error(Enodrawimage);
          863         return d->image;
          864 }
          865 
          866 void
          867 drawrectangle(Rectangle *r, uchar *a)
          868 {
          869         r->min.x = BGLONG(a+0*4);
          870         r->min.y = BGLONG(a+1*4);
          871         r->max.x = BGLONG(a+2*4);
          872         r->max.y = BGLONG(a+3*4);
          873 }
          874 
          875 void
          876 drawpoint(Point *p, uchar *a)
          877 {
          878         p->x = BGLONG(a+0*4);
          879         p->y = BGLONG(a+1*4);
          880 }
          881 
          882 Point
          883 drawchar(Memimage *dst, Memimage *rdst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
          884 {
          885         FChar *fc;
          886         Rectangle r;
          887         Point sp1;
          888         static Memimage *tmp;
          889 
          890         fc = &font->fchar[index];
          891         r.min.x = p.x+fc->left;
          892         r.min.y = p.y-(font->ascent-fc->miny);
          893         r.max.x = r.min.x+(fc->maxx-fc->minx);
          894         r.max.y = r.min.y+(fc->maxy-fc->miny);
          895         sp1.x = sp->x+fc->left;
          896         sp1.y = sp->y+fc->miny;
          897 
          898         /*
          899          * If we're drawing greyscale fonts onto a VGA screen,
          900          * it's very costly to read the screen memory to do the
          901          * alpha blending inside memdraw.  If this is really a stringbg,
          902          * then rdst is the bg image (in main memory) which we can
          903          * refer to for the underlying dst pixels instead of reading dst
          904          * directly.
          905          */
          906         if(ishwimage(dst) && !ishwimage(rdst) && font->image->depth > 1){
          907                 if(tmp == nil || tmp->chan != dst->chan || Dx(tmp->r) < Dx(r) || Dy(tmp->r) < Dy(r)){
          908                         if(tmp)
          909                                 freememimage(tmp);
          910                         tmp = allocmemimage(Rect(0,0,Dx(r),Dy(r)), dst->chan);
          911                         if(tmp == nil)
          912                                 goto fallback;
          913                 }
          914                 memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), rdst, r.min, memopaque, ZP, S);
          915                 memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), src, sp1, font->image, Pt(fc->minx, fc->miny), op);
          916                 memdraw(dst, r, tmp, ZP, memopaque, ZP, S);
          917         }else{
          918         fallback:
          919                 memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
          920         }
          921 
          922         p.x += fc->width;
          923         sp->x += fc->width;
          924         return p;
          925 }
          926 
          927 static DImage*
          928 makescreenimage(void)
          929 {
          930         void *X;
          931         int width, depth;
          932         ulong chan;
          933         DImage *di;
          934         Memdata *md;
          935         Memimage *i;
          936         Rectangle r;
          937 
          938         md = malloc(sizeof *md);
          939         if(md == nil)
          940                 return nil;
          941         md->allocd = 1;
          942         md->base = nil;
          943         md->bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen, &X);
          944         if(md->bdata == nil){
          945                 free(md);
          946                 return nil;
          947         }
          948         md->ref = 1;
          949         i = allocmemimaged(r, chan, md, X);
          950         if(i == nil){
          951                 free(md);
          952                 return nil;
          953         }
          954         i->width = width;
          955         i->clipr = r;
          956 
          957         di = allocdimage(i);
          958         if(di == nil){
          959                 freememimage(i);        /* frees md */
          960                 return nil;
          961         }
          962         if(!waserror()){
          963                 snprint(screenname, sizeof screenname, "noborder.screen.%d", ++screennameid);
          964                 drawaddname(nil, di, strlen(screenname), screenname);
          965                 poperror();
          966         }
          967         return di;
          968 }
          969 
          970 static int
          971 initscreenimage(void)
          972 {
          973         if(screenimage != nil)
          974                 return 1;
          975 
          976         screendimage = makescreenimage();
          977         if(screendimage == nil)
          978                 return 0;
          979         screenimage = screendimage->image;
          980 // iprint("initscreenimage %p %p\n", screendimage, screenimage);
          981         mouseresize();
          982         return 1;
          983 }
          984 
          985 void
          986 deletescreenimage(void)
          987 {
          988         drawqlock();
          989         if(screenimage){
          990                 /* will be freed via screendimage; disable */
          991                 screenimage->clipr = ZR;
          992                 screenimage = nil;
          993         }
          994         if(screendimage){
          995                 drawfreedimage(screendimage);
          996                 screendimage = nil;
          997         }
          998         drawqunlock();
          999 }
         1000 
         1001 void
         1002 resetscreenimage(void)
         1003 {
         1004         drawqlock();
         1005         initscreenimage();
         1006         drawqunlock();
         1007 }
         1008 
         1009 static Chan*
         1010 drawattach(char *spec)
         1011 {
         1012         drawqlock();
         1013         if(!conf.monitor || !initscreenimage()){
         1014                 drawqunlock();
         1015                 error("no frame buffer");
         1016         }
         1017         drawqunlock();
         1018         return devattach('i', spec);
         1019 }
         1020 
         1021 static Walkqid*
         1022 drawwalk(Chan *c, Chan *nc, char **name, int nname)
         1023 {
         1024         if(screenimage == nil)
         1025                 error("no frame buffer");
         1026         return devwalk(c, nc, name, nname, 0, 0, drawgen);
         1027 }
         1028 
         1029 static int
         1030 drawstat(Chan *c, uchar *db, int n)
         1031 {
         1032         return devstat(c, db, n, 0, 0, drawgen);
         1033 }
         1034 
         1035 static Chan*
         1036 drawopen(Chan *c, int omode)
         1037 {
         1038         Client *cl;
         1039         DName *dn;
         1040         DImage *di;
         1041 
         1042         if(c->qid.type & QTDIR){
         1043                 c = devopen(c, omode, 0, 0, drawgen);
         1044                 c->iounit = IOUNIT;
         1045         }
         1046 
         1047         drawqlock();
         1048         if(waserror()){
         1049                 drawqunlock();
         1050                 nexterror();
         1051         }
         1052 
         1053         if(QID(c->qid) == Qnew){
         1054                 cl = drawnewclient();
         1055                 if(cl == 0)
         1056                         error(Enodev);
         1057                 c->qid.path = Qctl|((cl->slot+1)<<QSHIFT);
         1058         }
         1059 
         1060         switch(QID(c->qid)){
         1061         case Qwinname:
         1062                 break;
         1063 
         1064         case Qnew:
         1065                 break;
         1066 
         1067         case Qctl:
         1068                 cl = drawclient(c);
         1069                 if(cl->busy)
         1070                         error(Einuse);
         1071                 cl->busy = 1;
         1072                 flushrect = Rect(10000, 10000, -10000, -10000);
         1073                 dn = drawlookupname(strlen(screenname), screenname);
         1074                 if(dn == 0)
         1075                         error("draw: cannot happen 2");
         1076                 if(drawinstall(cl, 0, dn->dimage->image, 0) == 0)
         1077                         error(Edrawmem);
         1078                 di = drawlookup(cl, 0, 0);
         1079                 if(di == 0)
         1080                         error("draw: cannot happen 1");
         1081                 di->vers = dn->vers;
         1082                 di->name = smalloc(strlen(screenname)+1);
         1083                 strcpy(di->name, screenname);
         1084                 di->fromname = dn->dimage;
         1085                 di->fromname->ref++;
         1086                 incref(&cl->r);
         1087                 break;
         1088 
         1089         case Qcolormap:
         1090         case Qdata:
         1091         case Qrefresh:
         1092                 cl = drawclient(c);
         1093                 incref(&cl->r);
         1094                 break;
         1095         }
         1096         drawqunlock();
         1097         poperror();
         1098         c->mode = openmode(omode);
         1099         c->flag |= COPEN;
         1100         c->offset = 0;
         1101         c->iounit = IOUNIT;
         1102         return c;
         1103 }
         1104 
         1105 static void
         1106 drawclose(Chan *c)
         1107 {
         1108         int i;
         1109         DImage *d, **dp;
         1110         Client *cl;
         1111         Refresh *r;
         1112 
         1113         if(QID(c->qid) < Qcolormap)        /* Qtopdir, Qnew, Q3rd, Q2nd have no client */
         1114                 return;
         1115         drawqlock();
         1116         if(waserror()){
         1117                 drawqunlock();
         1118                 nexterror();
         1119         }
         1120 
         1121         cl = drawclient(c);
         1122         if(QID(c->qid) == Qctl)
         1123                 cl->busy = 0;
         1124         if((c->flag&COPEN) && (decref(&cl->r)==0)){
         1125                 while((r = cl->refresh)){        /* assign = */
         1126                         cl->refresh = r->next;
         1127                         free(r);
         1128                 }
         1129                 /* free names */
         1130                 for(i=0; i<sdraw.nname; )
         1131                         if(sdraw.name[i].client == cl)
         1132                                 drawdelname(sdraw.name+i);
         1133                         else
         1134                                 i++;
         1135                 while(cl->cscreen)
         1136                         drawuninstallscreen(cl, cl->cscreen);
         1137                 /* all screens are freed, so now we can free images */
         1138                 dp = cl->dimage;
         1139                 for(i=0; i<NHASH; i++){
         1140                         while((d = *dp) != nil){
         1141                                 *dp = d->next;
         1142                                 drawfreedimage(d);
         1143                         }
         1144                         dp++;
         1145                 }
         1146                 sdraw.client[cl->slot] = 0;
         1147                 drawflush();        /* to erase visible, now dead windows */
         1148                 free(cl);
         1149         }
         1150         drawqunlock();
         1151         poperror();
         1152 }
         1153 
         1154 long
         1155 drawread(Chan *c, void *a, long n, vlong off)
         1156 {
         1157         int index, m;
         1158         ulong red, green, blue;
         1159         Client *cl;
         1160         uchar *p;
         1161         Refresh *r;
         1162         DImage *di;
         1163         Memimage *i;
         1164         ulong offset = off;
         1165         char buf[16];
         1166 
         1167         if(c->qid.type & QTDIR)
         1168                 return devdirread(c, a, n, 0, 0, drawgen);
         1169         if(QID(c->qid) == Qwinname)
         1170                 return readstr(off, a, n, screenname);
         1171 
         1172         cl = drawclient(c);
         1173         drawqlock();
         1174         if(waserror()){
         1175                 drawqunlock();
         1176                 nexterror();
         1177         }
         1178         switch(QID(c->qid)){
         1179         case Qctl:
         1180                 if(n < 12*12)
         1181                         error(Eshortread);
         1182                 if(cl->infoid < 0)
         1183                         error(Enodrawimage);
         1184                 if(cl->infoid == 0){
         1185                         i = screenimage;
         1186                         if(i == nil)
         1187                                 error(Enodrawimage);
         1188                 }else{
         1189                         di = drawlookup(cl, cl->infoid, 1);
         1190                         if(di == nil)
         1191                                 error(Enodrawimage);
         1192                         i = di->image;
         1193                 }
         1194                 n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
         1195                         cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl,
         1196                         i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
         1197                         i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
         1198                 cl->infoid = -1;
         1199                 break;
         1200 
         1201         case Qcolormap:
         1202                 drawactive(1);        /* to restore map from backup */
         1203                 p = malloc(4*12*256+1);
         1204                 if(p == 0)
         1205                         error(Enomem);
         1206                 m = 0;
         1207                 for(index = 0; index < 256; index++){
         1208                         getcolor(index, &red, &green, &blue);
         1209                         m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24);
         1210                 }
         1211                 n = readstr(offset, a, n, (char*)p);
         1212                 free(p);
         1213                 break;
         1214 
         1215         case Qdata:
         1216                 if(cl->readdata == nil)
         1217                         error("no draw data");
         1218                 if(n < cl->nreaddata)
         1219                         error(Eshortread);
         1220                 n = cl->nreaddata;
         1221                 memmove(a, cl->readdata, cl->nreaddata);
         1222                 free(cl->readdata);
         1223                 cl->readdata = nil;
         1224                 break;
         1225 
         1226         case Qrefresh:
         1227                 if(n < 5*4)
         1228                         error(Ebadarg);
         1229                 for(;;){
         1230                         if(cl->refreshme || cl->refresh)
         1231                                 break;
         1232                         drawqunlock();
         1233                         if(waserror()){
         1234                                 drawqlock();        /* restore lock for waserror() above */
         1235                                 nexterror();
         1236                         }
         1237                         sleep(&cl->refrend, drawrefactive, cl);
         1238                         poperror();
         1239                         drawqlock();
         1240                 }
         1241                 p = a;
         1242                 while(cl->refresh && n>=5*4){
         1243                         r = cl->refresh;
         1244                         BPLONG(p+0*4, r->dimage->id);
         1245                         BPLONG(p+1*4, r->r.min.x);
         1246                         BPLONG(p+2*4, r->r.min.y);
         1247                         BPLONG(p+3*4, r->r.max.x);
         1248                         BPLONG(p+4*4, r->r.max.y);
         1249                         cl->refresh = r->next;
         1250                         free(r);
         1251                         p += 5*4;
         1252                         n -= 5*4;
         1253                 }
         1254                 cl->refreshme = 0;
         1255                 n = p-(uchar*)a;
         1256                 break;
         1257         }
         1258         drawqunlock();
         1259         poperror();
         1260         return n;
         1261 }
         1262 
         1263 void
         1264 drawwakeall(void)
         1265 {
         1266         Client *cl;
         1267         int i;
         1268 
         1269         for(i=0; i<sdraw.nclient; i++){
         1270                 cl = sdraw.client[i];
         1271                 if(cl && (cl->refreshme || cl->refresh))
         1272                         wakeup(&cl->refrend);
         1273         }
         1274 }
         1275 
         1276 static long
         1277 drawwrite(Chan *c, void *a, long n, vlong _)
         1278 {
         1279         char buf[128], *fields[4], *q;
         1280         Client *cl;
         1281         int i, m, red, green, blue, x;
         1282 
         1283         if(c->qid.type & QTDIR)
         1284                 error(Eisdir);
         1285         cl = drawclient(c);
         1286         drawqlock();
         1287         if(waserror()){
         1288                 drawwakeall();
         1289                 drawqunlock();
         1290                 nexterror();
         1291         }
         1292         switch(QID(c->qid)){
         1293         case Qctl:
         1294                 if(n != 4)
         1295                         error("unknown draw control request");
         1296                 cl->infoid = BGLONG((uchar*)a);
         1297                 break;
         1298 
         1299         case Qcolormap:
         1300                 drawactive(1);        /* to restore map from backup */
         1301                 m = n;
         1302                 n = 0;
         1303                 while(m > 0){
         1304                         x = m;
         1305                         if(x > sizeof(buf)-1)
         1306                                 x = sizeof(buf)-1;
         1307                         q = memccpy(buf, a, '\n', x);
         1308                         if(q == 0)
         1309                                 break;
         1310                         i = q-buf;
         1311                         n += i;
         1312                         a = (char*)a + i;
         1313                         m -= i;
         1314                         *q = 0;
         1315                         if(tokenize(buf, fields, nelem(fields)) != 4)
         1316                                 error(Ebadarg);
         1317                         i = strtoul(fields[0], 0, 0);
         1318                         red = strtoul(fields[1], 0, 0);
         1319                         green = strtoul(fields[2], 0, 0);
         1320                         blue = strtoul(fields[3], &q, 0);
         1321                         if(fields[3] == q)
         1322                                 error(Ebadarg);
         1323                         if(red>255 || green>255 || blue>255 || i<0 || i>255)
         1324                                 error(Ebadarg);
         1325                         red |= red<<8;
         1326                         red |= red<<16;
         1327                         green |= green<<8;
         1328                         green |= green<<16;
         1329                         blue |= blue<<8;
         1330                         blue |= blue<<16;
         1331                         setcolor(i, red, green, blue);
         1332                 }
         1333                 break;
         1334 
         1335         case Qdata:
         1336                 drawmesg(cl, a, n);
         1337                 drawwakeall();
         1338                 break;
         1339 
         1340         default:
         1341                 error(Ebadusefd);
         1342         }
         1343         drawqunlock();
         1344         poperror();
         1345         return n;
         1346 }
         1347 
         1348 uchar*
         1349 drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
         1350 {
         1351         int b, x;
         1352 
         1353         if(p >= maxp)
         1354                 error(Eshortdraw);
         1355         b = *p++;
         1356         x = b & 0x7F;
         1357         if(b & 0x80){
         1358                 if(p+1 >= maxp)
         1359                         error(Eshortdraw);
         1360                 x |= *p++ << 7;
         1361                 x |= *p++ << 15;
         1362                 if(x & (1<<22))
         1363                         x |= ~0<<23;
         1364         }else{
         1365                 if(b & 0x40)
         1366                         x |= ~0<<7;
         1367                 x += oldx;
         1368         }
         1369         *newx = x;
         1370         return p;
         1371 }
         1372 
         1373 static void
         1374 printmesg(char *fmt, uchar *a, int plsprnt)
         1375 {
         1376         char buf[256];
         1377         char *p, *q;
         1378 
         1379         if(1|| plsprnt==0){
         1380                 return;
         1381         }
         1382         q = buf;
         1383         *q++ = *a++;
         1384         for(p=fmt; *p; p++){
         1385                 switch(*p){
         1386                 case 'l':
         1387                         q += sprint(q, " %ld", (long)BGLONG(a));
         1388                         a += 4;
         1389                         break;
         1390                 case 'L':
         1391                         q += sprint(q, " %.8lux", (ulong)BGLONG(a));
         1392                         a += 4;
         1393                         break;
         1394                 case 'R':
         1395                         q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12));
         1396                         a += 16;
         1397                         break;
         1398                 case 'P':
         1399                         q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4));
         1400                         a += 8;
         1401                         break;
         1402                 case 'b':
         1403                         q += sprint(q, " %d", *a++);
         1404                         break;
         1405                 case 's':
         1406                         q += sprint(q, " %d", BGSHORT(a));
         1407                         a += 2;
         1408                         break;
         1409                 case 'S':
         1410                         q += sprint(q, " %.4ux", BGSHORT(a));
         1411                         a += 2;
         1412                         break;
         1413                 }
         1414         }
         1415         *q++ = '\n';
         1416         *q = 0;
         1417         iprint("%.*s", (int)(q-buf), buf);
         1418 }
         1419 
         1420 void
         1421 drawmesg(Client *client, void *av, int n)
         1422 {
         1423         int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
         1424         uchar *u, *a, refresh;
         1425         char *fmt;
         1426         ulong value, chan;
         1427         Rectangle r, clipr;
         1428         Point p, q, *pp, sp;
         1429         Memimage *i, *bg, *dst, *src, *mask;
         1430         Memimage *l, **lp;
         1431         Memscreen *scrn;
         1432         DImage *font, *ll, *di, *ddst, *dsrc;
         1433         DName *dn;
         1434         DScreen *dscrn;
         1435         FChar *fc;
         1436         Refx *refx;
         1437         CScreen *cs;
         1438         Refreshfn reffn;
         1439 
         1440         a = av;
         1441         m = 0;
         1442         fmt = nil;
         1443         if(waserror()){
         1444                 if(fmt) printmesg(fmt, a, 1);
         1445         /*        iprint("error: %s\n", up->errstr);        */
         1446                 nexterror();
         1447         }
         1448         while((n-=m) > 0){
         1449                 a += m;
         1450                 switch(*a){
         1451                 default:
         1452                         error("bad draw command");
         1453                 /* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */
         1454                 case 'b':
         1455                         printmesg(fmt="LLbLbRRL", a, 0);
         1456                         m = 1+4+4+1+4+1+4*4+4*4+4;
         1457                         if(n < m)
         1458                                 error(Eshortdraw);
         1459                         dstid = BGLONG(a+1);
         1460                         scrnid = BGSHORT(a+5);
         1461                         refresh = a[9];
         1462                         chan = BGLONG(a+10);
         1463                         repl = a[14];
         1464                         drawrectangle(&r, a+15);
         1465                         drawrectangle(&clipr, a+31);
         1466                         value = BGLONG(a+47);
         1467                         if(drawlookup(client, dstid, 0))
         1468                                 error(Eimageexists);
         1469                         if(scrnid){
         1470                                 dscrn = drawlookupscreen(client, scrnid, &cs);
         1471                                 scrn = dscrn->screen;
         1472                                 if(repl || chan!=scrn->image->chan)
         1473                                         error("image parameters incompatible with screen");
         1474                                 reffn = nil;
         1475                                 switch(refresh){
         1476                                 case Refbackup:
         1477                                         break;
         1478                                 case Refnone:
         1479                                         reffn = memlnorefresh;
         1480                                         break;
         1481                                 case Refmesg:
         1482                                         reffn = drawrefresh;
         1483                                         break;
         1484                                 default:
         1485                                         error("unknown refresh method");
         1486                                 }
         1487                                 l = memlalloc(scrn, r, reffn, 0, value);
         1488                                 if(l == 0)
         1489                                         error(Edrawmem);
         1490                                 addflush(l->layer->screenr);
         1491                                 l->clipr = clipr;
         1492                                 rectclip(&l->clipr, r);
         1493                                 if(drawinstall(client, dstid, l, dscrn) == 0){
         1494                                         memldelete(l);
         1495                                         error(Edrawmem);
         1496                                 }
         1497                                 dscrn->ref++;
         1498                                 if(reffn){
         1499                                         refx = nil;
         1500                                         if(reffn == drawrefresh){
         1501                                                 refx = malloc(sizeof(Refx));
         1502                                                 if(refx == 0){
         1503                                                         drawuninstall(client, dstid);
         1504                                                         error(Edrawmem);
         1505                                                 }
         1506                                                 refx->client = client;
         1507                                                 refx->dimage = drawlookup(client, dstid, 1);
         1508                                         }
         1509                                         memlsetrefresh(l, reffn, refx);
         1510                                 }
         1511                                 continue;
         1512                         }
         1513                         i = allocmemimage(r, chan);
         1514                         if(i == 0)
         1515                                 error(Edrawmem);
         1516                         if(repl)
         1517                                 i->flags |= Frepl;
         1518                         i->clipr = clipr;
         1519                         if(!repl)
         1520                                 rectclip(&i->clipr, r);
         1521                         if(drawinstall(client, dstid, i, 0) == 0){
         1522                                 freememimage(i);
         1523                                 error(Edrawmem);
         1524                         }
         1525                         memfillcolor(i, value);
         1526                         continue;
         1527 
         1528                 /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
         1529                 case 'A':
         1530                         printmesg(fmt="LLLb", a, 1);
         1531                         m = 1+4+4+4+1;
         1532                         if(n < m)
         1533                                 error(Eshortdraw);
         1534                         dstid = BGLONG(a+1);
         1535                         if(dstid == 0)
         1536                                 error(Ebadarg);
         1537                         if(drawlookupdscreen(dstid))
         1538                                 error(Escreenexists);
         1539                         ddst = drawlookup(client, BGLONG(a+5), 1);
         1540                         dsrc = drawlookup(client, BGLONG(a+9), 1);
         1541                         if(ddst==0 || dsrc==0)
         1542                                 error(Enodrawimage);
         1543                         if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
         1544                                 error(Edrawmem);
         1545                         continue;
         1546 
         1547                 /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
         1548                 case 'c':
         1549                         printmesg(fmt="LbR", a, 0);
         1550                         m = 1+4+1+4*4;
         1551                         if(n < m)
         1552                                 error(Eshortdraw);
         1553                         ddst = drawlookup(client, BGLONG(a+1), 1);
         1554                         if(ddst == nil)
         1555                                 error(Enodrawimage);
         1556                         if(ddst->name)
         1557                                 error("cannot change repl/clipr of shared image");
         1558                         dst = ddst->image;
         1559                         if(a[5])
         1560                                 dst->flags |= Frepl;
         1561                         drawrectangle(&dst->clipr, a+6);
         1562                         continue;
         1563 
         1564                 /* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
         1565                 case 'd':
         1566                         printmesg(fmt="LLLRPP", a, 0);
         1567                         m = 1+4+4+4+4*4+2*4+2*4;
         1568                         if(n < m)
         1569                                 error(Eshortdraw);
         1570                         dst = drawimage(client, a+1);
         1571                         dstid = BGLONG(a+1);
         1572                         src = drawimage(client, a+5);
         1573                         mask = drawimage(client, a+9);
         1574                         drawrectangle(&r, a+13);
         1575                         drawpoint(&p, a+29);
         1576                         drawpoint(&q, a+37);
         1577                         op = drawclientop(client);
         1578                         memdraw(dst, r, src, p, mask, q, op);
         1579                         dstflush(dstid, dst, r);
         1580                         continue;
         1581 
         1582                 /* toggle debugging: 'D' val[1] */
         1583                 case 'D':
         1584                         printmesg(fmt="b", a, 0);
         1585                         m = 1+1;
         1586                         if(n < m)
         1587                                 error(Eshortdraw);
         1588                         drawdebug = a[1];
         1589                         continue;
         1590 
         1591                 /* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
         1592                 case 'e':
         1593                 case 'E':
         1594                         printmesg(fmt="LLPlllPll", a, 0);
         1595                         m = 1+4+4+2*4+4+4+4+2*4+2*4;
         1596                         if(n < m)
         1597                                 error(Eshortdraw);
         1598                         dst = drawimage(client, a+1);
         1599                         dstid = BGLONG(a+1);
         1600                         src = drawimage(client, a+5);
         1601                         drawpoint(&p, a+9);
         1602                         e0 = BGLONG(a+17);
         1603                         e1 = BGLONG(a+21);
         1604                         if(e0<0 || e1<0)
         1605                                 error("invalid ellipse semidiameter");
         1606                         j = BGLONG(a+25);
         1607                         if(j < 0)
         1608                                 error("negative ellipse thickness");
         1609                         drawpoint(&sp, a+29);
         1610                         c = j;
         1611                         if(*a == 'E')
         1612                                 c = -1;
         1613                         ox = BGLONG(a+37);
         1614                         oy = BGLONG(a+41);
         1615                         op = drawclientop(client);
         1616                         /* high bit indicates arc angles are present */
         1617                         if(ox & (1<<31)){
         1618                                 if((ox & (1<<30)) == 0)
         1619                                         ox &= ~(1<<31);
         1620                                 memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
         1621                         }else
         1622                                 memellipse(dst, p, e0, e1, c, src, sp, op);
         1623                         dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
         1624                         continue;
         1625 
         1626                 /* free: 'f' id[4] */
         1627                 case 'f':
         1628                         printmesg(fmt="L", a, 1);
         1629                         m = 1+4;
         1630                         if(n < m)
         1631                                 error(Eshortdraw);
         1632                         ll = drawlookup(client, BGLONG(a+1), 0);
         1633                         if(ll && ll->dscreen && ll->dscreen->owner != client)
         1634                                 ll->dscreen->owner->refreshme = 1;
         1635                         drawuninstall(client, BGLONG(a+1));
         1636                         continue;
         1637 
         1638                 /* free screen: 'F' id[4] */
         1639                 case 'F':
         1640                         printmesg(fmt="L", a, 1);
         1641                         m = 1+4;
         1642                         if(n < m)
         1643                                 error(Eshortdraw);
         1644                         drawlookupscreen(client, BGLONG(a+1), &cs);
         1645                         drawuninstallscreen(client, cs);
         1646                         continue;
         1647 
         1648                 /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
         1649                 case 'i':
         1650                         printmesg(fmt="Llb", a, 1);
         1651                         m = 1+4+4+1;
         1652                         if(n < m)
         1653                                 error(Eshortdraw);
         1654                         dstid = BGLONG(a+1);
         1655                         if(dstid == 0)
         1656                                 error("cannot use display as font");
         1657                         font = drawlookup(client, dstid, 1);
         1658                         if(font == 0)
         1659                                 error(Enodrawimage);
         1660                         if(font->image->layer)
         1661                                 error("cannot use window as font");
         1662                         ni = BGLONG(a+5);
         1663                         if(ni<=0 || ni>4096)
         1664                                 error("bad font size (4096 chars max)");
         1665                         free(font->fchar);        /* should we complain if non-zero? */
         1666                         font->fchar = malloc(ni*sizeof(FChar));
         1667                         if(font->fchar == 0)
         1668                                 error("no memory for font");
         1669                         memset(font->fchar, 0, ni*sizeof(FChar));
         1670                         font->nfchar = ni;
         1671                         font->ascent = a[9];
         1672                         continue;
         1673 
         1674                 /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
         1675                 case 'l':
         1676                         printmesg(fmt="LLSRPbb", a, 0);
         1677                         m = 1+4+4+2+4*4+2*4+1+1;
         1678                         if(n < m)
         1679                                 error(Eshortdraw);
         1680                         font = drawlookup(client, BGLONG(a+1), 1);
         1681                         if(font == 0)
         1682                                 error(Enodrawimage);
         1683                         if(font->nfchar == 0)
         1684                                 error(Enotfont);
         1685                         src = drawimage(client, a+5);
         1686                         ci = BGSHORT(a+9);
         1687                         if(ci >= font->nfchar)
         1688                                 error(Eindex);
         1689                         drawrectangle(&r, a+11);
         1690                         drawpoint(&p, a+27);
         1691                         memdraw(font->image, r, src, p, memopaque, p, S);
         1692                         fc = &font->fchar[ci];
         1693                         fc->minx = r.min.x;
         1694                         fc->maxx = r.max.x;
         1695                         fc->miny = r.min.y;
         1696                         fc->maxy = r.max.y;
         1697                         fc->left = a[35];
         1698                         fc->width = a[36];
         1699                         continue;
         1700 
         1701                 /* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
         1702                 case 'L':
         1703                         printmesg(fmt="LPPlllLP", a, 0);
         1704                         m = 1+4+2*4+2*4+4+4+4+4+2*4;
         1705                         if(n < m)
         1706                                 error(Eshortdraw);
         1707                         dst = drawimage(client, a+1);
         1708                         dstid = BGLONG(a+1);
         1709                         drawpoint(&p, a+5);
         1710                         drawpoint(&q, a+13);
         1711                         e0 = BGLONG(a+21);
         1712                         e1 = BGLONG(a+25);
         1713                         j = BGLONG(a+29);
         1714                         if(j < 0)
         1715                                 error("negative line width");
         1716                         src = drawimage(client, a+33);
         1717                         drawpoint(&sp, a+37);
         1718                         op = drawclientop(client);
         1719                         memline(dst, p, q, e0, e1, j, src, sp, op);
         1720                         /* avoid memlinebbox if possible */
         1721                         if(dstid==0 || dst->layer!=nil){
         1722                                 /* BUG: this is terribly inefficient: update maximal containing rect*/
         1723                                 r = memlinebbox(p, q, e0, e1, j);
         1724                                 dstflush(dstid, dst, insetrect(r, -(1+1+j)));
         1725                         }
         1726                         continue;
         1727 
         1728                 /* create image mask: 'm' newid[4] id[4] */
         1729 /*
         1730  *
         1731                 case 'm':
         1732                         printmesg("LL", a, 0);
         1733                         m = 4+4;
         1734                         if(n < m)
         1735                                 error(Eshortdraw);
         1736                         break;
         1737  *
         1738  */
         1739 
         1740                 /* attach to a named image: 'n' dstid[4] j[1] name[j] */
         1741                 case 'n':
         1742                         printmesg(fmt="Lz", a, 0);
         1743                         m = 1+4+1;
         1744                         if(n < m)
         1745                                 error(Eshortdraw);
         1746                         j = a[5];
         1747                         if(j == 0)        /* give me a non-empty name please */
         1748                                 error(Eshortdraw);
         1749                         m += j;
         1750                         if(n < m)
         1751                                 error(Eshortdraw);
         1752                         dstid = BGLONG(a+1);
         1753                         if(drawlookup(client, dstid, 0))
         1754                                 error(Eimageexists);
         1755                         dn = drawlookupname(j, (char*)a+6);
         1756                         if(dn == nil)
         1757                                 error(Enoname);
         1758                         if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
         1759                                 error(Edrawmem);
         1760                         di = drawlookup(client, dstid, 0);
         1761                         if(di == 0)
         1762                                 error("draw: cannot happen");
         1763                         di->vers = dn->vers;
         1764                         di->name = smalloc(j+1);
         1765                         di->fromname = dn->dimage;
         1766                         di->fromname->ref++;
         1767                         memmove(di->name, a+6, j);
         1768                         di->name[j] = 0;
         1769                         client->infoid = dstid;
         1770                         continue;
         1771 
         1772                 /* name an image: 'N' dstid[4] in[1] j[1] name[j] */
         1773                 case 'N':
         1774                         printmesg(fmt="Lbz", a, 0);
         1775                         m = 1+4+1+1;
         1776                         if(n < m)
         1777                                 error(Eshortdraw);
         1778                         c = a[5];
         1779                         j = a[6];
         1780                         if(j == 0)        /* give me a non-empty name please */
         1781                                 error(Eshortdraw);
         1782                         m += j;
         1783                         if(n < m)
         1784                                 error(Eshortdraw);
         1785                         di = drawlookup(client, BGLONG(a+1), 0);
         1786                         if(di == 0)
         1787                                 error(Enodrawimage);
         1788                         if(di->name)
         1789                                 error(Enamed);
         1790                         if(c)
         1791                                 drawaddname(client, di, j, (char*)a+7);
         1792                         else{
         1793                                 dn = drawlookupname(j, (char*)a+7);
         1794                                 if(dn == nil)
         1795                                         error(Enoname);
         1796                                 if(dn->dimage != di)
         1797                                         error(Ewrongname);
         1798                                 drawdelname(dn);
         1799                         }
         1800                         continue;
         1801 
         1802                 /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
         1803                 case 'o':
         1804                         printmesg(fmt="LPP", a, 0);
         1805                         m = 1+4+2*4+2*4;
         1806                         if(n < m)
         1807                                 error(Eshortdraw);
         1808                         dst = drawimage(client, a+1);
         1809                         if(dst->layer){
         1810                                 drawpoint(&p, a+5);
         1811                                 drawpoint(&q, a+13);
         1812                                 r = dst->layer->screenr;
         1813                                 ni = memlorigin(dst, p, q);
         1814                                 if(ni < 0)
         1815                                         error("image origin failed");
         1816                                 if(ni > 0){
         1817                                         addflush(r);
         1818                                         addflush(dst->layer->screenr);
         1819                                         ll = drawlookup(client, BGLONG(a+1), 1);
         1820                                         drawrefreshscreen(ll, client);
         1821                                 }
         1822                         }
         1823                         continue;
         1824 
         1825                 /* set compositing operator for next draw operation: 'O' op */
         1826                 case 'O':
         1827                         printmesg(fmt="b", a, 0);
         1828                         m = 1+1;
         1829                         if(n < m)
         1830                                 error(Eshortdraw);
         1831                         client->op = a[1];
         1832                         continue;
         1833 
         1834                 /* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
         1835                 /* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
         1836                 case 'p':
         1837                 case 'P':
         1838                         printmesg(fmt="LslllLPP", a, 0);
         1839                         m = 1+4+2+4+4+4+4+2*4;
         1840                         if(n < m)
         1841                                 error(Eshortdraw);
         1842                         dstid = BGLONG(a+1);
         1843                         dst = drawimage(client, a+1);
         1844                         ni = BGSHORT(a+5);
         1845                         if(ni < 0)
         1846                                 error("negative count in polygon");
         1847                         e0 = BGLONG(a+7);
         1848                         e1 = BGLONG(a+11);
         1849                         j = 0;
         1850                         if(*a == 'p'){
         1851                                 j = BGLONG(a+15);
         1852                                 if(j < 0)
         1853                                         error("negative polygon line width");
         1854                         }
         1855                         src = drawimage(client, a+19);
         1856                         drawpoint(&sp, a+23);
         1857                         drawpoint(&p, a+31);
         1858                         ni++;
         1859                         pp = malloc(ni*sizeof(Point));
         1860                         if(pp == nil)
         1861                                 error(Enomem);
         1862                         doflush = 0;
         1863                         if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
         1864                                 doflush = 1;        /* simplify test in loop */
         1865                         ox = oy = 0;
         1866                         esize = 0;
         1867                         u = a+m;
         1868                         for(y=0; y<ni; y++){
         1869                                 q = p;
         1870                                 oesize = esize;
         1871                                 u = drawcoord(u, a+n, ox, &p.x);
         1872                                 u = drawcoord(u, a+n, oy, &p.y);
         1873                                 ox = p.x;
         1874                                 oy = p.y;
         1875                                 if(doflush){
         1876                                         esize = j;
         1877                                         if(*a == 'p'){
         1878                                                 if(y == 0){
         1879                                                         c = memlineendsize(e0);
         1880                                                         if(c > esize)
         1881                                                                 esize = c;
         1882                                                 }
         1883                                                 if(y == ni-1){
         1884                                                         c = memlineendsize(e1);
         1885                                                         if(c > esize)
         1886                                                                 esize = c;
         1887                                                 }
         1888                                         }
         1889                                         if(*a=='P' && e0!=1 && e0 !=~0)
         1890                                                 r = dst->clipr;
         1891                                         else if(y > 0){
         1892                                                 r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1);
         1893                                                 combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
         1894                                         }
         1895                                         if(rectclip(&r, dst->clipr))                /* should perhaps be an arg to dstflush */
         1896                                                 dstflush(dstid, dst, r);
         1897                                 }
         1898                                 pp[y] = p;
         1899                         }
         1900                         if(y == 1)
         1901                                 dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
         1902                         op = drawclientop(client);
         1903                         if(*a == 'p')
         1904                                 mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
         1905                         else
         1906                                 memfillpoly(dst, pp, ni, e0, src, sp, op);
         1907                         free(pp);
         1908                         m = u-a;
         1909                         continue;
         1910 
         1911                 /* read: 'r' id[4] R[4*4] */
         1912                 case 'r':
         1913                         printmesg(fmt="LR", a, 0);
         1914                         m = 1+4+4*4;
         1915                         if(n < m)
         1916                                 error(Eshortdraw);
         1917                         i = drawimage(client, a+1);
         1918                         drawrectangle(&r, a+5);
         1919                         if(!rectinrect(r, i->r))
         1920                                 error(Ereadoutside);
         1921                         c = bytesperline(r, i->depth);
         1922                         c *= Dy(r);
         1923                         free(client->readdata);
         1924                         client->readdata = mallocz(c, 0);
         1925                         if(client->readdata == nil)
         1926                                 error("readimage malloc failed");
         1927                         client->nreaddata = memunload(i, r, client->readdata, c);
         1928                         if(client->nreaddata < 0){
         1929                                 free(client->readdata);
         1930                                 client->readdata = nil;
         1931                                 error("bad readimage call");
         1932                         }
         1933                         continue;
         1934 
         1935                 /* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
         1936                 /* stringbg: 'x' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] bgid[4] bgpt[2*4] ni*(index[2]) */
         1937                 case 's':
         1938                 case 'x':
         1939                         printmesg(fmt="LLLPRPs", a, 0);
         1940                         m = 1+4+4+4+2*4+4*4+2*4+2;
         1941                         if(*a == 'x')
         1942                                 m += 4+2*4;
         1943                         if(n < m)
         1944                                 error(Eshortdraw);
         1945 
         1946                         dst = drawimage(client, a+1);
         1947                         dstid = BGLONG(a+1);
         1948                         src = drawimage(client, a+5);
         1949                         font = drawlookup(client, BGLONG(a+9), 1);
         1950                         if(font == 0)
         1951                                 error(Enodrawimage);
         1952                         if(font->nfchar == 0)
         1953                                 error(Enotfont);
         1954                         drawpoint(&p, a+13);
         1955                         drawrectangle(&r, a+21);
         1956                         drawpoint(&sp, a+37);
         1957                         ni = BGSHORT(a+45);
         1958                         u = a+m;
         1959                         m += ni*2;
         1960                         if(n < m)
         1961                                 error(Eshortdraw);
         1962                         clipr = dst->clipr;
         1963                         dst->clipr = r;
         1964                         op = drawclientop(client);
         1965                         bg = dst;
         1966                         if(*a == 'x'){
         1967                                 /* paint background */
         1968                                 bg = drawimage(client, a+47);
         1969                                 drawpoint(&q, a+51);
         1970                                 r.min.x = p.x;
         1971                                 r.min.y = p.y-font->ascent;
         1972                                 r.max.x = p.x;
         1973                                 r.max.y = r.min.y+Dy(font->image->r);
         1974                                 j = ni;
         1975                                 while(--j >= 0){
         1976                                         ci = BGSHORT(u);
         1977                                         if(ci<0 || ci>=font->nfchar){
         1978                                                 dst->clipr = clipr;
         1979                                                 error(Eindex);
         1980                                         }
         1981                                         r.max.x += font->fchar[ci].width;
         1982                                         u += 2;
         1983                                 }
         1984                                 memdraw(dst, r, bg, q, memopaque, ZP, op);
         1985                                 u -= 2*ni;
         1986                         }
         1987                         q = p;
         1988                         while(--ni >= 0){
         1989                                 ci = BGSHORT(u);
         1990                                 if(ci<0 || ci>=font->nfchar){
         1991                                         dst->clipr = clipr;
         1992                                         error(Eindex);
         1993                                 }
         1994                                 q = drawchar(dst, bg, q, src, &sp, font, ci, op);
         1995                                 u += 2;
         1996                         }
         1997                         dst->clipr = clipr;
         1998                         p.y -= font->ascent;
         1999                         dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
         2000                         continue;
         2001 
         2002                 /* use public screen: 'S' id[4] chan[4] */
         2003                 case 'S':
         2004                         printmesg(fmt="Ll", a, 0);
         2005                         m = 1+4+4;
         2006                         if(n < m)
         2007                                 error(Eshortdraw);
         2008                         dstid = BGLONG(a+1);
         2009                         if(dstid == 0)
         2010                                 error(Ebadarg);
         2011                         dscrn = drawlookupdscreen(dstid);
         2012                         if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
         2013                                 error(Enodrawscreen);
         2014                         if(dscrn->screen->image->chan != BGLONG(a+5))
         2015                                 error("inconsistent chan");
         2016                         if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
         2017                                 error(Edrawmem);
         2018                         continue;
         2019 
         2020                 /* top or bottom windows: 't' top[1] nw[2] n*id[4] */
         2021                 case 't':
         2022                         printmesg(fmt="bsL", a, 0);
         2023                         m = 1+1+2;
         2024                         if(n < m)
         2025                                 error(Eshortdraw);
         2026                         nw = BGSHORT(a+2);
         2027                         if(nw < 0)
         2028                                 error(Ebadarg);
         2029                         if(nw == 0)
         2030                                 continue;
         2031                         m += nw*4;
         2032                         if(n < m)
         2033                                 error(Eshortdraw);
         2034                         lp = malloc(nw*sizeof(Memimage*));
         2035                         if(lp == 0)
         2036                                 error(Enomem);
         2037                         if(waserror()){
         2038                                 free(lp);
         2039                                 nexterror();
         2040                         }
         2041                         for(j=0; j<nw; j++)
         2042                                 lp[j] = drawimage(client, a+1+1+2+j*4);
         2043                         if(lp[0]->layer == 0)
         2044                                 error("images are not windows");
         2045                         for(j=1; j<nw; j++)
         2046                                 if(lp[j]->layer->screen != lp[0]->layer->screen)
         2047                                         error("images not on same screen");
         2048                         if(a[1])
         2049                                 memltofrontn(lp, nw);
         2050                         else
         2051                                 memltorearn(lp, nw);
         2052                         if(lp[0]->layer->screen->image->data == screenimage->data)
         2053                                 for(j=0; j<nw; j++)
         2054                                         addflush(lp[j]->layer->screenr);
         2055                         ll = drawlookup(client, BGLONG(a+1+1+2), 1);
         2056                         drawrefreshscreen(ll, client);
         2057                         poperror();
         2058                         free(lp);
         2059                         continue;
         2060 
         2061                 /* visible: 'v' */
         2062                 case 'v':
         2063                         printmesg(fmt="", a, 0);
         2064                         m = 1;
         2065                         drawflush();
         2066                         continue;
         2067 
         2068                 /* write: 'y' id[4] R[4*4] data[x*1] */
         2069                 /* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */
         2070                 case 'y':
         2071                 case 'Y':
         2072                         printmesg(fmt="LR", a, 0);
         2073                 //        iprint("load %c\n", *a);
         2074                         m = 1+4+4*4;
         2075                         if(n < m)
         2076                                 error(Eshortdraw);
         2077                         dstid = BGLONG(a+1);
         2078                         dst = drawimage(client, a+1);
         2079                         drawrectangle(&r, a+5);
         2080                         if(!rectinrect(r, dst->r))
         2081                                 error(Ewriteoutside);
         2082                         y = memload(dst, r, a+m, n-m, *a=='Y');
         2083                         if(y < 0)
         2084                                 error("bad writeimage call");
         2085                         dstflush(dstid, dst, r);
         2086                         m += y;
         2087                         continue;
         2088                 }
         2089         }
         2090         poperror();
         2091 }
         2092 
         2093 Dev drawdevtab = {
         2094         'i',
         2095         "draw",
         2096 
         2097         devreset,
         2098         devinit,
         2099         devshutdown,
         2100         drawattach,
         2101         drawwalk,
         2102         drawstat,
         2103         drawopen,
         2104         devcreate,
         2105         drawclose,
         2106         drawread,
         2107         devbread,
         2108         drawwrite,
         2109         devbwrite,
         2110         devremove,
         2111         devwstat,
         2112 };
         2113 
         2114 /*
         2115  * On 8 bit displays, load the default color map
         2116  */
         2117 void
         2118 drawcmap(void)
         2119 {
         2120         int r, g, b, cr, cg, cb, v;
         2121         int num, den;
         2122         int i, j;
         2123 
         2124         drawactive(1);        /* to restore map from backup */
         2125         for(r=0,i=0; r!=4; r++)
         2126             for(v=0; v!=4; v++,i+=16){
         2127                 for(g=0,j=v-r; g!=4; g++)
         2128                     for(b=0;b!=4;b++,j++){
         2129                         den = r;
         2130                         if(g > den)
         2131                                 den = g;
         2132                         if(b > den)
         2133                                 den = b;
         2134                         if(den == 0)        /* divide check -- pick grey shades */
         2135                                 cr = cg = cb = v*17;
         2136                         else{
         2137                                 num = 17*(4*den+v);
         2138                                 cr = r*num/den;
         2139                                 cg = g*num/den;
         2140                                 cb = b*num/den;
         2141                         }
         2142                         setcolor(i+(j&15),
         2143                                 cr*0x01010101, cg*0x01010101, cb*0x01010101);
         2144                     }
         2145         }
         2146 }
         2147 
         2148 void
         2149 drawblankscreen(int blank)
         2150 {
         2151         int i, nc;
         2152         ulong *p;
         2153 
         2154         if(blank == sdraw.blanked)
         2155                 return;
         2156         if(!drawcanqlock())
         2157                 return;
         2158         if(!initscreenimage()){
         2159                 drawqunlock();
         2160                 return;
         2161         }
         2162         p = sdraw.savemap;
         2163         nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth;
         2164 
         2165         /*
         2166          * blankscreen uses the hardware to blank the screen
         2167          * when possible.  to help in cases when it is not possible,
         2168          * we set the color map to be all black.
         2169          */
         2170         if(blank == 0){        /* turn screen on */
         2171                 for(i=0; i<nc; i++, p+=3)
         2172                         setcolor(i, p[0], p[1], p[2]);
         2173                 blankscreen(0);
         2174         }else{        /* turn screen off */
         2175                 blankscreen(1);
         2176                 for(i=0; i<nc; i++, p+=3){
         2177                         getcolor(i, &p[0], &p[1], &p[2]);
         2178                         setcolor(i, 0, 0, 0);
         2179                 }
         2180         }
         2181         sdraw.blanked = blank;
         2182         drawqunlock();
         2183 }
         2184 
         2185 /*
         2186  * record activity on screen, changing blanking as appropriate
         2187  */
         2188 void
         2189 drawactive(int active)
         2190 {
         2191         if(active){
         2192                 drawblankscreen(0);
         2193                 sdraw.blanktime = msec()/1000;
         2194         }else{
         2195                 if(blanktime && sdraw.blanktime && TK2SEC(msec()/1000 - sdraw.blanktime)/60 >= blanktime)
         2196                         drawblankscreen(1);
         2197         }
         2198 }
         2199 
         2200 int
         2201 drawidletime(void)
         2202 {
         2203         return TK2SEC(msec()/1000 - sdraw.blanktime)/60;
         2204 }
         2205 
         2206 /* why is this here? why can't caller use drawqlock himself? */
         2207 void
         2208 drawflushr(Rectangle r)
         2209 {
         2210         drawqlock();
         2211         flushmemscreen(r);
         2212         drawqunlock();
         2213 }
         2214 
         2215 void
         2216 drawreplacescreenimage(Memimage *m)
         2217 {
         2218         int i;
         2219         DImage *di;
         2220 
         2221         if(screendimage == nil)
         2222                 return;
         2223 
         2224         /*
         2225          * Replace the screen image because the screen
         2226          * was resized.  Clients still have references to the
         2227          * old screen image, so we can't free it just yet.
         2228          */
         2229         drawqlock();
         2230         di = allocdimage(m);
         2231         if(di == nil){
         2232                 print("no memory to replace screen image\n");
         2233                 freememimage(m);
         2234                 drawqunlock();
         2235                 return;
         2236         }
         2237         
         2238         /* Replace old screen image in global name lookup. */
         2239         for(i=0; i<sdraw.nname; i++){
         2240                 if(sdraw.name[i].dimage == screendimage)
         2241                 if(sdraw.name[i].client == nil){
         2242                         sdraw.name[i].dimage = di;
         2243                         break;
         2244                 }
         2245         }
         2246 
         2247         drawfreedimage(screendimage);
         2248         screendimage = di;
         2249         screenimage = m;
         2250 
         2251         /*
         2252          * Every client, when it starts, gets a copy of the
         2253          * screen image as image 0.  Clients only use it 
         2254          * for drawing if there is no /dev/winname, but
         2255          * this /dev/draw provides a winname (early ones
         2256          * didn't; winname originated in rio), so the
         2257          * image only ends up used to find the screen
         2258          * resolution and pixel format during initialization.
         2259          * Silently remove the now-outdated image 0s.
         2260          */
         2261         for(i=0; i<sdraw.nclient; i++){
         2262                 if(sdraw.client[i] && !waserror()){
         2263                         drawuninstall(sdraw.client[i], 0);
         2264                         poperror();
         2265                 }
         2266         }
         2267 
         2268         drawqunlock();
         2269         mouseresize();
         2270 }