]> Pileus Git - ~andy/gtk/blob - gtk/gtkpreview.c
major overhaul of the code, fixed all known bugs (hopefully ;).
[~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 Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <math.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/param.h>
23 #include <netinet/in.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 ()
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         (GtkArgSetFunc) NULL,
143         (GtkArgGetFunc) NULL,
144       };
145
146       preview_type = gtk_type_unique (gtk_widget_get_type (), &preview_info);
147     }
148
149   return preview_type;
150 }
151
152 static void
153 gtk_preview_class_init (GtkPreviewClass *klass)
154 {
155   GtkObjectClass *object_class;
156   GtkWidgetClass *widget_class;
157
158   object_class = (GtkObjectClass*) klass;
159   widget_class = (GtkWidgetClass*) klass;
160
161   parent_class = gtk_type_class (gtk_widget_get_type ());
162   preview_class = klass;
163
164   object_class->finalize = gtk_preview_finalize;
165
166   widget_class->realize = gtk_preview_realize;
167   widget_class->expose_event = gtk_preview_expose;
168
169   if (preview_info)
170     klass->info = *preview_info;
171   else
172     {
173       klass->info.visual = NULL;
174       klass->info.cmap = NULL;
175
176       klass->info.color_pixels = NULL;
177       klass->info.gray_pixels = NULL;
178       klass->info.reserved_pixels = NULL;
179
180       klass->info.lookup_red = NULL;
181       klass->info.lookup_green = NULL;
182       klass->info.lookup_blue = NULL;
183
184       klass->info.dither_red = NULL;
185       klass->info.dither_green = NULL;
186       klass->info.dither_blue = NULL;
187       klass->info.dither_gray = NULL;
188       klass->info.dither_matrix = NULL;
189
190       klass->info.nred_shades = 6;
191       klass->info.ngreen_shades = 6;
192       klass->info.nblue_shades = 4;
193       klass->info.ngray_shades = 24;
194       klass->info.nreserved = 0;
195
196       klass->info.bpp = 0;
197       klass->info.cmap_alloced = FALSE;
198       klass->info.gamma = 1.0;
199     }
200
201   klass->image = NULL;
202
203   gtk_preview_get_visuals (klass);
204   gtk_preview_get_cmaps (klass);
205   gtk_preview_dither_init (klass);
206 }
207
208 void
209 gtk_preview_reset (void)
210 {
211   GtkPreviewInfo *info;
212
213   if (!preview_class || !preview_info)
214     return;
215   
216   info = &preview_class->info;
217
218   gtk_preview_uninit();
219
220   if (info->color_pixels)
221     {
222       gdk_colors_free (info->cmap,
223                        info->color_pixels,
224                        info->nred_shades *
225                          info->ngreen_shades *
226                          info->nblue_shades, 
227                        0);
228
229       gdk_colors_free (info->cmap,
230                        info->gray_pixels,
231                        info->ngray_shades, 0);
232       
233       g_free (info->color_pixels);
234       g_free (info->gray_pixels);
235     }
236
237   if (info->reserved_pixels)
238     {
239       gdk_colors_free (info->cmap,
240                        info->reserved_pixels,
241                        info->nreserved, 0);
242       g_free (info->reserved_pixels);
243     }
244
245   if (info->cmap && info->cmap_alloced)
246     gdk_colormap_unref (info->cmap);
247
248   if (info->lookup_red)
249     {
250       g_free (info->lookup_red);
251       g_free (info->lookup_green);
252       g_free (info->lookup_blue);
253     }
254
255   if (info->dither_matrix)
256     {
257       int i, j;
258
259       for (i= 0 ; i < 8 ; i++)
260         {
261           for (j = 0; j < 8 ; j++)
262             g_free (info->dither_matrix[i][j]);
263           g_free (info->dither_matrix[i]);
264         }
265       g_free (info->dither_matrix);
266       g_free (info->dither_red);
267       g_free (info->dither_green);
268       g_free (info->dither_blue);
269     }
270
271   preview_class->info = *preview_info;
272
273   gtk_preview_get_visuals (preview_class);
274   gtk_preview_get_cmaps (preview_class);
275   gtk_preview_dither_init (preview_class);
276 }
277
278 static void
279 gtk_preview_init (GtkPreview *preview)
280 {
281   GTK_WIDGET_SET_FLAGS (preview, GTK_BASIC);
282
283   preview->buffer = NULL;
284   preview->buffer_width = 0;
285   preview->buffer_height = 0;
286   preview->expand = FALSE;
287 }
288
289 void
290 gtk_preview_uninit ()
291 {
292   GtkPreviewProp *prop;
293   GdkAtom property;
294
295   /* FIXME: need to grab the server here to prevent a race condition */
296
297   if (preview_class && !install_cmap && preview_class->info.visual &&
298       (preview_class->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
299       (preview_class->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
300     {
301       property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
302
303       if (gdk_property_get (NULL, property, property,
304                             0, sizeof (GtkPreviewProp), FALSE,
305                             NULL, NULL, NULL, (guchar**) &prop))
306         {
307           prop->ref_count = ntohs (prop->ref_count) - 1;
308           if (prop->ref_count == 0)
309             {
310               gdk_property_delete (NULL, property);
311             }
312           else
313             {
314               prop->ref_count = htons (prop->ref_count);
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 ()
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 ()
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 ()
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 = gtk_widget_get_visual (widget);
741   attributes.colormap = gtk_widget_get_colormap (widget);
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   switch (klass->info.visual->depth)
877     {
878     case 8:
879       klass->info.bpp = 1;
880       break;
881     case 15:
882     case 16:
883       klass->info.bpp = 2;
884       break;
885     case 24:
886     case 32:
887       klass->info.bpp = 3;
888       break;
889     }
890 }
891
892 static void
893 gtk_preview_get_cmaps (GtkPreviewClass *klass)
894 {
895   g_return_if_fail (klass != NULL);
896   g_return_if_fail (klass->info.visual != NULL);
897
898   if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
899       (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
900     {
901       if (install_cmap)
902         {
903           klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
904           klass->info.cmap_alloced = install_cmap;
905
906           gtk_trim_cmap (klass);
907           gtk_create_8_bit (klass);
908         }
909       else
910         {
911           guint nred;
912           guint ngreen;
913           guint nblue;
914           guint ngray;
915           gint set_prop;
916
917           klass->info.cmap = gdk_colormap_get_system ();
918
919           set_prop = TRUE;
920           if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray))
921             {
922               set_prop = FALSE;
923
924               klass->info.nred_shades = nred;
925               klass->info.ngreen_shades = ngreen;
926               klass->info.nblue_shades = nblue;
927               klass->info.ngray_shades = ngray;
928
929               if (klass->info.nreserved)
930                 {
931                   klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved);
932                   if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0,
933                                          klass->info.reserved_pixels,
934                                          klass->info.nreserved))
935                     {
936                       g_free (klass->info.reserved_pixels);
937                       klass->info.reserved_pixels = NULL;
938                     }
939                 }
940             }
941           else
942             {
943               gtk_trim_cmap (klass);
944             }
945
946           gtk_create_8_bit (klass);
947
948           if (set_prop)
949             gtk_set_preview_prop (klass->info.nred_shades,
950                                   klass->info.ngreen_shades,
951                                   klass->info.nblue_shades,
952                                   klass->info.ngray_shades);
953         }
954     }
955   else
956     {
957       if (klass->info.visual == gdk_visual_get_system ())
958         klass->info.cmap = gdk_colormap_get_system ();
959       else
960         {
961           klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
962           klass->info.cmap_alloced = TRUE;
963         }
964
965       klass->info.nred_shades = 0;
966       klass->info.ngreen_shades = 0;
967       klass->info.nblue_shades = 0;
968       klass->info.ngray_shades = 0;
969     }
970 }
971
972 static void
973 gtk_preview_dither_init (GtkPreviewClass *klass)
974 {
975   int i, j, k;
976   unsigned char low_shade, high_shade;
977   unsigned short index;
978   long red_mult, green_mult;
979   double red_matrix_width;
980   double green_matrix_width;
981   double blue_matrix_width;
982   double gray_matrix_width;
983   double red_colors_per_shade;
984   double green_colors_per_shade;
985   double blue_colors_per_shade;
986   double gray_colors_per_shade;
987   gulong *gray_pixels;
988   gint shades_r, shades_g, shades_b, shades_gray;
989   GtkDitherInfo *red_ordered_dither;
990   GtkDitherInfo *green_ordered_dither;
991   GtkDitherInfo *blue_ordered_dither;
992   GtkDitherInfo *gray_ordered_dither;
993   guchar ***dither_matrix;
994   guchar DM[8][8] =
995   {
996     { 0,  32, 8,  40, 2,  34, 10, 42 },
997     { 48, 16, 56, 24, 50, 18, 58, 26 },
998     { 12, 44, 4,  36, 14, 46, 6,  38 },
999     { 60, 28, 52, 20, 62, 30, 54, 22 },
1000     { 3,  35, 11, 43, 1,  33, 9,  41 },
1001     { 51, 19, 59, 27, 49, 17, 57, 25 },
1002     { 15, 47, 7,  39, 13, 45, 5,  37 },
1003     { 63, 31, 55, 23, 61, 29, 53, 21 }
1004   };
1005
1006   if (!klass->info.visual || klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR)
1007     return;
1008
1009   shades_r = klass->info.nred_shades;
1010   shades_g = klass->info.ngreen_shades;
1011   shades_b = klass->info.nblue_shades;
1012   shades_gray = klass->info.ngray_shades;
1013
1014   red_mult = shades_g * shades_b;
1015   green_mult = shades_b;
1016
1017   red_colors_per_shade = 255.0 / (shades_r - 1);
1018   red_matrix_width = red_colors_per_shade / 64;
1019
1020   green_colors_per_shade = 255.0 / (shades_g - 1);
1021   green_matrix_width = green_colors_per_shade / 64;
1022
1023   blue_colors_per_shade = 255.0 / (shades_b - 1);
1024   blue_matrix_width = blue_colors_per_shade / 64;
1025
1026   gray_colors_per_shade = 255.0 / (shades_gray - 1);
1027   gray_matrix_width = gray_colors_per_shade / 64;
1028
1029   /*  alloc the ordered dither arrays for accelerated dithering  */
1030
1031   klass->info.dither_red = g_new (GtkDitherInfo, 256);
1032   klass->info.dither_green = g_new (GtkDitherInfo, 256);
1033   klass->info.dither_blue = g_new (GtkDitherInfo, 256);
1034   klass->info.dither_gray = g_new (GtkDitherInfo, 256);
1035
1036   red_ordered_dither = klass->info.dither_red;
1037   green_ordered_dither = klass->info.dither_green;
1038   blue_ordered_dither = klass->info.dither_blue;
1039   gray_ordered_dither = klass->info.dither_gray;
1040
1041   dither_matrix = g_new (guchar**, 8);
1042   for (i = 0; i < 8; i++)
1043     {
1044       dither_matrix[i] = g_new (guchar*, 8);
1045       for (j = 0; j < 8; j++)
1046         dither_matrix[i][j] = g_new (guchar, 65);
1047     }
1048
1049   klass->info.dither_matrix = dither_matrix;
1050
1051   /*  setup the ordered_dither_matrices  */
1052
1053   for (i = 0; i < 8; i++)
1054     for (j = 0; j < 8; j++)
1055       for (k = 0; k <= 64; k++)
1056         dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0;
1057
1058   /*  setup arrays containing three bytes of information for red, green, & blue  */
1059   /*  the arrays contain :
1060    *    1st byte:    low end shade value
1061    *    2nd byte:    high end shade value
1062    *    3rd & 4th bytes:    ordered dither matrix index
1063    */
1064
1065   gray_pixels = klass->info.gray_pixels;
1066
1067   for (i = 0; i < 256; i++)
1068     {
1069
1070       /*  setup the red information  */
1071       {
1072         low_shade = (unsigned char) (i / red_colors_per_shade);
1073         if (low_shade == (shades_r - 1))
1074           low_shade--;
1075         high_shade = low_shade + 1;
1076
1077         index = (unsigned short)
1078           (((double) i - low_shade * red_colors_per_shade) /
1079            red_matrix_width);
1080
1081         low_shade *= red_mult;
1082         high_shade *= red_mult;
1083
1084         red_ordered_dither[i].s[1] = index;
1085         red_ordered_dither[i].c[0] = low_shade;
1086         red_ordered_dither[i].c[1] = high_shade;
1087       }
1088
1089
1090       /*  setup the green information  */
1091       {
1092         low_shade = (unsigned char) (i / green_colors_per_shade);
1093         if (low_shade == (shades_g - 1))
1094           low_shade--;
1095         high_shade = low_shade + 1;
1096
1097         index = (unsigned short)
1098           (((double) i - low_shade * green_colors_per_shade) /
1099            green_matrix_width);
1100
1101         low_shade *= green_mult;
1102         high_shade *= green_mult;
1103
1104         green_ordered_dither[i].s[1] = index;
1105         green_ordered_dither[i].c[0] = low_shade;
1106         green_ordered_dither[i].c[1] = high_shade;
1107       }
1108
1109
1110       /*  setup the blue information  */
1111       {
1112         low_shade = (unsigned char) (i / blue_colors_per_shade);
1113         if (low_shade == (shades_b - 1))
1114           low_shade--;
1115         high_shade = low_shade + 1;
1116
1117         index = (unsigned short)
1118           (((double) i - low_shade * blue_colors_per_shade) /
1119            blue_matrix_width);
1120
1121         blue_ordered_dither[i].s[1] = index;
1122         blue_ordered_dither[i].c[0] = low_shade;
1123         blue_ordered_dither[i].c[1] = high_shade;
1124       }
1125
1126
1127       /*  setup the gray information */
1128       {
1129         low_shade = (unsigned char) (i / gray_colors_per_shade);
1130         if (low_shade == (shades_gray - 1))
1131           low_shade--;
1132         high_shade = low_shade + 1;
1133
1134         index = (unsigned short)
1135           (((double) i - low_shade * gray_colors_per_shade) /
1136            gray_matrix_width);
1137
1138         gray_ordered_dither[i].s[1] = index;
1139         gray_ordered_dither[i].c[0] = gray_pixels[low_shade];
1140         gray_ordered_dither[i].c[1] = gray_pixels[high_shade];
1141       }
1142     }
1143 }
1144
1145 static void
1146 gtk_fill_lookup_array (gulong *array,
1147                        int     depth,
1148                        int     shift,
1149                        int     prec)
1150 {
1151   double one_over_gamma;
1152   double ind;
1153   int val;
1154   int i;
1155
1156   if (preview_class->info.gamma != 0.0)
1157     one_over_gamma = 1.0 / preview_class->info.gamma;
1158   else
1159     one_over_gamma = 1.0;
1160
1161   for (i = 0; i < 256; i++)
1162     {
1163       if (one_over_gamma == 1.0)
1164         array[i] = ((i >> prec) << shift);
1165       else
1166         {
1167           ind = (double) i / 255.0;
1168           val = (int) (255 * pow (ind, one_over_gamma));
1169           array[i] = ((val >> prec) << shift);
1170         }
1171     }
1172 }
1173
1174 static void
1175 gtk_trim_cmap (GtkPreviewClass *klass)
1176 {
1177   gulong pixels[256];
1178   guint nred;
1179   guint ngreen;
1180   guint nblue;
1181   guint ngray;
1182   guint nreserved;
1183   guint total;
1184   guint tmp;
1185   gint success;
1186
1187   nred = klass->info.nred_shades;
1188   ngreen = klass->info.ngreen_shades;
1189   nblue = klass->info.nblue_shades;
1190   ngray = klass->info.ngray_shades;
1191   nreserved = klass->info.nreserved;
1192
1193   success = FALSE;
1194   while (!success)
1195     {
1196       total = nred * ngreen * nblue + ngray + nreserved;
1197
1198       if (total <= 256)
1199         {
1200           if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1201             success = TRUE;
1202           else
1203             {
1204               success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total);
1205               if (success)
1206                 {
1207                   if (nreserved > 0)
1208                     {
1209                       klass->info.reserved_pixels = g_new (gulong, nreserved);
1210                       memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved);
1211                       gdk_colors_free (klass->info.cmap, &pixels[nreserved],
1212                                        total - nreserved, 0);
1213                     }
1214                   else
1215                     {
1216                       gdk_colors_free (klass->info.cmap, pixels, total, 0);
1217                     }
1218                 }
1219             }
1220         }
1221
1222       if (!success)
1223         {
1224           if ((nblue >= nred) && (nblue >= ngreen))
1225             nblue = nblue - 1;
1226           else if ((nred >= ngreen) && (nred >= nblue))
1227             nred = nred - 1;
1228           else
1229             {
1230               tmp = log (ngray) / log (2);
1231
1232               if (ngreen >= tmp)
1233                 ngreen = ngreen - 1;
1234               else
1235                 ngray -= 1;
1236             }
1237         }
1238     }
1239
1240   if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
1241     {
1242       g_print ("Unable to allocate sufficient colormap entries.\n");
1243       g_print ("Try exiting other color intensive applications.\n");
1244       return;
1245     }
1246
1247   /*  If any of the shade values has changed, issue a warning  */
1248   if ((nred != klass->info.nred_shades) ||
1249       (ngreen != klass->info.ngreen_shades) ||
1250       (nblue != klass->info.nblue_shades) ||
1251       (ngray != klass->info.ngray_shades))
1252     {
1253       g_print ("Not enough colors to satisfy requested color cube.\n");
1254       g_print ("Reduced color cube shades from\n");
1255       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",
1256                klass->info.nred_shades, klass->info.ngreen_shades,
1257                klass->info.nblue_shades, klass->info.ngray_shades,
1258                nred, ngreen, nblue, ngray);
1259     }
1260
1261   klass->info.nred_shades = nred;
1262   klass->info.ngreen_shades = ngreen;
1263   klass->info.nblue_shades = nblue;
1264   klass->info.ngray_shades = ngray;
1265 }
1266
1267 static void
1268 gtk_create_8_bit (GtkPreviewClass *klass)
1269 {
1270   unsigned int r, g, b;
1271   unsigned int rv, gv, bv;
1272   unsigned int dr, dg, db, dgray;
1273   GdkColor color;
1274   gulong *pixels;
1275   double one_over_gamma;
1276   int i;
1277
1278   if (!klass->info.color_pixels)
1279     klass->info.color_pixels = g_new (gulong, 256);
1280
1281   if (!klass->info.gray_pixels)
1282     klass->info.gray_pixels = g_new (gulong, 256);
1283
1284   if (klass->info.gamma != 0.0)
1285     one_over_gamma = 1.0 / klass->info.gamma;
1286   else
1287     one_over_gamma = 1.0;
1288
1289   dr = klass->info.nred_shades - 1;
1290   dg = klass->info.ngreen_shades - 1;
1291   db = klass->info.nblue_shades - 1;
1292   dgray = klass->info.ngray_shades - 1;
1293
1294   pixels = klass->info.color_pixels;
1295
1296   for (r = 0, i = 0; r <= dr; r++)
1297     for (g = 0; g <= dg; g++)
1298       for (b = 0; b <= db; b++, i++)
1299         {
1300           rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr);
1301           gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg);
1302           bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db);
1303           color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257;
1304           color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257;
1305           color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257;
1306
1307           if (!gdk_color_alloc (klass->info.cmap, &color))
1308             {
1309               g_error ("could not initialize 8-bit combined colormap");
1310               return;
1311             }
1312
1313           pixels[i] = color.pixel;
1314         }
1315
1316
1317   pixels = klass->info.gray_pixels;
1318
1319   for (i = 0; i < (int) klass->info.ngray_shades; i++)
1320     {
1321       color.red = (i * klass->info.visual->colormap_size) / dgray;
1322       color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257;
1323       color.green = color.red;
1324       color.blue = color.red;
1325
1326       if (!gdk_color_alloc (klass->info.cmap, &color))
1327         {
1328           g_error ("could not initialize 8-bit combined colormap");
1329           return;
1330         }
1331
1332       pixels[i] = color.pixel;
1333     }
1334 }
1335
1336
1337 static void
1338 gtk_color_8 (guchar *src,
1339              guchar *dest,
1340              gint    x,
1341              gint    y,
1342              gulong  width)
1343 {
1344   gulong *colors;
1345   GtkDitherInfo *dither_red;
1346   GtkDitherInfo *dither_green;
1347   GtkDitherInfo *dither_blue;
1348   GtkDitherInfo r, g, b;
1349   guchar **dither_matrix;
1350   guchar *matrix;
1351
1352   colors = preview_class->info.color_pixels;
1353   dither_red = preview_class->info.dither_red;
1354   dither_green = preview_class->info.dither_green;
1355   dither_blue = preview_class->info.dither_blue;
1356   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1357
1358   while (width--)
1359     {
1360       r = dither_red[src[0]];
1361       g = dither_green[src[1]];
1362       b = dither_blue[src[2]];
1363       src += 3;
1364
1365       matrix = dither_matrix[x++ & 0x7];
1366       *dest++ = colors[(r.c[matrix[r.s[1]]] +
1367                         g.c[matrix[g.s[1]]] +
1368                         b.c[matrix[b.s[1]]])];
1369     }
1370 }
1371
1372 static void
1373 gtk_color_16 (guchar *src,
1374               guchar *dest,
1375               gulong  width)
1376 {
1377   gulong *lookup_red;
1378   gulong *lookup_green;
1379   gulong *lookup_blue;
1380   gulong val;
1381
1382   lookup_red = preview_class->info.lookup_red;
1383   lookup_green = preview_class->info.lookup_green;
1384   lookup_blue = preview_class->info.lookup_blue;
1385
1386   while (width--)
1387     {
1388       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1389       dest[0] = val;
1390       dest[1] = val >> 8;
1391       dest += 2;
1392       src += 3;
1393     }
1394 }
1395
1396 static void
1397 gtk_color_24 (guchar *src,
1398               guchar *dest,
1399               gulong  width)
1400 {
1401   gulong *lookup_red;
1402   gulong *lookup_green;
1403   gulong *lookup_blue;
1404   gulong val;
1405
1406   lookup_red = preview_class->info.lookup_red;
1407   lookup_green = preview_class->info.lookup_green;
1408   lookup_blue = preview_class->info.lookup_blue;
1409
1410   while (width--)
1411     {
1412       val = COLOR_COMPOSE (src[0], src[1], src[2]);
1413       dest[0] = val;
1414       dest[1] = val >> 8;
1415       dest[2] = val >> 16;
1416       dest += 3;
1417       src += 3;
1418     }
1419 }
1420
1421 static void
1422 gtk_grayscale_8 (guchar *src,
1423                  guchar *dest,
1424                  gint    x,
1425                  gint    y,
1426                  gulong  width)
1427 {
1428   GtkDitherInfo *dither_gray;
1429   GtkDitherInfo gray;
1430   guchar **dither_matrix;
1431   guchar *matrix;
1432
1433   dither_gray = preview_class->info.dither_gray;
1434   dither_matrix = preview_class->info.dither_matrix[y & 0x7];
1435
1436   while (width--)
1437     {
1438       gray = dither_gray[*src++];
1439       matrix = dither_matrix[x++ & 0x7];
1440       *dest++ = gray.c[matrix[gray.s[1]]];
1441     }
1442 }
1443
1444 static void
1445 gtk_grayscale_16 (guchar *src,
1446                   guchar *dest,
1447                   gulong  width)
1448 {
1449   gulong *lookup_red;
1450   gulong *lookup_green;
1451   gulong *lookup_blue;
1452   gulong val;
1453
1454   lookup_red = preview_class->info.lookup_red;
1455   lookup_green = preview_class->info.lookup_green;
1456   lookup_blue = preview_class->info.lookup_blue;
1457
1458   while (width--)
1459     {
1460       val = COLOR_COMPOSE (*src, *src, *src);
1461       dest[0] = val;
1462       dest[1] = val >> 8;
1463       dest += 2;
1464       src += 1;
1465     }
1466 }
1467
1468 static void
1469 gtk_grayscale_24 (guchar  *src,
1470                   guchar  *dest,
1471                   gulong   width)
1472 {
1473   gulong *lookup_red;
1474   gulong *lookup_green;
1475   gulong *lookup_blue;
1476   gulong val;
1477
1478   lookup_red = preview_class->info.lookup_red;
1479   lookup_green = preview_class->info.lookup_green;
1480   lookup_blue = preview_class->info.lookup_blue;
1481
1482   while (width--)
1483     {
1484       val = COLOR_COMPOSE (*src, *src, *src);
1485       dest[0] = val;
1486       dest[1] = val >> 8;
1487       dest[2] = val >> 16;
1488       dest += 3;
1489       src += 1;
1490     }
1491 }
1492
1493
1494 static gint
1495 gtk_get_preview_prop (guint *nred,
1496                       guint *ngreen,
1497                       guint *nblue,
1498                       guint *ngray)
1499 {
1500   GtkPreviewProp *prop;
1501   GdkAtom property;
1502
1503   /* FIXME: need to grab the server here to prevent a race condition */
1504
1505   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1506
1507   if (gdk_property_get (NULL, property, property,
1508                         0, sizeof (GtkPreviewProp), FALSE,
1509                         NULL, NULL, NULL, (guchar**) &prop))
1510     {
1511       *nred = ntohs (prop->nred_shades);
1512       *ngreen = ntohs (prop->ngreen_shades);
1513       *nblue = ntohs (prop->nblue_shades);
1514       *ngray = ntohs (prop->ngray_shades);
1515
1516       prop->ref_count = htons (ntohs (prop->ref_count) + 1);
1517       gdk_property_change (NULL, property, property, 16,
1518                            GDK_PROP_MODE_REPLACE,
1519                            (guchar*) prop, 5);
1520
1521       return TRUE;
1522     }
1523
1524   return FALSE;
1525 }
1526
1527 static void
1528 gtk_set_preview_prop (guint nred,
1529                       guint ngreen,
1530                       guint nblue,
1531                       guint ngray)
1532 {
1533   GtkPreviewProp prop;
1534   GdkAtom property;
1535
1536   property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
1537
1538   prop.ref_count = htons (1);
1539   prop.nred_shades = htons (nred);
1540   prop.ngreen_shades = htons (ngreen);
1541   prop.nblue_shades = htons (nblue);
1542   prop.ngray_shades = htons (ngray);
1543
1544   gdk_property_change (NULL, property, property, 16,
1545                        GDK_PROP_MODE_REPLACE,
1546                        (guchar*) &prop, 5);
1547 }
1548
1549
1550 static void
1551 gtk_lsbmsb_1_1 (guchar *dest,
1552                 guchar *src,
1553                 gint    count)
1554 {
1555   memcpy (dest, src, count);
1556 }
1557
1558 static void
1559 gtk_lsb_2_2 (guchar *dest,
1560              guchar *src,
1561              gint    count)
1562 {
1563   memcpy (dest, src, count * 2);
1564 }
1565
1566 static void
1567 gtk_msb_2_2 (guchar *dest,
1568              guchar *src,
1569              gint    count)
1570 {
1571   while (count--)
1572     {
1573       dest[0] = src[1];
1574       dest[1] = src[0];
1575       dest += 2;
1576       src += 2;
1577     }
1578 }
1579
1580 static void
1581 gtk_lsb_3_3 (guchar *dest,
1582              guchar *src,
1583              gint    count)
1584 {
1585   memcpy (dest, src, count * 3);
1586 }
1587
1588 static void
1589 gtk_msb_3_3 (guchar *dest,
1590              guchar *src,
1591              gint    count)
1592 {
1593   while (count--)
1594     {
1595       dest[0] = src[2];
1596       dest[1] = src[1];
1597       dest[2] = src[0];
1598       dest += 3;
1599       src += 3;
1600     }
1601 }
1602
1603 static void
1604 gtk_lsb_3_4 (guchar *dest,
1605              guchar *src,
1606              gint    count)
1607 {
1608   while (count--)
1609     {
1610       dest[0] = src[0];
1611       dest[1] = src[1];
1612       dest[2] = src[2];
1613       dest += 4;
1614       src += 3;
1615     }
1616 }
1617
1618 static void
1619 gtk_msb_3_4 (guchar *dest,
1620              guchar *src,
1621              gint    count)
1622 {
1623   while (count--)
1624     {
1625       dest[1] = src[2];
1626       dest[2] = src[1];
1627       dest[3] = src[0];
1628       dest += 4;
1629       src += 3;
1630     }
1631 }