]> Pileus Git - ~andy/gtk/blob - gdk/gdkcolor.c
Beginnings of support for 1 bpp depth in gdk. Very minor changes.
[~andy/gtk] / gdk / gdkcolor.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 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.
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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <X11/Xlib.h>
19 #include "gdk.h"
20 #include "gdkprivate.h"
21
22
23 static gint  gdk_colormap_match_color (GdkColormap *cmap,
24                                        GdkColor    *color,
25                                        const gchar *available);
26 static void  gdk_colormap_add         (GdkColormap *cmap);
27 static void  gdk_colormap_remove      (GdkColormap *cmap);
28 static guint gdk_colormap_hash        (Colormap    *cmap);
29 static gint  gdk_colormap_cmp         (Colormap    *a,
30                                        Colormap    *b);
31 static void gdk_colormap_real_destroy (GdkColormap *colormap);
32
33 static GHashTable *colormap_hash = NULL;
34
35
36 GdkColormap*
37 gdk_colormap_new (GdkVisual *visual,
38                   gint       private_cmap)
39 {
40   GdkColormap *colormap;
41   GdkColormapPrivate *private;
42   Visual *xvisual;
43   XColor default_colors[256];
44   int size;
45   int i;
46
47   g_return_val_if_fail (visual != NULL, NULL);
48
49   private = g_new (GdkColormapPrivate, 1);
50   colormap = (GdkColormap*) private;
51
52   private->xdisplay = gdk_display;
53   private->visual = visual;
54   private->next_color = 0;
55   private->ref_count = 1;
56   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
57
58   switch (visual->type)
59     {
60     case GDK_VISUAL_GRAYSCALE:
61     case GDK_VISUAL_PSEUDO_COLOR:
62       private->private_val = private_cmap;
63       private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
64                                             xvisual, (private_cmap) ? (AllocAll) : (AllocNone));
65
66       if (private_cmap)
67         {
68           for (i = 0; i < 256; i++)
69             default_colors[i].pixel = i;
70
71           XQueryColors (private->xdisplay,
72                         DefaultColormap (private->xdisplay, gdk_screen),
73                         default_colors, visual->colormap_size);
74
75           for (i = 0; i < visual->colormap_size; i++)
76             {
77               colormap->colors[i].pixel = default_colors[i].pixel;
78               colormap->colors[i].red = default_colors[i].red;
79               colormap->colors[i].green = default_colors[i].green;
80               colormap->colors[i].blue = default_colors[i].blue;
81             }
82
83           gdk_colormap_change (colormap, visual->colormap_size);
84         }
85       break;
86
87     case GDK_VISUAL_DIRECT_COLOR:
88       private->private_val = TRUE;
89       private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
90                                             xvisual, AllocAll);
91
92       size = 1 << visual->red_prec;
93       for (i = 0; i < size; i++)
94         colormap->colors[i].red = i * 65535 / (size - 1);
95
96       size = 1 << visual->green_prec;
97       for (i = 0; i < size; i++)
98         colormap->colors[i].green = i * 65535 / (size - 1);
99
100       size = 1 << visual->blue_prec;
101       for (i = 0; i < size; i++)
102         colormap->colors[i].blue = i * 65535 / (size - 1);
103
104       gdk_colormap_change (colormap, visual->colormap_size);
105       break;
106
107     case GDK_VISUAL_STATIC_GRAY:
108     case GDK_VISUAL_STATIC_COLOR:
109     case GDK_VISUAL_TRUE_COLOR:
110       private->private_val = FALSE;
111       private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
112                                             xvisual, AllocNone);
113       break;
114     }
115
116   gdk_colormap_add (colormap);
117
118   return colormap;
119 }
120
121 static void
122 gdk_colormap_real_destroy (GdkColormap *colormap)
123 {
124   GdkColormapPrivate *private = (GdkColormapPrivate*) colormap;
125
126   g_return_if_fail (colormap != NULL);
127
128   if (private->ref_count > 0)
129     return;
130
131   gdk_colormap_remove (colormap);
132   XFreeColormap (private->xdisplay, private->xcolormap);
133   g_free (colormap);
134 }
135
136 GdkColormap*
137 gdk_colormap_ref (GdkColormap *cmap)
138 {
139   GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
140   g_return_val_if_fail (cmap != NULL, NULL);
141
142   private->ref_count += 1;
143   return cmap;
144 }
145
146 void
147 gdk_colormap_unref (GdkColormap *cmap)
148 {
149   GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
150   g_return_if_fail (cmap != NULL);
151
152   private->ref_count -= 1;
153   if (private->ref_count == 0)
154     gdk_colormap_real_destroy (cmap);
155 }
156
157 GdkColormap*
158 gdk_colormap_get_system (void)
159 {
160   static GdkColormap *colormap = NULL;
161   GdkColormapPrivate *private;
162   XColor xpalette[256];
163   gint i;
164
165   if (!colormap)
166     {
167       private = g_new (GdkColormapPrivate, 1);
168       colormap = (GdkColormap*) private;
169
170       private->xdisplay = gdk_display;
171       private->xcolormap = DefaultColormap (gdk_display, gdk_screen);
172       private->visual = gdk_visual_get_system ();
173       private->private_val = FALSE;
174       private->next_color = 0;
175       private->ref_count = 1;
176
177       for (i = 0; i < 256; i++)
178         {
179           xpalette[i].pixel = i;
180           xpalette[i].red = 0;
181           xpalette[i].green = 0;
182           xpalette[i].blue = 0;
183         }
184
185       XQueryColors (gdk_display, private->xcolormap, xpalette, 
186                     private->visual->colormap_size);
187
188       for (i = 0; i < 256; i++)
189         {
190           colormap->colors[i].pixel = xpalette[i].pixel;
191           colormap->colors[i].red = xpalette[i].red;
192           colormap->colors[i].green = xpalette[i].green;
193           colormap->colors[i].blue = xpalette[i].blue;
194         }
195
196       gdk_colormap_add (colormap);
197     }
198
199   return colormap;
200 }
201
202 gint
203 gdk_colormap_get_system_size (void)
204 {
205   return DisplayCells (gdk_display, gdk_screen);
206 }
207
208 void
209 gdk_colormap_change (GdkColormap *colormap,
210                      gint         ncolors)
211 {
212   GdkColormapPrivate *private;
213   GdkVisual *visual;
214   XColor palette[256];
215   gint shift;
216   int max_colors;
217   int size;
218   int i;
219
220   g_return_if_fail (colormap != NULL);
221
222   private = (GdkColormapPrivate*) colormap;
223   switch (private->visual->type)
224     {
225     case GDK_VISUAL_GRAYSCALE:
226     case GDK_VISUAL_PSEUDO_COLOR:
227       for (i = 0; i < ncolors; i++)
228         {
229           palette[i].pixel = colormap->colors[i].pixel;
230           palette[i].red = colormap->colors[i].red;
231           palette[i].green = colormap->colors[i].green;
232           palette[i].blue = colormap->colors[i].blue;
233           palette[i].flags = DoRed | DoGreen | DoBlue;
234         }
235
236       XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors);
237       private->next_color = MAX (private->next_color, ncolors);
238       break;
239
240     case GDK_VISUAL_DIRECT_COLOR:
241       visual = private->visual;
242
243       shift = visual->red_shift;
244       max_colors = 1 << visual->red_prec;
245       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
246
247       for (i = 0; i < size; i++)
248         {
249           palette[i].pixel = i << shift;
250           palette[i].red = colormap->colors[i].red;
251           palette[i].flags = DoRed;
252         }
253
254       XStoreColors (private->xdisplay, private->xcolormap, palette, size);
255
256       shift = visual->green_shift;
257       max_colors = 1 << visual->green_prec;
258       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
259
260       for (i = 0; i < size; i++)
261         {
262           palette[i].pixel = i << shift;
263           palette[i].green = colormap->colors[i].green;
264           palette[i].flags = DoGreen;
265         }
266
267       XStoreColors (private->xdisplay, private->xcolormap, palette, size);
268
269       shift = visual->blue_shift;
270       max_colors = 1 << visual->blue_prec;
271       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
272
273       for (i = 0; i < size; i++)
274         {
275           palette[i].pixel = i << shift;
276           palette[i].blue = colormap->colors[i].blue;
277           palette[i].flags = DoBlue;
278         }
279
280       XStoreColors (private->xdisplay, private->xcolormap, palette, size);
281       break;
282
283     default:
284       break;
285     }
286 }
287
288 void
289 gdk_colors_store (GdkColormap   *colormap,
290                   GdkColor      *colors,
291                   gint           ncolors)
292 {
293   gint i;
294
295   for (i = 0; i < ncolors; i++)
296     {
297       colormap->colors[i].pixel = colors[i].pixel;
298       colormap->colors[i].red = colors[i].red;
299       colormap->colors[i].green = colors[i].green;
300       colormap->colors[i].blue = colors[i].blue;
301     }
302
303   gdk_colormap_change (colormap, ncolors);
304 }
305
306 gint
307 gdk_colors_alloc (GdkColormap   *colormap,
308                   gint           contiguous,
309                   gulong        *planes,
310                   gint           nplanes,
311                   gulong        *pixels,
312                   gint           npixels)
313 {
314   GdkColormapPrivate *private;
315   gint return_val;
316
317   g_return_val_if_fail (colormap != NULL, 0);
318
319   private = (GdkColormapPrivate*) colormap;
320
321   return_val = XAllocColorCells (private->xdisplay, private->xcolormap,
322                                  contiguous, planes, nplanes, pixels, npixels);
323
324   return return_val;
325 }
326
327 void
328 gdk_colors_free (GdkColormap *colormap,
329                  gulong      *pixels,
330                  gint         npixels,
331                  gulong       planes)
332 {
333   GdkColormapPrivate *private;
334
335   g_return_if_fail (colormap != NULL);
336
337   private = (GdkColormapPrivate*) colormap;
338
339   XFreeColors (private->xdisplay, private->xcolormap,
340                pixels, npixels, planes);
341 }
342
343 gint
344 gdk_color_white (GdkColormap *colormap,
345                  GdkColor    *color)
346 {
347   gint return_val;
348
349   g_return_val_if_fail (colormap != NULL, FALSE);
350
351   if (color)
352     {
353       color->pixel = WhitePixel (gdk_display, gdk_screen);
354       color->red = 65535;
355       color->green = 65535;
356       color->blue = 65535;
357
358       return_val = gdk_color_alloc (colormap, color);
359     }
360   else
361     return_val = FALSE;
362
363   return return_val;
364 }
365
366 gint
367 gdk_color_black (GdkColormap *colormap,
368                  GdkColor    *color)
369 {
370   gint return_val;
371
372   g_return_val_if_fail (colormap != NULL, FALSE);
373
374   if (color)
375     {
376       color->pixel = BlackPixel (gdk_display, gdk_screen);
377       color->red = 0;
378       color->green = 0;
379       color->blue = 0;
380
381       return_val = gdk_color_alloc (colormap, color);
382     }
383   else
384     return_val = FALSE;
385
386   return return_val;
387 }
388
389 gint
390 gdk_color_parse (const gchar *spec,
391                  GdkColor *color)
392 {
393   Colormap xcolormap;
394   XColor xcolor;
395   gint return_val;
396
397   g_return_val_if_fail (spec != NULL, FALSE);
398   g_return_val_if_fail (color != NULL, FALSE);
399
400   xcolormap = DefaultColormap (gdk_display, gdk_screen);
401
402   if (XParseColor (gdk_display, xcolormap, spec, &xcolor))
403     {
404       return_val = TRUE;
405       color->red = xcolor.red;
406       color->green = xcolor.green;
407       color->blue = xcolor.blue;
408     }
409   else
410     return_val = FALSE;
411
412   return return_val;
413 }
414
415 gint
416 gdk_color_alloc (GdkColormap *colormap,
417                  GdkColor    *color)
418 {
419   GdkColormapPrivate *private;
420   GdkVisual *visual;
421   XColor xcolor;
422   gchar available[256];
423   gint available_init;
424   gint return_val;
425   gint i, index;
426
427   g_return_val_if_fail (colormap != NULL, FALSE);
428   g_return_val_if_fail (color != NULL, FALSE);
429
430   xcolor.red = color->red;
431   xcolor.green = color->green;
432   xcolor.blue = color->blue;
433   xcolor.pixel = color->pixel;
434   xcolor.flags = DoRed | DoGreen | DoBlue;
435
436   return_val = FALSE;
437   private = (GdkColormapPrivate*) colormap;
438
439   switch (private->visual->type)
440     {
441     case GDK_VISUAL_GRAYSCALE:
442     case GDK_VISUAL_PSEUDO_COLOR:
443       if (private->private_val)
444         {
445           if (private->next_color > 255)
446             {
447               for (i = 0; i < 256; i++)
448                 available[i] = TRUE;
449
450               index = gdk_colormap_match_color (colormap, color, available);
451               if (index != -1)
452                 {
453                   available[index] = FALSE;
454                   *color = colormap->colors[index];
455                   return_val = TRUE;
456                 }
457               else
458                 {
459                   return_val = FALSE;
460                 }
461             }
462           else
463             {
464               xcolor.pixel = 255 - private->next_color;
465               color->pixel = xcolor.pixel;
466               private->next_color += 1;
467
468               XStoreColor (private->xdisplay, private->xcolormap, &xcolor);
469               return_val = TRUE;
470             }
471         }
472       else
473         {
474           available_init = 1;
475
476           while (1)
477             {
478               if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor))
479                 {
480                   color->pixel = xcolor.pixel;
481                   color->red = xcolor.red;
482                   color->green = xcolor.green;
483                   color->blue = xcolor.blue;
484
485                   colormap->colors[color->pixel] = *color;
486
487                   return_val = TRUE;
488                   break;
489                 }
490               else
491                 {
492                   if (available_init)
493                     {
494                       available_init = 0;
495                       for (i = 0; i < 256; i++)
496                         available[i] = TRUE;
497                     }
498
499                   index = gdk_colormap_match_color (colormap, color, available);
500                   if (index != -1)
501                     {
502                       available[index] = FALSE;
503                       xcolor.red = colormap->colors[index].red;
504                       xcolor.green = colormap->colors[index].green;
505                       xcolor.blue = colormap->colors[index].blue;
506                     }
507                   else
508                     {
509                       return_val = FALSE;
510                       break;
511                     }
512                 }
513             }
514         }
515       break;
516
517     case GDK_VISUAL_DIRECT_COLOR:
518       visual = private->visual;
519       xcolor.pixel = (((xcolor.red >> (16 - visual->red_prec)) << visual->red_shift) +
520                       ((xcolor.green >> (16 - visual->green_prec)) << visual->green_shift) +
521                       ((xcolor.blue >> (16 - visual->blue_prec)) << visual->blue_shift));
522       color->pixel = xcolor.pixel;
523       return_val = TRUE;
524       break;
525
526     case GDK_VISUAL_STATIC_GRAY:
527     case GDK_VISUAL_STATIC_COLOR:
528     case GDK_VISUAL_TRUE_COLOR:
529       if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor))
530         {
531           color->pixel = xcolor.pixel;
532           return_val = TRUE;
533         }
534       else
535         return_val = FALSE;
536       break;
537     }
538
539   return return_val;
540 }
541
542 gint
543 gdk_color_change (GdkColormap *colormap,
544                   GdkColor    *color)
545 {
546   GdkColormapPrivate *private;
547   XColor xcolor;
548
549   g_return_val_if_fail (colormap != NULL, FALSE);
550   g_return_val_if_fail (color != NULL, FALSE);
551
552   xcolor.pixel = color->pixel;
553   xcolor.red = color->red;
554   xcolor.green = color->green;
555   xcolor.blue = color->blue;
556   xcolor.flags = DoRed | DoGreen | DoBlue;
557
558   private = (GdkColormapPrivate*) colormap;
559   XStoreColor (private->xdisplay, private->xcolormap, &xcolor);
560
561   return TRUE;
562 }
563
564 gint
565 gdk_color_equal (GdkColor *colora,
566                  GdkColor *colorb)
567 {
568   g_return_val_if_fail (colora != NULL, FALSE);
569   g_return_val_if_fail (colorb != NULL, FALSE);
570
571   return ((colora->red == colorb->red) &&
572           (colora->green == colorb->green) &&
573           (colora->blue == colorb->blue));
574 }
575
576 GdkColormap*
577 gdkx_colormap_get (Colormap xcolormap)
578 {
579   GdkColormap *colormap;
580   GdkColormapPrivate *private;
581   XColor xpalette[256];
582   gint i;
583
584   colormap = gdk_colormap_lookup (xcolormap);
585   if (colormap)
586     return colormap;
587
588   if (xcolormap == DefaultColormap (gdk_display, gdk_screen))
589     return gdk_colormap_get_system ();
590
591   private = g_new (GdkColormapPrivate, 1);
592   colormap = (GdkColormap*) private;
593
594   private->xdisplay = gdk_display;
595   private->xcolormap = xcolormap;
596   private->visual = NULL;
597   private->private_val = TRUE;
598   private->next_color = 0;
599
600   for (i = 0; i < 256; i++)
601     {
602       xpalette[i].pixel = i;
603       xpalette[i].red = 0;
604       xpalette[i].green = 0;
605       xpalette[i].blue = 0;
606     }
607
608   XQueryColors (gdk_display, private->xcolormap, xpalette, 256);
609
610   for (i = 0; i < 256; i++)
611     {
612       colormap->colors[i].pixel = xpalette[i].pixel;
613       colormap->colors[i].red = xpalette[i].red;
614       colormap->colors[i].green = xpalette[i].green;
615       colormap->colors[i].blue = xpalette[i].blue;
616     }
617
618   gdk_colormap_add (colormap);
619
620   return colormap;
621 }
622
623
624 static gint
625 gdk_colormap_match_color (GdkColormap *cmap,
626                           GdkColor    *color,
627                           const gchar *available)
628 {
629   GdkColor *colors;
630   guint sum, max;
631   gint rdiff, gdiff, bdiff;
632   gint i, index;
633
634   g_return_val_if_fail (cmap != NULL, 0);
635   g_return_val_if_fail (color != NULL, 0);
636
637   colors = cmap->colors;
638   max = 3 * (65536);
639   index = -1;
640
641   for (i = 0; i < 256; i++)
642     {
643       if ((!available) || (available && available[i]))
644         {
645           rdiff = (color->red - colors[i].red);
646           gdiff = (color->green - colors[i].green);
647           bdiff = (color->blue - colors[i].blue);
648
649           sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
650
651           if (sum < max)
652             {
653               index = i;
654               max = sum;
655             }
656         }
657     }
658
659   return index;
660 }
661
662
663 GdkColormap*
664 gdk_colormap_lookup (Colormap xcolormap)
665 {
666   GdkColormap *cmap;
667
668   if (!colormap_hash)
669     return NULL;
670
671   cmap = g_hash_table_lookup (colormap_hash, &xcolormap);
672   return cmap;
673 }
674
675 static void
676 gdk_colormap_add (GdkColormap *cmap)
677 {
678   GdkColormapPrivate *private;
679
680   if (!colormap_hash)
681     colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
682                                       (GCompareFunc) gdk_colormap_cmp);
683
684   private = (GdkColormapPrivate*) cmap;
685
686   g_hash_table_insert (colormap_hash, &private->xcolormap, cmap);
687 }
688
689 static void
690 gdk_colormap_remove (GdkColormap *cmap)
691 {
692   GdkColormapPrivate *private;
693
694   if (!colormap_hash)
695     colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
696                                       (GCompareFunc) gdk_colormap_cmp);
697
698   private = (GdkColormapPrivate*) cmap;
699
700   g_hash_table_remove (colormap_hash, &private->xcolormap);
701 }
702
703 static guint
704 gdk_colormap_hash (Colormap *cmap)
705 {
706   return *cmap;
707 }
708
709 static gint
710 gdk_colormap_cmp (Colormap *a,
711                   Colormap *b)
712 {
713   return (*a == *b);
714 }