URI:
       tdevdraw.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tdevdraw.c (32173B)
       ---
            1 /*
            2  * /dev/draw simulator -- handles the messages prepared by the draw library.
            3  * Doesn't simulate the file system part, just the messages.
            4  */
            5 
            6 #include <u.h>
            7 #include <libc.h>
            8 #include <draw.h>
            9 #include <memdraw.h>
           10 #include <memlayer.h>
           11 #include <mouse.h>
           12 #include <cursor.h>
           13 #include <keyboard.h>
           14 #include <drawfcall.h>
           15 #include "devdraw.h"
           16 
           17 QLock        drawlk;
           18 
           19 static        int                drawuninstall(Client*, int);
           20 static        Memimage*        drawinstall(Client*, int, Memimage*, DScreen*);
           21 static        void                drawfreedimage(Client*, DImage*);
           22 
           23 void
           24 draw_initdisplaymemimage(Client *c, Memimage *m)
           25 {
           26         c->screenimage = m;
           27         m->screenref = 1;
           28         c->slot = 0;
           29         c->clientid = 1;
           30         c->op = SoverD;
           31 }
           32 
           33 // gfx_replacescreenimage replaces c's screen image with m.
           34 // It is called by the host driver on the main host thread.
           35 void
           36 gfx_replacescreenimage(Client *c, Memimage *m)
           37 {
           38         /*
           39          * Replace the screen image because the screen
           40          * was resized.
           41          *
           42          * In theory there should only be one reference
           43          * to the current screen image, and that's through
           44          * client0's image 0, installed a few lines above.
           45          * Once the client drops the image, the underlying backing
           46          * store freed properly.  The client is being notified
           47          * about the resize through external means, so all we
           48          * need to do is this assignment.
           49          */
           50         Memimage *om;
           51 
           52         qlock(&drawlk);
           53         om = c->screenimage;
           54         c->screenimage = m;
           55         m->screenref = 1;
           56         if(om && --om->screenref == 0){
           57                 _freememimage(om);
           58         }
           59         qunlock(&drawlk);
           60         gfx_mouseresized(c);
           61 }
           62 
           63 static void
           64 drawrefreshscreen(DImage *l, Client *client)
           65 {
           66         while(l != nil && l->dscreen == nil)
           67                 l = l->fromname;
           68         if(l != nil && l->dscreen->owner != client)
           69                 l->dscreen->owner->refreshme = 1;
           70 }
           71 
           72 static void
           73 drawrefresh(Memimage *m, Rectangle r, void *v)
           74 {
           75         Refx *x;
           76         DImage *d;
           77         Client *c;
           78         Refresh *ref;
           79 
           80         USED(m);
           81 
           82         if(v == 0)
           83                 return;
           84         x = v;
           85         c = x->client;
           86         d = x->dimage;
           87         for(ref=c->refresh; ref; ref=ref->next)
           88                 if(ref->dimage == d){
           89                         combinerect(&ref->r, r);
           90                         return;
           91                 }
           92         ref = mallocz(sizeof(Refresh), 1);
           93         if(ref){
           94                 ref->dimage = d;
           95                 ref->r = r;
           96                 ref->next = c->refresh;
           97                 c->refresh = ref;
           98         }
           99 }
          100 
          101 static void
          102 addflush(Client *c, Rectangle r)
          103 {
          104         int abb, ar, anbb;
          105         Rectangle nbb, fr;
          106 
          107         if(/*sdraw.softscreen==0 ||*/ !rectclip(&r, c->screenimage->r))
          108                 return;
          109 
          110         if(c->flushrect.min.x >= c->flushrect.max.x){
          111                 c->flushrect = r;
          112                 c->waste = 0;
          113                 return;
          114         }
          115         nbb = c->flushrect;
          116         combinerect(&nbb, r);
          117         ar = Dx(r)*Dy(r);
          118         abb = Dx(c->flushrect)*Dy(c->flushrect);
          119         anbb = Dx(nbb)*Dy(nbb);
          120         /*
          121          * Area of new waste is area of new bb minus area of old bb,
          122          * less the area of the new segment, which we assume is not waste.
          123          * This could be negative, but that's OK.
          124          */
          125         c->waste += anbb-abb - ar;
          126         if(c->waste < 0)
          127                 c->waste = 0;
          128         /*
          129          * absorb if:
          130          *        total area is small
          131          *        waste is less than half total area
          132          *         rectangles touch
          133          */
          134         if(anbb<=1024 || c->waste*2<anbb || rectXrect(c->flushrect, r)){
          135                 c->flushrect = nbb;
          136                 return;
          137         }
          138         /* emit current state */
          139         fr = c->flushrect;
          140         c->flushrect = r;
          141         c->waste = 0;
          142         if(fr.min.x < fr.max.x) {
          143                 // Unlock drawlk because rpc_flush may want to run on gfx thread,
          144                 // and gfx thread might be blocked on drawlk trying to install a new screen
          145                 // during a resize.
          146                 rpc_gfxdrawunlock();
          147                 qunlock(&drawlk);
          148                 c->impl->rpc_flush(c, fr);
          149                 qlock(&drawlk);
          150                 rpc_gfxdrawlock();
          151         }
          152 }
          153 
          154 static void
          155 dstflush(Client *c, int dstid, Memimage *dst, Rectangle r)
          156 {
          157         Memlayer *l;
          158 
          159         if(dstid == 0){
          160                 combinerect(&c->flushrect, r);
          161                 return;
          162         }
          163         /* how can this happen? -rsc, dec 12 2002 */
          164         if(dst == 0){
          165                 fprint(2, "nil dstflush\n");
          166                 return;
          167         }
          168         l = dst->layer;
          169         if(l == nil)
          170                 return;
          171         do{
          172                 if(l->screen->image->data != c->screenimage->data)
          173                         return;
          174                 r = rectaddpt(r, l->delta);
          175                 l = l->screen->image->layer;
          176         }while(l);
          177         addflush(c, r);
          178 }
          179 
          180 static void
          181 drawflush(Client *c)
          182 {
          183         Rectangle r;
          184 
          185         r = c->flushrect;
          186         c->flushrect = Rect(10000, 10000, -10000, -10000);
          187         if(r.min.x < r.max.x) {
          188                 // Unlock drawlk because rpc_flush may want to run on gfx thread,
          189                 // and gfx thread might be blocked on drawlk trying to install a new screen
          190                 // during a resize.
          191                 rpc_gfxdrawunlock();
          192                 qunlock(&drawlk);
          193                 c->impl->rpc_flush(c, r);
          194                 qlock(&drawlk);
          195                 rpc_gfxdrawlock();
          196         }
          197 }
          198 
          199 static int
          200 drawcmp(char *a, char *b, int n)
          201 {
          202         if(strlen(a) != n)
          203                 return 1;
          204         return memcmp(a, b, n);
          205 }
          206 
          207 static DName*
          208 drawlookupname(Client *client, int n, char *str)
          209 {
          210         DName *name, *ename;
          211 
          212         name = client->name;
          213         ename = &name[client->nname];
          214         for(; name<ename; name++)
          215                 if(drawcmp(name->name, str, n) == 0)
          216                         return name;
          217         return 0;
          218 }
          219 
          220 static int
          221 drawgoodname(Client *client, DImage *d)
          222 {
          223         DName *n;
          224 
          225         /* if window, validate the screen's own images */
          226         if(d->dscreen)
          227                 if(drawgoodname(client, d->dscreen->dimage) == 0
          228                 || drawgoodname(client, d->dscreen->dfill) == 0)
          229                         return 0;
          230         if(d->name == nil)
          231                 return 1;
          232         n = drawlookupname(client, strlen(d->name), d->name);
          233         if(n==nil || n->vers!=d->vers)
          234                 return 0;
          235         return 1;
          236 }
          237 
          238 static DImage*
          239 drawlookup(Client *client, int id, int checkname)
          240 {
          241         DImage *d;
          242 
          243         d = client->dimage[id&HASHMASK];
          244         while(d){
          245                 if(d->id == id){
          246                         /*
          247                          * BUG: should error out but too hard.
          248                          * Return 0 instead.
          249                          */
          250                         if(checkname && !drawgoodname(client, d))
          251                                 return 0;
          252                         return d;
          253                 }
          254                 d = d->next;
          255         }
          256         return 0;
          257 }
          258 
          259 static DScreen*
          260 drawlookupdscreen(Client *c, int id)
          261 {
          262         DScreen *s;
          263 
          264         s = c->dscreen;
          265         while(s){
          266                 if(s->id == id)
          267                         return s;
          268                 s = s->next;
          269         }
          270         return 0;
          271 }
          272 
          273 static DScreen*
          274 drawlookupscreen(Client *client, int id, CScreen **cs)
          275 {
          276         CScreen *s;
          277 
          278         s = client->cscreen;
          279         while(s){
          280                 if(s->dscreen->id == id){
          281                         *cs = s;
          282                         return s->dscreen;
          283                 }
          284                 s = s->next;
          285         }
          286         /* caller must check! */
          287         return 0;
          288 }
          289 
          290 static Memimage*
          291 drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
          292 {
          293         DImage *d;
          294 
          295         d = mallocz(sizeof(DImage), 1);
          296         if(d == 0)
          297                 return 0;
          298         d->id = id;
          299         d->ref = 1;
          300         d->name = 0;
          301         d->vers = 0;
          302         d->image = i;
          303         if(i->screenref)
          304                 ++i->screenref;
          305         d->nfchar = 0;
          306         d->fchar = 0;
          307         d->fromname = 0;
          308         d->dscreen = dscreen;
          309         d->next = client->dimage[id&HASHMASK];
          310         client->dimage[id&HASHMASK] = d;
          311         return i;
          312 }
          313 
          314 static Memscreen*
          315 drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
          316 {
          317         Memscreen *s;
          318         CScreen *c;
          319 
          320         c = mallocz(sizeof(CScreen), 1);
          321         if(dimage && dimage->image && dimage->image->chan == 0){
          322                 fprint(2, "bad image %p in drawinstallscreen", dimage->image);
          323                 abort();
          324         }
          325 
          326         if(c == 0)
          327                 return 0;
          328         if(d == 0){
          329                 d = mallocz(sizeof(DScreen), 1);
          330                 if(d == 0){
          331                         free(c);
          332                         return 0;
          333                 }
          334                 s = mallocz(sizeof(Memscreen), 1);
          335                 if(s == 0){
          336                         free(c);
          337                         free(d);
          338                         return 0;
          339                 }
          340                 s->frontmost = 0;
          341                 s->rearmost = 0;
          342                 d->dimage = dimage;
          343                 if(dimage){
          344                         s->image = dimage->image;
          345                         dimage->ref++;
          346                 }
          347                 d->dfill = dfill;
          348                 if(dfill){
          349                         s->fill = dfill->image;
          350                         dfill->ref++;
          351                 }
          352                 d->ref = 0;
          353                 d->id = id;
          354                 d->screen = s;
          355                 d->public = public;
          356                 d->next = client->dscreen;
          357                 d->owner = client;
          358                 client->dscreen = d;
          359         }
          360         c->dscreen = d;
          361         d->ref++;
          362         c->next = client->cscreen;
          363         client->cscreen = c;
          364         return d->screen;
          365 }
          366 
          367 static void
          368 drawdelname(Client *client, DName *name)
          369 {
          370         int i;
          371 
          372         i = name-client->name;
          373         memmove(name, name+1, (client->nname-(i+1))*sizeof(DName));
          374         client->nname--;
          375 }
          376 
          377 static void
          378 drawfreedscreen(Client *client, DScreen *this)
          379 {
          380         DScreen *ds, *next;
          381 
          382         this->ref--;
          383         if(this->ref < 0)
          384                 fprint(2, "negative ref in drawfreedscreen\n");
          385         if(this->ref > 0)
          386                 return;
          387         ds = client->dscreen;
          388         if(ds == this){
          389                 client->dscreen = this->next;
          390                 goto Found;
          391         }
          392         while(next = ds->next){        /* assign = */
          393                 if(next == this){
          394                         ds->next = this->next;
          395                         goto Found;
          396                 }
          397                 ds = next;
          398         }
          399         /*
          400          * Should signal Enodrawimage, but too hard.
          401          */
          402         return;
          403 
          404     Found:
          405         if(this->dimage)
          406                 drawfreedimage(client, this->dimage);
          407         if(this->dfill)
          408                 drawfreedimage(client, this->dfill);
          409         free(this->screen);
          410         free(this);
          411 }
          412 
          413 static void
          414 drawfreedimage(Client *client, DImage *dimage)
          415 {
          416         int i;
          417         Memimage *l;
          418         DScreen *ds;
          419 
          420         dimage->ref--;
          421         if(dimage->ref < 0)
          422                 fprint(2, "negative ref in drawfreedimage\n");
          423         if(dimage->ref > 0)
          424                 return;
          425 
          426         /* any names? */
          427         for(i=0; i<client->nname; )
          428                 if(client->name[i].dimage == dimage)
          429                         drawdelname(client, client->name+i);
          430                 else
          431                         i++;
          432         if(dimage->fromname){        /* acquired by name; owned by someone else*/
          433                 drawfreedimage(client, dimage->fromname);
          434                 goto Return;
          435         }
          436         ds = dimage->dscreen;
          437         l = dimage->image;
          438         dimage->dscreen = nil;        /* paranoia */
          439         dimage->image = nil;
          440         if(ds){
          441                 if(l->data == client->screenimage->data)
          442                         addflush(client, l->layer->screenr);
          443                 if(l->layer->refreshfn == drawrefresh)        /* else true owner will clean up */
          444                         free(l->layer->refreshptr);
          445                 l->layer->refreshptr = nil;
          446                 if(drawgoodname(client, dimage))
          447                         memldelete(l);
          448                 else
          449                         memlfree(l);
          450                 drawfreedscreen(client, ds);
          451         }else{
          452                 if(l->screenref==0)
          453                         freememimage(l);
          454                 else if(--l->screenref==0)
          455                         _freememimage(l);
          456         }
          457     Return:
          458         free(dimage->fchar);
          459         free(dimage);
          460 }
          461 
          462 static void
          463 drawuninstallscreen(Client *client, CScreen *this)
          464 {
          465         CScreen *cs, *next;
          466 
          467         cs = client->cscreen;
          468         if(cs == this){
          469                 client->cscreen = this->next;
          470                 drawfreedscreen(client, this->dscreen);
          471                 free(this);
          472                 return;
          473         }
          474         while(next = cs->next){        /* assign = */
          475                 if(next == this){
          476                         cs->next = this->next;
          477                         drawfreedscreen(client, this->dscreen);
          478                         free(this);
          479                         return;
          480                 }
          481                 cs = next;
          482         }
          483 }
          484 
          485 static int
          486 drawuninstall(Client *client, int id)
          487 {
          488         DImage *d, **l;
          489 
          490         for(l=&client->dimage[id&HASHMASK]; (d=*l) != nil; l=&d->next){
          491                 if(d->id == id){
          492                         *l = d->next;
          493                         drawfreedimage(client, d);
          494                         return 0;
          495                 }
          496         }
          497         return -1;
          498 }
          499 
          500 static int
          501 drawaddname(Client *client, DImage *di, int n, char *str, char **err)
          502 {
          503         DName *name, *ename, *new, *t;
          504         char *ns;
          505 
          506         name = client->name;
          507         ename = &name[client->nname];
          508         for(; name<ename; name++)
          509                 if(drawcmp(name->name, str, n) == 0){
          510                         *err = "image name in use";
          511                         return -1;
          512                 }
          513         t = mallocz((client->nname+1)*sizeof(DName), 1);
          514         ns = malloc(n+1);
          515         if(t == nil || ns == nil){
          516                 free(t);
          517                 free(ns);
          518                 *err = "out of memory";
          519                 return -1;
          520         }
          521         memmove(t, client->name, client->nname*sizeof(DName));
          522         free(client->name);
          523         client->name = t;
          524         new = &client->name[client->nname++];
          525         new->name = ns;
          526         memmove(new->name, str, n);
          527         new->name[n] = 0;
          528         new->dimage = di;
          529         new->client = client;
          530         new->vers = ++client->namevers;
          531         return 0;
          532 }
          533 
          534 static int
          535 drawclientop(Client *cl)
          536 {
          537         int op;
          538 
          539         op = cl->op;
          540         cl->op = SoverD;
          541         return op;
          542 }
          543 
          544 static Memimage*
          545 drawimage(Client *client, uchar *a)
          546 {
          547         DImage *d;
          548 
          549         d = drawlookup(client, BGLONG(a), 1);
          550         if(d == nil)
          551                 return nil;        /* caller must check! */
          552         return d->image;
          553 }
          554 
          555 static void
          556 drawrectangle(Rectangle *r, uchar *a)
          557 {
          558         r->min.x = BGLONG(a+0*4);
          559         r->min.y = BGLONG(a+1*4);
          560         r->max.x = BGLONG(a+2*4);
          561         r->max.y = BGLONG(a+3*4);
          562 }
          563 
          564 static void
          565 drawpoint(Point *p, uchar *a)
          566 {
          567         p->x = BGLONG(a+0*4);
          568         p->y = BGLONG(a+1*4);
          569 }
          570 
          571 static Point
          572 drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
          573 {
          574         FChar *fc;
          575         Rectangle r;
          576         Point sp1;
          577 
          578         fc = &font->fchar[index];
          579         r.min.x = p.x+fc->left;
          580         r.min.y = p.y-(font->ascent-fc->miny);
          581         r.max.x = r.min.x+(fc->maxx-fc->minx);
          582         r.max.y = r.min.y+(fc->maxy-fc->miny);
          583         sp1.x = sp->x+fc->left;
          584         sp1.y = sp->y+fc->miny;
          585         memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
          586         p.x += fc->width;
          587         sp->x += fc->width;
          588         return p;
          589 }
          590 
          591 static uchar*
          592 drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
          593 {
          594         int b, x;
          595 
          596         if(p >= maxp)
          597                 return nil;
          598         b = *p++;
          599         x = b & 0x7F;
          600         if(b & 0x80){
          601                 if(p+1 >= maxp)
          602                         return nil;
          603                 x |= *p++ << 7;
          604                 x |= *p++ << 15;
          605                 if(x & (1<<22))
          606                         x |= ~0U<<23;
          607         }else{
          608                 if(b & 0x40)
          609                         x |= ~0U<<7;
          610                 x += oldx;
          611         }
          612         *newx = x;
          613         return p;
          614 }
          615 
          616 int
          617 draw_dataread(Client *cl, void *a, int n)
          618 {
          619         qlock(&drawlk);
          620         if(cl->readdata == nil){
          621                 werrstr("no draw data");
          622                 goto err;
          623         }
          624         if(n < cl->nreaddata){
          625                 werrstr("short read");
          626                 goto err;
          627         }
          628         n = cl->nreaddata;
          629         memmove(a, cl->readdata, cl->nreaddata);
          630         free(cl->readdata);
          631         cl->readdata = nil;
          632         qunlock(&drawlk);
          633         return n;
          634 
          635 err:
          636         qunlock(&drawlk);
          637         return -1;
          638 }
          639 
          640 int
          641 draw_datawrite(Client *client, void *v, int n)
          642 {
          643         char cbuf[40], *err, ibuf[12*12+1], *s;
          644         int c, ci, doflush, dstid, e0, e1, esize, j, m;
          645         int ni, nw, oesize, oldn, op, ox, oy, repl, scrnid, y;
          646         uchar *a, refresh, *u;
          647         u32int chan, value;
          648         CScreen *cs;
          649         DImage *di, *ddst, *dsrc, *font, *ll;
          650         DName *dn;
          651         DScreen *dscrn;
          652         FChar *fc;
          653         Fmt fmt;
          654         Memimage *dst, *i, *l, **lp, *mask, *src;
          655         Memscreen *scrn;
          656         Point p, *pp, q, sp;
          657         Rectangle clipr, r;
          658         Refreshfn reffn;
          659         Refx *refx;
          660 
          661         qlock(&drawlk);
          662         rpc_gfxdrawlock();
          663         a = v;
          664         m = 0;
          665         oldn = n;
          666 
          667         while((n-=m) > 0){
          668                 a += m;
          669 /*fprint(2, "msgwrite %d(%d)...", n, *a); */
          670                 switch(*a){
          671                 default:
          672 /*fprint(2, "bad command %d\n", *a); */
          673                         err = "bad draw command";
          674                         goto error;
          675 
          676                 /* allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1]
          677                         R[4*4] clipR[4*4] rrggbbaa[4]
          678                  */
          679                 case 'b':
          680                         m = 1+4+4+1+4+1+4*4+4*4+4;
          681                         if(n < m)
          682                                 goto Eshortdraw;
          683                         dstid = BGLONG(a+1);
          684                         scrnid = BGSHORT(a+5);
          685                         refresh = a[9];
          686                         chan = BGLONG(a+10);
          687                         repl = a[14];
          688                         drawrectangle(&r, a+15);
          689                         drawrectangle(&clipr, a+31);
          690                         value = BGLONG(a+47);
          691                         if(drawlookup(client, dstid, 0))
          692                                 goto Eimageexists;
          693                         if(scrnid){
          694                                 dscrn = drawlookupscreen(client, scrnid, &cs);
          695                                 if(!dscrn)
          696                                         goto Enodrawscreen;
          697                                 scrn = dscrn->screen;
          698                                 if(repl || chan!=scrn->image->chan){
          699                                         err = "image parameters incompatibile with screen";
          700                                         goto error;
          701                                 }
          702                                 reffn = 0;
          703                                 switch(refresh){
          704                                 case Refbackup:
          705                                         break;
          706                                 case Refnone:
          707                                         reffn = memlnorefresh;
          708                                         break;
          709                                 case Refmesg:
          710                                         reffn = drawrefresh;
          711                                         break;
          712                                 default:
          713                                         err = "unknown refresh method";
          714                                         goto error;
          715                                 }
          716                                 l = memlalloc(scrn, r, reffn, 0, value);
          717                                 if(l == 0)
          718                                         goto Edrawmem;
          719                                 addflush(client, l->layer->screenr);
          720                                 l->clipr = clipr;
          721                                 rectclip(&l->clipr, r);
          722                                 if(drawinstall(client, dstid, l, dscrn) == 0){
          723                                         memldelete(l);
          724                                         goto Edrawmem;
          725                                 }
          726                                 dscrn->ref++;
          727                                 if(reffn){
          728                                         refx = nil;
          729                                         if(reffn == drawrefresh){
          730                                                 refx = mallocz(sizeof(Refx), 1);
          731                                                 if(refx == 0){
          732                                                         if(drawuninstall(client, dstid) < 0)
          733                                                                 goto Enodrawimage;
          734                                                         goto Edrawmem;
          735                                                 }
          736                                                 refx->client = client;
          737                                                 refx->dimage = drawlookup(client, dstid, 1);
          738                                         }
          739                                         memlsetrefresh(l, reffn, refx);
          740                                 }
          741                                 continue;
          742                         }
          743                         i = allocmemimage(r, chan);
          744                         if(i == 0)
          745                                 goto Edrawmem;
          746                         if(repl)
          747                                 i->flags |= Frepl;
          748                         i->clipr = clipr;
          749                         if(!repl)
          750                                 rectclip(&i->clipr, r);
          751                         if(drawinstall(client, dstid, i, 0) == 0){
          752                                 freememimage(i);
          753                                 goto Edrawmem;
          754                         }
          755                         memfillcolor(i, value);
          756                         continue;
          757 
          758                 /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
          759                 case 'A':
          760                         m = 1+4+4+4+1;
          761                         if(n < m)
          762                                 goto Eshortdraw;
          763                         dstid = BGLONG(a+1);
          764                         if(dstid == 0)
          765                                 goto Ebadarg;
          766                         if(drawlookupdscreen(client, dstid))
          767                                 goto Escreenexists;
          768                         ddst = drawlookup(client, BGLONG(a+5), 1);
          769                         dsrc = drawlookup(client, BGLONG(a+9), 1);
          770                         if(ddst==0 || dsrc==0)
          771                                 goto Enodrawimage;
          772                         if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
          773                                 goto Edrawmem;
          774                         continue;
          775 
          776                 /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
          777                 case 'c':
          778                         m = 1+4+1+4*4;
          779                         if(n < m)
          780                                 goto Eshortdraw;
          781                         ddst = drawlookup(client, BGLONG(a+1), 1);
          782                         if(ddst == nil)
          783                                 goto Enodrawimage;
          784                         if(ddst->name){
          785                                 err = "can't change repl/clipr of shared image";
          786                                 goto error;
          787                         }
          788                         dst = ddst->image;
          789                         if(a[5])
          790                                 dst->flags |= Frepl;
          791                         drawrectangle(&dst->clipr, a+6);
          792                         continue;
          793 
          794                 /* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
          795                 case 'd':
          796                         m = 1+4+4+4+4*4+2*4+2*4;
          797                         if(n < m)
          798                                 goto Eshortdraw;
          799                         dst = drawimage(client, a+1);
          800                         dstid = BGLONG(a+1);
          801                         src = drawimage(client, a+5);
          802                         mask = drawimage(client, a+9);
          803                         if(!dst || !src || !mask)
          804                                 goto Enodrawimage;
          805                         drawrectangle(&r, a+13);
          806                         drawpoint(&p, a+29);
          807                         drawpoint(&q, a+37);
          808                         op = drawclientop(client);
          809                         memdraw(dst, r, src, p, mask, q, op);
          810                         dstflush(client, dstid, dst, r);
          811                         continue;
          812 
          813                 /* toggle debugging: 'D' val[1] */
          814                 case 'D':
          815                         m = 1+1;
          816                         if(n < m)
          817                                 goto Eshortdraw;
          818                         drawdebug = a[1];
          819                         continue;
          820 
          821                 /* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
          822                 case 'e':
          823                 case 'E':
          824                         m = 1+4+4+2*4+4+4+4+2*4+2*4;
          825                         if(n < m)
          826                                 goto Eshortdraw;
          827                         dst = drawimage(client, a+1);
          828                         dstid = BGLONG(a+1);
          829                         src = drawimage(client, a+5);
          830                         if(!dst || !src)
          831                                 goto Enodrawimage;
          832                         drawpoint(&p, a+9);
          833                         e0 = BGLONG(a+17);
          834                         e1 = BGLONG(a+21);
          835                         if(e0<0 || e1<0){
          836                                 err = "invalid ellipse semidiameter";
          837                                 goto error;
          838                         }
          839                         j = BGLONG(a+25);
          840                         if(j < 0){
          841                                 err = "negative ellipse thickness";
          842                                 goto error;
          843                         }
          844 
          845                         drawpoint(&sp, a+29);
          846                         c = j;
          847                         if(*a == 'E')
          848                                 c = -1;
          849                         ox = BGLONG(a+37);
          850                         oy = BGLONG(a+41);
          851                         op = drawclientop(client);
          852                         /* high bit indicates arc angles are present */
          853                         if(ox & ((ulong)1<<31)){
          854                                 if((ox & ((ulong)1<<30)) == 0)
          855                                         ox &= ~((ulong)1<<31);
          856                                 memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
          857                         }else
          858                                 memellipse(dst, p, e0, e1, c, src, sp, op);
          859                         dstflush(client, dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
          860                         continue;
          861 
          862                 /* free: 'f' id[4] */
          863                 case 'f':
          864                         m = 1+4;
          865                         if(n < m)
          866                                 goto Eshortdraw;
          867                         ll = drawlookup(client, BGLONG(a+1), 0);
          868                         if(ll && ll->dscreen && ll->dscreen->owner != client)
          869                                 ll->dscreen->owner->refreshme = 1;
          870                         if(drawuninstall(client, BGLONG(a+1)) < 0)
          871                                 goto Enodrawimage;
          872                         continue;
          873 
          874                 /* free screen: 'F' id[4] */
          875                 case 'F':
          876                         m = 1+4;
          877                         if(n < m)
          878                                 goto Eshortdraw;
          879                         if(!drawlookupscreen(client, BGLONG(a+1), &cs))
          880                                 goto Enodrawscreen;
          881                         drawuninstallscreen(client, cs);
          882                         continue;
          883 
          884                 /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
          885                 case 'i':
          886                         m = 1+4+4+1;
          887                         if(n < m)
          888                                 goto Eshortdraw;
          889                         dstid = BGLONG(a+1);
          890                         if(dstid == 0){
          891                                 err = "can't use display as font";
          892                                 goto error;
          893                         }
          894                         font = drawlookup(client, dstid, 1);
          895                         if(font == 0)
          896                                 goto Enodrawimage;
          897                         if(font->image->layer){
          898                                 err = "can't use window as font";
          899                                 goto error;
          900                         }
          901                         ni = BGLONG(a+5);
          902                         if(ni<=0 || ni>4096){
          903                                 err = "bad font size (4096 chars max)";
          904                                 goto error;
          905                         }
          906                         free(font->fchar);        /* should we complain if non-zero? */
          907                         font->fchar = mallocz(ni*sizeof(FChar), 1);
          908                         if(font->fchar == 0){
          909                                 err = "no memory for font";
          910                                 goto error;
          911                         }
          912                         memset(font->fchar, 0, ni*sizeof(FChar));
          913                         font->nfchar = ni;
          914                         font->ascent = a[9];
          915                         continue;
          916 
          917                 /* set image 0 to screen image */
          918                 case 'J':
          919                         m = 1;
          920                         if(n < m)
          921                                 goto Eshortdraw;
          922                         if(drawlookup(client, 0, 0))
          923                                 goto Eimageexists;
          924                         drawinstall(client, 0, client->screenimage, 0);
          925                         client->infoid = 0;
          926                         continue;
          927 
          928                 /* get image info: 'I' */
          929                 case 'I':
          930                         m = 1;
          931                         if(n < m)
          932                                 goto Eshortdraw;
          933                         if(client->infoid < 0)
          934                                 goto Enodrawimage;
          935                         if(client->infoid == 0){
          936                                 i = client->screenimage;
          937                                 if(i == nil)
          938                                         goto Enodrawimage;
          939                         }else{
          940                                 di = drawlookup(client, client->infoid, 1);
          941                                 if(di == nil)
          942                                         goto Enodrawimage;
          943                                 i = di->image;
          944                         }
          945                         ni = sprint(ibuf, "%11d %11d %11s %11d %11d %11d %11d %11d"
          946                                         " %11d %11d %11d %11d ",
          947                                         client->clientid,
          948                                         client->infoid,
          949                                         chantostr(cbuf, i->chan),
          950                                         (i->flags&Frepl)==Frepl,
          951                                         i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
          952                                         i->clipr.min.x, i->clipr.min.y,
          953                                         i->clipr.max.x, i->clipr.max.y);
          954                         free(client->readdata);
          955                         client->readdata = malloc(ni);
          956                         if(client->readdata == nil)
          957                                 goto Enomem;
          958                         memmove(client->readdata, ibuf, ni);
          959                         client->nreaddata = ni;
          960                         client->infoid = -1;
          961                         continue;
          962 
          963                 /* query: 'Q' n[1] queryspec[n] */
          964                 case 'q':
          965                         if(n < 2)
          966                                 goto Eshortdraw;
          967                         m = 1+1+a[1];
          968                         if(n < m)
          969                                 goto Eshortdraw;
          970                         fmtstrinit(&fmt);
          971                         for(c=0; c<a[1]; c++) {
          972                                 switch(a[2+c]) {
          973                                 default:
          974                                         err = "unknown query";
          975                                         goto error;
          976                                 case 'd':        /* dpi */
          977                                         if(client->forcedpi)
          978                                                 fmtprint(&fmt, "%11d ", client->forcedpi);
          979                                         else
          980                                                 fmtprint(&fmt, "%11d ", client->displaydpi);
          981                                         break;
          982                                 }
          983                         }
          984                         client->readdata = (uchar*)fmtstrflush(&fmt);
          985                         if(client->readdata == nil)
          986                                 goto Enomem;
          987                         client->nreaddata = strlen((char*)client->readdata);
          988                         continue;
          989 
          990                 /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
          991                 case 'l':
          992                         m = 1+4+4+2+4*4+2*4+1+1;
          993                         if(n < m)
          994                                 goto Eshortdraw;
          995                         font = drawlookup(client, BGLONG(a+1), 1);
          996                         if(font == 0)
          997                                 goto Enodrawimage;
          998                         if(font->nfchar == 0)
          999                                 goto Enotfont;
         1000                         src = drawimage(client, a+5);
         1001                         if(!src)
         1002                                 goto Enodrawimage;
         1003                         ci = BGSHORT(a+9);
         1004                         if(ci >= font->nfchar)
         1005                                 goto Eindex;
         1006                         drawrectangle(&r, a+11);
         1007                         drawpoint(&p, a+27);
         1008                         memdraw(font->image, r, src, p, memopaque, p, S);
         1009                         fc = &font->fchar[ci];
         1010                         fc->minx = r.min.x;
         1011                         fc->maxx = r.max.x;
         1012                         fc->miny = r.min.y;
         1013                         fc->maxy = r.max.y;
         1014                         fc->left = a[35];
         1015                         fc->width = a[36];
         1016                         continue;
         1017 
         1018                 /* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
         1019                 case 'L':
         1020                         m = 1+4+2*4+2*4+4+4+4+4+2*4;
         1021                         if(n < m)
         1022                                 goto Eshortdraw;
         1023                         dst = drawimage(client, a+1);
         1024                         dstid = BGLONG(a+1);
         1025                         drawpoint(&p, a+5);
         1026                         drawpoint(&q, a+13);
         1027                         e0 = BGLONG(a+21);
         1028                         e1 = BGLONG(a+25);
         1029                         j = BGLONG(a+29);
         1030                         if(j < 0){
         1031                                 err = "negative line width";
         1032                                 goto error;
         1033                         }
         1034                         src = drawimage(client, a+33);
         1035                         if(!dst || !src)
         1036                                 goto Enodrawimage;
         1037                         drawpoint(&sp, a+37);
         1038                         op = drawclientop(client);
         1039                         memline(dst, p, q, e0, e1, j, src, sp, op);
         1040                         /* avoid memlinebbox if possible */
         1041                         if(dstid==0 || dst->layer!=nil){
         1042                                 /* BUG: this is terribly inefficient: update maximal containing rect*/
         1043                                 r = memlinebbox(p, q, e0, e1, j);
         1044                                 dstflush(client, dstid, dst, insetrect(r, -(1+1+j)));
         1045                         }
         1046                         continue;
         1047 
         1048                 /* create image mask: 'm' newid[4] id[4] */
         1049 /*
         1050  *
         1051                 case 'm':
         1052                         m = 4+4;
         1053                         if(n < m)
         1054                                 goto Eshortdraw;
         1055                         break;
         1056  *
         1057  */
         1058 
         1059                 /* attach to a named image: 'n' dstid[4] j[1] name[j] */
         1060                 case 'n':
         1061                         m = 1+4+1;
         1062                         if(n < m)
         1063                                 goto Eshortdraw;
         1064                         j = a[5];
         1065                         if(j == 0)        /* give me a non-empty name please */
         1066                                 goto Eshortdraw;
         1067                         m += j;
         1068                         if(n < m)
         1069                                 goto Eshortdraw;
         1070                         dstid = BGLONG(a+1);
         1071                         if(drawlookup(client, dstid, 0))
         1072                                 goto Eimageexists;
         1073                         dn = drawlookupname(client, j, (char*)a+6);
         1074                         if(dn == nil)
         1075                                 goto Enoname;
         1076                         s = malloc(j+1);
         1077                         if(s == nil)
         1078                                 goto Enomem;
         1079                         if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
         1080                                 goto Edrawmem;
         1081                         di = drawlookup(client, dstid, 0);
         1082                         if(di == 0)
         1083                                 goto Eoldname;
         1084                         di->vers = dn->vers;
         1085                         di->name = s;
         1086                         di->fromname = dn->dimage;
         1087                         di->fromname->ref++;
         1088                         memmove(di->name, a+6, j);
         1089                         di->name[j] = 0;
         1090                         client->infoid = dstid;
         1091                         continue;
         1092 
         1093                 /* name an image: 'N' dstid[4] in[1] j[1] name[j] */
         1094                 case 'N':
         1095                         m = 1+4+1+1;
         1096                         if(n < m)
         1097                                 goto Eshortdraw;
         1098                         c = a[5];
         1099                         j = a[6];
         1100                         if(j == 0)        /* give me a non-empty name please */
         1101                                 goto Eshortdraw;
         1102                         m += j;
         1103                         if(n < m)
         1104                                 goto Eshortdraw;
         1105                         di = drawlookup(client, BGLONG(a+1), 0);
         1106                         if(di == 0)
         1107                                 goto Enodrawimage;
         1108                         if(di->name)
         1109                                 goto Enamed;
         1110                         if(c)
         1111                                 if(drawaddname(client, di, j, (char*)a+7, &err) < 0)
         1112                                         goto error;
         1113                         else{
         1114                                 dn = drawlookupname(client, j, (char*)a+7);
         1115                                 if(dn == nil)
         1116                                         goto Enoname;
         1117                                 if(dn->dimage != di)
         1118                                         goto Ewrongname;
         1119                                 drawdelname(client, dn);
         1120                         }
         1121                         continue;
         1122 
         1123                 /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
         1124                 case 'o':
         1125                         m = 1+4+2*4+2*4;
         1126                         if(n < m)
         1127                                 goto Eshortdraw;
         1128                         dst = drawimage(client, a+1);
         1129                         if(!dst)
         1130                                 goto Enodrawimage;
         1131                         if(dst->layer){
         1132                                 drawpoint(&p, a+5);
         1133                                 drawpoint(&q, a+13);
         1134                                 r = dst->layer->screenr;
         1135                                 ni = memlorigin(dst, p, q);
         1136                                 if(ni < 0){
         1137                                         err = "image origin failed";
         1138                                         goto error;
         1139                                 }
         1140                                 if(ni > 0){
         1141                                         addflush(client, r);
         1142                                         addflush(client, dst->layer->screenr);
         1143                                         ll = drawlookup(client, BGLONG(a+1), 1);
         1144                                         drawrefreshscreen(ll, client);
         1145                                 }
         1146                         }
         1147                         continue;
         1148 
         1149                 /* set compositing operator for next draw operation: 'O' op */
         1150                 case 'O':
         1151                         m = 1+1;
         1152                         if(n < m)
         1153                                 goto Eshortdraw;
         1154                         client->op = a[1];
         1155                         continue;
         1156 
         1157                 /* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
         1158                 /* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
         1159                 case 'p':
         1160                 case 'P':
         1161                         m = 1+4+2+4+4+4+4+2*4;
         1162                         if(n < m)
         1163                                 goto Eshortdraw;
         1164                         dstid = BGLONG(a+1);
         1165                         dst = drawimage(client, a+1);
         1166                         ni = BGSHORT(a+5);
         1167                         if(ni < 0){
         1168                                 err = "negative cout in polygon";
         1169                                 goto error;
         1170                         }
         1171                         e0 = BGLONG(a+7);
         1172                         e1 = BGLONG(a+11);
         1173                         j = 0;
         1174                         if(*a == 'p'){
         1175                                 j = BGLONG(a+15);
         1176                                 if(j < 0){
         1177                                         err = "negative polygon line width";
         1178                                         goto error;
         1179                                 }
         1180                         }
         1181                         src = drawimage(client, a+19);
         1182                         if(!dst || !src)
         1183                                 goto Enodrawimage;
         1184                         drawpoint(&sp, a+23);
         1185                         drawpoint(&p, a+31);
         1186                         ni++;
         1187                         pp = mallocz(ni*sizeof(Point), 1);
         1188                         if(pp == nil)
         1189                                 goto Enomem;
         1190                         doflush = 0;
         1191                         if(dstid==0 || (dst->layer && dst->layer->screen->image->data == client->screenimage->data))
         1192                                 doflush = 1;        /* simplify test in loop */
         1193                         ox = oy = 0;
         1194                         esize = 0;
         1195                         u = a+m;
         1196                         for(y=0; y<ni; y++){
         1197                                 q = p;
         1198                                 oesize = esize;
         1199                                 u = drawcoord(u, a+n, ox, &p.x);
         1200                                 if(!u)
         1201                                         goto Eshortdraw;
         1202                                 u = drawcoord(u, a+n, oy, &p.y);
         1203                                 if(!u)
         1204                                         goto Eshortdraw;
         1205                                 ox = p.x;
         1206                                 oy = p.y;
         1207                                 if(doflush){
         1208                                         esize = j;
         1209                                         if(*a == 'p'){
         1210                                                 if(y == 0){
         1211                                                         c = memlineendsize(e0);
         1212                                                         if(c > esize)
         1213                                                                 esize = c;
         1214                                                 }
         1215                                                 if(y == ni-1){
         1216                                                         c = memlineendsize(e1);
         1217                                                         if(c > esize)
         1218                                                                 esize = c;
         1219                                                 }
         1220                                         }
         1221                                         if(*a=='P' && e0!=1 && e0 !=~0)
         1222                                                 r = dst->clipr;
         1223                                         else if(y > 0){
         1224                                                 r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1);
         1225                                                 combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
         1226                                         }
         1227                                         if(rectclip(&r, dst->clipr))                /* should perhaps be an arg to dstflush */
         1228                                                 dstflush(client, dstid, dst, r);
         1229                                 }
         1230                                 pp[y] = p;
         1231                         }
         1232                         if(y == 1)
         1233                                 dstflush(client, dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
         1234                         op = drawclientop(client);
         1235                         if(*a == 'p')
         1236                                 mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
         1237                         else
         1238                                 memfillpoly(dst, pp, ni, e0, src, sp, op);
         1239                         free(pp);
         1240                         m = u-a;
         1241                         continue;
         1242 
         1243                 /* read: 'r' id[4] R[4*4] */
         1244                 case 'r':
         1245                         m = 1+4+4*4;
         1246                         if(n < m)
         1247                                 goto Eshortdraw;
         1248                         i = drawimage(client, a+1);
         1249                         if(!i)
         1250                                 goto Enodrawimage;
         1251                         drawrectangle(&r, a+5);
         1252                         if(!rectinrect(r, i->r))
         1253                                 goto Ereadoutside;
         1254                         c = bytesperline(r, i->depth);
         1255                         c *= Dy(r);
         1256                         free(client->readdata);
         1257                         client->readdata = mallocz(c, 0);
         1258                         if(client->readdata == nil){
         1259                                 err = "readimage malloc failed";
         1260                                 goto error;
         1261                         }
         1262                         client->nreaddata = memunload(i, r, client->readdata, c);
         1263                         if(client->nreaddata < 0){
         1264                                 free(client->readdata);
         1265                                 client->readdata = nil;
         1266                                 err = "bad readimage call";
         1267                                 goto error;
         1268                         }
         1269                         continue;
         1270 
         1271                 /* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
         1272                 /* 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]) */
         1273                 case 's':
         1274                 case 'x':
         1275                         m = 1+4+4+4+2*4+4*4+2*4+2;
         1276                         if(*a == 'x')
         1277                                 m += 4+2*4;
         1278                         if(n < m)
         1279                                 goto Eshortdraw;
         1280 
         1281                         dst = drawimage(client, a+1);
         1282                         dstid = BGLONG(a+1);
         1283                         src = drawimage(client, a+5);
         1284                         if(!dst || !src)
         1285                                 goto Enodrawimage;
         1286                         font = drawlookup(client, BGLONG(a+9), 1);
         1287                         if(font == 0)
         1288                                 goto Enodrawimage;
         1289                         if(font->nfchar == 0)
         1290                                 goto Enotfont;
         1291                         drawpoint(&p, a+13);
         1292                         drawrectangle(&r, a+21);
         1293                         drawpoint(&sp, a+37);
         1294                         ni = BGSHORT(a+45);
         1295                         u = a+m;
         1296                         m += ni*2;
         1297                         if(n < m)
         1298                                 goto Eshortdraw;
         1299                         clipr = dst->clipr;
         1300                         dst->clipr = r;
         1301                         op = drawclientop(client);
         1302                         if(*a == 'x'){
         1303                                 /* paint background */
         1304                                 l = drawimage(client, a+47);
         1305                                 if(!l)
         1306                                         goto Enodrawimage;
         1307                                 drawpoint(&q, a+51);
         1308                                 r.min.x = p.x;
         1309                                 r.min.y = p.y-font->ascent;
         1310                                 r.max.x = p.x;
         1311                                 r.max.y = r.min.y+Dy(font->image->r);
         1312                                 j = ni;
         1313                                 while(--j >= 0){
         1314                                         ci = BGSHORT(u);
         1315                                         if(ci<0 || ci>=font->nfchar){
         1316                                                 dst->clipr = clipr;
         1317                                                 goto Eindex;
         1318                                         }
         1319                                         r.max.x += font->fchar[ci].width;
         1320                                         u += 2;
         1321                                 }
         1322                                 memdraw(dst, r, l, q, memopaque, ZP, op);
         1323                                 u -= 2*ni;
         1324                         }
         1325                         q = p;
         1326                         while(--ni >= 0){
         1327                                 ci = BGSHORT(u);
         1328                                 if(ci<0 || ci>=font->nfchar){
         1329                                         dst->clipr = clipr;
         1330                                         goto Eindex;
         1331                                 }
         1332                                 q = drawchar(dst, q, src, &sp, font, ci, op);
         1333                                 u += 2;
         1334                         }
         1335                         dst->clipr = clipr;
         1336                         p.y -= font->ascent;
         1337                         dstflush(client, dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
         1338                         continue;
         1339 
         1340                 /* use public screen: 'S' id[4] chan[4] */
         1341                 case 'S':
         1342                         m = 1+4+4;
         1343                         if(n < m)
         1344                                 goto Eshortdraw;
         1345                         dstid = BGLONG(a+1);
         1346                         if(dstid == 0)
         1347                                 goto Ebadarg;
         1348                         dscrn = drawlookupdscreen(client, dstid);
         1349                         if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
         1350                                 goto Enodrawscreen;
         1351                         if(dscrn->screen->image->chan != BGLONG(a+5)){
         1352                                 err = "inconsistent chan";
         1353                                 goto error;
         1354                         }
         1355                         if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
         1356                                 goto Edrawmem;
         1357                         continue;
         1358 
         1359                 /* top or bottom windows: 't' top[1] nw[2] n*id[4] */
         1360                 case 't':
         1361                         m = 1+1+2;
         1362                         if(n < m)
         1363                                 goto Eshortdraw;
         1364                         nw = BGSHORT(a+2);
         1365                         if(nw < 0)
         1366                                 goto Ebadarg;
         1367                         if(nw == 0)
         1368                                 continue;
         1369                         m += nw*4;
         1370                         if(n < m)
         1371                                 goto Eshortdraw;
         1372                         lp = mallocz(nw*sizeof(Memimage*), 1);
         1373                         if(lp == 0)
         1374                                 goto Enomem;
         1375                         for(j=0; j<nw; j++){
         1376                                 lp[j] = drawimage(client, a+1+1+2+j*4);
         1377                                 if(lp[j] == nil){
         1378                                         free(lp);
         1379                                         goto Enodrawimage;
         1380                                 }
         1381                         }
         1382                         if(lp[0]->layer == 0){
         1383                                 err = "images are not windows";
         1384                                 free(lp);
         1385                                 goto error;
         1386                         }
         1387                         for(j=1; j<nw; j++)
         1388                                 if(lp[j]->layer->screen != lp[0]->layer->screen){
         1389                                         err = "images not on same screen";
         1390                                         free(lp);
         1391                                         goto error;
         1392                                 }
         1393                         if(a[1])
         1394                                 memltofrontn(lp, nw);
         1395                         else
         1396                                 memltorearn(lp, nw);
         1397                         if(lp[0]->layer->screen->image->data == client->screenimage->data)
         1398                                 for(j=0; j<nw; j++)
         1399                                         addflush(client, lp[j]->layer->screenr);
         1400                         free(lp);
         1401                         ll = drawlookup(client, BGLONG(a+1+1+2), 1);
         1402                         drawrefreshscreen(ll, client);
         1403                         continue;
         1404 
         1405                 /* visible: 'v' */
         1406                 case 'v':
         1407                         m = 1;
         1408                         drawflush(client);
         1409                         continue;
         1410 
         1411                 /* write: 'y' id[4] R[4*4] data[x*1] */
         1412                 /* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */
         1413                 case 'y':
         1414                 case 'Y':
         1415                         m = 1+4+4*4;
         1416                         if(n < m)
         1417                                 goto Eshortdraw;
         1418                         dstid = BGLONG(a+1);
         1419                         dst = drawimage(client, a+1);
         1420                         if(!dst)
         1421                                 goto Enodrawimage;
         1422                         drawrectangle(&r, a+5);
         1423                         if(!rectinrect(r, dst->r))
         1424                                 goto Ewriteoutside;
         1425                         y = memload(dst, r, a+m, n-m, *a=='Y');
         1426                         if(y < 0){
         1427                                 err = "bad writeimage call";
         1428                                 goto error;
         1429                         }
         1430                         dstflush(client, dstid, dst, r);
         1431                         m += y;
         1432                         continue;
         1433                 }
         1434         }
         1435         rpc_gfxdrawunlock();
         1436         qunlock(&drawlk);
         1437         return oldn - n;
         1438 
         1439 Enodrawimage:
         1440         err = "unknown id for draw image";
         1441         goto error;
         1442 Enodrawscreen:
         1443         err = "unknown id for draw screen";
         1444         goto error;
         1445 Eshortdraw:
         1446         err = "short draw message";
         1447         goto error;
         1448 /*
         1449 Eshortread:
         1450         err = "draw read too short";
         1451         goto error;
         1452 */
         1453 Eimageexists:
         1454         err = "image id in use";
         1455         goto error;
         1456 Escreenexists:
         1457         err = "screen id in use";
         1458         goto error;
         1459 Edrawmem:
         1460         err = "image memory allocation failed";
         1461         goto error;
         1462 Ereadoutside:
         1463         err = "readimage outside image";
         1464         goto error;
         1465 Ewriteoutside:
         1466         err = "writeimage outside image";
         1467         goto error;
         1468 Enotfont:
         1469         err = "image not a font";
         1470         goto error;
         1471 Eindex:
         1472         err = "character index out of range";
         1473         goto error;
         1474 /*
         1475 Enoclient:
         1476         err = "no such draw client";
         1477         goto error;
         1478 Edepth:
         1479         err = "image has bad depth";
         1480         goto error;
         1481 Enameused:
         1482         err = "image name in use";
         1483         goto error;
         1484 */
         1485 Enoname:
         1486         err = "no image with that name";
         1487         goto error;
         1488 Eoldname:
         1489         err = "named image no longer valid";
         1490         goto error;
         1491 Enamed:
         1492         err = "image already has name";
         1493         goto error;
         1494 Ewrongname:
         1495         err = "wrong name for image";
         1496         goto error;
         1497 Enomem:
         1498         err = "out of memory";
         1499         goto error;
         1500 Ebadarg:
         1501         err = "bad argument in draw message";
         1502         goto error;
         1503 
         1504 error:
         1505         werrstr("%s", err);
         1506         rpc_gfxdrawunlock();
         1507         qunlock(&drawlk);
         1508         return -1;
         1509 }