]> Pileus Git - ~andy/gtk/blob - contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-drawable.c
Merge branch 'master' into toolpalette
[~andy/gtk] / contrib / gdk-pixbuf-xlib / gdk-pixbuf-xlib-drawable.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* GdkPixbuf library - convert X drawable information to RGB
3  *
4  * Copyright (C) 1999 Michael Zucchi
5  *
6  * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
7  *          Cody Russell <bratsche@dfw.net>
8  *          Federico Mena-Quintero <federico@gimp.org>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 /* Ported to Xlib by John Harper <john@dcs.warwick.ac.uk> */
27
28
29 #include "config.h"
30 #include <stdio.h>
31 #include <string.h>
32 #include <gdk-pixbuf/gdk-pixbuf-private.h>
33 #include "gdk-pixbuf-xlib-private.h"
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36
37 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
38 #define LITTLE
39 #endif
40 #define d(x)
41
42 \f
43
44 static const guint32 mask_table[] = {
45         0x00000000, 0x00000001, 0x00000003, 0x00000007,
46         0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
47         0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
48         0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
49         0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
50         0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
51         0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
52         0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
53         0xffffffff
54 };
55
56 \f
57 /* color handling */
58
59 typedef struct xlib_colormap_struct xlib_colormap;
60 struct xlib_colormap_struct {
61         int size;
62         XColor *colors;
63         Visual *visual;
64         Colormap colormap;
65 };
66
67 static xlib_colormap *
68 xlib_get_colormap (Colormap id, Visual *visual)
69 {
70         int i;
71         xlib_colormap *xc = g_new (xlib_colormap, 1);
72
73         xc->size = visual->map_entries;
74         xc->colors = g_new (XColor, xc->size);
75         xc->visual = visual;
76         xc->colormap = id;
77
78         for (i = 0; i < xc->size; i++) {
79                 xc->colors[i].pixel = i;
80                 xc->colors[i].flags = DoRed | DoGreen | DoBlue;
81         }
82
83         XQueryColors (gdk_pixbuf_dpy, xc->colormap, xc->colors, xc->size);
84
85         return xc;
86 }
87
88 static void
89 xlib_colormap_free (xlib_colormap *xc)
90 {
91         g_free (xc->colors);
92         g_free (xc);
93 }
94
95 /* from gdkvisual.c */
96 static void
97 visual_decompose_mask (gulong  mask,
98                        gint   *shift,
99                        gint   *prec)
100 {
101         *shift = 0;
102         *prec = 0;
103
104         while (!(mask & 0x1)) {
105                 (*shift)++;
106                 mask >>= 1;
107         }
108
109         while (mask & 0x1) {
110                 (*prec)++;
111                 mask >>= 1;
112         }
113 }
114
115 static gboolean x_error;
116
117 static int
118 handle_x_error (Display *dpy, XErrorEvent *ev)
119 {
120         x_error = TRUE;
121         return 0;
122 }
123
124 static gboolean
125 drawable_is_pixmap (Drawable d)
126 {
127         /* copied from Imlib */
128
129         XErrorHandler errh;
130         XWindowAttributes wa;
131         gboolean is_pixmap;
132
133         errh = XSetErrorHandler (handle_x_error);
134         x_error = FALSE;
135         XGetWindowAttributes (gdk_pixbuf_dpy, d, &wa);
136         XSync (gdk_pixbuf_dpy, False);
137         is_pixmap = x_error;
138         XSetErrorHandler (errh);
139
140         return is_pixmap;
141 }
142
143 \f
144
145 /*
146   convert 1 bits-pixel data
147   no alpha
148 */
149 static void
150 rgb1 (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
151 {
152         int xx, yy;
153         int width, height;
154         int bpl;
155         register guint8 data;
156         guint8 *o;
157         guint8 *srow = (guint8 *)image->data, *orow = pixels;
158
159         d (printf ("1 bits/pixel\n"));
160
161         /* convert upto 8 pixels/time */
162         /* its probably not worth trying to make this run very fast, who uses
163            1 bit displays anymore? */
164         width = image->width;
165         height = image->height;
166         bpl = image->bytes_per_line;
167
168         for (yy = 0; yy < height; yy++) {
169                 o = orow;
170
171                 for (xx = 0; xx < width; xx ++) {
172                         data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
173                         *o++ = colormap->colors[data].red;
174                         *o++ = colormap->colors[data].green;
175                         *o++ = colormap->colors[data].blue;
176                 }
177                 srow += bpl;
178                 orow += rowstride;
179         }
180 }
181
182 /*
183   convert 1 bits/pixel data
184   with alpha
185 */
186 static void
187 rgb1a (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
188 {
189         int xx, yy;
190         int width, height;
191         int bpl;
192         register guint8 data;
193         guint8 *o;
194         guint8 *srow = (guint8 *)image->data, *orow = pixels;
195         guint32 remap[2];
196
197         d (printf ("1 bits/pixel\n"));
198
199         /* convert upto 8 pixels/time */
200         /* its probably not worth trying to make this run very fast, who uses
201            1 bit displays anymore? */
202         width = image->width;
203         height = image->height;
204         bpl = image->bytes_per_line;
205
206         for (xx = 0; xx < 2; xx++) {
207 #ifdef LITTLE
208                 remap[xx] = 0xff000000
209                         | colormap->colors[xx].blue << 16
210                         | colormap->colors[xx].green << 8
211                         | colormap->colors[xx].red;
212 #else
213                 remap[xx] = 0xff
214                         | colormap->colors[xx].red << 24
215                         | colormap->colors[xx].green << 16
216                         | colormap->colors[xx].blue << 8;
217 #endif
218         }
219
220         for (yy = 0; yy < height; yy++) {
221                 o = orow;
222
223                 for (xx = 0; xx < width; xx ++) {
224                         data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
225                         *o++ = remap[data];
226                 }
227                 srow += bpl;
228                 orow += rowstride;
229         }
230 }
231
232 /*
233   convert 8 bits/pixel data
234   no alpha
235 */
236 static void
237 rgb8 (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
238 {
239         int xx, yy;
240         int width, height;
241         int bpl;
242         guint32 mask;
243         register guint32 data;
244         guint8 *srow = (guint8 *)image->data, *orow = pixels;
245         register guint8 *s;
246         register guint8 *o;
247
248         width = image->width;
249         height = image->height;
250         bpl = image->bytes_per_line;
251
252         d (printf ("8 bit, no alpha output\n"));
253
254         mask = mask_table[image->depth];
255
256         for (yy = 0; yy < height; yy++) {
257                 s = srow;
258                 o = orow;
259                 for (xx = 0; xx < width; xx++) {
260                         data = *s++ & mask;
261                         *o++ = colormap->colors[data].red;
262                         *o++ = colormap->colors[data].green;
263                         *o++ = colormap->colors[data].blue;
264                 }
265                 srow += bpl;
266                 orow += rowstride;
267         }
268 }
269
270 /*
271   convert 8 bits/pixel data
272   with alpha
273 */
274 static void
275 rgb8a (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
276 {
277         int xx, yy;
278         int width, height;
279         int bpl;
280         guint32 mask;
281         register guint32 data;
282         guint32 remap[256];
283         register guint8 *s;     /* read 2 pixels at once */
284         register guint32 *o;
285         guint8 *srow = (guint8 *)image->data, *orow = pixels;
286
287         width = image->width;
288         height = image->height;
289         bpl = image->bytes_per_line;
290
291         d (printf ("8 bit, with alpha output\n"));
292
293         mask = mask_table[image->depth];
294
295         for (xx = 0; xx < colormap->size; xx++) {
296 #ifdef LITTLE
297                 remap[xx] = 0xff000000
298                         | colormap->colors[xx].blue << 16
299                         | colormap->colors[xx].green << 8
300                         | colormap->colors[xx].red;
301 #else
302                 remap[xx] = 0xff
303                         | colormap->colors[xx].red << 24
304                         | colormap->colors[xx].green << 16
305                         | colormap->colors[xx].blue << 8;
306 #endif
307         }
308
309         for (yy = 0; yy < height; yy++) {
310                 s = srow;
311                 o = (guint32 *) orow;
312                 for (xx = 0; xx < width; xx ++) {
313                         data = *s++ & mask;
314                         *o++ = remap[data];
315                 }
316                 srow += bpl;
317                 orow += rowstride;
318         }
319 }
320
321 /*
322   convert 16 bits/pixel data
323   no alpha
324   data in lsb format
325 */
326 static void
327 rgb565lsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
328 {
329         int xx, yy;
330         int width, height;
331         int bpl;
332
333 #ifdef LITTLE
334         register guint32 *s;    /* read 2 pixels at once */
335 #else
336         register guint8 *s;     /* read 2 pixels at once */
337 #endif
338         register guint16 *o;
339         guint8 *srow = (guint8 *)image->data, *orow = pixels;
340
341         width = image->width;
342         height = image->height;
343         bpl = image->bytes_per_line;
344
345         for (yy = 0; yy < height; yy++) {
346 #ifdef LITTLE
347                 s = (guint32 *) srow;
348 #else
349                 s = srow;
350 #endif
351                 o = (guint16 *) orow;
352                 for (xx = 1; xx < width; xx += 2) {
353                         register guint32 data;
354 #ifdef LITTLE
355                         data = *s++;
356                         *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
357                                 | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
358                         *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
359                                 | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
360                         *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
361                                 | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
362 #else
363                         /* swap endianness first */
364                         data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
365                         s += 4;
366                         *o++ = (data & 0xf800) | (data & 0xe000) >> 5
367                                 | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
368                         *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
369                                 | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
370                         *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
371                                 | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
372 #endif
373                 }
374                 /* check for last remaining pixel */
375                 if (width & 1) {
376                         register guint16 data;
377 #ifdef LITTLE
378                         data = *((short *) s);
379 #else
380                         data = *((short *) s);
381                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
382 #endif
383                         ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
384                         ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
385                         ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
386                 }
387                 srow += bpl;
388                 orow += rowstride;
389         }
390 }
391
392 /*
393   convert 16 bits/pixel data
394   no alpha
395   data in msb format
396 */
397 static void
398 rgb565msb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
399 {
400         int xx, yy;
401         int width, height;
402         int bpl;
403
404 #ifdef LITTLE
405         register guint8 *s;     /* need to swap data order */
406 #else
407         register guint32 *s;    /* read 2 pixels at once */
408 #endif
409         register guint16 *o;
410         guint8 *srow = (guint8 *)image->data, *orow = pixels;
411
412         width = image->width;
413         height = image->height;
414         bpl = image->bytes_per_line;
415
416         for (yy = 0; yy < height; yy++) {
417 #ifdef LITTLE
418                 s = srow;
419 #else
420                 s = (guint32 *) srow;
421 #endif
422                 o = (guint16 *) orow;
423                 for (xx = 1; xx < width; xx += 2) {
424                         register guint32 data;
425 #ifdef LITTLE
426                         /* swap endianness first */
427                         data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
428                         s += 4;
429                         *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
430                                 | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
431                         *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
432                                 | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
433                         *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
434                                 | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
435 #else
436                         data = *s++;
437                         *o++ = (data & 0xf800) | (data & 0xe000) >> 5
438                                 | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
439                         *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
440                                 | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
441                         *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
442                                 | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
443 #endif
444                 }
445                 /* check for last remaining pixel */
446                 if (width & 1) {
447                         register guint16 data;
448 #ifdef LITTLE
449                         data = *((short *) s);
450                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
451 #else
452                         data = *((short *) s);
453 #endif
454                         ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
455                         ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
456                         ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
457                 }
458                 srow += bpl;
459                 orow += rowstride;
460         }
461 }
462
463 /*
464   convert 16 bits/pixel data
465   with alpha
466   data in lsb format
467 */
468 static void
469 rgb565alsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
470 {
471         int xx, yy;
472         int width, height;
473         int bpl;
474
475 #ifdef LITTLE
476         register guint16 *s;    /* read 1 pixels at once */
477 #else
478         register guint8 *s;
479 #endif
480         register guint32 *o;
481
482         guint8 *srow = (guint8 *)image->data, *orow = pixels;
483
484         width = image->width;
485         height = image->height;
486         bpl = image->bytes_per_line;
487
488         for (yy = 0; yy < height; yy++) {
489 #ifdef LITTLE
490                 s = (guint16 *) srow;
491 #else
492                 s = (guint8 *) srow;
493 #endif
494                 o = (guint32 *) orow;
495                 for (xx = 0; xx < width; xx ++) {
496                         register guint32 data;
497                         /*  rrrrrggg gggbbbbb -> rrrrrRRR ggggggGG bbbbbBBB aaaaaaaa */
498                         /*  little endian: aaaaaaaa bbbbbBBB ggggggGG rrrrrRRR */
499 #ifdef LITTLE
500                         data = *s++;
501                         *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
502                                 | (data & 0x7e0) << 5 | (data & 0x600) >> 1
503                                 | (data & 0x1f) << 19 | (data & 0x1c) << 14
504                                 | 0xff000000;
505 #else
506                         /* swap endianness first */
507                         data = s[0] | s[1] << 8;
508                         s += 2;
509                         *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
510                                 | (data & 0x7e0) << 13 | (data & 0x600) << 7
511                                 | (data & 0x1f) << 11 | (data & 0x1c) << 6
512                                 | 0xff;
513 #endif
514                 }
515                 srow += bpl;
516                 orow += rowstride;
517         }
518 }
519
520 /*
521   convert 16 bits/pixel data
522   with alpha
523   data in msb format
524 */
525 static void
526 rgb565amsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
527 {
528         int xx, yy;
529         int width, height;
530         int bpl;
531
532 #ifdef LITTLE
533         register guint8 *s;
534 #else
535         register guint16 *s;    /* read 1 pixels at once */
536 #endif
537         register guint32 *o;
538
539         guint8 *srow = (guint8 *)image->data, *orow = pixels;
540
541         width = image->width;
542         height = image->height;
543         bpl = image->bytes_per_line;
544
545         for (yy = 0; yy < height; yy++) {
546 #ifdef LITTLE
547                 s = srow;
548 #else
549                 s = (guint16 *) srow;
550 #endif
551                 o = (guint32 *) orow;
552                 for (xx = 0; xx < width; xx ++) {
553                         register guint32 data;
554                         /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggg00 bbbbbBBB aaaaaaaa */
555                         /*  little endian: aaaaaaaa bbbbbBBB gggggg00 rrrrrRRR */
556 #ifdef LITTLE
557                         /* swap endianness first */
558                         data = s[0] | s[1] << 8;
559                         s += 2;
560                         *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
561                                 | (data & 0x7e0) << 5 | (data & 0x600) >> 1
562                                 | (data & 0x1f) << 19 | (data & 0x1c) << 14
563                                 | 0xff000000;
564 #else
565                         data = *s++;
566                         *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
567                                 | (data & 0x7e0) << 13 | (data & 0x600) << 7
568                                 | (data & 0x1f) << 11 | (data & 0x1c) << 6
569                                 | 0xff;
570 #endif
571                 }
572                 srow += bpl;
573                 orow += rowstride;
574         }
575 }
576
577 /*
578   convert 15 bits/pixel data
579   no alpha
580   data in lsb format
581 */
582 static void
583 rgb555lsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
584 {
585         int xx, yy;
586         int width, height;
587         int bpl;
588
589 #ifdef LITTLE
590         register guint32 *s;    /* read 2 pixels at once */
591 #else
592         register guint8 *s;     /* read 2 pixels at once */
593 #endif
594         register guint16 *o;
595         guint8 *srow = (guint8 *)image->data, *orow = pixels;
596
597         width = image->width;
598         height = image->height;
599         bpl = image->bytes_per_line;
600
601         for (yy = 0; yy < height; yy++) {
602 #ifdef LITTLE
603                 s = (guint32 *) srow;
604 #else
605                 s = srow;
606 #endif
607                 o = (guint16 *) orow;
608                 for (xx = 1; xx < width; xx += 2) {
609                         register guint32 data;
610 #ifdef LITTLE
611                         data = *s++;
612                         *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
613                                 | (data & 0x3e0) << 6 | (data & 0x380) << 1;
614                         *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
615                                 | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
616                         *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
617                                 | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
618 #else
619                         /* swap endianness first */
620                         data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
621                         s += 4;
622                         *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
623                                 | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
624                         *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
625                                 | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
626                         *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
627                                 | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
628 #endif
629                 }
630                 /* check for last remaining pixel */
631                 if (width & 1) {
632                         register guint16 data;
633 #ifdef LITTLE
634                         data = *((short *) s);
635 #else
636                         data = *((short *) s);
637                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
638 #endif
639                         ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
640                         ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
641                         ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
642                 }
643                 srow += bpl;
644                 orow += rowstride;
645         }
646 }
647
648 /*
649   convert 15 bits/pixel data
650   no alpha
651   data in msb format
652 */
653 static void
654 rgb555msb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
655 {
656         int xx, yy;
657         int width, height;
658         int bpl;
659
660 #ifdef LITTLE
661         register guint8 *s;     /* read 2 pixels at once */
662 #else
663         register guint32 *s;    /* read 2 pixels at once */
664 #endif
665         register guint16 *o;
666         guint8 *srow = (guint8 *)image->data, *orow = pixels;
667
668         width = image->width;
669         height = image->height;
670         bpl = image->bytes_per_line;
671
672         for (yy = 0; yy < height; yy++) {
673 #ifdef LITTLE
674                 s = srow;
675 #else
676                 s = (guint32 *) srow;
677 #endif
678                 o = (guint16 *) orow;
679                 for (xx = 1; xx < width; xx += 2) {
680                         register guint32 data;
681 #ifdef LITTLE
682                         /* swap endianness first */
683                         data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
684                         s += 4;
685                         *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
686                                 | (data & 0x3e0) << 6 | (data & 0x380) << 1;
687                         *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
688                                 | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
689                         *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
690                                 | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
691 #else
692                         data = *s++;
693                         *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
694                                 | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
695                         *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
696                                 | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
697                         *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
698                                 | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
699 #endif
700                 }
701                 /* check for last remaining pixel */
702                 if (width & 1) {
703                         register guint16 data;
704 #ifdef LITTLE
705                         data = *((short *) s);
706                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
707 #else
708                         data = *((short *) s);
709 #endif
710                         ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
711                         ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
712                         ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
713                 }
714                 srow += bpl;
715                 orow += rowstride;
716         }
717 }
718
719 /*
720   convert 15 bits/pixel data
721   with alpha
722   data in lsb format
723 */
724 static void
725 rgb555alsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
726 {
727         int xx, yy;
728         int width, height;
729         int bpl;
730
731 #ifdef LITTLE
732         register guint16 *s;    /* read 1 pixels at once */
733 #else
734         register guint8 *s;
735 #endif
736         register guint32 *o;
737
738         guint8 *srow = (guint8 *)image->data, *orow = pixels;
739
740         width = image->width;
741         height = image->height;
742         bpl = image->bytes_per_line;
743
744         for (yy = 0; yy < height; yy++) {
745 #ifdef LITTLE
746                 s = (guint16 *) srow;
747 #else
748                 s = srow;
749 #endif
750                 o = (guint32 *) orow;
751                 for (xx = 0; xx < width; xx++) {
752                         register guint32 data;
753                         /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
754                         /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
755 #ifdef LITTLE
756                         data = *s++;
757                         *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
758                                 | (data & 0x3e0) << 6 | (data & 0x380) << 1
759                                 | (data & 0x1f) << 19 | (data & 0x1c) << 14
760                                 | 0xff000000;
761 #else
762                         /* swap endianness first */
763                         data = s[0] | s[1] << 8;
764                         s += 2;
765                         *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
766                                 | (data & 0x3e0) << 14 | (data & 0x380) << 9
767                                 | (data & 0x1f) << 11 | (data & 0x1c) << 6
768                                 | 0xff;
769 #endif
770                 }
771                 srow += bpl;
772                 orow += rowstride;
773         }
774 }
775
776 /*
777   convert 15 bits/pixel data
778   with alpha
779   data in msb format
780 */
781 static void
782 rgb555amsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
783 {
784         int xx, yy;
785         int width, height;
786         int bpl;
787
788 #ifdef LITTLE
789         register guint16 *s;    /* read 1 pixels at once */
790 #else
791         register guint8 *s;
792 #endif
793         register guint32 *o;
794
795         guint8 *srow = (guint8 *)image->data, *orow = pixels;
796
797         width = image->width;
798         height = image->height;
799         bpl = image->bytes_per_line;
800
801         for (yy = 0; yy < height; yy++) {
802 #ifdef LITTLE
803                 s = (guint16 *) srow;
804 #else
805                 s = srow;
806 #endif
807                 o = (guint32 *) orow;
808                 for (xx = 0; xx < width; xx++) {
809                         register guint32 data;
810                         /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
811                         /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
812 #ifdef LITTLE
813                         /* swap endianness first */
814                         data = s[0] | s[1] << 8;
815                         s += 2;
816                         *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
817                                 | (data & 0x3e0) << 6 | (data & 0x380) << 1
818                                 | (data & 0x1f) << 19 | (data & 0x1c) << 14
819                                 | 0xff000000;
820 #else
821                         data = *s++;
822                         *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
823                                 | (data & 0x3e0) << 14 | (data & 0x380) << 9
824                                 | (data & 0x1f) << 11 | (data & 0x1c) << 6
825                                 | 0xff;
826 #endif
827                 }
828                 srow += bpl;
829                 orow += rowstride;
830         }
831 }
832
833
834 static void
835 rgb888alsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
836 {
837         int xx, yy;
838         int width, height;
839         int bpl;
840
841         guint8 *s;      /* for byte order swapping */
842         guint8 *o;
843         guint8 *srow = (guint8 *)image->data, *orow = pixels;
844
845         width = image->width;
846         height = image->height;
847         bpl = image->bytes_per_line;
848
849         d (printf ("32 bits/pixel with alpha\n"));
850
851         /* lsb data */
852         for (yy = 0; yy < height; yy++) {
853                 s = srow;
854                 o = orow;
855                 for (xx = 0; xx < width; xx++) {
856                         *o++ = s[2];
857                         *o++ = s[1];
858                         *o++ = s[0];
859                         *o++ = 0xff;
860                         s += 4;
861                 }
862                 srow += bpl;
863                 orow += rowstride;
864         }
865 }
866
867 static void
868 rgb888lsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
869 {
870         int xx, yy;
871         int width, height;
872         int bpl;
873
874         guint8 *srow = (guint8 *)image->data, *orow = pixels;
875         guint8 *o, *s;
876
877         width = image->width;
878         height = image->height;
879         bpl = image->bytes_per_line;
880
881         d (printf ("32 bit, lsb, no alpha\n"));
882
883         for (yy = 0; yy < height; yy++) {
884                 s = srow;
885                 o = orow;
886                 for (xx = 0; xx < width; xx++) {
887                         *o++ = s[2];
888                         *o++ = s[1];
889                         *o++ = s[0];
890                         s += 4;
891                 }
892                 srow += bpl;
893                 orow += rowstride;
894         }
895 }
896
897 static void
898 rgb888amsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
899 {
900         int xx, yy;
901         int width, height;
902         int bpl;
903
904         guint8 *srow = (guint8 *)image->data, *orow = pixels;
905 #ifdef LITTLE
906         guint32 *o;
907         guint32 *s;
908 #else
909         guint8 *s;      /* for byte order swapping */
910         guint8 *o;
911 #endif
912
913         d (printf ("32 bit, msb, with alpha\n"));
914
915         width = image->width;
916         height = image->height;
917         bpl = image->bytes_per_line;
918
919         /* msb data */
920         for (yy = 0; yy < height; yy++) {
921 #ifdef LITTLE
922                 s = (guint32 *) srow;
923                 o = (guint32 *) orow;
924 #else
925                 s = srow;
926                 o = orow;
927 #endif
928                 for (xx = 0; xx < width; xx++) {
929 #ifdef LITTLE
930                         *o++ = s[1];
931                         *o++ = s[2];
932                         *o++ = s[3];
933                         *o++ = 0xff;
934                         s += 4;
935 #else
936                         *o++ = (*s << 8) | 0xff; /* untested */
937                         s++;
938 #endif
939                 }
940                 srow += bpl;
941                 orow += rowstride;
942         }
943 }
944
945 static void
946 rgb888msb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
947 {
948         int xx, yy;
949         int width, height;
950         int bpl;
951
952         guint8 *srow = (guint8 *)image->data, *orow = pixels;
953         guint8 *s;
954         guint8 *o;
955
956         d (printf ("32 bit, msb, no alpha\n"));
957
958         width = image->width;
959         height = image->height;
960         bpl = image->bytes_per_line;
961
962         for (yy = 0; yy < height; yy++) {
963                 s = srow;
964                 o = orow;
965                 for (xx = 0; xx < width; xx++) {
966                         *o++ = s[1];
967                         *o++ = s[2];
968                         *o++ = s[3];
969                         s += 4;
970                 }
971                 srow += bpl;
972                 orow += rowstride;
973         }
974 }
975
976 /*
977   This should work correctly with any display/any endianness, but will probably
978   run quite slow
979 */
980 static void
981 convert_real_slow (XImage *image, guchar *pixels, int rowstride, xlib_colormap *cmap, int alpha)
982 {
983         int xx, yy;
984         int width, height;
985         int bpl;
986         guint8 *srow = (guint8 *)image->data, *orow = pixels;
987         guint8 *o;
988         guint32 pixel;
989         Visual *v;
990         guint8 component;
991         int i;
992         int red_shift, red_prec, green_shift, green_prec, blue_shift, blue_prec;
993
994         width = image->width;
995         height = image->height;
996         bpl = image->bytes_per_line;
997         v = cmap->visual;
998
999         visual_decompose_mask (v->red_mask, &red_shift, &red_prec);
1000         visual_decompose_mask (v->green_mask, &green_shift, &green_prec);
1001         visual_decompose_mask (v->blue_mask, &blue_shift, &blue_prec);
1002
1003         d(printf("rgb  mask/shift/prec = %x:%x:%x %d:%d:%d  %d:%d:%d\n",
1004                  v->red_mask, v->green_mask, v->blue_mask,
1005                  red_shift, green_shift, blue_shift,
1006                  red_prec, green_prec, blue_prec));
1007
1008         for (yy = 0; yy < height; yy++) {
1009                 o = orow;
1010                 for (xx = 0; xx < width; xx++) {
1011                         pixel = XGetPixel (image, xx, yy);
1012                         switch (v->class) {
1013                                 /* I assume this is right for static & greyscale's too? */
1014                         case StaticGray:
1015                         case GrayScale:
1016                         case StaticColor:
1017                         case PseudoColor:
1018                                 *o++ = cmap->colors[pixel].red;
1019                                 *o++ = cmap->colors[pixel].green;
1020                                 *o++ = cmap->colors[pixel].blue;
1021                                 break;
1022                         case TrueColor:
1023                                 /* This is odd because it must sometimes shift left (otherwise
1024                                    I'd just shift >> (*_shift - 8 + *_prec + <0-7>). This logic
1025                                    should work for all bit sizes/shifts/etc. */
1026                                 component = 0;
1027                                 for (i = 24; i < 32; i += red_prec)
1028                                         component |= ((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> i;
1029                                 *o++ = component;
1030                                 component = 0;
1031                                 for (i = 24; i < 32; i += green_prec)
1032                                         component |= ((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> i;
1033                                 *o++ = component;
1034                                 component = 0;
1035                                 for (i = 24; i < 32; i += blue_prec)
1036                                         component |= ((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> i;
1037                                 *o++ = component;
1038                                 break;
1039                         case DirectColor:
1040                                 *o++ = cmap->colors[((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> 24].red;
1041                                 *o++ = cmap->colors[((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> 24].green;
1042                                 *o++ = cmap->colors[((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> 24].blue;
1043                                 break;
1044                         }
1045                         if (alpha)
1046                                 *o++ = 0xff;
1047                 }
1048                 srow += bpl;
1049                 orow += rowstride;
1050         }
1051 }
1052
1053 typedef void (* cfunc) (XImage *image, guchar *pixels, int rowstride, xlib_colormap *cmap);
1054
1055 static const cfunc convert_map[] = {
1056         rgb1,rgb1,rgb1a,rgb1a,
1057         rgb8,rgb8,rgb8a,rgb8a,
1058         rgb555lsb,rgb555msb,rgb555alsb,rgb555amsb,
1059         rgb565lsb,rgb565msb,rgb565alsb,rgb565amsb,
1060         rgb888lsb,rgb888msb,rgb888alsb,rgb888amsb
1061 };
1062
1063 /*
1064   perform actual conversion
1065
1066   If we can, try and use the optimised code versions, but as a default
1067   fallback, and always for direct colour, use the generic/slow but complete
1068   conversion function.
1069 */
1070 static void
1071 rgbconvert (XImage *image, guchar *pixels, int rowstride, int alpha, xlib_colormap *cmap)
1072 {
1073         int index = (image->byte_order == MSBFirst) | (alpha != 0) << 1;
1074         int bank=5;             /* default fallback converter */
1075         Visual *v = cmap->visual;
1076
1077         d(printf("masks = %x:%x:%x\n", v->red_mask, v->green_mask, v->blue_mask));
1078         d(printf("image depth = %d, bpp = %d\n", image->depth, image->bits_per_pixel));
1079
1080         switch (v->class) {
1081                                 /* I assume this is right for static & greyscale's too? */
1082         case StaticGray:
1083         case GrayScale:
1084         case StaticColor:
1085         case PseudoColor:
1086                 switch (image->bits_per_pixel) {
1087                 case 1:
1088                         bank = 0;
1089                         break;
1090                 case 8:
1091                         bank = 1;
1092                         break;
1093                 }
1094                 break;
1095         case TrueColor:
1096                 switch (image->depth) {
1097                 case 15:
1098                         if (v->red_mask == 0x7c00 && v->green_mask == 0x3e0 && v->blue_mask == 0x1f
1099                             && image->bits_per_pixel == 16)
1100                                 bank = 2;
1101                         break;
1102                 case 16:
1103                         if (v->red_mask == 0xf800 && v->green_mask == 0x7e0 && v->blue_mask == 0x1f
1104                             && image->bits_per_pixel == 16)
1105                                 bank = 3;
1106                         break;
1107                 case 24:
1108                 case 32:
1109                         if (v->red_mask == 0xff0000 && v->green_mask == 0xff00 && v->blue_mask == 0xff
1110                             && image->bits_per_pixel == 32)
1111                                 bank = 4;
1112                         break;
1113                 }
1114                 break;
1115         case DirectColor:
1116                 /* always use the slow version */
1117                 break;
1118         }
1119
1120         d(printf("converting using conversion function in bank %d\n", bank));
1121
1122         if (bank==5) {
1123                 convert_real_slow(image, pixels, rowstride, cmap, alpha);
1124         } else {
1125                 index |= bank << 2;
1126                 (* convert_map[index]) (image, pixels, rowstride, cmap);
1127         }
1128 }
1129
1130 static gboolean
1131 xlib_window_is_viewable (Window w)
1132 {
1133         XWindowAttributes wa;
1134
1135         while (w != 0) {
1136                 Window parent, root, *children;
1137                 guint nchildren;
1138
1139                 XGetWindowAttributes (gdk_pixbuf_dpy, w, &wa);
1140                 if (wa.map_state != IsViewable)
1141                         return FALSE;
1142
1143                 if (!XQueryTree (gdk_pixbuf_dpy, w, &root,
1144                                  &parent, &children, &nchildren))
1145                         return FALSE;
1146
1147                 if (nchildren > 0)
1148                         XFree (children);
1149
1150                 if ((parent == root) || (w == root))
1151                         return TRUE;
1152
1153                 w = parent;
1154         }
1155
1156         return FALSE;
1157 }
1158
1159 static gint
1160 xlib_window_get_origin (Window w, gint *x, gint *y)
1161 {
1162         Window child;
1163         return XTranslateCoordinates (gdk_pixbuf_dpy, w,
1164                                       RootWindow (gdk_pixbuf_dpy,
1165                                                   gdk_pixbuf_screen),
1166                                       0, 0, x, y, &child);
1167 }
1168
1169 /* Exported functions */
1170
1171 /**
1172  * gdk_pixbuf_xlib_get_from_drawable:
1173  * @dest: Destination pixbuf, or NULL if a new pixbuf should be created.
1174  * @src: Source drawable.
1175  * @cmap: A colormap if @src is a pixmap.  If it is a window, this argument will
1176  * be ignored.
1177  * @visual: A visual if @src is a pixmap.  If it is a window, this argument will
1178  * be ignored.
1179  * @src_x: Source X coordinate within drawable.
1180  * @src_y: Source Y coordinate within drawable.
1181  * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
1182  * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
1183  * @width: Width in pixels of region to get.
1184  * @height: Height in pixels of region to get.
1185  *
1186  * Transfers image data from a Gdk drawable and converts it to an RGB(A)
1187  * representation inside a GdkPixbuf.
1188  *
1189  * If the drawable @src is a pixmap, then a suitable colormap must be specified,
1190  * since pixmaps are just blocks of pixel data without an associated colormap.
1191  * If the drawable is a window, the @cmap argument will be ignored and the
1192  * window's own colormap will be used instead.
1193  *
1194  * If the specified destination pixbuf @dest is #NULL, then this function will
1195  * create an RGB pixbuf with 8 bits per channel and no alpha, with the same size
1196  * specified by the @width and @height arguments.  In this case, the @dest_x and
1197  * @dest_y arguments must be specified as 0, otherwise the function will return
1198  * #NULL.  If the specified destination pixbuf is not NULL and it contains alpha
1199  * information, then the filled pixels will be set to full opacity.
1200  *
1201  * If the specified drawable is a pixmap, then the requested source rectangle
1202  * must be completely contained within the pixmap, otherwise the function will
1203  * return #NULL.
1204  *
1205  * If the specified drawable is a window, then it must be viewable, i.e. all of
1206  * its ancestors up to the root window must be mapped.  Also, the specified
1207  * source rectangle must be completely contained within the window and within
1208  * the screen.  If regions of the window are obscured by noninferior windows, the
1209  * contents of those regions are undefined.  The contents of regions obscured by
1210  * inferior windows of a different depth than that of the source window will also
1211  * be undefined.
1212  *
1213  * Return value: The same pixbuf as @dest if it was non-NULL, or a newly-created
1214  * pixbuf with a reference count of 1 if no destination pixbuf was specified; in
1215  * the latter case, NULL will be returned if not enough memory could be
1216  * allocated for the pixbuf to be created.
1217  **/
1218 GdkPixbuf *
1219 gdk_pixbuf_xlib_get_from_drawable (GdkPixbuf *dest,
1220                                    Drawable src,
1221                                    Colormap cmap, Visual *visual,
1222                                    int src_x, int src_y,
1223                                    int dest_x, int dest_y,
1224                                    int width, int height)
1225 {
1226         guint src_width, src_height;
1227         XImage *image;
1228         int rowstride, bpp, alpha;
1229         XWindowAttributes wa;
1230         xlib_colormap *x_cmap;
1231         gboolean is_pixmap;
1232
1233         /* General sanity checks */
1234
1235         g_return_val_if_fail (src != 0, NULL);
1236
1237         is_pixmap = drawable_is_pixmap (src);
1238
1239         if (is_pixmap) {
1240                 g_return_val_if_fail (cmap != 0, NULL);
1241                 g_return_val_if_fail (visual != NULL, NULL);
1242         }
1243         else
1244                 g_return_val_if_fail (xlib_window_is_viewable (src), NULL);
1245
1246         if (!dest)
1247                 g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
1248         else {
1249                 g_return_val_if_fail (dest->colorspace == GDK_COLORSPACE_RGB, NULL);
1250                 g_return_val_if_fail (dest->n_channels == 3
1251                                       || dest->n_channels == 4, NULL);
1252                 g_return_val_if_fail (dest->bits_per_sample == 8, NULL);
1253         }
1254
1255         /* Coordinate sanity checks */
1256
1257         if (!is_pixmap) {
1258             XGetWindowAttributes (gdk_pixbuf_dpy, src, &wa);
1259             src_width = wa.width;
1260             src_height = wa.height;
1261         } else {
1262             Window root;
1263             int tx, ty;
1264             guint bwidth, depth;
1265             XGetGeometry (gdk_pixbuf_dpy, src, &root, &tx, &ty,
1266                           &src_width, &src_height, &bwidth, &depth);
1267         }
1268
1269         g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
1270         g_return_val_if_fail (src_x + width <= src_width
1271                               && src_y + height <= src_height, NULL);
1272
1273         if (dest) {
1274                 g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
1275                 g_return_val_if_fail (dest_x + width <= dest->width, NULL);
1276                 g_return_val_if_fail (dest_y + height <= dest->height, NULL);
1277         }
1278
1279         if (!is_pixmap) {
1280                 int ret;
1281                 int src_xorigin, src_yorigin;
1282                 int screen_width, screen_height;
1283                 int screen_srcx, screen_srcy;
1284
1285                 ret = xlib_window_get_origin (src, &src_xorigin, &src_yorigin);
1286                 g_return_val_if_fail (ret != FALSE, NULL);
1287
1288                 screen_width = DisplayWidth (gdk_pixbuf_dpy, gdk_pixbuf_screen);
1289                 screen_height = DisplayHeight (gdk_pixbuf_dpy, gdk_pixbuf_screen);
1290
1291                 screen_srcx = src_xorigin + src_x;
1292                 screen_srcy = src_yorigin + src_y;
1293
1294                 g_return_val_if_fail (screen_srcx >= 0 && screen_srcy >= 0, NULL);
1295                 g_return_val_if_fail (screen_srcx + width <= screen_width, NULL);
1296                 g_return_val_if_fail (screen_srcy + height <= screen_height, NULL);
1297         }
1298
1299         /* Get Image in ZPixmap format (packed bits). */
1300         image = XGetImage (gdk_pixbuf_dpy, src, src_x, src_y,
1301                            width, height, AllPlanes, ZPixmap);
1302         g_return_val_if_fail (image != NULL, NULL);
1303
1304         /* Create the pixbuf if needed */
1305         if (!dest) {
1306                 dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1307                                        FALSE, 8, width, height);
1308                 if (!dest) {
1309                         XDestroyImage (image);
1310                         return NULL;
1311                 }
1312         }
1313
1314         /* Get the colormap if needed */
1315         if (!is_pixmap)
1316         {
1317                 cmap = wa.colormap;
1318                 visual = wa.visual;
1319         }
1320
1321         x_cmap = xlib_get_colormap (cmap, visual);
1322
1323         alpha = dest->has_alpha;
1324         rowstride = dest->rowstride;
1325         bpp = alpha ? 4 : 3;
1326
1327         /* we offset into the image data based on the position we are retrieving from */
1328         rgbconvert (image, dest->pixels +
1329                     (dest_y * rowstride) + (dest_x * bpp),
1330                     rowstride,
1331                     alpha,
1332                     x_cmap);
1333
1334         xlib_colormap_free (x_cmap);
1335         XDestroyImage (image);
1336
1337         return dest;
1338 }