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