1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 #include "gdkprivate.h"
25 static gint gdk_colormap_match_color (GdkColormap *cmap,
27 const gchar *available);
28 static void gdk_colormap_add (GdkColormap *cmap);
29 static void gdk_colormap_remove (GdkColormap *cmap);
30 static guint gdk_colormap_hash (Colormap *cmap);
31 static gint gdk_colormap_cmp (Colormap *a,
33 static void gdk_colormap_real_destroy (GdkColormap *colormap);
35 static GHashTable *colormap_hash = NULL;
39 gdk_colormap_new (GdkVisual *visual,
42 GdkColormap *colormap;
43 GdkColormapPrivate *private;
48 g_return_val_if_fail (visual != NULL, NULL);
50 private = g_new (GdkColormapPrivate, 1);
51 colormap = (GdkColormap*) private;
53 private->xdisplay = gdk_display;
54 private->visual = visual;
55 private->next_color = 0;
56 private->ref_count = 1;
57 xvisual = ((GdkVisualPrivate*) visual)->xvisual;
59 colormap->size = visual->colormap_size;
60 colormap->colors = g_new (GdkColor, colormap->size);
64 case GDK_VISUAL_GRAYSCALE:
65 case GDK_VISUAL_PSEUDO_COLOR:
66 private->private_val = private_cmap;
67 private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
68 xvisual, (private_cmap) ? (AllocAll) : (AllocNone));
72 XColor *default_colors;
74 default_colors = g_new (XColor, colormap->size);
76 for (i = 0; i < colormap->size; i++)
77 default_colors[i].pixel = i;
79 XQueryColors (private->xdisplay,
80 DefaultColormap (private->xdisplay, gdk_screen),
81 default_colors, colormap->size);
83 for (i = 0; i < colormap->size; i++)
85 colormap->colors[i].pixel = default_colors[i].pixel;
86 colormap->colors[i].red = default_colors[i].red;
87 colormap->colors[i].green = default_colors[i].green;
88 colormap->colors[i].blue = default_colors[i].blue;
91 gdk_colormap_change (colormap, colormap->size);
93 g_free (default_colors);
97 case GDK_VISUAL_DIRECT_COLOR:
98 private->private_val = TRUE;
99 private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
102 size = 1 << visual->red_prec;
103 for (i = 0; i < size; i++)
104 colormap->colors[i].red = i * 65535 / (size - 1);
106 size = 1 << visual->green_prec;
107 for (i = 0; i < size; i++)
108 colormap->colors[i].green = i * 65535 / (size - 1);
110 size = 1 << visual->blue_prec;
111 for (i = 0; i < size; i++)
112 colormap->colors[i].blue = i * 65535 / (size - 1);
114 gdk_colormap_change (colormap, colormap->size);
117 case GDK_VISUAL_STATIC_GRAY:
118 case GDK_VISUAL_STATIC_COLOR:
119 case GDK_VISUAL_TRUE_COLOR:
120 private->private_val = FALSE;
121 private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
126 gdk_colormap_add (colormap);
132 gdk_colormap_real_destroy (GdkColormap *colormap)
134 GdkColormapPrivate *private = (GdkColormapPrivate*) colormap;
136 g_return_if_fail (colormap != NULL);
138 if (private->ref_count > 0)
141 gdk_colormap_remove (colormap);
142 XFreeColormap (private->xdisplay, private->xcolormap);
143 g_free (colormap->colors);
148 gdk_colormap_ref (GdkColormap *cmap)
150 GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
151 g_return_val_if_fail (cmap != NULL, NULL);
153 private->ref_count += 1;
158 gdk_colormap_unref (GdkColormap *cmap)
160 GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
161 g_return_if_fail (cmap != NULL);
163 private->ref_count -= 1;
164 if (private->ref_count == 0)
165 gdk_colormap_real_destroy (cmap);
169 gdk_colormap_get_system (void)
171 static GdkColormap *colormap = NULL;
172 GdkColormapPrivate *private;
178 private = g_new (GdkColormapPrivate, 1);
179 colormap = (GdkColormap*) private;
181 private->xdisplay = gdk_display;
182 private->xcolormap = DefaultColormap (gdk_display, gdk_screen);
183 private->visual = gdk_visual_get_system ();
184 private->private_val = FALSE;
185 private->next_color = 0;
186 private->ref_count = 1;
188 colormap->size = private->visual->colormap_size;
189 colormap->colors = g_new (GdkColor, colormap->size);
191 if ((private->visual->type == GDK_VISUAL_GRAYSCALE) ||
192 (private->visual->type == GDK_VISUAL_PSEUDO_COLOR))
194 xpalette = g_new (XColor, colormap->size);
196 for (i = 0; i < colormap->size; i++)
198 xpalette[i].pixel = i;
200 xpalette[i].green = 0;
201 xpalette[i].blue = 0;
204 XQueryColors (gdk_display, private->xcolormap, xpalette,
207 for (i = 0; i < colormap->size; i++)
209 colormap->colors[i].pixel = xpalette[i].pixel;
210 colormap->colors[i].red = xpalette[i].red;
211 colormap->colors[i].green = xpalette[i].green;
212 colormap->colors[i].blue = xpalette[i].blue;
218 gdk_colormap_add (colormap);
225 gdk_colormap_get_system_size (void)
227 return DisplayCells (gdk_display, gdk_screen);
231 gdk_colormap_change (GdkColormap *colormap,
234 GdkColormapPrivate *private;
242 g_return_if_fail (colormap != NULL);
244 palette = g_new (XColor, ncolors);
246 private = (GdkColormapPrivate*) colormap;
247 switch (private->visual->type)
249 case GDK_VISUAL_GRAYSCALE:
250 case GDK_VISUAL_PSEUDO_COLOR:
251 for (i = 0; i < ncolors; i++)
253 palette[i].pixel = colormap->colors[i].pixel;
254 palette[i].red = colormap->colors[i].red;
255 palette[i].green = colormap->colors[i].green;
256 palette[i].blue = colormap->colors[i].blue;
257 palette[i].flags = DoRed | DoGreen | DoBlue;
260 XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors);
261 private->next_color = MAX (private->next_color, ncolors);
264 case GDK_VISUAL_DIRECT_COLOR:
265 visual = private->visual;
267 shift = visual->red_shift;
268 max_colors = 1 << visual->red_prec;
269 size = (ncolors < max_colors) ? (ncolors) : (max_colors);
271 for (i = 0; i < size; i++)
273 palette[i].pixel = i << shift;
274 palette[i].red = colormap->colors[i].red;
275 palette[i].flags = DoRed;
278 XStoreColors (private->xdisplay, private->xcolormap, palette, size);
280 shift = visual->green_shift;
281 max_colors = 1 << visual->green_prec;
282 size = (ncolors < max_colors) ? (ncolors) : (max_colors);
284 for (i = 0; i < size; i++)
286 palette[i].pixel = i << shift;
287 palette[i].green = colormap->colors[i].green;
288 palette[i].flags = DoGreen;
291 XStoreColors (private->xdisplay, private->xcolormap, palette, size);
293 shift = visual->blue_shift;
294 max_colors = 1 << visual->blue_prec;
295 size = (ncolors < max_colors) ? (ncolors) : (max_colors);
297 for (i = 0; i < size; i++)
299 palette[i].pixel = i << shift;
300 palette[i].blue = colormap->colors[i].blue;
301 palette[i].flags = DoBlue;
304 XStoreColors (private->xdisplay, private->xcolormap, palette, size);
315 gdk_colors_store (GdkColormap *colormap,
321 for (i = 0; i < ncolors; i++)
323 colormap->colors[i].pixel = colors[i].pixel;
324 colormap->colors[i].red = colors[i].red;
325 colormap->colors[i].green = colors[i].green;
326 colormap->colors[i].blue = colors[i].blue;
329 gdk_colormap_change (colormap, ncolors);
333 gdk_colors_alloc (GdkColormap *colormap,
340 GdkColormapPrivate *private;
343 g_return_val_if_fail (colormap != NULL, 0);
345 private = (GdkColormapPrivate*) colormap;
347 return_val = XAllocColorCells (private->xdisplay, private->xcolormap,
348 contiguous, planes, nplanes, pixels, npixels);
354 gdk_colors_free (GdkColormap *colormap,
359 GdkColormapPrivate *private;
361 g_return_if_fail (colormap != NULL);
363 private = (GdkColormapPrivate*) colormap;
365 XFreeColors (private->xdisplay, private->xcolormap,
366 pixels, npixels, planes);
370 *--------------------------------------------------------------
373 * Copy a color structure into new storage.
376 * "color" is the color struct to copy.
379 * A new color structure. Free it with gdk_color_free.
381 *--------------------------------------------------------------
384 static GMemChunk *color_chunk;
387 gdk_color_copy (GdkColor *color)
391 g_return_val_if_fail (color != NULL, NULL);
393 if (color_chunk == NULL)
394 color_chunk = g_mem_chunk_new ("colors",
399 new_color = g_chunk_new (GdkColor, color_chunk);
405 *--------------------------------------------------------------
408 * Free a color structure obtained from gdk_color_copy. Do not use
409 * with other color structures.
412 * "color" is the color struct to free.
414 *-------------------------------------------------------------- */
417 gdk_color_free (GdkColor *color)
419 g_assert (color_chunk != NULL);
420 g_return_if_fail (color != NULL);
422 g_mem_chunk_free (color_chunk, color);
426 gdk_color_white (GdkColormap *colormap,
431 g_return_val_if_fail (colormap != NULL, FALSE);
435 color->pixel = WhitePixel (gdk_display, gdk_screen);
437 color->green = 65535;
440 return_val = gdk_color_alloc (colormap, color);
449 gdk_color_black (GdkColormap *colormap,
454 g_return_val_if_fail (colormap != NULL, FALSE);
458 color->pixel = BlackPixel (gdk_display, gdk_screen);
463 return_val = gdk_color_alloc (colormap, color);
472 gdk_color_parse (const gchar *spec,
479 g_return_val_if_fail (spec != NULL, FALSE);
480 g_return_val_if_fail (color != NULL, FALSE);
482 xcolormap = DefaultColormap (gdk_display, gdk_screen);
484 if (XParseColor (gdk_display, xcolormap, spec, &xcolor))
487 color->red = xcolor.red;
488 color->green = xcolor.green;
489 color->blue = xcolor.blue;
498 gdk_color_alloc (GdkColormap *colormap,
501 GdkColormapPrivate *private;
504 gchar *available = NULL;
508 g_return_val_if_fail (colormap != NULL, FALSE);
509 g_return_val_if_fail (color != NULL, FALSE);
511 xcolor.red = color->red;
512 xcolor.green = color->green;
513 xcolor.blue = color->blue;
514 xcolor.pixel = color->pixel;
515 xcolor.flags = DoRed | DoGreen | DoBlue;
518 private = (GdkColormapPrivate*) colormap;
520 switch (private->visual->type)
522 case GDK_VISUAL_GRAYSCALE:
523 case GDK_VISUAL_PSEUDO_COLOR:
524 if (private->private_val)
526 if (private->next_color >= colormap->size)
528 available = g_new (gchar, colormap->size);
529 for (i = 0; i < colormap->size; i++)
532 index = gdk_colormap_match_color (colormap, color, available);
535 available[index] = FALSE;
536 *color = colormap->colors[index];
546 xcolor.pixel = colormap->size - 1 -private->next_color;
547 color->pixel = xcolor.pixel;
548 private->next_color += 1;
550 XStoreColor (private->xdisplay, private->xcolormap, &xcolor);
558 if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor))
560 color->pixel = xcolor.pixel;
561 color->red = xcolor.red;
562 color->green = xcolor.green;
563 color->blue = xcolor.blue;
565 if (color->pixel < colormap->size)
566 colormap->colors[color->pixel] = *color;
573 if (available == NULL)
575 available = g_new (gchar, colormap->size);
576 for (i = 0; i < colormap->size; i++)
580 index = gdk_colormap_match_color (colormap, color, available);
583 available[index] = FALSE;
584 xcolor.red = colormap->colors[index].red;
585 xcolor.green = colormap->colors[index].green;
586 xcolor.blue = colormap->colors[index].blue;
598 case GDK_VISUAL_DIRECT_COLOR:
599 visual = private->visual;
600 xcolor.pixel = (((xcolor.red >> (16 - visual->red_prec)) << visual->red_shift) +
601 ((xcolor.green >> (16 - visual->green_prec)) << visual->green_shift) +
602 ((xcolor.blue >> (16 - visual->blue_prec)) << visual->blue_shift));
603 color->pixel = xcolor.pixel;
607 case GDK_VISUAL_STATIC_GRAY:
608 case GDK_VISUAL_STATIC_COLOR:
609 case GDK_VISUAL_TRUE_COLOR:
610 if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor))
612 color->pixel = xcolor.pixel;
627 gdk_color_change (GdkColormap *colormap,
630 GdkColormapPrivate *private;
633 g_return_val_if_fail (colormap != NULL, FALSE);
634 g_return_val_if_fail (color != NULL, FALSE);
636 xcolor.pixel = color->pixel;
637 xcolor.red = color->red;
638 xcolor.green = color->green;
639 xcolor.blue = color->blue;
640 xcolor.flags = DoRed | DoGreen | DoBlue;
642 private = (GdkColormapPrivate*) colormap;
643 XStoreColor (private->xdisplay, private->xcolormap, &xcolor);
649 gdk_color_equal (GdkColor *colora,
652 g_return_val_if_fail (colora != NULL, FALSE);
653 g_return_val_if_fail (colorb != NULL, FALSE);
655 return ((colora->red == colorb->red) &&
656 (colora->green == colorb->green) &&
657 (colora->blue == colorb->blue));
661 gdkx_colormap_get (Colormap xcolormap)
663 GdkColormap *colormap;
664 GdkColormapPrivate *private;
666 colormap = gdk_colormap_lookup (xcolormap);
670 if (xcolormap == DefaultColormap (gdk_display, gdk_screen))
671 return gdk_colormap_get_system ();
673 private = g_new (GdkColormapPrivate, 1);
674 colormap = (GdkColormap*) private;
676 private->xdisplay = gdk_display;
677 private->xcolormap = xcolormap;
678 private->visual = NULL;
679 private->private_val = TRUE;
680 private->next_color = 0;
682 /* To do the following safely, we would have to have some way of finding
683 * out what the size or visual of the given colormap is. It seems
684 * X doesn't allow this
688 for (i = 0; i < 256; i++)
690 xpalette[i].pixel = i;
692 xpalette[i].green = 0;
693 xpalette[i].blue = 0;
696 XQueryColors (gdk_display, private->xcolormap, xpalette, 256);
698 for (i = 0; i < 256; i++)
700 colormap->colors[i].pixel = xpalette[i].pixel;
701 colormap->colors[i].red = xpalette[i].red;
702 colormap->colors[i].green = xpalette[i].green;
703 colormap->colors[i].blue = xpalette[i].blue;
707 colormap->colors = NULL;
710 gdk_colormap_add (colormap);
717 gdk_colormap_match_color (GdkColormap *cmap,
719 const gchar *available)
723 gint rdiff, gdiff, bdiff;
726 g_return_val_if_fail (cmap != NULL, 0);
727 g_return_val_if_fail (color != NULL, 0);
729 colors = cmap->colors;
733 for (i = 0; i < cmap->size; i++)
735 if ((!available) || (available && available[i]))
737 rdiff = (color->red - colors[i].red);
738 gdiff = (color->green - colors[i].green);
739 bdiff = (color->blue - colors[i].blue);
741 sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
756 gdk_colormap_lookup (Colormap xcolormap)
763 cmap = g_hash_table_lookup (colormap_hash, &xcolormap);
768 gdk_colormap_add (GdkColormap *cmap)
770 GdkColormapPrivate *private;
773 colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
774 (GCompareFunc) gdk_colormap_cmp);
776 private = (GdkColormapPrivate*) cmap;
778 g_hash_table_insert (colormap_hash, &private->xcolormap, cmap);
782 gdk_colormap_remove (GdkColormap *cmap)
784 GdkColormapPrivate *private;
787 colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
788 (GCompareFunc) gdk_colormap_cmp);
790 private = (GdkColormapPrivate*) cmap;
792 g_hash_table_remove (colormap_hash, &private->xcolormap);
796 gdk_colormap_hash (Colormap *cmap)
802 gdk_colormap_cmp (Colormap *a,