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 Lesser 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 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser 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-2000. 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 #define GDK_COLORMAP_PRIVATE_DATA(cmap) ((GdkColormapPrivateFB *) GDK_COLORMAP (cmap)->windowing_data)
37 static gint gdk_colormap_match_color (GdkColormap *cmap,
39 const gchar *available);
40 static void gdk_fb_color_round_to_hw (GdkColor *color);
42 static gpointer parent_class;
45 gdk_colormap_finalize (GObject *object)
47 GdkColormap *colormap = GDK_COLORMAP (object);
48 GdkColormapPrivateFB *private = GDK_COLORMAP_PRIVATE_DATA (colormap);
51 g_hash_table_destroy (private->hash);
53 g_free (private->info);
54 g_free (colormap->colors);
57 G_OBJECT_CLASS (parent_class)->finalize (object);
61 gdk_colormap_init (GdkColormap *colormap)
63 GdkColormapPrivateFB *private;
65 private = g_new (GdkColormapPrivateFB, 1);
67 colormap->windowing_data = private;
70 colormap->colors = NULL;
74 gdk_colormap_class_init (GdkColormapClass *klass)
76 GObjectClass *object_class = G_OBJECT_CLASS (klass);
78 parent_class = g_type_class_peek_parent (klass);
80 object_class->finalize = gdk_colormap_finalize;
84 gdk_colormap_get_type (void)
86 static GType object_type = 0;
90 static const GTypeInfo object_info =
92 sizeof (GdkColormapClass),
94 (GBaseFinalizeFunc) NULL,
95 (GClassInitFunc) gdk_colormap_class_init,
96 NULL, /* class_finalize */
97 NULL, /* class_data */
100 (GInstanceInitFunc) gdk_colormap_init,
103 object_type = g_type_register_static (G_TYPE_OBJECT,
113 gdk_colormap_new (GdkVisual *visual,
116 GdkColormap *colormap;
118 GdkColormapPrivateFB *private;
122 g_return_val_if_fail (visual != NULL, NULL);
124 colormap = g_object_new (gdk_colormap_get_type (), NULL);
125 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
127 colormap->visual = visual;
130 private->hash = NULL;
132 colormap->size = visual->colormap_size;
133 colormap->colors = NULL;
135 switch (visual->type)
137 case GDK_VISUAL_STATIC_GRAY:
138 case GDK_VISUAL_STATIC_COLOR:
139 case GDK_VISUAL_GRAYSCALE:
140 case GDK_VISUAL_PSEUDO_COLOR:
141 private->info = g_new0 (GdkColorInfo, colormap->size);
142 colormap->colors = g_new (GdkColor, colormap->size);
144 private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
145 (GEqualFunc) gdk_color_equal);
147 system = gdk_colormap_get_system ();
148 memcpy (colormap->colors, system->colors, colormap->size * sizeof (GdkColor));
152 guint16 red[256], green[256], blue[256];
153 struct fb_cmap fbc = {0, 256};
159 if (ioctl (fbd->fb_fd, FBIOGETCMAP, &fbc))
160 g_error("ioctl(FBIOGETCMAP) failed");
162 for (i = 0; i < colormap->size; i++)
164 colormap->colors[i].pixel = i;
165 colormap->colors[i].red = red[i];
166 colormap->colors[i].green = green[i];
167 colormap->colors[i].blue = blue[i];
170 gdk_colormap_change (colormap, colormap->size);
174 case GDK_VISUAL_DIRECT_COLOR:
175 g_warning ("gdk_colormap_new () on a direct color visual not implemented");
177 colormap->colors = g_new (GdkColor, colormap->size);
179 size = 1 << visual->red_prec;
180 for (i = 0; i < size; i++)
181 colormap->colors[i].red = i * 65535 / (size - 1);
183 size = 1 << visual->green_prec;
184 for (i = 0; i < size; i++)
185 colormap->colors[i].green = i * 65535 / (size - 1);
187 size = 1 << visual->blue_prec;
188 for (i = 0; i < size; i++)
189 colormap->colors[i].blue = i * 65535 / (size - 1);
191 gdk_colormap_change (colormap, colormap->size);
196 g_assert_not_reached ();
198 case GDK_VISUAL_TRUE_COLOR:
206 gdk_screen_get_system_colormap (GdkScreen *screen)
208 static GdkColormap *colormap = NULL;
212 GdkColormapPrivateFB *private;
213 GdkVisual *visual = gdk_visual_get_system ();
216 colormap = g_object_new (gdk_colormap_get_type (), NULL);
217 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
219 colormap->visual = visual;
220 private->hash = NULL;
222 colormap->size = visual->colormap_size;
223 colormap->colors = NULL;
225 switch (visual->type)
227 case GDK_VISUAL_STATIC_GRAY:
228 case GDK_VISUAL_STATIC_COLOR:
229 case GDK_VISUAL_GRAYSCALE:
230 case GDK_VISUAL_PSEUDO_COLOR:
231 private->info = g_new0 (GdkColorInfo, colormap->size);
232 colormap->colors = g_new (GdkColor, colormap->size);
234 private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
235 (GEqualFunc) gdk_color_equal);
238 case GDK_VISUAL_GRAYSCALE:
239 for(i = 0; i < 256; i++) {
240 colormap->colors[i].red =
241 colormap->colors[i].green =
242 colormap->colors[i].blue = i << 8;
243 gdk_fb_color_round_to_hw (&colormap->colors[i]);
246 colormap->colors[i].red =
247 colormap->colors[i].green =
248 colormap->colors[i].blue = 65535; /* Make it a true white */
249 gdk_fb_color_round_to_hw (&colormap->colors[i]);
251 case GDK_VISUAL_PSEUDO_COLOR:
252 /* Color cube stolen from gdkrgb upon advice from Owen */
253 for(i = r = 0; r < 6; r++)
254 for(g = 0; g < 6; g++)
255 for(b = 0; b < 6; b++)
257 colormap->colors[i].red = r * 65535 / 5;
258 colormap->colors[i].green = g * 65535 / 5;
259 colormap->colors[i].blue = b * 65535 / 5;
260 gdk_fb_color_round_to_hw (&colormap->colors[i]);
264 /* Fill in remaining space with grays */
265 for(i = 216; i < 256; i++)
267 colormap->colors[i].red =
268 colormap->colors[i].green =
269 colormap->colors[i].blue = (i - 216) * 40;
270 gdk_fb_color_round_to_hw (&colormap->colors[i]);
273 colormap->colors[255].red =
274 colormap->colors[255].green =
275 colormap->colors[255].blue = 65535;
276 gdk_fb_color_round_to_hw (&colormap->colors[255]);
283 case GDK_VISUAL_DIRECT_COLOR:
284 g_warning ("gdk_colormap_get_system() on a direct color visual is not implemented");
287 g_assert_not_reached ();
288 case GDK_VISUAL_TRUE_COLOR:
292 /* Lock all colors for the system colormap
293 * on pseudocolor visuals. The AA text rendering
294 * takes to many colors otherwise.
296 if ((visual->type == GDK_VISUAL_GRAYSCALE) ||
297 (visual->type == GDK_VISUAL_PSEUDO_COLOR))
299 for(i = 0; i < 256; i++)
301 colormap->colors[i].pixel = i;
302 private->info[i].ref_count = 1;
303 g_hash_table_insert (private->hash,
304 &colormap->colors[i],
305 &colormap->colors[i]);
308 gdk_colormap_change (colormap, colormap->size);
315 gdk_colormap_get_system_size (void)
317 return 1 << (gdk_display->modeinfo.bits_per_pixel);
321 gdk_colormap_change (GdkColormap *colormap,
324 guint16 red[256], green[256], blue[256];
325 struct fb_cmap fbc = {0,256};
326 GdkColormapPrivateFB *private;
329 g_return_if_fail (colormap != NULL);
335 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
336 switch (colormap->visual->type)
338 case GDK_VISUAL_GRAYSCALE:
339 for(i = 0; i < ncolors; i++)
341 red[i] = green[i] = blue[i] =
342 (colormap->colors[i].red +
343 colormap->colors[i].green +
344 colormap->colors[i].blue)/3;
346 ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
349 case GDK_VISUAL_PSEUDO_COLOR:
350 for (i = 0; i < ncolors; i++)
352 red[i] = colormap->colors[i].red;
353 green[i] = colormap->colors[i].green;
354 blue[i] = colormap->colors[i].blue;
356 ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
365 gdk_colormap_free_colors (GdkColormap *colormap,
369 GdkColormapPrivateFB *private;
372 g_return_if_fail (colormap != NULL);
373 g_return_if_fail (colors != NULL);
375 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
377 if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
378 (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
381 for (i = 0; i < ncolors; i++)
383 gulong pixel = colors[i].pixel;
385 if (private->info[pixel].ref_count)
387 private->info[pixel].ref_count--;
389 if (private->info[pixel].ref_count == 0)
391 if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
392 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
393 private->info[pixel].flags = 0;
399 /********************
401 ********************/
404 gdk_fb_color_round_to_hw (GdkColor *color)
406 guint rmask, gmask, bmask, len;
408 len = gdk_display->modeinfo.red.length;
409 rmask = ((1 << len) - 1) << (16-len);
410 len = gdk_display->modeinfo.green.length;
411 gmask = ((1 << len) - 1) << (16-len);
412 len = gdk_display->modeinfo.blue.length;
413 bmask = ((1 << len) - 1) << (16-len);
416 color->green &=gmask;
420 /* Try to allocate a single color using XAllocColor. If it succeeds,
421 * cache the result in our colormap, and store in ret.
424 gdk_colormap_alloc1 (GdkColormap *colormap,
428 GdkColormapPrivateFB *private;
431 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
433 if (colormap->visual->type != GDK_VISUAL_GRAYSCALE
434 && colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR)
439 gdk_fb_color_round_to_hw (ret);
441 for (i = 0; i<colormap->size; i++)
443 if (!(private->info[i].flags & GDK_COLOR_WRITEABLE) &&
444 (ret->red == colormap->colors[i].red) &&
445 (ret->green == colormap->colors[i].green) &&
446 (ret->blue == colormap->colors[i].blue))
449 colormap->colors[i].pixel = i;
450 if (private->info[i].ref_count == 0)
451 g_hash_table_insert (private->hash,
452 &colormap->colors[ret->pixel],
453 &colormap->colors[ret->pixel]);
454 private->info[i].ref_count++;
459 for (i = 0; i<colormap->size; i++)
461 if (private->info[i].ref_count==0)
463 guint16 red = color->red, green = color->green, blue = color->blue;
472 ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
475 colormap->colors[ret->pixel] = *ret;
476 private->info[ret->pixel].ref_count = 1;
477 g_hash_table_insert (private->hash,
478 &colormap->colors[ret->pixel],
479 &colormap->colors[ret->pixel]);
488 gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
495 GdkColormapPrivateFB *private;
500 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
503 for (i = 0; i < ncolors; i++)
507 if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
515 if (nremaining > 0 && best_match)
517 gchar *available = g_new (gchar, colormap->size);
519 for (i = 0; i < colormap->size; i++)
520 available[i] = ((private->info[i].ref_count == 0) ||
521 !(private->info[i].flags & GDK_COLOR_WRITEABLE));
523 while (nremaining > 0)
525 for (i = 0; i < ncolors; i++)
529 index = gdk_colormap_match_color (colormap, &colors[i], available);
532 if (private->info[index].ref_count)
534 private->info[index].ref_count++;
535 colors[i] = colormap->colors[index];
541 if (gdk_colormap_alloc1 (colormap,
542 &colormap->colors[index],
551 available[index] = FALSE;
559 success[i] = 2; /* flag as permanent failure */
567 /* Change back the values we flagged as permanent failures */
570 for (i = 0; i < ncolors; i++)
573 nremaining = nfailed;
576 return (ncolors - nremaining);
580 gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
587 GdkColormapPrivateFB *private;
588 GdkColor *lookup_color;
592 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
594 /* Check for an exact match among previously allocated colors */
596 for (i = 0; i < ncolors; i++)
600 lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
603 private->info[lookup_color->pixel].ref_count++;
604 colors[i].pixel = lookup_color->pixel;
612 /* If that failed, we try to allocate a new color, or approxmiate
613 * with what we can get if best_match is TRUE.
616 return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
622 gdk_colormap_alloc_colors (GdkColormap *colormap,
629 GdkColormapPrivateFB *private;
634 g_return_val_if_fail (colormap != NULL, FALSE);
635 g_return_val_if_fail (colors != NULL, FALSE);
637 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
639 for (i = 0; i < ncolors; i++)
642 visual = colormap->visual;
643 switch (visual->type)
645 case GDK_VISUAL_PSEUDO_COLOR:
646 case GDK_VISUAL_GRAYSCALE:
647 case GDK_VISUAL_STATIC_GRAY:
648 case GDK_VISUAL_STATIC_COLOR:
649 return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
650 writeable, best_match, success);
653 case GDK_VISUAL_DIRECT_COLOR:
654 case GDK_VISUAL_TRUE_COLOR:
655 for (i = 0; i < ncolors; i++)
657 colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
658 ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
659 ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
668 gdk_color_change (GdkColormap *colormap,
671 GdkColormapPrivateFB *private;
672 struct fb_cmap fbc = {0, 1};
674 g_return_val_if_fail (colormap != NULL, FALSE);
675 g_return_val_if_fail (color != NULL, FALSE);
677 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
679 switch(colormap->visual->type)
681 case GDK_VISUAL_GRAYSCALE:
682 color->red = color->green = color->blue = (color->red + color->green + color->blue)/3;
685 case GDK_VISUAL_PSEUDO_COLOR:
686 colormap->colors[color->pixel] = *color;
688 fbc.start = color->pixel;
689 fbc.red = &color->red;
690 fbc.green = &color->green;
691 fbc.blue = &color->blue;
692 ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
703 gdk_colormap_match_color (GdkColormap *cmap,
705 const gchar *available)
709 gint rdiff, gdiff, bdiff;
712 g_return_val_if_fail (cmap != NULL, 0);
713 g_return_val_if_fail (color != NULL, 0);
715 colors = cmap->colors;
719 for (i = 0; i < cmap->size; i++)
721 if ((!available) || (available && available[i]))
723 rdiff = (color->red - colors[i].red);
724 gdiff = (color->green - colors[i].green);
725 bdiff = (color->blue - colors[i].blue);
727 sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
741 gdk_colors_alloc (GdkColormap *colormap,
748 GdkColormapPrivateFB *private;
751 g_return_val_if_fail (colormap != NULL, FALSE);
753 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
759 for (i = 1; i < colormap->size; i++)
761 if (private->info[i].ref_count == 0)
764 if (found >= npixels)
773 for (i = 1; i < colormap->size; i++)
775 if (private->info[i].ref_count == 0)
778 private->info[i].ref_count++;
779 private->info[i].flags |= GDK_COLOR_WRITEABLE;
785 g_assert_not_reached ();
790 gdk_colors_free (GdkColormap *colormap,
795 GdkColormapPrivateFB *private;
798 g_return_if_fail (colormap != NULL);
800 if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
801 (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
804 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
806 for (i = 0; i < npixels; i++)
810 if (private->info[pixel].ref_count)
812 private->info[pixel].ref_count--;
814 if (private->info[pixel].ref_count == 0)
816 if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
817 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
818 private->info[pixel].flags = 0;
826 gdk_colormap_query_color (GdkColormap *colormap,
832 g_return_if_fail (GDK_IS_COLORMAP (colormap));
834 visual = gdk_colormap_get_visual (colormap);
836 switch (visual->type)
838 case GDK_VISUAL_DIRECT_COLOR:
839 case GDK_VISUAL_TRUE_COLOR:
840 result->red = 65535. * (gdouble) ((pixel & visual->red_mask) >> visual->red_shift) / ((1 << visual->red_prec) - 1);
841 result->green = 65535. * (gdouble) ((pixel & visual->green_mask) >> visual->green_shift) / ((1 << visual->green_prec) - 1);
842 result->blue = 65535. * (gdouble) ((pixel & visual->blue_mask) >> visual->blue_shift) / ((1 << visual->blue_prec) - 1);
844 case GDK_VISUAL_STATIC_GRAY:
845 case GDK_VISUAL_GRAYSCALE:
846 result->red = result->green = result->blue = 65535. * (double)pixel/((1<<visual->depth) - 1);
848 case GDK_VISUAL_PSEUDO_COLOR:
849 result->red = colormap->colors[pixel].red;
850 result->green = colormap->colors[pixel].green;
851 result->blue = colormap->colors[pixel].blue;
854 g_assert_not_reached ();
860 gdk_colormap_get_screen (GdkColormap *cmap)
862 g_return_val_if_fail (cmap != NULL, NULL);
864 return gdk_screen_get_default ();