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