]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkcolor-x11.c
7fa8cc044ea4ca4f2f3160dd8d1810b9ead3d7bd
[~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 <time.h>
28
29 #include "gdkcolor.h"
30 #include "gdkinternals.h"
31 #include "gdkx.h"
32 #include "gdkprivate-x11.h"
33 #include "gdkscreen-x11.h"
34
35 typedef struct _GdkColormapPrivateX11  GdkColormapPrivateX11;
36
37 struct _GdkColormapPrivateX11
38 {
39   GdkScreen *screen;
40   Colormap xcolormap;
41   gint private_val;
42
43   GHashTable *hash;
44   GdkColorInfo *info;
45   time_t last_sync_time;
46
47   guint foreign : 1;
48 };
49
50 #define GDK_COLORMAP_PRIVATE_DATA(cmap) ((GdkColormapPrivateX11 *) GDK_COLORMAP (cmap)->windowing_data)
51
52 static gint     gdk_colormap_match_color (GdkColormap *cmap,
53                                           GdkColor    *color,
54                                           const gchar *available);
55 static void     gdk_colormap_add         (GdkColormap *cmap);
56 static void     gdk_colormap_remove      (GdkColormap *cmap);
57
58 static GdkColormap *gdk_colormap_lookup   (GdkScreen   *screen,
59                                            Colormap     xcolormap);
60
61 static guint    gdk_colormap_hash        (Colormap    *cmap);
62 static gboolean gdk_colormap_equal       (Colormap    *a,
63                                           Colormap    *b);
64 static void     gdk_colormap_sync        (GdkColormap *colormap,
65                                           gboolean     force);
66
67 static void gdk_colormap_init       (GdkColormap      *colormap);
68 static void gdk_colormap_class_init (GdkColormapClass *klass);
69 static void gdk_colormap_finalize   (GObject              *object);
70
71 static gpointer parent_class = NULL;
72
73 GType
74 gdk_colormap_get_type (void)
75 {
76   static GType object_type = 0;
77
78   if (!object_type)
79     {
80       static const GTypeInfo object_info =
81       {
82         sizeof (GdkColormapClass),
83         (GBaseInitFunc) NULL,
84         (GBaseFinalizeFunc) NULL,
85         (GClassInitFunc) gdk_colormap_class_init,
86         NULL,           /* class_finalize */
87         NULL,           /* class_data */
88         sizeof (GdkColormap),
89         0,              /* n_preallocs */
90         (GInstanceInitFunc) gdk_colormap_init,
91       };
92       
93       object_type = g_type_register_static (G_TYPE_OBJECT,
94                                             "GdkColormap",
95                                             &object_info, 0);
96     }
97   
98   return object_type;
99 }
100
101 static void
102 gdk_colormap_init (GdkColormap *colormap)
103 {
104   GdkColormapPrivateX11 *private;
105
106   private = g_new (GdkColormapPrivateX11, 1);
107
108   colormap->windowing_data = private;
109   
110   private->screen = NULL;
111   private->hash = NULL;
112   private->last_sync_time = 0;
113   private->info = NULL;
114
115   colormap->size = 0;
116   colormap->colors = NULL;
117 }
118
119 static void
120 gdk_colormap_class_init (GdkColormapClass *klass)
121 {
122   GObjectClass *object_class = G_OBJECT_CLASS (klass);
123
124   parent_class = g_type_class_peek_parent (klass);
125
126   object_class->finalize = gdk_colormap_finalize;
127 }
128
129 static void
130 gdk_colormap_finalize (GObject *object)
131 {
132   GdkColormap *colormap = GDK_COLORMAP (object);
133   GdkColormapPrivateX11 *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
134
135   gdk_colormap_remove (colormap);
136
137   if (!private->screen->closed)
138     XFreeColormap (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap);
139
140   if (private->hash)
141     g_hash_table_destroy (private->hash);
142   
143   g_free (private->info);
144   g_free (colormap->colors);
145   g_free (private);
146   
147   G_OBJECT_CLASS (parent_class)->finalize (object);
148 }
149
150 /**
151  * gdk_colormap_new:
152  * @visual: a #GdkVisual.
153  * @allocate: if %TRUE, the newly created colormap will be
154  * a private colormap, and all colors in it will be
155  * allocated for the applications use.
156  * 
157  * Creates a new colormap for the given visual.
158  * 
159  * Return value: the new #GdkColormap.
160  **/
161 GdkColormap*
162 gdk_colormap_new (GdkVisual *visual,
163                   gboolean   allocate)
164 {
165   GdkColormap *colormap;
166   GdkColormapPrivateX11 *private;
167   Visual *xvisual;
168   Display *xdisplay;
169   Window xrootwin;
170   int size;
171   int i;
172
173   /* FIXME when object properties settle down, there needs to be some
174    * kind of default construction (and construct-only arguments)
175    */
176   
177   g_return_val_if_fail (visual != NULL, NULL);
178
179   colormap = g_object_new (GDK_TYPE_COLORMAP, NULL);
180   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
181
182   colormap->visual = visual;
183   private->screen = gdk_visual_get_screen (visual);
184   
185   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
186   xdisplay = GDK_SCREEN_XDISPLAY (private->screen);
187   xrootwin = GDK_SCREEN_XROOTWIN (private->screen);
188
189   colormap->size = visual->colormap_size;
190
191   switch (visual->type)
192     {
193     case GDK_VISUAL_GRAYSCALE:
194     case GDK_VISUAL_PSEUDO_COLOR:
195       private->info = g_new0 (GdkColorInfo, colormap->size);
196       colormap->colors = g_new (GdkColor, colormap->size);
197       
198       private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
199                                         (GEqualFunc) gdk_color_equal);
200       
201       private->private_val = allocate;
202       private->xcolormap = XCreateColormap (xdisplay, xrootwin,
203                                             xvisual, (allocate) ? (AllocAll) : (AllocNone));
204
205       if (allocate)
206         {
207           GdkVisual *system_visual;
208           XColor *default_colors;
209           gint n_default_colors;
210
211           system_visual = gdk_screen_get_system_visual (private->screen);
212           n_default_colors = MIN (system_visual->colormap_size, colormap->size);
213
214           default_colors = g_new (XColor, colormap->size);
215
216           for (i = 0; i < n_default_colors; i++)
217             default_colors[i].pixel = i;
218           
219           XQueryColors (xdisplay,
220                         DefaultColormapOfScreen (GDK_SCREEN_X11 (private->screen)->xscreen),
221                         default_colors, n_default_colors);
222
223           for (i = 0; i < n_default_colors; i++)
224             {
225               colormap->colors[i].pixel = default_colors[i].pixel;
226               colormap->colors[i].red = default_colors[i].red;
227               colormap->colors[i].green = default_colors[i].green;
228               colormap->colors[i].blue = default_colors[i].blue;
229             }
230
231           gdk_colormap_change (colormap, n_default_colors);
232           
233           g_free (default_colors);
234         }
235       break;
236
237     case GDK_VISUAL_DIRECT_COLOR:
238       private->private_val = TRUE;
239       private->xcolormap = XCreateColormap (xdisplay, xrootwin,
240                                             xvisual, AllocAll);
241       colormap->colors = g_new (GdkColor, colormap->size);
242
243       size = 1 << visual->red_prec;
244       for (i = 0; i < size; i++)
245         colormap->colors[i].red = i * 65535 / (size - 1);
246
247       size = 1 << visual->green_prec;
248       for (i = 0; i < size; i++)
249         colormap->colors[i].green = i * 65535 / (size - 1);
250
251       size = 1 << visual->blue_prec;
252       for (i = 0; i < size; i++)
253         colormap->colors[i].blue = i * 65535 / (size - 1);
254
255       gdk_colormap_change (colormap, colormap->size);
256       break;
257
258     case GDK_VISUAL_STATIC_GRAY:
259     case GDK_VISUAL_STATIC_COLOR:
260       private->private_val = FALSE;
261       private->xcolormap = XCreateColormap (xdisplay, xrootwin,
262                                             xvisual, AllocNone);
263       
264       colormap->colors = g_new (GdkColor, colormap->size);
265       gdk_colormap_sync (colormap, TRUE);
266       break;
267       
268     case GDK_VISUAL_TRUE_COLOR:
269       private->private_val = FALSE;
270       private->xcolormap = XCreateColormap (xdisplay, xrootwin,
271                                             xvisual, AllocNone);
272       break;
273     }
274
275   gdk_colormap_add (colormap);
276
277   return colormap;
278 }
279
280 static void
281 gdk_colormap_sync_palette (GdkColormap *colormap)
282 {
283   GdkColormapPrivateX11 *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
284   XColor *xpalette;
285   gint nlookup;
286   gint i;
287
288   nlookup = 0;
289   xpalette = g_new (XColor, colormap->size);
290   
291   for (i = 0; i < colormap->size; i++)
292     {
293       if (!private->info || private->info[i].ref_count == 0)
294         {
295           xpalette[nlookup].pixel = i;
296           xpalette[nlookup].red = 0;
297           xpalette[nlookup].green = 0;
298           xpalette[nlookup].blue = 0;
299           nlookup++;
300         }
301     }
302
303   XQueryColors (GDK_SCREEN_XDISPLAY (private->screen),
304                 private->xcolormap, xpalette, nlookup);
305   
306   for (i = 0; i < nlookup; i++)
307     {
308       gulong pixel = xpalette[i].pixel;
309       colormap->colors[pixel].pixel = pixel;
310       colormap->colors[pixel].red = xpalette[i].red;
311       colormap->colors[pixel].green = xpalette[i].green;
312       colormap->colors[pixel].blue = xpalette[i].blue;
313     }
314   
315   g_free (xpalette);
316 }
317
318 static void
319 gdk_colormap_sync_direct_color (GdkColormap *colormap)
320 {
321   GdkColormapPrivateX11 *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
322   GdkVisual *visual = colormap->visual;
323   XColor *xpalette;
324   gint i;
325
326   xpalette = g_new (XColor, colormap->size);
327   
328   for (i = 0; i < colormap->size; i++)
329     {
330       xpalette[i].pixel =
331         (((i << visual->red_shift)   & visual->red_mask)   |
332          ((i << visual->green_shift) & visual->green_mask) |
333          ((i << visual->blue_shift)  & visual->blue_mask));
334     }
335
336   XQueryColors (GDK_SCREEN_XDISPLAY (private->screen),
337                 private->xcolormap, xpalette, colormap->size);
338   
339   for (i = 0; i < colormap->size; i++)
340     {
341       colormap->colors[i].pixel = xpalette[i].pixel;
342       colormap->colors[i].red = xpalette[i].red;
343       colormap->colors[i].green = xpalette[i].green;
344       colormap->colors[i].blue = xpalette[i].blue;
345     }
346   
347   g_free (xpalette);
348 }
349
350 #define MIN_SYNC_TIME 2
351
352 static void
353 gdk_colormap_sync (GdkColormap *colormap,
354                    gboolean     force)
355 {
356   time_t current_time;
357   GdkColormapPrivateX11 *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
358
359   g_return_if_fail (GDK_IS_COLORMAP (colormap));
360
361   if (private->screen->closed)
362     return;
363
364   current_time = time (NULL);
365   if (!force && ((current_time - private->last_sync_time) < MIN_SYNC_TIME))
366     return;
367
368   private->last_sync_time = current_time;
369
370   if (colormap->visual->type == GDK_VISUAL_DIRECT_COLOR)
371     gdk_colormap_sync_direct_color (colormap);
372   else
373     gdk_colormap_sync_palette (colormap);
374 }
375                    
376 /**
377  * gdk_screen_get_system_colormap:
378  * @screen: a #GdkScreen
379  *
380  * Gets the system's default colormap for @screen
381  *
382  * Returns: the default colormap for @screen.
383  *
384  * Since: 2.2
385  */
386 GdkColormap *
387 gdk_screen_get_system_colormap (GdkScreen *screen)
388 {
389   GdkColormap *colormap = NULL;
390   GdkColormapPrivateX11 *private;
391   GdkScreenX11 *screen_x11;
392
393   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
394   screen_x11 = GDK_SCREEN_X11 (screen);
395
396   if (screen_x11->system_colormap)
397     return screen_x11->system_colormap;
398
399   colormap = g_object_new (GDK_TYPE_COLORMAP, NULL);
400   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
401
402   private->screen = screen;
403   colormap->visual = gdk_screen_get_system_visual (screen);
404   
405   private->xcolormap = DefaultColormapOfScreen (screen_x11->xscreen);
406   private->private_val = FALSE;
407
408   private->hash = NULL;
409   private->last_sync_time = 0;
410   private->info = NULL;
411
412   colormap->colors = NULL;
413   colormap->size = colormap->visual->colormap_size;
414
415   switch (colormap->visual->type)
416     {
417     case GDK_VISUAL_GRAYSCALE:
418     case GDK_VISUAL_PSEUDO_COLOR:
419       private->info = g_new0 (GdkColorInfo, colormap->size);
420       private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
421                                         (GEqualFunc) gdk_color_equal);
422       /* Fall through */
423     case GDK_VISUAL_STATIC_GRAY:
424     case GDK_VISUAL_STATIC_COLOR:
425     case GDK_VISUAL_DIRECT_COLOR:
426       colormap->colors = g_new (GdkColor, colormap->size);
427       gdk_colormap_sync (colormap, TRUE);
428       
429     case GDK_VISUAL_TRUE_COLOR:
430       break;
431     }
432   
433   gdk_colormap_add (colormap);
434   screen_x11->system_colormap = colormap;
435   
436   return colormap;
437 }
438
439 /**
440  * gdk_colormap_get_system_size:
441  * 
442  * Returns the size of the system's default colormap.
443  * (See the description of struct #GdkColormap for an
444  * explanation of the size of a colormap.)
445  * 
446  * Return value: the size of the system's default colormap.
447  **/
448 gint
449 gdk_colormap_get_system_size (void)
450 {
451   return DisplayCells (GDK_SCREEN_XDISPLAY (gdk_screen_get_default()),
452                        GDK_SCREEN_X11 (gdk_screen_get_default())->screen_num);
453 }
454
455 /**
456  * gdk_colormap_change:
457  * @colormap: a #GdkColormap.
458  * @ncolors: the number of colors to change.
459  * 
460  * Changes the value of the first @ncolors in a private colormap
461  * to match the values in the <structfield>colors</structfield>
462  * array in the colormap. This function is obsolete and
463  * should not be used. See gdk_color_change().
464  **/
465 void
466 gdk_colormap_change (GdkColormap *colormap,
467                      gint         ncolors)
468 {
469   GdkColormapPrivateX11 *private;
470   GdkVisual *visual;
471   XColor *palette;
472   Display *xdisplay;
473   gint shift;
474   int max_colors;
475   int size;
476   int i;
477
478   g_return_if_fail (GDK_IS_COLORMAP (colormap));
479
480   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
481
482   if (private->screen->closed)
483     return;
484
485   xdisplay = GDK_SCREEN_XDISPLAY (private->screen);
486   palette = g_new (XColor, ncolors);
487
488   switch (colormap->visual->type)
489     {
490     case GDK_VISUAL_GRAYSCALE:
491     case GDK_VISUAL_PSEUDO_COLOR:
492       for (i = 0; i < ncolors; i++)
493         {
494           palette[i].pixel = colormap->colors[i].pixel;
495           palette[i].red = colormap->colors[i].red;
496           palette[i].green = colormap->colors[i].green;
497           palette[i].blue = colormap->colors[i].blue;
498           palette[i].flags = DoRed | DoGreen | DoBlue;
499         }
500
501       XStoreColors (xdisplay, private->xcolormap, palette, ncolors);
502       break;
503
504     case GDK_VISUAL_DIRECT_COLOR:
505       visual = colormap->visual;
506
507       shift = visual->red_shift;
508       max_colors = 1 << visual->red_prec;
509       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
510
511       for (i = 0; i < size; i++)
512         {
513           palette[i].pixel = i << shift;
514           palette[i].red = colormap->colors[i].red;
515           palette[i].flags = DoRed;
516         }
517
518       XStoreColors (xdisplay, private->xcolormap, palette, size);
519
520       shift = visual->green_shift;
521       max_colors = 1 << visual->green_prec;
522       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
523
524       for (i = 0; i < size; i++)
525         {
526           palette[i].pixel = i << shift;
527           palette[i].green = colormap->colors[i].green;
528           palette[i].flags = DoGreen;
529         }
530
531       XStoreColors (xdisplay, private->xcolormap, palette, size);
532
533       shift = visual->blue_shift;
534       max_colors = 1 << visual->blue_prec;
535       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
536
537       for (i = 0; i < size; i++)
538         {
539           palette[i].pixel = i << shift;
540           palette[i].blue = colormap->colors[i].blue;
541           palette[i].flags = DoBlue;
542         }
543
544       XStoreColors (xdisplay, private->xcolormap, palette, size);
545       break;
546
547     default:
548       break;
549     }
550
551   g_free (palette);
552 }
553
554 /**
555  * gdk_colors_alloc:
556  * @colormap: a #GdkColormap.
557  * @contiguous: if %TRUE, the colors should be allocated
558  *    in contiguous color cells.
559  * @planes: an array in which to store the plane masks.
560  * @nplanes: the number of planes to allocate. (Or zero,
561  *    to indicate that the color allocation should not be planar.)
562  * @pixels: an array into which to store allocated pixel values.
563  * @npixels: the number of pixels in each plane to allocate.
564  * 
565  * Allocates colors from a colormap. This function
566  * is obsolete. See gdk_colormap_alloc_colors().
567  * For full documentation of the fields, see 
568  * the Xlib documentation for <function>XAllocColorCells()</function>.
569  * 
570  * Return value: 
571  **/
572 gboolean
573 gdk_colors_alloc (GdkColormap   *colormap,
574                   gboolean       contiguous,
575                   gulong        *planes,
576                   gint           nplanes,
577                   gulong        *pixels,
578                   gint           npixels)
579 {
580   GdkColormapPrivateX11 *private;
581   gint return_val;
582   gint i;
583
584   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), 0);
585
586   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
587
588   if (private->screen->closed)
589     return FALSE;
590
591   return_val = XAllocColorCells (GDK_SCREEN_XDISPLAY (private->screen),
592                                  private->xcolormap,contiguous, planes,
593                                  nplanes, pixels, npixels);
594   if (return_val)
595     {
596       for (i=0; i<npixels; i++)
597         {
598           private->info[pixels[i]].ref_count++;
599           private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
600         }
601     }
602
603   return return_val != 0;
604 }
605
606 /* This is almost identical to gdk_colormap_free_colors.
607  * Keep them in sync!
608  */
609
610
611 /**
612  * gdk_colors_free:
613  * @colormap: a #GdkColormap.
614  * @pixels: the pixel values of the colors to free.
615  * @npixels: the number of values in @pixels.
616  * @planes: the plane masks for all planes to free, OR'd together.
617  * 
618  * Frees colors allocated with gdk_colors_alloc(). This
619  * function is obsolete. See gdk_colormap_free_colors().
620  **/
621 void
622 gdk_colors_free (GdkColormap *colormap,
623                  gulong      *pixels,
624                  gint         npixels,
625                  gulong       planes)
626 {
627   GdkColormapPrivateX11 *private;
628   gulong *pixels_to_free;
629   gint npixels_to_free = 0;
630   gint i;
631
632   g_return_if_fail (GDK_IS_COLORMAP (colormap));
633   g_return_if_fail (pixels != NULL);
634
635   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
636
637   if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
638       (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
639     return;
640   
641   pixels_to_free = g_new (gulong, npixels);
642
643   for (i=0; i<npixels; i++)
644     {
645       gulong pixel = pixels[i];
646       
647       if (private->info[pixel].ref_count)
648         {
649           private->info[pixel].ref_count--;
650
651           if (private->info[pixel].ref_count == 0)
652             {
653               pixels_to_free[npixels_to_free++] = pixel;
654               if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
655                 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
656               private->info[pixel].flags = 0;
657             }
658         }
659     }
660
661   if (npixels_to_free && !private->private_val && !private->screen->closed)
662     XFreeColors (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
663                  pixels_to_free, npixels_to_free, planes);
664   g_free (pixels_to_free);
665 }
666
667 /* This is almost identical to gdk_colors_free.
668  * Keep them in sync!
669  */
670
671 /**
672  * gdk_colormap_free_colors:
673  * @colormap: a #GdkColormap.
674  * @colors: the colors to free.
675  * @ncolors: the number of colors in @colors.
676  * 
677  * Frees previously allocated colors.
678  **/
679 void
680 gdk_colormap_free_colors (GdkColormap *colormap,
681                           GdkColor    *colors,
682                           gint         ncolors)
683 {
684   GdkColormapPrivateX11 *private;
685   gulong *pixels;
686   gint npixels = 0;
687   gint i;
688
689   g_return_if_fail (GDK_IS_COLORMAP (colormap));
690   g_return_if_fail (colors != NULL);
691
692   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
693
694   if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
695       (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
696     return;
697
698   pixels = g_new (gulong, ncolors);
699
700   for (i=0; i<ncolors; i++)
701     {
702       gulong pixel = colors[i].pixel;
703       
704       if (private->info[pixel].ref_count)
705         {
706           private->info[pixel].ref_count--;
707
708           if (private->info[pixel].ref_count == 0)
709             {
710               pixels[npixels++] = pixel;
711               if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
712                 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
713               private->info[pixel].flags = 0;
714             }
715         }
716     }
717
718   if (npixels && !private->private_val && !private->screen->closed)
719     XFreeColors (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
720                  pixels, npixels, 0);
721
722   g_free (pixels);
723 }
724
725 /********************
726  * Color allocation *
727  ********************/
728
729 /* Try to allocate a single color using XAllocColor. If it succeeds,
730  * cache the result in our colormap, and store in ret.
731  */
732 static gboolean 
733 gdk_colormap_alloc1 (GdkColormap *colormap,
734                      GdkColor    *color,
735                      GdkColor    *ret)
736 {
737   GdkColormapPrivateX11 *private;
738   XColor xcolor;
739
740   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
741
742   xcolor.red = color->red;
743   xcolor.green = color->green;
744   xcolor.blue = color->blue;
745   xcolor.pixel = color->pixel;
746   xcolor.flags = DoRed | DoGreen | DoBlue;
747
748   if (XAllocColor (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap, &xcolor))
749     {
750       ret->pixel = xcolor.pixel;
751       ret->red = xcolor.red;
752       ret->green = xcolor.green;
753       ret->blue = xcolor.blue;
754       
755       if (ret->pixel < colormap->size)
756         {
757           if (private->info[ret->pixel].ref_count) /* got a duplicate */
758             {
759               XFreeColors (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
760                            &xcolor.pixel, 1, 0);
761               private->info[ret->pixel].ref_count++;
762             }
763           else
764             {
765               colormap->colors[ret->pixel] = *color;
766               colormap->colors[ret->pixel].pixel = ret->pixel;
767               private->info[ret->pixel].ref_count = 1;
768
769               g_hash_table_insert (private->hash,
770                                    &colormap->colors[ret->pixel],
771                                    &colormap->colors[ret->pixel]);
772             }
773         }
774       return TRUE;
775     }
776   else
777     {
778       return FALSE;
779     }
780 }
781
782 static gint
783 gdk_colormap_alloc_colors_writeable (GdkColormap *colormap,
784                                      GdkColor    *colors,
785                                      gint         ncolors,
786                                      gboolean     writeable,
787                                      gboolean     best_match,
788                                      gboolean    *success)
789 {
790   GdkColormapPrivateX11 *private;
791   gulong *pixels;
792   Status status;
793   gint i, index;
794
795   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
796
797   if (private->private_val)
798     {
799       index = 0;
800       for (i=0; i<ncolors; i++)
801         {
802           while ((index < colormap->size) && (private->info[index].ref_count != 0))
803             index++;
804           
805           if (index < colormap->size)
806             {
807               colors[i].pixel = index;
808               success[i] = TRUE;
809               private->info[index].ref_count++;
810               private->info[i].flags |= GDK_COLOR_WRITEABLE;
811             }
812           else
813             break;
814         }
815       return ncolors - i;
816     }
817   else
818     {
819       pixels = g_new (gulong, ncolors);
820       /* Allocation of a writeable color cells */
821       
822       status =  XAllocColorCells (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
823                                   FALSE, NULL, 0, pixels, ncolors);
824       if (status)
825         {
826           for (i=0; i<ncolors; i++)
827             {
828               colors[i].pixel = pixels[i];
829               success[i] = TRUE;
830               private->info[pixels[i]].ref_count++;
831               private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
832             }
833         }
834       
835       g_free (pixels);
836
837       return status ? 0 : ncolors; 
838     }
839 }
840
841 static gint
842 gdk_colormap_alloc_colors_private (GdkColormap *colormap,
843                                    GdkColor    *colors,
844                                    gint         ncolors,
845                                    gboolean     writeable,
846                                    gboolean     best_match,
847                                    gboolean    *success)
848 {
849   GdkColormapPrivateX11 *private;
850   gint i, index;
851   XColor *store = g_new (XColor, ncolors);
852   gint nstore = 0;
853   gint nremaining = 0;
854   
855   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
856
857   /* First, store the colors we have room for */
858
859   index = 0;
860   for (i=0; i<ncolors; i++)
861     {
862       if (!success[i])
863         {
864           while ((index < colormap->size) && (private->info[index].ref_count != 0))
865             index++;
866
867           if (index < colormap->size)
868             {
869               store[nstore].red = colors[i].red;
870               store[nstore].blue = colors[i].blue;
871               store[nstore].green = colors[i].green;
872               store[nstore].pixel = index;
873               store[nstore].flags = DoRed | DoGreen | DoBlue;
874               nstore++;
875
876               success[i] = TRUE;
877               colors[i].pixel = index;
878
879               colormap->colors[i] = colors[i];
880               private->info[index].ref_count++;
881
882               g_hash_table_insert (private->hash,
883                                    &colormap->colors[index],
884                                    &colormap->colors[index]);
885             }
886           else
887             nremaining++;
888         }
889     }
890   
891   XStoreColors (GDK_SCREEN_XDISPLAY (private->screen), private->xcolormap,
892                 store, nstore);
893   g_free (store);
894
895   if (nremaining > 0 && best_match)
896     {
897       /* Get best matches for remaining colors */
898
899       gchar *available = g_new (gchar, colormap->size);
900       for (i = 0; i < colormap->size; i++)
901         available[i] = !(private->info[i].flags & GDK_COLOR_WRITEABLE);
902
903       for (i=0; i<ncolors; i++)
904         {
905           if (!success[i])
906             {
907               index = gdk_colormap_match_color (colormap, 
908                                                 &colors[i], 
909                                                 available);
910               if (index != -1)
911                 {
912                   colors[i] = colormap->colors[index];
913                   private->info[index].ref_count++;
914
915                   success[i] = TRUE;
916                   nremaining--;
917                 }
918             }
919         }
920       g_free (available);
921     }
922
923   return nremaining;
924 }
925
926 static gint
927 gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
928                                   GdkColor    *colors,
929                                   gint         ncolors,
930                                   gboolean     writeable,
931                                   gboolean     best_match,
932                                   gboolean    *success)
933 {
934   GdkColormapPrivateX11 *private;
935   gint i, index;
936   gint nremaining = 0;
937   gint nfailed = 0;
938
939   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
940
941   for (i=0; i<ncolors; i++)
942     {
943       if (!success[i])
944         {
945           if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
946             success[i] = TRUE;
947           else
948             nremaining++;
949         }
950     }
951
952
953   if (nremaining > 0 && best_match)
954     {
955       gchar *available = g_new (gchar, colormap->size);
956       for (i = 0; i < colormap->size; i++)
957         available[i] = ((private->info[i].ref_count == 0) ||
958                         !(private->info[i].flags & GDK_COLOR_WRITEABLE));
959       gdk_colormap_sync (colormap, FALSE);
960       
961       while (nremaining > 0)
962         {
963           for (i=0; i<ncolors; i++)
964             {
965               if (!success[i])
966                 {
967                   index = gdk_colormap_match_color (colormap, &colors[i], available);
968                   if (index != -1)
969                     {
970                       if (private->info[index].ref_count)
971                         {
972                           private->info[index].ref_count++;
973                           colors[i] = colormap->colors[index];
974                           success[i] = TRUE;
975                           nremaining--;
976                         }
977                       else
978                         {
979                           if (gdk_colormap_alloc1 (colormap, 
980                                                    &colormap->colors[index],
981                                                    &colors[i]))
982                             {
983                               success[i] = TRUE;
984                               nremaining--;
985                               break;
986                             }
987                           else
988                             {
989                               available[index] = FALSE;
990                             }
991                         }
992                     }
993                   else
994                     {
995                       nfailed++;
996                       nremaining--;
997                       success[i] = 2; /* flag as permanent failure */
998                     }
999                 }
1000             }
1001         }
1002       g_free (available);
1003     }
1004
1005   /* Change back the values we flagged as permanent failures */
1006   if (nfailed > 0)
1007     {
1008       for (i=0; i<ncolors; i++)
1009         if (success[i] == 2)
1010           success[i] = FALSE;
1011       nremaining = nfailed;
1012     }
1013   
1014   return nremaining;
1015 }
1016
1017 static gint
1018 gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
1019                                        GdkColor    *colors,
1020                                        gint         ncolors,
1021                                        gboolean     writeable,
1022                                        gboolean     best_match,
1023                                        gboolean    *success)
1024 {
1025   GdkColormapPrivateX11 *private;
1026   GdkColor *lookup_color;
1027   gint i;
1028   gint nremaining = 0;
1029
1030   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1031
1032   /* Check for an exact match among previously allocated colors */
1033
1034   for (i=0; i<ncolors; i++)
1035     {
1036       if (!success[i])
1037         {
1038           lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
1039           if (lookup_color)
1040             {
1041               private->info[lookup_color->pixel].ref_count++;
1042               colors[i].pixel = lookup_color->pixel;
1043               success[i] = TRUE;
1044             }
1045           else
1046             nremaining++;
1047         }
1048     }
1049
1050   /* If that failed, we try to allocate a new color, or approxmiate
1051    * with what we can get if best_match is TRUE.
1052    */
1053   if (nremaining > 0)
1054     {
1055       if (private->private_val)
1056         return gdk_colormap_alloc_colors_private (colormap, colors, ncolors, writeable, best_match, success);
1057       else
1058         return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
1059     }
1060   else
1061     return 0;
1062 }
1063
1064 /**
1065  * gdk_colormap_alloc_colors:
1066  * @colormap: a #GdkColormap.
1067  * @colors: The color values to allocate. On return, the pixel
1068  *    values for allocated colors will be filled in.
1069  * @ncolors: The number of colors in @colors.
1070  * @writeable: If %TRUE, the colors are allocated writeable
1071  *    (their values can later be changed using gdk_color_change()).
1072  *    Writeable colors cannot be shared between applications.
1073  * @best_match: If %TRUE, GDK will attempt to do matching against
1074  *    existing colors if the colors cannot be allocated as requested.
1075  * @success: An array of length @ncolors. On return, this
1076  *   indicates whether the corresponding color in @colors was
1077  *   sucessfully allocated or not.
1078  * 
1079  * Allocates colors from a colormap.
1080  * 
1081  * Return value: The number of colors that were not sucessfully 
1082  * allocated.
1083  **/
1084 gint
1085 gdk_colormap_alloc_colors (GdkColormap *colormap,
1086                            GdkColor    *colors,
1087                            gint         ncolors,
1088                            gboolean     writeable,
1089                            gboolean     best_match,
1090                            gboolean    *success)
1091 {
1092   GdkColormapPrivateX11 *private;
1093   GdkVisual *visual;
1094   gint i;
1095   gint nremaining = 0;
1096   XColor xcolor;
1097
1098   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), ncolors);
1099   g_return_val_if_fail (colors != NULL, ncolors);
1100
1101   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1102
1103   if (private->screen->closed)
1104     return ncolors;
1105
1106   for (i=0; i<ncolors; i++)
1107     {
1108       success[i] = FALSE;
1109     }
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   g_return_val_if_fail (cmap != NULL, 0);
1383   g_return_val_if_fail (color != NULL, 0);
1384
1385   colors = cmap->colors;
1386   max = 3 * (65536);
1387   index = -1;
1388
1389   for (i = 0; i < cmap->size; i++)
1390     {
1391       if ((!available) || (available && available[i]))
1392         {
1393           rdiff = (color->red - colors[i].red);
1394           gdiff = (color->green - colors[i].green);
1395           bdiff = (color->blue - colors[i].blue);
1396
1397           sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1398
1399           if (sum < max)
1400             {
1401               index = i;
1402               max = sum;
1403             }
1404         }
1405     }
1406
1407   return index;
1408 }
1409
1410
1411 static GdkColormap*
1412 gdk_colormap_lookup (GdkScreen *screen,
1413                      Colormap   xcolormap)
1414 {
1415   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1416
1417   if (screen_x11->colormap_hash)
1418     return g_hash_table_lookup (screen_x11->colormap_hash, &xcolormap);
1419   else
1420     return NULL;
1421 }
1422
1423 static void
1424 gdk_colormap_add (GdkColormap *cmap)
1425 {
1426   GdkScreenX11 *screen_x11;
1427   GdkColormapPrivateX11 *private;
1428
1429   private = GDK_COLORMAP_PRIVATE_DATA (cmap);
1430   screen_x11 = GDK_SCREEN_X11 (private->screen);
1431
1432   if (!screen_x11->colormap_hash)
1433     screen_x11->colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
1434                                                   (GEqualFunc) gdk_colormap_equal);
1435
1436   g_hash_table_insert (screen_x11->colormap_hash, &private->xcolormap, cmap);
1437 }
1438
1439 static void
1440 gdk_colormap_remove (GdkColormap *cmap)
1441 {
1442   GdkScreenX11 *screen_x11;
1443   GdkColormapPrivateX11 *private;
1444
1445   private = GDK_COLORMAP_PRIVATE_DATA (cmap);
1446   screen_x11 = GDK_SCREEN_X11 (private->screen);
1447
1448   if (screen_x11->colormap_hash)
1449     g_hash_table_remove (screen_x11->colormap_hash, &private->xcolormap);
1450 }
1451
1452 static guint
1453 gdk_colormap_hash (Colormap *colormap)
1454 {
1455   return *colormap;
1456 }
1457
1458 static gboolean
1459 gdk_colormap_equal (Colormap *a,
1460                     Colormap *b)
1461 {
1462   return (*a == *b);
1463 }
1464
1465 /**
1466  * gdk_x11_colormap_get_xdisplay:
1467  * @colormap: a #GdkColormap.
1468  * 
1469  * Returns the display of a #GdkColormap.
1470  * 
1471  * Return value: an Xlib <type>Display*</type>.
1472  **/
1473 Display *
1474 gdk_x11_colormap_get_xdisplay (GdkColormap *colormap)
1475 {
1476   GdkColormapPrivateX11 *private;
1477
1478   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), NULL);
1479
1480   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1481
1482   return GDK_SCREEN_XDISPLAY (private->screen);
1483 }
1484
1485 /**
1486  * gdk_x11_colormap_get_xcolormap:
1487  * @colormap:  a #GdkColormap.
1488  * 
1489  * Returns the X colormap belonging to a #GdkColormap.
1490  * 
1491  * Return value: an Xlib <type>Colormap</type>.
1492  **/
1493 Colormap
1494 gdk_x11_colormap_get_xcolormap (GdkColormap *colormap)
1495 {
1496   GdkColormapPrivateX11 *private;
1497
1498   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), None);
1499
1500   private = GDK_COLORMAP_PRIVATE_DATA (colormap);
1501
1502   if (private->screen->closed)
1503     return None;
1504   else
1505     return private->xcolormap;
1506 }
1507
1508 /**
1509  * gdk_colormap_get_screen:
1510  * @cmap: a #GdkColormap
1511  * 
1512  * Gets the screen for which this colormap was created.
1513  * 
1514  * Return value: the screen for which this colormap was created.
1515  *
1516  * Since: 2.2
1517  **/
1518 GdkScreen *
1519 gdk_colormap_get_screen (GdkColormap *cmap)
1520 {
1521   g_return_val_if_fail (GDK_IS_COLORMAP (cmap), NULL);
1522
1523   return  GDK_COLORMAP_PRIVATE_DATA (cmap)->screen;
1524 }