]> Pileus Git - ~andy/gtk/blob - gtk/gtkpreview.c
changed reversed_[12] to reserved_[12] in gtk_*_get_type functions.
[~andy/gtk] / gtk / gtkpreview.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <math.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <sys/param.h>
24 #include "gdk/gdkx.h"
25 #include "gtkpreview.h"
26 #include "gtksignal.h"
27
28
29 #define IMAGE_SIZE            256
30 #define PREVIEW_CLASS(w)      GTK_PREVIEW_CLASS (GTK_OBJECT (w)->klass)
31 #define COLOR_COMPOSE(r,g,b)  (lookup_red[r] | lookup_green[g] | lookup_blue[b])
32
33
34 typedef struct _GtkPreviewProp  GtkPreviewProp;
35 typedef void (*GtkTransferFunc) (guchar *dest, guchar *src, gint count);
36
37 struct _GtkPreviewProp
38 {
39   guint16 ref_count;
40   guint16 nred_shades;
41   guint16 ngreen_shades;
42   guint16 nblue_shades;
43   guint16 ngray_shades;
44 };
45
46
47 static void   gtk_preview_class_init    (GtkPreviewClass  *klass);
48 static void   gtk_preview_init          (GtkPreview       *preview);
49 static void   gtk_preview_finalize      (GtkObject        *object);
50 static void   gtk_preview_realize       (GtkWidget        *widget);
51 static gint   gtk_preview_expose        (GtkWidget        *widget,
52                                          GdkEventExpose   *event);
53 static void   gtk_preview_make_buffer   (GtkPreview       *preview);
54 static void   gtk_preview_get_visuals   (GtkPreviewClass  *klass);
55 static void   gtk_preview_get_cmaps     (GtkPreviewClass  *klass);
56 static void   gtk_preview_dither_init   (GtkPreviewClass  *klass);
57 static void   gtk_fill_lookup_array     (gulong           *array,
58                                          int               depth,
59                                          int               shift,
60                                          int               prec);
61 static void   gtk_trim_cmap             (GtkPreviewClass  *klass);
62 static void   gtk_create_8_bit          (GtkPreviewClass  *klass);
63
64 static void   gtk_color_8               (guchar           *src,
65                                          guchar           *data,
66                                          gint              x,
67                                          gint              y,
68                                          gulong            width);
69 static void   gtk_color_16              (guchar           *src,
70                                          guchar           *data,
71                                          gulong            width);
72 static void   gtk_color_24              (guchar           *src,
73                                          guchar           *data,
74                                          gulong            width);
75 static void   gtk_grayscale_8           (guchar           *src,
76                                          guchar           *data,
77                                          gint              x,
78                                          gint              y,
79                                          gulong            width);
80 static void   gtk_grayscale_16          (guchar           *src,
81                                          guchar           *data,
82                                          gulong            width);
83 static void   gtk_grayscale_24          (guchar           *src,
84                                          guchar           *data,
85                                          gulong            width);
86
87 static gint   gtk_get_preview_prop      (guint            *nred,
88                                          guint            *nblue,
89                                          guint            *ngreen,
90                                          guint            *ngray);
91 static void   gtk_set_preview_prop      (guint             nred,
92                                          guint             ngreen,
93                                          guint             nblue,
94                                          guint             ngray);
95
96 /* transfer functions:
97  *  destination byte order/source bpp/destination bpp
98  */
99 static void   gtk_lsbmsb_1_1            (guchar           *dest,
100                                          guchar           *src,
101                                          gint              count);
102 static void   gtk_lsb_2_2               (guchar           *dest,
103                                          guchar           *src,
104                                          gint              count);
105 static void   gtk_msb_2_2               (guchar           *dest,
106                                          guchar           *src,
107                                          gint              count);
108 static void   gtk_lsb_3_3               (guchar           *dest,
109                                          guchar           *src,
110                                          gint              count);
111 static void   gtk_msb_3_3               (guchar           *dest,
112                                          guchar           *src,
113                                          gint              count);
114 static void   gtk_lsb_3_4               (guchar           *dest,
115                                          guchar           *src,
116                                          gint              count);
117 static void   gtk_msb_3_4               (guchar           *dest,
118                                          guchar           *src,
119                                          gint              count);
120
121
122 static GtkWidgetClass *parent_class = NULL;
123 static GtkPreviewClass *preview_class = NULL;
124 static GtkPreviewInfo *preview_info = NULL;
125 static gint install_cmap = FALSE;
126
127
128 guint
129 gtk_preview_get_type (void)
130 {
131   static guint preview_type = 0;
132
133   if (!preview_type)
134     {
135       GtkTypeInfo preview_info =
136       {
137         "GtkPreview",
138         sizeof (GtkPreview),
139         sizeof (GtkPreviewClass),
140         (GtkClassInitFunc) gtk_preview_class_init,
141         (GtkObjectInitFunc) gtk_preview_init,
142         /* reserved_1 */ NULL,
143         /* reserved_2 */ NULL,
144         (GtkClassInitFunc) NULL,
145       };
146
147       preview_type = gtk_type_unique (gtk_widget_get_type (), &preview_info);
148     }
149
150   return preview_type;
151 }
152
153 static void
154 gtk_preview_class_init (GtkPreviewClass *klass)
155 {
156   GtkObjectClass *object_class;
157   GtkWidgetClass *widget_class;
158
159   object_class = (GtkObjectClass*) klass;
160   widget_class = (GtkWidgetClass*) klass;
161
162   parent_class = gtk_type_class (gtk_widget_get_type ());
163   preview_class = klass;
164
165   object_class->finalize = gtk_preview_finalize;
166
167   widget_class->realize = gtk_preview_realize;
168   widget_class->expose_event = gtk_preview_expose;
169
170   if (preview_info)
171     klass->info = *preview_info;
172   else
173     {
174       klass->info.visual = NULL;
175       klass->info.cmap = NULL;
176
177       klass->info.color_pixels = NULL;
178       klass->info.gray_pixels = NULL;
179       klass->info.reserved_pixels = NULL;
180
181       klass->info.lookup_red = NULL;
182       klass->info.lookup_green = NULL;
183       klass->info.lookup_blue = NULL;
184
185       klass->info.dither_red = NULL;
186       klass->info.dither_green = NULL;
187       klass->info.dither_blue = NULL;
188       klass->info.dither_gray = NULL;
189       klass->info.dither_matrix = NULL;
190
191       klass->info.nred_shades = 6;
192       klass->info.ngreen_shades = 6;
193       klass->info.nblue_shades = 4;
194       klass->info.ngray_shades = 24;
195       klass->info.nreserved = 0;
196
197       klass->info.bpp = 0;
198       klass->info.cmap_alloced = FALSE;
199       klass->info.gamma = 1.0;
200     }
201
202   klass->image = NULL;
203
204   gtk_preview_get_visuals (klass);
205   gtk_preview_get_cmaps (klass);
206   gtk_preview_dither_init (klass);
207 }
208
209 void
210 gtk_preview_reset (void)
211 {
212   GtkPreviewInfo *info;
213
214   if (!preview_class || !preview_info)
215     return;
216   
217   info = &preview_class->info;
218
219   gtk_preview_uninit();
220
221   if (info->color_pixels)
222     {
223       gdk_colors_free (info->cmap,
224                        info->color_pixels,
225                        info->nred_shades *
226                          info->ngreen_shades *
227                          info->nblue_shades, 
228                        0);
229
230       gdk_colors_free (info->cmap,
231                        info->gray_pixels,
232                        info->ngray_shades, 0);
233       
234       g_free (info->color_pixels);
235       g_free (info->gray_pixels);
236     }
237
238   if (info->reserved_pixels)
239     {
240       gdk_colors_free (info->cmap,
241                        info->reserved_pixels,
242                        info->nreserved, 0);
243       g_free (info->reserved_pixels);
244     }
245
246   if (info->cmap && info->cmap_alloced)
247     gdk_colormap_unref (info->cmap);
248
249   if (info->lookup_red)
250     {
251       g_free (info->lookup_red);
252       g_free (info->lookup_green);
253       g_free (info->lookup_blue);
254     }
255
256   if (info->dither_matrix)
257     {
258       int i, j;
259
260       for (i= 0 ; i < 8 ; i++)
261         {
262           for (j = 0; j < 8 ; j++)
263             g_free (info->dither_matrix[i][j]);
264           g_free (info->dither_matrix[i]);
265         }
266       g_free (info->dither_matrix);
267       g_free (info->dither_red);
268       g_free (info->dither_green);
269       g_free (info->dither_blue);
270     }
271
272   preview_class->info = *preview_info;
273
274   gtk_preview_get_visuals (preview_class);
275   gtk_preview_get_cmaps (preview_class);
276   gtk_preview_dither_init (preview_class);
277 }
278
279 static void
280 gtk_preview_init (GtkPreview *preview)
281 {
282   GTK_WIDGET_SET_FLAGS (preview, GTK_BASIC);
283
284   preview->buffer = NULL;
285   preview->buffer_width = 0;
286   preview->buffer_height = 0;
287   preview->expand = FALSE;
288 }
289
290 void
291 gtk_preview_uninit (void)
292 {
293   GtkPreviewProp *prop;
294   GdkAtom property;
295
296   /* FIXME: need to grab the server here to prevent a race condition */
297
298   if (preview_class && !install_cmap && preview_class->info.visual &&
299       (preview_class->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
300       (preview_class->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
301     {
302       property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
303
304       if (gdk_property_get (NULL, property, property,
305                             0, sizeof (GtkPreviewProp), FALSE,
306                             NULL, NULL, NULL, (guchar**) &prop))
307         {
308           prop->ref_count = prop->ref_count - 1;
309           if (prop->ref_count == 0)
310             {
311               gdk_property_delete (NULL, property);
312             }
313           else
314             {
315               gdk_property_change (NULL, property, property, 16,
316                                    GDK_PROP_MODE_REPLACE,
317                                    (guchar*) prop, 5);
318             }
319         }
320     }
321 }
322
323 GtkWidget*
324 gtk_preview_new (GtkPreviewType type)
325 {
326   GtkPreview *preview;
327
328   preview = gtk_type_new (gtk_preview_get_type ());
329   preview->type = type;
330
331   return GTK_WIDGET (preview);
332 }
333
334 void
335 gtk_preview_size (GtkPreview *preview,
336                   gint        width,
337                   gint        height)
338 {
339   g_return_if_fail (preview != NULL);
340   g_return_if_fail (GTK_IS_PREVIEW (preview));
341
342   if ((width != GTK_WIDGET (preview)->requisition.width) ||
343       (height != GTK_WIDGET (preview)->requisition.height))
344     {
345       GTK_WIDGET (preview)->requisition.width = width;
346       GTK_WIDGET (preview)->requisition.height = height;
347
348       if (preview->buffer)
349         g_free (preview->buffer);
350       preview->buffer = NULL;
351     }
352 }
353
354 void
355 gtk_preview_put (GtkPreview   *preview,
356                  GdkWindow    *window,
357                  GdkGC        *gc,
358                  gint          srcx,
359                  gint          srcy,
360                  gint          destx,
361                  gint          desty,
362                  gint          width,
363                  gint          height)
364 {
365   GtkWidget *widget;
366   GdkImage *image;
367   GdkRectangle r1, r2, r3;
368   GtkTransferFunc transfer_func;
369   guchar *image_mem;
370   guchar *src, *dest;
371   gint x, xe, x2;
372   gint y, ye, y2;
373   guint dest_rowstride;
374   guint src_bpp;
375   guint dest_bpp;
376   gint i;
377
378   g_return_if_fail (preview != NULL);
379   g_return_if_fail (GTK_IS_PREVIEW (preview));
380   g_return_if_fail (window != NULL);
381
382   if (!preview->buffer)
383     return;
384
385   widget = GTK_WIDGET (preview);
386
387   r1.x = 0;
388   r1.y = 0;
389   r1.width = preview->buffer_width;
390   r1.height = preview->buffer_height;
391
392   r2.x = srcx;
393   r2.y = srcy;
394   r2.width = width;
395   r2.height = height;
396
397   if (!gdk_rectangle_intersect (&r1, &r2, &r3))
398     return;
399
400   x2 = r3.x + r3.width;
401   y2 = r3.y + r3.height;
402
403   if (!preview_class->image)
404     preview_class->image = gdk_image_new (GDK_IMAGE_FASTEST,
405                                           preview_class->info.visual,
406                                           IMAGE_SIZE, IMAGE_SIZE);
407   image = preview_class->image;
408   src_bpp = preview_class->info.bpp;
409
410   image_mem = image->mem;
411   dest_bpp = image->bpp;
412   dest_rowstride = image->bpl;
413
414   transfer_func = NULL;
415
416   switch (dest_bpp)
417     {
418     case 1:
419       switch (src_bpp)
420         {
421         case 1:
422           transfer_func = gtk_lsbmsb_1_1;
423           break;
424         }
425       break;
426     case 2:
427       switch (src_bpp)
428         {
429         case 2:
430           if (image->byte_order == GDK_MSB_FIRST)
431             transfer_func = gtk_msb_2_2;
432           else
433             transfer_func = gtk_lsb_2_2;
434           break;
435         case 3:
436           break;
437         }
438       break;
439     case 3:
440       switch (src_bpp)
441         {
442         case 3:
443           if (image->byte_order == GDK_MSB_FIRST)
444             transfer_func = gtk_msb_3_3;
445           else
446             transfer_func = gtk_lsb_3_3;
447           break;
448         }
449       break;
450     case 4:
451       switch (src_bpp)
452         {
453         case 3:
454           if (image->byte_order == GDK_MSB_FIRST)
455             transfer_func = gtk_msb_3_4;
456           else
457             transfer_func = gtk_lsb_3_4;
458           break;
459         }
460       break;
461     }
462
463   if (!transfer_func)
464     {
465       g_warning ("unsupported byte order/src bpp/dest bpp combination: %s:%d:%d",
466                  (image->byte_order == GDK_MSB_FIRST) ? "msb" : "lsb", src_bpp, dest_bpp);
467       return;
468     }
469
470   for (y = r3.y; y < y2; y += IMAGE_SIZE)
471     {
472       for (x = r3.x; x < x2; x += IMAGE_SIZE)
473         {
474           xe = x + IMAGE_SIZE;
475           if (xe > x2)
476             xe = x2;
477
478           ye = y + IMAGE_SIZE;
479           if (ye > y2)
480             ye = y2;
481
482           for (i = y; i < ye; i++)
483             {
484               src = preview->buffer + (((gulong) (i - r1.y) * (gulong) preview->buffer_width) +
485                                        (x - r1.x)) * (gulong) src_bpp;
486               dest = image_mem + ((gulong) (i - y) * dest_rowstride);
487
488               if (xe > x)
489                 (* transfer_func) (dest, src, xe - x);
490             }
491
492           gdk_draw_image (window, gc,
493                           image, 0, 0,
494                           destx + (r3.x - srcx) + (x - r3.x),
495                           desty + (r3.y - srcy) + (y - r3.y),
496                           xe - x, ye - y);
497           gdk_flush ();
498         }
499     }
500 }
501
502 void
503 gtk_preview_put_row (GtkPreview *preview,
504                      guchar     *src,
505                      guchar     *dest,
506                      gint        x,
507                      gint        y,
508                      gint        w)
509 {
510   g_return_if_fail (preview != NULL);
511   g_return_if_fail (GTK_IS_PREVIEW (preview));
512   g_return_if_fail (src != NULL);
513   g_return_if_fail (dest != NULL);
514
515   switch (preview->type)
516     {
517     case GTK_PREVIEW_COLOR:
518       switch (preview_class->info.visual->depth)
519         {
520         case 8:
521           gtk_color_8 (src, dest, x, y, w);
522           break;
523         case 15:
524         case 16:
525           gtk_color_16 (src, dest, w);
526           break;
527         case 24:
528         case 32:
529           gtk_color_24 (src, dest, w);
530           break;
531         }
532       break;
533     case GTK_PREVIEW_GRAYSCALE:
534       switch (preview_class->info.visual->depth)
535         {
536         case 8:
537           gtk_grayscale_8 (src, dest, x, y, w);
538           break;
539         case 15:
540         case 16:
541           gtk_grayscale_16 (src, dest, w);
542           break;
543         case 24:
544         case 32:
545           gtk_grayscale_24 (src, dest, w);
546           break;
547         }
548       break;
549     }
550 }
551
552 void
553 gtk_preview_draw_row (GtkPreview *preview,
554                       guchar     *data,
555                       gint        x,
556                       gint        y,
557                       gint        w)
558 {
559   guchar *dest;
560
561   g_return_if_fail (preview != NULL);
562   g_return_if_fail (GTK_IS_PREVIEW (preview));
563   g_return_if_fail (data != NULL);
564   g_return_if_fail (preview_class->info.visual != NULL);
565   
566   if ((w <= 0) || (y < 0))
567     return;
568
569   g_return_if_fail (data != NULL);
570
571   gtk_preview_make_buffer (preview);
572
573   if (y >= preview->buffer_height)
574     return;
575
576   switch (preview->type)
577     {
578     case GTK_PREVIEW_COLOR:
579       switch (preview_class->info.visual->depth)
580         {
581         case 8:
582           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
583           gtk_color_8 (data, dest, x, y, w);
584           break;
585         case 15:
586         case 16:
587           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
588           gtk_color_16 (data, dest, w);
589           break;
590         case 24:
591         case 32:
592           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
593           gtk_color_24 (data, dest, w);
594           break;
595         }
596       break;
597     case GTK_PREVIEW_GRAYSCALE:
598       switch (preview_class->info.visual->depth)
599         {
600         case 8:
601           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
602           gtk_grayscale_8 (data, dest, x, y, w);
603           break;
604         case 15:
605         case 16:
606           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
607           gtk_grayscale_16 (data, dest, w);
608           break;
609         case 24:
610         case 32:
611           dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
612           gtk_grayscale_24 (data, dest, w);
613           break;
614         }
615       break;
616     }
617 }
618
619 void
620 gtk_preview_set_expand (GtkPreview *preview,
621                         gint        expand)
622 {
623   g_return_if_fail (preview != NULL);
624   g_return_if_fail (GTK_IS_PREVIEW (preview));
625
626   preview->expand = (expand != FALSE);
627 }
628
629 void
630 gtk_preview_set_gamma (double _gamma)
631 {
632   if (!preview_info)
633     {
634       preview_info = g_new0 (GtkPreviewInfo, 1);
635       preview_info->nred_shades = 6;
636       preview_info->ngreen_shades = 6;
637       preview_info->nblue_shades = 4;
638       preview_info->ngray_shades = 24;
639     }
640
641   preview_info->gamma = _gamma;
642 }
643
644 void
645 gtk_preview_set_color_cube (guint nred_shades,
646                             guint ngreen_shades,
647                             guint nblue_shades,
648                             guint ngray_shades)
649 {
650   if (!preview_info)
651     {
652       preview_info = g_new0 (GtkPreviewInfo, 1);
653       preview_info->gamma = 1.0;
654     }
655
656   preview_info->nred_shades = nred_shades;
657   preview_info->ngreen_shades = ngreen_shades;
658   preview_info->nblue_shades = nblue_shades;
659   preview_info->ngray_shades = ngray_shades;
660 }
661
662 void
663 gtk_preview_set_install_cmap (gint _install_cmap)
664 {
665   install_cmap = _install_cmap;
666 }
667
668 void
669 gtk_preview_set_reserved (gint nreserved)
670 {
671   if (!preview_info)
672     preview_info = g_new0 (GtkPreviewInfo, 1);
673
674   preview_info->nreserved = nreserved;
675 }
676
677 GdkVisual*
678 gtk_preview_get_visual (void)
679 {
680   if (!preview_class)
681     preview_class = gtk_type_class (gtk_preview_get_type ());
682
683   return preview_class->info.visual;
684 }
685
686 GdkColormap*
687 gtk_preview_get_cmap (void)
688 {
689   if (!preview_class)
690     preview_class = gtk_type_class (gtk_preview_get_type ());
691
692   return preview_class->info.cmap;
693 }
694
695 GtkPreviewInfo*
696 gtk_preview_get_info (void)
697 {
698   if (!preview_class)
699     preview_class = gtk_type_class (gtk_preview_get_type ());
700
701   return &preview_class->info;
702 }
703
704
705 static void
706 gtk_preview_finalize (GtkObject *object)
707 {
708   GtkPreview *preview;
709
710   g_return_if_fail (object != NULL);
711   g_return_if_fail (GTK_IS_PREVIEW (object));
712
713   preview = GTK_PREVIEW (object);
714   if (preview->buffer)
715     g_free (preview->buffer);
716   preview->type = (GtkPreviewType) -1;
717
718   (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
719 }
720
721 static void
722 gtk_preview_realize (GtkWidget *widget)
723 {
724   GtkPreview *preview;
725   GdkWindowAttr attributes;
726   gint attributes_mask;
727
728   g_return_if_fail (widget != NULL);
729   g_return_if_fail (GTK_IS_PREVIEW (widget));
730
731   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
732   preview = GTK_PREVIEW (widget);
733
734   attributes.window_type = GDK_WINDOW_CHILD;
735   attributes.x = widget->allocation.x;
736   attributes.y = widget->allocation.y;
737   attributes.width = widget->allocation.width;
738   attributes.height = widget->allocation.height;
739   attributes.wclass = GDK_INPUT_OUTPUT;
740   attributes.visual = preview_class->info.visual;
741   attributes.colormap = preview_class->info.cmap;
742   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
743   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
744
745   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
746   gdk_window_set_user_data (widget->window, widget);
747
748   widget->style = gtk_style_attach (widget->style, widget->window);
749   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
750 }
751
752 static gint
753 gtk_preview_expose (GtkWidget      *widget,
754                     GdkEventExpose *event)
755 {
756   GtkPreview *preview;
757
758   g_return_val_if_fail (widget != NULL, FALSE);
759   g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE);
760   g_return_val_if_fail (event != NULL, FALSE);
761
762   if (GTK_WIDGET_DRAWABLE (widget))
763     {
764       preview = GTK_PREVIEW (widget);
765       
766       gtk_preview_put (GTK_PREVIEW (widget),
767                        widget->window, widget->style->black_gc,
768                        event->area.x -
769                        (widget->allocation.width - preview->buffer_width)/2,
770                        event->area.y -
771                        (widget->allocation.height - preview->buffer_height)/2,
772                        event->area.x, event->area.y,
773                        event->area.width, event->area.height);
774     }
775   
776   return FALSE;
777 }
778
779 static void
780 gtk_preview_make_buffer (GtkPreview *preview)
781 {
782   GtkWidget *widget;
783   gint width;
784   gint height;
785
786   g_return_if_fail (preview != NULL);
787   g_return_if_fail (GTK_IS_PREVIEW (preview));
788
789   widget = GTK_WIDGET (preview);
790
791   if (preview->expand &&
792       (widget->allocation.width != 0) &&
793       (widget->allocation.height != 0))
794     {
795       width = widget->allocation.width;
796       height = widget->allocation.height;
797     }
798   else
799     {
800       width = widget->requisition.width;
801       height = widget->requisition.height;
802     }
803
804   if (!preview->buffer ||
805       (preview->buffer_width != width) ||
806       (preview->buffer_height != height))
807     {
808       if (preview->buffer)
809         g_free (preview->buffer);
810
811       preview->buffer_width = width;
812       preview->buffer_height = height;
813
814       preview->buffer = g_new0 (guchar,
815                                 preview->buffer_width *
816                                 preview->buffer_height *
817                                 preview_class->info.bpp);
818     }
819 }
820
821 static void
822 gtk_preview_get_visuals (GtkPreviewClass *klass)
823 {
824   static GdkVisualType types[] =
825   {
826     GDK_VISUAL_TRUE_COLOR,
827     GDK_VISUAL_DIRECT_COLOR,
828     GDK_VISUAL_TRUE_COLOR,
829     GDK_VISUAL_DIRECT_COLOR,
830     GDK_VISUAL_TRUE_COLOR,
831     GDK_VISUAL_DIRECT_COLOR,
832     GDK_VISUAL_TRUE_COLOR,
833     GDK_VISUAL_DIRECT_COLOR,
834     GDK_VISUAL_PSEUDO_COLOR
835   };
836   static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8 };
837   static gint nvisual_types = sizeof (types) / sizeof (types[0]);
838
839   int i;
840
841   g_return_if_fail (klass != NULL);
842
843   if (!klass->info.visual)
844     for (i = 0; i < nvisual_types; i++)
845       if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i])))
846         {
847           if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) ||
848               (klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR))
849             {
850               klass->info.lookup_red = g_new (gulong, 256);
851               klass->info.lookup_green = g_new (gulong, 256);
852               klass->info.lookup_blue = g_new (gulong, 256);
853
854               gtk_fill_lookup_array (klass->info.lookup_red,
855                                      klass->info.visual->depth,
856                                      klass->info.visual->red_shift,
857                                      8 - klass->info.visual->red_prec);
858               gtk_fill_lookup_array (klass->info.lookup_green,
859                                      klass->info.visual->depth,
860                                      klass->info.visual->green_shift,
861                                      8 - klass->info.visual->green_prec);
862               gtk_fill_lookup_array (klass->info.lookup_blue,
863                                      klass->info.visual->depth,
864                                      klass->info.visual->blue_shift,
865                                      8 - klass->info.visual->blue_prec);
866             }
867           break;
868         }
869
870   if (!klass->info.visual)
871     {
872       g_warning ("unable to find a suitable visual for color image display.\n");
873       return;
874     }
875
876   /* If we are _not_ running with an installed cmap, we must run
877    * with the system visual. Otherwise, we let GDK pick the visual,
878    * and it makes some effort to pick a non-default visual, which
879    * will hopefully provide minimum color flashing.
880    */
881   if ((klass->info.visual->depth == gdk_visual_get_system()->depth) &&
882       (klass->info.visual->type == gdk_visual_get_system()->type) &&
883       !install_cmap)
884     {
885       klass->info.visual = gdk_visual_get_system();
886     }
887     
888   switch (klass->info.visual->depth)
889     {
890     case 8:
891       klass->info.bpp = 1;
892       break;
893     case 15:
894     case 16:
895       klass->info.bpp = 2;
896       break;
897     case 24:
898     case 32:
899       klass->info.bpp = 3;
900       break;
901     }
902 }
903
904 static void
905 gtk_preview_get_cmaps (GtkPreviewClass *klass)
906 {
907   g_return_if_fail (klass != NULL);
908   g_return_if_fail (klass->info.visual != NULL);
909
910   if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
911       (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
912     {
913       if (install_cmap)
914         {
915           klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
916           klass->info.cmap_alloced = install_cmap;
917
918           gtk_trim_cmap (klass);
919           gtk_create_8_bit (klass);
920         }
921       else
922         {
923           guint nred;
924           guint ngreen;
925           guint nblue;
926           guint ngray;
927           gint set_prop;
928
929           klass->info.cmap = gdk_colormap_get_system ();
930
931           set_prop = TRUE;
932           if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray))
933             {
934               set_prop = FALSE;
935
936               klass->info.nred_shades = nred;
937               klass->info.ngreen_shades = ngreen;
938               klass->info.nblue_shades = nblue;
939               klass->info.ngray_shades = ngray;
940
941               if (klass->info.nreserved)
942                 {
943                   klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved);
944                   if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0,
945                                          klass->info.reserved_pixels,
946                                          klass->info.nreserved))
947                     {
948                       g_free (klass->info.reserved_pixels);
949                       klass->info.reserved_pixels = NULL;
950                     }
951                 }
952             }
953           else
954             {
955               gtk_trim_cmap (klass);
956             }
957
958           gtk_create_8_bit (klass);
959
960           if (set_prop)
961             gtk_set_preview_prop (klass->info.nred_shades,
962                                   klass->info.ngreen_shades,
963                                   klass->info.nblue_shades,
964                                   klass->info.ngray_shades);
965         }
966     }
967   else
968     {
969       if (klass->info.visual == gdk_visual_get_system ())
970         klass->info.cmap = gdk_colormap_get_system ();
971       else
972         {
973           klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
974           klass->info.cmap_alloced = TRUE;
975         }
976
977       klass->info.nred_shades = 0;
978       klass->info.ngreen_shades = 0;
979       klass->info.nblue_shades = 0;
980       klass->info.ngray_shades = 0;
981     }
982 }
983
984 static void
985 gtk_preview_dither_init (GtkPreviewClass *klass)
986 {
987   int i, j, k;
988   unsigned char low_shade, high_shade;
989   unsigned short index;
990   long red_mult, green_mult;
991   double red_matrix_width;
992   double green_matrix_width;
993   double blue_matrix_width;
994   double gray_matrix_width;
995   double red_colors_per_shade;
996   double green_colors_per_shade;
997   double blue_colors_per_shade;
998   double gray_colors_per_shade;
999   gulong *gray_pixels;
1000   gint shades_r, shades_g, shades_b, shades_gray;
1001   GtkDitherInfo *red_ordered_dither;
1002   GtkDitherInfo *green_ordered_dither;
1003   GtkDitherInfo *blue_ordered_dither;
1004   GtkDitherInfo *gray_ordered_dither;
1005   guchar ***dither_matrix;
1006   guchar DM[8][8] =
1007   {
1008     { 0,  32, 8,  40, 2,  34, 10, 42 },
1009     { 48, 16, 56, 24, 50, 18, 58, 26 },
1010     { 12, 44, 4,  36, 14, 46, 6,  38 },
1011     { 60, 28, 52, 20, 62, 30, 54, 22 },
1012     { 3,  35, 11, 43, 1,  33, 9,  41 },
1013     { 51, 19, 59, 27, 49, 17, 57, 25 },
1014     { 15, 47, 7,  39, 13, 45, 5,  37 },
1015     { 63, 31, 55, 23, 61, 29, 53, 21 }
1016   };
1017
1018   if (!klass->info.visual || klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR)
1019     return;
1020
1021   shades_r = klass->info.nred_shades;
1022   shades_g = klass->info.ngreen_shades;
1023   shades_b = klass->info.nblue_shades;
1024   shades_gray = klass->info.ngray_shades;
1025
1026   red_mult = shades_g * shades_b;
1027   green_mult = shades_b;
1028
1029   red_colors_per_shade = 255.0 / (shades_r - 1);
1030   red_matrix_width = red_colors_per_shade / 64;
1031
1032   green_colors_per_shade = 255.0 / (shades_g - 1);
1033   green_matrix_width = green_colors_per_shade / 64;
1034
1035   blue_colors_per_shade = 255.0 / (shades_b - 1);
1036   blue_matrix_width = blue_colors_per_shade / 64;
1037
1038   gray_colors_per_shade = 255.0 / (shades_gray - 1);
1039   gray_matrix_width = gray_colors_per_shade / 64;
1040
1041   /*  alloc the ordered dither arrays for accelerated dithering  */
1042
1043   klass->info.dither_red = g_new (GtkDitherInfo, 256);
1044   klass->info.dither_green = g_new (GtkDitherInfo, 256);
1045   klass->info.dither_blue = g_new (GtkDitherInfo, 256);
1046   klass->info.dither_gray = g_new (GtkDitherInfo, 256);
1047
1048   red_ordered_dither = klass->info.dither_red;
1049   green_ordered_dither = klass->info.dither_green;
1050   blue_ordered_dither = klass->info.dither_blue;
1051   gray_ordered_dither = klass->info.dither_gray;
1052
1053   dither_matrix = g_new (guchar**, 8);
1054   for (i = 0; i < 8; i++)
1055     {
1056       dither_matrix[i] = g_new (guchar*, 8);
1057       for (j = 0; j < 8; j++)
1058         dither_matrix[i][j] = g_new (guchar, 65);
1059     }
1060
1061   klass->info.dither_matrix = dither_matrix;
1062
1063   /*  setup the ordered_dither_matrices  */
1064
1065   for (i = 0; i < 8; i++)
1066     for (j = 0; j < 8; j++)
1067       for (k = 0; k <= 64; k++)
1068         dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0;
1069
1070   /*  setup arrays containing three bytes of information for red, green, & blue  */
1071   /*  the arrays contain :
1072    *    1st byte:    low end shade value
1073    *    2nd byte:    high end shade value
1074    *    3rd & 4th bytes:    ordered dither matrix index
1075    */
1076
1077   gray_pixels = klass->info.gray_pixels;
1078
1079   for (i = 0; i < 256; i++)
1080     {
1081
1082       /*  setup the red information  */
1083       {
1084         low_shade = (unsigned char) (i / red_colors_per_shade);
1085         if (low_shade == (shades_r - 1))
1086           low_shade--;
1087         high_shade = low_shade + 1;
1088
1089         index = (unsigned short)
1090           (((double) i - low_shade * red_colors_per_shade) /
1091            red_matrix_width);
1092
1093         low_shade *= red_mult;
1094         high_shade *= red_mult;
1095
1096         red_ordered_dither[i].s[1] = index;
1097         red_ordered_dither[i].c[0] = low_shade;
1098         red_ordered_dither[i].c[1] = high_shade;
1099       }
1100
1101
1102       /*  setup the green information  */
1103       {
1104         low_shade = (unsigned char) (i / green_colors_per_shade);
1105         if (low_shade == (shades_g - 1))
1106           low_shade--;
1107         high_shade = low_shade + 1;
1108
1109         index = (unsigned short)
1110           (((double) i - low_shade * green_colors_per_shade) /
1111            green_matrix_width);
1112
1113         low_shade *= green_mult;
1114         high_shade *= green_mult;
1115
1116         green_ordered_dither[i].s[1] = index;
1117         green_ordered_dither[i].c[0] = low_shade;
1118         green_ordered_dither[i].c[1] = high_shade;
1119       }
1120
1121
1122       /*  setup the blue information  */
1123       {
1124         low_shade = (unsigned char) (i / blue_colors_per_shade);
1125         if (low_shade == (shades_b - 1))
1126           low_shade--;
1127         high_shade = low_shade + 1;
1128
1129         index = (unsigned short)
1130           (((double) i - low_shade * blue_colors_per_shade) /
1131            blue_matrix_width);
1132
1133         blue_ordered_dither[i].s[1] = index;
1134         blue_ordered_dither[i].c[0] = low_shade;
1135         blue_ordered_dither[i].c[1] = high_shade;
1136       }
1137
1138
1139       /*  setup the gray information */
1140       {
1141         low_shade = (unsigned char) (i / gray_colors_per_shade);
1142         if (low_shade == (shades_gray - 1))
1143           low_shade--;
1144         high_shade = low_shade + 1;
1145
1146         index = (unsigned short)
1147           (((double) i - low_shade * gray_colors_per_shade) /
1148            gray_matrix_width);
1149
1150         gray_ordered_dither[i].s[1] = index;
1151         gray_ordered_dither[i].c[0] = gray_pixels[low_shade];
1152         gray_ordered_dither[i].c[1] = gray_pixels[high_shade];
1153       }
1154     }
1155 }
1156
1157 static void
1158 gtk_fill_lookup_array (gulong *array,
1159                        int     depth,
1160                        int     shift,
1161                        int     prec)
1162 {
1163   double one_over_gamma;
1164   double ind;
1165   int val;
1166   int i;
1167
1168   if (preview_class->info.gamma != 0.0)
1169     one_over_gamma = 1.0 / preview_class->info.gamma;
1170   else
1171     one_over_gamma = 1.0;
1172
1173   for (i = 0; i < 256; i++)
1174     {
1175       if (one_over_gamma == 1.0)
1176         array[i] = ((i >> prec) << shift);
1177       else
1178         {
1179           ind = (double) i / 255.0;
1180           val = (int) (255 * pow (ind, one_over_gamma));
1181           array[i] = ((val >> prec) << shift);
1182         }
1183     }
1184 }
1185
1186 static void
1187 gtk_trim_cmap (GtkPreviewClass *klass)
1188 {
1189   gulong pixels[256];
1190   guint nred;
1191   guint ngreen;
1192   guint nblue;
1193   guint ngray;
1194   guint nreserved;
1195   guint total;
1196   guint tmp;
1197   gint success;
1198
1199   nred = klass->info.nred_shades;
1200   ngreen = klass->info.ngreen_shades;
1201   nblue = klass->info.nblue_shades;
1202   ngray = klass->info.ngray_shades;
1203   nreserved = klass->info.nreserved;
1204
1205   success = FALSE;
1206   while (!success)
1207     {
1208       total = nred * ngreen * nblue + ngray + nreserved;
1209
1210       if (total <= 256)
1211         {
1212           if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1213             success = TRUE;
1214           else
1215             {
1216               success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total);
1217               if (success)
1218                 {
1219                   if (nreserved > 0)
1220                     {
1221                       klass->info.reserved_pixels = g_new (gulong, nreserved);
1222                       memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved);
1223                       gdk_colors_free (klass->info.cmap, &pixels[nreserved],
1224                                        total - nreserved, 0);
1225                     }
1226                   else
1227                     {
1228                       gdk_colors_free (klass->info.cmap, pixels, total, 0);
1229                     }
1230                 }
1231             }
1232         }
1233
1234       if (!success)
1235         {
1236           if ((nblue >= nred) && (nblue >= ngreen))
1237             nblue = nblue - 1;
1238           else if ((nred >= ngreen) && (nred >= nblue))
1239             nred = nred - 1;
1240           else
1241             {
1242               tmp = log ((gdouble)ngray) / log (2.0);
1243
1244               if (ngreen >= tmp)
1245                 ngreen = ngreen - 1;
1246               else
1247                 ngray -= 1;
1248             }
1249         }
1250     }
1251
1252   if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1253     {
1254       g_print ("Unable to allocate sufficient colormap entries.\n");
1255       g_print ("Try exiting other color intensive applications.\n");
1256       return;
1257     }
1258
1259   /*  If any of the shade values has changed, issue a warning  */
1260   if ((nred != klass->info.nred_shades) ||
1261       (ngreen != klass->info.ngreen_shades) ||
1262       (nblue != klass->info.nblue_shades) ||
1263       (ngray != klass->info.ngray_shades))
1264     {
1265       g_print ("Not enough colors to satisfy requested color cube.\n");
1266       g_print ("Reduced color cube shades from\n");
1267       g_print ("[%d of Red, %d of Green, %d of Blue, %d of Gray] ==> [%d of Red, %d of Green, %d of Blue, %d of Gray]\n",
1268                klass->info.nred_shades, klass->info.ngreen_shades,
1269                klass->info.nblue_shades, klass->info.ngray_shades,
1270                nred, ngreen, nblue, ngray);
1271     }
1272
1273   klass->info.nred_shades = nred;
1274   klass->info.ngreen_shades = ngreen;
1275   klass->info.nblue_shades = nblue;
1276   klass->info.ngray_shades = ngray;
1277 }
1278
1279 static void
1280 gtk_create_8_bit (GtkPreviewClass *klass)
1281 {
1282   unsigned int r, g, b;
1283   unsigned int rv, gv, bv;
1284   unsigned int dr, dg, db, dgray;
1285   GdkColor color;
1286   gulong *pixels;
1287   double one_over_gamma;
1288   int i;
1289
1290   if (!klass->info.color_pixels)
1291     klass->info.color_pixels = g_new (gulong, 256);
1292
1293   if (!klass->info.gray_pixels)
1294     klass->info.gray_pixels = g_new (gulong, 256);
1295
1296   if (klass->info.gamma != 0.0)
1297     one_over_gamma = 1.0 / klass->info.gamma;
1298   else
1299     one_over_gamma = 1.0;
1300
1301   dr = klass->info.nred_shades - 1;
1302   dg = klass->info.ngreen_shades - 1;
1303   db = klass->info.nblue_shades - 1;
1304   dgray = klass->info.ngray_shades - 1;
1305
1306   pixels = klass->info.color_pixels;
1307
1308   for (r = 0, i = 0; r <= dr; r++)
1309     for (g = 0; g <= dg; g++)
1310       for (b = 0; b <= db; b++, i++)
1311         {
1312           rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr);
1313           gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg);
1314           bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db);
1315           color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257;
1316           color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257;
1317           color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257;
1318
1319           if (!gdk_color_alloc (klass->info.cmap, &color))
1320             {
1321               g_error ("could not initialize 8-bit combined colormap");
1322               return;
1323             }
1324
1325           pixels[i] = color.pixel;
1326         }
1327
1328
1329   pixels = klass->info.gray_pixels;
1330
1331   for (i = 0; i < (int) klass->info.ngray_shades; i++)
1332     {
1333       color.red = (i * klass->info.visual->colormap_size) / dgray;
1334       color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257;
1335       color.green = color.red;
1336       color.blue = color.red;
1337
1338       if (!gdk_color_alloc (klass->info.cmap, &color))
1339         {
1340           g_error ("could not initialize 8-bit combined colormap");
1341           return;
1342         }
1343
1344       pixels[i] = color.pixel;
1345     }
1346 }
1347
1348
1349 static void
1350 gtk_color_8 (guchar *src,
1351              guchar *dest,
1352              gint    x,
1353              gint    y,
1354              gulong  width)
1355 {
1356   gulong *colors;
1357   GtkDitherInfo *dither_red;
1358   GtkDitherInfo *dither_green;
1359   GtkDitherInfo *dither_blue;
1360   GtkDitherInfo r, g, b;
1361   guchar **dither_matrix;
1362   guchar *matrix;
1363
1364   colors = preview_class->info.color_pixels;
1365   dither_red = preview_class->info.dither_red;
1366   dither_green = preview_class->info.dither_green;
1367   dither_blue = preview_class->info.dither_blue;
1368   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1369
1370   while (width--)
1371     {
1372       r = dither_red[src[0]];
1373       g = dither_green[src[1]];
1374       b = dither_blue[src[2]];
1375       src += 3;
1376
1377       matrix = dither_matrix[x++ & 0x7];
1378       *dest++ = colors[(r.c[matrix[r.s[1]]] +
1379                         g.c[matrix[g.s[1]]] +
1380                         b.c[matrix[b.s[1]]])];
1381     }
1382 }
1383
1384 static void
1385 gtk_color_16 (guchar *src,
1386               guchar *dest,
1387               gulong  width)
1388 {
1389   gulong *lookup_red;
1390   gulong *lookup_green;
1391   gulong *lookup_blue;
1392   gulong val;
1393
1394   lookup_red = preview_class->info.lookup_red;
1395   lookup_green = preview_class->info.lookup_green;
1396   lookup_blue = preview_class->info.lookup_blue;
1397
1398   while (width--)
1399     {
1400       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1401       dest[0] = val;
1402       dest[1] = val >> 8;
1403       dest += 2;
1404       src += 3;
1405     }
1406 }
1407
1408 static void
1409 gtk_color_24 (guchar *src,
1410               guchar *dest,
1411               gulong  width)
1412 {
1413   gulong *lookup_red;
1414   gulong *lookup_green;
1415   gulong *lookup_blue;
1416   gulong val;
1417
1418   lookup_red = preview_class->info.lookup_red;
1419   lookup_green = preview_class->info.lookup_green;
1420   lookup_blue = preview_class->info.lookup_blue;
1421
1422   while (width--)
1423     {
1424       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1425       dest[0] = val;
1426       dest[1] = val >> 8;
1427       dest[2] = val >> 16;
1428       dest += 3;
1429       src += 3;
1430     }
1431 }
1432
1433 static void
1434 gtk_grayscale_8 (guchar *src,
1435                  guchar *dest,
1436                  gint    x,
1437                  gint    y,
1438                  gulong  width)
1439 {
1440   GtkDitherInfo *dither_gray;
1441   GtkDitherInfo gray;
1442   guchar **dither_matrix;
1443   guchar *matrix;
1444
1445   dither_gray = preview_class->info.dither_gray;
1446   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1447
1448   while (width--)
1449     {
1450       gray = dither_gray[*src++];
1451       matrix = dither_matrix[x++ & 0x7];
1452       *dest++ = gray.c[matrix[gray.s[1]]];
1453     }
1454 }
1455
1456 static void
1457 gtk_grayscale_16 (guchar *src,
1458                   guchar *dest,
1459                   gulong  width)
1460 {
1461   gulong *lookup_red;
1462   gulong *lookup_green;
1463   gulong *lookup_blue;
1464   gulong val;
1465
1466   lookup_red = preview_class->info.lookup_red;
1467   lookup_green = preview_class->info.lookup_green;
1468   lookup_blue = preview_class->info.lookup_blue;
1469
1470   while (width--)
1471     {
1472       val = COLOR_COMPOSE (*src, *src, *src);
1473       dest[0] = val;
1474       dest[1] = val >> 8;
1475       dest += 2;
1476       src += 1;
1477     }
1478 }
1479
1480 static void
1481 gtk_grayscale_24 (guchar  *src,
1482                   guchar  *dest,
1483                   gulong   width)
1484 {
1485   gulong *lookup_red;
1486   gulong *lookup_green;
1487   gulong *lookup_blue;
1488   gulong val;
1489
1490   lookup_red = preview_class->info.lookup_red;
1491   lookup_green = preview_class->info.lookup_green;
1492   lookup_blue = preview_class->info.lookup_blue;
1493
1494   while (width--)
1495     {
1496       val = COLOR_COMPOSE (*src, *src, *src);
1497       dest[0] = val;
1498       dest[1] = val >> 8;
1499       dest[2] = val >> 16;
1500       dest += 3;
1501       src += 1;
1502     }
1503 }
1504
1505
1506 static gint
1507 gtk_get_preview_prop (guint *nred,
1508                       guint *ngreen,
1509                       guint *nblue,
1510                       guint *ngray)
1511 {
1512   GtkPreviewProp *prop;
1513   GdkAtom property;
1514
1515   /* FIXME: need to grab the server here to prevent a race condition */
1516
1517   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1518
1519   if (gdk_property_get (NULL, property, property,
1520                         0, sizeof (GtkPreviewProp), FALSE,
1521                         NULL, NULL, NULL, (guchar**) &prop))
1522     {
1523       *nred = prop->nred_shades;
1524       *ngreen = prop->ngreen_shades;
1525       *nblue = prop->nblue_shades;
1526       *ngray = prop->ngray_shades;
1527
1528       prop->ref_count = prop->ref_count + 1;
1529       gdk_property_change (NULL, property, property, 16,
1530                            GDK_PROP_MODE_REPLACE,
1531                            (guchar*) prop, 5);
1532
1533       return TRUE;
1534     }
1535
1536   return FALSE;
1537 }
1538
1539 static void
1540 gtk_set_preview_prop (guint nred,
1541                       guint ngreen,
1542                       guint nblue,
1543                       guint ngray)
1544 {
1545   GtkPreviewProp prop;
1546   GdkAtom property;
1547
1548   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1549
1550   prop.ref_count = 1;
1551   prop.nred_shades = nred;
1552   prop.ngreen_shades = ngreen;
1553   prop.nblue_shades = nblue;
1554   prop.ngray_shades = ngray;
1555
1556   gdk_property_change (NULL, property, property, 16,
1557                        GDK_PROP_MODE_REPLACE,
1558                        (guchar*) &prop, 5);
1559 }
1560
1561
1562 static void
1563 gtk_lsbmsb_1_1 (guchar *dest,
1564                 guchar *src,
1565                 gint    count)
1566 {
1567   memcpy (dest, src, count);
1568 }
1569
1570 static void
1571 gtk_lsb_2_2 (guchar *dest,
1572              guchar *src,
1573              gint    count)
1574 {
1575   memcpy (dest, src, count * 2);
1576 }
1577
1578 static void
1579 gtk_msb_2_2 (guchar *dest,
1580              guchar *src,
1581              gint    count)
1582 {
1583   while (count--)
1584     {
1585       dest[0] = src[1];
1586       dest[1] = src[0];
1587       dest += 2;
1588       src += 2;
1589     }
1590 }
1591
1592 static void
1593 gtk_lsb_3_3 (guchar *dest,
1594              guchar *src,
1595              gint    count)
1596 {
1597   memcpy (dest, src, count * 3);
1598 }
1599
1600 static void
1601 gtk_msb_3_3 (guchar *dest,
1602              guchar *src,
1603              gint    count)
1604 {
1605   while (count--)
1606     {
1607       dest[0] = src[2];
1608       dest[1] = src[1];
1609       dest[2] = src[0];
1610       dest += 3;
1611       src += 3;
1612     }
1613 }
1614
1615 static void
1616 gtk_lsb_3_4 (guchar *dest,
1617              guchar *src,
1618              gint    count)
1619 {
1620   while (count--)
1621     {
1622       dest[0] = src[0];
1623       dest[1] = src[1];
1624       dest[2] = src[2];
1625       dest += 4;
1626       src += 3;
1627     }
1628 }
1629
1630 static void
1631 gtk_msb_3_4 (guchar *dest,
1632              guchar *src,
1633              gint    count)
1634 {
1635   while (count--)
1636     {
1637       dest[1] = src[2];
1638       dest[2] = src[1];
1639       dest[3] = src[0];
1640       dest += 4;
1641       src += 3;
1642     }
1643 }