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);
56 G_OBJECT_CLASS (parent_class)->finalize (object);
60 gdk_colormap_init (GdkColormap *colormap)
62 GdkColormapPrivateFB *private;
64 private = g_new (GdkColormapPrivateFB, 1);
66 colormap->windowing_data = private;
69 colormap->colors = NULL;
73 gdk_colormap_class_init (GdkColormapClass *klass)
75 GObjectClass *object_class = G_OBJECT_CLASS (klass);
77 parent_class = g_type_class_peek_parent (klass);
79 object_class->finalize = gdk_colormap_finalize;
83 gdk_colormap_get_type (void)
85 static GType object_type = 0;
89 static const GTypeInfo object_info =
91 sizeof (GdkColormapClass),
93 (GBaseFinalizeFunc) NULL,
94 (GClassInitFunc) gdk_colormap_class_init,
95 NULL, /* class_finalize */
96 NULL, /* class_data */
99 (GInstanceInitFunc) gdk_colormap_init,
102 object_type = g_type_register_static (G_TYPE_OBJECT,
112 gdk_colormap_new (GdkVisual *visual,
115 GdkColormap *colormap;
117 GdkColormapPrivateFB *private;
121 g_return_val_if_fail (visual != NULL, NULL);
123 colormap = g_object_new (gdk_colormap_get_type (), NULL);
124 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
126 colormap->visual = visual;
129 private->hash = NULL;
131 colormap->size = visual->colormap_size;
132 colormap->colors = NULL;
134 switch (visual->type)
136 case GDK_VISUAL_STATIC_GRAY:
137 case GDK_VISUAL_STATIC_COLOR:
138 case GDK_VISUAL_GRAYSCALE:
139 case GDK_VISUAL_PSEUDO_COLOR:
140 private->info = g_new0 (GdkColorInfo, colormap->size);
141 colormap->colors = g_new (GdkColor, colormap->size);
143 private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
144 (GEqualFunc) gdk_color_equal);
146 system = gdk_colormap_get_system ();
147 memcpy (colormap->colors, system->colors, colormap->size * sizeof (GdkColor));
151 guint16 red[256], green[256], blue[256];
152 struct fb_cmap fbc = {0, 256};
158 if (ioctl (fbd->fb_fd, FBIOGETCMAP, &fbc))
159 g_error("ioctl(FBIOGETCMAP) failed");
161 for (i = 0; i < colormap->size; i++)
163 colormap->colors[i].pixel = i;
164 colormap->colors[i].red = red[i];
165 colormap->colors[i].green = green[i];
166 colormap->colors[i].blue = blue[i];
169 gdk_colormap_change (colormap, colormap->size);
173 case GDK_VISUAL_DIRECT_COLOR:
174 g_warning ("gdk_colormap_new () on a direct color visual not implemented");
176 colormap->colors = g_new (GdkColor, colormap->size);
178 size = 1 << visual->red_prec;
179 for (i = 0; i < size; i++)
180 colormap->colors[i].red = i * 65535 / (size - 1);
182 size = 1 << visual->green_prec;
183 for (i = 0; i < size; i++)
184 colormap->colors[i].green = i * 65535 / (size - 1);
186 size = 1 << visual->blue_prec;
187 for (i = 0; i < size; i++)
188 colormap->colors[i].blue = i * 65535 / (size - 1);
190 gdk_colormap_change (colormap, colormap->size);
195 g_assert_not_reached ();
197 case GDK_VISUAL_TRUE_COLOR:
205 gdk_screen_get_system_colormap (GdkScreen *screen)
207 static GdkColormap *colormap = NULL;
211 GdkColormapPrivateFB *private;
212 GdkVisual *visual = gdk_visual_get_system ();
215 colormap = g_object_new (gdk_colormap_get_type (), NULL);
216 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
218 colormap->visual = visual;
219 private->hash = NULL;
221 colormap->size = visual->colormap_size;
222 colormap->colors = NULL;
224 switch (visual->type)
226 case GDK_VISUAL_STATIC_GRAY:
227 case GDK_VISUAL_STATIC_COLOR:
228 case GDK_VISUAL_GRAYSCALE:
229 case GDK_VISUAL_PSEUDO_COLOR:
230 private->info = g_new0 (GdkColorInfo, colormap->size);
231 colormap->colors = g_new (GdkColor, colormap->size);
233 private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
234 (GEqualFunc) gdk_color_equal);
237 case GDK_VISUAL_GRAYSCALE:
238 for(i = 0; i < 256; i++) {
239 colormap->colors[i].red =
240 colormap->colors[i].green =
241 colormap->colors[i].blue = i << 8;
242 gdk_fb_color_round_to_hw (&colormap->colors[i]);
245 colormap->colors[i].red =
246 colormap->colors[i].green =
247 colormap->colors[i].blue = 65535; /* Make it a true white */
248 gdk_fb_color_round_to_hw (&colormap->colors[i]);
250 case GDK_VISUAL_PSEUDO_COLOR:
251 /* Color cube stolen from gdkrgb upon advice from Owen */
252 for(i = r = 0; r < 6; r++)
253 for(g = 0; g < 6; g++)
254 for(b = 0; b < 6; b++)
256 colormap->colors[i].red = r * 65535 / 5;
257 colormap->colors[i].green = g * 65535 / 5;
258 colormap->colors[i].blue = b * 65535 / 5;
259 gdk_fb_color_round_to_hw (&colormap->colors[i]);
263 /* Fill in remaining space with grays */
264 for(i = 216; i < 256; i++)
266 colormap->colors[i].red =
267 colormap->colors[i].green =
268 colormap->colors[i].blue = (i - 216) * 40;
269 gdk_fb_color_round_to_hw (&colormap->colors[i]);
272 colormap->colors[255].red =
273 colormap->colors[255].green =
274 colormap->colors[255].blue = 65535;
275 gdk_fb_color_round_to_hw (&colormap->colors[255]);
282 case GDK_VISUAL_DIRECT_COLOR:
283 g_warning ("gdk_colormap_get_system() on a direct color visual is not implemented");
286 g_assert_not_reached ();
287 case GDK_VISUAL_TRUE_COLOR:
291 /* Lock all colors for the system colormap
292 * on pseudocolor visuals. The AA text rendering
293 * takes to many colors otherwise.
295 if ((visual->type == GDK_VISUAL_GRAYSCALE) ||
296 (visual->type == GDK_VISUAL_PSEUDO_COLOR))
298 for(i = 0; i < 256; i++)
300 colormap->colors[i].pixel = i;
301 private->info[i].ref_count = 1;
302 g_hash_table_insert (private->hash,
303 &colormap->colors[i],
304 &colormap->colors[i]);
307 gdk_colormap_change (colormap, colormap->size);
314 gdk_colormap_get_system_size (void)
316 return 1 << (gdk_display->modeinfo.bits_per_pixel);
320 gdk_colormap_change (GdkColormap *colormap,
323 guint16 red[256], green[256], blue[256];
324 struct fb_cmap fbc = {0,256};
325 GdkColormapPrivateFB *private;
328 g_return_if_fail (colormap != NULL);
334 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
335 switch (colormap->visual->type)
337 case GDK_VISUAL_GRAYSCALE:
338 for(i = 0; i < ncolors; i++)
340 red[i] = green[i] = blue[i] =
341 (colormap->colors[i].red +
342 colormap->colors[i].green +
343 colormap->colors[i].blue)/3;
345 ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
348 case GDK_VISUAL_PSEUDO_COLOR:
349 for (i = 0; i < ncolors; i++)
351 red[i] = colormap->colors[i].red;
352 green[i] = colormap->colors[i].green;
353 blue[i] = colormap->colors[i].blue;
355 ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
364 gdk_colormap_free_colors (GdkColormap *colormap,
368 GdkColormapPrivateFB *private;
371 g_return_if_fail (colormap != NULL);
372 g_return_if_fail (colors != NULL);
374 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
376 if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
377 (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
380 for (i = 0; i < ncolors; i++)
382 gulong pixel = colors[i].pixel;
384 if (private->info[pixel].ref_count)
386 private->info[pixel].ref_count--;
388 if (private->info[pixel].ref_count == 0)
390 if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
391 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
392 private->info[pixel].flags = 0;
398 /********************
400 ********************/
403 gdk_fb_color_round_to_hw (GdkColor *color)
405 guint rmask, gmask, bmask, len;
407 len = gdk_display->modeinfo.red.length;
408 rmask = ((1 << len) - 1) << (16-len);
409 len = gdk_display->modeinfo.green.length;
410 gmask = ((1 << len) - 1) << (16-len);
411 len = gdk_display->modeinfo.blue.length;
412 bmask = ((1 << len) - 1) << (16-len);
415 color->green &=gmask;
419 /* Try to allocate a single color using XAllocColor. If it succeeds,
420 * cache the result in our colormap, and store in ret.
423 gdk_colormap_alloc1 (GdkColormap *colormap,
427 GdkColormapPrivateFB *private;
430 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
432 if (colormap->visual->type != GDK_VISUAL_GRAYSCALE
433 && colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR)
438 gdk_fb_color_round_to_hw (ret);
440 for (i = 0; i<colormap->size; i++)
442 if (!(private->info[i].flags & GDK_COLOR_WRITEABLE) &&
443 (ret->red == colormap->colors[i].red) &&
444 (ret->green == colormap->colors[i].green) &&
445 (ret->blue == colormap->colors[i].blue))
448 colormap->colors[i].pixel = i;
449 if (private->info[i].ref_count == 0)
450 g_hash_table_insert (private->hash,
451 &colormap->colors[ret->pixel],
452 &colormap->colors[ret->pixel]);
453 private->info[i].ref_count++;
458 for (i = 0; i<colormap->size; i++)
460 if (private->info[i].ref_count==0)
462 guint16 red = color->red, green = color->green, blue = color->blue;
471 ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
474 colormap->colors[ret->pixel] = *ret;
475 private->info[ret->pixel].ref_count = 1;
476 g_hash_table_insert (private->hash,
477 &colormap->colors[ret->pixel],
478 &colormap->colors[ret->pixel]);
487 gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
494 GdkColormapPrivateFB *private;
499 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
502 for (i = 0; i < ncolors; i++)
506 if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
514 if (nremaining > 0 && best_match)
516 gchar *available = g_new (gchar, colormap->size);
518 for (i = 0; i < colormap->size; i++)
519 available[i] = ((private->info[i].ref_count == 0) ||
520 !(private->info[i].flags & GDK_COLOR_WRITEABLE));
522 while (nremaining > 0)
524 for (i = 0; i < ncolors; i++)
528 index = gdk_colormap_match_color (colormap, &colors[i], available);
531 if (private->info[index].ref_count)
533 private->info[index].ref_count++;
534 colors[i] = colormap->colors[index];
540 if (gdk_colormap_alloc1 (colormap,
541 &colormap->colors[index],
550 available[index] = FALSE;
558 success[i] = 2; /* flag as permanent failure */
566 /* Change back the values we flagged as permanent failures */
569 for (i = 0; i < ncolors; i++)
572 nremaining = nfailed;
575 return (ncolors - nremaining);
579 gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
586 GdkColormapPrivateFB *private;
587 GdkColor *lookup_color;
591 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
593 /* Check for an exact match among previously allocated colors */
595 for (i = 0; i < ncolors; i++)
599 lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
602 private->info[lookup_color->pixel].ref_count++;
603 colors[i].pixel = lookup_color->pixel;
611 /* If that failed, we try to allocate a new color, or approxmiate
612 * with what we can get if best_match is TRUE.
615 return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
621 gdk_colormap_alloc_colors (GdkColormap *colormap,
628 GdkColormapPrivateFB *private;
633 g_return_val_if_fail (colormap != NULL, FALSE);
634 g_return_val_if_fail (colors != NULL, FALSE);
636 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
638 for (i = 0; i < ncolors; i++)
641 visual = colormap->visual;
642 switch (visual->type)
644 case GDK_VISUAL_PSEUDO_COLOR:
645 case GDK_VISUAL_GRAYSCALE:
646 case GDK_VISUAL_STATIC_GRAY:
647 case GDK_VISUAL_STATIC_COLOR:
648 return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
649 writeable, best_match, success);
652 case GDK_VISUAL_DIRECT_COLOR:
653 case GDK_VISUAL_TRUE_COLOR:
654 for (i = 0; i < ncolors; i++)
656 colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
657 ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
658 ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
667 gdk_color_change (GdkColormap *colormap,
670 GdkColormapPrivateFB *private;
671 struct fb_cmap fbc = {0, 1};
673 g_return_val_if_fail (colormap != NULL, FALSE);
674 g_return_val_if_fail (color != NULL, FALSE);
676 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
678 switch(colormap->visual->type)
680 case GDK_VISUAL_GRAYSCALE:
681 color->red = color->green = color->blue = (color->red + color->green + color->blue)/3;
684 case GDK_VISUAL_PSEUDO_COLOR:
685 colormap->colors[color->pixel] = *color;
687 fbc.start = color->pixel;
688 fbc.red = &color->red;
689 fbc.green = &color->green;
690 fbc.blue = &color->blue;
691 ioctl (gdk_display->fb_fd, FBIOPUTCMAP, &fbc);
702 gdk_colormap_match_color (GdkColormap *cmap,
704 const gchar *available)
708 gint rdiff, gdiff, bdiff;
711 g_return_val_if_fail (cmap != NULL, 0);
712 g_return_val_if_fail (color != NULL, 0);
714 colors = cmap->colors;
718 for (i = 0; i < cmap->size; i++)
720 if ((!available) || (available && available[i]))
722 rdiff = (color->red - colors[i].red);
723 gdiff = (color->green - colors[i].green);
724 bdiff = (color->blue - colors[i].blue);
726 sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
740 gdk_colors_alloc (GdkColormap *colormap,
747 GdkColormapPrivateFB *private;
750 g_return_val_if_fail (colormap != NULL, FALSE);
752 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
758 for (i = 1; i < colormap->size; i++)
760 if (private->info[i].ref_count == 0)
763 if (found >= npixels)
772 for (i = 1; i < colormap->size; i++)
774 if (private->info[i].ref_count == 0)
777 private->info[i].ref_count++;
778 private->info[i].flags |= GDK_COLOR_WRITEABLE;
784 g_assert_not_reached ();
789 gdk_colors_free (GdkColormap *colormap,
794 GdkColormapPrivateFB *private;
797 g_return_if_fail (colormap != NULL);
799 if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
800 (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
803 private = GDK_COLORMAP_PRIVATE_DATA (colormap);
805 for (i = 0; i < npixels; i++)
809 if (private->info[pixel].ref_count)
811 private->info[pixel].ref_count--;
813 if (private->info[pixel].ref_count == 0)
815 if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
816 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
817 private->info[pixel].flags = 0;
825 gdk_colormap_query_color (GdkColormap *colormap,
831 g_return_if_fail (GDK_IS_COLORMAP (colormap));
833 visual = gdk_colormap_get_visual (colormap);
835 switch (visual->type)
837 case GDK_VISUAL_DIRECT_COLOR:
838 case GDK_VISUAL_TRUE_COLOR:
839 result->red = 65535. * (gdouble) ((pixel & visual->red_mask) >> visual->red_shift) / ((1 << visual->red_prec) - 1);
840 result->green = 65535. * (gdouble) ((pixel & visual->green_mask) >> visual->green_shift) / ((1 << visual->green_prec) - 1);
841 result->blue = 65535. * (gdouble) ((pixel & visual->blue_mask) >> visual->blue_shift) / ((1 << visual->blue_prec) - 1);
843 case GDK_VISUAL_STATIC_GRAY:
844 case GDK_VISUAL_GRAYSCALE:
845 result->red = result->green = result->blue = 65535. * (double)pixel/((1<<visual->depth) - 1);
847 case GDK_VISUAL_PSEUDO_COLOR:
848 result->red = colormap->colors[pixel].red;
849 result->green = colormap->colors[pixel].green;
850 result->blue = colormap->colors[pixel].blue;
853 g_assert_not_reached ();
859 gdk_colormap_get_screen (GdkColormap *cmap)
861 g_return_val_if_fail (cmap != NULL, NULL);
863 return gdk_screen_get_default ();