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