]> Pileus Git - ~andy/gtk/blob - gdk/linux-fb/gdkcolor-fb.c
Fixes #132975.
[~andy/gtk] / gdk / linux-fb / gdkcolor-fb.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <time.h>
28 #include <sys/ioctl.h>
29 #include <string.h>
30 #include <stdlib.h>
31
32 #include "gdkcolor.h"
33 #include "gdkprivate-fb.h"
34
35 #define GDK_COLORMAP_PRIVATE_DATA(cmap) ((GdkColormapPrivateFB *) GDK_COLORMAP (cmap)->windowing_data)
36
37 static gint  gdk_colormap_match_color (GdkColormap *cmap,
38                                        GdkColor    *color,
39                                        const gchar *available);
40 static void  gdk_fb_color_round_to_hw (GdkColor *color);
41
42 static gpointer parent_class;
43
44 static void
45 gdk_colormap_finalize (GObject *object)
46 {
47   GdkColormap *colormap = GDK_COLORMAP (object);
48   GdkColormapPrivateFB *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
49
50   if (private->hash)
51     g_hash_table_destroy (private->hash);
52   
53   g_free (private->info);
54   g_free (colormap->colors);
55   g_free (private);
56
57   G_OBJECT_CLASS (parent_class)->finalize (object);
58 }
59
60 static void
61 gdk_colormap_init (GdkColormap *colormap)
62 {
63   GdkColormapPrivateFB *private;
64
65   private = g_new (GdkColormapPrivateFB, 1);
66
67   colormap->windowing_data = private;
68   
69   colormap->size = 0;
70   colormap->colors = NULL;
71 }
72
73 static void
74 gdk_colormap_class_init (GdkColormapClass *klass)
75 {
76   GObjectClass *object_class = G_OBJECT_CLASS (klass);
77
78   parent_class = g_type_class_peek_parent (klass);
79
80   object_class->finalize = gdk_colormap_finalize;
81 }
82
83 GType
84 gdk_colormap_get_type (void)
85 {
86   static GType object_type = 0;
87
88   if (!object_type)
89     {
90       static const GTypeInfo object_info =
91       {
92         sizeof (GdkColormapClass),
93         (GBaseInitFunc) NULL,
94         (GBaseFinalizeFunc) NULL,
95         (GClassInitFunc) gdk_colormap_class_init,
96         NULL,           /* class_finalize */
97         NULL,           /* class_data */
98         sizeof (GdkColormap),
99         0,              /* n_preallocs */
100         (GInstanceInitFunc) gdk_colormap_init,
101       };
102       
103       object_type = g_type_register_static (G_TYPE_OBJECT,
104                                             "GdkColormap",
105                                             &object_info,
106                                             0);
107     }
108   
109   return object_type;
110 }
111
112 GdkColormap *
113 gdk_colormap_new (GdkVisual *visual,
114                   gint       private_cmap)
115 {
116   GdkColormap *colormap;
117   GdkColormap *system;
118   GdkColormapPrivateFB *private;
119   GdkFBDisplay *fbd;
120   int i;
121
122   g_return_val_if_fail (visual != NULL, NULL);
123
124   colormap = g_object_new (gdk_colormap_get_type (), NULL);
125   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
126
127   colormap->visual = visual;
128   fbd = gdk_display;
129
130   private->hash = NULL;
131   
132   colormap->size = visual->colormap_size;
133   colormap->colors = NULL;
134
135   switch (visual->type)
136     {
137     case GDK_VISUAL_STATIC_GRAY:
138     case GDK_VISUAL_STATIC_COLOR:
139     case GDK_VISUAL_GRAYSCALE:
140     case GDK_VISUAL_PSEUDO_COLOR:
141       private->info = g_new0 (GdkColorInfo, colormap->size);
142       colormap->colors = g_new (GdkColor, colormap->size);
143       
144       private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
145                                         (GEqualFunc) gdk_color_equal);
146
147       system = gdk_colormap_get_system ();
148       memcpy (colormap->colors, system->colors, colormap->size * sizeof (GdkColor));
149       
150       if (private_cmap)
151         {
152           guint16 red[256], green[256], blue[256];
153           struct fb_cmap fbc = {0, 256};
154
155           fbc.red = red;
156           fbc.green = green;
157           fbc.blue = blue;
158
159           if (ioctl (fbd->fb_fd, FBIOGETCMAP, &fbc))
160             g_error("ioctl(FBIOGETCMAP) failed");
161
162           for (i = 0; i < colormap->size; i++)
163             {
164               colormap->colors[i].pixel = i;
165               colormap->colors[i].red = red[i];
166               colormap->colors[i].green = green[i];
167               colormap->colors[i].blue = blue[i];
168             }
169
170           gdk_colormap_change (colormap, colormap->size);
171         }
172       break;
173
174     case GDK_VISUAL_DIRECT_COLOR:
175       g_warning ("gdk_colormap_new () on a direct color visual not implemented");
176 #if 0
177       colormap->colors = g_new (GdkColor, colormap->size);
178
179       size = 1 << visual->red_prec;
180       for (i = 0; i < size; i++)
181         colormap->colors[i].red = i * 65535 / (size - 1);
182
183       size = 1 << visual->green_prec;
184       for (i = 0; i < size; i++)
185         colormap->colors[i].green = i * 65535 / (size - 1);
186
187       size = 1 << visual->blue_prec;
188       for (i = 0; i < size; i++)
189         colormap->colors[i].blue = i * 65535 / (size - 1);
190
191       gdk_colormap_change (colormap, colormap->size);
192 #endif
193       break;
194
195     default:
196       g_assert_not_reached ();
197
198     case GDK_VISUAL_TRUE_COLOR:
199       break;
200     }
201
202   return colormap;
203 }
204
205 GdkColormap*
206 gdk_screen_get_system_colormap (GdkScreen *screen)
207 {
208   static GdkColormap *colormap = NULL;
209
210   if (!colormap)
211     {
212       GdkColormapPrivateFB *private;
213       GdkVisual *visual = gdk_visual_get_system ();
214       int i, r, g, b;
215       
216       colormap = g_object_new (gdk_colormap_get_type (), NULL);
217       private = GDK_COLORMAP_PRIVATE_DATA (colormap);
218
219       colormap->visual = visual;
220       private->hash = NULL;
221       
222       colormap->size = visual->colormap_size;
223       colormap->colors = NULL;
224       
225       switch (visual->type)
226         {
227         case GDK_VISUAL_STATIC_GRAY:
228         case GDK_VISUAL_STATIC_COLOR:
229         case GDK_VISUAL_GRAYSCALE:
230         case GDK_VISUAL_PSEUDO_COLOR:
231           private->info = g_new0 (GdkColorInfo, colormap->size);
232           colormap->colors = g_new (GdkColor, colormap->size);
233           
234           private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
235                                             (GEqualFunc) gdk_color_equal);
236           switch(visual->type)
237             {
238             case GDK_VISUAL_GRAYSCALE:
239               for(i = 0; i < 256; i++) {
240                 colormap->colors[i].red = 
241                   colormap->colors[i].green =
242                   colormap->colors[i].blue = i << 8;
243                 gdk_fb_color_round_to_hw (&colormap->colors[i]);
244               }
245               i--;
246               colormap->colors[i].red = 
247                 colormap->colors[i].green =
248                 colormap->colors[i].blue = 65535; /* Make it a true white */
249               gdk_fb_color_round_to_hw (&colormap->colors[i]);
250               break;
251             case GDK_VISUAL_PSEUDO_COLOR:
252               /* Color cube stolen from gdkrgb upon advice from Owen */
253               for(i = r = 0; r < 6; r++)
254                 for(g = 0; g < 6; g++)
255                   for(b = 0; b < 6; b++)
256                     {
257                       colormap->colors[i].red = r * 65535 / 5;
258                       colormap->colors[i].green = g * 65535 / 5;
259                       colormap->colors[i].blue = b * 65535 / 5;
260                       gdk_fb_color_round_to_hw (&colormap->colors[i]);
261                       i++;
262                     }
263               g_assert (i == 216);
264               /* Fill in remaining space with grays */
265               for(i = 216; i < 256; i++)
266                 {
267                   colormap->colors[i].red = 
268                     colormap->colors[i].green =
269                     colormap->colors[i].blue = (i - 216) * 40;
270                   gdk_fb_color_round_to_hw (&colormap->colors[i]);
271                 }
272               /* Real white */
273               colormap->colors[255].red = 
274                   colormap->colors[255].green =
275                   colormap->colors[255].blue = 65535;
276               gdk_fb_color_round_to_hw (&colormap->colors[255]);
277
278               break;
279             default:
280               break;
281             }
282           break;
283         case GDK_VISUAL_DIRECT_COLOR:
284           g_warning ("gdk_colormap_get_system() on a direct color visual is not implemented");
285           break;
286         default:
287           g_assert_not_reached ();
288         case GDK_VISUAL_TRUE_COLOR:
289           break;
290         }
291       
292       /* Lock all colors for the system colormap
293        * on pseudocolor visuals. The AA text rendering
294        * takes to many colors otherwise.
295        */
296       if ((visual->type == GDK_VISUAL_GRAYSCALE) ||
297           (visual->type == GDK_VISUAL_PSEUDO_COLOR))
298         {
299           for(i = 0; i < 256; i++)
300             {
301               colormap->colors[i].pixel = i;
302               private->info[i].ref_count = 1;
303               g_hash_table_insert (private->hash,
304                                    &colormap->colors[i],
305                                    &colormap->colors[i]);
306             }
307         }
308       gdk_colormap_change (colormap, colormap->size);
309     }
310
311   return colormap;
312 }
313
314 gint
315 gdk_colormap_get_system_size (void)
316 {
317   return 1 << (gdk_display->modeinfo.bits_per_pixel);
318 }
319
320 void
321 gdk_colormap_change (GdkColormap *colormap,
322                      gint         ncolors)
323 {
324   guint16 red[256], green[256], blue[256];
325   struct fb_cmap fbc = {0,256};
326   GdkColormapPrivateFB *private;
327   int i;
328
329   g_return_if_fail (colormap != NULL);
330
331   fbc.red = red;
332   fbc.green = green;
333   fbc.blue = blue;
334
335   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
336   switch (colormap->visual->type)
337     {
338     case GDK_VISUAL_GRAYSCALE:
339       for(i = 0; i < ncolors; i++)
340         {
341           red[i] = green[i] = blue[i] =
342             (colormap->colors[i].red +
343              colormap->colors[i].green +
344              colormap->colors[i].blue)/3;
345         }
346       ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
347       break;
348
349     case GDK_VISUAL_PSEUDO_COLOR:
350       for (i = 0; i < ncolors; i++)
351         {
352           red[i] = colormap->colors[i].red;
353           green[i] = colormap->colors[i].green;
354           blue[i] = colormap->colors[i].blue;
355         }
356       ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
357       break;
358
359     default:
360       break;
361     }
362 }
363
364 void
365 gdk_colormap_free_colors (GdkColormap *colormap,
366                           GdkColor    *colors,
367                           gint         ncolors)
368 {
369   GdkColormapPrivateFB *private;
370   gint i;
371
372   g_return_if_fail (colormap != NULL);
373   g_return_if_fail (colors != NULL);
374
375   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
376
377   if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
378       (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
379     return;
380
381   for (i = 0; i < ncolors; i++)
382     {
383       gulong pixel = colors[i].pixel;
384       
385       if (private->info[pixel].ref_count)
386         {
387           private->info[pixel].ref_count--;
388
389           if (private->info[pixel].ref_count == 0)
390             {
391               if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
392                 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
393               private->info[pixel].flags = 0;
394             }
395         }
396     }
397 }
398
399 /********************
400  * Color allocation *
401  ********************/
402
403 static void
404 gdk_fb_color_round_to_hw (GdkColor *color)
405 {
406   guint rmask, gmask, bmask, len;
407
408   len = gdk_display->modeinfo.red.length;
409   rmask = ((1 << len) - 1) << (16-len);
410   len = gdk_display->modeinfo.green.length;
411   gmask = ((1 << len) - 1) << (16-len);
412   len = gdk_display->modeinfo.blue.length;
413   bmask = ((1 << len) - 1) << (16-len);
414   
415   color->red &=rmask;
416   color->green &=gmask;
417   color->blue &=bmask;
418 }
419
420 /* Try to allocate a single color using XAllocColor. If it succeeds,
421  * cache the result in our colormap, and store in ret.
422  */
423 static gboolean 
424 gdk_colormap_alloc1 (GdkColormap *colormap,
425                      GdkColor    *color,
426                      GdkColor    *ret)
427 {
428   GdkColormapPrivateFB *private;
429   int i;
430
431   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
432
433   if (colormap->visual->type != GDK_VISUAL_GRAYSCALE
434       && colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR)
435     return FALSE;
436
437   *ret = *color;
438   
439   gdk_fb_color_round_to_hw (ret);
440
441   for (i = 0; i<colormap->size; i++)
442     {
443       if (!(private->info[i].flags & GDK_COLOR_WRITEABLE) &&
444           (ret->red == colormap->colors[i].red) &&
445           (ret->green == colormap->colors[i].green) &&
446           (ret->blue == colormap->colors[i].blue))
447         {
448           ret->pixel = i;
449           colormap->colors[i].pixel = i;
450           if (private->info[i].ref_count == 0)
451             g_hash_table_insert (private->hash,
452                                  &colormap->colors[ret->pixel],
453                                  &colormap->colors[ret->pixel]);
454           private->info[i].ref_count++;
455           return TRUE;
456         }
457     }
458
459   for (i = 0; i<colormap->size; i++)
460     {
461       if (private->info[i].ref_count==0)
462         {
463           guint16 red = color->red, green = color->green, blue = color->blue;
464           struct fb_cmap fbc;
465           
466           fbc.len = 1;
467           fbc.start = i;
468           fbc.red = &red;
469           fbc.green = &green;
470           fbc.blue = &blue;
471
472           ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
473
474           ret->pixel = i;
475           colormap->colors[ret->pixel] = *ret;
476           private->info[ret->pixel].ref_count = 1;
477           g_hash_table_insert (private->hash,
478                                &colormap->colors[ret->pixel],
479                                &colormap->colors[ret->pixel]);
480           return TRUE;
481         }
482     }
483       
484   return FALSE;
485 }
486
487 static gint
488 gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
489                                   GdkColor    *colors,
490                                   gint         ncolors,
491                                   gboolean     writeable,
492                                   gboolean     best_match,
493                                   gboolean    *success)
494 {
495   GdkColormapPrivateFB *private;
496   gint i, index;
497   gint nremaining = 0;
498   gint nfailed = 0;
499
500   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
501   index = -1;
502
503   for (i = 0; i < ncolors; i++)
504     {
505       if (!success[i])
506         {
507           if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
508             success[i] = TRUE;
509           else
510             nremaining++;
511         }
512     }
513
514
515   if (nremaining > 0 && best_match)
516     {
517       gchar *available = g_new (gchar, colormap->size);
518
519       for (i = 0; i < colormap->size; i++)
520         available[i] = ((private->info[i].ref_count == 0) ||
521                         !(private->info[i].flags & GDK_COLOR_WRITEABLE));
522       
523       while (nremaining > 0)
524         {
525           for (i = 0; i < ncolors; i++)
526             {
527               if (!success[i])
528                 {
529                   index = gdk_colormap_match_color (colormap, &colors[i], available);
530                   if (index != -1)
531                     {
532                       if (private->info[index].ref_count)
533                         {
534                           private->info[index].ref_count++;
535                           colors[i] = colormap->colors[index];
536                           success[i] = TRUE;
537                           nremaining--;
538                         }
539                       else
540                         {
541                           if (gdk_colormap_alloc1 (colormap, 
542                                                    &colormap->colors[index],
543                                                    &colors[i]))
544                             {
545                               success[i] = TRUE;
546                               nremaining--;
547                               break;
548                             }
549                           else
550                             {
551                               available[index] = FALSE;
552                             }
553                         }
554                     }
555                   else
556                     {
557                       nfailed++;
558                       nremaining--;
559                       success[i] = 2; /* flag as permanent failure */
560                     }
561                 }
562             }
563         }
564       g_free (available);
565     }
566
567   /* Change back the values we flagged as permanent failures */
568   if (nfailed > 0)
569     {
570       for (i = 0; i < ncolors; i++)
571         if (success[i] == 2)
572           success[i] = FALSE;
573       nremaining = nfailed;
574     }
575   
576   return (ncolors - nremaining);
577 }
578
579 static gint
580 gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
581                                        GdkColor    *colors,
582                                        gint         ncolors,
583                                        gboolean     writeable,
584                                        gboolean     best_match,
585                                        gboolean    *success)
586 {
587   GdkColormapPrivateFB *private;
588   GdkColor *lookup_color;
589   gint i;
590   gint nremaining = 0;
591
592   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
593
594   /* Check for an exact match among previously allocated colors */
595
596   for (i = 0; i < ncolors; i++)
597     {
598       if (!success[i])
599         {
600           lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
601           if (lookup_color)
602             {
603               private->info[lookup_color->pixel].ref_count++;
604               colors[i].pixel = lookup_color->pixel;
605               success[i] = TRUE;
606             }
607           else
608             nremaining++;
609         }
610     }
611
612   /* If that failed, we try to allocate a new color, or approxmiate
613    * with what we can get if best_match is TRUE.
614    */
615   if (nremaining > 0)
616     return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
617   else
618     return 0;
619 }
620
621 gint
622 gdk_colormap_alloc_colors (GdkColormap *colormap,
623                            GdkColor    *colors,
624                            gint         ncolors,
625                            gboolean     writeable,
626                            gboolean     best_match,
627                            gboolean    *success)
628 {
629   GdkColormapPrivateFB *private;
630   GdkVisual *visual;
631   gint i;
632   gint nremaining = 0;
633
634   g_return_val_if_fail (colormap != NULL, FALSE);
635   g_return_val_if_fail (colors != NULL, FALSE);
636
637   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
638
639   for (i = 0; i < ncolors; i++)
640     success[i] = FALSE;
641
642   visual = colormap->visual;
643   switch (visual->type)
644     {
645     case GDK_VISUAL_PSEUDO_COLOR:
646     case GDK_VISUAL_GRAYSCALE:
647     case GDK_VISUAL_STATIC_GRAY:
648     case GDK_VISUAL_STATIC_COLOR:
649       return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
650                                                     writeable, best_match, success);
651       break;
652
653     case GDK_VISUAL_DIRECT_COLOR:
654     case GDK_VISUAL_TRUE_COLOR:
655       for (i = 0; i < ncolors; i++)
656         {
657           colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
658                              ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
659                              ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
660           success[i] = TRUE;
661         }
662       break;
663     }
664   return nremaining;
665 }
666
667 gboolean
668 gdk_color_change (GdkColormap *colormap,
669                   GdkColor    *color)
670 {
671   GdkColormapPrivateFB *private;
672   struct fb_cmap fbc = {0, 1};
673
674   g_return_val_if_fail (colormap != NULL, FALSE);
675   g_return_val_if_fail (color != NULL, FALSE);
676
677   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
678
679   switch(colormap->visual->type)
680     {
681     case GDK_VISUAL_GRAYSCALE:
682       color->red = color->green = color->blue = (color->red + color->green + color->blue)/3;
683
684       /* Fall through */
685     case GDK_VISUAL_PSEUDO_COLOR:
686       colormap->colors[color->pixel] = *color;
687       
688       fbc.start = color->pixel;
689       fbc.red = &color->red;
690       fbc.green = &color->green;
691       fbc.blue = &color->blue;
692       ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
693       break;
694
695     default:
696       break;
697     }
698
699   return TRUE;
700 }
701
702 static gint
703 gdk_colormap_match_color (GdkColormap *cmap,
704                           GdkColor    *color,
705                           const gchar *available)
706 {
707   GdkColor *colors;
708   guint sum, max;
709   gint rdiff, gdiff, bdiff;
710   gint i, index;
711
712   g_return_val_if_fail (cmap != NULL, 0);
713   g_return_val_if_fail (color != NULL, 0);
714
715   colors = cmap->colors;
716   max = 3 * (65536);
717   index = -1;
718
719   for (i = 0; i < cmap->size; i++)
720     {
721       if ((!available) || (available && available[i]))
722         {
723           rdiff = (color->red - colors[i].red);
724           gdiff = (color->green - colors[i].green);
725           bdiff = (color->blue - colors[i].blue);
726
727           sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
728
729           if (sum < max)
730             {
731               index = i;
732               max = sum;
733             }
734         }
735     }
736
737   return index;
738 }
739
740 gboolean
741 gdk_colors_alloc (GdkColormap   *colormap,
742                   gboolean       contiguous,
743                   gulong        *planes,
744                   gint           nplanes,
745                   gulong        *pixels,
746                   gint           npixels)
747 {
748   GdkColormapPrivateFB *private;
749   gint found, i, col;
750
751   g_return_val_if_fail (colormap != NULL, FALSE);
752
753   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
754   
755   if (nplanes > 0)
756     return FALSE;
757
758   found = 0;
759   for (i = 1; i < colormap->size; i++)
760     {
761       if (private->info[i].ref_count == 0)
762         {
763           found++;
764           if (found >= npixels)
765             break;
766         }
767     }
768
769   if (found < npixels)
770     return FALSE;
771
772   col = 0;
773   for (i = 1; i < colormap->size; i++)
774     {
775       if (private->info[i].ref_count == 0)
776         {
777           pixels[col++] = i;
778           private->info[i].ref_count++;
779           private->info[i].flags |= GDK_COLOR_WRITEABLE;
780           if (col == npixels)
781             return TRUE;
782         }
783     }
784
785   g_assert_not_reached ();
786   return FALSE;
787 }
788
789 void
790 gdk_colors_free (GdkColormap    *colormap,
791                  gulong         *pixels,
792                  gint            npixels,
793                  gulong          planes)
794 {
795   GdkColormapPrivateFB *private;
796   gint i, pixel;
797
798   g_return_if_fail (colormap != NULL);
799
800   if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
801       (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
802     return;
803   
804   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
805   
806   for (i = 0; i < npixels; i++)
807     {
808       pixel = pixels[i];
809       
810       if (private->info[pixel].ref_count)
811         {
812           private->info[pixel].ref_count--;
813
814           if (private->info[pixel].ref_count == 0)
815             {
816               if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
817                 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
818               private->info[pixel].flags = 0;
819             }
820         }
821     }
822 }
823
824
825 void
826 gdk_colormap_query_color (GdkColormap *colormap,
827                           gulong       pixel,
828                           GdkColor    *result)
829 {
830   GdkVisual *visual;
831
832   g_return_if_fail (GDK_IS_COLORMAP (colormap));
833   
834   visual = gdk_colormap_get_visual (colormap);
835
836   switch (visual->type)
837     {
838     case GDK_VISUAL_DIRECT_COLOR:
839     case GDK_VISUAL_TRUE_COLOR:
840       result->red = 65535. * (gdouble) ((pixel & visual->red_mask) >> visual->red_shift) / ((1 << visual->red_prec) - 1);
841       result->green = 65535. * (gdouble) ((pixel & visual->green_mask) >> visual->green_shift) / ((1 << visual->green_prec) - 1);
842       result->blue = 65535. * (gdouble) ((pixel & visual->blue_mask) >> visual->blue_shift) / ((1 << visual->blue_prec) - 1);
843       break;
844     case GDK_VISUAL_STATIC_GRAY:
845     case GDK_VISUAL_GRAYSCALE:
846       result->red = result->green = result->blue = 65535. * (double)pixel/((1<<visual->depth) - 1);
847       break;
848     case GDK_VISUAL_PSEUDO_COLOR:
849       result->red = colormap->colors[pixel].red;
850       result->green = colormap->colors[pixel].green;
851       result->blue = colormap->colors[pixel].blue;
852       break;
853     default:
854       g_assert_not_reached ();
855       break;
856     }
857 }
858
859 GdkScreen*
860 gdk_colormap_get_screen (GdkColormap *cmap)
861 {
862   g_return_val_if_fail (cmap != NULL, NULL);
863
864   return gdk_screen_get_default ();
865 }