]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkcc-x11.c
573b2efa15465b1780229fe568f7a60443e674eb
[~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       /* XXX: quick-and-dirty way to remove everything */
495       
496       g_hash_table_destroy (cc->color_hash);
497       cc->color_hash = g_hash_table_new (hash_color, compare_colors);
498     }
499   
500   cc->palette = NULL;
501   cc->num_palette = 0;
502   cc->fast_dither = NULL;
503 }
504
505 GdkColorContext *
506 gdk_color_context_new (GdkVisual   *visual,
507                        GdkColormap *colormap)
508 {
509   GdkColorContextPrivate *ccp;
510   gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
511   GdkColorContext *cc;
512   gint retry_count;
513   GdkColormap *default_colormap;
514   
515   g_assert (visual != NULL);
516   g_assert (colormap != NULL);
517   
518   ccp = g_new (GdkColorContextPrivate, 1);
519   cc = (GdkColorContext *) ccp;
520   ccp->xdisplay = gdk_display;
521   cc->visual = visual;
522   cc->colormap = colormap;
523   cc->clut = NULL;
524   cc->cmap = NULL;
525   cc->mode = GDK_CC_MODE_UNDEFINED;
526   cc->need_to_free_colormap = FALSE;
527   
528   cc->color_hash = NULL;
529   cc->palette = NULL;
530   cc->num_palette = 0;
531   cc->fast_dither = NULL;
532   
533   default_colormap = gdk_colormap_get_system ();
534   
535   retry_count = 0;
536   
537   while (retry_count < 2)
538     {
539       /* Only create a private colormap if the visual found isn't equal
540        * to the default visual and we don't have a private colormap,
541        * -or- if we are instructed to create a private colormap (which
542        * never is the case for XmHTML).
543        */
544       
545       if (use_private_colormap
546           || ((cc->visual != gdk_visual_get_system ()) /* default visual? */
547               && (GDK_COLORMAP_XCOLORMAP (colormap) == GDK_COLORMAP_XCOLORMAP (default_colormap))))
548         {
549           g_warning ("gdk_color_context_new: non-default visual detected, "
550                      "using private colormap");
551           
552           cc->colormap = gdk_colormap_new (cc->visual, FALSE);
553           
554           cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP (colormap)
555                                        != GDK_COLORMAP_XCOLORMAP (default_colormap));
556         }
557       
558       switch (visual->type)
559         {
560         case GDK_VISUAL_STATIC_GRAY:
561         case GDK_VISUAL_GRAYSCALE:
562           GDK_NOTE (COLOR_CONTEXT,
563                     g_message ("gdk_color_context_new: visual class is %s\n",
564                                (visual->type == GDK_VISUAL_STATIC_GRAY) ?
565                                "GDK_VISUAL_STATIC_GRAY" :
566                                "GDK_VISUAL_GRAYSCALE"));
567           
568           if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
569             init_bw (cc);
570           else
571             init_gray (cc);
572           
573           break;
574           
575         case GDK_VISUAL_TRUE_COLOR: /* shifts */
576           GDK_NOTE (COLOR_CONTEXT,
577                     g_message ("gdk_color_context_new: visual class is GDK_VISUAL_TRUE_COLOR\n"));
578           
579           init_true_color (cc);
580           break;
581           
582         case GDK_VISUAL_DIRECT_COLOR: /* shifts and fake CLUT */
583           GDK_NOTE (COLOR_CONTEXT,
584                     g_message ("gdk_color_context_new: visual class is GDK_VISUAL_DIRECT_COLOR\n"));
585           
586           init_direct_color (cc);
587           break;
588           
589         case GDK_VISUAL_STATIC_COLOR:
590         case GDK_VISUAL_PSEUDO_COLOR:
591           GDK_NOTE (COLOR_CONTEXT,
592                     g_message ("gdk_color_context_new: visual class is %s\n",
593                                (visual->type == GDK_VISUAL_STATIC_COLOR) ?
594                                "GDK_VISUAL_STATIC_COLOR" :
595                                "GDK_VISUAL_PSEUDO_COLOR"));
596           
597           init_color (cc);
598           break;
599           
600         default:
601           g_assert_not_reached ();
602         }
603       
604       if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1))
605         {
606           use_private_colormap = TRUE;
607           retry_count++;
608         }
609       else
610         break;
611     }
612   
613   /* no. of colors allocated yet */
614   
615   cc->num_allocated = 0;
616   
617   GDK_NOTE (COLOR_CONTEXT,
618             g_message ("gdk_color_context_new: screen depth is %i, no. of colors is %i\n",
619                        cc->visual->depth, cc->num_colors));
620   
621   /* check if we need to initialize a hash table */
622   
623   if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED))
624     cc->color_hash = g_hash_table_new (hash_color, compare_colors);
625   
626   return (GdkColorContext *) cc;
627 }
628
629 GdkColorContext *
630 gdk_color_context_new_mono (GdkVisual   *visual,
631                             GdkColormap *colormap)
632 {
633   GdkColorContextPrivate *ccp;
634   GdkColorContext *cc;
635   
636   g_assert (visual != NULL);
637   g_assert (colormap != NULL);
638   
639   cc = g_new (GdkColorContext, 1);
640   ccp = (GdkColorContextPrivate *) cc;
641   ccp->xdisplay = gdk_display;
642   cc->visual = visual;
643   cc->colormap = colormap;
644   cc->clut = NULL;
645   cc->cmap = NULL;
646   cc->mode = GDK_CC_MODE_UNDEFINED;
647   cc->need_to_free_colormap = FALSE;
648   
649   init_bw (cc);
650   
651   return (GdkColorContext *) cc;
652 }
653
654 /* This doesn't currently free black/white, hmm... */
655
656 void
657 gdk_color_context_free (GdkColorContext *cc)
658 {
659   g_assert (cc != NULL);
660   
661   if ((cc->visual->type == GDK_VISUAL_STATIC_COLOR)
662       || (cc->visual->type == GDK_VISUAL_PSEUDO_COLOR))
663     {
664       gdk_colors_free (cc->colormap, cc->clut, cc->num_allocated, 0);
665       g_free (cc->clut);
666     }
667   else if (cc->clut != NULL)
668     {
669       gdk_colors_free (cc->colormap, cc->clut, cc->num_colors, 0);
670       g_free (cc->clut);
671     }
672   
673   if (cc->cmap != NULL)
674     g_free (cc->cmap);
675   
676   if (cc->need_to_free_colormap)
677     gdk_colormap_unref (cc->colormap);
678   
679   /* free any palette that has been associated with this GdkColorContext */
680   
681   init_palette (cc);
682   
683   if (cc->color_hash)
684     {
685       g_hash_table_foreach (cc->color_hash,
686                             free_hash_entry,
687                             NULL);
688       g_hash_table_destroy (cc->color_hash);
689     }
690   
691   g_free (cc);
692 }
693
694 gulong
695 gdk_color_context_get_pixel (GdkColorContext *cc,
696                              gushort          red,
697                              gushort          green,
698                              gushort          blue,
699                              gint            *failed)
700 {
701   GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
702   g_assert (cc != NULL);
703   g_assert (failed != NULL);
704   
705   *failed = FALSE;
706   
707   switch (cc->mode)
708     {
709     case GDK_CC_MODE_BW:
710     {
711       gdouble value;
712       
713       value = (red / 65535.0 * 0.30
714                + green / 65535.0 * 0.59
715                + blue / 65535.0 * 0.11);
716       
717       if (value > 0.5)
718         return cc->white_pixel;
719       
720       return cc->black_pixel;
721     }
722     
723     case GDK_CC_MODE_MY_GRAY:
724     {
725       gulong ired, igreen, iblue;
726       
727       red   = red * 0.30 + green * 0.59 + blue * 0.11;
728       green = 0;
729       blue  = 0;
730       
731       if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff) > ccp->std_cmap.red_max)
732         ired = ccp->std_cmap.red_max;
733       
734       ired *= ccp->std_cmap.red_mult;
735       
736       if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff) > ccp->std_cmap.green_max)
737         igreen = ccp->std_cmap.green_max;
738       
739       igreen *= ccp->std_cmap.green_mult;
740       
741       if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff) > ccp->std_cmap.blue_max)
742         iblue = ccp->std_cmap.blue_max;
743       
744       iblue *= ccp->std_cmap.blue_mult;
745       
746       if (cc->clut != NULL)
747         return cc->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
748       
749       return ccp->std_cmap.base_pixel + ired + igreen + iblue;
750     }
751     
752     case GDK_CC_MODE_TRUE:
753     {
754       gulong ired, igreen, iblue;
755       
756       if (cc->clut == NULL)
757         {
758           red   >>= 16 - cc->bits.red;
759           green >>= 16 - cc->bits.green;
760           blue  >>= 16 - cc->bits.blue;
761           
762           ired   = (red << cc->shifts.red) & cc->masks.red;
763           igreen = (green << cc->shifts.green) & cc->masks.green;
764           iblue  = (blue << cc->shifts.blue) & cc->masks.blue;
765           
766           return ired | igreen | iblue;
767         }
768       
769       ired   = cc->clut[red * cc->max_entry / 65535] & cc->masks.red;
770       igreen = cc->clut[green * cc->max_entry / 65535] & cc->masks.green;
771       iblue  = cc->clut[blue * cc->max_entry / 65535] & cc->masks.blue;
772       
773       return ired | igreen | iblue;
774     }
775     
776     case GDK_CC_MODE_PALETTE:
777       return gdk_color_context_get_pixel_from_palette (cc, &red, &green, &blue, failed);
778       
779     case GDK_CC_MODE_STD_CMAP:
780     default:
781     {
782       GdkColor color;
783       GdkColor *result;
784       
785       color.red   = red;
786       color.green = green;
787       color.blue  = blue;
788       
789       result = g_hash_table_lookup (cc->color_hash, &color);
790       
791       if (!result)
792         {
793           color.red   = red;
794           color.green = green;
795           color.blue  = blue;
796           color.pixel = 0;
797           
798           if (!gdk_color_alloc (cc->colormap, &color))
799             *failed = TRUE;
800           else
801             {
802               GdkColor *cnew;
803               
804               /* XXX: the following comment comes directly from
805                * XCC.c.  I don't know if it is relevant for
806                * gdk_color_alloc() as it is for XAllocColor()
807                * - Federico
808                */
809               /*
810                * I can't figure this out entirely, but it *is* possible
811                * that XAllocColor succeeds, even if the number of
812                * allocations we've made exceeds the number of available
813                * colors in the current colormap. And therefore it
814                * might be necessary for us to resize the CLUT.
815                */
816               
817               if (cc->num_allocated == cc->max_colors)
818                 {
819                   cc->max_colors *= 2;
820                   
821                   GDK_NOTE (COLOR_CONTEXT,
822                             g_message ("gdk_color_context_get_pixel: "
823                                        "resizing CLUT to %i entries\n",
824                                        cc->max_colors));
825                   
826                   cc->clut = g_realloc (cc->clut,
827                                         cc->max_colors * sizeof (gulong));
828                 }
829               
830               /* Key and value are the same color structure */
831               
832               cnew = g_new (GdkColor, 1);
833               *cnew = color;
834               g_hash_table_insert (cc->color_hash, cnew, cnew);
835               
836               cc->clut[cc->num_allocated] = color.pixel;
837               cc->num_allocated++;
838               return color.pixel;
839             }
840         }
841       
842       return result->pixel;
843     }
844     }
845 }
846
847 void
848 gdk_color_context_get_pixels (GdkColorContext *cc,
849                               gushort         *reds,
850                               gushort         *greens,
851                               gushort         *blues,
852                               gint             ncolors,
853                               gulong          *colors,
854                               gint            *nallocated)
855 {
856   gint i, k, idx;
857   gint cmapsize, ncols = 0, nopen = 0, counter = 0;
858   gint bad_alloc = FALSE;
859   gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
860   GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
861 #ifdef G_ENABLE_DEBUG  
862   gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
863 #endif
864   g_assert (cc != NULL);
865   g_assert (reds != NULL);
866   g_assert (greens != NULL);
867   g_assert (blues != NULL);
868   g_assert (colors != NULL);
869   g_assert (nallocated != NULL);
870   
871   memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
872   memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
873   memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
874   
875   /* Will only have a value if used by the progressive image loader */
876   
877   ncols = *nallocated;
878   
879   *nallocated = 0;
880   
881   /* First allocate all pixels */
882   
883   for (i = 0; i < ncolors; i++)
884     {
885       /* colors[i] is only zero if the pixel at that location hasn't
886        * been allocated yet.  This is a sanity check required for proper
887        * color allocation by the progressive image loader
888        */
889       
890       if (colors[i] == 0)
891         {
892           defs[i].red   = reds[i];
893           defs[i].green = greens[i];
894           defs[i].blue  = blues[i];
895           
896           colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i],
897                                                    &bad_alloc);
898           
899           /* successfully allocated, store it */
900           
901           if (!bad_alloc)
902             {
903               defs[i].pixel = colors[i];
904               allocated[ncols++] = colors[i];
905             }
906           else
907             failed[nopen++] = i;
908         }
909     }
910   
911   *nallocated = ncols;
912   
913   /* all colors available, all done */
914   
915   if ((ncols == ncolors) || (nopen == 0))
916     {
917       GDK_NOTE (COLOR_CONTEXT,
918                 g_message ("gdk_color_context_get_pixels: got all %i colors; "
919                            "(%i colors allocated so far)\n", ncolors, cc->num_allocated));
920       
921       return;
922     }
923   
924   /* The fun part.  We now try to allocate the colors we couldn't allocate
925    * directly.  The first step will map a color onto its nearest color
926    * that has been allocated (either by us or someone else).  If any colors
927    * remain unallocated, we map these onto the colors that we have allocated
928    * ourselves.
929    */
930   
931   /* read up to MAX_IMAGE_COLORS colors of the current colormap */
932   
933   cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
934   
935   /* see if the colormap has any colors to read */
936   
937   if (cmapsize < 0)
938     {
939       g_warning ("gdk_color_context_get_pixels: oops!  no colors available, "
940                  "your images will look *really* ugly.");
941       
942       return;
943     }
944   
945 #ifdef G_ENABLE_DEBUG
946   exact_col = ncols;
947 #endif
948   
949   /* initialize pixels */
950   
951   for (i = 0; i < cmapsize; i++)
952     {
953       cmap[i].pixel = i;
954       cmap[i].red = cmap[i].green = cmap[i].blue = 0;
955     }
956   
957   /* read the colormap */
958   
959   my_x_query_colors (cc->colormap, cmap, cmapsize);
960   
961   /* get a close match for any unallocated colors */
962   
963   counter = nopen;
964   nopen = 0;
965   idx = 0;
966   
967   do
968     {
969       gint d, j, mdist, close, ri, gi, bi;
970       gint rd, gd, bd;
971       
972       i = failed[idx];
973       
974       mdist = 0x1000000;
975       close = -1;
976       
977       /* Store these vals.  Small performance increase as this skips three
978        * indexing operations in the loop code.
979        */
980       
981       ri = reds[i];
982       gi = greens[i];
983       bi = blues[i];
984       
985       /* Walk all colors in the colormap and see which one is the
986        * closest.  Uses plain least squares.
987        */
988       
989       for (j = 0; (j < cmapsize) && (mdist != 0); j++)
990         {
991           /* Don't replace these by shifts; the sign may get clobbered */
992           
993           rd = (ri - cmap[j].red) / 256;
994           gd = (gi - cmap[j].green) / 256;
995           bd = (bi - cmap[j].blue) / 256;
996           
997           d = rd * rd + gd * gd + bd * bd;
998           
999           if (d < mdist)
1000             {
1001               close = j;
1002               mdist = d;
1003             }
1004         }
1005       
1006       if (close != -1)
1007         {
1008           rd = cmap[close].red;
1009           gd = cmap[close].green;
1010           bd = cmap[close].blue;
1011           
1012           /* allocate */
1013           
1014           colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1015           
1016           /* store */
1017           
1018           if (!bad_alloc)
1019             {
1020               defs[i] = cmap[close];
1021               defs[i].pixel = colors[i];
1022               allocated[ncols++] = colors[i];
1023 #ifdef G_ENABLE_DEBUG
1024               close_col++;
1025 #endif
1026             } else
1027               failed[nopen++] = i;
1028         } else
1029           failed[nopen++] = i;
1030       /* deal with in next stage if allocation failed */
1031     }
1032   while (++idx < counter);
1033   
1034   *nallocated = ncols;
1035   
1036   /* This is the maximum no. of allocated colors.  See also the nopen == 0
1037    * note above.
1038    */
1039   
1040   if ((ncols == ncolors) || (nopen == 0))
1041     {
1042       GDK_NOTE (COLOR_CONTEXT,
1043                 g_message ("gdk_color_context_get_pixels: got %i colors, %i exact and "
1044                            "%i close (%i colors allocated so far)\n",
1045                            ncolors, exact_col, close_col, cc->num_allocated));
1046       
1047       return;
1048     }
1049   
1050   /* Now map any remaining unallocated pixels into the colors we did get */
1051   
1052   idx = 0;
1053   
1054   do
1055     {
1056       gint d, mdist, close, ri, gi, bi;
1057       gint j, rd, gd, bd;
1058       
1059       i = failed[idx];
1060       
1061       mdist = 0x1000000;
1062       close = -1;
1063       
1064       /* store */
1065       
1066       ri = reds[i];
1067       gi = greens[i];
1068       bi = blues[i];
1069       
1070       /* search allocated colors */
1071       
1072       for (j = 0; (j < ncols) && (mdist != 0); j++)
1073         {
1074           k = allocated[j];
1075           
1076           /* Don't replace these by shifts; the sign may get clobbered */
1077           
1078           rd = (ri - defs[k].red) / 256;
1079           gd = (gi - defs[k].green) / 256;
1080           bd = (bi - defs[k].blue) / 256;
1081           
1082           d = rd * rd + gd * gd + bd * bd;
1083           
1084           if (d < mdist)
1085             {
1086               close = k;
1087               mdist = d;
1088             }
1089         }
1090       
1091       if (close < 0)
1092         {
1093           /* too bad, map to black */
1094           
1095           defs[i].pixel = cc->black_pixel;
1096           defs[i].red = defs[i].green = defs[i].blue = 0;
1097 #ifdef G_ENABLE_DEBUG
1098           black_col++;
1099 #endif
1100         }
1101       else
1102         {
1103           defs[i] = defs[close];
1104 #ifdef G_ENABLE_DEBUG
1105           subst_col++;
1106 #endif
1107         }
1108       
1109       colors[i] = defs[i].pixel;
1110     }
1111   while (++idx < nopen);
1112   
1113   GDK_NOTE (COLOR_CONTEXT,
1114             g_message ("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
1115                        "%i substituted, %i to black (%i colors allocated so far)\n",
1116                        ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1117 }
1118
1119 void
1120 gdk_color_context_get_pixels_incremental (GdkColorContext *cc,
1121                                           gushort         *reds,
1122                                           gushort         *greens,
1123                                           gushort         *blues,
1124                                           gint             ncolors,
1125                                           gint            *used,
1126                                           gulong          *colors,
1127                                           gint            *nallocated)
1128 {
1129   gint i, k, idx;
1130   gint cmapsize, ncols = 0, nopen = 0, counter = 0;
1131   gint bad_alloc = FALSE;
1132   gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
1133   GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
1134 #ifdef G_ENABLE_DEBUG  
1135   gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
1136 #endif  
1137   
1138   g_assert (cc != NULL);
1139   g_assert (reds != NULL);
1140   g_assert (greens != NULL);
1141   g_assert (blues != NULL);
1142   g_assert (used != NULL);
1143   g_assert (colors != NULL);
1144   g_assert (nallocated != NULL);
1145   
1146   memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
1147   memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
1148   memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
1149   
1150   /* Will only have a value if used by the progressive image loader */
1151   
1152   ncols = *nallocated;
1153   
1154   *nallocated = 0;
1155   
1156   /* First allocate all pixels */
1157   
1158   for (i = 0; i < ncolors; i++)
1159     {
1160       /* used[i] is only -1 if the pixel at that location hasn't
1161        * been allocated yet.  This is a sanity check required for proper
1162        * color allocation by the progressive image loader.
1163        * When colors[i] == 0 it indicates the slot is available for
1164        * allocation.
1165        */
1166       
1167       if (used[i] != FALSE)
1168         {
1169           if (colors[i] == 0)
1170             {
1171               defs[i].red   = reds[i];
1172               defs[i].green = greens[i];
1173               defs[i].blue  = blues[i];
1174               
1175               colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i], &bad_alloc);
1176               
1177               /* successfully allocated, store it */
1178               
1179               if (!bad_alloc)
1180                 {
1181                   defs[i].pixel = colors[i];
1182                   allocated[ncols++] = colors[i];
1183                 }
1184               else
1185                 failed[nopen++] = i;
1186             }
1187 #ifdef DEBUG
1188           else
1189             GDK_NOTE (COLOR_CONTEXT,
1190                       g_message ("gdk_color_context_get_pixels_incremental: "
1191                                  "pixel at slot %i already allocated, skipping\n", i));
1192 #endif
1193         }
1194     }
1195   
1196   *nallocated = ncols;
1197   
1198   if ((ncols == ncolors) || (nopen == 0))
1199     {
1200       GDK_NOTE (COLOR_CONTEXT,
1201                 g_message ("gdk_color_context_get_pixels_incremental: got all %i colors "
1202                            "(%i colors allocated so far)\n",
1203                            ncolors, cc->num_allocated));
1204       
1205       return;
1206     }
1207   
1208   cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
1209   
1210   if (cmapsize < 0)
1211     {
1212       g_warning ("gdk_color_context_get_pixels_incremental: oops!  "
1213                  "No colors available images will look *really* ugly.");
1214       return;
1215     }
1216   
1217 #ifdef G_ENABLE_DEBUG
1218   exact_col = ncols;
1219 #endif
1220   
1221   /* initialize pixels */
1222   
1223   for (i = 0; i < cmapsize; i++)
1224     {
1225       cmap[i].pixel = i;
1226       cmap[i].red = cmap[i].green = cmap[i].blue = 0;
1227     }
1228   
1229   /* read */
1230   
1231   my_x_query_colors (cc->colormap, cmap, cmapsize);
1232   
1233   /* now match any unallocated colors */
1234   
1235   counter = nopen;
1236   nopen = 0;
1237   idx = 0;
1238   
1239   do
1240     {
1241       gint d, j, mdist, close, ri, gi, bi;
1242       gint rd, gd, bd;
1243       
1244       i = failed[idx];
1245       
1246       mdist = 0x1000000;
1247       close = -1;
1248       
1249       /* store */
1250       
1251       ri = reds[i];
1252       gi = greens[i];
1253       bi = blues[i];
1254       
1255       for (j = 0; (j < cmapsize) && (mdist != 0); j++)
1256         {
1257           /* Don't replace these by shifts; the sign may get clobbered */
1258           
1259           rd = (ri - cmap[j].red) / 256;
1260           gd = (gi - cmap[j].green) / 256;
1261           bd = (bi - cmap[j].blue) / 256;
1262           
1263           d = rd * rd + gd * gd + bd * bd;
1264           
1265           if (d < mdist)
1266             {
1267               close = j;
1268               mdist = d;
1269             }
1270         }
1271       
1272       if (close != -1)
1273         {
1274           rd = cmap[close].red;
1275           gd = cmap[close].green;
1276           bd = cmap[close].blue;
1277           
1278           /* allocate */
1279           
1280           colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
1281           
1282           /* store */
1283           
1284           if (!bad_alloc)
1285             {
1286               defs[i] = cmap[close];
1287               defs[i].pixel = colors[i];
1288               allocated[ncols++] = colors[i];
1289 #ifdef G_ENABLE_DEBUG
1290               close_col++;
1291 #endif
1292             }
1293           else
1294             failed[nopen++] = i;
1295         }
1296       else
1297         failed[nopen++] = i;
1298       /* deal with in next stage if allocation failed */
1299     }
1300   while (++idx < counter);
1301   
1302   *nallocated = ncols;
1303   
1304   if ((ncols == ncolors) || (nopen == 0))
1305     {
1306       GDK_NOTE (COLOR_CONTEXT,
1307                 g_message ("gdk_color_context_get_pixels_incremental: "
1308                            "got %i colors, %i exact and %i close "
1309                            "(%i colors allocated so far)\n",
1310                            ncolors, exact_col, close_col, cc->num_allocated));
1311       
1312       return;
1313     }
1314   
1315   /* map remaining unallocated pixels into colors we did get */
1316   
1317   idx = 0;
1318   
1319   do
1320     {
1321       gint d, mdist, close, ri, gi, bi;
1322       gint j, rd, gd, bd;
1323       
1324       i = failed[idx];
1325       
1326       mdist = 0x1000000;
1327       close = -1;
1328       
1329       ri = reds[i];
1330       gi = greens[i];
1331       bi = blues[i];
1332       
1333       /* search allocated colors */
1334       
1335       for (j = 0; (j < ncols) && (mdist != 0); j++)
1336         {
1337           k = allocated[j];
1338           
1339           /* downscale */
1340           /* Don't replace these by shifts; the sign may get clobbered */
1341           
1342           rd = (ri - defs[k].red) / 256;
1343           gd = (gi - defs[k].green) / 256;
1344           bd = (bi - defs[k].blue) / 256;
1345           
1346           d = rd * rd + gd * gd + bd * bd;
1347           
1348           if (d < mdist)
1349             {
1350               close = k;
1351               mdist = d;
1352             }
1353         }
1354       
1355       if (close < 0)
1356         {
1357           /* too bad, map to black */
1358           
1359           defs[i].pixel = cc->black_pixel;
1360           defs[i].red = defs[i].green = defs[i].blue = 0;
1361 #ifdef G_ENABLE_DEBUG
1362           black_col++;
1363 #endif
1364         }
1365       else
1366         {
1367           defs[i] = defs[close];
1368 #ifdef G_ENABLE_DEBUG
1369           subst_col++;
1370 #endif
1371         }
1372       
1373       colors[i] = defs[i].pixel;
1374     }
1375   while (++idx < nopen);
1376   
1377   GDK_NOTE (COLOR_CONTEXT,
1378             g_message ("gdk_color_context_get_pixels_incremental: "
1379                        "got %i colors, %i exact, %i close, %i substituted, %i to black "
1380                        "(%i colors allocated so far)\n",
1381                        ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
1382 }
1383
1384 gint
1385 gdk_color_context_query_color (GdkColorContext *cc,
1386                                GdkColor        *color)
1387 {
1388   return gdk_color_context_query_colors (cc, color, 1);
1389 }
1390
1391 gint
1392 gdk_color_context_query_colors (GdkColorContext *cc,
1393                                 GdkColor        *colors,
1394                                 gint             num_colors)
1395 {
1396   gint i;
1397   GdkColor *tc;
1398   
1399   g_assert (cc != NULL);
1400   g_assert (colors != NULL);
1401   
1402   switch (cc->mode)
1403     {
1404     case GDK_CC_MODE_BW:
1405       for (i = 0, tc = colors; i < num_colors; i++, tc++)
1406         {
1407           if (tc->pixel == cc->white_pixel)
1408             tc->red = tc->green = tc->blue = 65535;
1409           else
1410             tc->red = tc->green = tc->blue = 0;
1411         }
1412       break;
1413       
1414     case GDK_CC_MODE_TRUE:
1415       if (cc->clut == NULL)
1416         for (i = 0, tc = colors; i < num_colors; i++, tc++)
1417           {
1418             tc->red   = ((tc->pixel & cc->masks.red) >> cc->shifts.red) << (16 - cc->bits.red);
1419             tc->green = ((tc->pixel & cc->masks.green) >> cc->shifts.green) << (16 - cc->bits.green);
1420             tc->blue  = ((tc->pixel & cc->masks.blue) >> cc->shifts.blue) << (16 - cc->bits.blue);
1421           }
1422       else
1423         {
1424           my_x_query_colors (cc->colormap, colors, num_colors);
1425           return 1;
1426         }
1427       break;
1428       
1429     case GDK_CC_MODE_STD_CMAP:
1430     default:
1431       if (cc->cmap == NULL)
1432         {
1433           my_x_query_colors (cc->colormap, colors, num_colors);
1434           return 1;
1435         }
1436       else
1437         {
1438           gint first, last, half;
1439           gulong half_pixel;
1440           
1441           for (i = 0, tc = colors; i < num_colors; i++)
1442             {
1443               first = 0;
1444               last = cc->num_colors - 1;
1445               
1446               while (first <= last)
1447                 {
1448                   half = (first + last) / 2;
1449                   half_pixel = cc->cmap[half].pixel;
1450                   
1451                   if (tc->pixel == half_pixel)
1452                     {
1453                       tc->red   = cc->cmap[half].red;
1454                       tc->green = cc->cmap[half].green;
1455                       tc->blue  = cc->cmap[half].blue;
1456                       first = last + 1; /* false break */
1457                     }
1458                   else
1459                     {
1460                       if (tc->pixel > half_pixel)
1461                         first = half + 1;
1462                       else
1463                         last = half - 1;
1464                     }
1465                 }
1466             }
1467           return 1;
1468         }
1469       break;
1470     }
1471   return 1;
1472 }
1473
1474 gint
1475 gdk_color_context_add_palette (GdkColorContext *cc,
1476                                GdkColor        *palette,
1477                                gint             num_palette)
1478 {
1479   gint i, j, erg;
1480   gushort r, g, b;
1481   gulong pixel[1];
1482   
1483   g_assert (cc != NULL);
1484   
1485   /* initialize this palette (will also erase previous palette as well) */
1486   
1487   init_palette (cc);
1488   
1489   /* restore previous mode if we aren't adding a new palette */
1490   
1491   if (num_palette == 0)
1492     {
1493       /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */
1494       
1495       /* XXX: here, the hash table is already initialized */
1496       
1497       return 0;
1498     }
1499   
1500   /* Initialize a hash table for this palette (we need one for allocating
1501    * the pixels in the palette using the current settings)
1502    */
1503   
1504   if (cc->color_hash == NULL)
1505     cc->color_hash = g_hash_table_new (hash_color, compare_colors);
1506   
1507   /* copy incoming palette */
1508   
1509   cc->palette = g_new0(GdkColor, num_palette);
1510   
1511   j = 0;
1512   
1513   for (i = 0; i < num_palette; i++)
1514     {
1515       erg = 0;
1516       pixel[0] = 0;
1517       
1518       /* try to allocate this color */
1519       
1520       r = palette[i].red;
1521       g = palette[i].green;
1522       b = palette[i].blue;
1523       
1524       gdk_color_context_get_pixels (cc, &r, &g, &b, 1, pixel, &erg);
1525       
1526       /* only store if we succeed */
1527       
1528       if (erg)
1529         {
1530           /* store in palette */
1531           
1532           cc->palette[j].red   = r;
1533           cc->palette[j].green = g;
1534           cc->palette[j].blue  = b;
1535           cc->palette[j].pixel = pixel[0];
1536           
1537           /* move to next slot */
1538           
1539           j++;
1540         }
1541     }
1542   
1543   /* resize to fit */
1544   
1545   if (j != num_palette)
1546     cc->palette = g_realloc (cc->palette, j * sizeof (GdkColor));
1547   
1548   /* clear the hash table, we don't use it when dithering */
1549   
1550   if (cc->color_hash)
1551     {
1552       g_hash_table_destroy (cc->color_hash);
1553       cc->color_hash = NULL;
1554     }
1555   
1556   /* store real palette size */
1557   
1558   cc->num_palette = j;
1559   
1560   /* switch to palette mode */
1561   
1562   cc->mode = GDK_CC_MODE_PALETTE;
1563   
1564   /* sort palette */
1565   
1566   qsort (cc->palette, cc->num_palette, sizeof (GdkColor), pixel_sort);
1567   
1568   cc->fast_dither = NULL;
1569   
1570   return j;
1571 }
1572
1573 void
1574 gdk_color_context_init_dither (GdkColorContext *cc)
1575 {
1576   gint rr, gg, bb, err, erg, erb;
1577   gint success = FALSE;
1578   
1579   g_assert (cc != NULL);
1580   
1581   /* now we can initialize the fast dither matrix */
1582   
1583   if (cc->fast_dither == NULL)
1584     cc->fast_dither = g_new (GdkColorContextDither, 1);
1585   
1586   /* Fill it.  We ignore unsuccessful allocations, they are just mapped
1587    * to black instead */
1588   
1589   for (rr = 0; rr < 32; rr++)
1590     for (gg = 0; gg < 32; gg++)
1591       for (bb = 0; bb < 32; bb++)
1592         {
1593           err = (rr << 3) | (rr >> 2);
1594           erg = (gg << 3) | (gg >> 2);
1595           erb = (bb << 3) | (bb >> 2);
1596           
1597           cc->fast_dither->fast_rgb[rr][gg][bb] =
1598             gdk_color_context_get_index_from_palette (cc, &err, &erg, &erb, &success);
1599           cc->fast_dither->fast_err[rr][gg][bb] = err;
1600           cc->fast_dither->fast_erg[rr][gg][bb] = erg;
1601           cc->fast_dither->fast_erb[rr][gg][bb] = erb;
1602         }
1603 }
1604
1605 void
1606 gdk_color_context_free_dither (GdkColorContext *cc)
1607 {
1608   g_assert (cc != NULL);
1609   
1610   if (cc->fast_dither)
1611     g_free (cc->fast_dither);
1612   
1613   cc->fast_dither = NULL;
1614 }
1615
1616 gulong
1617 gdk_color_context_get_pixel_from_palette (GdkColorContext *cc,
1618                                           gushort         *red,
1619                                           gushort         *green,
1620                                           gushort         *blue,
1621                                           gint            *failed)
1622 {
1623   gulong pixel = 0;
1624   gint dif, dr, dg, db, j = -1;
1625   gint mindif = 0x7fffffff;
1626   gint err = 0, erg = 0, erb = 0;
1627   gint i;
1628   
1629   g_assert (cc != NULL);
1630   g_assert (red != NULL);
1631   g_assert (green != NULL);
1632   g_assert (blue != NULL);
1633   g_assert (failed != NULL);
1634   
1635   *failed = FALSE;
1636   
1637   for (i = 0; i < cc->num_palette; i++)
1638     {
1639       dr = *red - cc->palette[i].red;
1640       dg = *green - cc->palette[i].green;
1641       db = *blue - cc->palette[i].blue;
1642       
1643       dif = dr * dr + dg * dg + db * db;
1644       
1645       if (dif < mindif)
1646         {
1647           mindif = dif;
1648           j = i;
1649           pixel = cc->palette[i].pixel;
1650           err = dr;
1651           erg = dg;
1652           erb = db;
1653           
1654           if (mindif == 0)
1655             break;
1656         }
1657     }
1658   
1659   /* we failed to map onto a color */
1660   
1661   if (j == -1)
1662     *failed = TRUE;
1663   else
1664     {
1665       *red   = ABS (err);
1666       *green = ABS (erg);
1667       *blue  = ABS (erb);
1668     }
1669   
1670   return pixel;
1671 }
1672
1673 guchar
1674 gdk_color_context_get_index_from_palette (GdkColorContext *cc,
1675                                           gint            *red,
1676                                           gint            *green,
1677                                           gint            *blue,
1678                                           gint            *failed)
1679 {
1680   gint dif, dr, dg, db, j = -1;
1681   gint mindif = 0x7fffffff;
1682   gint err = 0, erg = 0, erb = 0;
1683   gint i;
1684   
1685   g_assert (cc != NULL);
1686   g_assert (red != NULL);
1687   g_assert (green != NULL);
1688   g_assert (blue != NULL);
1689   g_assert (failed != NULL);
1690   
1691   *failed = FALSE;
1692   
1693   for (i = 0; i < cc->num_palette; i++)
1694     {
1695       dr = *red - cc->palette[i].red;
1696       dg = *green - cc->palette[i].green;
1697       db = *blue - cc->palette[i].blue;
1698       
1699       dif = dr * dr + dg * dg + db * db;
1700       
1701       if (dif < mindif)
1702         {
1703           mindif = dif;
1704           j = i;
1705           err = dr;
1706           erg = dg;
1707           erb = db;
1708           
1709           if (mindif == 0)
1710             break;
1711         }
1712     }
1713   
1714   /* we failed to map onto a color */
1715   
1716   if (j == -1)
1717     {
1718       *failed = TRUE;
1719       j = 0;
1720     }
1721   else
1722     {
1723       /* return error fractions */
1724       
1725       *red   = err;
1726       *green = erg;
1727       *blue  = erb;
1728     }
1729   
1730   return j;
1731 }