x11-draw.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       x11-draw.c (9288B)
       ---
            1 #include "u.h"
            2 #include "lib.h"
            3 #include "mem.h"
            4 #include "dat.h"
            5 #include "fns.h"
            6 #include "error.h"
            7 #define Image IMAGE        /* kernel has its own Image */
            8 #include <draw.h>
            9 #include <memdraw.h>
           10 #include <keyboard.h>
           11 #include <cursor.h>
           12 #include "screen.h"
           13 #include "x11-inc.h"
           14 
           15 /*
           16  * Allocate a Memimage with an optional pixmap backing on the X server.
           17  */
           18 Memimage*
           19 _xallocmemimage(Rectangle r, uint32 chan, int pixmap)
           20 {
           21         int d, offset;
           22         Memimage *m;
           23         Xmem *xm;
           24         XImage *xi;
           25 
           26         m = _allocmemimage(r, chan);
           27         if(chan != GREY1 && chan != _x.chan)
           28                 return m;
           29         if(_x.display == 0)
           30                 return m;
           31 
           32         /*
           33          * For bootstrapping, don't bother storing 1x1 images
           34          * on the X server.  Memimageinit needs to allocate these
           35          * and we memimageinit before we do the rest of the X stuff.
           36          * Of course, 1x1 images on the server are useless anyway.
           37          */
           38         if(Dx(r)==1 && Dy(r)==1)
           39                 return m;
           40 
           41         xm = mallocz(sizeof(Xmem), 1);
           42         if(xm == nil){
           43                 iprint("mallocz failed\n");
           44                 freememimage(m);
           45                 return nil;
           46         }
           47 
           48         /*
           49          * Allocate backing store.
           50          */
           51         if(chan == GREY1)
           52                 d = 1;
           53         else
           54                 d = _x.depth;
           55         if(pixmap != PMundef)
           56                 xm->pixmap = pixmap;
           57         else
           58                 xm->pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), d);
           59 
           60         /*
           61          * We want to align pixels on word boundaries.
           62          */
           63         if(m->depth == 24)
           64                 offset = r.min.x&3;
           65         else
           66                 offset = r.min.x&(31/m->depth);
           67         r.min.x -= offset;
           68         assert(wordsperline(r, m->depth) <= m->width);
           69 
           70         /*
           71          * Wrap our data in an XImage structure.
           72          */
           73         xi = XCreateImage(_x.display, _x.vis, d,
           74                 ZPixmap, 0, (char*)m->data->bdata, Dx(r), Dy(r),
           75                 32, m->width*sizeof(uint32));
           76         if(xi == nil){
           77                 iprint("XCreateImage %R %d %d failed\n", r, m->width, m->depth);
           78                 freememimage(m);
           79                 if(xm->pixmap != pixmap)
           80                         XFreePixmap(_x.display, xm->pixmap);
           81                 return nil;
           82         }
           83 
           84         xm->xi = xi;
           85         xm->r = r;
           86 
           87         /*
           88          * Set the XImage parameters so that it looks exactly like
           89          * a Memimage -- we're using the same data.
           90          */
           91         if(m->depth < 8 || m->depth == 24)
           92                 xi->bitmap_unit = 8;
           93         else
           94                 xi->bitmap_unit = m->depth;
           95         xi->byte_order = LSBFirst;
           96         xi->bitmap_bit_order = MSBFirst;
           97         xi->bitmap_pad = 32;
           98         XInitImage(xi);
           99         XFlush(_x.display);
          100 
          101         m->x = xm;
          102         return m;
          103 }
          104 
          105 /*
          106  * Replacements for libmemdraw routines.
          107  * (They've been underscored.)
          108  */
          109 Memimage*
          110 allocmemimage(Rectangle r, uint32 chan)
          111 {
          112         return _xallocmemimage(r, chan, PMundef);
          113 }
          114 
          115 void
          116 freememimage(Memimage *m)
          117 {
          118         Xmem *xm;
          119 
          120         if(m == nil)
          121                 return;
          122 
          123         xm = m->x;
          124         if(xm && m->data->ref == 1){
          125                 if(xm->xi){
          126                         xm->xi->data = nil;
          127                         XFree(xm->xi);
          128                 }
          129                 XFreePixmap(_x.display, xm->pixmap);
          130                 free(xm);
          131                 m->x = nil;
          132         }
          133         _freememimage(m);
          134 }
          135 
          136 
          137 int
          138 cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
          139 {
          140         int n;
          141 
          142         n = _cloadmemimage(i, r, data, ndata);
          143         if(n > 0 && i->x)
          144                 _xputxdata(i, r);
          145         return n;
          146 }
          147 
          148 static int xdraw(Memdrawparam*);
          149 
          150 /*
          151  * The X acceleration doesn't fit into the standard hwaccel
          152  * model because we have the extra steps of pulling the image
          153  * data off the server and putting it back when we're done.
          154  */
          155 void
          156 memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp,
          157         Memimage *mask, Point mp, int op)
          158 {
          159         Memdrawparam *par;
          160 
          161         if((par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil)
          162                 return;
          163 
          164         /* only fetch dst data if we need it */
          165         if((par->state&(Simplemask|Fullmask)) != (Simplemask|Fullmask))
          166                 _xgetxdata(par->dst, par->r);
          167 
          168         /* always fetch source and mask */
          169         _xgetxdata(par->src, par->sr);
          170         _xgetxdata(par->mask, par->mr);
          171 
          172         /* now can run memimagedraw on the in-memory bits */
          173         _memimagedraw(par);
          174 
          175         if(xdraw(par))
          176                 return;
          177 
          178         /* put bits back on x server */
          179         _xputxdata(par->dst, par->r);
          180 }
          181 
          182 static int
          183 xdraw(Memdrawparam *par)
          184 {
          185         uint32 sdval;
          186         uint m, state;
          187         Memimage *src, *dst, *mask;
          188         Point dp, mp, sp;
          189         Rectangle r;
          190         Xmem *xdst, *xmask, *xsrc;
          191         XGC gc;
          192 
          193         if(par->dst->x == nil)
          194                 return 0;
          195 
          196         dst   = par->dst;
          197         mask  = par->mask;
          198         r     = par->r;
          199         src   = par->src;
          200         state = par->state;
          201 
          202         /*
          203          * If we have an opaque mask and source is one opaque pixel,
          204          * we can convert to the destination format and just XFillRectangle.
          205          */
          206         m = Simplesrc|Fullsrc|Simplemask|Fullmask;
          207         if((state&m) == m){
          208                 _xfillcolor(dst, r, par->sdval);
          209         /*        xdirtyxdata(dst, r); */
          210                 return 1;
          211         }
          212 
          213         /*
          214          * If no source alpha and an opaque mask, we can just copy
          215          * the source onto the destination.  If the channels are the
          216          * same and the source is not replicated, XCopyArea works.
          217          */
          218         m = Simplemask|Fullmask;
          219         if((state&(m|Replsrc))==m && src->chan==dst->chan && src->x){
          220                 xdst = dst->x;
          221                 xsrc = src->x;
          222                 dp = subpt(r.min,       dst->r.min);
          223                 sp = subpt(par->sr.min, src->r.min);
          224                 gc = dst->chan==GREY1 ?  _x.gccopy0 : _x.gccopy;
          225 
          226                 XCopyArea(_x.display, xsrc->pixmap, xdst->pixmap, gc,
          227                         sp.x, sp.y, Dx(r), Dy(r), dp.x, dp.y);
          228         /*        xdirtyxdata(dst, r); */
          229                 return 1;
          230         }
          231 
          232         /*
          233          * If no source alpha, a 1-bit mask, and a simple source,
          234          * we can copy through the mask onto the destination.
          235          */
          236         if(dst->x && mask->x && !(mask->flags&Frepl)
          237         && mask->chan==GREY1 && (state&Simplesrc)){
          238                 xdst = dst->x;
          239                 xmask = mask->x;
          240                 sdval = par->sdval;
          241 
          242                 dp = subpt(r.min, dst->r.min);
          243                 mp = subpt(r.min, subpt(par->mr.min, mask->r.min));
          244 
          245                 if(dst->chan == GREY1){
          246                         gc = _x.gcsimplesrc0;
          247                         if(_x.gcsimplesrc0color != sdval){
          248                                 XSetForeground(_x.display, gc, sdval);
          249                                 _x.gcsimplesrc0color = sdval;
          250                         }
          251                         if(_x.gcsimplesrc0pixmap != xmask->pixmap){
          252                                 XSetStipple(_x.display, gc, xmask->pixmap);
          253                                 _x.gcsimplesrc0pixmap = xmask->pixmap;
          254                         }
          255                 }else{
          256                         /* this doesn't work on rob's mac?  */
          257                         return 0;
          258                         /* gc = _x.gcsimplesrc;
          259                         if(dst->chan == CMAP8 && _x.usetable)
          260                                 sdval = _x.tox11[sdval];
          261 
          262                         if(_x.gcsimplesrccolor != sdval){
          263                                 XSetForeground(_x.display, gc, sdval);
          264                                 _x.gcsimplesrccolor = sdval;
          265                         }
          266                         if(_x.gcsimplesrcpixmap != xmask->pixmap){
          267                                 XSetStipple(_x.display, gc, xmask->pixmap);
          268                                 _x.gcsimplesrcpixmap = xmask->pixmap;
          269                         }
          270                         */
          271                 }
          272                 XSetTSOrigin(_x.display, gc, mp.x, mp.y);
          273                 XFillRectangle(_x.display, xdst->pixmap, gc, dp.x, dp.y,
          274                         Dx(r), Dy(r));
          275         /*        xdirtyxdata(dst, r); */
          276                 return 1;
          277         }
          278 
          279         /*
          280          * Can't accelerate.
          281          */
          282         return 0;
          283 }
          284 
          285 
          286 void
          287 memfillcolor(Memimage *m, uint32 val)
          288 {
          289         _memfillcolor(m, val);
          290         if(m->x == nil)
          291                 return;
          292         if((val & 0xFF) == 0xFF)        /* full alpha */
          293                 _xfillcolor(m, m->r, _rgbatoimg(m, val));
          294         else
          295                 _xputxdata(m, m->r);
          296 }
          297 
          298 void
          299 _xfillcolor(Memimage *m, Rectangle r, uint32 v)
          300 {
          301         Point p;
          302         Xmem *xm;
          303         XGC gc;
          304         
          305         xm = m->x;
          306         assert(xm != nil);
          307 
          308         /*
          309          * Set up fill context appropriately.
          310          */
          311         if(m->chan == GREY1){
          312                 gc = _x.gcfill0;
          313                 if(_x.gcfill0color != v){
          314                         XSetForeground(_x.display, gc, v);
          315                         _x.gcfill0color = v;
          316                 }
          317         }else{
          318                 if(m->chan == CMAP8 && _x.usetable)
          319                         v = _x.tox11[v];
          320                 gc = _x.gcfill;
          321                 if(_x.gcfillcolor != v){
          322                         XSetForeground(_x.display, gc, v);
          323                         _x.gcfillcolor = v;
          324                 }
          325         }
          326 
          327         /*
          328          * XFillRectangle takes coordinates relative to image rectangle.
          329          */
          330         p = subpt(r.min, m->r.min);
          331         XFillRectangle(_x.display, xm->pixmap, gc, p.x, p.y, Dx(r), Dy(r));
          332 }
          333 
          334 static void
          335 addrect(Rectangle *rp, Rectangle r)
          336 {
          337         if(rp->min.x >= rp->max.x)
          338                 *rp = r;
          339         else
          340                 combinerect(rp, r);
          341 }
          342 
          343 XImage*
          344 _xgetxdata(Memimage *m, Rectangle r)
          345 {
          346         int x, y;
          347         uchar *p;
          348         Point tp, xdelta, delta;
          349         Xmem *xm;
          350         
          351         xm = m->x;
          352         if(xm == nil)
          353                 return nil;
          354 
          355         if(xm->dirty == 0)
          356                 return xm->xi;
          357 
          358         abort();        /* should never call this now */
          359 
          360         r = xm->dirtyr;
          361         if(Dx(r)==0 || Dy(r)==0)
          362                 return xm->xi;
          363 
          364         delta = subpt(r.min, m->r.min);
          365 
          366         tp = xm->r.min;        /* need temp for Digital UNIX */
          367         xdelta = subpt(r.min, tp);
          368 
          369         XGetSubImage(_x.display, xm->pixmap, delta.x, delta.y, Dx(r), Dy(r),
          370                 AllPlanes, ZPixmap, xm->xi, xdelta.x, delta.y);
          371 
          372         if(_x.usetable && m->chan==CMAP8){
          373                 for(y=r.min.y; y<r.max.y; y++)
          374                 for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
          375                         *p = _x.toplan9[*p];
          376         }
          377         xm->dirty = 0;
          378         xm->dirtyr = Rect(0,0,0,0);
          379         return xm->xi;
          380 }
          381 
          382 void
          383 _xputxdata(Memimage *m, Rectangle r)
          384 {
          385         int offset, x, y;
          386         uchar *p;
          387         Point tp, xdelta, delta;
          388         Xmem *xm;
          389         XGC gc;
          390         XImage *xi;
          391 
          392         xm = m->x;
          393         if(xm == nil)
          394                 return;
          395 
          396         xi = xm->xi;
          397         gc = m->chan==GREY1 ? _x.gccopy0 : _x.gccopy;
          398         if(m->depth == 24)
          399                 offset = r.min.x & 3;
          400         else
          401                 offset = r.min.x & (31/m->depth);
          402 
          403         delta = subpt(r.min, m->r.min);
          404 
          405         tp = xm->r.min;        /* need temporary on Digital UNIX */
          406         xdelta = subpt(r.min, tp);
          407 
          408         if(_x.usetable && m->chan==CMAP8){
          409                 for(y=r.min.y; y<r.max.y; y++)
          410                 for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
          411                         *p = _x.tox11[*p];
          412         }
          413 
          414         XPutImage(_x.display, xm->pixmap, gc, xi, xdelta.x, xdelta.y, delta.x, delta.y,
          415                 Dx(r), Dy(r));
          416         
          417         if(_x.usetable && m->chan==CMAP8){
          418                 for(y=r.min.y; y<r.max.y; y++)
          419                 for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
          420                         *p = _x.toplan9[*p];
          421         }
          422 }
          423 
          424 void
          425 _xdirtyxdata(Memimage *m, Rectangle r)
          426 {
          427         Xmem *xm;
          428 
          429         xm = m->x;
          430         if(xm == nil)
          431                 return;
          432 
          433         xm->dirty = 1;
          434         addrect(&xm->dirtyr, r);
          435 }
          436 
          437 
          438 int
          439 loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
          440 {
          441         int n;
          442 
          443         n = _loadmemimage(i, r, data, ndata);
          444         if(n > 0 && i->x)
          445                 _xputxdata(i, r);
          446         return n;
          447 }
          448 
          449 int
          450 unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
          451 {
          452         if(i->x)
          453                 _xgetxdata(i, r);
          454         return _unloadmemimage(i, r, data, ndata);
          455 }
          456 
          457 uint32
          458 pixelbits(Memimage *m, Point p)
          459 {
          460         if(m->x)
          461                 _xgetxdata(m, Rect(p.x, p.y, p.x+1, p.y+1));
          462         return _pixelbits(m, p);
          463 }