]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkcolor-x11.c
6265dcfc7a63c8e8dd0c299f396e5b4619d78837
[~andy/gtk] / gdk / x11 / gdkcolor-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
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 <config.h>
28 #include <time.h>
29
30 #include "gdkcolor.h"
31 #include "gdkinternals.h"
32 #include "gdkx.h"
33 #include "gdkprivate-x11.h"
34 #include "gdkscreen-x11.h"
35
36 typedef struct _GdkColormapPrivateX11  GdkColormapPrivateX11;
37
38 struct _GdkColormapPrivateX11
39 {
40   GdkScreen *screen;
41   Colormap xcolormap;
42   gint private_val;
43
44   GHashTable *hash;
45   GdkColorInfo *info;
46   time_t last_sync_time;
47
48   guint foreign : 1;
49 };
50
51 #define GDK_COLORMAP_PRIVATE_DATA(cmap) ((GdkColormapPrivateX11 *) GDK_COLORMAP (cmap)->windowing_data)
52
53 static gint     gdk_colormap_match_color (GdkColormap *cmap,
54                                           GdkColor    *color,
55                                           const gchar *available);
56 static void     gdk_colormap_add         (GdkColormap *cmap);
57 static void     gdk_colormap_remove      (GdkColormap *cmap);
58
59 static GdkColormap *gdk_colormap_lookup   (GdkScreen   *screen,
60                                            Colormap     xcolormap);
61
62 static guint    gdk_colormap_hash        (Colormap    *cmap);
63 static gboolean gdk_colormap_equal       (Colormap    *a,
64                                           Colormap    *b);
65 static void     gdk_colormap_sync        (GdkColormap *colormap,
66                                           gboolean     force);
67
68 static void gdk_colormap_init       (GdkColormap      *colormap);
69 static void gdk_colormap_class_init (GdkColormapClass *klass);
70 static void gdk_colormap_finalize   (GObject              *object);
71
72 static gpointer parent_class = NULL;
73
74 GType
75 gdk_colormap_get_type (void)
76 {
77   static GType object_type = 0;
78
79   if (!object_type)
80     {
81       static const GTypeInfo object_info =
82       {
83         sizeof (GdkColormapClass),
84         (GBaseInitFunc) NULL,
85         (GBaseFinalizeFunc) NULL,
86         (GClassInitFunc) gdk_colormap_class_init,
87         NULL,           /* class_finalize */
88         NULL,           /* class_data */
89         sizeof (GdkColormap),
90         0,              /* n_preallocs */
91         (GInstanceInitFunc) gdk_colormap_init,
92       };
93       
94       object_type = g_type_register_static (G_TYPE_OBJECT,
95                                             "GdkColormap",
96                                             &object_info, 0);
97     }
98   
99   return object_type;
100 }
101
102 static void
103 gdk_colormap_init (GdkColormap *colormap)
104 {
105   GdkColormapPrivateX11 *private;
106
107   private = g_new (GdkColormapPrivateX11, 1);
108
109   colormap->windowing_data = private;
110   
111   private->screen = NULL;
112   private->hash = NULL;
113   private->last_sync_time = 0;
114   private->info = NULL;
115
116   colormap->size = 0;
117   colormap->colors = NULL;
118 }
119
120 static void
121 gdk_colormap_class_init (GdkColormapClass *klass)
122 {
123   GObjectClass *object_class = G_OBJECT_CLASS (klass);
124
125   parent_class = g_type_class_peek_parent (klass);
126
127   object_class->finalize = gdk_colormap_finalize;
128 }
129
130 static void
131 gdk_colormap_finalize (GObject *object)
132 {
133   GdkColormap *colormap = GDK_COLORMAP (object);
134   GdkColormapPrivateX11 *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
135
136   gdk_colormap_remove (colormap);
137
138   if (!private->screen->closed)
139     XFreeColormap (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap);
140
141   if (private->hash)
142     g_hash_table_destroy (private->hash);
143   
144   g_free (private->info);
145   g_free (colormap->colors);
146   g_free (private);
147   
148   G_OBJECT_CLASS (parent_class)->finalize (object);
149 }
150
151 /**
152  * gdk_colormap_new:
153  * @visual: a #GdkVisual.
154  * @allocate: if %TRUE, the newly created colormap will be
155  * a private colormap, and all colors in it will be
156  * allocated for the applications use.
157  * 
158  * Creates a new colormap for the given visual.
159  * 
160  * Return value: the new #GdkColormap.
161  **/
162 GdkColormap*
163 gdk_colormap_new (GdkVisual *visual,
164                   gboolean   allocate)
165 {
166   GdkColormap *colormap;
167   GdkColormapPrivateX11 *private;
168   Visual *xvisual;
169   Display *xdisplay;
170   Window xrootwin;
171   int size;
172   int i;
173
174   /* FIXME when object properties settle down, there needs to be some
175    * kind of default construction (and construct-only arguments)
176    */
177   
178   g_return_val_if_fail (GDK_IS_VISUAL (visual), NULL);
179
180   colormap = g_object_new (GDK_TYPE_COLORMAP, NULL);
181   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
182
183   colormap->visual = visual;
184   private->screen = gdk_visual_get_screen (visual);
185   
186   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
187   xdisplay = GDK_SCREEN_XDISPLAY (private->screen);
188   xrootwin = GDK_SCREEN_XROOTWIN (private->screen);
189
190   colormap->size = visual->colormap_size;
191
192   switch (visual->type)
193     {
194     case GDK_VISUAL_GRAYSCALE:
195     case GDK_VISUAL_PSEUDO_COLOR:
196       private->info = g_new0 (GdkColorInfo, colormap->size);
197       colormap->colors = g_new (GdkColor, colormap->size);
198       
199       private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
200                                         (GEqualFunc) gdk_color_equal);
201       
202       private->private_val = allocate;
203       private->xcolormap = XCreateColormap (xdisplay, xrootwin,
204                                             xvisual, (allocate) ? (AllocAll) : (AllocNone));
205
206       if (allocate)
207         {
208           GdkVisual *system_visual;
209           XColor *default_colors;
210           gint n_default_colors;
211
212           system_visual = gdk_screen_get_system_visual (private->screen);
213           n_default_colors = MIN (system_visual->colormap_size, colormap->size);
214
215           default_colors = g_new (XColor, colormap->size);
216
217           for (i = 0; i < n_default_colors; i++)
218             default_colors[i].pixel = i;
219           
220           XQueryColors (xdisplay,
221                         DefaultColormapOfScreen (GDK_SCREEN_X11 (private->screen)->xscreen),
222                         default_colors, n_default_colors);
223
224           for (i = 0; i < n_default_colors; i++)
225             {
226               colormap->colors[i].pixel = default_colors[i].pixel;
227               colormap->colors[i].red = default_colors[i].red;
228               colormap->colors[i].green = default_colors[i].green;
229               colormap->colors[i].blue = default_colors[i].blue;
230             }
231
232           gdk_colormap_change (colormap, n_default_colors);
233           
234           g_free (default_colors);
235         }
236       break;
237
238     case GDK_VISUAL_DIRECT_COLOR:
239       private->private_val = TRUE;
240       private->xcolormap = XCreateColormap (xdisplay, xrootwin,
241                                             xvisual, AllocAll);
242       colormap->colors = g_new (GdkColor, colormap->size);
243
244       size = 1 << visual->red_prec;
245       for (i = 0; i < size; i++)
246         colormap->colors[i].red = i * 65535 / (size - 1);
247
248       size = 1 << visual->green_prec;
249       for (i = 0; i < size; i++)
250         colormap->colors[i].green = i * 65535 / (size - 1);
251
252       size = 1 << visual->blue_prec;
253       for (i = 0; i < size; i++)
254         colormap->colors[i].blue = i * 65535 / (size - 1);
255
256       gdk_colormap_change (colormap, colormap->size);
257       break;
258
259     case GDK_VISUAL_STATIC_GRAY:
260     case GDK_VISUAL_STATIC_COLOR:
261       private->private_val = FALSE;
262       private->xcolormap = XCreateColormap (xdisplay, xrootwin,
263                                             xvisual, AllocNone);
264       
265       colormap->colors = g_new (GdkColor, colormap->size);
266       gdk_colormap_sync (colormap, TRUE);
267       break;
268       
269     case GDK_VISUAL_TRUE_COLOR:
270       private->private_val = FALSE;
271       private->xcolormap = XCreateColormap (xdisplay, xrootwin,
272                                             xvisual, AllocNone);
273       break;
274     }
275
276   gdk_colormap_add (colormap);
277
278   return colormap;
279 }
280
281 static void
282 gdk_colormap_sync_palette (GdkColormap *colormap)
283 {
284   GdkColormapPrivateX11 *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
285   XColor *xpalette;
286   gint nlookup;
287   gint i;
288
289   nlookup = 0;
290   xpalette = g_new (XColor, colormap->size);
291   
292   for (i = 0; i < colormap->size; i++)
293     {
294       if (!private->info || private->info[i].ref_count == 0)
295         {
296           xpalette[nlookup].pixel = i;
297           xpalette[nlookup].red = 0;
298           xpalette[nlookup].green = 0;
299           xpalette[nlookup].blue = 0;
300           nlookup++;
301         }
302     }
303
304   XQueryColors (GDK_SCREEN_XDISPLAY (private->screen),
305                 private->xcolormap, xpalette, nlookup);
306   
307   for (i = 0; i < nlookup; i++)
308     {
309       gulong pixel = xpalette[i].pixel;
310       colormap->colors[pixel].pixel = pixel;
311       colormap->colors[pixel].red = xpalette[i].red;
312       colormap->colors[pixel].green = xpalette[i].green;
313       colormap->colors[pixel].blue = xpalette[i].blue;
314     }
315   
316   g_free (xpalette);
317 }
318
319 static void
320 gdk_colormap_sync_direct_color (GdkColormap *colormap)
321 {
322   GdkColormapPrivateX11 *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
323   GdkVisual *visual = colormap->visual;
324   XColor *xpalette;
325   gint i;
326
327   xpalette = g_new (XColor, colormap->size);
328   
329   for (i = 0; i < colormap->size; i++)
330     {
331       xpalette[i].pixel =
332         (((i << visual->red_shift)   & visual->red_mask)   |
333          ((i << visual->green_shift) & visual->green_mask) |
334          ((i << visual->blue_shift)  & visual->blue_mask));
335     }
336
337   XQueryColors (GDK_SCREEN_XDISPLAY (private->screen),
338                 private->xcolormap, xpalette, colormap->size);
339   
340   for (i = 0; i < colormap->size; i++)
341     {
342       colormap->colors[i].pixel = xpalette[i].pixel;
343       colormap->colors[i].red = xpalette[i].red;
344       colormap->colors[i].green = xpalette[i].green;
345       colormap->colors[i].blue = xpalette[i].blue;
346     }
347   
348   g_free (xpalette);
349 }
350
351 #define MIN_SYNC_TIME 2
352
353 static void
354 gdk_colormap_sync (GdkColormap *colormap,
355                    gboolean     force)
356 {
357   time_t current_time;
358   GdkColormapPrivateX11 *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
359
360   g_return_if_fail (GDK_IS_COLORMAP (colormap));
361
362   if (private->screen->closed)
363     return;
364
365   current_time = time (NULL);
366   if (!force && ((current_time - private->last_sync_time) < MIN_SYNC_TIME))
367     return;
368
369   private->last_sync_time = current_time;
370
371   if (colormap->visual->type == GDK_VISUAL_DIRECT_COLOR)
372     gdk_colormap_sync_direct_color (colormap);
373   else
374     gdk_colormap_sync_palette (colormap);
375 }
376                    
377 /**
378  * gdk_screen_get_system_colormap:
379  * @screen: a #GdkScreen
380  *
381  * Gets the system's default colormap for @screen
382  *
383  * Returns: the default colormap for @screen.
384  *
385  * Since: 2.2
386  */
387 GdkColormap *
388 gdk_screen_get_system_colormap (GdkScreen *screen)
389 {
390   GdkColormap *colormap = NULL;
391   GdkColormapPrivateX11 *private;
392   GdkScreenX11 *screen_x11;
393
394   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
395   screen_x11 = GDK_SCREEN_X11 (screen);
396
397   if (screen_x11->system_colormap)
398     return screen_x11->system_colormap;
399
400   colormap = g_object_new (GDK_TYPE_COLORMAP, NULL);
401   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
402
403   private->screen = screen;
404   colormap->visual = gdk_screen_get_system_visual (screen);
405   
406   private->xcolormap = DefaultColormapOfScreen (screen_x11->xscreen);
407   private->private_val = FALSE;
408
409   private->hash = NULL;
410   private->last_sync_time = 0;
411   private->info = NULL;
412
413   colormap->colors = NULL;
414   colormap->size = colormap->visual->colormap_size;
415
416   switch (colormap->visual->type)
417     {
418     case GDK_VISUAL_GRAYSCALE:
419     case GDK_VISUAL_PSEUDO_COLOR:
420       private->info = g_new0 (GdkColorInfo, colormap->size);
421       private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
422                                         (GEqualFunc) gdk_color_equal);
423       /* Fall through */
424     case GDK_VISUAL_STATIC_GRAY:
425     case GDK_VISUAL_STATIC_COLOR:
426     case GDK_VISUAL_DIRECT_COLOR:
427       colormap->colors = g_new (GdkColor, colormap->size);
428       gdk_colormap_sync (colormap, TRUE);
429       
430     case GDK_VISUAL_TRUE_COLOR:
431       break;
432     }
433   
434   gdk_colormap_add (colormap);
435   screen_x11->system_colormap = colormap;
436   
437   return colormap;
438 }
439
440 /**
441  * gdk_colormap_get_system_size:
442  * 
443  * Returns the size of the system's default colormap.
444  * (See the description of struct #GdkColormap for an
445  * explanation of the size of a colormap.)
446  * 
447  * Return value: the size of the system's default colormap.
448  **/
449 gint
450 gdk_colormap_get_system_size (void)
451 {
452   return DisplayCells (GDK_SCREEN_XDISPLAY (gdk_screen_get_default()),
453                        GDK_SCREEN_X11 (gdk_screen_get_default())->screen_num);
454 }
455
456 /**
457  * gdk_colormap_change:
458  * @colormap: a #GdkColormap.
459  * @ncolors: the number of colors to change.
460  * 
461  * Changes the value of the first @ncolors in a private colormap
462  * to match the values in the <structfield>colors</structfield>
463  * array in the colormap. This function is obsolete and
464  * should not be used. See gdk_color_change().
465  **/
466 void
467 gdk_colormap_change (GdkColormap *colormap,
468                      gint         ncolors)
469 {
470   GdkColormapPrivateX11 *private;
471   GdkVisual *visual;
472   XColor *palette;
473   Display *xdisplay;
474   gint shift;
475   int max_colors;
476   int size;
477   int i;
478
479   g_return_if_fail (GDK_IS_COLORMAP (colormap));
480
481   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
482
483   if (private->screen->closed)
484     return;
485
486   xdisplay = GDK_SCREEN_XDISPLAY (private->screen);
487   palette = g_new (XColor, ncolors);
488
489   switch (colormap->visual->type)
490     {
491     case GDK_VISUAL_GRAYSCALE:
492     case GDK_VISUAL_PSEUDO_COLOR:
493       for (i = 0; i < ncolors; i++)
494         {
495           palette[i].pixel = colormap->colors[i].pixel;
496           palette[i].red = colormap->colors[i].red;
497           palette[i].green = colormap->colors[i].green;
498           palette[i].blue = colormap->colors[i].blue;
499           palette[i].flags = DoRed | DoGreen | DoBlue;
500         }
501
502       XStoreColors (xdisplay, private->xcolormap, palette, ncolors);
503       break;
504
505     case GDK_VISUAL_DIRECT_COLOR:
506       visual = colormap->visual;
507
508       shift = visual->red_shift;
509       max_colors = 1 << visual->red_prec;
510       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
511
512       for (i = 0; i < size; i++)
513         {
514           palette[i].pixel = i << shift;
515           palette[i].red = colormap->colors[i].red;
516           palette[i].flags = DoRed;
517         }
518
519       XStoreColors (xdisplay, private->xcolormap, palette, size);
520
521       shift = visual->green_shift;
522       max_colors = 1 << visual->green_prec;
523       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
524
525       for (i = 0; i < size; i++)
526         {
527           palette[i].pixel = i << shift;
528           palette[i].green = colormap->colors[i].green;
529           palette[i].flags = DoGreen;
530         }
531
532       XStoreColors (xdisplay, private->xcolormap, palette, size);
533
534       shift = visual->blue_shift;
535       max_colors = 1 << visual->blue_prec;
536       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
537
538       for (i = 0; i < size; i++)
539         {
540           palette[i].pixel = i << shift;
541           palette[i].blue = colormap->colors[i].blue;
542           palette[i].flags = DoBlue;
543         }
544
545       XStoreColors (xdisplay, private->xcolormap, palette, size);
546       break;
547
548     default:
549       break;
550     }
551
552   g_free (palette);
553 }
554
555 /**
556  * gdk_colors_alloc:
557  * @colormap: a #GdkColormap.
558  * @contiguous: if %TRUE, the colors should be allocated
559  *    in contiguous color cells.
560  * @planes: an array in which to store the plane masks.
561  * @nplanes: the number of planes to allocate. (Or zero,
562  *    to indicate that the color allocation should not be planar.)
563  * @pixels: an array into which to store allocated pixel values.
564  * @npixels: the number of pixels in each plane to allocate.
565  * 
566  * Allocates colors from a colormap. This function
567  * is obsolete. See gdk_colormap_alloc_colors().
568  * For full documentation of the fields, see 
569  * the Xlib documentation for <function>XAllocColorCells()</function>.
570  * 
571  * Return value: 
572  **/
573 gboolean
574 gdk_colors_alloc (GdkColormap   *colormap,
575                   gboolean       contiguous,
576                   gulong        *planes,
577                   gint           nplanes,
578                   gulong        *pixels,
579                   gint           npixels)
580 {
581   GdkColormapPrivateX11 *private;
582   gint return_val;
583   gint i;
584
585   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), FALSE);
586
587   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
588
589   if (private->screen->closed)
590     return FALSE;
591
592   return_val = XAllocColorCells (GDK_SCREEN_XDISPLAY (private->screen),
593                                  private->xcolormap,contiguous, planes,
594                                  nplanes, pixels, npixels);
595   if (return_val)
596     {
597       for (i = 0; i < npixels; i++)
598         {
599           private->info[pixels[i]].ref_count++;
600           private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
601         }
602     }
603
604   return return_val != 0;
605 }
606
607 /* This is almost identical to gdk_colormap_free_colors.
608  * Keep them in sync!
609  */
610
611
612 /**
613  * gdk_colors_free:
614  * @colormap: a #GdkColormap.
615  * @pixels: the pixel values of the colors to free.
616  * @npixels: the number of values in @pixels.
617  * @planes: the plane masks for all planes to free, OR'd together.
618  * 
619  * Frees colors allocated with gdk_colors_alloc(). This
620  * function is obsolete. See gdk_colormap_free_colors().
621  **/
622 void
623 gdk_colors_free (GdkColormap *colormap,
624                  gulong      *pixels,
625                  gint         npixels,
626                  gulong       planes)
627 {
628   GdkColormapPrivateX11 *private;
629   gulong *pixels_to_free;
630   gint npixels_to_free = 0;
631   gint i;
632
633   g_return_if_fail (GDK_IS_COLORMAP (colormap));
634   g_return_if_fail (pixels != NULL);
635
636   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
637
638   if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
639       (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
640     return;
641   
642   pixels_to_free = g_new (gulong, npixels);
643
644   for (i = 0; i < npixels; i++)
645     {
646       gulong pixel = pixels[i];
647       
648       if (private->info[pixel].ref_count)
649         {
650           private->info[pixel].ref_count--;
651
652           if (private->info[pixel].ref_count == 0)
653             {
654               pixels_to_free[npixels_to_free++] = pixel;
655               if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
656                 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
657               private->info[pixel].flags = 0;
658             }
659         }
660     }
661
662   if (npixels_to_free && !private->private_val && !private->screen->closed)
663     XFreeColors (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
664                  pixels_to_free, npixels_to_free, planes);
665   g_free (pixels_to_free);
666 }
667
668 /* This is almost identical to gdk_colors_free.
669  * Keep them in sync!
670  */
671
672 /**
673  * gdk_colormap_free_colors:
674  * @colormap: a #GdkColormap.
675  * @colors: the colors to free.
676  * @ncolors: the number of colors in @colors.
677  * 
678  * Frees previously allocated colors.
679  **/
680 void
681 gdk_colormap_free_colors (GdkColormap *colormap,
682                           GdkColor    *colors,
683                           gint         ncolors)
684 {
685   GdkColormapPrivateX11 *private;
686   gulong *pixels;
687   gint npixels = 0;
688   gint i;
689
690   g_return_if_fail (GDK_IS_COLORMAP (colormap));
691   g_return_if_fail (colors != NULL);
692
693   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
694
695   if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
696       (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
697     return;
698
699   pixels = g_new (gulong, ncolors);
700
701   for (i = 0; i < ncolors; i++)
702     {
703       gulong pixel = colors[i].pixel;
704       
705       if (private->info[pixel].ref_count)
706         {
707           private->info[pixel].ref_count--;
708
709           if (private->info[pixel].ref_count == 0)
710             {
711               pixels[npixels++] = pixel;
712               if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
713                 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
714               private->info[pixel].flags = 0;
715             }
716         }
717     }
718
719   if (npixels && !private->private_val && !private->screen->closed)
720     XFreeColors (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
721                  pixels, npixels, 0);
722
723   g_free (pixels);
724 }
725
726 /********************
727  * Color allocation *
728  ********************/
729
730 /* Try to allocate a single color using XAllocColor. If it succeeds,
731  * cache the result in our colormap, and store in ret.
732  */
733 static gboolean 
734 gdk_colormap_alloc1 (GdkColormap *colormap,
735                      GdkColor    *color,
736                      GdkColor    *ret)
737 {
738   GdkColormapPrivateX11 *private;
739   XColor xcolor;
740
741   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
742
743   xcolor.red = color->red;
744   xcolor.green = color->green;
745   xcolor.blue = color->blue;
746   xcolor.pixel = color->pixel;
747   xcolor.flags = DoRed | DoGreen | DoBlue;
748
749   if (XAllocColor (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap, &xcolor))
750     {
751       ret->pixel = xcolor.pixel;
752       ret->red = xcolor.red;
753       ret->green = xcolor.green;
754       ret->blue = xcolor.blue;
755       
756       if (ret->pixel < colormap->size)
757         {
758           if (private->info[ret->pixel].ref_count) /* got a duplicate */
759             {
760               XFreeColors (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
761                            &xcolor.pixel, 1, 0);
762               private->info[ret->pixel].ref_count++;
763             }
764           else
765             {
766               colormap->colors[ret->pixel] = *color;
767               colormap->colors[ret->pixel].pixel = ret->pixel;
768               private->info[ret->pixel].ref_count = 1;
769
770               g_hash_table_insert (private->hash,
771                                    &colormap->colors[ret->pixel],
772                                    &colormap->colors[ret->pixel]);
773             }
774         }
775       return TRUE;
776     }
777   else
778     {
779       return FALSE;
780     }
781 }
782
783 static gint
784 gdk_colormap_alloc_colors_writeable (GdkColormap *colormap,
785                                      GdkColor    *colors,
786                                      gint         ncolors,
787                                      gboolean     writeable,
788                                      gboolean     best_match,
789                                      gboolean    *success)
790 {
791   GdkColormapPrivateX11 *private;
792   gulong *pixels;
793   Status status;
794   gint i, index;
795
796   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
797
798   if (private->private_val)
799     {
800       index = 0;
801       for (i = 0; i < ncolors; i++)
802         {
803           while ((index < colormap->size) && (private->info[index].ref_count != 0))
804             index++;
805           
806           if (index < colormap->size)
807             {
808               colors[i].pixel = index;
809               success[i] = TRUE;
810               private->info[index].ref_count++;
811               private->info[i].flags |= GDK_COLOR_WRITEABLE;
812             }
813           else
814             break;
815         }
816       return ncolors - i;
817     }
818   else
819     {
820       pixels = g_new (gulong, ncolors);
821       /* Allocation of a writeable color cells */
822       
823       status =  XAllocColorCells (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
824                                   FALSE, NULL, 0, pixels, ncolors);
825       if (status)
826         {
827           for (i = 0; i < ncolors; i++)
828             {
829               colors[i].pixel = pixels[i];
830               success[i] = TRUE;
831               private->info[pixels[i]].ref_count++;
832               private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
833             }
834         }
835       
836       g_free (pixels);
837
838       return status ? 0 : ncolors; 
839     }
840 }
841
842 static gint
843 gdk_colormap_alloc_colors_private (GdkColormap *colormap,
844                                    GdkColor    *colors,
845                                    gint         ncolors,
846                                    gboolean     writeable,
847                                    gboolean     best_match,
848                                    gboolean    *success)
849 {
850   GdkColormapPrivateX11 *private;
851   gint i, index;
852   XColor *store = g_new (XColor, ncolors);
853   gint nstore = 0;
854   gint nremaining = 0;
855   
856   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
857
858   /* First, store the colors we have room for */
859
860   index = 0;
861   for (i = 0; i < ncolors; i++)
862     {
863       if (!success[i])
864         {
865           while ((index < colormap->size) && (private->info[index].ref_count != 0))
866             index++;
867
868           if (index < colormap->size)
869             {
870               store[nstore].red = colors[i].red;
871               store[nstore].blue = colors[i].blue;
872               store[nstore].green = colors[i].green;
873               store[nstore].pixel = index;
874               store[nstore].flags = DoRed | DoGreen | DoBlue;
875               nstore++;
876
877               success[i] = TRUE;
878               colors[i].pixel = index;
879
880               colormap->colors[index] = colors[i];
881               private->info[index].ref_count++;
882
883               g_hash_table_insert (private->hash,
884                                    &colormap->colors[index],
885                                    &colormap->colors[index]);
886             }
887           else
888             nremaining++;
889         }
890     }
891   
892   XStoreColors (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
893                 store, nstore);
894   g_free (store);
895
896   if (nremaining > 0 && best_match)
897     {
898       /* Get best matches for remaining colors */
899
900       gchar *available = g_new (gchar, colormap->size);
901       for (i = 0; i < colormap->size; i++)
902         available[i] = !(private->info[i].flags & GDK_COLOR_WRITEABLE);
903
904       for (i = 0; i < ncolors; i++)
905         {
906           if (!success[i])
907             {
908               index = gdk_colormap_match_color (colormap, 
909                                                 &colors[i], 
910                                                 available);
911               if (index != -1)
912                 {
913                   colors[i] = colormap->colors[index];
914                   private->info[index].ref_count++;
915
916                   success[i] = TRUE;
917                   nremaining--;
918                 }
919             }
920         }
921       g_free (available);
922     }
923
924   return nremaining;
925 }
926
927 static gint
928 gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
929                                   GdkColor    *colors,
930                                   gint         ncolors,
931                                   gboolean     writeable,
932                                   gboolean     best_match,
933                                   gboolean    *success)
934 {
935   GdkColormapPrivateX11 *private;
936   gint i, index;
937   gint nremaining = 0;
938   gint nfailed = 0;
939
940   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
941
942   for (i = 0; i < ncolors; i++)
943     {
944       if (!success[i])
945         {
946           if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
947             success[i] = TRUE;
948           else
949             nremaining++;
950         }
951     }
952
953
954   if (nremaining > 0 && best_match)
955     {
956       gchar *available = g_new (gchar, colormap->size);
957       for (i = 0; i < colormap->size; i++)
958         available[i] = ((private->info[i].ref_count == 0) ||
959                         !(private->info[i].flags & GDK_COLOR_WRITEABLE));
960       gdk_colormap_sync (colormap, FALSE);
961       
962       while (nremaining > 0)
963         {
964           for (i = 0; i < ncolors; i++)
965             {
966               if (!success[i])
967                 {
968                   index = gdk_colormap_match_color (colormap, &colors[i], available);
969                   if (index != -1)
970                     {
971                       if (private->info[index].ref_count)
972                         {
973                           private->info[index].ref_count++;
974                           colors[i] = colormap->colors[index];
975                           success[i] = TRUE;
976                           nremaining--;
977                         }
978                       else
979                         {
980                           if (gdk_colormap_alloc1 (colormap, 
981                                                    &colormap->colors[index],
982                                                    &colors[i]))
983                             {
984                               success[i] = TRUE;
985                               nremaining--;
986                               break;
987                             }
988                           else
989                             {
990                               available[index] = FALSE;
991                             }
992                         }
993                     }
994                   else
995                     {
996                       nfailed++;
997                       nremaining--;
998                       success[i] = 2; /* flag as permanent failure */
999                     }
1000                 }
1001             }
1002         }
1003       g_free (available);
1004     }
1005
1006   /* Change back the values we flagged as permanent failures */
1007   if (nfailed > 0)
1008     {
1009       for (i = 0; i < ncolors; i++)
1010         if (success[i] == 2)
1011           success[i] = FALSE;
1012       nremaining = nfailed;
1013     }
1014   
1015   return nremaining;
1016 }
1017
1018 static gint
1019 gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
1020                                        GdkColor    *colors,
1021                                        gint         ncolors,
1022                                        gboolean     writeable,
1023                                        gboolean     best_match,
1024                                        gboolean    *success)
1025 {
1026   GdkColormapPrivateX11 *private;
1027   GdkColor *lookup_color;
1028   gint i;
1029   gint nremaining = 0;
1030
1031   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1032
1033   /* Check for an exact match among previously allocated colors */
1034
1035   for (i = 0; i < ncolors; i++)
1036     {
1037       if (!success[i])
1038         {
1039           lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
1040           if (lookup_color)
1041             {
1042               private->info[lookup_color->pixel].ref_count++;
1043               colors[i].pixel = lookup_color->pixel;
1044               success[i] = TRUE;
1045             }
1046           else
1047             nremaining++;
1048         }
1049     }
1050
1051   /* If that failed, we try to allocate a new color, or approxmiate
1052    * with what we can get if best_match is TRUE.
1053    */
1054   if (nremaining > 0)
1055     {
1056       if (private->private_val)
1057         return gdk_colormap_alloc_colors_private (colormap, colors, ncolors, writeable, best_match, success);
1058       else
1059         return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
1060     }
1061   else
1062     return 0;
1063 }
1064
1065 /**
1066  * gdk_colormap_alloc_colors:
1067  * @colormap: a #GdkColormap.
1068  * @colors: The color values to allocate. On return, the pixel
1069  *    values for allocated colors will be filled in.
1070  * @ncolors: The number of colors in @colors.
1071  * @writeable: If %TRUE, the colors are allocated writeable
1072  *    (their values can later be changed using gdk_color_change()).
1073  *    Writeable colors cannot be shared between applications.
1074  * @best_match: If %TRUE, GDK will attempt to do matching against
1075  *    existing colors if the colors cannot be allocated as requested.
1076  * @success: An array of length @ncolors. On return, this
1077  *   indicates whether the corresponding color in @colors was
1078  *   successfully allocated or not.
1079  * 
1080  * Allocates colors from a colormap.
1081  * 
1082  * Return value: The number of colors that were not successfully 
1083  * allocated.
1084  **/
1085 gint
1086 gdk_colormap_alloc_colors (GdkColormap *colormap,
1087                            GdkColor    *colors,
1088                            gint         ncolors,
1089                            gboolean     writeable,
1090                            gboolean     best_match,
1091                            gboolean    *success)
1092 {
1093   GdkColormapPrivateX11 *private;
1094   GdkVisual *visual;
1095   gint i;
1096   gint nremaining = 0;
1097   XColor xcolor;
1098
1099   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), ncolors);
1100   g_return_val_if_fail (colors != NULL, ncolors);
1101   g_return_val_if_fail (success != NULL, ncolors);
1102
1103   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1104
1105   if (private->screen->closed)
1106     return ncolors;
1107
1108   for (i = 0; i < ncolors; i++)
1109     success[i] = FALSE;
1110
1111   switch (colormap->visual->type)
1112     {
1113     case GDK_VISUAL_PSEUDO_COLOR:
1114     case GDK_VISUAL_GRAYSCALE:
1115       if (writeable)
1116         return gdk_colormap_alloc_colors_writeable (colormap, colors, ncolors,
1117                                                     writeable, best_match, success);
1118       else
1119         return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
1120                                                     writeable, best_match, success);
1121       break;
1122
1123     case GDK_VISUAL_DIRECT_COLOR:
1124     case GDK_VISUAL_TRUE_COLOR:
1125       visual = colormap->visual;
1126
1127       for (i = 0; i < ncolors; i++)
1128         {
1129           colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
1130                              ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
1131                              ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
1132           success[i] = TRUE;
1133         }
1134       break;
1135     case GDK_VISUAL_STATIC_GRAY:
1136     case GDK_VISUAL_STATIC_COLOR:
1137       for (i = 0; i < ncolors; i++)
1138         {
1139           xcolor.red = colors[i].red;
1140           xcolor.green = colors[i].green;
1141           xcolor.blue = colors[i].blue;
1142           xcolor.pixel = colors[i].pixel;
1143           xcolor.flags = DoRed | DoGreen | DoBlue;
1144
1145           if (XAllocColor (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap, &xcolor))
1146             {
1147               colors[i].pixel = xcolor.pixel;
1148               success[i] = TRUE;
1149             }
1150           else
1151             nremaining++;
1152         }
1153       break;
1154     }
1155   return nremaining;
1156 }
1157
1158 /**
1159  * gdk_colormap_query_color:
1160  * @colormap: a #GdkColormap
1161  * @pixel: pixel value in hardware display format
1162  * @result: #GdkColor with red, green, blue fields initialized
1163  * 
1164  * Locates the RGB color in @colormap corresponding to the given
1165  * hardware pixel @pixel. @pixel must be a valid pixel in the
1166  * colormap; it's a programmer error to call this function with a
1167  * pixel which is not in the colormap. Hardware pixels are normally
1168  * obtained from gdk_colormap_alloc_colors(), or from a #GdkImage. (A
1169  * #GdkImage contains image data in hardware format, a #GdkPixbuf
1170  * contains image data in a canonical 24-bit RGB format.)
1171  *
1172  * This function is rarely useful; it's used for example to
1173  * implement the eyedropper feature in #GtkColorSelection.
1174  * 
1175  **/
1176 void
1177 gdk_colormap_query_color (GdkColormap *colormap,
1178                           gulong       pixel,
1179                           GdkColor    *result)
1180 {
1181   XColor xcolor;
1182   GdkVisual *visual;
1183   GdkColormapPrivateX11 *private;
1184   
1185   g_return_if_fail (GDK_IS_COLORMAP (colormap));
1186   
1187   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1188
1189   visual = gdk_colormap_get_visual (colormap);
1190
1191   switch (visual->type) {
1192   case GDK_VISUAL_DIRECT_COLOR:
1193   case GDK_VISUAL_TRUE_COLOR:
1194     result->red = 65535. * (double)((pixel & visual->red_mask) >> visual->red_shift) / ((1 << visual->red_prec) - 1);
1195     result->green = 65535. * (double)((pixel & visual->green_mask) >> visual->green_shift) / ((1 << visual->green_prec) - 1);
1196     result->blue = 65535. * (double)((pixel & visual->blue_mask) >> visual->blue_shift) / ((1 << visual->blue_prec) - 1);
1197     break;
1198   case GDK_VISUAL_STATIC_GRAY:
1199   case GDK_VISUAL_GRAYSCALE:
1200     result->red = result->green = result->blue = 65535. * (double)pixel/((1<<visual->depth) - 1);
1201     break;
1202   case GDK_VISUAL_STATIC_COLOR:
1203     xcolor.pixel = pixel;
1204     if (!private->screen->closed)
1205       {
1206         XQueryColor (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap, &xcolor);
1207         result->red = xcolor.red;
1208         result->green = xcolor.green;
1209         result->blue =  xcolor.blue;
1210       }
1211     else
1212       result->red = result->green = result->blue = 0;
1213     break;
1214   case GDK_VISUAL_PSEUDO_COLOR:
1215     g_return_if_fail (pixel < colormap->size);
1216     result->red = colormap->colors[pixel].red;
1217     result->green = colormap->colors[pixel].green;
1218     result->blue = colormap->colors[pixel].blue;
1219     break;
1220   default:
1221     g_assert_not_reached ();
1222     break;
1223   }
1224 }
1225
1226 /**
1227  * gdk_color_change:
1228  * @colormap: a #GdkColormap.
1229  * @color: a #GdkColor, with the color to change
1230  * in the <structfield>pixel</structfield> field,
1231  * and the new value in the remaining fields.
1232  * 
1233  * Changes the value of a color that has already
1234  * been allocated. If @colormap is not a private
1235  * colormap, then the color must have been allocated
1236  * using gdk_colormap_alloc_colors() with the 
1237  * @writeable set to %TRUE.
1238  * 
1239  * Return value: %TRUE if the color was successfully changed.
1240  **/
1241 gboolean
1242 gdk_color_change (GdkColormap *colormap,
1243                   GdkColor    *color)
1244 {
1245   GdkColormapPrivateX11 *private;
1246   XColor xcolor;
1247
1248   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), FALSE);
1249   g_return_val_if_fail (color != NULL, FALSE);
1250
1251   xcolor.pixel = color->pixel;
1252   xcolor.red = color->red;
1253   xcolor.green = color->green;
1254   xcolor.blue = color->blue;
1255   xcolor.flags = DoRed | DoGreen | DoBlue;
1256
1257   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1258   if (!private->screen->closed)
1259     XStoreColor (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap, &xcolor);
1260
1261   return TRUE;
1262 }
1263
1264 /**
1265  * gdk_x11_colormap_foreign_new:
1266  * @visual: a #GdkVisual
1267  * @xcolormap: The XID of a colormap with visual @visual
1268  * 
1269  * If xcolormap refers to a colormap previously known to GTK+,
1270  * returns a new reference to the existing #GdkColormap object,
1271  * otherwise creates a new GdkColormap object and returns that
1272  *
1273  * Return value: the #GdkColormap object for @xcolormap.
1274  *   Free with g_object_unref(). Note that for colormap created
1275  *   with gdk_x11_colormap_foreign_new(), unref'ing the last
1276  *   reference to the object will only free the #GdkColoramp
1277  *   object and not call XFreeColormap()
1278  *
1279  * Since: 2.2
1280  **/
1281 GdkColormap *
1282 gdk_x11_colormap_foreign_new (GdkVisual *visual,
1283                               Colormap   xcolormap)
1284 {
1285   GdkColormap *colormap;
1286   GdkScreen *screen;
1287   GdkColormapPrivateX11 *private;
1288   
1289   g_return_val_if_fail (GDK_IS_VISUAL (visual), NULL);
1290   g_return_val_if_fail (xcolormap != None, NULL);
1291
1292   screen = gdk_visual_get_screen (visual);
1293   
1294   if (xcolormap == DefaultColormap (GDK_SCREEN_XDISPLAY (screen),
1295                                     GDK_SCREEN_XNUMBER (screen)))
1296     return g_object_ref (gdk_screen_get_system_colormap (screen));
1297
1298   colormap = gdk_colormap_lookup (screen, xcolormap);
1299   if (colormap)
1300     return g_object_ref (colormap);
1301
1302   colormap = g_object_new (GDK_TYPE_COLORMAP, NULL);
1303   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1304
1305   colormap->visual = visual;
1306
1307   private->screen = screen;
1308   private->xcolormap = xcolormap;
1309   private->private_val = FALSE;
1310
1311   colormap->size = visual->colormap_size;
1312
1313   switch (colormap->visual->type)
1314     {
1315     case GDK_VISUAL_GRAYSCALE:
1316     case GDK_VISUAL_PSEUDO_COLOR:
1317       private->info = g_new0 (GdkColorInfo, colormap->size);
1318       private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
1319                                         (GEqualFunc) gdk_color_equal);
1320       /* Fall through */
1321     case GDK_VISUAL_STATIC_GRAY:
1322     case GDK_VISUAL_STATIC_COLOR:
1323     case GDK_VISUAL_DIRECT_COLOR:
1324       colormap->colors = g_new (GdkColor, colormap->size);
1325       gdk_colormap_sync (colormap, TRUE);
1326       
1327     case GDK_VISUAL_TRUE_COLOR:
1328       break;
1329     }
1330
1331   gdk_colormap_add (colormap);
1332
1333   return colormap;
1334   
1335 }
1336
1337 /**
1338  * gdkx_colormap_get:
1339  * @xcolormap: the XID of a colormap for the default screen.
1340  * 
1341  * Returns a #GdkColormap corresponding to a X colormap;
1342  * this function only works if the colormap is already
1343  * known to GTK+ (a colormap created by GTK+ or the default
1344  * colormap for the screen), since GTK+ 
1345  *
1346  * Always use gdk_x11_colormap_foreign_new() instead.
1347  *
1348  * Return value: the existing #GdkColormap object if it was
1349  *  already known to GTK+, otherwise warns and return
1350  *  %NULL.
1351  **/
1352 GdkColormap*
1353 gdkx_colormap_get (Colormap xcolormap)
1354 {
1355   GdkScreen *screen = gdk_screen_get_default ();
1356   GdkColormap *colormap;
1357
1358   if (xcolormap == DefaultColormap (GDK_SCREEN_XDISPLAY (screen),
1359                                     GDK_SCREEN_XNUMBER (screen)));
1360     return g_object_ref (gdk_screen_get_system_colormap (screen));
1361
1362   colormap = gdk_colormap_lookup (screen, xcolormap);
1363   if (colormap)
1364     return g_object_ref (colormap);
1365
1366   g_warning ("Colormap passed to gdkx_colormap_get\n"
1367              "does not previously exist");
1368
1369   return NULL;
1370 }
1371
1372 static gint
1373 gdk_colormap_match_color (GdkColormap *cmap,
1374                           GdkColor    *color,
1375                           const gchar *available)
1376 {
1377   GdkColor *colors;
1378   guint sum, max;
1379   gint rdiff, gdiff, bdiff;
1380   gint i, index;
1381
1382   colors = cmap->colors;
1383   max = 3 * (65536);
1384   index = -1;
1385
1386   for (i = 0; i < cmap->size; i++)
1387     {
1388       if ((!available) || (available && available[i]))
1389         {
1390           rdiff = (color->red - colors[i].red);
1391           gdiff = (color->green - colors[i].green);
1392           bdiff = (color->blue - colors[i].blue);
1393
1394           sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1395
1396           if (sum < max)
1397             {
1398               index = i;
1399               max = sum;
1400             }
1401         }
1402     }
1403
1404   return index;
1405 }
1406
1407
1408 static GdkColormap*
1409 gdk_colormap_lookup (GdkScreen *screen,
1410                      Colormap   xcolormap)
1411 {
1412   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1413
1414   if (screen_x11->colormap_hash)
1415     return g_hash_table_lookup (screen_x11->colormap_hash, &xcolormap);
1416   else
1417     return NULL;
1418 }
1419
1420 static void
1421 gdk_colormap_add (GdkColormap *cmap)
1422 {
1423   GdkScreenX11 *screen_x11;
1424   GdkColormapPrivateX11 *private;
1425
1426   private = GDK_COLORMAP_PRIVATE_DATA (cmap);
1427   screen_x11 = GDK_SCREEN_X11 (private->screen);
1428
1429   if (!screen_x11->colormap_hash)
1430     screen_x11->colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
1431                                                   (GEqualFunc) gdk_colormap_equal);
1432
1433   g_hash_table_insert (screen_x11->colormap_hash, &private->xcolormap, cmap);
1434 }
1435
1436 static void
1437 gdk_colormap_remove (GdkColormap *cmap)
1438 {
1439   GdkScreenX11 *screen_x11;
1440   GdkColormapPrivateX11 *private;
1441
1442   private = GDK_COLORMAP_PRIVATE_DATA (cmap);
1443   screen_x11 = GDK_SCREEN_X11 (private->screen);
1444
1445   if (screen_x11->colormap_hash)
1446     g_hash_table_remove (screen_x11->colormap_hash, &private->xcolormap);
1447 }
1448
1449 static guint
1450 gdk_colormap_hash (Colormap *colormap)
1451 {
1452   return *colormap;
1453 }
1454
1455 static gboolean
1456 gdk_colormap_equal (Colormap *a,
1457                     Colormap *b)
1458 {
1459   return (*a == *b);
1460 }
1461
1462 /**
1463  * gdk_x11_colormap_get_xdisplay:
1464  * @colormap: a #GdkColormap.
1465  * 
1466  * Returns the display of a #GdkColormap.
1467  * 
1468  * Return value: an Xlib <type>Display*</type>.
1469  **/
1470 Display *
1471 gdk_x11_colormap_get_xdisplay (GdkColormap *colormap)
1472 {
1473   GdkColormapPrivateX11 *private;
1474
1475   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), NULL);
1476
1477   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1478
1479   return GDK_SCREEN_XDISPLAY (private->screen);
1480 }
1481
1482 /**
1483  * gdk_x11_colormap_get_xcolormap:
1484  * @colormap:  a #GdkColormap.
1485  * 
1486  * Returns the X colormap belonging to a #GdkColormap.
1487  * 
1488  * Return value: an Xlib <type>Colormap</type>.
1489  **/
1490 Colormap
1491 gdk_x11_colormap_get_xcolormap (GdkColormap *colormap)
1492 {
1493   GdkColormapPrivateX11 *private;
1494
1495   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), None);
1496
1497   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1498
1499   if (private->screen->closed)
1500     return None;
1501   else
1502     return private->xcolormap;
1503 }
1504
1505 /**
1506  * gdk_colormap_get_screen:
1507  * @cmap: a #GdkColormap
1508  * 
1509  * Gets the screen for which this colormap was created.
1510  * 
1511  * Return value: the screen for which this colormap was created.
1512  *
1513  * Since: 2.2
1514  **/
1515 GdkScreen *
1516 gdk_colormap_get_screen (GdkColormap *cmap)
1517 {
1518   g_return_val_if_fail (GDK_IS_COLORMAP (cmap), NULL);
1519
1520   return  GDK_COLORMAP_PRIVATE_DATA (cmap)->screen;
1521 }