The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/devdraw.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 4658a9d76d5af085f8b609b9037381af


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.