vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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 }