]> Pileus Git - ~andy/gtk/blob - gtk/gtkpreview.c
add in just enough support for 1 or 4 bits so that it seems to allow
[~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     GDK_VISUAL_STATIC_COLOR,
836     GDK_VISUAL_STATIC_GRAY
837   };
838   static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8, 4, 1 };
839   static gint nvisual_types = sizeof (types) / sizeof (types[0]);
840
841   int i;
842
843   g_return_if_fail (klass != NULL);
844
845   if (!klass->info.visual)
846     for (i = 0; i < nvisual_types; i++)
847       if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i])))
848         {
849           if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) ||
850               (klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR))
851             {
852               klass->info.lookup_red = g_new (gulong, 256);
853               klass->info.lookup_green = g_new (gulong, 256);
854               klass->info.lookup_blue = g_new (gulong, 256);
855
856               gtk_fill_lookup_array (klass->info.lookup_red,
857                                      klass->info.visual->depth,
858                                      klass->info.visual->red_shift,
859                                      8 - klass->info.visual->red_prec);
860               gtk_fill_lookup_array (klass->info.lookup_green,
861                                      klass->info.visual->depth,
862                                      klass->info.visual->green_shift,
863                                      8 - klass->info.visual->green_prec);
864               gtk_fill_lookup_array (klass->info.lookup_blue,
865                                      klass->info.visual->depth,
866                                      klass->info.visual->blue_shift,
867                                      8 - klass->info.visual->blue_prec);
868             }
869           break;
870         }
871
872   if (!klass->info.visual)
873     {
874       g_warning ("unable to find a suitable visual for color image display.\n");
875       return;
876     }
877
878   /* If we are _not_ running with an installed cmap, we must run
879    * with the system visual. Otherwise, we let GDK pick the visual,
880    * and it makes some effort to pick a non-default visual, which
881    * will hopefully provide minimum color flashing.
882    */
883   if ((klass->info.visual->depth == gdk_visual_get_system()->depth) &&
884       (klass->info.visual->type == gdk_visual_get_system()->type) &&
885       !install_cmap)
886     {
887       klass->info.visual = gdk_visual_get_system();
888     }
889     
890   switch (klass->info.visual->depth)
891     {
892     case 1:
893     case 4:
894     case 8:
895       klass->info.bpp = 1;
896       break;
897     case 15:
898     case 16:
899       klass->info.bpp = 2;
900       break;
901     case 24:
902     case 32:
903       klass->info.bpp = 3;
904       break;
905     }
906 }
907
908 static void
909 gtk_preview_get_cmaps (GtkPreviewClass *klass)
910 {
911   g_return_if_fail (klass != NULL);
912   g_return_if_fail (klass->info.visual != NULL);
913
914   if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
915       (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
916     {
917       if (install_cmap)
918         {
919           klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
920           klass->info.cmap_alloced = install_cmap;
921
922           gtk_trim_cmap (klass);
923           gtk_create_8_bit (klass);
924         }
925       else
926         {
927           guint nred;
928           guint ngreen;
929           guint nblue;
930           guint ngray;
931           gint set_prop;
932
933           klass->info.cmap = gdk_colormap_get_system ();
934
935           set_prop = TRUE;
936           if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray))
937             {
938               set_prop = FALSE;
939
940               klass->info.nred_shades = nred;
941               klass->info.ngreen_shades = ngreen;
942               klass->info.nblue_shades = nblue;
943               klass->info.ngray_shades = ngray;
944
945               if (klass->info.nreserved)
946                 {
947                   klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved);
948                   if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0,
949                                          klass->info.reserved_pixels,
950                                          klass->info.nreserved))
951                     {
952                       g_free (klass->info.reserved_pixels);
953                       klass->info.reserved_pixels = NULL;
954                     }
955                 }
956             }
957           else
958             {
959               gtk_trim_cmap (klass);
960             }
961
962           gtk_create_8_bit (klass);
963
964           if (set_prop)
965             gtk_set_preview_prop (klass->info.nred_shades,
966                                   klass->info.ngreen_shades,
967                                   klass->info.nblue_shades,
968                                   klass->info.ngray_shades);
969         }
970     }
971   else
972     {
973       if (klass->info.visual == gdk_visual_get_system ())
974         klass->info.cmap = gdk_colormap_get_system ();
975       else
976         {
977           klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
978           klass->info.cmap_alloced = TRUE;
979         }
980
981       klass->info.nred_shades = 0;
982       klass->info.ngreen_shades = 0;
983       klass->info.nblue_shades = 0;
984       klass->info.ngray_shades = 0;
985     }
986 }
987
988 static void
989 gtk_preview_dither_init (GtkPreviewClass *klass)
990 {
991   int i, j, k;
992   unsigned char low_shade, high_shade;
993   unsigned short index;
994   long red_mult, green_mult;
995   double red_matrix_width;
996   double green_matrix_width;
997   double blue_matrix_width;
998   double gray_matrix_width;
999   double red_colors_per_shade;
1000   double green_colors_per_shade;
1001   double blue_colors_per_shade;
1002   double gray_colors_per_shade;
1003   gulong *gray_pixels;
1004   gint shades_r, shades_g, shades_b, shades_gray;
1005   GtkDitherInfo *red_ordered_dither;
1006   GtkDitherInfo *green_ordered_dither;
1007   GtkDitherInfo *blue_ordered_dither;
1008   GtkDitherInfo *gray_ordered_dither;
1009   guchar ***dither_matrix;
1010   guchar DM[8][8] =
1011   {
1012     { 0,  32, 8,  40, 2,  34, 10, 42 },
1013     { 48, 16, 56, 24, 50, 18, 58, 26 },
1014     { 12, 44, 4,  36, 14, 46, 6,  38 },
1015     { 60, 28, 52, 20, 62, 30, 54, 22 },
1016     { 3,  35, 11, 43, 1,  33, 9,  41 },
1017     { 51, 19, 59, 27, 49, 17, 57, 25 },
1018     { 15, 47, 7,  39, 13, 45, 5,  37 },
1019     { 63, 31, 55, 23, 61, 29, 53, 21 }
1020   };
1021
1022   if (!klass->info.visual || klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR)
1023     return;
1024
1025   shades_r = klass->info.nred_shades;
1026   shades_g = klass->info.ngreen_shades;
1027   shades_b = klass->info.nblue_shades;
1028   shades_gray = klass->info.ngray_shades;
1029
1030   red_mult = shades_g * shades_b;
1031   green_mult = shades_b;
1032
1033   red_colors_per_shade = 255.0 / (shades_r - 1);
1034   red_matrix_width = red_colors_per_shade / 64;
1035
1036   green_colors_per_shade = 255.0 / (shades_g - 1);
1037   green_matrix_width = green_colors_per_shade / 64;
1038
1039   blue_colors_per_shade = 255.0 / (shades_b - 1);
1040   blue_matrix_width = blue_colors_per_shade / 64;
1041
1042   gray_colors_per_shade = 255.0 / (shades_gray - 1);
1043   gray_matrix_width = gray_colors_per_shade / 64;
1044
1045   /*  alloc the ordered dither arrays for accelerated dithering  */
1046
1047   klass->info.dither_red = g_new (GtkDitherInfo, 256);
1048   klass->info.dither_green = g_new (GtkDitherInfo, 256);
1049   klass->info.dither_blue = g_new (GtkDitherInfo, 256);
1050   klass->info.dither_gray = g_new (GtkDitherInfo, 256);
1051
1052   red_ordered_dither = klass->info.dither_red;
1053   green_ordered_dither = klass->info.dither_green;
1054   blue_ordered_dither = klass->info.dither_blue;
1055   gray_ordered_dither = klass->info.dither_gray;
1056
1057   dither_matrix = g_new (guchar**, 8);
1058   for (i = 0; i < 8; i++)
1059     {
1060       dither_matrix[i] = g_new (guchar*, 8);
1061       for (j = 0; j < 8; j++)
1062         dither_matrix[i][j] = g_new (guchar, 65);
1063     }
1064
1065   klass->info.dither_matrix = dither_matrix;
1066
1067   /*  setup the ordered_dither_matrices  */
1068
1069   for (i = 0; i < 8; i++)
1070     for (j = 0; j < 8; j++)
1071       for (k = 0; k <= 64; k++)
1072         dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0;
1073
1074   /*  setup arrays containing three bytes of information for red, green, & blue  */
1075   /*  the arrays contain :
1076    *    1st byte:    low end shade value
1077    *    2nd byte:    high end shade value
1078    *    3rd & 4th bytes:    ordered dither matrix index
1079    */
1080
1081   gray_pixels = klass->info.gray_pixels;
1082
1083   for (i = 0; i < 256; i++)
1084     {
1085
1086       /*  setup the red information  */
1087       {
1088         low_shade = (unsigned char) (i / red_colors_per_shade);
1089         if (low_shade == (shades_r - 1))
1090           low_shade--;
1091         high_shade = low_shade + 1;
1092
1093         index = (unsigned short)
1094           (((double) i - low_shade * red_colors_per_shade) /
1095            red_matrix_width);
1096
1097         low_shade *= red_mult;
1098         high_shade *= red_mult;
1099
1100         red_ordered_dither[i].s[1] = index;
1101         red_ordered_dither[i].c[0] = low_shade;
1102         red_ordered_dither[i].c[1] = high_shade;
1103       }
1104
1105
1106       /*  setup the green information  */
1107       {
1108         low_shade = (unsigned char) (i / green_colors_per_shade);
1109         if (low_shade == (shades_g - 1))
1110           low_shade--;
1111         high_shade = low_shade + 1;
1112
1113         index = (unsigned short)
1114           (((double) i - low_shade * green_colors_per_shade) /
1115            green_matrix_width);
1116
1117         low_shade *= green_mult;
1118         high_shade *= green_mult;
1119
1120         green_ordered_dither[i].s[1] = index;
1121         green_ordered_dither[i].c[0] = low_shade;
1122         green_ordered_dither[i].c[1] = high_shade;
1123       }
1124
1125
1126       /*  setup the blue information  */
1127       {
1128         low_shade = (unsigned char) (i / blue_colors_per_shade);
1129         if (low_shade == (shades_b - 1))
1130           low_shade--;
1131         high_shade = low_shade + 1;
1132
1133         index = (unsigned short)
1134           (((double) i - low_shade * blue_colors_per_shade) /
1135            blue_matrix_width);
1136
1137         blue_ordered_dither[i].s[1] = index;
1138         blue_ordered_dither[i].c[0] = low_shade;
1139         blue_ordered_dither[i].c[1] = high_shade;
1140       }
1141
1142
1143       /*  setup the gray information */
1144       {
1145         low_shade = (unsigned char) (i / gray_colors_per_shade);
1146         if (low_shade == (shades_gray - 1))
1147           low_shade--;
1148         high_shade = low_shade + 1;
1149
1150         index = (unsigned short)
1151           (((double) i - low_shade * gray_colors_per_shade) /
1152            gray_matrix_width);
1153
1154         gray_ordered_dither[i].s[1] = index;
1155         gray_ordered_dither[i].c[0] = gray_pixels[low_shade];
1156         gray_ordered_dither[i].c[1] = gray_pixels[high_shade];
1157       }
1158     }
1159 }
1160
1161 static void
1162 gtk_fill_lookup_array (gulong *array,
1163                        int     depth,
1164                        int     shift,
1165                        int     prec)
1166 {
1167   double one_over_gamma;
1168   double ind;
1169   int val;
1170   int i;
1171
1172   if (preview_class->info.gamma != 0.0)
1173     one_over_gamma = 1.0 / preview_class->info.gamma;
1174   else
1175     one_over_gamma = 1.0;
1176
1177   for (i = 0; i < 256; i++)
1178     {
1179       if (one_over_gamma == 1.0)
1180         array[i] = ((i >> prec) << shift);
1181       else
1182         {
1183           ind = (double) i / 255.0;
1184           val = (int) (255 * pow (ind, one_over_gamma));
1185           array[i] = ((val >> prec) << shift);
1186         }
1187     }
1188 }
1189
1190 static void
1191 gtk_trim_cmap (GtkPreviewClass *klass)
1192 {
1193   gulong pixels[256];
1194   guint nred;
1195   guint ngreen;
1196   guint nblue;
1197   guint ngray;
1198   guint nreserved;
1199   guint total;
1200   guint tmp;
1201   gint success;
1202
1203   nred = klass->info.nred_shades;
1204   ngreen = klass->info.ngreen_shades;
1205   nblue = klass->info.nblue_shades;
1206   ngray = klass->info.ngray_shades;
1207   nreserved = klass->info.nreserved;
1208
1209   success = FALSE;
1210   while (!success)
1211     {
1212       total = nred * ngreen * nblue + ngray + nreserved;
1213
1214       if (total <= 256)
1215         {
1216           if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1217             success = TRUE;
1218           else
1219             {
1220               success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total);
1221               if (success)
1222                 {
1223                   if (nreserved > 0)
1224                     {
1225                       klass->info.reserved_pixels = g_new (gulong, nreserved);
1226                       memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved);
1227                       gdk_colors_free (klass->info.cmap, &pixels[nreserved],
1228                                        total - nreserved, 0);
1229                     }
1230                   else
1231                     {
1232                       gdk_colors_free (klass->info.cmap, pixels, total, 0);
1233                     }
1234                 }
1235             }
1236         }
1237
1238       if (!success)
1239         {
1240           if ((nblue >= nred) && (nblue >= ngreen))
1241             nblue = nblue - 1;
1242           else if ((nred >= ngreen) && (nred >= nblue))
1243             nred = nred - 1;
1244           else
1245             {
1246               tmp = log ((gdouble)ngray) / log (2.0);
1247
1248               if (ngreen >= tmp)
1249                 ngreen = ngreen - 1;
1250               else
1251                 ngray -= 1;
1252             }
1253         }
1254     }
1255
1256   if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1257     {
1258       g_print ("Unable to allocate sufficient colormap entries.\n");
1259       g_print ("Try exiting other color intensive applications.\n");
1260       return;
1261     }
1262
1263   /*  If any of the shade values has changed, issue a warning  */
1264   if ((nred != klass->info.nred_shades) ||
1265       (ngreen != klass->info.ngreen_shades) ||
1266       (nblue != klass->info.nblue_shades) ||
1267       (ngray != klass->info.ngray_shades))
1268     {
1269       g_print ("Not enough colors to satisfy requested color cube.\n");
1270       g_print ("Reduced color cube shades from\n");
1271       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",
1272                klass->info.nred_shades, klass->info.ngreen_shades,
1273                klass->info.nblue_shades, klass->info.ngray_shades,
1274                nred, ngreen, nblue, ngray);
1275     }
1276
1277   klass->info.nred_shades = nred;
1278   klass->info.ngreen_shades = ngreen;
1279   klass->info.nblue_shades = nblue;
1280   klass->info.ngray_shades = ngray;
1281 }
1282
1283 static void
1284 gtk_create_8_bit (GtkPreviewClass *klass)
1285 {
1286   unsigned int r, g, b;
1287   unsigned int rv, gv, bv;
1288   unsigned int dr, dg, db, dgray;
1289   GdkColor color;
1290   gulong *pixels;
1291   double one_over_gamma;
1292   int i;
1293
1294   if (!klass->info.color_pixels)
1295     klass->info.color_pixels = g_new (gulong, 256);
1296
1297   if (!klass->info.gray_pixels)
1298     klass->info.gray_pixels = g_new (gulong, 256);
1299
1300   if (klass->info.gamma != 0.0)
1301     one_over_gamma = 1.0 / klass->info.gamma;
1302   else
1303     one_over_gamma = 1.0;
1304
1305   dr = klass->info.nred_shades - 1;
1306   dg = klass->info.ngreen_shades - 1;
1307   db = klass->info.nblue_shades - 1;
1308   dgray = klass->info.ngray_shades - 1;
1309
1310   pixels = klass->info.color_pixels;
1311
1312   for (r = 0, i = 0; r <= dr; r++)
1313     for (g = 0; g <= dg; g++)
1314       for (b = 0; b <= db; b++, i++)
1315         {
1316           rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr);
1317           gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg);
1318           bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db);
1319           color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257;
1320           color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257;
1321           color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257;
1322
1323           if (!gdk_color_alloc (klass->info.cmap, &color))
1324             {
1325               g_error ("could not initialize 8-bit combined colormap");
1326               return;
1327             }
1328
1329           pixels[i] = color.pixel;
1330         }
1331
1332
1333   pixels = klass->info.gray_pixels;
1334
1335   for (i = 0; i < (int) klass->info.ngray_shades; i++)
1336     {
1337       color.red = (i * klass->info.visual->colormap_size) / dgray;
1338       color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257;
1339       color.green = color.red;
1340       color.blue = color.red;
1341
1342       if (!gdk_color_alloc (klass->info.cmap, &color))
1343         {
1344           g_error ("could not initialize 8-bit combined colormap");
1345           return;
1346         }
1347
1348       pixels[i] = color.pixel;
1349     }
1350 }
1351
1352
1353 static void
1354 gtk_color_8 (guchar *src,
1355              guchar *dest,
1356              gint    x,
1357              gint    y,
1358              gulong  width)
1359 {
1360   gulong *colors;
1361   GtkDitherInfo *dither_red;
1362   GtkDitherInfo *dither_green;
1363   GtkDitherInfo *dither_blue;
1364   GtkDitherInfo r, g, b;
1365   guchar **dither_matrix;
1366   guchar *matrix;
1367
1368   colors = preview_class->info.color_pixels;
1369   dither_red = preview_class->info.dither_red;
1370   dither_green = preview_class->info.dither_green;
1371   dither_blue = preview_class->info.dither_blue;
1372   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1373
1374   while (width--)
1375     {
1376       r = dither_red[src[0]];
1377       g = dither_green[src[1]];
1378       b = dither_blue[src[2]];
1379       src += 3;
1380
1381       matrix = dither_matrix[x++ & 0x7];
1382       *dest++ = colors[(r.c[matrix[r.s[1]]] +
1383                         g.c[matrix[g.s[1]]] +
1384                         b.c[matrix[b.s[1]]])];
1385     }
1386 }
1387
1388 static void
1389 gtk_color_16 (guchar *src,
1390               guchar *dest,
1391               gulong  width)
1392 {
1393   gulong *lookup_red;
1394   gulong *lookup_green;
1395   gulong *lookup_blue;
1396   gulong val;
1397
1398   lookup_red = preview_class->info.lookup_red;
1399   lookup_green = preview_class->info.lookup_green;
1400   lookup_blue = preview_class->info.lookup_blue;
1401
1402   while (width--)
1403     {
1404       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1405       dest[0] = val;
1406       dest[1] = val >> 8;
1407       dest += 2;
1408       src += 3;
1409     }
1410 }
1411
1412 static void
1413 gtk_color_24 (guchar *src,
1414               guchar *dest,
1415               gulong  width)
1416 {
1417   gulong *lookup_red;
1418   gulong *lookup_green;
1419   gulong *lookup_blue;
1420   gulong val;
1421
1422   lookup_red = preview_class->info.lookup_red;
1423   lookup_green = preview_class->info.lookup_green;
1424   lookup_blue = preview_class->info.lookup_blue;
1425
1426   while (width--)
1427     {
1428       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1429       dest[0] = val;
1430       dest[1] = val >> 8;
1431       dest[2] = val >> 16;
1432       dest += 3;
1433       src += 3;
1434     }
1435 }
1436
1437 static void
1438 gtk_grayscale_8 (guchar *src,
1439                  guchar *dest,
1440                  gint    x,
1441                  gint    y,
1442                  gulong  width)
1443 {
1444   GtkDitherInfo *dither_gray;
1445   GtkDitherInfo gray;
1446   guchar **dither_matrix;
1447   guchar *matrix;
1448
1449   dither_gray = preview_class->info.dither_gray;
1450   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1451
1452   while (width--)
1453     {
1454       gray = dither_gray[*src++];
1455       matrix = dither_matrix[x++ & 0x7];
1456       *dest++ = gray.c[matrix[gray.s[1]]];
1457     }
1458 }
1459
1460 static void
1461 gtk_grayscale_16 (guchar *src,
1462                   guchar *dest,
1463                   gulong  width)
1464 {
1465   gulong *lookup_red;
1466   gulong *lookup_green;
1467   gulong *lookup_blue;
1468   gulong val;
1469
1470   lookup_red = preview_class->info.lookup_red;
1471   lookup_green = preview_class->info.lookup_green;
1472   lookup_blue = preview_class->info.lookup_blue;
1473
1474   while (width--)
1475     {
1476       val = COLOR_COMPOSE (*src, *src, *src);
1477       dest[0] = val;
1478       dest[1] = val >> 8;
1479       dest += 2;
1480       src += 1;
1481     }
1482 }
1483
1484 static void
1485 gtk_grayscale_24 (guchar  *src,
1486                   guchar  *dest,
1487                   gulong   width)
1488 {
1489   gulong *lookup_red;
1490   gulong *lookup_green;
1491   gulong *lookup_blue;
1492   gulong val;
1493
1494   lookup_red = preview_class->info.lookup_red;
1495   lookup_green = preview_class->info.lookup_green;
1496   lookup_blue = preview_class->info.lookup_blue;
1497
1498   while (width--)
1499     {
1500       val = COLOR_COMPOSE (*src, *src, *src);
1501       dest[0] = val;
1502       dest[1] = val >> 8;
1503       dest[2] = val >> 16;
1504       dest += 3;
1505       src += 1;
1506     }
1507 }
1508
1509
1510 static gint
1511 gtk_get_preview_prop (guint *nred,
1512                       guint *ngreen,
1513                       guint *nblue,
1514                       guint *ngray)
1515 {
1516   GtkPreviewProp *prop;
1517   GdkAtom property;
1518
1519   /* FIXME: need to grab the server here to prevent a race condition */
1520
1521   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1522
1523   if (gdk_property_get (NULL, property, property,
1524                         0, sizeof (GtkPreviewProp), FALSE,
1525                         NULL, NULL, NULL, (guchar**) &prop))
1526     {
1527       *nred = prop->nred_shades;
1528       *ngreen = prop->ngreen_shades;
1529       *nblue = prop->nblue_shades;
1530       *ngray = prop->ngray_shades;
1531
1532       prop->ref_count = prop->ref_count + 1;
1533       gdk_property_change (NULL, property, property, 16,
1534                            GDK_PROP_MODE_REPLACE,
1535                            (guchar*) prop, 5);
1536
1537       return TRUE;
1538     }
1539
1540   return FALSE;
1541 }
1542
1543 static void
1544 gtk_set_preview_prop (guint nred,
1545                       guint ngreen,
1546                       guint nblue,
1547                       guint ngray)
1548 {
1549   GtkPreviewProp prop;
1550   GdkAtom property;
1551
1552   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1553
1554   prop.ref_count = 1;
1555   prop.nred_shades = nred;
1556   prop.ngreen_shades = ngreen;
1557   prop.nblue_shades = nblue;
1558   prop.ngray_shades = ngray;
1559
1560   gdk_property_change (NULL, property, property, 16,
1561                        GDK_PROP_MODE_REPLACE,
1562                        (guchar*) &prop, 5);
1563 }
1564
1565
1566 static void
1567 gtk_lsbmsb_1_1 (guchar *dest,
1568                 guchar *src,
1569                 gint    count)
1570 {
1571   memcpy (dest, src, count);
1572 }
1573
1574 static void
1575 gtk_lsb_2_2 (guchar *dest,
1576              guchar *src,
1577              gint    count)
1578 {
1579   memcpy (dest, src, count * 2);
1580 }
1581
1582 static void
1583 gtk_msb_2_2 (guchar *dest,
1584              guchar *src,
1585              gint    count)
1586 {
1587   while (count--)
1588     {
1589       dest[0] = src[1];
1590       dest[1] = src[0];
1591       dest += 2;
1592       src += 2;
1593     }
1594 }
1595
1596 static void
1597 gtk_lsb_3_3 (guchar *dest,
1598              guchar *src,
1599              gint    count)
1600 {
1601   memcpy (dest, src, count * 3);
1602 }
1603
1604 static void
1605 gtk_msb_3_3 (guchar *dest,
1606              guchar *src,
1607              gint    count)
1608 {
1609   while (count--)
1610     {
1611       dest[0] = src[2];
1612       dest[1] = src[1];
1613       dest[2] = src[0];
1614       dest += 3;
1615       src += 3;
1616     }
1617 }
1618
1619 static void
1620 gtk_lsb_3_4 (guchar *dest,
1621              guchar *src,
1622              gint    count)
1623 {
1624   while (count--)
1625     {
1626       dest[0] = src[0];
1627       dest[1] = src[1];
1628       dest[2] = src[2];
1629       dest += 4;
1630       src += 3;
1631     }
1632 }
1633
1634 static void
1635 gtk_msb_3_4 (guchar *dest,
1636              guchar *src,
1637              gint    count)
1638 {
1639   while (count--)
1640     {
1641       dest[1] = src[2];
1642       dest[2] = src[1];
1643       dest[3] = src[0];
1644       dest += 4;
1645       src += 3;
1646     }
1647 }