source: trunk/third/gtk/gdk/gdkcolor.c @ 14482

Revision 14482, 29.1 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
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
20/*
21 * Modified by the GTK+ Team and others 1997-1999.  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#include <X11/Xlib.h>
29#include "gdk.h"
30#include "gdkprivate.h"
31#include "gdkx.h"
32
33
34static gint  gdk_colormap_match_color (GdkColormap *cmap,
35                                       GdkColor    *color,
36                                       const gchar *available);
37static void  gdk_colormap_add         (GdkColormap *cmap);
38static void  gdk_colormap_remove      (GdkColormap *cmap);
39static guint gdk_colormap_hash        (Colormap    *cmap);
40static gint  gdk_colormap_cmp         (Colormap    *a,
41                                       Colormap    *b);
42static void gdk_colormap_real_destroy (GdkColormap *colormap);
43
44static GHashTable *colormap_hash = NULL;
45
46
47GdkColormap*
48gdk_colormap_new (GdkVisual *visual,
49                  gboolean   private_cmap)
50{
51  GdkColormap *colormap;
52  GdkColormapPrivate *private;
53  Visual *xvisual;
54  int size;
55  int i;
56
57  g_return_val_if_fail (visual != NULL, NULL);
58
59  private = g_new (GdkColormapPrivate, 1);
60  colormap = (GdkColormap*) private;
61
62  private->xdisplay = gdk_display;
63  private->visual = visual;
64  private->ref_count = 1;
65
66  private->hash = NULL;
67  private->last_sync_time = 0;
68  private->info = NULL;
69 
70  xvisual = ((GdkVisualPrivate*) visual)->xvisual;
71
72  colormap->size = visual->colormap_size;
73  colormap->colors = NULL;
74
75  switch (visual->type)
76    {
77    case GDK_VISUAL_GRAYSCALE:
78    case GDK_VISUAL_PSEUDO_COLOR:
79      private->info = g_new0 (GdkColorInfo, colormap->size);
80      colormap->colors = g_new (GdkColor, colormap->size);
81     
82      private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
83                                        (GCompareFunc) gdk_color_equal);
84     
85      private->private_val = private_cmap;
86      private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
87                                            xvisual, (private_cmap) ? (AllocAll) : (AllocNone));
88
89      if (private_cmap)
90        {
91          XColor *default_colors;
92
93          default_colors = g_new (XColor, colormap->size);
94
95          for (i = 0; i < colormap->size; i++)
96            default_colors[i].pixel = i;
97
98          XQueryColors (private->xdisplay,
99                        DefaultColormap (private->xdisplay, gdk_screen),
100                        default_colors, colormap->size);
101
102          for (i = 0; i < colormap->size; i++)
103            {
104              colormap->colors[i].pixel = default_colors[i].pixel;
105              colormap->colors[i].red = default_colors[i].red;
106              colormap->colors[i].green = default_colors[i].green;
107              colormap->colors[i].blue = default_colors[i].blue;
108            }
109
110          gdk_colormap_change (colormap, colormap->size);
111         
112          g_free (default_colors);
113        }
114      break;
115
116    case GDK_VISUAL_DIRECT_COLOR:
117      private->private_val = TRUE;
118      private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
119                                            xvisual, AllocAll);
120      colormap->colors = g_new (GdkColor, colormap->size);
121
122      size = 1 << visual->red_prec;
123      for (i = 0; i < size; i++)
124        colormap->colors[i].red = i * 65535 / (size - 1);
125
126      size = 1 << visual->green_prec;
127      for (i = 0; i < size; i++)
128        colormap->colors[i].green = i * 65535 / (size - 1);
129
130      size = 1 << visual->blue_prec;
131      for (i = 0; i < size; i++)
132        colormap->colors[i].blue = i * 65535 / (size - 1);
133
134      gdk_colormap_change (colormap, colormap->size);
135      break;
136
137    case GDK_VISUAL_STATIC_GRAY:
138    case GDK_VISUAL_STATIC_COLOR:
139    case GDK_VISUAL_TRUE_COLOR:
140      private->private_val = FALSE;
141      private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window,
142                                            xvisual, AllocNone);
143      break;
144    }
145
146  gdk_colormap_add (colormap);
147
148  return colormap;
149}
150
151static void
152gdk_colormap_real_destroy (GdkColormap *colormap)
153{
154  GdkColormapPrivate *private = (GdkColormapPrivate*) colormap;
155
156  g_return_if_fail (colormap != NULL);
157  g_return_if_fail (private->ref_count == 0);
158
159  gdk_colormap_remove (colormap);
160  XFreeColormap (private->xdisplay, private->xcolormap);
161
162  if (private->hash)
163    g_hash_table_destroy (private->hash);
164 
165  g_free (private->info);
166  g_free (colormap->colors);
167  g_free (colormap);
168}
169
170GdkColormap*
171gdk_colormap_ref (GdkColormap *cmap)
172{
173  GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
174
175  g_return_val_if_fail (cmap != NULL, NULL);
176
177  private->ref_count += 1;
178  return cmap;
179}
180
181void
182gdk_colormap_unref (GdkColormap *cmap)
183{
184  GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
185
186  g_return_if_fail (cmap != NULL);
187  g_return_if_fail (private->ref_count > 0);
188
189  private->ref_count -= 1;
190  if (private->ref_count == 0)
191    gdk_colormap_real_destroy (cmap);
192}
193
194GdkVisual *
195gdk_colormap_get_visual (GdkColormap *colormap)
196{
197  GdkColormapPrivate *private;
198
199  g_return_val_if_fail (colormap != NULL, NULL);
200 
201  private = (GdkColormapPrivate *)colormap;
202
203  return private->visual;
204}
205     
206#define MIN_SYNC_TIME 2
207
208void
209gdk_colormap_sync (GdkColormap *colormap,
210                   gboolean     force)
211{
212  time_t current_time;
213  GdkColormapPrivate *private = (GdkColormapPrivate *)colormap;
214  XColor *xpalette;
215  gint nlookup;
216  gint i;
217 
218  g_return_if_fail (colormap != NULL);
219
220  current_time = time (NULL);
221  if (!force && ((current_time - private->last_sync_time) < MIN_SYNC_TIME))
222    return;
223
224  private->last_sync_time = current_time;
225
226  nlookup = 0;
227  xpalette = g_new (XColor, colormap->size);
228 
229  for (i = 0; i < colormap->size; i++)
230    {
231      if (private->info[i].ref_count == 0)
232        {
233          xpalette[nlookup].pixel = i;
234          xpalette[nlookup].red = 0;
235          xpalette[nlookup].green = 0;
236          xpalette[nlookup].blue = 0;
237          nlookup++;
238        }
239    }
240 
241  XQueryColors (gdk_display, private->xcolormap, xpalette, nlookup);
242 
243  for (i = 0; i < nlookup; i++)
244    {
245      gulong pixel = xpalette[i].pixel;
246      colormap->colors[pixel].pixel = pixel;
247      colormap->colors[pixel].red = xpalette[i].red;
248      colormap->colors[pixel].green = xpalette[i].green;
249      colormap->colors[pixel].blue = xpalette[i].blue;
250    }
251 
252  g_free (xpalette);
253}
254                   
255
256GdkColormap*
257gdk_colormap_get_system (void)
258{
259  static GdkColormap *colormap = NULL;
260  GdkColormapPrivate *private;
261
262  if (!colormap)
263    {
264      private = g_new (GdkColormapPrivate, 1);
265      colormap = (GdkColormap*) private;
266
267      private->xdisplay = gdk_display;
268      private->xcolormap = DefaultColormap (gdk_display, gdk_screen);
269      private->visual = gdk_visual_get_system ();
270      private->private_val = FALSE;
271      private->ref_count = 1;
272
273      private->hash = NULL;
274      private->last_sync_time = 0;
275      private->info = NULL;
276
277      colormap->colors = NULL;
278      colormap->size = private->visual->colormap_size;
279
280      if ((private->visual->type == GDK_VISUAL_GRAYSCALE) ||
281          (private->visual->type == GDK_VISUAL_PSEUDO_COLOR))
282        {
283          private->info = g_new0 (GdkColorInfo, colormap->size);
284          colormap->colors = g_new (GdkColor, colormap->size);
285         
286          private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
287                                            (GCompareFunc) gdk_color_equal);
288
289          gdk_colormap_sync (colormap, TRUE);
290        }
291
292      gdk_colormap_add (colormap);
293    }
294
295  return colormap;
296}
297
298gint
299gdk_colormap_get_system_size (void)
300{
301  return DisplayCells (gdk_display, gdk_screen);
302}
303
304void
305gdk_colormap_change (GdkColormap *colormap,
306                     gint         ncolors)
307{
308  GdkColormapPrivate *private;
309  GdkVisual *visual;
310  XColor *palette;
311  gint shift;
312  int max_colors;
313  int size;
314  int i;
315
316  g_return_if_fail (colormap != NULL);
317
318  palette = g_new (XColor, ncolors);
319
320  private = (GdkColormapPrivate*) colormap;
321  switch (private->visual->type)
322    {
323    case GDK_VISUAL_GRAYSCALE:
324    case GDK_VISUAL_PSEUDO_COLOR:
325      for (i = 0; i < ncolors; i++)
326        {
327          palette[i].pixel = colormap->colors[i].pixel;
328          palette[i].red = colormap->colors[i].red;
329          palette[i].green = colormap->colors[i].green;
330          palette[i].blue = colormap->colors[i].blue;
331          palette[i].flags = DoRed | DoGreen | DoBlue;
332        }
333
334      XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors);
335      break;
336
337    case GDK_VISUAL_DIRECT_COLOR:
338      visual = private->visual;
339
340      shift = visual->red_shift;
341      max_colors = 1 << visual->red_prec;
342      size = (ncolors < max_colors) ? (ncolors) : (max_colors);
343
344      for (i = 0; i < size; i++)
345        {
346          palette[i].pixel = i << shift;
347          palette[i].red = colormap->colors[i].red;
348          palette[i].flags = DoRed;
349        }
350
351      XStoreColors (private->xdisplay, private->xcolormap, palette, size);
352
353      shift = visual->green_shift;
354      max_colors = 1 << visual->green_prec;
355      size = (ncolors < max_colors) ? (ncolors) : (max_colors);
356
357      for (i = 0; i < size; i++)
358        {
359          palette[i].pixel = i << shift;
360          palette[i].green = colormap->colors[i].green;
361          palette[i].flags = DoGreen;
362        }
363
364      XStoreColors (private->xdisplay, private->xcolormap, palette, size);
365
366      shift = visual->blue_shift;
367      max_colors = 1 << visual->blue_prec;
368      size = (ncolors < max_colors) ? (ncolors) : (max_colors);
369
370      for (i = 0; i < size; i++)
371        {
372          palette[i].pixel = i << shift;
373          palette[i].blue = colormap->colors[i].blue;
374          palette[i].flags = DoBlue;
375        }
376
377      XStoreColors (private->xdisplay, private->xcolormap, palette, size);
378      break;
379
380    default:
381      break;
382    }
383
384  g_free (palette);
385}
386
387void
388gdk_colors_store (GdkColormap   *colormap,
389                  GdkColor      *colors,
390                  gint           ncolors)
391{
392  gint i;
393
394  for (i = 0; i < ncolors; i++)
395    {
396      colormap->colors[i].pixel = colors[i].pixel;
397      colormap->colors[i].red = colors[i].red;
398      colormap->colors[i].green = colors[i].green;
399      colormap->colors[i].blue = colors[i].blue;
400    }
401
402  gdk_colormap_change (colormap, ncolors);
403}
404
405gboolean
406gdk_colors_alloc (GdkColormap   *colormap,
407                  gboolean       contiguous,
408                  gulong        *planes,
409                  gint           nplanes,
410                  gulong        *pixels,
411                  gint           npixels)
412{
413  GdkColormapPrivate *private;
414  gint return_val;
415  gint i;
416
417  g_return_val_if_fail (colormap != NULL, 0);
418
419  private = (GdkColormapPrivate*) colormap;
420
421  return_val = XAllocColorCells (private->xdisplay, private->xcolormap,
422                                 contiguous, planes, nplanes, pixels, npixels);
423
424  if (return_val)
425    {
426      for (i=0; i<npixels; i++)
427        {
428          private->info[pixels[i]].ref_count++;
429          private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
430        }
431    }
432
433  return return_val != 0;
434}
435
436/*
437 *--------------------------------------------------------------
438 * gdk_color_copy
439 *
440 *   Copy a color structure into new storage.
441 *
442 * Arguments:
443 *   "color" is the color struct to copy.
444 *
445 * Results:
446 *   A new color structure.  Free it with gdk_color_free.
447 *
448 *--------------------------------------------------------------
449 */
450
451static GMemChunk *color_chunk;
452
453GdkColor*
454gdk_color_copy (const GdkColor *color)
455{
456  GdkColor *new_color;
457 
458  g_return_val_if_fail (color != NULL, NULL);
459
460  if (color_chunk == NULL)
461    color_chunk = g_mem_chunk_new ("colors",
462                                   sizeof (GdkColor),
463                                   4096,
464                                   G_ALLOC_AND_FREE);
465
466  new_color = g_chunk_new (GdkColor, color_chunk);
467  *new_color = *color;
468  return new_color;
469}
470
471/*
472 *--------------------------------------------------------------
473 * gdk_color_free
474 *
475 *   Free a color structure obtained from gdk_color_copy.  Do not use
476 *   with other color structures.
477 *
478 * Arguments:
479 *   "color" is the color struct to free.
480 *
481 *-------------------------------------------------------------- */
482
483void
484gdk_color_free (GdkColor *color)
485{
486  g_assert (color_chunk != NULL);
487  g_return_if_fail (color != NULL);
488
489  g_mem_chunk_free (color_chunk, color);
490}
491
492gboolean
493gdk_color_white (GdkColormap *colormap,
494                 GdkColor    *color)
495{
496  gint return_val;
497
498  g_return_val_if_fail (colormap != NULL, FALSE);
499
500  if (color)
501    {
502      color->pixel = WhitePixel (gdk_display, gdk_screen);
503      color->red = 65535;
504      color->green = 65535;
505      color->blue = 65535;
506
507      return_val = gdk_color_alloc (colormap, color);
508    }
509  else
510    return_val = FALSE;
511
512  return return_val;
513}
514
515gboolean
516gdk_color_black (GdkColormap *colormap,
517                 GdkColor    *color)
518{
519  gint return_val;
520
521  g_return_val_if_fail (colormap != NULL, FALSE);
522
523  if (color)
524    {
525      color->pixel = BlackPixel (gdk_display, gdk_screen);
526      color->red = 0;
527      color->green = 0;
528      color->blue = 0;
529
530      return_val = gdk_color_alloc (colormap, color);
531    }
532  else
533    return_val = FALSE;
534
535  return return_val;
536}
537
538gboolean
539gdk_color_parse (const gchar *spec,
540                 GdkColor *color)
541{
542  Colormap xcolormap;
543  XColor xcolor;
544  gboolean return_val;
545
546  g_return_val_if_fail (spec != NULL, FALSE);
547  g_return_val_if_fail (color != NULL, FALSE);
548
549  xcolormap = DefaultColormap (gdk_display, gdk_screen);
550
551  if (XParseColor (gdk_display, xcolormap, spec, &xcolor))
552    {
553      return_val = TRUE;
554      color->red = xcolor.red;
555      color->green = xcolor.green;
556      color->blue = xcolor.blue;
557    }
558  else
559    return_val = FALSE;
560
561  return return_val;
562}
563
564/* This is almost identical to gdk_colormap_free_colors.
565 * Keep them in sync!
566 */
567void
568gdk_colors_free (GdkColormap *colormap,
569                 gulong      *in_pixels,
570                 gint         in_npixels,
571                 gulong       planes)
572{
573  GdkColormapPrivate *private;
574  gulong *pixels;
575  gint npixels = 0;
576  gint i;
577
578  g_return_if_fail (colormap != NULL);
579  g_return_if_fail (in_pixels != NULL);
580
581  private = (GdkColormapPrivate*) colormap;
582
583  if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
584      (private->visual->type != GDK_VISUAL_GRAYSCALE))
585    return;
586 
587  pixels = g_new (gulong, in_npixels);
588
589  for (i=0; i<in_npixels; i++)
590    {
591      gulong pixel = in_pixels[i];
592     
593      if (private->info[pixel].ref_count)
594        {
595          private->info[pixel].ref_count--;
596
597          if (private->info[pixel].ref_count == 0)
598            {
599              pixels[npixels++] = pixel;
600              if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
601                g_hash_table_remove (private->hash, &colormap->colors[pixel]);
602              private->info[pixel].flags = 0;
603            }
604        }
605    }
606
607  if (npixels)
608    XFreeColors (private->xdisplay, private->xcolormap,
609                 pixels, npixels, planes);
610  g_free (pixels);
611}
612
613/* This is almost identical to gdk_colors_free.
614 * Keep them in sync!
615 */
616void
617gdk_colormap_free_colors (GdkColormap *colormap,
618                          GdkColor    *colors,
619                          gint         ncolors)
620{
621  GdkColormapPrivate *private;
622  gulong *pixels;
623  gint npixels = 0;
624  gint i;
625
626  g_return_if_fail (colormap != NULL);
627  g_return_if_fail (colors != NULL);
628
629  private = (GdkColormapPrivate*) colormap;
630
631  if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
632      (private->visual->type != GDK_VISUAL_GRAYSCALE))
633    return;
634
635  pixels = g_new (gulong, ncolors);
636
637  for (i=0; i<ncolors; i++)
638    {
639      gulong pixel = colors[i].pixel;
640     
641      if (private->info[pixel].ref_count)
642        {
643          private->info[pixel].ref_count--;
644
645          if (private->info[pixel].ref_count == 0)
646            {
647              pixels[npixels++] = pixel;
648              if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
649                g_hash_table_remove (private->hash, &colormap->colors[pixel]);
650              private->info[pixel].flags = 0;
651            }
652        }
653    }
654
655  if (npixels)
656    XFreeColors (private->xdisplay, private->xcolormap,
657                 pixels, npixels, 0);
658
659  g_free (pixels);
660}
661
662/********************
663 * Color allocation *
664 ********************/
665
666/* Try to allocate a single color using XAllocColor. If it succeeds,
667 * cache the result in our colormap, and store in ret.
668 */
669static gboolean
670gdk_colormap_alloc1 (GdkColormap *colormap,
671                     GdkColor    *color,
672                     GdkColor    *ret)
673{
674  GdkColormapPrivate *private;
675  XColor xcolor;
676
677  private = (GdkColormapPrivate*) colormap;
678
679  xcolor.red = color->red;
680  xcolor.green = color->green;
681  xcolor.blue = color->blue;
682  xcolor.pixel = color->pixel;
683  xcolor.flags = DoRed | DoGreen | DoBlue;
684
685  if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor))
686    {
687      ret->pixel = xcolor.pixel;
688      ret->red = xcolor.red;
689      ret->green = xcolor.green;
690      ret->blue = xcolor.blue;
691     
692      if (ret->pixel < colormap->size)
693        {
694          if (private->info[ret->pixel].ref_count) /* got a duplicate */
695            {
696              XFreeColors (private->xdisplay, private->xcolormap,
697                           &ret->pixel, 1, 0);
698            }
699          else
700            {
701              colormap->colors[ret->pixel] = *color;
702              colormap->colors[ret->pixel].pixel = ret->pixel;
703              private->info[ret->pixel].ref_count = 1;
704
705              g_hash_table_insert (private->hash,
706                                   &colormap->colors[ret->pixel],
707                                   &colormap->colors[ret->pixel]);
708            }
709        }
710      return TRUE;
711    }
712  else
713    {
714      return FALSE;
715    }
716}
717
718static gint
719gdk_colormap_alloc_colors_writeable (GdkColormap *colormap,
720                                     GdkColor    *colors,
721                                     gint         ncolors,
722                                     gboolean     writeable,
723                                     gboolean     best_match,
724                                     gboolean    *success)
725{
726  GdkColormapPrivate *private;
727  gulong *pixels;
728  Status status;
729  gint i, index;
730
731  private = (GdkColormapPrivate*) colormap;
732
733  if (private->private_val)
734    {
735      index = 0;
736      for (i=0; i<ncolors; i++)
737        {
738          while ((index < colormap->size) && (private->info[index].ref_count != 0))
739            index++;
740         
741          if (index < colormap->size)
742            {
743              colors[i].pixel = index;
744              success[i] = TRUE;
745              private->info[index].ref_count++;
746              private->info[i].flags |= GDK_COLOR_WRITEABLE;
747            }
748          else
749            break;
750        }
751      return i;
752    }
753  else
754    {
755      pixels = g_new (gulong, ncolors);
756      /* Allocation of a writeable color cells */
757     
758      status =  XAllocColorCells (private->xdisplay, private->xcolormap,
759                                  FALSE, NULL, 0, pixels, ncolors);
760      if (status)
761        {
762          for (i=0; i<ncolors; i++)
763            {
764              colors[i].pixel = pixels[i];
765              private->info[pixels[i]].ref_count++;
766              private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
767            }
768        }
769     
770      g_free (pixels);
771
772      return status ? ncolors : 0;
773    }
774}
775
776static gint
777gdk_colormap_alloc_colors_private (GdkColormap *colormap,
778                                   GdkColor    *colors,
779                                   gint         ncolors,
780                                   gboolean     writeable,
781                                   gboolean     best_match,
782                                   gboolean    *success)
783{
784  GdkColormapPrivate *private;
785  gint i, index;
786  XColor *store = g_new (XColor, ncolors);
787  gint nstore = 0;
788  gint nremaining = 0;
789 
790  private = (GdkColormapPrivate*) colormap;
791  index = -1;
792
793  /* First, store the colors we have room for */
794
795  index = 0;
796  for (i=0; i<ncolors; i++)
797    {
798      if (!success[i])
799        {
800          while ((index < colormap->size) && (private->info[index].ref_count != 0))
801            index++;
802
803          if (index < colormap->size)
804            {
805              store[nstore].red = colors[i].red;
806              store[nstore].blue = colors[i].blue;
807              store[nstore].green = colors[i].green;
808              store[nstore].pixel = index;
809              nstore++;
810
811              success[i] = TRUE;
812
813              colors[i].pixel = index;
814              private->info[index].ref_count++;
815            }
816          else
817            nremaining++;
818        }
819    }
820 
821  XStoreColors (private->xdisplay, private->xcolormap, store, nstore);
822  g_free (store);
823
824  if (nremaining > 0 && best_match)
825    {
826      /* Get best matches for remaining colors */
827
828      gchar *available = g_new (gchar, colormap->size);
829      for (i = 0; i < colormap->size; i++)
830        available[i] = TRUE;
831
832      for (i=0; i<ncolors; i++)
833        {
834          if (!success[i])
835            {
836              index = gdk_colormap_match_color (colormap,
837                                                &colors[i],
838                                                available);
839              if (index != -1)
840                {
841                  colors[i] = colormap->colors[index];
842                  private->info[index].ref_count++;
843
844                  success[i] = TRUE;
845                  nremaining--;
846                }
847            }
848        }
849      g_free (available);
850    }
851
852  return (ncolors - nremaining);
853}
854
855static gint
856gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
857                                  GdkColor    *colors,
858                                  gint         ncolors,
859                                  gboolean     writeable,
860                                  gboolean     best_match,
861                                  gboolean    *success)
862{
863  GdkColormapPrivate *private;
864  gint i, index;
865  gint nremaining = 0;
866  gint nfailed = 0;
867
868  private = (GdkColormapPrivate*) colormap;
869  index = -1;
870
871  for (i=0; i<ncolors; i++)
872    {
873      if (!success[i])
874        {
875          if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
876            success[i] = TRUE;
877          else
878            nremaining++;
879        }
880    }
881
882
883  if (nremaining > 0 && best_match)
884    {
885      gchar *available = g_new (gchar, colormap->size);
886      for (i = 0; i < colormap->size; i++)
887        available[i] = ((private->info[i].ref_count == 0) ||
888                        !(private->info[i].flags && GDK_COLOR_WRITEABLE));
889      gdk_colormap_sync (colormap, FALSE);
890     
891      while (nremaining > 0)
892        {
893          for (i=0; i<ncolors; i++)
894            {
895              if (!success[i])
896                {
897                  index = gdk_colormap_match_color (colormap, &colors[i], available);
898                  if (index != -1)
899                    {
900                      if (private->info[index].ref_count)
901                        {
902                          private->info[index].ref_count++;
903                          colors[i] = colormap->colors[index];
904                          success[i] = TRUE;
905                          nremaining--;
906                        }
907                      else
908                        {
909                          if (gdk_colormap_alloc1 (colormap,
910                                                   &colormap->colors[index],
911                                                   &colors[i]))
912                            {
913                              success[i] = TRUE;
914                              nremaining--;
915                              break;
916                            }
917                          else
918                            {
919                              available[index] = FALSE;
920                            }
921                        }
922                    }
923                  else
924                    {
925                      nfailed++;
926                      nremaining--;
927                      success[i] = 2; /* flag as permanent failure */
928                    }
929                }
930            }
931        }
932      g_free (available);
933    }
934
935  /* Change back the values we flagged as permanent failures */
936  if (nfailed > 0)
937    {
938      for (i=0; i<ncolors; i++)
939        if (success[i] == 2)
940          success[i] = FALSE;
941      nremaining = nfailed;
942    }
943 
944  return (ncolors - nremaining);
945}
946
947static gint
948gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
949                                       GdkColor    *colors,
950                                       gint         ncolors,
951                                       gboolean     writeable,
952                                       gboolean     best_match,
953                                       gboolean    *success)
954{
955  GdkColormapPrivate *private;
956  GdkColor *lookup_color;
957  gint i;
958  gint nremaining = 0;
959
960  private = (GdkColormapPrivate*) colormap;
961
962  /* Check for an exact match among previously allocated colors */
963
964  for (i=0; i<ncolors; i++)
965    {
966      if (!success[i])
967        {
968          lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
969          if (lookup_color)
970            {
971              private->info[lookup_color->pixel].ref_count++;
972              colors[i].pixel = lookup_color->pixel;
973              success[i] = TRUE;
974            }
975          else
976            nremaining++;
977        }
978    }
979
980  /* If that failed, we try to allocate a new color, or approxmiate
981   * with what we can get if best_match is TRUE.
982   */
983  if (nremaining > 0)
984    {
985      if (private->private_val)
986        return gdk_colormap_alloc_colors_private (colormap, colors, ncolors, writeable, best_match, success);
987      else
988        return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
989    }
990  else
991    return 0;
992}
993
994gint
995gdk_colormap_alloc_colors (GdkColormap *colormap,
996                           GdkColor    *colors,
997                           gint         ncolors,
998                           gboolean     writeable,
999                           gboolean     best_match,
1000                           gboolean    *success)
1001{
1002  GdkColormapPrivate *private;
1003  GdkVisual *visual;
1004  gint i;
1005  gint nremaining = 0;
1006  XColor xcolor;
1007
1008  g_return_val_if_fail (colormap != NULL, FALSE);
1009  g_return_val_if_fail (colors != NULL, FALSE);
1010
1011  private = (GdkColormapPrivate*) colormap;
1012
1013  for (i=0; i<ncolors; i++)
1014    {
1015      success[i] = FALSE;
1016    }
1017
1018  switch (private->visual->type)
1019    {
1020    case GDK_VISUAL_PSEUDO_COLOR:
1021    case GDK_VISUAL_GRAYSCALE:
1022      if (writeable)
1023        return gdk_colormap_alloc_colors_writeable (colormap, colors, ncolors,
1024                                                    writeable, best_match, success);
1025      else
1026        return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
1027                                                    writeable, best_match, success);
1028      break;
1029
1030    case GDK_VISUAL_DIRECT_COLOR:
1031    case GDK_VISUAL_TRUE_COLOR:
1032      visual = private->visual;
1033
1034      for (i=0; i<ncolors; i++)
1035        {
1036          colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
1037                             ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
1038                             ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
1039          success[i] = TRUE;
1040        }
1041      break;
1042
1043    case GDK_VISUAL_STATIC_GRAY:
1044    case GDK_VISUAL_STATIC_COLOR:
1045      for (i=0; i<ncolors; i++)
1046        {
1047          xcolor.red = colors[i].red;
1048          xcolor.green = colors[i].green;
1049          xcolor.blue = colors[i].blue;
1050          xcolor.pixel = colors[i].pixel;
1051          xcolor.flags = DoRed | DoGreen | DoBlue;
1052
1053          if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor))
1054            {
1055              colors[i].pixel = xcolor.pixel;
1056              success[i] = TRUE;
1057            }
1058          else
1059            nremaining++;
1060        }
1061      break;
1062    }
1063  return nremaining;
1064}
1065
1066gboolean
1067gdk_colormap_alloc_color (GdkColormap *colormap,
1068                          GdkColor    *color,
1069                          gboolean     writeable,
1070                          gboolean     best_match)
1071{
1072  gboolean success;
1073
1074  gdk_colormap_alloc_colors (colormap, color, 1, writeable, best_match,
1075                             &success);
1076
1077  return success;
1078}
1079
1080gboolean
1081gdk_color_alloc (GdkColormap *colormap,
1082                 GdkColor    *color)
1083{
1084  gboolean success;
1085
1086  gdk_colormap_alloc_colors (colormap, color, 1, FALSE, TRUE, &success);
1087
1088  return success;
1089}
1090
1091gboolean
1092gdk_color_change (GdkColormap *colormap,
1093                  GdkColor    *color)
1094{
1095  GdkColormapPrivate *private;
1096  XColor xcolor;
1097
1098  g_return_val_if_fail (colormap != NULL, FALSE);
1099  g_return_val_if_fail (color != NULL, FALSE);
1100
1101  xcolor.pixel = color->pixel;
1102  xcolor.red = color->red;
1103  xcolor.green = color->green;
1104  xcolor.blue = color->blue;
1105  xcolor.flags = DoRed | DoGreen | DoBlue;
1106
1107  private = (GdkColormapPrivate*) colormap;
1108  XStoreColor (private->xdisplay, private->xcolormap, &xcolor);
1109
1110  return TRUE;
1111}
1112
1113guint
1114gdk_color_hash (const GdkColor *colora,
1115                const GdkColor *colorb)
1116{
1117  return ((colora->red) +
1118          (colora->green << 11) +
1119          (colora->blue << 22) +
1120          (colora->blue >> 6));
1121}
1122
1123gboolean
1124gdk_color_equal (const GdkColor *colora,
1125                 const GdkColor *colorb)
1126{
1127  g_return_val_if_fail (colora != NULL, FALSE);
1128  g_return_val_if_fail (colorb != NULL, FALSE);
1129
1130  return ((colora->red == colorb->red) &&
1131          (colora->green == colorb->green) &&
1132          (colora->blue == colorb->blue));
1133}
1134
1135/* XXX: Do not use this function until it is fixed. An X Colormap
1136 *      is useless unless we also have the visual.
1137 */
1138GdkColormap*
1139gdkx_colormap_get (Colormap xcolormap)
1140{
1141  GdkColormap *colormap;
1142  GdkColormapPrivate *private;
1143
1144  colormap = gdk_colormap_lookup (xcolormap);
1145  if (colormap)
1146    return colormap;
1147
1148  if (xcolormap == DefaultColormap (gdk_display, gdk_screen))
1149    return gdk_colormap_get_system ();
1150
1151  private = g_new (GdkColormapPrivate, 1);
1152  colormap = (GdkColormap*) private;
1153
1154  private->xdisplay = gdk_display;
1155  private->xcolormap = xcolormap;
1156  private->visual = NULL;
1157  private->private_val = TRUE;
1158
1159  /* To do the following safely, we would have to have some way of finding
1160   * out what the size or visual of the given colormap is. It seems
1161   * X doesn't allow this
1162   */
1163
1164#if 0
1165  for (i = 0; i < 256; i++)
1166    {
1167      xpalette[i].pixel = i;
1168      xpalette[i].red = 0;
1169      xpalette[i].green = 0;
1170      xpalette[i].blue = 0;
1171    }
1172
1173  XQueryColors (gdk_display, private->xcolormap, xpalette, 256);
1174
1175  for (i = 0; i < 256; i++)
1176    {
1177      colormap->colors[i].pixel = xpalette[i].pixel;
1178      colormap->colors[i].red = xpalette[i].red;
1179      colormap->colors[i].green = xpalette[i].green;
1180      colormap->colors[i].blue = xpalette[i].blue;
1181    }
1182#endif
1183
1184  colormap->colors = NULL;
1185  colormap->size = 0;
1186
1187  gdk_colormap_add (colormap);
1188
1189  return colormap;
1190}
1191
1192
1193static gint
1194gdk_colormap_match_color (GdkColormap *cmap,
1195                          GdkColor    *color,
1196                          const gchar *available)
1197{
1198  GdkColor *colors;
1199  guint sum, max;
1200  gint rdiff, gdiff, bdiff;
1201  gint i, index;
1202
1203  g_return_val_if_fail (cmap != NULL, 0);
1204  g_return_val_if_fail (color != NULL, 0);
1205
1206  colors = cmap->colors;
1207  max = 3 * (65536);
1208  index = -1;
1209
1210  for (i = 0; i < cmap->size; i++)
1211    {
1212      if ((!available) || (available && available[i]))
1213        {
1214          rdiff = (color->red - colors[i].red);
1215          gdiff = (color->green - colors[i].green);
1216          bdiff = (color->blue - colors[i].blue);
1217
1218          sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1219
1220          if (sum < max)
1221            {
1222              index = i;
1223              max = sum;
1224            }
1225        }
1226    }
1227
1228  return index;
1229}
1230
1231
1232GdkColormap*
1233gdk_colormap_lookup (Colormap xcolormap)
1234{
1235  GdkColormap *cmap;
1236
1237  if (!colormap_hash)
1238    return NULL;
1239
1240  cmap = g_hash_table_lookup (colormap_hash, &xcolormap);
1241  return cmap;
1242}
1243
1244static void
1245gdk_colormap_add (GdkColormap *cmap)
1246{
1247  GdkColormapPrivate *private;
1248
1249  if (!colormap_hash)
1250    colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
1251                                      (GCompareFunc) gdk_colormap_cmp);
1252
1253  private = (GdkColormapPrivate*) cmap;
1254
1255  g_hash_table_insert (colormap_hash, &private->xcolormap, cmap);
1256}
1257
1258static void
1259gdk_colormap_remove (GdkColormap *cmap)
1260{
1261  GdkColormapPrivate *private;
1262
1263  if (!colormap_hash)
1264    colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
1265                                      (GCompareFunc) gdk_colormap_cmp);
1266
1267  private = (GdkColormapPrivate*) cmap;
1268
1269  g_hash_table_remove (colormap_hash, &private->xcolormap);
1270}
1271
1272static guint
1273gdk_colormap_hash (Colormap *cmap)
1274{
1275  return *cmap;
1276}
1277
1278static gint
1279gdk_colormap_cmp (Colormap *a,
1280                  Colormap *b)
1281{
1282  return (*a == *b);
1283}
Note: See TracBrowser for help on using the repository browser.