]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkcc-x11.c
moved back to a sane value!
[~andy/gtk] / gdk / x11 / gdkcc-x11.c
1 /* GDK - The GIMP Drawing Kit
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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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 /* Color Context module
21  * Copyright 1994,1995 John L. Cwikla
22  * Copyright (C) 1997 by Ripley Software Development
23  * Copyright (C) 1997 by Federico Mena (port to Gtk/Gdk)
24  */
25
26 /* Copyright 1994,1995 John L. Cwikla
27  *
28  * Permission to use, copy, modify, distribute, and sell this software
29  * and its documentation for any purpose is hereby granted without fee,
30  * provided that the above copyright notice appears in all copies and that
31  * both that copyright notice and this permission notice appear in
32  * supporting documentation, and that the name of John L. Cwikla or
33  * Wolfram Research, Inc not be used in advertising or publicity
34  * pertaining to distribution of the software without specific, written
35  * prior permission.  John L. Cwikla and Wolfram Research, Inc make no
36  * representations about the suitability of this software for any
37  * purpose.  It is provided "as is" without express or implied warranty.
38  *
39  * John L. Cwikla and Wolfram Research, Inc disclaim all warranties with
40  * regard to this software, including all implied warranties of
41  * merchantability and fitness, in no event shall John L. Cwikla or
42  * Wolfram Research, Inc be liable for any special, indirect or
43  * consequential damages or any damages whatsoever resulting from loss of
44  * use, data or profits, whether in an action of contract, negligence or
45  * other tortious action, arising out of or in connection with the use or
46  * performance of this software.
47  *
48  * Author:
49  *  John L. Cwikla
50  *  X Programmer
51  *  Wolfram Research Inc.
52  *
53  *  cwikla@wri.com
54  */
55
56 /*
57  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
58  * file for a list of people on the GTK+ Team.  See the ChangeLog
59  * files for a list of changes.  These files are distributed with
60  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
61  */
62
63 #include <X11/Xlib.h>
64 #include <X11/Xutil.h>
65 #include <stdlib.h>
66 #include <string.h>
67
68 #include "gdkcc.h"
69 #include "gdkcolor.h"
70 #include "gdkx.h"
71 #include "gdkinternals.h"
72
73 #define MAX_IMAGE_COLORS 256
74
75 typedef struct _GdkColorContextPrivate GdkColorContextPrivate;
76
77 struct _GdkColorContextPrivate
78 {
79   GdkColorContext color_context;
80   Display *xdisplay;
81   XStandardColormap std_cmap;
82 };
83
84 static guint
85 hash_color (gconstpointer key)
86 {
87   const GdkColor *color = key;
88   
89   return (color->red * 33023 + color->green * 30013 + color->blue * 27011);
90 }
91
92 static gint
93 compare_colors (gconstpointer a,
94                 gconstpointer b)
95 {
96   const GdkColor *aa = a;
97   const GdkColor *bb = b;
98   
99   return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue));
100 }
101
102 static void
103 free_hash_entry (gpointer key,
104                  gpointer value,
105                  gpointer user_data)
106 {
107   g_free (key); /* key and value are the same GdkColor */
108 }
109
110 static int
111 pixel_sort (const void *a, const void *b)
112 {
113   return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
114 }
115
116 /* XXX: This function does an XQueryColors() the hard way, because there is
117  * no corresponding function in Gdk.
118  */
119
120 static void
121 my_x_query_colors (GdkColormap *colormap,
122                    GdkColor    *colors,
123                    gint         ncolors)
124 {
125   XColor *xcolors;
126   gint    i;
127   
128   xcolors = g_new (XColor, ncolors);
129   for (i = 0; i < ncolors; i++)
130     xcolors[i].pixel = colors[i].pixel;
131   
132   XQueryColors (gdk_display, GDK_COLORMAP_XCOLORMAP (colormap), xcolors, ncolors);
133   
134   for (i = 0; i < ncolors; i++)
135     {
136       colors[i].red   = xcolors[i].red;
137       colors[i].green = xcolors[i].green;
138       colors[i].blue  = xcolors[i].blue;
139     }
140   
141   g_free (xcolors);
142 }
143
144 static void
145 query_colors (GdkColorContext *cc)
146 {
147   gint i;
148   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
149   cc->cmap = g_new (GdkColor, cc->num_colors);
150   
151   for (i = 0; i < cc->num_colors; i++)
152     cc->cmap[i].pixel = cc->clut ? cc->clut[i] : ccp->std_cmap.base_pixel + i;
153   
154   my_x_query_colors (cc->colormap, cc->cmap, cc->num_colors);
155   
156   qsort (cc->cmap, cc->num_colors, sizeof (GdkColor), pixel_sort);
157 }
158
159 static void
160 init_bw (GdkColorContext *cc)
161 {
162   GdkColor color;
163   
164   g_warning ("init_bw: failed to allocate colors, falling back to black and white");
165   
166   cc->mode = GDK_CC_MODE_BW;
167   
168   color.red = color.green = color.blue = 0;
169   
170   if (!gdk_color_alloc (cc->colormap, &color))
171     cc->black_pixel = 0;
172   else
173     cc->black_pixel = color.pixel;
174   
175   color.red = color.green = color.blue = 0xffff;
176   
177   if (!gdk_color_alloc (cc->colormap, &color))
178     cc->white_pixel = cc->black_pixel ? 0 : 1;
179   else
180     cc->white_pixel = color.pixel;
181   
182   cc->num_colors = 2;
183 }
184
185 static void
186 init_gray (GdkColorContext *cc)
187 {
188   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
189   GdkColor *clrs, *cstart;
190   gint i;
191   gdouble dinc;
192   
193   cc->num_colors = GDK_VISUAL_XVISUAL (cc->visual)->map_entries;
194   
195   cc->clut = g_new (gulong, cc->num_colors);
196   cstart = g_new (GdkColor, cc->num_colors);
197   
198  retrygray:
199   
200   dinc = 65535.0 / (cc->num_colors - 1);
201   
202   clrs = cstart;
203   
204   for (i = 0; i < cc->num_colors; i++)
205     {
206       clrs->red = clrs->green = clrs->blue = dinc * i;
207       
208       if (!gdk_color_alloc (cc->colormap, clrs))
209         {
210           gdk_colors_free (cc->colormap, cc->clut, i, 0);
211           
212           cc->num_colors /= 2;
213           
214           if (cc->num_colors > 1)
215             goto retrygray;
216           else
217             {
218               g_free (cc->clut);
219               cc->clut = NULL;
220               init_bw (cc);
221               g_free (cstart);
222               return;
223             }
224         }
225       
226       cc->clut[i] = clrs++->pixel;
227     }
228   
229   g_free (cstart);
230   
231   /* XXX: is this the right thing to do? */
232   ccp->std_cmap.colormap = GDK_COLORMAP_XCOLORMAP (cc->colormap);
233   ccp->std_cmap.base_pixel = 0;
234   ccp->std_cmap.red_max = cc->num_colors - 1;
235   ccp->std_cmap.green_max = 0;
236   ccp->std_cmap.blue_max = 0;
237   ccp->std_cmap.red_mult = 1;
238   ccp->std_cmap.green_mult = 0;
239   ccp->std_cmap.blue_mult = 0;
240   
241   cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
242   cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
243   
244   query_colors (cc);
245   
246   cc->mode = GDK_CC_MODE_MY_GRAY;
247 }
248
249 static void
250 init_color (GdkColorContext *cc)
251 {
252   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
253   gint cubeval;
254   
255   cubeval = 1;
256   while ((cubeval * cubeval * cubeval) < GDK_VISUAL_XVISUAL (cc->visual)->map_entries)
257     cubeval++;
258   cubeval--;
259   
260   cc->num_colors = cubeval * cubeval * cubeval;
261   
262   ccp->std_cmap.red_max    = cubeval - 1;
263   ccp->std_cmap.green_max  = cubeval - 1;
264   ccp->std_cmap.blue_max   = cubeval - 1;
265   ccp->std_cmap.red_mult   = cubeval * cubeval;
266   ccp->std_cmap.green_mult = cubeval;
267   ccp->std_cmap.blue_mult  = 1;
268   ccp->std_cmap.base_pixel = 0;
269   
270   cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
271   cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
272   cc->num_colors = DisplayCells (ccp->xdisplay, gdk_screen);
273   
274   /* a CLUT for storing allocated pixel indices */
275   
276   cc->max_colors = cc->num_colors;
277   cc->clut = g_new (gulong, cc->max_colors);
278   
279   for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
280     cc->clut[cubeval] = cubeval;
281   
282   query_colors (cc);
283   
284   cc->mode = GDK_CC_MODE_STD_CMAP;
285 }
286
287
288 static void
289 init_true_color (GdkColorContext *cc)
290 {
291   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
292   gulong rmask, gmask, bmask;
293   
294   cc->mode = GDK_CC_MODE_TRUE;
295   
296   /* Red */
297   
298   rmask = cc->masks.red = cc->visual->red_mask;
299   
300   cc->shifts.red = 0;
301   cc->bits.red = 0;
302   
303   while (!(rmask & 1))
304     {
305       rmask >>= 1;
306       cc->shifts.red++;
307     }
308   
309   while (rmask & 1)
310     {
311       rmask >>= 1;
312       cc->bits.red++;
313     }
314   
315   /* Green */
316   
317   gmask = cc->masks.green = cc->visual->green_mask;
318   
319   cc->shifts.green = 0;
320   cc->bits.green = 0;
321   
322   while (!(gmask & 1))
323     {
324       gmask >>= 1;
325       cc->shifts.green++;
326     }
327   
328   while (gmask & 1)
329     {
330       gmask >>= 1;
331       cc->bits.green++;
332     }
333   
334   /* Blue */
335   
336   bmask = cc->masks.blue = cc->visual->blue_mask;
337   
338   cc->shifts.blue = 0;
339   cc->bits.blue = 0;
340   
341   while (!(bmask & 1))
342     {
343       bmask >>= 1;
344       cc->shifts.blue++;
345     }
346   
347   while (bmask & 1)
348     {
349       bmask >>= 1;
350       cc->bits.blue++;
351     }
352   
353   cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1;
354   cc->white_pixel = WhitePixel (ccp->xdisplay, gdk_screen);
355   cc->black_pixel = BlackPixel (ccp->xdisplay, gdk_screen);
356 }
357
358 static void
359 init_direct_color (GdkColorContext *cc)
360 {
361   gint n, count;
362   GdkColor *clrs, *cstart;
363   gulong rval, gval, bval;
364   gulong *rtable;
365   gulong *gtable;
366   gulong *btable;
367   gdouble dinc;
368   
369   init_true_color (cc); /* for shift stuff */
370   
371   rval = cc->visual->red_mask >> cc->shifts.red;
372   gval = cc->visual->green_mask >> cc->shifts.green;
373   bval = cc->visual->blue_mask >> cc->shifts.blue;
374   
375   rtable = g_new (gulong, rval + 1);
376   gtable = g_new (gulong, gval + 1);
377   btable = g_new (gulong, bval + 1);
378   
379   cc->max_entry = MAX (rval, gval);
380   cc->max_entry = MAX (cc->max_entry, bval);
381   
382   cstart = g_new (GdkColor, cc->max_entry + 1);
383   cc->clut = g_new (gulong, cc->max_entry + 1);
384   
385  retrydirect:
386   
387   for (n = 0; n < rval; n++)
388     rtable[n] = rval ? (65535.0 / rval * n) : 0;
389   
390   for (n = 0; n < gval; n++)
391     gtable[n] = gval ? (65535.0 / gval * n) : 0;
392   
393   for (n = 0; n < bval; n++)
394     btable[n] = bval ? (65535.0 / bval * n) : 0;
395   
396   cc->max_entry = MAX (rval, gval);
397   cc->max_entry = MAX (cc->max_entry, bval);
398   
399   count = 0;
400   clrs = cstart;
401   cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
402   
403   for (n = 0; n < cc->max_entry; n++)
404     {
405       dinc = (double) n / cc->max_entry;
406       
407       clrs->red   = rtable[(int) (dinc * rval)];
408       clrs->green = gtable[(int) (dinc * gval)];
409       clrs->blue  = btable[(int) (dinc * bval)];
410       
411       if (gdk_color_alloc (cc->colormap, clrs))
412         {
413           cc->clut[count++] = clrs->pixel;
414           clrs++;
415         }
416       else
417         {
418           gdk_colors_free (cc->colormap, cc->clut, count, 0);
419           
420           rval >>= 1;
421           gval >>= 1;
422           bval >>= 1;
423           
424           cc->masks.red   = (cc->masks.red >> 1) & cc->visual->red_mask;
425           cc->masks.green = (cc->masks.green >> 1) & cc->visual->green_mask;
426           cc->masks.blue  = (cc->masks.blue >> 1) & cc->visual->blue_mask;
427           
428           cc->shifts.red++;
429           cc->shifts.green++;
430           cc->shifts.blue++;
431           
432           cc->bits.red--;
433           cc->bits.green--;
434           cc->bits.blue--;
435           
436           cc->num_colors = (rval + 1) * (gval + 1) * (bval + 1);
437           
438           if (cc->num_colors >1)
439             goto retrydirect;
440           else
441             {
442               g_free (cc->clut);
443               cc->clut = NULL;
444               init_bw (cc);
445               break;
446             }
447         }
448     }
449   
450   /* Update allocated color count; original num_colors is max_entry, which
451    * is not necessarily the same as the really allocated number of colors.
452    */
453   
454   cc->num_colors = count;
455   
456   g_free (rtable);
457   g_free (gtable);
458   g_free (btable);
459   g_free (cstart);
460 }
461
462 static void
463 init_palette (GdkColorContext *cc)
464 {
465   /* restore correct mode for this cc */
466   
467   switch (cc->visual->type)
468     {
469     case GDK_VISUAL_STATIC_GRAY:
470     case GDK_VISUAL_GRAYSCALE:
471       if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
472         cc->mode = GDK_CC_MODE_BW;
473       else
474         cc->mode = GDK_CC_MODE_MY_GRAY;
475       break;
476       
477     case GDK_VISUAL_TRUE_COLOR:
478     case GDK_VISUAL_DIRECT_COLOR:
479       cc->mode = GDK_CC_MODE_TRUE;
480       break;
481       
482     case GDK_VISUAL_STATIC_COLOR:
483     case GDK_VISUAL_PSEUDO_COLOR:
484       cc->mode = GDK_CC_MODE_STD_CMAP;
485       break;
486       
487     default:
488       cc->mode = GDK_CC_MODE_UNDEFINED;
489       break;
490     }
491   
492   /* previous palette */
493   
494   if (cc->num_palette)
495     g_free (cc->palette);
496   
497   if (cc->fast_dither)
498     g_free (cc->fast_dither);
499   
500   /* clear hash table if present */
501   
502   if (cc->color_hash)
503     {
504       g_hash_table_foreach (cc->color_hash,
505                             free_hash_entry,
506                             NULL);
507       g_hash_table_destroy (cc->color_hash);
508       cc->color_hash = NULL;
509     }
510   
511   cc->palette = NULL;
512   cc->num_palette = 0;
513   cc->fast_dither = NULL;
514 }
515
516 GdkColorContext *
517 gdk_color_context_new (GdkVisual   *visual,
518                        GdkColormap *colormap)
519 {
520   GdkColorContextPrivate *ccp;
521   gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
522   GdkColorContext *cc;
523   gint retry_count;
524   GdkColormap *default_colormap;
525   
526   g_assert (visual != NULL);
527   g_assert (colormap != NULL);
528   
529   ccp = g_new (GdkColorContextPrivate, 1);
530   cc = (GdkColorContext *) ccp;
531   ccp->xdisplay = gdk_display;
532   cc->visual = visual;
533   cc->colormap = colormap;
534   cc->clut = NULL;
535   cc->cmap = NULL;
536   cc->mode = GDK_CC_MODE_UNDEFINED;
537   cc->need_to_free_colormap = FALSE;
538   
539   cc->color_hash = NULL;
540   cc->palette = NULL;
541   cc->num_palette = 0;
542   cc->fast_dither = NULL;
543   
544   default_colormap = gdk_colormap_get_system ();
545   
546   retry_count = 0;
547   
548   while (retry_count < 2)
549     {
550       /* Only create a private colormap if the visual found isn't equal
551        * to the default visual and we don't have a private colormap,
552        * -or- if we are instructed to create a private colormap (which
553        * never is the case for XmHTML).
554        */
555       
556       if (use_private_colormap
557           || ((cc->visual != gdk_visual_get_system ()) /* default visual? */
558               && (GDK_COLORMAP_XCOLORMAP (colormap) == GDK_COLORMAP_XCOLORMAP (default_colormap))))
559         {
560           g_warning ("gdk_color_context_new: non-default visual detected, "
561                      "using private colormap");
562           
563           cc->colormap = gdk_colormap_new (cc->visual, FALSE);
564           
565           cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP (colormap)
566                                        != GDK_COLORMAP_XCOLORMAP (default_colormap));
567         }
568       
569       switch (visual->type)
570         {
571         case GDK_VISUAL_STATIC_GRAY:
572         case GDK_VISUAL_GRAYSCALE:
573           GDK_NOTE (COLOR_CONTEXT,
574                     g_message ("gdk_color_context_new: visual class is %s\n",
575                                (visual->type == GDK_VISUAL_STATIC_GRAY) ?
576                                "GDK_VISUAL_STATIC_GRAY" :
577                                "GDK_VISUAL_GRAYSCALE"));
578           
579           if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
580             init_bw (cc);
581           else
582             init_gray (cc);
583           
584           break;
585           
586         case GDK_VISUAL_TRUE_COLOR: /* shifts */
587           GDK_NOTE (COLOR_CONTEXT,
588                     g_message ("gdk_color_context_new: visual class is GDK_VISUAL_TRUE_COLOR\n"));
589           
590           init_true_color (cc);
591           break;
592           
593         case GDK_VISUAL_DIRECT_COLOR: /* shifts and fake CLUT */
594           GDK_NOTE (COLOR_CONTEXT,
595                     g_message ("gdk_color_context_new: visual class is GDK_VISUAL_DIRECT_COLOR\n"));
596           
597           init_direct_color (cc);
598           break;
599           
600         case GDK_VISUAL_STATIC_COLOR:
601         case GDK_VISUAL_PSEUDO_COLOR:
602           GDK_NOTE (COLOR_CONTEXT,
603                     g_message ("gdk_color_context_new: visual class is %s\n",
604                                (visual->type == GDK_VISUAL_STATIC_COLOR) ?
605                                "GDK_VISUAL_STATIC_COLOR" :
606                                "GDK_VISUAL_PSEUDO_COLOR"));
607           
608           init_color (cc);
609           break;
610           
611         default:
612           g_assert_not_reached ();
613         }
614       
615       if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1))
616         {
617           use_private_colormap = TRUE;
618           retry_count++;
619         }
620       else
621         break;
622     }
623   
624   /* no. of colors allocated yet */
625   
626   cc->num_allocated = 0;
627   
628   GDK_NOTE (COLOR_CONTEXT,
629             g_message ("gdk_color_context_new: screen depth is %i, no. of colors is %i\n",
630                        cc->visual->depth, cc->num_colors));
631   
632   return (GdkColorContext *) cc;
633 }
634
635 GdkColorContext *
636 gdk_color_context_new_mono (GdkVisual   *visual,
637                             GdkColormap *colormap)
638 {
639   GdkColorContextPrivate *ccp;
640   GdkColorContext *cc;
641   
642   g_assert (visual != NULL);
643   g_assert (colormap != NULL);
644   
645   cc = g_new (GdkColorContext, 1);
646   ccp = (GdkColorContextPrivate *) cc;
647   ccp->xdisplay = gdk_display;
648   cc->visual = visual;
649   cc->colormap = colormap;
650   cc->clut = NULL;
651   cc->cmap = NULL;
652   cc->mode = GDK_CC_MODE_UNDEFINED;
653   cc->need_to_free_colormap = FALSE;
654   
655   init_bw (cc);
656   
657   return (GdkColorContext *) cc;
658 }
659
660 /* This doesn't currently free black/white, hmm... */
661
662 void
663 gdk_color_context_free (GdkColorContext *cc)
664 {
665   g_assert (cc != NULL);
666   
667   if ((cc->visual->type == GDK_VISUAL_STATIC_COLOR)
668       || (cc->visual->type == GDK_VISUAL_PSEUDO_COLOR))
669     {
670       gdk_colors_free (cc->colormap, cc->clut, cc->num_allocated, 0);
671       g_free (cc->clut);
672     }
673   else if (cc->clut != NULL)
674     {
675       gdk_colors_free (cc->colormap, cc->clut, cc->num_colors, 0);
676       g_free (cc->clut);
677     }
678   
679   if (cc->cmap != NULL)
680     g_free (cc->cmap);
681   
682   if (cc->need_to_free_colormap)
683     gdk_colormap_unref (cc->colormap);
684   
685   /* free any palette that has been associated with this GdkColorContext */
686
687   init_palette (cc);
688   
689   g_free (cc);
690 }
691
692 gulong
693 gdk_color_context_get_pixel (GdkColorContext *cc,
694                              gushort          red,
695                              gushort          green,
696                              gushort          blue,
697                              gint            *failed)
698 {
699   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
700   g_assert (cc != NULL);
701   g_assert (failed != NULL);
702   
703   *failed = FALSE;
704   
705   switch (cc->mode)
706     {
707     case GDK_CC_MODE_BW:
708     {
709       gdouble value;
710       
711       value = (red / 65535.0 * 0.30
712                + green / 65535.0 * 0.59
713                + blue / 65535.0 * 0.11);
714       
715       if (value > 0.5)
716         return cc->white_pixel;
717       
718       return cc->black_pixel;
719     }
720     
721     case GDK_CC_MODE_MY_GRAY:
722     {
723       gulong ired, igreen, iblue;
724       
725       red   = red * 0.30 + green * 0.59 + blue * 0.11;
726       green = 0;
727       blue  = 0;
728       
729       if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff) > ccp->std_cmap.red_max)
730         ired = ccp->std_cmap.red_max;
731       
732       ired *= ccp->std_cmap.red_mult;
733       
734       if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff) > ccp->std_cmap.green_max)
735         igreen = ccp->std_cmap.green_max;
736       
737       igreen *= ccp->std_cmap.green_mult;
738       
739       if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff) > ccp->std_cmap.blue_max)
740         iblue = ccp->std_cmap.blue_max;
741       
742       iblue *= ccp->std_cmap.blue_mult;
743       
744       if (cc->clut != NULL)
745         return cc->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
746       
747       return ccp->std_cmap.base_pixel + ired + igreen + iblue;
748     }
749     
750     case GDK_CC_MODE_TRUE:
751     {
752       gulong ired, igreen, iblue;
753       
754       if (cc->clut == NULL)
755         {
756           red   >>= 16 - cc->bits.red;
757           green >>= 16 - cc->bits.green;
758           blue  >>= 16 - cc->bits.blue;
759           
760           ired   = (red << cc->shifts.red) & cc->masks.red;
761           igreen = (green << cc->shifts.green) & cc->masks.green;
762           iblue  = (blue << cc->shifts.blue) & cc->masks.blue;
763           
764           return ired | igreen | iblue;
765         }
766       
767       ired   = cc->clut[red * cc->max_entry / 65535] & cc->masks.red;
768       igreen = cc->clut[green * cc->max_entry / 65535] & cc->masks.green;
769       iblue  = cc->clut[blue * cc->max_entry / 65535] & cc->masks.blue;
770       
771       return ired | igreen | iblue;
772     }
773     
774     case GDK_CC_MODE_PALETTE:
775       return gdk_color_context_get_pixel_from_palette (cc, &red, &green, &blue, failed);
776       
777     case GDK_CC_MODE_STD_CMAP:
778     default:
779     {
780       GdkColor color;
781       GdkColor *result = NULL;
782       
783       color.red   = red;
784       color.green = green;
785       color.blue  = blue;
786
787       if (cc->color_hash)
788         result = g_hash_table_lookup (cc->color_hash, &color);
789       
790       if (!result)
791         {
792           color.red   = red;
793           color.green = green;
794           color.blue  = blue;
795           color.pixel = 0;
796           
797           if (!gdk_color_alloc (cc->colormap, &color))
798             *failed = TRUE;
799           else
800             {
801               GdkColor *cnew;
802               
803               /* XXX: the following comment comes directly from
804                * XCC.c.  I don't know if it is relevant for
805                * gdk_color_alloc() as it is for XAllocColor()
806                * - Federico
807                */
808               /*
809                * I can't figure this out entirely, but it *is* possible
810                * that XAllocColor succeeds, even if the number of
811                * allocations we've made exceeds the number of available
812                * colors in the current colormap. And therefore it
813                * might be necessary for us to resize the CLUT.
814                */
815               
816               if (cc->num_allocated == cc->max_colors)
817                 {
818                   cc->max_colors *= 2;
819                   
820                   GDK_NOTE (COLOR_CONTEXT,
821                             g_message ("gdk_color_context_get_pixel: "
822                                        "resizing CLUT to %i entries\n",
823                                        cc->max_colors));
824                   
825                   cc->clut = g_realloc (cc->clut,
826                                         cc->max_colors * sizeof (gulong));
827                 }
828               
829               /* Key and value are the same color structure */
830               
831               cnew = g_new (GdkColor, 1);
832               *cnew = color;
833               
834               if (!cc->color_hash)
835                 cc->color_hash = g_hash_table_new (hash_color, compare_colors);
836               g_hash_table_insert (cc->color_hash, cnew, cnew);
837               
838               cc->clut[cc->num_allocated] = color.pixel;
839               cc->num_allocated++;
840               return color.pixel;
841             }
842         }
843       
844       return result->pixel;
845     }
846     }
847 }
848
849 void
850 gdk_color_context_get_pixels (GdkColorContext *cc,
851                               gushort         *reds,
852                               gushort         *greens,
853                               gushort         *blues,
854                               gint             ncolors,
855                               gulong          *colors,
856                               gint            *nallocated)
857 {
858   gint i, k, idx;
859   gint cmapsize, ncols = 0, nopen = 0, counter = 0;
860   gint bad_alloc = FALSE;
861   gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
862   GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
863 #ifdef G_ENABLE_DEBUG  
864   gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
865 #endif
866   g_assert (cc != NULL);
867   g_assert (reds != NULL);
868   g_assert (greens != NULL);
869   g_assert (blues != NULL);
870   g_assert (colors != NULL);
871   g_assert (nallocated != NULL);
872   
873   memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
874   memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
875   memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
876   
877   /* Will only have a value if used by the progressive image loader */
878   
879   ncols = *nallocated;
880   
881   *nallocated = 0;
882   
883   /* First allocate all pixels */
884   
885   for (i = 0; i < ncolors; i++)
886     {
887       /* colors[i] is only zero if the pixel at that location hasn't
888        * been allocated yet.  This is a sanity check required for proper
889        * color allocation by the progressive image loader
890        */
891       
892       if (colors[i] == 0)
893         {
894           defs[i].red   = reds[i];
895           defs[i].green = greens[i];
896           defs[i].blue  = blues[i];
897           
898           colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i],
899                                                    &bad_alloc);
900           
901           /* successfully allocated, store it */
902           
903           if (!bad_alloc)
904             {
905               defs[i].pixel = colors[i];
906               allocated[ncols++] = colors[i];
907             }
908           else
909             failed[nopen++] = i;
910         }
911     }
912   
913   *nallocated = ncols;
914   
915   /* all colors available, all done */
916   
917   if ((ncols == ncolors) || (nopen == 0))
918     {
919       GDK_NOTE (COLOR_CONTEXT,
920                 g_message ("gdk_color_context_get_pixels: got all %i colors; "
921                            "(%i colors allocated so far)\n", ncolors, cc->num_allocated));
922       
923       return;
924     }
925   
926   /* The fun part.  We now try to allocate the colors we couldn't allocate
927    * directly.  The first step will map a color onto its nearest color
928    * that has been allocated (either by us or someone else).  If any colors
929    * remain unallocated, we map these onto the colors that we have allocated
930    * ourselves.
931    */
932   
933   /* read up to MAX_IMAGE_COLORS colors of the current colormap */
934   
935   cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
936   
937   /* see if the colormap has any colors to read */
938   
939   if (cmapsize < 0)
940     {
941       g_warning ("gdk_color_context_get_pixels: oops!  no colors available, "
942                  "your images will look *really* ugly.");
943       
944       return;
945     }
946   
947 #ifdef G_ENABLE_DEBUG
948   exact_col = ncols;
949 #endif
950   
951   /* initialize pixels */
952   
953   for (i = 0; i < cmapsize; i++)
954     {
955       cmap[i].pixel = i;
956       cmap[i].red = cmap[i].green = cmap[i].blue = 0;
957     }
958   
959   /* read the colormap */
960   
961   my_x_query_colors (cc->colormap, cmap, cmapsize);
962   
963   /* get a close match for any unallocated colors */
964   
965   counter = nopen;
966   nopen = 0;
967   idx = 0;
968   
969   do
970     {
971       gint d, j, mdist, close, ri, gi, bi;
972       gint rd, gd, bd;
973       
974       i = failed[idx];
975       
976       mdist = 0x1000000;
977       close = -1;
978       
979       /* Store these vals.  Small performance increase as this skips three
980        * indexing operations in the loop code.
981        */
982       
983       ri = reds[i];
984       gi = greens[i];
985       bi = blues[i];
986       
987       /* Walk all colors in the colormap and see which one is the
988        * closest.  Uses plain least squares.
989        */
990       
991       for (j = 0; (j < cmapsize) && (mdist != 0); j++)
992         {
993           /* Don't replace these by shifts; the sign may get clobbered */
994           
995           rd = (ri - cmap[j].red) / 256;
996           gd = (gi - cmap[j].green) / 256;
997           bd = (bi - cmap[j].blue) / 256;
998           
999           d = rd * rd + gd * gd + bd * bd;
1000           
1001           if (d < mdist)
1002             {
1003               close = j;
1004               mdist = d;
1005             }
1006         }
1007       
1008       if (close != -1)
1009         {
1010           rd = cmap[close].red;
1011           gd = cmap[close].green;
1012           bd = cmap[close].blue;
1013           
1014           /* allocate */
1015           
1016           colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1017           
1018           /* store */
1019           
1020           if (!bad_alloc)
1021             {
1022               defs[i] = cmap[close];
1023               defs[i].pixel = colors[i];
1024               allocated[ncols++] = colors[i];
1025 #ifdef G_ENABLE_DEBUG
1026               close_col++;
1027 #endif
1028             } else
1029               failed[nopen++] = i;
1030         } else
1031           failed[nopen++] = i;
1032       /* deal with in next stage if allocation failed */
1033     }
1034   while (++idx < counter);
1035   
1036   *nallocated = ncols;
1037   
1038   /* This is the maximum no. of allocated colors.  See also the nopen == 0
1039    * note above.
1040    */
1041   
1042   if ((ncols == ncolors) || (nopen == 0))
1043     {
1044       GDK_NOTE (COLOR_CONTEXT,
1045                 g_message ("gdk_color_context_get_pixels: got %i colors, %i exact and "
1046                            "%i close (%i colors allocated so far)\n",
1047                            ncolors, exact_col, close_col, cc->num_allocated));
1048       
1049       return;
1050     }
1051   
1052   /* Now map any remaining unallocated pixels into the colors we did get */
1053   
1054   idx = 0;
1055   
1056   do
1057     {
1058       gint d, mdist, close, ri, gi, bi;
1059       gint j, rd, gd, bd;
1060       
1061       i = failed[idx];
1062       
1063       mdist = 0x1000000;
1064       close = -1;
1065       
1066       /* store */
1067       
1068       ri = reds[i];
1069       gi = greens[i];
1070       bi = blues[i];
1071       
1072       /* search allocated colors */
1073       
1074       for (j = 0; (j < ncols) && (mdist != 0); j++)
1075         {
1076           k = allocated[j];
1077           
1078           /* Don't replace these by shifts; the sign may get clobbered */
1079           
1080           rd = (ri - defs[k].red) / 256;
1081           gd = (gi - defs[k].green) / 256;
1082           bd = (bi - defs[k].blue) / 256;
1083           
1084           d = rd * rd + gd * gd + bd * bd;
1085           
1086           if (d < mdist)
1087             {
1088               close = k;
1089               mdist = d;
1090             }
1091         }
1092       
1093       if (close < 0)
1094         {
1095           /* too bad, map to black */
1096           
1097           defs[i].pixel = cc->black_pixel;
1098           defs[i].red = defs[i].green = defs[i].blue = 0;
1099 #ifdef G_ENABLE_DEBUG
1100           black_col++;
1101 #endif
1102         }
1103       else
1104         {
1105           defs[i] = defs[close];
1106 #ifdef G_ENABLE_DEBUG
1107           subst_col++;
1108 #endif
1109         }
1110       
1111       colors[i] = defs[i].pixel;
1112     }
1113   while (++idx < nopen);
1114   
1115   GDK_NOTE (COLOR_CONTEXT,
1116             g_message ("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
1117                        "%i substituted, %i to black (%i colors allocated so far)\n",
1118                        ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1119 }
1120
1121 void
1122 gdk_color_context_get_pixels_incremental (GdkColorContext *cc,
1123                                           gushort         *reds,
1124                                           gushort         *greens,
1125                                           gushort         *blues,
1126                                           gint             ncolors,
1127                                           gint            *used,
1128                                           gulong          *colors,
1129                                           gint            *nallocated)
1130 {
1131   gint i, k, idx;
1132   gint cmapsize, ncols = 0, nopen = 0, counter = 0;
1133   gint bad_alloc = FALSE;
1134   gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
1135   GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
1136 #ifdef G_ENABLE_DEBUG  
1137   gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
1138 #endif  
1139   
1140   g_assert (cc != NULL);
1141   g_assert (reds != NULL);
1142   g_assert (greens != NULL);
1143   g_assert (blues != NULL);
1144   g_assert (used != NULL);
1145   g_assert (colors != NULL);
1146   g_assert (nallocated != NULL);
1147   
1148   memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
1149   memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
1150   memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
1151   
1152   /* Will only have a value if used by the progressive image loader */
1153   
1154   ncols = *nallocated;
1155   
1156   *nallocated = 0;
1157   
1158   /* First allocate all pixels */
1159   
1160   for (i = 0; i < ncolors; i++)
1161     {
1162       /* used[i] is only -1 if the pixel at that location hasn't
1163        * been allocated yet.  This is a sanity check required for proper
1164        * color allocation by the progressive image loader.
1165        * When colors[i] == 0 it indicates the slot is available for
1166        * allocation.
1167        */
1168       
1169       if (used[i] != FALSE)
1170         {
1171           if (colors[i] == 0)
1172             {
1173               defs[i].red   = reds[i];
1174               defs[i].green = greens[i];
1175               defs[i].blue  = blues[i];
1176               
1177               colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i], &bad_alloc);
1178               
1179               /* successfully allocated, store it */
1180               
1181               if (!bad_alloc)
1182                 {
1183                   defs[i].pixel = colors[i];
1184                   allocated[ncols++] = colors[i];
1185                 }
1186               else
1187                 failed[nopen++] = i;
1188             }
1189 #ifdef DEBUG
1190           else
1191             GDK_NOTE (COLOR_CONTEXT,
1192                       g_message ("gdk_color_context_get_pixels_incremental: "
1193                                  "pixel at slot %i already allocated, skipping\n", i));
1194 #endif
1195         }
1196     }
1197   
1198   *nallocated = ncols;
1199   
1200   if ((ncols == ncolors) || (nopen == 0))
1201     {
1202       GDK_NOTE (COLOR_CONTEXT,
1203                 g_message ("gdk_color_context_get_pixels_incremental: got all %i colors "
1204                            "(%i colors allocated so far)\n",
1205                            ncolors, cc->num_allocated));
1206       
1207       return;
1208     }
1209   
1210   cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
1211   
1212   if (cmapsize < 0)
1213     {
1214       g_warning ("gdk_color_context_get_pixels_incremental: oops!  "
1215                  "No colors available images will look *really* ugly.");
1216       return;
1217     }
1218   
1219 #ifdef G_ENABLE_DEBUG
1220   exact_col = ncols;
1221 #endif
1222   
1223   /* initialize pixels */
1224   
1225   for (i = 0; i < cmapsize; i++)
1226     {
1227       cmap[i].pixel = i;
1228       cmap[i].red = cmap[i].green = cmap[i].blue = 0;
1229     }
1230   
1231   /* read */
1232   
1233   my_x_query_colors (cc->colormap, cmap, cmapsize);
1234   
1235   /* now match any unallocated colors */
1236   
1237   counter = nopen;
1238   nopen = 0;
1239   idx = 0;
1240   
1241   do
1242     {
1243       gint d, j, mdist, close, ri, gi, bi;
1244       gint rd, gd, bd;
1245       
1246       i = failed[idx];
1247       
1248       mdist = 0x1000000;
1249       close = -1;
1250       
1251       /* store */
1252       
1253       ri = reds[i];
1254       gi = greens[i];
1255       bi = blues[i];
1256       
1257       for (j = 0; (j < cmapsize) && (mdist != 0); j++)
1258         {
1259           /* Don't replace these by shifts; the sign may get clobbered */
1260           
1261           rd = (ri - cmap[j].red) / 256;
1262           gd = (gi - cmap[j].green) / 256;
1263           bd = (bi - cmap[j].blue) / 256;
1264           
1265           d = rd * rd + gd * gd + bd * bd;
1266           
1267           if (d < mdist)
1268             {
1269               close = j;
1270               mdist = d;
1271             }
1272         }
1273       
1274       if (close != -1)
1275         {
1276           rd = cmap[close].red;
1277           gd = cmap[close].green;
1278           bd = cmap[close].blue;
1279           
1280           /* allocate */
1281           
1282           colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1283           
1284           /* store */
1285           
1286           if (!bad_alloc)
1287             {
1288               defs[i] = cmap[close];
1289               defs[i].pixel = colors[i];
1290               allocated[ncols++] = colors[i];
1291 #ifdef G_ENABLE_DEBUG
1292               close_col++;
1293 #endif
1294             }
1295           else
1296             failed[nopen++] = i;
1297         }
1298       else
1299         failed[nopen++] = i;
1300       /* deal with in next stage if allocation failed */
1301     }
1302   while (++idx < counter);
1303   
1304   *nallocated = ncols;
1305   
1306   if ((ncols == ncolors) || (nopen == 0))
1307     {
1308       GDK_NOTE (COLOR_CONTEXT,
1309                 g_message ("gdk_color_context_get_pixels_incremental: "
1310                            "got %i colors, %i exact and %i close "
1311                            "(%i colors allocated so far)\n",
1312                            ncolors, exact_col, close_col, cc->num_allocated));
1313       
1314       return;
1315     }
1316   
1317   /* map remaining unallocated pixels into colors we did get */
1318   
1319   idx = 0;
1320   
1321   do
1322     {
1323       gint d, mdist, close, ri, gi, bi;
1324       gint j, rd, gd, bd;
1325       
1326       i = failed[idx];
1327       
1328       mdist = 0x1000000;
1329       close = -1;
1330       
1331       ri = reds[i];
1332       gi = greens[i];
1333       bi = blues[i];
1334       
1335       /* search allocated colors */
1336       
1337       for (j = 0; (j < ncols) && (mdist != 0); j++)
1338         {
1339           k = allocated[j];
1340           
1341           /* downscale */
1342           /* Don't replace these by shifts; the sign may get clobbered */
1343           
1344           rd = (ri - defs[k].red) / 256;
1345           gd = (gi - defs[k].green) / 256;
1346           bd = (bi - defs[k].blue) / 256;
1347           
1348           d = rd * rd + gd * gd + bd * bd;
1349           
1350           if (d < mdist)
1351             {
1352               close = k;
1353               mdist = d;
1354             }
1355         }
1356       
1357       if (close < 0)
1358         {
1359           /* too bad, map to black */
1360           
1361           defs[i].pixel = cc->black_pixel;
1362           defs[i].red = defs[i].green = defs[i].blue = 0;
1363 #ifdef G_ENABLE_DEBUG
1364           black_col++;
1365 #endif
1366         }
1367       else
1368         {
1369           defs[i] = defs[close];
1370 #ifdef G_ENABLE_DEBUG
1371           subst_col++;
1372 #endif
1373         }
1374       
1375       colors[i] = defs[i].pixel;
1376     }
1377   while (++idx < nopen);
1378   
1379   GDK_NOTE (COLOR_CONTEXT,
1380             g_message ("gdk_color_context_get_pixels_incremental: "
1381                        "got %i colors, %i exact, %i close, %i substituted, %i to black "
1382                        "(%i colors allocated so far)\n",
1383                        ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1384 }
1385
1386 gint
1387 gdk_color_context_query_color (GdkColorContext *cc,
1388                                GdkColor        *color)
1389 {
1390   return gdk_color_context_query_colors (cc, color, 1);
1391 }
1392
1393 gint
1394 gdk_color_context_query_colors (GdkColorContext *cc,
1395                                 GdkColor        *colors,
1396                                 gint             num_colors)
1397 {
1398   gint i;
1399   GdkColor *tc;
1400   
1401   g_assert (cc != NULL);
1402   g_assert (colors != NULL);
1403   
1404   switch (cc->mode)
1405     {
1406     case GDK_CC_MODE_BW:
1407       for (i = 0, tc = colors; i < num_colors; i++, tc++)
1408         {
1409           if (tc->pixel == cc->white_pixel)
1410             tc->red = tc->green = tc->blue = 65535;
1411           else
1412             tc->red = tc->green = tc->blue = 0;
1413         }
1414       break;
1415       
1416     case GDK_CC_MODE_TRUE:
1417       if (cc->clut == NULL)
1418         for (i = 0, tc = colors; i < num_colors; i++, tc++)
1419           {
1420             tc->red   = ((tc->pixel & cc->masks.red) >> cc->shifts.red) << (16 - cc->bits.red);
1421             tc->green = ((tc->pixel & cc->masks.green) >> cc->shifts.green) << (16 - cc->bits.green);
1422             tc->blue  = ((tc->pixel & cc->masks.blue) >> cc->shifts.blue) << (16 - cc->bits.blue);
1423           }
1424       else
1425         {
1426           my_x_query_colors (cc->colormap, colors, num_colors);
1427           return 1;
1428         }
1429       break;
1430       
1431     case GDK_CC_MODE_STD_CMAP:
1432     default:
1433       if (cc->cmap == NULL)
1434         {
1435           my_x_query_colors (cc->colormap, colors, num_colors);
1436           return 1;
1437         }
1438       else
1439         {
1440           gint first, last, half;
1441           gulong half_pixel;
1442           
1443           for (i = 0, tc = colors; i < num_colors; i++)
1444             {
1445               first = 0;
1446               last = cc->num_colors - 1;
1447               
1448               while (first <= last)
1449                 {
1450                   half = (first + last) / 2;
1451                   half_pixel = cc->cmap[half].pixel;
1452                   
1453                   if (tc->pixel == half_pixel)
1454                     {
1455                       tc->red   = cc->cmap[half].red;
1456                       tc->green = cc->cmap[half].green;
1457                       tc->blue  = cc->cmap[half].blue;
1458                       first = last + 1; /* false break */
1459                     }
1460                   else
1461                     {
1462                       if (tc->pixel > half_pixel)
1463                         first = half + 1;
1464                       else
1465                         last = half - 1;
1466                     }
1467                 }
1468             }
1469           return 1;
1470         }
1471       break;
1472     }
1473   return 1;
1474 }
1475
1476 gint
1477 gdk_color_context_add_palette (GdkColorContext *cc,
1478                                GdkColor        *palette,
1479                                gint             num_palette)
1480 {
1481   gint i, j, erg;
1482   gushort r, g, b;
1483   gulong pixel[1];
1484   
1485   g_assert (cc != NULL);
1486   
1487   /* initialize this palette (will also erase previous palette as well) */
1488   
1489   init_palette (cc);
1490   
1491   /* restore previous mode if we aren't adding a new palette */
1492   
1493   if (num_palette == 0)
1494     return 0;
1495   
1496   /* copy incoming palette */
1497   
1498   cc->palette = g_new0(GdkColor, num_palette);
1499   
1500   j = 0;
1501   
1502   for (i = 0; i < num_palette; i++)
1503     {
1504       erg = 0;
1505       pixel[0] = 0;
1506       
1507       /* try to allocate this color */
1508       
1509       r = palette[i].red;
1510       g = palette[i].green;
1511       b = palette[i].blue;
1512       
1513       gdk_color_context_get_pixels (cc, &r, &g, &b, 1, pixel, &erg);
1514       
1515       /* only store if we succeed */
1516       
1517       if (erg)
1518         {
1519           /* store in palette */
1520           
1521           cc->palette[j].red   = r;
1522           cc->palette[j].green = g;
1523           cc->palette[j].blue  = b;
1524           cc->palette[j].pixel = pixel[0];
1525           
1526           /* move to next slot */
1527           
1528           j++;
1529         }
1530     }
1531   
1532   /* resize to fit */
1533   
1534   if (j != num_palette)
1535     cc->palette = g_realloc (cc->palette, j * sizeof (GdkColor));
1536   
1537   /* clear the hash table, we don't use it when dithering */
1538   
1539   if (cc->color_hash)
1540     {
1541       g_hash_table_foreach (cc->color_hash,
1542                             free_hash_entry,
1543                             NULL);
1544       g_hash_table_destroy (cc->color_hash);
1545       cc->color_hash = NULL;
1546     }
1547   
1548   /* store real palette size */
1549   
1550   cc->num_palette = j;
1551   
1552   /* switch to palette mode */
1553   
1554   cc->mode = GDK_CC_MODE_PALETTE;
1555   
1556   /* sort palette */
1557   
1558   qsort (cc->palette, cc->num_palette, sizeof (GdkColor), pixel_sort);
1559   
1560   cc->fast_dither = NULL;
1561   
1562   return j;
1563 }
1564
1565 void
1566 gdk_color_context_init_dither (GdkColorContext *cc)
1567 {
1568   gint rr, gg, bb, err, erg, erb;
1569   gint success = FALSE;
1570   
1571   g_assert (cc != NULL);
1572   
1573   /* now we can initialize the fast dither matrix */
1574   
1575   if (cc->fast_dither == NULL)
1576     cc->fast_dither = g_new (GdkColorContextDither, 1);
1577   
1578   /* Fill it.  We ignore unsuccessful allocations, they are just mapped
1579    * to black instead */
1580   
1581   for (rr = 0; rr < 32; rr++)
1582     for (gg = 0; gg < 32; gg++)
1583       for (bb = 0; bb < 32; bb++)
1584         {
1585           err = (rr << 3) | (rr >> 2);
1586           erg = (gg << 3) | (gg >> 2);
1587           erb = (bb << 3) | (bb >> 2);
1588           
1589           cc->fast_dither->fast_rgb[rr][gg][bb] =
1590             gdk_color_context_get_index_from_palette (cc, &err, &erg, &erb, &success);
1591           cc->fast_dither->fast_err[rr][gg][bb] = err;
1592           cc->fast_dither->fast_erg[rr][gg][bb] = erg;
1593           cc->fast_dither->fast_erb[rr][gg][bb] = erb;
1594         }
1595 }
1596
1597 void
1598 gdk_color_context_free_dither (GdkColorContext *cc)
1599 {
1600   g_assert (cc != NULL);
1601   
1602   if (cc->fast_dither)
1603     g_free (cc->fast_dither);
1604   
1605   cc->fast_dither = NULL;
1606 }
1607
1608 gulong
1609 gdk_color_context_get_pixel_from_palette (GdkColorContext *cc,
1610                                           gushort         *red,
1611                                           gushort         *green,
1612                                           gushort         *blue,
1613                                           gint            *failed)
1614 {
1615   gulong pixel = 0;
1616   gint dif, dr, dg, db, j = -1;
1617   gint mindif = 0x7fffffff;
1618   gint err = 0, erg = 0, erb = 0;
1619   gint i;
1620   
1621   g_assert (cc != NULL);
1622   g_assert (red != NULL);
1623   g_assert (green != NULL);
1624   g_assert (blue != NULL);
1625   g_assert (failed != NULL);
1626   
1627   *failed = FALSE;
1628   
1629   for (i = 0; i < cc->num_palette; i++)
1630     {
1631       dr = *red - cc->palette[i].red;
1632       dg = *green - cc->palette[i].green;
1633       db = *blue - cc->palette[i].blue;
1634       
1635       dif = dr * dr + dg * dg + db * db;
1636       
1637       if (dif < mindif)
1638         {
1639           mindif = dif;
1640           j = i;
1641           pixel = cc->palette[i].pixel;
1642           err = dr;
1643           erg = dg;
1644           erb = db;
1645           
1646           if (mindif == 0)
1647             break;
1648         }
1649     }
1650   
1651   /* we failed to map onto a color */
1652   
1653   if (j == -1)
1654     *failed = TRUE;
1655   else
1656     {
1657       *red   = ABS (err);
1658       *green = ABS (erg);
1659       *blue  = ABS (erb);
1660     }
1661   
1662   return pixel;
1663 }
1664
1665 guchar
1666 gdk_color_context_get_index_from_palette (GdkColorContext *cc,
1667                                           gint            *red,
1668                                           gint            *green,
1669                                           gint            *blue,
1670                                           gint            *failed)
1671 {
1672   gint dif, dr, dg, db, j = -1;
1673   gint mindif = 0x7fffffff;
1674   gint err = 0, erg = 0, erb = 0;
1675   gint i;
1676   
1677   g_assert (cc != NULL);
1678   g_assert (red != NULL);
1679   g_assert (green != NULL);
1680   g_assert (blue != NULL);
1681   g_assert (failed != NULL);
1682   
1683   *failed = FALSE;
1684   
1685   for (i = 0; i < cc->num_palette; i++)
1686     {
1687       dr = *red - cc->palette[i].red;
1688       dg = *green - cc->palette[i].green;
1689       db = *blue - cc->palette[i].blue;
1690       
1691       dif = dr * dr + dg * dg + db * db;
1692       
1693       if (dif < mindif)
1694         {
1695           mindif = dif;
1696           j = i;
1697           err = dr;
1698           erg = dg;
1699           erb = db;
1700           
1701           if (mindif == 0)
1702             break;
1703         }
1704     }
1705   
1706   /* we failed to map onto a color */
1707   
1708   if (j == -1)
1709     {
1710       *failed = TRUE;
1711       j = 0;
1712     }
1713   else
1714     {
1715       /* return error fractions */
1716       
1717       *red   = err;
1718       *green = erg;
1719       *blue  = erb;
1720     }
1721   
1722   return j;
1723 }