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