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 }