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 gdk_colormap_new (GdkVisual *visual,
42 GdkColormap *colormap;
43 GdkColormapPrivateFB *private;
47 g_return_val_if_fail (visual != NULL, NULL);
49 private = g_new (GdkColormapPrivateFB, 1);
50 colormap = (GdkColormap*) private;
52 private->base.visual = visual;
53 private->base.ref_count = 1;
58 colormap->size = visual->colormap_size;
59 colormap->colors = NULL;
63 case GDK_VISUAL_STATIC_GRAY:
64 case GDK_VISUAL_STATIC_COLOR:
65 case GDK_VISUAL_GRAYSCALE:
66 case GDK_VISUAL_PSEUDO_COLOR:
67 private->info = g_new0 (GdkColorInfo, colormap->size);
68 colormap->colors = g_new (GdkColor, colormap->size);
70 private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
71 (GCompareFunc) gdk_color_equal);
75 guint16 red[256], green[256], blue[256];
76 struct fb_cmap fbc = {0, 256};
82 if(ioctl(fbd->fd, FBIOGETCMAP, &fbc))
83 g_error("ioctl(FBIOGETCMAP) failed");
85 for (i = 0; i < colormap->size; i++)
87 colormap->colors[i].pixel = i;
88 colormap->colors[i].red = red[i];
89 colormap->colors[i].green = green[i];
90 colormap->colors[i].blue = blue[i];
93 gdk_colormap_change (colormap, colormap->size);
97 case GDK_VISUAL_DIRECT_COLOR:
100 colormap->colors = g_new (GdkColor, colormap->size);
102 size = 1 << visual->red_prec;
103 for (i = 0; i < size; i++)
104 colormap->colors[i].red = i * 65535 / (size - 1);
106 size = 1 << visual->green_prec;
107 for (i = 0; i < size; i++)
108 colormap->colors[i].green = i * 65535 / (size - 1);
110 size = 1 << visual->blue_prec;
111 for (i = 0; i < size; i++)
112 colormap->colors[i].blue = i * 65535 / (size - 1);
114 gdk_colormap_change (colormap, colormap->size);
119 g_assert_not_reached();
121 case GDK_VISUAL_TRUE_COLOR:
129 _gdk_colormap_real_destroy (GdkColormap *colormap)
131 GdkColormapPrivateFB *private = (GdkColormapPrivateFB*) colormap;
134 g_hash_table_destroy (private->hash);
136 g_free (private->info);
137 g_free (colormap->colors);
141 #define MIN_SYNC_TIME 2
144 gdk_colormap_sync (GdkColormap *colormap,
151 gdk_colormap_get_system (void)
153 static GdkColormap *colormap = NULL;
157 guint16 red[256], green[256], blue[256];
158 struct fb_cmap fbc = {0, 256};
160 GdkVisual *visual = gdk_visual_get_system();
162 if(visual->type == GDK_VISUAL_GRAYSCALE
163 || visual->type == GDK_VISUAL_PSEUDO_COLOR)
170 case GDK_VISUAL_GRAYSCALE:
171 for(i = 0; i < 256; i++)
172 red[i] = green[i] = blue[i] = i << 8;
174 red[i] = green[i] = blue[i] = 65535; /* Make it a true white */
176 case GDK_VISUAL_PSEUDO_COLOR:
177 /* Color cube stolen from gdkrgb upon advice from Owen */
178 for(i = r = 0; r < 6; r++)
179 for(g = 0; g < 6; g++)
180 for(b = 0; b < 6; b++)
182 red[i] = r * 65535 / 5;
183 green[i] = g * 65535 / 5;
184 blue[i] = b * 65535 / 5;
189 /* Fill in remaining space with grays */
190 for(i = 216; i < 256; i++)
192 red[i] = green[i] = blue[i] =
196 red[255] = green[255] = blue[255] = 65535;
202 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
205 colormap = gdk_colormap_new(visual, TRUE);
212 gdk_colormap_get_system_size (void)
214 return 1 << (gdk_display->modeinfo.bits_per_pixel);
218 gdk_colormap_change (GdkColormap *colormap,
221 guint16 red[256], green[256], blue[256];
222 struct fb_cmap fbc = {0,256};
223 GdkColormapPrivateFB *private;
226 g_return_if_fail (colormap != NULL);
232 private = (GdkColormapPrivateFB*) colormap;
233 switch (private->base.visual->type)
235 case GDK_VISUAL_GRAYSCALE:
236 for(i = 0; i < ncolors; i++)
238 red[i] = green[i] = blue[i] =
239 (colormap->colors[i].red +
240 colormap->colors[i].green +
241 colormap->colors[i].blue)/3;
243 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
246 case GDK_VISUAL_PSEUDO_COLOR:
247 for (i = 0; i < ncolors; i++)
249 red[i] = colormap->colors[i].red;
250 green[i] = colormap->colors[i].green;
251 blue[i] = colormap->colors[i].blue;
253 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
262 gdk_color_parse (const gchar *spec,
268 g_return_val_if_fail(spec, FALSE);
269 g_return_val_if_fail(color, FALSE);
273 if(strlen(spec) == 7)
277 sscanf(spec + 1, "%x", &num);
278 color->red = (num & 0xFF0000) >> 8;
279 color->green = (num & 0xFF00);
280 color->blue = (num & 0xFF) << 8;
282 else if(strlen(spec) == 13)
284 char s1[5], s2[5], s3[5];
285 g_snprintf(s1, sizeof(s1), spec + 1);
286 g_snprintf(s2, sizeof(s2), spec + 5);
287 g_snprintf(s3, sizeof(s3), spec + 9);
289 if(!sscanf(s1, "%hx", &color->red))
290 g_error("sscanf failed");
291 if(!sscanf(s2, "%hx", &color->green))
292 g_error("sscanf failed");
293 if(!sscanf(s3, "%hx", &color->blue))
294 g_error("sscanf failed");
298 g_warning("Couldn't parse color specifier `%s'", spec);
306 fh = fopen("/usr/lib/X11/rgb.txt", "r");
310 while(fgets(aline, sizeof(aline), fh))
312 int red, green, blue;
316 if(!aline[0] || aline[0] == '#' || aline[0] == '!')
319 ctmp = strtok(aline, " \t");
324 ctmp = strtok(NULL, " \t");
329 ctmp = strtok(NULL, " \t");
334 ctmp = strtok(NULL, " \t");
335 if(!ctmp || strcmp(ctmp, spec))
338 color->red = red << 8;
339 color->green = green << 8;
340 color->blue = blue << 8;
350 gdk_colormap_free_colors (GdkColormap *colormap,
354 GdkColormapPrivateFB *private;
357 g_return_if_fail (colormap != NULL);
358 g_return_if_fail (colors != NULL);
360 private = (GdkColormapPrivateFB*) colormap;
362 if ((private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
363 (private->base.visual->type != GDK_VISUAL_GRAYSCALE))
366 for (i=0; i<ncolors; i++)
368 gulong pixel = colors[i].pixel;
370 if (private->info[pixel].ref_count)
372 private->info[pixel].ref_count--;
374 if (private->info[pixel].ref_count == 0)
376 if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
377 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
378 private->info[pixel].flags = 0;
384 /********************
386 ********************/
388 /* Try to allocate a single color using XAllocColor. If it succeeds,
389 * cache the result in our colormap, and store in ret.
392 gdk_colormap_alloc1 (GdkColormap *colormap,
396 GdkColormapPrivateFB *private;
399 private = (GdkColormapPrivateFB*) colormap;
401 if(private->base.visual->type != GDK_VISUAL_GRAYSCALE
402 && private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR)
406 if(!color->red && !color->green && !color->blue) /* black */
409 private->info[ret->pixel].ref_count++;
413 if(color->red == 65535 && color->green == 65535 && color->blue == 65535) /* white */
416 private->info[ret->pixel].ref_count++;
420 for(i = 1; i < (colormap->size - 1); i++)
422 if(!private->info[i].ref_count)
424 guint16 red = color->red, green = color->green, blue = color->blue;
432 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
435 colormap->colors[ret->pixel] = *ret;
436 private->info[ret->pixel].ref_count = 1;
437 g_hash_table_insert (private->hash,
438 &colormap->colors[ret->pixel],
439 &colormap->colors[ret->pixel]);
448 gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
455 GdkColormapPrivateFB *private;
460 private = (GdkColormapPrivateFB*) colormap;
463 for (i=0; i<ncolors; i++)
467 if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
475 if (nremaining > 0 && best_match)
477 gchar *available = g_new (gchar, colormap->size);
479 for (i = 0; i < colormap->size; i++)
480 available[i] = ((private->info[i].ref_count == 0) ||
481 !(private->info[i].flags && GDK_COLOR_WRITEABLE));
483 while (nremaining > 0)
485 for (i=0; i<ncolors; i++)
489 index = gdk_colormap_match_color (colormap, &colors[i], available);
492 if (private->info[index].ref_count)
494 private->info[index].ref_count++;
495 colors[i] = colormap->colors[index];
501 if (gdk_colormap_alloc1 (colormap,
502 &colormap->colors[index],
511 available[index] = FALSE;
519 success[i] = 2; /* flag as permanent failure */
527 /* Change back the values we flagged as permanent failures */
530 for (i=0; i<ncolors; i++)
533 nremaining = nfailed;
536 return (ncolors - nremaining);
540 gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
547 GdkColormapPrivateFB *private;
548 GdkColor *lookup_color;
552 private = (GdkColormapPrivateFB*) colormap;
554 /* Check for an exact match among previously allocated colors */
556 for (i=0; i<ncolors; i++)
560 lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
563 private->info[lookup_color->pixel].ref_count++;
564 colors[i].pixel = lookup_color->pixel;
572 /* If that failed, we try to allocate a new color, or approxmiate
573 * with what we can get if best_match is TRUE.
576 return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
582 gdk_colormap_alloc_colors (GdkColormap *colormap,
589 GdkColormapPrivateFB *private;
594 g_return_val_if_fail (colormap != NULL, FALSE);
595 g_return_val_if_fail (colors != NULL, FALSE);
597 private = (GdkColormapPrivateFB*) colormap;
599 for (i=0; i<ncolors; i++)
602 switch (private->base.visual->type)
604 case GDK_VISUAL_PSEUDO_COLOR:
605 case GDK_VISUAL_GRAYSCALE:
606 case GDK_VISUAL_STATIC_GRAY:
607 case GDK_VISUAL_STATIC_COLOR:
608 return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
609 writeable, best_match, success);
612 case GDK_VISUAL_DIRECT_COLOR:
613 case GDK_VISUAL_TRUE_COLOR:
614 visual = private->base.visual;
616 for (i=0; i<ncolors; i++)
618 colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
619 ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
620 ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
629 gdk_color_change (GdkColormap *colormap,
632 GdkColormapPrivateFB *private;
633 struct fb_cmap fbc = {0, 1};
635 g_return_val_if_fail (colormap != NULL, FALSE);
636 g_return_val_if_fail (color != NULL, FALSE);
638 private = (GdkColormapPrivateFB*) colormap;
640 switch(private->base.visual->type)
642 case GDK_VISUAL_GRAYSCALE:
643 color->red = color->green = color->blue = (color->red + color->green + color->blue)/3;
645 case GDK_VISUAL_PSEUDO_COLOR:
646 fbc.start = color->pixel;
647 fbc.red = &color->red;
648 fbc.green = &color->green;
649 fbc.blue = &color->blue;
650 ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
661 gdk_colormap_match_color (GdkColormap *cmap,
663 const gchar *available)
667 gint rdiff, gdiff, bdiff;
670 g_return_val_if_fail (cmap != NULL, 0);
671 g_return_val_if_fail (color != NULL, 0);
673 colors = cmap->colors;
677 for (i = 0; i < cmap->size; i++)
679 if ((!available) || (available && available[i]))
681 rdiff = (color->red - colors[i].red);
682 gdiff = (color->green - colors[i].green);
683 bdiff = (color->blue - colors[i].blue);
685 sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
698 gint gdk_colors_alloc (GdkColormap *colormap,
709 gdk_colors_free (GdkColormap *colormap,
717 gdk_color_context_get_pixel(GdkColorContext *cc,
729 gdk_color_context_new(GdkVisual *visual,
730 GdkColormap *colormap)
738 gdk_color_context_new_mono(GdkVisual *visual,
739 GdkColormap *colormap)
747 gdk_color_context_free(GdkColorContext *cc)
753 gdk_color_context_query_color(GdkColorContext *cc,