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 }