]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkcolor-x11.c
removed gtk_input_add_interp.
[~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 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
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include <X11/Xlib.h>
20 #include "gdk.h"
21 #include "gdkprivate.h"
22 #include "gdkx.h"
23
24
25 static gint  gdk_colormap_match_color (GdkColormap *cmap,
26                                        GdkColor    *color,
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,
32                                        Colormap    *b);
33 static void gdk_colormap_real_destroy (GdkColormap *colormap);
34
35 static GHashTable *colormap_hash = NULL;
36
37
38 GdkColormap*
39 gdk_colormap_new (GdkVisual *visual,
40                   gint       private_cmap)
41 {
42   GdkColormap *colormap;
43   GdkColormapPrivate *private;
44   Visual *xvisual;
45   int size;
46   int i;
47
48   g_return_val_if_fail (visual != NULL, NULL);
49
50   private = g_new (GdkColormapPrivate, 1);
51   colormap = (GdkColormap*) private;
52
53   private->xdisplay = gdk_display;
54   private->visual = visual;
55   private->next_color = 0;
56   private->ref_count = 1;
57   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
58
59   colormap->size = visual->colormap_size;
60   colormap->colors = g_new (GdkColor, colormap->size);
61
62   switch (visual->type)
63     {
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));
69
70       if (private_cmap)
71         {
72           XColor *default_colors;
73
74           default_colors = g_new (XColor, colormap->size);
75
76           for (i = 0; i < colormap->size; i++)
77             default_colors[i].pixel = i;
78
79           XQueryColors (private->xdisplay,
80                         DefaultColormap (private->xdisplay, gdk_screen),
81                         default_colors, colormap->size);
82
83           for (i = 0; i < colormap->size; i++)
84             {
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;
89             }
90
91           gdk_colormap_change (colormap, colormap->size);
92           
93           g_free (default_colors);
94         }
95       break;
96
97     case GDK_VISUAL_DIRECT_COLOR:
98       private->private_val = TRUE;
99       private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
100                                             xvisual, AllocAll);
101
102       size = 1 << visual->red_prec;
103       for (i = 0; i < size; i++)
104         colormap->colors[i].red = i * 65535 / (size - 1);
105
106       size = 1 << visual->green_prec;
107       for (i = 0; i < size; i++)
108         colormap->colors[i].green = i * 65535 / (size - 1);
109
110       size = 1 << visual->blue_prec;
111       for (i = 0; i < size; i++)
112         colormap->colors[i].blue = i * 65535 / (size - 1);
113
114       gdk_colormap_change (colormap, colormap->size);
115       break;
116
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,
122                                             xvisual, AllocNone);
123       break;
124     }
125
126   gdk_colormap_add (colormap);
127
128   return colormap;
129 }
130
131 static void
132 gdk_colormap_real_destroy (GdkColormap *colormap)
133 {
134   GdkColormapPrivate *private = (GdkColormapPrivate*) colormap;
135
136   g_return_if_fail (colormap != NULL);
137
138   if (private->ref_count > 0)
139     return;
140
141   gdk_colormap_remove (colormap);
142   XFreeColormap (private->xdisplay, private->xcolormap);
143   g_free (colormap->colors);
144   g_free (colormap);
145 }
146
147 GdkColormap*
148 gdk_colormap_ref (GdkColormap *cmap)
149 {
150   GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
151   g_return_val_if_fail (cmap != NULL, NULL);
152
153   private->ref_count += 1;
154   return cmap;
155 }
156
157 void
158 gdk_colormap_unref (GdkColormap *cmap)
159 {
160   GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
161   g_return_if_fail (cmap != NULL);
162
163   private->ref_count -= 1;
164   if (private->ref_count == 0)
165     gdk_colormap_real_destroy (cmap);
166 }
167
168 GdkColormap*
169 gdk_colormap_get_system (void)
170 {
171   static GdkColormap *colormap = NULL;
172   GdkColormapPrivate *private;
173   XColor *xpalette;
174   gint i;
175
176   if (!colormap)
177     {
178       private = g_new (GdkColormapPrivate, 1);
179       colormap = (GdkColormap*) private;
180
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;
187
188       colormap->size = private->visual->colormap_size;
189       colormap->colors = g_new (GdkColor, colormap->size);
190
191       if ((private->visual->type == GDK_VISUAL_GRAYSCALE) ||
192           (private->visual->type == GDK_VISUAL_PSEUDO_COLOR))
193         {
194           xpalette = g_new (XColor, colormap->size);
195           
196           for (i = 0; i < colormap->size; i++)
197             {
198               xpalette[i].pixel = i;
199               xpalette[i].red = 0;
200               xpalette[i].green = 0;
201               xpalette[i].blue = 0;
202             }
203           
204           XQueryColors (gdk_display, private->xcolormap, xpalette, 
205                         colormap->size);
206           
207           for (i = 0; i < colormap->size; i++)
208             {
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;
213             }
214
215           g_free (xpalette);
216         }
217
218       gdk_colormap_add (colormap);
219     }
220
221   return colormap;
222 }
223
224 gint
225 gdk_colormap_get_system_size (void)
226 {
227   return DisplayCells (gdk_display, gdk_screen);
228 }
229
230 void
231 gdk_colormap_change (GdkColormap *colormap,
232                      gint         ncolors)
233 {
234   GdkColormapPrivate *private;
235   GdkVisual *visual;
236   XColor *palette;
237   gint shift;
238   int max_colors;
239   int size;
240   int i;
241
242   g_return_if_fail (colormap != NULL);
243
244   palette = g_new (XColor, ncolors);
245
246   private = (GdkColormapPrivate*) colormap;
247   switch (private->visual->type)
248     {
249     case GDK_VISUAL_GRAYSCALE:
250     case GDK_VISUAL_PSEUDO_COLOR:
251       for (i = 0; i < ncolors; i++)
252         {
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;
258         }
259
260       XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors);
261       private->next_color = MAX (private->next_color, ncolors);
262       break;
263
264     case GDK_VISUAL_DIRECT_COLOR:
265       visual = private->visual;
266
267       shift = visual->red_shift;
268       max_colors = 1 << visual->red_prec;
269       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
270
271       for (i = 0; i < size; i++)
272         {
273           palette[i].pixel = i << shift;
274           palette[i].red = colormap->colors[i].red;
275           palette[i].flags = DoRed;
276         }
277
278       XStoreColors (private->xdisplay, private->xcolormap, palette, size);
279
280       shift = visual->green_shift;
281       max_colors = 1 << visual->green_prec;
282       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
283
284       for (i = 0; i < size; i++)
285         {
286           palette[i].pixel = i << shift;
287           palette[i].green = colormap->colors[i].green;
288           palette[i].flags = DoGreen;
289         }
290
291       XStoreColors (private->xdisplay, private->xcolormap, palette, size);
292
293       shift = visual->blue_shift;
294       max_colors = 1 << visual->blue_prec;
295       size = (ncolors < max_colors) ? (ncolors) : (max_colors);
296
297       for (i = 0; i < size; i++)
298         {
299           palette[i].pixel = i << shift;
300           palette[i].blue = colormap->colors[i].blue;
301           palette[i].flags = DoBlue;
302         }
303
304       XStoreColors (private->xdisplay, private->xcolormap, palette, size);
305       break;
306
307     default:
308       break;
309     }
310
311   g_free (palette);
312 }
313
314 void
315 gdk_colors_store (GdkColormap   *colormap,
316                   GdkColor      *colors,
317                   gint           ncolors)
318 {
319   gint i;
320
321   for (i = 0; i < ncolors; i++)
322     {
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;
327     }
328
329   gdk_colormap_change (colormap, ncolors);
330 }
331
332 gboolean
333 gdk_colors_alloc (GdkColormap   *colormap,
334                   gint           contiguous,
335                   gulong        *planes,
336                   gint           nplanes,
337                   gulong        *pixels,
338                   gint           npixels)
339 {
340   GdkColormapPrivate *private;
341   gint return_val;
342
343   g_return_val_if_fail (colormap != NULL, 0);
344
345   private = (GdkColormapPrivate*) colormap;
346
347   return_val = XAllocColorCells (private->xdisplay, private->xcolormap,
348                                  contiguous, planes, nplanes, pixels, npixels);
349
350   return return_val;
351 }
352
353 void
354 gdk_colors_free (GdkColormap *colormap,
355                  gulong      *pixels,
356                  gint         npixels,
357                  gulong       planes)
358 {
359   GdkColormapPrivate *private;
360
361   g_return_if_fail (colormap != NULL);
362
363   private = (GdkColormapPrivate*) colormap;
364
365   XFreeColors (private->xdisplay, private->xcolormap,
366                pixels, npixels, planes);
367 }
368
369 /*
370  *--------------------------------------------------------------
371  * gdk_color_copy
372  *
373  *   Copy a color structure into new storage.
374  *
375  * Arguments:
376  *   "color" is the color struct to copy.
377  *
378  * Results:
379  *   A new color structure.  Free it with gdk_color_free.
380  *
381  *--------------------------------------------------------------
382  */
383
384 static GMemChunk *color_chunk;
385
386 GdkColor*
387 gdk_color_copy (GdkColor *color)
388 {
389   GdkColor *new_color;
390   
391   g_return_val_if_fail (color != NULL, NULL);
392
393   if (color_chunk == NULL)
394     color_chunk = g_mem_chunk_new ("colors",
395                                    sizeof (GdkColor),
396                                    4096,
397                                    G_ALLOC_AND_FREE);
398
399   new_color = g_chunk_new (GdkColor, color_chunk);
400   *new_color = *color;
401   return new_color;
402 }
403
404 /*
405  *--------------------------------------------------------------
406  * gdk_color_free
407  *
408  *   Free a color structure obtained from gdk_color_copy.  Do not use
409  *   with other color structures.
410  *
411  * Arguments:
412  *   "color" is the color struct to free.
413  *
414  *-------------------------------------------------------------- */
415
416 void
417 gdk_color_free (GdkColor *color)
418 {
419   g_assert (color_chunk != NULL);
420   g_return_if_fail (color != NULL);
421
422   g_mem_chunk_free (color_chunk, color);
423 }
424
425 gint
426 gdk_color_white (GdkColormap *colormap,
427                  GdkColor    *color)
428 {
429   gint return_val;
430
431   g_return_val_if_fail (colormap != NULL, FALSE);
432
433   if (color)
434     {
435       color->pixel = WhitePixel (gdk_display, gdk_screen);
436       color->red = 65535;
437       color->green = 65535;
438       color->blue = 65535;
439
440       return_val = gdk_color_alloc (colormap, color);
441     }
442   else
443     return_val = FALSE;
444
445   return return_val;
446 }
447
448 gint
449 gdk_color_black (GdkColormap *colormap,
450                  GdkColor    *color)
451 {
452   gint return_val;
453
454   g_return_val_if_fail (colormap != NULL, FALSE);
455
456   if (color)
457     {
458       color->pixel = BlackPixel (gdk_display, gdk_screen);
459       color->red = 0;
460       color->green = 0;
461       color->blue = 0;
462
463       return_val = gdk_color_alloc (colormap, color);
464     }
465   else
466     return_val = FALSE;
467
468   return return_val;
469 }
470
471 gboolean
472 gdk_color_parse (const gchar *spec,
473                  GdkColor *color)
474 {
475   Colormap xcolormap;
476   XColor xcolor;
477   gboolean return_val;
478
479   g_return_val_if_fail (spec != NULL, FALSE);
480   g_return_val_if_fail (color != NULL, FALSE);
481
482   xcolormap = DefaultColormap (gdk_display, gdk_screen);
483
484   if (XParseColor (gdk_display, xcolormap, spec, &xcolor))
485     {
486       return_val = TRUE;
487       color->red = xcolor.red;
488       color->green = xcolor.green;
489       color->blue = xcolor.blue;
490     }
491   else
492     return_val = FALSE;
493
494   return return_val;
495 }
496
497 gboolean
498 gdk_color_alloc (GdkColormap *colormap,
499                  GdkColor    *color)
500 {
501   GdkColormapPrivate *private;
502   GdkVisual *visual;
503   XColor xcolor;
504   gchar *available = NULL;
505   gboolean return_val;
506   gint i, index;
507
508   g_return_val_if_fail (colormap != NULL, FALSE);
509   g_return_val_if_fail (color != NULL, FALSE);
510
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;
516
517   return_val = FALSE;
518   private = (GdkColormapPrivate*) colormap;
519
520   switch (private->visual->type)
521     {
522     case GDK_VISUAL_GRAYSCALE:
523     case GDK_VISUAL_PSEUDO_COLOR:
524       if (private->private_val)
525         {
526           if (private->next_color >= colormap->size)
527             {
528               available = g_new (gchar, colormap->size);
529               for (i = 0; i < colormap->size; i++)
530                 available[i] = TRUE;
531
532               index = gdk_colormap_match_color (colormap, color, available);
533               if (index != -1)
534                 {
535                   available[index] = FALSE;
536                   *color = colormap->colors[index];
537                   return_val = TRUE;
538                 }
539               else
540                 {
541                   return_val = FALSE;
542                 }
543             }
544           else
545             {
546               xcolor.pixel = colormap->size - 1 -private->next_color;
547               color->pixel = xcolor.pixel;
548               private->next_color += 1;
549
550               XStoreColor (private->xdisplay, private->xcolormap, &xcolor);
551               return_val = TRUE;
552             }
553         }
554       else
555         {
556           while (1)
557             {
558               if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor))
559                 {
560                   color->pixel = xcolor.pixel;
561                   color->red = xcolor.red;
562                   color->green = xcolor.green;
563                   color->blue = xcolor.blue;
564
565                   if (color->pixel < colormap->size)
566                     colormap->colors[color->pixel] = *color;
567
568                   return_val = TRUE;
569                   break;
570                 }
571               else
572                 {
573                   if (available == NULL)
574                     {
575                       available = g_new (gchar, colormap->size);
576                       for (i = 0; i < colormap->size; i++)
577                         available[i] = TRUE;
578                     }
579
580                   index = gdk_colormap_match_color (colormap, color, available);
581                   if (index != -1)
582                     {
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;
587                     }
588                   else
589                     {
590                       return_val = FALSE;
591                       break;
592                     }
593                 }
594             }
595         }
596       break;
597
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;
604       return_val = TRUE;
605       break;
606
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))
611         {
612           color->pixel = xcolor.pixel;
613           return_val = TRUE;
614         }
615       else
616         return_val = FALSE;
617       break;
618     }
619
620   if (available)
621     g_free (available);
622   
623   return return_val;
624 }
625
626 gboolean
627 gdk_color_change (GdkColormap *colormap,
628                   GdkColor    *color)
629 {
630   GdkColormapPrivate *private;
631   XColor xcolor;
632
633   g_return_val_if_fail (colormap != NULL, FALSE);
634   g_return_val_if_fail (color != NULL, FALSE);
635
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;
641
642   private = (GdkColormapPrivate*) colormap;
643   XStoreColor (private->xdisplay, private->xcolormap, &xcolor);
644
645   return TRUE;
646 }
647
648 gint
649 gdk_color_equal (GdkColor *colora,
650                  GdkColor *colorb)
651 {
652   g_return_val_if_fail (colora != NULL, FALSE);
653   g_return_val_if_fail (colorb != NULL, FALSE);
654
655   return ((colora->red == colorb->red) &&
656           (colora->green == colorb->green) &&
657           (colora->blue == colorb->blue));
658 }
659
660 GdkColormap*
661 gdkx_colormap_get (Colormap xcolormap)
662 {
663   GdkColormap *colormap;
664   GdkColormapPrivate *private;
665
666   colormap = gdk_colormap_lookup (xcolormap);
667   if (colormap)
668     return colormap;
669
670   if (xcolormap == DefaultColormap (gdk_display, gdk_screen))
671     return gdk_colormap_get_system ();
672
673   private = g_new (GdkColormapPrivate, 1);
674   colormap = (GdkColormap*) private;
675
676   private->xdisplay = gdk_display;
677   private->xcolormap = xcolormap;
678   private->visual = NULL;
679   private->private_val = TRUE;
680   private->next_color = 0;
681
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
685    */
686
687 #if 0
688   for (i = 0; i < 256; i++)
689     {
690       xpalette[i].pixel = i;
691       xpalette[i].red = 0;
692       xpalette[i].green = 0;
693       xpalette[i].blue = 0;
694     }
695
696   XQueryColors (gdk_display, private->xcolormap, xpalette, 256);
697
698   for (i = 0; i < 256; i++)
699     {
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;
704     }
705 #endif
706
707   colormap->colors = NULL;
708   colormap->size = 0;
709
710   gdk_colormap_add (colormap);
711
712   return colormap;
713 }
714
715
716 static gint
717 gdk_colormap_match_color (GdkColormap *cmap,
718                           GdkColor    *color,
719                           const gchar *available)
720 {
721   GdkColor *colors;
722   guint sum, max;
723   gint rdiff, gdiff, bdiff;
724   gint i, index;
725
726   g_return_val_if_fail (cmap != NULL, 0);
727   g_return_val_if_fail (color != NULL, 0);
728
729   colors = cmap->colors;
730   max = 3 * (65536);
731   index = -1;
732
733   for (i = 0; i < cmap->size; i++)
734     {
735       if ((!available) || (available && available[i]))
736         {
737           rdiff = (color->red - colors[i].red);
738           gdiff = (color->green - colors[i].green);
739           bdiff = (color->blue - colors[i].blue);
740
741           sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
742
743           if (sum < max)
744             {
745               index = i;
746               max = sum;
747             }
748         }
749     }
750
751   return index;
752 }
753
754
755 GdkColormap*
756 gdk_colormap_lookup (Colormap xcolormap)
757 {
758   GdkColormap *cmap;
759
760   if (!colormap_hash)
761     return NULL;
762
763   cmap = g_hash_table_lookup (colormap_hash, &xcolormap);
764   return cmap;
765 }
766
767 static void
768 gdk_colormap_add (GdkColormap *cmap)
769 {
770   GdkColormapPrivate *private;
771
772   if (!colormap_hash)
773     colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
774                                       (GCompareFunc) gdk_colormap_cmp);
775
776   private = (GdkColormapPrivate*) cmap;
777
778   g_hash_table_insert (colormap_hash, &private->xcolormap, cmap);
779 }
780
781 static void
782 gdk_colormap_remove (GdkColormap *cmap)
783 {
784   GdkColormapPrivate *private;
785
786   if (!colormap_hash)
787     colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
788                                       (GCompareFunc) gdk_colormap_cmp);
789
790   private = (GdkColormapPrivate*) cmap;
791
792   g_hash_table_remove (colormap_hash, &private->xcolormap);
793 }
794
795 static guint
796 gdk_colormap_hash (Colormap *cmap)
797 {
798   return *cmap;
799 }
800
801 static gint
802 gdk_colormap_cmp (Colormap *a,
803                   Colormap *b)
804 {
805   return (*a == *b);
806 }