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"
24 static gint gdk_colormap_match_color (GdkColormap *cmap,
26 const gchar *available);
27 static void gdk_colormap_add (GdkColormap *cmap);
28 static void gdk_colormap_remove (GdkColormap *cmap);
29 static guint gdk_colormap_hash (Colormap *cmap);
30 static gint gdk_colormap_cmp (Colormap *a,
32 static void gdk_colormap_real_destroy (GdkColormap *colormap);
34 static GHashTable *colormap_hash = NULL;
38 gdk_colormap_new (GdkVisual *visual,
41 GdkColormap *colormap;
42 GdkColormapPrivate *private;
47 g_return_val_if_fail (visual != NULL, NULL);
49 private = g_new (GdkColormapPrivate, 1);
50 colormap = (GdkColormap*) private;
52 private->xdisplay = gdk_display;
53 private->visual = visual;
54 private->next_color = 0;
55 private->ref_count = 1;
56 xvisual = ((GdkVisualPrivate*) visual)->xvisual;
58 colormap->size = visual->colormap_size;
59 colormap->colors = g_new (GdkColor, colormap->size);
63 case GDK_VISUAL_GRAYSCALE:
64 case GDK_VISUAL_PSEUDO_COLOR:
65 private->private_val = private_cmap;
66 private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
67 xvisual, (private_cmap) ? (AllocAll) : (AllocNone));
71 XColor *default_colors;
73 default_colors = g_new (XColor, colormap->size);
75 for (i = 0; i < colormap->size; i++)
76 default_colors[i].pixel = i;
78 XQueryColors (private->xdisplay,
79 DefaultColormap (private->xdisplay, gdk_screen),
80 default_colors, colormap->size);
82 for (i = 0; i < colormap->size; i++)
84 colormap->colors[i].pixel = default_colors[i].pixel;
85 colormap->colors[i].red = default_colors[i].red;
86 colormap->colors[i].green = default_colors[i].green;
87 colormap->colors[i].blue = default_colors[i].blue;
90 gdk_colormap_change (colormap, colormap->size);
92 g_free (default_colors);
96 case GDK_VISUAL_DIRECT_COLOR:
97 private->private_val = TRUE;
98 private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
101 size = 1 << visual->red_prec;
102 for (i = 0; i < size; i++)
103 colormap->colors[i].red = i * 65535 / (size - 1);
105 size = 1 << visual->green_prec;
106 for (i = 0; i < size; i++)
107 colormap->colors[i].green = i * 65535 / (size - 1);
109 size = 1 << visual->blue_prec;
110 for (i = 0; i < size; i++)
111 colormap->colors[i].blue = i * 65535 / (size - 1);
113 gdk_colormap_change (colormap, colormap->size);
116 case GDK_VISUAL_STATIC_GRAY:
117 case GDK_VISUAL_STATIC_COLOR:
118 case GDK_VISUAL_TRUE_COLOR:
119 private->private_val = FALSE;
120 private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
125 gdk_colormap_add (colormap);
131 gdk_colormap_real_destroy (GdkColormap *colormap)
133 GdkColormapPrivate *private = (GdkColormapPrivate*) colormap;
135 g_return_if_fail (colormap != NULL);
137 if (private->ref_count > 0)
140 gdk_colormap_remove (colormap);
141 XFreeColormap (private->xdisplay, private->xcolormap);
142 g_free (colormap->colors);
147 gdk_colormap_ref (GdkColormap *cmap)
149 GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
150 g_return_val_if_fail (cmap != NULL, NULL);
152 private->ref_count += 1;
157 gdk_colormap_unref (GdkColormap *cmap)
159 GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
160 g_return_if_fail (cmap != NULL);
162 private->ref_count -= 1;
163 if (private->ref_count == 0)
164 gdk_colormap_real_destroy (cmap);
168 gdk_colormap_get_system (void)
170 static GdkColormap *colormap = NULL;
171 GdkColormapPrivate *private;
177 private = g_new (GdkColormapPrivate, 1);
178 colormap = (GdkColormap*) private;
180 private->xdisplay = gdk_display;
181 private->xcolormap = DefaultColormap (gdk_display, gdk_screen);
182 private->visual = gdk_visual_get_system ();
183 private->private_val = FALSE;
184 private->next_color = 0;
185 private->ref_count = 1;
187 colormap->size = private->visual->colormap_size;
188 colormap->colors = g_new (GdkColor, colormap->size);
190 if ((private->visual->type == GDK_VISUAL_GRAYSCALE) ||
191 (private->visual->type == GDK_VISUAL_PSEUDO_COLOR))
193 xpalette = g_new (XColor, colormap->size);
195 for (i = 0; i < colormap->size; i++)
197 xpalette[i].pixel = i;
199 xpalette[i].green = 0;
200 xpalette[i].blue = 0;
203 XQueryColors (gdk_display, private->xcolormap, xpalette,
206 for (i = 0; i < colormap->size; i++)
208 colormap->colors[i].pixel = xpalette[i].pixel;
209 colormap->colors[i].red = xpalette[i].red;
210 colormap->colors[i].green = xpalette[i].green;
211 colormap->colors[i].blue = xpalette[i].blue;
217 gdk_colormap_add (colormap);
224 gdk_colormap_get_system_size (void)
226 return DisplayCells (gdk_display, gdk_screen);
230 gdk_colormap_change (GdkColormap *colormap,
233 GdkColormapPrivate *private;
241 g_return_if_fail (colormap != NULL);
243 palette = g_new (XColor, ncolors);
245 private = (GdkColormapPrivate*) colormap;
246 switch (private->visual->type)
248 case GDK_VISUAL_GRAYSCALE:
249 case GDK_VISUAL_PSEUDO_COLOR:
250 for (i = 0; i < ncolors; i++)
252 palette[i].pixel = colormap->colors[i].pixel;
253 palette[i].red = colormap->colors[i].red;
254 palette[i].green = colormap->colors[i].green;
255 palette[i].blue = colormap->colors[i].blue;
256 palette[i].flags = DoRed | DoGreen | DoBlue;
259 XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors);
260 private->next_color = MAX (private->next_color, ncolors);
263 case GDK_VISUAL_DIRECT_COLOR:
264 visual = private->visual;
266 shift = visual->red_shift;
267 max_colors = 1 << visual->red_prec;
268 size = (ncolors < max_colors) ? (ncolors) : (max_colors);
270 for (i = 0; i < size; i++)
272 palette[i].pixel = i << shift;
273 palette[i].red = colormap->colors[i].red;
274 palette[i].flags = DoRed;
277 XStoreColors (private->xdisplay, private->xcolormap, palette, size);
279 shift = visual->green_shift;
280 max_colors = 1 << visual->green_prec;
281 size = (ncolors < max_colors) ? (ncolors) : (max_colors);
283 for (i = 0; i < size; i++)
285 palette[i].pixel = i << shift;
286 palette[i].green = colormap->colors[i].green;
287 palette[i].flags = DoGreen;
290 XStoreColors (private->xdisplay, private->xcolormap, palette, size);
292 shift = visual->blue_shift;
293 max_colors = 1 << visual->blue_prec;
294 size = (ncolors < max_colors) ? (ncolors) : (max_colors);
296 for (i = 0; i < size; i++)
298 palette[i].pixel = i << shift;
299 palette[i].blue = colormap->colors[i].blue;
300 palette[i].flags = DoBlue;
303 XStoreColors (private->xdisplay, private->xcolormap, palette, size);
314 gdk_colors_store (GdkColormap *colormap,
320 for (i = 0; i < ncolors; i++)
322 colormap->colors[i].pixel = colors[i].pixel;
323 colormap->colors[i].red = colors[i].red;
324 colormap->colors[i].green = colors[i].green;
325 colormap->colors[i].blue = colors[i].blue;
328 gdk_colormap_change (colormap, ncolors);
332 gdk_colors_alloc (GdkColormap *colormap,
339 GdkColormapPrivate *private;
342 g_return_val_if_fail (colormap != NULL, 0);
344 private = (GdkColormapPrivate*) colormap;
346 return_val = XAllocColorCells (private->xdisplay, private->xcolormap,
347 contiguous, planes, nplanes, pixels, npixels);
353 gdk_colors_free (GdkColormap *colormap,
358 GdkColormapPrivate *private;
360 g_return_if_fail (colormap != NULL);
362 private = (GdkColormapPrivate*) colormap;
364 XFreeColors (private->xdisplay, private->xcolormap,
365 pixels, npixels, planes);
369 *--------------------------------------------------------------
372 * Copy a color structure into new storage.
375 * "color" is the color struct to copy.
378 * A new color structure. Free it with gdk_color_free.
380 *--------------------------------------------------------------
383 static GMemChunk *color_chunk;
386 gdk_color_copy (GdkColor *color)
390 g_return_val_if_fail (color != NULL, NULL);
392 if (color_chunk == NULL)
393 color_chunk = g_mem_chunk_new ("colors",
398 new_color = g_chunk_new (GdkColor, color_chunk);
404 *--------------------------------------------------------------
407 * Free a color structure obtained from gdk_color_copy. Do not use
408 * with other color structures.
411 * "color" is the color struct to free.
413 *-------------------------------------------------------------- */
416 gdk_color_free (GdkColor *color)
418 g_assert (color_chunk != NULL);
419 g_return_if_fail (color != NULL);
421 g_mem_chunk_free (color_chunk, color);
425 gdk_color_white (GdkColormap *colormap,
430 g_return_val_if_fail (colormap != NULL, FALSE);
434 color->pixel = WhitePixel (gdk_display, gdk_screen);
436 color->green = 65535;
439 return_val = gdk_color_alloc (colormap, color);
448 gdk_color_black (GdkColormap *colormap,
453 g_return_val_if_fail (colormap != NULL, FALSE);
457 color->pixel = BlackPixel (gdk_display, gdk_screen);
462 return_val = gdk_color_alloc (colormap, color);
471 gdk_color_parse (const gchar *spec,
478 g_return_val_if_fail (spec != NULL, FALSE);
479 g_return_val_if_fail (color != NULL, FALSE);
481 xcolormap = DefaultColormap (gdk_display, gdk_screen);
483 if (XParseColor (gdk_display, xcolormap, spec, &xcolor))
486 color->red = xcolor.red;
487 color->green = xcolor.green;
488 color->blue = xcolor.blue;
497 gdk_color_alloc (GdkColormap *colormap,
500 GdkColormapPrivate *private;
503 gchar *available = NULL;
507 g_return_val_if_fail (colormap != NULL, FALSE);
508 g_return_val_if_fail (color != NULL, FALSE);
510 xcolor.red = color->red;
511 xcolor.green = color->green;
512 xcolor.blue = color->blue;
513 xcolor.pixel = color->pixel;
514 xcolor.flags = DoRed | DoGreen | DoBlue;
517 private = (GdkColormapPrivate*) colormap;
519 switch (private->visual->type)
521 case GDK_VISUAL_GRAYSCALE:
522 case GDK_VISUAL_PSEUDO_COLOR:
523 if (private->private_val)
525 if (private->next_color >= colormap->size)
527 available = g_new (gchar, colormap->size);
528 for (i = 0; i < colormap->size; i++)
531 index = gdk_colormap_match_color (colormap, color, available);
534 available[index] = FALSE;
535 *color = colormap->colors[index];
545 xcolor.pixel = colormap->size - 1 -private->next_color;
546 color->pixel = xcolor.pixel;
547 private->next_color += 1;
549 XStoreColor (private->xdisplay, private->xcolormap, &xcolor);
557 if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor))
559 color->pixel = xcolor.pixel;
560 color->red = xcolor.red;
561 color->green = xcolor.green;
562 color->blue = xcolor.blue;
564 if (color->pixel < colormap->size)
565 colormap->colors[color->pixel] = *color;
572 if (available == NULL)
574 available = g_new (gchar, colormap->size);
575 for (i = 0; i < colormap->size; i++)
579 index = gdk_colormap_match_color (colormap, color, available);
582 available[index] = FALSE;
583 xcolor.red = colormap->colors[index].red;
584 xcolor.green = colormap->colors[index].green;
585 xcolor.blue = colormap->colors[index].blue;
597 case GDK_VISUAL_DIRECT_COLOR:
598 visual = private->visual;
599 xcolor.pixel = (((xcolor.red >> (16 - visual->red_prec)) << visual->red_shift) +
600 ((xcolor.green >> (16 - visual->green_prec)) << visual->green_shift) +
601 ((xcolor.blue >> (16 - visual->blue_prec)) << visual->blue_shift));
602 color->pixel = xcolor.pixel;
606 case GDK_VISUAL_STATIC_GRAY:
607 case GDK_VISUAL_STATIC_COLOR:
608 case GDK_VISUAL_TRUE_COLOR:
609 if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor))
611 color->pixel = xcolor.pixel;
626 gdk_color_change (GdkColormap *colormap,
629 GdkColormapPrivate *private;
632 g_return_val_if_fail (colormap != NULL, FALSE);
633 g_return_val_if_fail (color != NULL, FALSE);
635 xcolor.pixel = color->pixel;
636 xcolor.red = color->red;
637 xcolor.green = color->green;
638 xcolor.blue = color->blue;
639 xcolor.flags = DoRed | DoGreen | DoBlue;
641 private = (GdkColormapPrivate*) colormap;
642 XStoreColor (private->xdisplay, private->xcolormap, &xcolor);
648 gdk_color_equal (GdkColor *colora,
651 g_return_val_if_fail (colora != NULL, FALSE);
652 g_return_val_if_fail (colorb != NULL, FALSE);
654 return ((colora->red == colorb->red) &&
655 (colora->green == colorb->green) &&
656 (colora->blue == colorb->blue));
660 gdkx_colormap_get (Colormap xcolormap)
662 GdkColormap *colormap;
663 GdkColormapPrivate *private;
665 colormap = gdk_colormap_lookup (xcolormap);
669 if (xcolormap == DefaultColormap (gdk_display, gdk_screen))
670 return gdk_colormap_get_system ();
672 private = g_new (GdkColormapPrivate, 1);
673 colormap = (GdkColormap*) private;
675 private->xdisplay = gdk_display;
676 private->xcolormap = xcolormap;
677 private->visual = NULL;
678 private->private_val = TRUE;
679 private->next_color = 0;
681 /* To do the following safely, we would have to have some way of finding
682 * out what the size or visual of the given colormap is. It seems
683 * X doesn't allow this
687 for (i = 0; i < 256; i++)
689 xpalette[i].pixel = i;
691 xpalette[i].green = 0;
692 xpalette[i].blue = 0;
695 XQueryColors (gdk_display, private->xcolormap, xpalette, 256);
697 for (i = 0; i < 256; i++)
699 colormap->colors[i].pixel = xpalette[i].pixel;
700 colormap->colors[i].red = xpalette[i].red;
701 colormap->colors[i].green = xpalette[i].green;
702 colormap->colors[i].blue = xpalette[i].blue;
706 colormap->colors = NULL;
709 gdk_colormap_add (colormap);
716 gdk_colormap_match_color (GdkColormap *cmap,
718 const gchar *available)
722 gint rdiff, gdiff, bdiff;
725 g_return_val_if_fail (cmap != NULL, 0);
726 g_return_val_if_fail (color != NULL, 0);
728 colors = cmap->colors;
732 for (i = 0; i < cmap->size; i++)
734 if ((!available) || (available && available[i]))
736 rdiff = (color->red - colors[i].red);
737 gdiff = (color->green - colors[i].green);
738 bdiff = (color->blue - colors[i].blue);
740 sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
755 gdk_colormap_lookup (Colormap xcolormap)
762 cmap = g_hash_table_lookup (colormap_hash, &xcolormap);
767 gdk_colormap_add (GdkColormap *cmap)
769 GdkColormapPrivate *private;
772 colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
773 (GCompareFunc) gdk_colormap_cmp);
775 private = (GdkColormapPrivate*) cmap;
777 g_hash_table_insert (colormap_hash, &private->xcolormap, cmap);
781 gdk_colormap_remove (GdkColormap *cmap)
783 GdkColormapPrivate *private;
786 colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
787 (GCompareFunc) gdk_colormap_cmp);
789 private = (GdkColormapPrivate*) cmap;
791 g_hash_table_remove (colormap_hash, &private->xcolormap);
795 gdk_colormap_hash (Colormap *cmap)
801 gdk_colormap_cmp (Colormap *a,