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