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 * 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/.
28 #include <sys/ioctl.h>
33 #include "gdkprivate-fb.h"
35 static gint gdk_colormap_match_color (GdkColormap *cmap,
37 const gchar *available);
39 static gpointer parent_class;
42 gdk_colormap_finalize (GObject *object)
44 GdkColormap *colormap = GDK_COLORMAP(object);
45 GdkColormapPrivateFB *private = (GdkColormapPrivateFB*) colormap;
48 g_hash_table_destroy (private->hash);
50 g_free (private->info);
51 g_free (colormap->colors);
53 G_OBJECT_CLASS(parent_class)->finalize(object);
57 gdk_colormap_init (GdkColormap *colormap)
59 colormap->windowing_data = NULL;
62 colormap->colors = NULL;
66 gdk_colormap_class_init (GdkColormapClass *klass)
68 GObjectClass *object_class = G_OBJECT_CLASS (klass);
70 parent_class = g_type_class_peek_parent (klass);
72 object_class->finalize = gdk_colormap_finalize;
76 gdk_colormap_get_type (void)
78 static GType object_type = 0;
82 static const GTypeInfo object_info =
84 sizeof (GdkColormapFBClass),
86 (GBaseFinalizeFunc) NULL,
87 (GClassInitFunc) gdk_colormap_class_init,
88 NULL, /* class_finalize */
89 NULL, /* class_data */
90 sizeof (GdkColormapPrivateFB),
92 (GInstanceInitFunc) gdk_colormap_init,
95 object_type = g_type_register_static (G_TYPE_OBJECT,
104 gdk_colormap_new (GdkVisual *visual,
107 GdkColormap *colormap;
108 GdkColormapPrivateFB *private;
112 g_return_val_if_fail (visual != NULL, NULL);
114 private = (GdkColormapPrivateFB *)g_type_create_instance(gdk_colormap_get_type());
115 colormap = (GdkColormap*) private;
117 private->base.visual = visual;
120 private->hash = NULL;
122 colormap->size = visual->colormap_size;
123 colormap->colors = NULL;
125 switch (visual->type)
127 case GDK_VISUAL_STATIC_GRAY:
128 case GDK_VISUAL_STATIC_COLOR:
129 case GDK_VISUAL_GRAYSCALE:
130 case GDK_VISUAL_PSEUDO_COLOR:
131 private->info = g_new0 (GdkColorInfo, colormap->size);
132 colormap->colors = g_new (GdkColor, colormap->size);
134 private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
135 (GCompareFunc) gdk_color_equal);
139 guint16 red[256], green[256], blue[256];
140 struct fb_cmap fbc = {0, 256};
146 if(ioctl(fbd->fd, FBIOGETCMAP, &fbc))
147 g_error("ioctl(FBIOGETCMAP) failed");
149 for (i = 0; i < colormap->size; i++)
151 colormap->colors[i].pixel = i;
152 colormap->colors[i].red = red[i];
153 colormap->colors[i].green = green[i];
154 colormap->colors[i].blue = blue[i];
157 gdk_colormap_change (colormap, colormap->size);
161 case GDK_VISUAL_DIRECT_COLOR:
164 colormap->colors = g_new (GdkColor, colormap->size);
166 size = 1 << visual->red_prec;
167 for (i = 0; i < size; i++)
168 colormap->colors[i].red = i * 65535 / (size - 1);
170 size = 1 << visual->green_prec;
171 for (i = 0; i < size; i++)
172 colormap->colors[i].green = i * 65535 / (size - 1);
174 size = 1 << visual->blue_prec;
175 for (i = 0; i < size; i++)
176 colormap->colors[i].blue = i * 65535 / (size - 1);
178 gdk_colormap_change (colormap, colormap->size);
183 g_assert_not_reached();
185 case GDK_VISUAL_TRUE_COLOR:
192 #define MIN_SYNC_TIME 2
195 gdk_colormap_sync (GdkColormap *colormap,
202 gdk_colormap_get_system (void)
204 static GdkColormap *colormap = NULL;
208 guint16 red[256], green[256], blue[256];
209 struct fb_cmap fbc = {0, 256};
211 GdkVisual *visual = gdk_visual_get_system();
213 if(visual->type == GDK_VISUAL_GRAYSCALE
214 || visual->type == GDK_VISUAL_PSEUDO_COLOR)
221 case GDK_VISUAL_GRAYSCALE:
222 for(i = 0; i < 256; i++)
223 red[i] = green[i] = blue[i] = i << 8;
225 red[i] = green[i] = blue[i] = 65535; /* Make it a true white */
227 case GDK_VISUAL_PSEUDO_COLOR:
228 /* Color cube stolen from gdkrgb upon advice from Owen */
229 for(i = r = 0; r < 6; r++)
230 for(g = 0; g < 6; g++)
231 for(b = 0; b < 6; b++)
233 red[i] = r * 65535 / 5;
234 green[i] = g * 65535 / 5;
235 blue[i] = b * 65535 / 5;
240 /* Fill in remaining space with grays */
241 for(i = 216; i < 256; i++)
243 red[i] = green[i] = blue[i] =
247 red[255] = green[255] = blue[255] = 65535;
253 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
256 colormap = gdk_colormap_new(visual, TRUE);
263 gdk_colormap_get_system_size (void)
265 return 1 << (gdk_display->modeinfo.bits_per_pixel);
269 gdk_colormap_change (GdkColormap *colormap,
272 guint16 red[256], green[256], blue[256];
273 struct fb_cmap fbc = {0,256};
274 GdkColormapPrivateFB *private;
277 g_return_if_fail (colormap != NULL);
283 private = (GdkColormapPrivateFB*) colormap;
284 switch (private->base.visual->type)
286 case GDK_VISUAL_GRAYSCALE:
287 for(i = 0; i < ncolors; i++)
289 red[i] = green[i] = blue[i] =
290 (colormap->colors[i].red +
291 colormap->colors[i].green +
292 colormap->colors[i].blue)/3;
294 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
297 case GDK_VISUAL_PSEUDO_COLOR:
298 for (i = 0; i < ncolors; i++)
300 red[i] = colormap->colors[i].red;
301 green[i] = colormap->colors[i].green;
302 blue[i] = colormap->colors[i].blue;
304 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
313 gdk_color_parse (const gchar *spec,
319 g_return_val_if_fail(spec, FALSE);
320 g_return_val_if_fail(color, FALSE);
324 if(strlen(spec) == 7)
328 sscanf(spec + 1, "%x", &num);
329 color->red = (num & 0xFF0000) >> 8;
330 color->green = (num & 0xFF00);
331 color->blue = (num & 0xFF) << 8;
333 else if(strlen(spec) == 13)
335 char s1[5], s2[5], s3[5];
336 g_snprintf(s1, sizeof(s1), spec + 1);
337 g_snprintf(s2, sizeof(s2), spec + 5);
338 g_snprintf(s3, sizeof(s3), spec + 9);
340 if(!sscanf(s1, "%hx", &color->red))
341 g_error("sscanf failed");
342 if(!sscanf(s2, "%hx", &color->green))
343 g_error("sscanf failed");
344 if(!sscanf(s3, "%hx", &color->blue))
345 g_error("sscanf failed");
349 g_warning("Couldn't parse color specifier `%s'", spec);
357 fh = fopen("/usr/lib/X11/rgb.txt", "r");
361 while(fgets(aline, sizeof(aline), fh))
363 int red, green, blue;
367 if(!aline[0] || aline[0] == '#' || aline[0] == '!')
370 ctmp = strtok(aline, " \t");
375 ctmp = strtok(NULL, " \t");
380 ctmp = strtok(NULL, " \t");
385 ctmp = strtok(NULL, " \t");
386 if(!ctmp || strcmp(ctmp, spec))
389 color->red = red << 8;
390 color->green = green << 8;
391 color->blue = blue << 8;
401 gdk_colormap_free_colors (GdkColormap *colormap,
405 GdkColormapPrivateFB *private;
408 g_return_if_fail (colormap != NULL);
409 g_return_if_fail (colors != NULL);
411 private = (GdkColormapPrivateFB*) colormap;
413 if ((private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
414 (private->base.visual->type != GDK_VISUAL_GRAYSCALE))
417 for (i=0; i<ncolors; i++)
419 gulong pixel = colors[i].pixel;
421 if (private->info[pixel].ref_count)
423 private->info[pixel].ref_count--;
425 if (private->info[pixel].ref_count == 0)
427 if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
428 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
429 private->info[pixel].flags = 0;
435 /********************
437 ********************/
439 /* Try to allocate a single color using XAllocColor. If it succeeds,
440 * cache the result in our colormap, and store in ret.
443 gdk_colormap_alloc1 (GdkColormap *colormap,
447 GdkColormapPrivateFB *private;
450 private = (GdkColormapPrivateFB*) colormap;
452 if(private->base.visual->type != GDK_VISUAL_GRAYSCALE
453 && private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR)
457 if(!color->red && !color->green && !color->blue) /* black */
460 private->info[ret->pixel].ref_count++;
464 if(color->red == 65535 && color->green == 65535 && color->blue == 65535) /* white */
467 private->info[ret->pixel].ref_count++;
471 for(i = 1; i < (colormap->size - 1); i++)
473 if(!private->info[i].ref_count)
475 guint16 red = color->red, green = color->green, blue = color->blue;
483 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
486 colormap->colors[ret->pixel] = *ret;
487 private->info[ret->pixel].ref_count = 1;
488 g_hash_table_insert (private->hash,
489 &colormap->colors[ret->pixel],
490 &colormap->colors[ret->pixel]);
499 gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
506 GdkColormapPrivateFB *private;
511 private = (GdkColormapPrivateFB*) colormap;
514 for (i=0; i<ncolors; i++)
518 if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
526 if (nremaining > 0 && best_match)
528 gchar *available = g_new (gchar, colormap->size);
530 for (i = 0; i < colormap->size; i++)
531 available[i] = ((private->info[i].ref_count == 0) ||
532 !(private->info[i].flags && GDK_COLOR_WRITEABLE));
534 while (nremaining > 0)
536 for (i=0; i<ncolors; i++)
540 index = gdk_colormap_match_color (colormap, &colors[i], available);
543 if (private->info[index].ref_count)
545 private->info[index].ref_count++;
546 colors[i] = colormap->colors[index];
552 if (gdk_colormap_alloc1 (colormap,
553 &colormap->colors[index],
562 available[index] = FALSE;
570 success[i] = 2; /* flag as permanent failure */
578 /* Change back the values we flagged as permanent failures */
581 for (i=0; i<ncolors; i++)
584 nremaining = nfailed;
587 return (ncolors - nremaining);
591 gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
598 GdkColormapPrivateFB *private;
599 GdkColor *lookup_color;
603 private = (GdkColormapPrivateFB*) colormap;
605 /* Check for an exact match among previously allocated colors */
607 for (i=0; i<ncolors; i++)
611 lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
614 private->info[lookup_color->pixel].ref_count++;
615 colors[i].pixel = lookup_color->pixel;
623 /* If that failed, we try to allocate a new color, or approxmiate
624 * with what we can get if best_match is TRUE.
627 return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
633 gdk_colormap_alloc_colors (GdkColormap *colormap,
640 GdkColormapPrivateFB *private;
645 g_return_val_if_fail (colormap != NULL, FALSE);
646 g_return_val_if_fail (colors != NULL, FALSE);
648 private = (GdkColormapPrivateFB*) colormap;
650 for (i=0; i<ncolors; i++)
653 switch (private->base.visual->type)
655 case GDK_VISUAL_PSEUDO_COLOR:
656 case GDK_VISUAL_GRAYSCALE:
657 case GDK_VISUAL_STATIC_GRAY:
658 case GDK_VISUAL_STATIC_COLOR:
659 return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
660 writeable, best_match, success);
663 case GDK_VISUAL_DIRECT_COLOR:
664 case GDK_VISUAL_TRUE_COLOR:
665 visual = private->base.visual;
667 for (i=0; i<ncolors; i++)
669 colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
670 ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
671 ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
680 gdk_color_change (GdkColormap *colormap,
683 GdkColormapPrivateFB *private;
684 struct fb_cmap fbc = {0, 1};
686 g_return_val_if_fail (colormap != NULL, FALSE);
687 g_return_val_if_fail (color != NULL, FALSE);
689 private = (GdkColormapPrivateFB*) colormap;
691 switch(private->base.visual->type)
693 case GDK_VISUAL_GRAYSCALE:
694 color->red = color->green = color->blue = (color->red + color->green + color->blue)/3;
696 case GDK_VISUAL_PSEUDO_COLOR:
697 fbc.start = color->pixel;
698 fbc.red = &color->red;
699 fbc.green = &color->green;
700 fbc.blue = &color->blue;
701 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
712 gdk_colormap_match_color (GdkColormap *cmap,
714 const gchar *available)
718 gint rdiff, gdiff, bdiff;
721 g_return_val_if_fail (cmap != NULL, 0);
722 g_return_val_if_fail (color != NULL, 0);
724 colors = cmap->colors;
728 for (i = 0; i < cmap->size; i++)
730 if ((!available) || (available && available[i]))
732 rdiff = (color->red - colors[i].red);
733 gdiff = (color->green - colors[i].green);
734 bdiff = (color->blue - colors[i].blue);
736 sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
749 gint gdk_colors_alloc (GdkColormap *colormap,
760 gdk_colors_free (GdkColormap *colormap,
768 gdk_color_context_get_pixel(GdkColorContext *cc,
780 gdk_color_context_new(GdkVisual *visual,
781 GdkColormap *colormap)
789 gdk_color_context_new_mono(GdkVisual *visual,
790 GdkColormap *colormap)
798 gdk_color_context_free(GdkColorContext *cc)
804 gdk_color_context_query_color(GdkColorContext *cc,