1 #include "common.h"
2 #ifdef BUILD_X11
3 #include <X11/Xlib.h>
4 #include <X11/Xutil.h>
5 #include <X11/extensions/shape.h>
6 #include <X11/extensions/XShm.h>
7 #include <sys/ipc.h>
8 #include <sys/shm.h>
9
10 #include "grab.h"
11 #include "ximage.h"
12
13 static char _x_err = 0;
14 static DATA8 rtab[256], gtab[256], btab[256];
15
16 static int
Tmp_HandleXError(Display * d,XErrorEvent * ev)17 Tmp_HandleXError(Display * d, XErrorEvent * ev)
18 {
19 _x_err = 1;
20 return 0;
21 }
22
23 void
__imlib_GrabXImageToRGBA(DATA32 * data,int ox,int oy,int ow,int oh,Display * d,XImage * xim,XImage * mxim,Visual * v,int depth,int x,int y,int w,int h,char grab)24 __imlib_GrabXImageToRGBA(DATA32 * data, int ox, int oy, int ow, int oh,
25 Display * d, XImage * xim, XImage * mxim, Visual * v,
26 int depth, int x, int y, int w, int h, char grab)
27 {
28 int inx, iny;
29 const DATA32 *src;
30 DATA32 *ptr;
31 int pixel;
32 int origx, origy;
33 int bgr = 0;
34
35 if (!data)
36 return;
37
38 if (grab)
39 XGrabServer(d); /* This may prevent the image to be changed under our feet */
40 origx = x;
41 origy = y;
42
43 if (v->blue_mask > v->red_mask)
44 bgr = 1;
45
46 if (origx < 0)
47 inx = -origx;
48 else
49 inx = ox;
50 if (origy < 0)
51 iny = -origy;
52 else
53 iny = oy;
54 /* go thru the XImage and convert */
55 if ((depth == 24) && (xim->bits_per_pixel == 32))
56 depth = 25; /* fake depth meaning 24 bit in 32 bpp ximage */
57 /* data needs swapping */
58
59 #ifdef WORDS_BIGENDIAN
60 if (xim->bitmap_bit_order == LSBFirst)
61 #else
62 if (xim->bitmap_bit_order == MSBFirst)
63 #endif
64 {
65 switch (depth)
66 {
67 case 0:
68 case 1:
69 case 2:
70 case 3:
71 case 4:
72 case 5:
73 case 6:
74 case 7:
75 case 8:
76 break;
77 case 15:
78 case 16:
79 for (y = 0; y < h; y++)
80 {
81 unsigned short *tmp;
82
83 tmp =
84 (unsigned short *)(xim->data + (xim->bytes_per_line * y));
85 for (x = 0; x < w; x++)
86 {
87 *tmp = SWAP16(*tmp);
88 tmp++;
89 }
90 }
91 break;
92 case 24:
93 case 25:
94 case 32:
95 for (y = 0; y < h; y++)
96 {
97 unsigned int *tmp;
98
99 tmp = (unsigned int *)(xim->data + (xim->bytes_per_line * y));
100 for (x = 0; x < w; x++)
101 {
102 *tmp = SWAP32(*tmp);
103 tmp++;
104 }
105 }
106 break;
107 default:
108 break;
109 }
110 }
111 switch (depth)
112 {
113 case 0:
114 case 1:
115 case 2:
116 case 3:
117 case 4:
118 case 5:
119 case 6:
120 case 7:
121 case 8:
122 if (mxim)
123 {
124 for (y = 0; y < h; y++)
125 {
126 ptr = data + ((y + iny) * ow) + inx;
127 for (x = 0; x < w; x++)
128 {
129 pixel = XGetPixel(xim, x, y);
130 pixel = (btab[pixel & 0xff]) |
131 (gtab[pixel & 0xff] << 8) |
132 (rtab[pixel & 0xff] << 16);
133 if (XGetPixel(mxim, x, y))
134 pixel |= 0xff000000;
135 *ptr++ = pixel;
136 }
137 }
138 }
139 else
140 {
141 for (y = 0; y < h; y++)
142 {
143 ptr = data + ((y + iny) * ow) + inx;
144 for (x = 0; x < w; x++)
145 {
146 pixel = XGetPixel(xim, x, y);
147 *ptr++ = 0xff000000 |
148 (btab[pixel & 0xff]) |
149 (gtab[pixel & 0xff] << 8) |
150 (rtab[pixel & 0xff] << 16);
151 }
152 }
153 }
154 break;
155 case 16:
156 #undef MP
157 #undef RMSK
158 #undef GMSK
159 #undef BMSK
160 #undef R1SH
161 #undef G1SH
162 #undef B1SH
163 #undef R2SH
164 #undef G2SH
165 #undef B2SH
166 #undef P1
167 #undef P2
168 #define MP(x, y) ((XGetPixel(mxim, (x), (y))) ? 0xff000000 : 0)
169 #define RMSK 0xf80000
170 #define GMSK 0x00fc00
171 #define BMSK 0x0000f8
172 #define R1SH(p) ((p) << 8)
173 #define G1SH(p) ((p) << 5)
174 #define B1SH(p) ((p) << 3)
175 #define R2SH(p) ((p) >> 8)
176 #define G2SH(p) ((p) >> 11)
177 #define B2SH(p) ((p) >> 13)
178 #define P1(p) (R1SH(p) & RMSK) | (G1SH(p) & GMSK) | (B1SH(p) & BMSK)
179 #define P2(p) (R2SH(p) & RMSK) | (G2SH(p) & GMSK) | (B2SH(p) & BMSK)
180 if (mxim)
181 {
182 for (y = 0; y < h; y++)
183 {
184 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
185 ptr = data + ((y + iny) * ow) + inx;
186 for (x = 0; x < (w - 1); x += 2)
187 {
188 #ifdef WORDS_BIGENDIAN
189 *ptr++ = MP(x + 1, y) | P2(*src);
190 *ptr++ = MP(x, y) | P1(*src);
191 #else
192 *ptr++ = MP(x, y) | P1(*src);
193 *ptr++ = MP(x + 1, y) | P2(*src);
194 #endif
195 src++;
196 }
197 if (x == (w - 1))
198 {
199 pixel = XGetPixel(xim, x, y);
200 *ptr++ = MP(x, y) | P1(pixel);
201 }
202 }
203 }
204 #undef MP
205 #define MP(x, y) (0xff000000)
206 else
207 {
208 for (y = 0; y < h; y++)
209 {
210 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
211 ptr = data + ((y + iny) * ow) + inx;
212 for (x = 0; x < (w - 1); x += 2)
213 {
214 #ifdef WORDS_BIGENDIAN
215 *ptr++ = MP(x + 1, y) | P2(*src);
216 *ptr++ = MP(x, y) | P1(*src);
217 #else
218 *ptr++ = MP(x, y) | P1(*src);
219 *ptr++ = MP(x + 1, y) | P2(*src);
220 #endif
221 src++;
222 }
223 if (x == (w - 1))
224 {
225 pixel = XGetPixel(xim, x, y);
226 *ptr++ = MP(x, y) | P1(pixel);
227 }
228 }
229 }
230 break;
231 case 15:
232 #undef MP
233 #undef RMSK
234 #undef GMSK
235 #undef BMSK
236 #undef R1SH
237 #undef G1SH
238 #undef B1SH
239 #undef R2SH
240 #undef G2SH
241 #undef B2SH
242 #undef P1
243 #undef P2
244 #define MP(x, y) ((XGetPixel(mxim, (x), (y))) ? 0xff000000 : 0)
245 #define RMSK 0xf80000
246 #define GMSK 0x00f800
247 #define BMSK 0x0000f8
248 #define R1SH(p) ((p) << 9)
249 #define G1SH(p) ((p) << 6)
250 #define B1SH(p) ((p) << 3)
251 #define R2SH(p) ((p) >> 7)
252 #define G2SH(p) ((p) >> 10)
253 #define B2SH(p) ((p) >> 13)
254 #define P1(p) (R1SH(p) & RMSK) | (G1SH(p) & GMSK) | (B1SH(p) & BMSK)
255 #define P2(p) (R2SH(p) & RMSK) | (G2SH(p) & GMSK) | (B2SH(p) & BMSK)
256 if (mxim)
257 {
258 for (y = 0; y < h; y++)
259 {
260 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
261 ptr = data + ((y + iny) * ow) + inx;
262 for (x = 0; x < (w - 1); x += 2)
263 {
264 #ifdef WORDS_BIGENDIAN
265 *ptr++ = MP(x + 1, y) | P2(*src);
266 *ptr++ = MP(x, y) | P1(*src);
267 #else
268 *ptr++ = MP(x, y) | P1(*src);
269 *ptr++ = MP(x + 1, y) | P2(*src);
270 #endif
271 src++;
272 }
273 if (x == (w - 1))
274 {
275 pixel = XGetPixel(xim, x, y);
276 *ptr++ = MP(x, y) | P1(pixel);
277 }
278 }
279 }
280 #undef MP
281 #define MP(x, y) (0xff000000)
282 else
283 {
284 for (y = 0; y < h; y++)
285 {
286 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
287 ptr = data + ((y + iny) * ow) + inx;
288 for (x = 0; x < (w - 1); x += 2)
289 {
290 #ifdef WORDS_BIGENDIAN
291 *ptr++ = MP(x + 1, y) | P2(*src);
292 *ptr++ = MP(x, y) | P1(*src);
293 #else
294 *ptr++ = MP(x, y) | P1(*src);
295 *ptr++ = MP(x + 1, y) | P2(*src);
296 #endif
297 src++;
298 }
299 if (x == (w - 1))
300 {
301 pixel = XGetPixel(xim, x, y);
302 *ptr++ = MP(x, y) | P1(pixel);
303 }
304 }
305 }
306 break;
307 case 24:
308 if (bgr)
309 {
310 if (mxim)
311 {
312 for (y = 0; y < h; y++)
313 {
314 ptr = data + ((y + iny) * ow) + inx;
315 for (x = 0; x < w; x++)
316 {
317 pixel = XGetPixel(xim, x, y);
318 pixel = ((pixel << 16) & 0xff0000) |
319 ((pixel) & 0x00ff00) |
320 ((pixel >> 16) & 0x0000ff);
321 if (XGetPixel(mxim, x, y))
322 pixel |= 0xff000000;
323 *ptr++ = pixel;
324 }
325 }
326 }
327 else
328 {
329 for (y = 0; y < h; y++)
330 {
331 ptr = data + ((y + iny) * ow) + inx;
332 for (x = 0; x < w; x++)
333 {
334 pixel = XGetPixel(xim, x, y);
335 *ptr++ = 0xff000000 |
336 ((pixel << 16) & 0xff0000) |
337 ((pixel) & 0x00ff00) |
338 ((pixel >> 16) & 0x0000ff);
339 }
340 }
341 }
342 }
343 else
344 {
345 if (mxim)
346 {
347 for (y = 0; y < h; y++)
348 {
349 ptr = data + ((y + iny) * ow) + inx;
350 for (x = 0; x < w; x++)
351 {
352 pixel = XGetPixel(xim, x, y) & 0x00ffffff;
353 if (XGetPixel(mxim, x, y))
354 pixel |= 0xff000000;
355 *ptr++ = pixel;
356 }
357 }
358 }
359 else
360 {
361 for (y = 0; y < h; y++)
362 {
363 ptr = data + ((y + iny) * ow) + inx;
364 for (x = 0; x < w; x++)
365 {
366 pixel = XGetPixel(xim, x, y);
367 *ptr++ = 0xff000000 | (pixel & 0x00ffffff);
368 }
369 }
370 }
371 }
372 break;
373 case 25:
374 if (bgr)
375 {
376 if (mxim)
377 {
378 for (y = 0; y < h; y++)
379 {
380 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
381 ptr = data + ((y + iny) * ow) + inx;
382 for (x = 0; x < w; x++)
383 {
384 pixel = ((*src << 16) & 0xff0000) |
385 ((*src) & 0x00ff00) | ((*src >> 16) & 0x0000ff);
386 if (XGetPixel(mxim, x, y))
387 pixel |= 0xff000000;
388 *ptr++ = pixel;
389 src++;
390 }
391 }
392 }
393 else
394 {
395 for (y = 0; y < h; y++)
396 {
397 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
398 ptr = data + ((y + iny) * ow) + inx;
399 for (x = 0; x < w; x++)
400 {
401 *ptr++ = 0xff000000 |
402 ((*src << 16) & 0xff0000) |
403 ((*src) & 0x00ff00) | ((*src >> 16) & 0x0000ff);
404 src++;
405 }
406 }
407 }
408 }
409 else
410 {
411 if (mxim)
412 {
413 for (y = 0; y < h; y++)
414 {
415 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
416 ptr = data + ((y + iny) * ow) + inx;
417 for (x = 0; x < w; x++)
418 {
419 pixel = (*src) & 0x00ffffff;
420 if (XGetPixel(mxim, x, y))
421 pixel |= 0xff000000;
422 *ptr++ = pixel;
423 src++;
424 }
425 }
426 }
427 else
428 {
429 for (y = 0; y < h; y++)
430 {
431 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
432 ptr = data + ((y + iny) * ow) + inx;
433 for (x = 0; x < w; x++)
434 {
435 *ptr++ = 0xff000000 | ((*src) & 0x00ffffff);
436 src++;
437 }
438 }
439 }
440 }
441 break;
442 case 32:
443 if (bgr)
444 {
445 if (mxim)
446 {
447 for (y = 0; y < h; y++)
448 {
449 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
450 ptr = data + ((y + iny) * ow) + inx;
451 for (x = 0; x < w; x++)
452 {
453 pixel = SWAP32(*src);
454 if (!XGetPixel(mxim, x, y))
455 pixel &= 0x00ffffff;
456 *ptr++ = pixel;
457 src++;
458 }
459 }
460 }
461 else
462 {
463 for (y = 0; y < h; y++)
464 {
465 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
466 ptr = data + ((y + iny) * ow) + inx;
467 for (x = 0; x < w; x++)
468 {
469 *ptr++ = SWAP32(*src);
470 src++;
471 }
472 }
473 }
474 }
475 else
476 {
477 if (mxim)
478 {
479 for (y = 0; y < h; y++)
480 {
481 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
482 ptr = data + ((y + iny) * ow) + inx;
483 for (x = 0; x < w; x++)
484 {
485 pixel = *src++;
486 if (!XGetPixel(mxim, x, y))
487 pixel &= 0x00ffffff;
488 *ptr++ = pixel;
489 }
490 }
491 }
492 else
493 {
494 for (y = 0; y < h; y++)
495 {
496 src = (DATA32 *) (xim->data + (xim->bytes_per_line * y));
497 ptr = data + ((y + iny) * ow) + inx;
498 for (x = 0; x < w; x++)
499 {
500 *ptr++ = *src++;
501 }
502 }
503 }
504 }
505 break;
506 default:
507 break;
508 }
509
510 if (grab)
511 XUngrabServer(d);
512 }
513
514 char
__imlib_GrabDrawableToRGBA(DATA32 * data,int ox,int oy,int ow,int oh,Display * d,Drawable p,Pixmap m,Visual * v,Colormap cm,int depth,int x,int y,int w,int h,char * pdomask,char grab)515 __imlib_GrabDrawableToRGBA(DATA32 * data, int ox, int oy, int ow, int oh,
516 Display * d, Drawable p, Pixmap m, Visual * v,
517 Colormap cm, int depth, int x, int y,
518 int w, int h, char *pdomask, char grab)
519 {
520 XErrorHandler prev_erh = NULL;
521 XWindowAttributes xatt, ratt;
522 char is_pixmap = 0, created_mask = 0, is_shm = 0, is_mshm = 0;
523 char domask;
524 int i;
525 int src_x, src_y, src_w, src_h;
526 int width, height, clipx, clipy;
527 XShmSegmentInfo shminfo, mshminfo;
528 XImage *xim, *mxim;
529 XColor cols[256];
530
531 domask = (pdomask) ? *pdomask : 0;
532 /* FIXME: oh isn't used - i wonder if there's a bug looming... */
533 oh = 0;
534 if (grab)
535 XGrabServer(d);
536 XSync(d, False);
537 prev_erh = XSetErrorHandler(Tmp_HandleXError);
538 _x_err = 0;
539 /* lets see if its a pixmap or not */
540 XGetWindowAttributes(d, p, &xatt);
541 XSync(d, False);
542 if (_x_err)
543 is_pixmap = 1;
544 /* reset our error handler */
545 XSetErrorHandler((XErrorHandler) prev_erh);
546 if (is_pixmap)
547 {
548 Window dw;
549
550 XGetGeometry(d, p, &dw, &src_x, &src_y,
551 (unsigned int *)&src_w, (unsigned int *)&src_h,
552 (unsigned int *)&src_x, (unsigned int *)&xatt.depth);
553 src_x = 0;
554 src_y = 0;
555 }
556 else
557 {
558 Window dw;
559
560 XGetWindowAttributes(d, xatt.root, &ratt);
561 XTranslateCoordinates(d, p, xatt.root, 0, 0, &src_x, &src_y, &dw);
562 src_w = xatt.width;
563 src_h = xatt.height;
564 if ((xatt.map_state != IsViewable) && (xatt.backing_store == NotUseful))
565 {
566 if (grab)
567 XUngrabServer(d);
568 return 0;
569 }
570 }
571
572 /* clip to the drawable tree and screen */
573 clipx = 0;
574 clipy = 0;
575 width = src_w - x;
576 height = src_h - y;
577 if (width > w)
578 width = w;
579 if (height > h)
580 height = h;
581
582 if (!is_pixmap)
583 {
584 if ((src_x + x + width) > ratt.width)
585 width = ratt.width - (src_x + x);
586 if ((src_y + y + height) > ratt.height)
587 height = ratt.height - (src_y + y);
588 }
589 if (x < 0)
590 {
591 clipx = -x;
592 width += x;
593 x = 0;
594 }
595 if (y < 0)
596 {
597 clipy = -y;
598 height += y;
599 y = 0;
600 }
601 if (!is_pixmap)
602 {
603 if ((src_x + x) < 0)
604 {
605 clipx -= (src_x + x);
606 width += (src_x + x);
607 x = -src_x;
608 }
609 if ((src_y + y) < 0)
610 {
611 clipy -= (src_y + y);
612 height += (src_y + y);
613 y = -src_y;
614 }
615 }
616 if ((width <= 0) || (height <= 0))
617 {
618 if (grab)
619 XUngrabServer(d);
620 return 0;
621 }
622 w = width;
623 h = height;
624 if ((!is_pixmap) && (domask) && (!m))
625 {
626 int ord, rect_no = 0;
627 XRectangle *r = NULL;
628
629 r = XShapeGetRectangles(d, p, ShapeBounding, &rect_no, &ord);
630 if (r)
631 {
632 if (!((rect_no == 1) &&
633 (r[0].x == 0) && (r[0].y == 0) &&
634 (r[0].width == xatt.width) && (r[0].height == xatt.height)))
635 {
636 XGCValues gcv;
637 GC gc;
638
639 created_mask = 1;
640 m = XCreatePixmap(d, p, w, h, 1);
641 gcv.foreground = 0;
642 gc = XCreateGC(d, m, GCForeground, &gcv);
643 XFillRectangle(d, m, gc, 0, 0, w, h);
644 XSetForeground(d, gc, 1);
645 for (i = 0; i < rect_no; i++)
646 XFillRectangle(d, m, gc,
647 r[i].x - x, r[i].y - y,
648 r[i].width, r[i].height);
649 XFreeGC(d, gc);
650 }
651 XFree(r);
652 }
653 }
654
655 /* Create an Ximage (shared or not) */
656 xim = __imlib_ShmGetXImage(d, v, p, xatt.depth, x, y, w, h, &shminfo);
657 is_shm = !!xim;
658
659 if (!xim)
660 xim = XGetImage(d, p, x, y, w, h, 0xffffffff, ZPixmap);
661 if (!xim)
662 {
663 if (grab)
664 XUngrabServer(d);
665 return 0;
666 }
667
668 mxim = NULL;
669 if ((m) && (domask))
670 {
671 mxim = __imlib_ShmGetXImage(d, v, m, 1, 0, 0, w, h, &mshminfo);
672 is_mshm = !!mxim;
673 if (!mxim)
674 mxim = XGetImage(d, m, 0, 0, w, h, 0xffffffff, ZPixmap);
675 }
676
677 if ((is_shm) || (is_mshm))
678 {
679 XSync(d, False);
680 if (grab)
681 XUngrabServer(d);
682 XSync(d, False);
683 }
684 else if (grab)
685 XUngrabServer(d);
686
687 if ((xatt.depth == 1) && (!cm) && (is_pixmap))
688 {
689 rtab[0] = 255;
690 gtab[0] = 255;
691 btab[0] = 255;
692 rtab[1] = 0;
693 gtab[1] = 0;
694 btab[1] = 0;
695 }
696 else if (xatt.depth <= 8)
697 {
698 if (!cm)
699 {
700 if (is_pixmap)
701 {
702 cm = DefaultColormap(d, DefaultScreen(d));
703 }
704 else
705 {
706 cm = xatt.colormap;
707 if (cm == None)
708 cm = ratt.colormap;
709 }
710 }
711
712 for (i = 0; i < (1 << xatt.depth); i++)
713 {
714 cols[i].pixel = i;
715 cols[i].flags = DoRed | DoGreen | DoBlue;
716 }
717 XQueryColors(d, cm, cols, 1 << xatt.depth);
718 for (i = 0; i < (1 << xatt.depth); i++)
719 {
720 rtab[i] = cols[i].red >> 8;
721 gtab[i] = cols[i].green >> 8;
722 btab[i] = cols[i].blue >> 8;
723 }
724 }
725 __imlib_GrabXImageToRGBA(data, ox + clipx, oy + clipy, ow, oh,
726 d, xim, mxim, v, xatt.depth, x, y, w, h, 0);
727
728 /* destroy the Ximage */
729 if (is_shm)
730 __imlib_ShmDestroyXImage(d, xim, &shminfo);
731 else
732 XDestroyImage(xim);
733
734 if (mxim)
735 {
736 if (is_mshm)
737 __imlib_ShmDestroyXImage(d, mxim, &mshminfo);
738 else
739 XDestroyImage(mxim);
740 }
741 if (created_mask)
742 XFreePixmap(d, m);
743
744 if (pdomask)
745 {
746 /* Set domask according to whether or not we have useful alpha data */
747 if (xatt.depth == 32)
748 *pdomask = 1;
749 else if (!m)
750 *pdomask = 0;
751 }
752
753 return 1;
754 }
755
756 #endif /* BUILD_X11 */
757