* atk-bridge/bridge.c:
[platform/core/uifw/at-spi2-atk.git] / util / mag_image.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001 Sun Microsystems Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "mag_image.h"
24
25
26 static int get_num(char* msg);
27 static void get_coord(char* msg,point *p);
28 static void get_rect(char* msg, point *p1, point *p2);
29 static void compute_center_coord(point p1, point p2, point *center);
30 static xlib_colormap * xlib_get_colormap (Colormap id, Visual *visual, MagnifierData *data);
31 static guint32 mask_table[] = {
32         0x00000000, 0x00000001, 0x00000003, 0x00000007,
33         0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
34         0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
35         0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
36         0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
37         0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
38         0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
39         0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
40         0xffffffff
41 };
42
43 void parse_message(char *msg, MagnifierData *data){
44
45   int type;
46   point roi_pos, roi_size;
47   point mag_pos, mag_size;
48   
49   printf("%s\n",msg);
50   if(msg[0] != '~'){
51     fprintf(stderr,"corrupted message, discarding\n");
52     return;
53   }
54   type = atoi((char*)&msg[1]);
55   switch (type){
56         case FACTOR :
57             old_factor_x = data->factor_x;
58             data->factor_x = get_num(msg);
59             old_factor_y = data->factor_y;
60             data->factor_y = get_num(msg);
61             printf("FACTOR = %d\n",data->factor_x);
62             break;
63         case CONTRAST :
64             data->contrast = get_num(msg);
65             printf("CONTRAST = %d\n",data->contrast);
66             break;
67         case FOLLOW_MOUSE :
68             data->follow_mouse = get_num(msg);
69             printf("FOLLOW_MOUSE = %d\n",data->follow_mouse);
70             break;
71         case COLOR_INVERTED :
72             data->color_inverted = get_num(msg);
73             printf("COLOR_INVERTED = %d\n",data->color_inverted);
74             break;
75         case GOTO :
76             get_coord(msg, &data->center);
77             printf("GOTO = (%d,%d)\n", data->center.x, data->center.y);
78             break;
79         case SET_ROI:
80             get_rect (msg, &roi_pos, &roi_size);
81             printf("ROI = (%d,%d; %d,%d)\n", roi_pos.x, roi_pos.y, roi_size.x, roi_size.y);
82             compute_center_coord (roi_pos, roi_size, &data->center);
83             break;
84         case SET_EXTENTS:
85             get_rect (msg, &mag_pos, &mag_size);
86             printf("EXTENTS = (%d,%d; %d,%d)\n", mag_pos.x, mag_pos.y, mag_size.x, mag_size.y);
87             data->mag_width = mag_size.x;
88             data->mag_height = mag_size.y;
89             gdk_window_move_resize (data->output_window->window, mag_pos.x,
90                                     mag_pos.y,
91                                     data->mag_width, data->mag_height);
92             break;
93         case STOP :
94             printf("STOP\n");
95             gtk_main_quit();
96             break;
97         default:
98             break;
99   }
100 }
101
102
103 static int get_num(char* msg){
104  int type,num;
105  sscanf(msg,"~%d:%d:",&type,&num);
106  return num;
107 }
108
109 static void get_coord(char* msg,point *p){
110  int type;
111  sscanf(msg,"~%d:%d,%d:",&type,&p->x,&p->y);
112 }
113
114 static void get_rect(char* msg, point *p1, point *p2){
115  int type;
116  sscanf(msg,"~%d:%d,%d;%d,%d:",&type, &p1->x, &p1->y, &p2->x, &p2->y);
117 }
118
119 static void compute_center_coord (point pos, point size, point *center) {
120   center->x = pos.x + (size.x/2);
121   center->y = pos.y + (size.y/2);
122 }
123
124 int display_image(gpointer data)
125 {
126   MagnifierData *mag_data = (MagnifierData *)data;
127   update_image(mag_data);
128   gdk_pixbuf_scale(image,
129                    scaled_image,
130                    0,
131                    0,
132                    DisplayWidth (mag_data->target_display,screen_num),
133                    DisplayHeight(mag_data->target_display,screen_num),
134                    0,
135                    0,
136                    mag_data->factor_x,
137                    mag_data->factor_y,
138                    GDK_INTERP_NEAREST);
139   
140   gdk_pixbuf_render_to_drawable (scaled_image,
141                         drawing_area->window,
142                         drawing_area->style->fg_gc[GTK_STATE_NORMAL],
143                         0,0,0,0,DisplayWidth (mag_data->target_display,screen_num),
144                         DisplayHeight(mag_data->target_display,screen_num),
145                         GDK_RGB_DITHER_NORMAL,0,0);
146
147   gdk_window_raise (drawing_area->window);
148   return TRUE;
149 }
150
151 void update_image(MagnifierData *mag_data)
152 {
153  int x, y, total_width, total_height;
154   
155  if(mag_data->follow_mouse){
156     Window root_return, child_return;
157     int win_x_return,win_y_return;
158     unsigned int mask_return;
159     XQueryPointer(mag_data->source_display,spi_image_root_window,
160                   &root_return,&child_return,
161                   &mag_data->center.x,&mag_data->center.y,
162                   &win_x_return,&win_y_return,&mask_return);
163   }
164
165   total_width = DisplayWidth (mag_data->source_display,screen_num);
166   total_height = DisplayHeight(mag_data->source_display,screen_num);
167
168   x = mag_data->center.x - mag_data->mag_width/mag_data->factor_x/2;
169   y = mag_data->center.y - mag_data->mag_height/mag_data->factor_y/2;
170
171   if(mag_data->center.x < mag_data->mag_width/mag_data->factor_x/2)
172     x = 0;
173   if(mag_data->center.x > (total_width - mag_data->mag_width/mag_data->factor_x/2))
174     x = total_width - mag_data->mag_width/mag_data->factor_x;
175   if(mag_data->center.y < mag_data->mag_height/mag_data->factor_y/2)
176     y = 0;
177   if(mag_data->center.y > (total_height - mag_data->mag_height/mag_data->factor_y/2))
178     y = total_height - mag_data->mag_height/mag_data->factor_y;
179   if(x < 0)
180     x = 0;
181   if(y < 0)
182     y = 0;
183 /*
184   printf("p = (%d,%d), x,y = (%d,%d), h,w = (%d,%d), ht,wt = (%d,%d)\n",
185                                         mag_data->center.x,
186                                         mag_data->center.y,
187                                         x,y,
188                                         mag_data->mag_height,mag_data->mag_width,
189                                         total_height,
190                                         total_width);
191 */
192   if(mag_data->factor_x != old_factor_x || mag_data->factor_y != old_factor_y){
193     g_object_unref((GObject *)image);
194     image = gdk_pixbuf_new (GDK_COLORSPACE_RGB,FALSE, 8,
195                                 DisplayWidth (mag_data->target_display,screen_num)/mag_data->factor_x,
196                                 DisplayHeight(mag_data->target_display,screen_num)/mag_data->factor_y);
197     /* yes, use target display above, since the size of the area grabbed depends on the target */
198     old_factor_x = mag_data->factor_x;
199     old_factor_y = mag_data->factor_y;
200   }
201   get_root_image(spi_image_root_window,
202                  image,
203                  x,
204                  y,
205                  mag_data);
206 }
207 void expose_event(GtkWidget * w, GdkEventExpose *event, gpointer data){
208
209 }
210
211
212
213
214 /* SpiImage grabbing and convertion routines from gdk-pixbuf-xlib */
215 /*
216   convert 1 bits-pixel data
217   no alpha
218 */
219 static void
220 rgb1 (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
221 {
222         int xx, yy;
223         int width, height;
224         int bpl;
225         guint8 *s;
226         register guint8 data;
227         guint8 *o;
228         guint8 *srow = image->data, *orow = pixels;
229
230         /* convert upto 8 pixels/time */
231         /* its probably not worth trying to make this run very fast, who uses
232            1 bit displays anymore? */
233         width = image->width;
234         height = image->height;
235         bpl = image->bytes_per_line;
236
237         for (yy = 0; yy < height; yy++) {
238                 s = srow;
239                 o = orow;
240
241                 for (xx = 0; xx < width; xx ++) {
242                         data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
243                         *o++ = colormap->colors[data].red;
244                         *o++ = colormap->colors[data].green;
245                         *o++ = colormap->colors[data].blue;
246                 }
247                 srow += bpl;
248                 orow += rowstride;
249         }
250 }
251
252 /*
253   convert 1 bits/pixel data
254   with alpha
255 */
256 static void
257 rgb1a (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
258 {
259         int xx, yy;
260         int width, height;
261         int bpl;
262         guint8 *s;
263         register guint8 data;
264         guint8 *o;
265         guint8 *srow = image->data, *orow = pixels;
266         guint32 remap[2];
267
268         /* convert upto 8 pixels/time */
269         /* its probably not worth trying to make this run very fast, who uses
270            1 bit displays anymore? */
271         width = image->width;
272         height = image->height;
273         bpl = image->bytes_per_line;
274
275         for (xx = 0; xx < 2; xx++) {
276 #ifdef LITTLE
277                 remap[xx] = 0xff000000
278                         | colormap->colors[xx].blue << 16
279                         | colormap->colors[xx].green << 8
280                         | colormap->colors[xx].red;
281 #else
282                 remap[xx] = 0xff
283                         | colormap->colors[xx].red << 24
284                         | colormap->colors[xx].green << 16
285                         | colormap->colors[xx].blue << 8;
286 #endif
287         }
288
289         for (yy = 0; yy < height; yy++) {
290                 s = srow;
291                 o = orow;
292
293                 for (xx = 0; xx < width; xx ++) {
294                         data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
295                         *o++ = remap[data];
296                 }
297                 srow += bpl;
298                 orow += rowstride;
299         }
300 }
301
302 /*
303   convert 8 bits/pixel data
304   no alpha
305 */
306 static void
307 rgb8 (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
308 {
309         int xx, yy;
310         int width, height;
311         int bpl;
312         guint32 mask;
313         register guint32 data;
314         guint8 *srow = image->data, *orow = pixels;
315         register guint8 *s;
316         register guint8 *o;
317
318         width = image->width;
319         height = image->height;
320         bpl = image->bytes_per_line;
321
322         mask = mask_table[image->depth];
323
324         for (yy = 0; yy < height; yy++) {
325                 s = srow;
326                 o = orow;
327                 for (xx = 0; xx < width; xx++) {
328                         data = *s++ & mask;
329                         *o++ = colormap->colors[data].red;
330                         *o++ = colormap->colors[data].green;
331                         *o++ = colormap->colors[data].blue;
332                 }
333                 srow += bpl;
334                 orow += rowstride;
335         }
336 }
337
338 /*
339   convert 8 bits/pixel data
340   with alpha
341 */
342 static void
343 rgb8a (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
344 {
345         int xx, yy;
346         int width, height;
347         int bpl;
348         guint32 mask;
349         register guint32 data;
350         guint32 remap[256];
351         register guint8 *s;     /* read 2 pixels at once */
352         register guint32 *o;
353         guint8 *srow = image->data, *orow = pixels;
354
355         width = image->width;
356         height = image->height;
357         bpl = image->bytes_per_line;
358
359         mask = mask_table[image->depth];
360
361         for (xx = 0; xx < colormap->size; xx++) {
362 #ifdef LITTLE
363                 remap[xx] = 0xff000000
364                         | colormap->colors[xx].blue << 16
365                         | colormap->colors[xx].green << 8
366                         | colormap->colors[xx].red;
367 #else
368                 remap[xx] = 0xff
369                         | colormap->colors[xx].red << 24
370                         | colormap->colors[xx].green << 16
371                         | colormap->colors[xx].blue << 8;
372 #endif
373         }
374
375         for (yy = 0; yy < height; yy++) {
376                 s = srow;
377                 o = (guint32 *) orow;
378                 for (xx = 0; xx < width; xx ++) {
379                         data = *s++ & mask;
380                         *o++ = remap[data];
381                 }
382                 srow += bpl;
383                 orow += rowstride;
384         }
385 }
386
387 /*
388   convert 16 bits/pixel data
389   no alpha
390   data in lsb format
391 */
392 static void
393 rgb565lsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
394 {
395         int xx, yy;
396         int width, height;
397         int bpl;
398
399 #ifdef LITTLE
400         register guint32 *s;    /* read 2 pixels at once */
401 #else
402         register guint8 *s;     /* read 2 pixels at once */
403 #endif
404         register guint16 *o;
405         guint8 *srow = image->data, *orow = pixels;
406
407         width = image->width;
408         height = image->height;
409         bpl = image->bytes_per_line;
410
411         for (yy = 0; yy < height; yy++) {
412 #ifdef LITTLE
413                 s = (guint32 *) srow;
414 #else
415                 s = srow;
416 #endif
417                 o = (guint16 *) orow;
418                 for (xx = 1; xx < width; xx += 2) {
419                         register guint32 data;
420 #ifdef LITTLE
421                         data = *s++;
422                         *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
423                                 | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
424                         *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
425                                 | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
426                         *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
427                                 | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
428 #else
429                         /* swap endianness first */
430                         data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
431                         s += 4;
432                         *o++ = (data & 0xf800) | (data & 0xe000) >> 5
433                                 | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
434                         *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
435                                 | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
436                         *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
437                                 | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
438 #endif
439                 }
440                 /* check for last remaining pixel */
441                 if (width & 1) {
442                         register guint16 data;
443 #ifdef LITTLE
444                         data = *((short *) s);
445 #else
446                         data = *((short *) s);
447                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
448 #endif
449                         ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
450                         ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
451                         ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
452                 }
453                 srow += bpl;
454                 orow += rowstride;
455         }
456 }
457
458 /*
459   convert 16 bits/pixel data
460   no alpha
461   data in msb format
462 */
463 static void
464 rgb565msb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
465 {
466         int xx, yy;
467         int width, height;
468         int bpl;
469
470 #ifdef LITTLE
471         register guint8 *s;     /* need to swap data order */
472 #else
473         register guint32 *s;    /* read 2 pixels at once */
474 #endif
475         register guint16 *o;
476         guint8 *srow = image->data, *orow = pixels;
477
478         width = image->width;
479         height = image->height;
480         bpl = image->bytes_per_line;
481
482         for (yy = 0; yy < height; yy++) {
483 #ifdef LITTLE
484                 s = srow;
485 #else
486                 s = (guint32 *) srow;
487 #endif
488                 o = (guint16 *) orow;
489                 for (xx = 1; xx < width; xx += 2) {
490                         register guint32 data;
491 #ifdef LITTLE
492                         /* swap endianness first */
493                         data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
494                         s += 4;
495                         *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
496                                 | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
497                         *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
498                                 | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
499                         *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
500                                 | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
501 #else
502                         data = *s++;
503                         *o++ = (data & 0xf800) | (data & 0xe000) >> 5
504                                 | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
505                         *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
506                                 | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
507                         *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
508                                 | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
509 #endif
510                 }
511                 /* check for last remaining pixel */
512                 if (width & 1) {
513                         register guint16 data;
514 #ifdef LITTLE
515                         data = *((short *) s);
516                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
517 #else
518                         data = *((short *) s);
519 #endif
520                         ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
521                         ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
522                         ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
523                 }
524                 srow += bpl;
525                 orow += rowstride;
526         }
527 }
528
529 /*
530   convert 16 bits/pixel data
531   with alpha
532   data in lsb format
533 */
534 static void
535 rgb565alsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
536 {
537         int xx, yy;
538         int width, height;
539         int bpl;
540
541 #ifdef LITTLE
542         register guint16 *s;    /* read 1 pixels at once */
543 #else
544         register guint8 *s;
545 #endif
546         register guint32 *o;
547
548         guint8 *srow = image->data, *orow = pixels;
549
550         width = image->width;
551         height = image->height;
552         bpl = image->bytes_per_line;
553
554         for (yy = 0; yy < height; yy++) {
555 #ifdef LITTLE
556                 s = (guint16 *) srow;
557 #else
558                 s = (guint8 *) srow;
559 #endif
560                 o = (guint32 *) orow;
561                 for (xx = 0; xx < width; xx ++) {
562                         register guint32 data;
563                         /*  rrrrrggg gggbbbbb -> rrrrrRRR ggggggGG bbbbbBBB aaaaaaaa */
564                         /*  little endian: aaaaaaaa bbbbbBBB ggggggGG rrrrrRRR */
565 #ifdef LITTLE
566                         data = *s++;
567                         *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
568                                 | (data & 0x7e0) << 5 | (data & 0x600) >> 1
569                                 | (data & 0x1f) << 19 | (data & 0x1c) << 14
570                                 | 0xff000000;
571 #else
572                         /* swap endianness first */
573                         data = s[0] | s[1] << 8;
574                         s += 2;
575                         *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
576                                 | (data & 0x7e0) << 13 | (data & 0x600) << 7
577                                 | (data & 0x1f) << 11 | (data & 0x1c) << 6
578                                 | 0xff;
579 #endif
580                 }
581                 srow += bpl;
582                 orow += rowstride;
583         }
584 }
585
586 /*
587   convert 16 bits/pixel data
588   with alpha
589   data in msb format
590 */
591 static void
592 rgb565amsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
593 {
594         int xx, yy;
595         int width, height;
596         int bpl;
597
598 #ifdef LITTLE
599         register guint8 *s;
600 #else
601         register guint16 *s;    /* read 1 pixels at once */
602 #endif
603         register guint32 *o;
604
605         guint8 *srow = image->data, *orow = pixels;
606
607         width = image->width;
608         height = image->height;
609         bpl = image->bytes_per_line;
610
611         for (yy = 0; yy < height; yy++) {
612                 s = srow;
613                 o = (guint32 *) orow;
614                 for (xx = 0; xx < width; xx ++) {
615                         register guint32 data;
616                         /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggg00 bbbbbBBB aaaaaaaa */
617                         /*  little endian: aaaaaaaa bbbbbBBB gggggg00 rrrrrRRR */
618 #ifdef LITTLE
619                         /* swap endianness first */
620                         data = s[0] | s[1] << 8;
621                         s += 2;
622                         *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
623                                 | (data & 0x7e0) << 5 | (data & 0x600) >> 1
624                                 | (data & 0x1f) << 19 | (data & 0x1c) << 14
625                                 | 0xff000000;
626 #else
627                         data = *s++;
628                         *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
629                                 | (data & 0x7e0) << 13 | (data & 0x600) << 7
630                                 | (data & 0x1f) << 11 | (data & 0x1c) << 6
631                                 | 0xff;
632 #endif
633                 }
634                 srow += bpl;
635                 orow += rowstride;
636         }
637 }
638
639 /*
640   convert 15 bits/pixel data
641   no alpha
642   data in lsb format
643 */
644 static void
645 rgb555lsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
646 {
647         int xx, yy;
648         int width, height;
649         int bpl;
650
651 #ifdef LITTLE
652         register guint32 *s;    /* read 2 pixels at once */
653 #else
654         register guint8 *s;     /* read 2 pixels at once */
655 #endif
656         register guint16 *o;
657         guint8 *srow = image->data, *orow = pixels;
658
659         width = image->width;
660         height = image->height;
661         bpl = image->bytes_per_line;
662
663         for (yy = 0; yy < height; yy++) {
664 #ifdef LITTLE
665                 s = (guint32 *) srow;
666 #else
667                 s = srow;
668 #endif
669                 o = (guint16 *) orow;
670                 for (xx = 1; xx < width; xx += 2) {
671                         register guint32 data;
672 #ifdef LITTLE
673                         data = *s++;
674                         *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
675                                 | (data & 0x3e0) << 6 | (data & 0x380) << 1;
676                         *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
677                                 | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
678                         *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
679                                 | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
680 #else
681                         /* swap endianness first */
682                         data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
683                         s += 4;
684                         *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
685                                 | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
686                         *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
687                                 | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
688                         *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
689                                 | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
690 #endif
691                 }
692                 /* check for last remaining pixel */
693                 if (width & 1) {
694                         register guint16 data;
695 #ifdef LITTLE
696                         data = *((short *) s);
697 #else
698                         data = *((short *) s);
699                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
700 #endif
701                         ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
702                         ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
703                         ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
704                 }
705                 srow += bpl;
706                 orow += rowstride;
707         }
708 }
709
710 /*
711   convert 15 bits/pixel data
712   no alpha
713   data in msb format
714 */
715 static void
716 rgb555msb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
717 {
718         int xx, yy;
719         int width, height;
720         int bpl;
721
722 #ifdef LITTLE
723         register guint8 *s;     /* read 2 pixels at once */
724 #else
725         register guint32 *s;    /* read 2 pixels at once */
726 #endif
727         register guint16 *o;
728         guint8 *srow = image->data, *orow = pixels;
729
730         width = image->width;
731         height = image->height;
732         bpl = image->bytes_per_line;
733
734         for (yy = 0; yy < height; yy++) {
735                 s = srow;
736                 o = (guint16 *) orow;
737                 for (xx = 1; xx < width; xx += 2) {
738                         register guint32 data;
739 #ifdef LITTLE
740                         /* swap endianness first */
741                         data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
742                         s += 4;
743                         *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
744                                 | (data & 0x3e0) << 6 | (data & 0x380) << 1;
745                         *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
746                                 | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
747                         *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
748                                 | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
749 #else
750                         data = *s++;
751                         *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
752                                 | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
753                         *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
754                                 | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
755                         *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
756                                 | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
757 #endif
758                 }
759                 /* check for last remaining pixel */
760                 if (width & 1) {
761                         register guint16 data;
762 #ifdef LITTLE
763                         data = *((short *) s);
764                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
765 #else
766                         data = *((short *) s);
767 #endif
768                         ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
769                         ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
770                         ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
771                 }
772                 srow += bpl;
773                 orow += rowstride;
774         }
775 }
776
777 /*
778   convert 15 bits/pixel data
779   with alpha
780   data in lsb format
781 */
782 static void
783 rgb555alsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
784 {
785         int xx, yy;
786         int width, height;
787         int bpl;
788
789 #ifdef LITTLE
790         register guint16 *s;    /* read 1 pixels at once */
791 #else
792         register guint8 *s;
793 #endif
794         register guint32 *o;
795
796         guint8 *srow = image->data, *orow = pixels;
797
798         width = image->width;
799         height = image->height;
800         bpl = image->bytes_per_line;
801
802         for (yy = 0; yy < height; yy++) {
803 #ifdef LITTLE
804                 s = (guint16 *) srow;
805 #else
806                 s = srow;
807 #endif
808                 o = (guint32 *) orow;
809                 for (xx = 0; xx < width; xx++) {
810                         register guint32 data;
811                         /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
812                         /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
813 #ifdef LITTLE
814                         data = *s++;
815                         *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
816                                 | (data & 0x3e0) << 6 | (data & 0x380) << 1
817                                 | (data & 0x1f) << 19 | (data & 0x1c) << 14
818                                 | 0xff000000;
819 #else
820                         /* swap endianness first */
821                         data = s[0] | s[1] << 8;
822                         s += 2;
823                         *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
824                                 | (data & 0x3e0) << 14 | (data & 0x380) << 9
825                                 | (data & 0x1f) << 11 | (data & 0x1c) << 6
826                                 | 0xff;
827 #endif
828                 }
829                 srow += bpl;
830                 orow += rowstride;
831         }
832 }
833
834 /*
835   convert 15 bits/pixel data
836   with alpha
837   data in msb format
838 */
839 static void
840 rgb555amsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
841 {
842         int xx, yy;
843         int width, height;
844         int bpl;
845
846 #ifdef LITTLE
847         register guint16 *s;    /* read 1 pixels at once */
848 #else
849         register guint8 *s;
850 #endif
851         register guint32 *o;
852
853         guint8 *srow = image->data, *orow = pixels;
854
855         width = image->width;
856         height = image->height;
857         bpl = image->bytes_per_line;
858
859         for (yy = 0; yy < height; yy++) {
860 #ifdef LITTLE
861                 s = (guint16 *) srow;
862 #else
863                 s = srow;
864 #endif
865                 o = (guint32 *) orow;
866                 for (xx = 0; xx < width; xx++) {
867                         register guint32 data;
868                         /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
869                         /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
870 #ifdef LITTLE
871                         /* swap endianness first */
872                         data = s[0] | s[1] << 8;
873                         s += 2;
874                         *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
875                                 | (data & 0x3e0) << 6 | (data & 0x380) << 1
876                                 | (data & 0x1f) << 19 | (data & 0x1c) << 14
877                                 | 0xff000000;
878 #else
879                         data = *s++;
880                         *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
881                                 | (data & 0x3e0) << 14 | (data & 0x380) << 9
882                                 | (data & 0x1f) << 11 | (data & 0x1c) << 6
883                                 | 0xff;
884 #endif
885                 }
886                 srow += bpl;
887                 orow += rowstride;
888         }
889 }
890
891
892 static void
893 rgb888alsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
894 {
895         int xx, yy;
896         int width, height;
897         int bpl;
898
899         guint8 *s;      /* for byte order swapping */
900         guint8 *o;
901         guint8 *srow = image->data, *orow = pixels;
902
903         width = image->width;
904         height = image->height;
905         bpl = image->bytes_per_line;
906
907         /* lsb data */
908         for (yy = 0; yy < height; yy++) {
909                 s = srow;
910                 o = orow;
911                 for (xx = 0; xx < width; xx++) {
912                         *o++ = s[2];
913                         *o++ = s[1];
914                         *o++ = s[0];
915                         *o++ = 0xff;
916                         s += 4;
917                 }
918                 srow += bpl;
919                 orow += rowstride;
920         }
921 }
922
923 static void
924 rgb888lsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
925 {
926         int xx, yy;
927         int width, height;
928         int bpl;
929
930         guint8 *srow = image->data, *orow = pixels;
931         guint8 *o, *s;
932
933         width = image->width;
934         height = image->height;
935         bpl = image->bytes_per_line;
936
937
938         for (yy = 0; yy < height; yy++) {
939                 s = srow;
940                 o = orow;
941                 for (xx = 0; xx < width; xx++) {
942                         *o++ = s[2];
943                         *o++ = s[1];
944                         *o++ = s[0];
945                         s += 4;
946                 }
947                 srow += bpl;
948                 orow += rowstride;
949         }
950 }
951
952 static void
953 rgb888amsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
954 {
955         int xx, yy;
956         int width, height;
957         int bpl;
958
959         guint8 *srow = image->data, *orow = pixels;
960 #ifdef LITTLE
961         guint32 *o;
962         guint32 *s;
963 #else
964         guint8 *s;      /* for byte order swapping */
965         guint8 *o;
966 #endif
967
968
969         width = image->width;
970         height = image->height;
971         bpl = image->bytes_per_line;
972
973         /* msb data */
974         for (yy = 0; yy < height; yy++) {
975 #ifdef LITTLE
976                 s = (guint32 *) srow;
977                 o = (guint32 *) orow;
978 #else
979                 s = srow;
980                 o = orow;
981 #endif
982                 for (xx = 0; xx < width; xx++) {
983 #ifdef LITTLE
984                         *o++ = s[1];
985                         *o++ = s[2];
986                         *o++ = s[3];
987                         *o++ = 0xff;
988                         s += 4;
989 #else
990                         *o++ = (*s << 8) | 0xff; /* untested */
991                         s++;
992 #endif
993                 }
994                 srow += bpl;
995                 orow += rowstride;
996         }
997 }
998
999 static void
1000 rgb888msb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
1001 {
1002         int xx, yy;
1003         int width, height;
1004         int bpl;
1005
1006         guint8 *srow = image->data, *orow = pixels;
1007         guint8 *s;
1008         guint8 *o;
1009
1010
1011         width = image->width;
1012         height = image->height;
1013         bpl = image->bytes_per_line;
1014
1015         for (yy = 0; yy < height; yy++) {
1016                 s = srow;
1017                 o = orow;
1018                 for (xx = 0; xx < width; xx++) {
1019                         *o++ = s[1];
1020                         *o++ = s[2];
1021                         *o++ = s[3];
1022                         s += 4;
1023                 }
1024                 srow += bpl;
1025                 orow += rowstride;
1026         }
1027 }
1028 static void
1029 visual_decompose_mask (gulong  mask,
1030                        gint   *shift,
1031                        gint   *prec)
1032 {
1033         *shift = 0;
1034         *prec = 0;
1035
1036         while (!(mask & 0x1)) {
1037                 (*shift)++;
1038                 mask >>= 1;
1039         }
1040
1041         while (mask & 0x1) {
1042                 (*prec)++;
1043                 mask >>= 1;
1044         }
1045 }
1046
1047
1048 /*
1049   This should work correctly with any display/any endianness, but will probably
1050   run quite slow
1051 */
1052 static void
1053 convert_real_slow (XImage *image, guchar *pixels, int rowstride, xlib_colormap *cmap, int alpha)
1054 {
1055         int xx, yy;
1056         int width, height;
1057         int bpl;
1058         guint8 *srow = image->data, *orow = pixels;
1059         guint8 *s;
1060         guint8 *o;
1061         guint32 pixel;
1062         Visual *v;
1063         guint8 component;
1064         int i;
1065         int red_shift, red_prec, green_shift, green_prec, blue_shift, blue_prec;
1066
1067         width = image->width;
1068         height = image->height;
1069         bpl = image->bytes_per_line;
1070         v = cmap->visual;
1071
1072         visual_decompose_mask (v->red_mask, &red_shift, &red_prec);
1073         visual_decompose_mask (v->green_mask, &green_shift, &green_prec);
1074         visual_decompose_mask (v->blue_mask, &blue_shift, &blue_prec);
1075
1076         for (yy = 0; yy < height; yy++) {
1077                 s = srow;
1078                 o = orow;
1079                 for (xx = 0; xx < width; xx++) {
1080                         pixel = XGetPixel (image, xx, yy);
1081                         switch (v->class) {
1082                                 /* I assume this is right for static & greyscale's too? */
1083                         case StaticGray:
1084                         case GrayScale:
1085                         case StaticColor:
1086                         case PseudoColor:
1087                                 *o++ = cmap->colors[pixel].red;
1088                                 *o++ = cmap->colors[pixel].green;
1089                                 *o++ = cmap->colors[pixel].blue;
1090                                 break;
1091                         case TrueColor:
1092                                 /* This is odd because it must sometimes shift left (otherwise
1093                                    I'd just shift >> (*_shift - 8 + *_prec + <0-7>). This logic
1094                                    should work for all bit sizes/shifts/etc. */
1095                                 component = 0;
1096                                 for (i = 24; i < 32; i += red_prec)
1097                                         component |= ((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> i;
1098                                 *o++ = component;
1099                                 component = 0;
1100                                 for (i = 24; i < 32; i += green_prec)
1101                                         component |= ((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> i;
1102                                 *o++ = component;
1103                                 component = 0;
1104                                 for (i = 24; i < 32; i += blue_prec)
1105                                         component |= ((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> i;
1106                                 *o++ = component;
1107                                 break;
1108                         case DirectColor:
1109                                 *o++ = cmap->colors[((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> 24].red;
1110                                 *o++ = cmap->colors[((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> 24].green;
1111                                 *o++ = cmap->colors[((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> 24].blue;
1112                                 break;
1113                         }
1114                         if (alpha)
1115                                 *o++ = 0xff;
1116                 }
1117                 srow += bpl;
1118                 orow += rowstride;
1119         }
1120 }
1121
1122 static xlib_colormap *
1123 xlib_get_colormap (Colormap id, Visual *visual, MagnifierData *mag_data)
1124 {
1125         int i;
1126         xlib_colormap *xc = g_new (xlib_colormap, 1);
1127
1128         xc->size = visual->map_entries;
1129         xc->colors = g_new (XColor, xc->size);
1130         xc->visual = visual;
1131         xc->colormap = id;
1132
1133         for (i = 0; i < xc->size; i++) {
1134                 xc->colors[i].pixel = i;
1135                 xc->colors[i].flags = DoRed | DoGreen | DoBlue;
1136         }
1137
1138         XQueryColors (mag_data->source_display, xc->colormap, xc->colors, xc->size);
1139
1140         return xc;
1141 }
1142
1143 typedef void (* cfunc) (XImage *image, guchar *pixels, int rowstride, xlib_colormap *cmap);
1144 static cfunc convert_map[] = {
1145         rgb1,rgb1,rgb1a,rgb1a,
1146         rgb8,rgb8,rgb8a,rgb8a,
1147         rgb555lsb,rgb555msb,rgb555alsb,rgb555amsb,
1148         rgb565lsb,rgb565msb,rgb565alsb,rgb565amsb,
1149         rgb888lsb,rgb888msb,rgb888alsb,rgb888amsb
1150 };
1151
1152 static void
1153 rgbconvert (XImage *image, guchar *pixels, int rowstride, int alpha, xlib_colormap *cmap,
1154             MagnifierData *mag_data)
1155 {
1156   int index = (image->byte_order == MSBFirst) | (alpha != 0) << 1;
1157   int bank=5;           /* default fallback converter */
1158   Visual *v = cmap->visual;
1159   if (mag_data->fast_rgb_convert)
1160     {     
1161         switch (v->class) {
1162                                 /* I assume this is right for static & greyscale's too? */
1163         case StaticGray:
1164         case GrayScale:
1165         case StaticColor:
1166         case PseudoColor:
1167                 switch (image->bits_per_pixel) {
1168                 case 1:
1169                         bank = 0;
1170                         break;
1171                 case 8:
1172                         bank = 1;
1173                         break;
1174                 }
1175                 break;
1176         case TrueColor:
1177                 switch (image->depth) {
1178                 case 15:
1179                         if (v->red_mask == 0x7c00 && v->green_mask == 0x3e0 && v->blue_mask == 0x1f
1180                             && image->bits_per_pixel == 16)
1181                                 bank = 2;
1182                         break;
1183                 case 16:
1184                         if (v->red_mask == 0xf800 && v->green_mask == 0x7e0 && v->blue_mask == 0x1f
1185                             && image->bits_per_pixel == 16)
1186                                 bank = 3;
1187                         break;
1188                 case 24:
1189                 case 32:
1190                         if (v->red_mask == 0xff0000 && v->green_mask == 0xff00 && v->blue_mask == 0xff
1191                             && image->bits_per_pixel == 32)
1192                                 bank = 4;
1193                         break;
1194                 }
1195                 break;
1196         case DirectColor:
1197                 /* always use the slow version */
1198                 break;
1199         }
1200     }
1201
1202         if (bank==5) {
1203                 convert_real_slow(image, pixels, rowstride, cmap, alpha);
1204         } else {
1205                 index |= bank << 2;
1206                 (* convert_map[index]) (image, pixels, rowstride, cmap);
1207         }
1208 }
1209
1210 void get_root_image(Window src, GdkPixbuf *dest, int src_x, int src_y, MagnifierData *mag_data)  {
1211         XImage *image;
1212         int width = mag_data->mag_width/mag_data->factor_x;
1213         int height = mag_data->mag_height/mag_data->factor_y;
1214
1215         /* Get SpiImage in ZPixmap format (packed bits). */
1216         image = XGetImage (mag_data->source_display, src, src_x, src_y,
1217                            width, height, AllPlanes, ZPixmap);
1218         g_assert(image != NULL);
1219
1220         if(x_cmap == NULL){
1221             XWindowAttributes wa;
1222             XGetWindowAttributes (mag_data->source_display, src, &wa);
1223             x_cmap = xlib_get_colormap (wa.colormap, wa.visual, mag_data);                        
1224         }
1225         /* we offset into the image data based on the position we are retrieving from */
1226         rgbconvert (image, gdk_pixbuf_get_pixels(dest),
1227                     gdk_pixbuf_get_rowstride(dest),
1228                     gdk_pixbuf_get_has_alpha(dest),
1229                     x_cmap,
1230                     mag_data);
1231
1232         /* would like to use GDK routine, but since we don't have multi-head
1233            yet, we have to use X */
1234
1235         XDestroyImage (image);
1236 }
1237
1238