]> Pileus Git - ~andy/gtk/blob - gdk/linux-fb/gdkcolor-fb.c
Put it into CVS.
[~andy/gtk] / gdk / linux-fb / gdkcolor-fb.c
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 <sys/ioctl.h>
29 #include <string.h>
30 #include <stdlib.h>
31
32 #include "gdkcolor.h"
33 #include "gdkprivate-fb.h"
34
35 static gint  gdk_colormap_match_color (GdkColormap *cmap,
36                                        GdkColor    *color,
37                                        const gchar *available);
38 GdkColormap*
39 gdk_colormap_new (GdkVisual *visual,
40                   gint       private_cmap)
41 {
42   GdkColormap *colormap;
43   GdkColormapPrivateFB *private;
44   GdkFBDisplay *fbd;
45   int i;
46
47   g_return_val_if_fail (visual != NULL, NULL);
48
49   private = g_new (GdkColormapPrivateFB, 1);
50   colormap = (GdkColormap*) private;
51
52   private->base.visual = visual;
53   private->base.ref_count = 1;
54   fbd = gdk_display;
55
56   private->hash = NULL;
57   
58   colormap->size = visual->colormap_size;
59   colormap->colors = NULL;
60
61   switch (visual->type)
62     {
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);
69       
70       private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
71                                         (GCompareFunc) gdk_color_equal);
72       
73       if (private_cmap)
74         {
75           guint16 red[256], green[256], blue[256];
76           struct fb_cmap fbc = {0, 256};
77
78           fbc.red = red;
79           fbc.green = green;
80           fbc.blue = blue;
81
82           if(ioctl(fbd->fd, FBIOGETCMAP, &fbc))
83             g_error("ioctl(FBIOGETCMAP) failed");
84
85           for (i = 0; i < colormap->size; i++)
86             {
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];
91             }
92
93           gdk_colormap_change (colormap, colormap->size);
94         }
95       break;
96
97     case GDK_VISUAL_DIRECT_COLOR:
98       g_error("NYI");
99 #if 0
100       colormap->colors = g_new (GdkColor, colormap->size);
101
102       size = 1 << visual->red_prec;
103       for (i = 0; i < size; i++)
104         colormap->colors[i].red = i * 65535 / (size - 1);
105
106       size = 1 << visual->green_prec;
107       for (i = 0; i < size; i++)
108         colormap->colors[i].green = i * 65535 / (size - 1);
109
110       size = 1 << visual->blue_prec;
111       for (i = 0; i < size; i++)
112         colormap->colors[i].blue = i * 65535 / (size - 1);
113
114       gdk_colormap_change (colormap, colormap->size);
115 #endif
116       break;
117
118     default:
119       g_assert_not_reached();
120
121     case GDK_VISUAL_TRUE_COLOR:
122       break;
123     }
124
125   return colormap;
126 }
127
128 void
129 _gdk_colormap_real_destroy (GdkColormap *colormap)
130 {
131   GdkColormapPrivateFB *private = (GdkColormapPrivateFB*) colormap;
132
133   if (private->hash)
134     g_hash_table_destroy (private->hash);
135   
136   g_free (private->info);
137   g_free (colormap->colors);
138   g_free (colormap);
139 }
140
141 #define MIN_SYNC_TIME 2
142
143 void
144 gdk_colormap_sync (GdkColormap *colormap,
145                    gboolean     force)
146 {
147   
148 }                  
149
150 GdkColormap*
151 gdk_colormap_get_system (void)
152 {
153   static GdkColormap *colormap = NULL;
154
155   if (!colormap)
156     {
157       guint16 red[256], green[256], blue[256];
158       struct fb_cmap fbc = {0, 256};
159       int i, r, g, b;
160       GdkVisual *visual = gdk_visual_get_system();
161
162       if(visual->type == GDK_VISUAL_GRAYSCALE
163          || visual->type ==  GDK_VISUAL_PSEUDO_COLOR)
164         {
165           fbc.red = red;
166           fbc.green = green;
167           fbc.blue = blue;
168           switch(visual->type)
169             {
170             case GDK_VISUAL_GRAYSCALE:
171               for(i = 0; i < 256; i++)
172                 red[i] = green[i] = blue[i] = i << 8;
173               i--;
174               red[i] = green[i] = blue[i] = 65535; /* Make it a true white */
175               break;
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++)
181                     {
182                       red[i] = r * 65535 / 5;
183                       green[i] = g * 65535 / 5;
184                       blue[i] = b * 65535 / 5;
185                       i++;
186                     }
187               g_assert(i == 216);
188
189           /* Fill in remaining space with grays */
190               for(i = 216; i < 256; i++)
191                 {
192                   red[i] = green[i] = blue[i] =
193                     (i - 216) * 40;
194                 }
195               /* Real white */
196               red[255] = green[255] = blue[255] = 65535;
197               break;
198             default:
199               break;
200             }
201
202           ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
203         }
204
205       colormap = gdk_colormap_new(visual, TRUE);
206     }
207
208   return colormap;
209 }
210
211 gint
212 gdk_colormap_get_system_size (void)
213 {
214   return 1 << (gdk_display->modeinfo.bits_per_pixel);
215 }
216
217 void
218 gdk_colormap_change (GdkColormap *colormap,
219                      gint         ncolors)
220 {
221   guint16 red[256], green[256], blue[256];
222   struct fb_cmap fbc = {0,256};
223   GdkColormapPrivateFB *private;
224   int i;
225
226   g_return_if_fail (colormap != NULL);
227
228   fbc.red = red;
229   fbc.green = green;
230   fbc.blue = blue;
231
232   private = (GdkColormapPrivateFB*) colormap;
233   switch (private->base.visual->type)
234     {
235     case GDK_VISUAL_GRAYSCALE:
236       for(i = 0; i < ncolors; i++)
237         {
238           red[i] = green[i] = blue[i] =
239             (colormap->colors[i].red +
240              colormap->colors[i].green +
241              colormap->colors[i].blue)/3;
242         }
243       ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
244       break;
245
246     case GDK_VISUAL_PSEUDO_COLOR:
247       for (i = 0; i < ncolors; i++)
248         {
249           red[i] = colormap->colors[i].red;
250           green[i] = colormap->colors[i].green;
251           blue[i] = colormap->colors[i].blue;
252         }
253       ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
254       break;
255
256     default:
257       break;
258     }
259 }
260
261 gboolean
262 gdk_color_parse (const gchar *spec,
263                  GdkColor *color)
264 {
265   char aline[512];
266   FILE *fh;
267
268   g_return_val_if_fail(spec, FALSE);
269   g_return_val_if_fail(color, FALSE);
270
271   if(spec[0] == '#')
272     {
273       if(strlen(spec) == 7)
274         {
275           guint num;
276
277           sscanf(spec + 1, "%x", &num);
278           color->red = (num & 0xFF0000) >> 8;
279           color->green = (num & 0xFF00);
280           color->blue = (num & 0xFF) << 8;
281         }
282       else if(strlen(spec) == 13)
283         {
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);
288
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");
295         }
296       else
297         {
298           g_warning("Couldn't parse color specifier `%s'", spec);
299           return FALSE;
300         }
301
302       return TRUE;
303     }
304   else
305     {
306       fh = fopen("/usr/lib/X11/rgb.txt", "r");
307       if(!fh)
308         return FALSE;
309
310       while(fgets(aline, sizeof(aline), fh))
311         {
312           int red, green, blue;
313           char *ctmp;
314
315           g_strstrip(aline);
316           if(!aline[0] || aline[0] == '#' || aline[0] == '!')
317             continue;
318
319           ctmp = strtok(aline, " \t");
320           if(!ctmp)
321             continue;
322           red = atoi(ctmp);
323
324           ctmp = strtok(NULL, " \t");
325           if(!ctmp)
326             continue;
327           green = atoi(ctmp);
328
329           ctmp = strtok(NULL, " \t");
330           if(!ctmp)
331             continue;
332           blue = atoi(ctmp);
333
334           ctmp = strtok(NULL, " \t");
335           if(!ctmp || strcmp(ctmp, spec))
336             continue;
337
338           color->red = red << 8;
339           color->green = green << 8;
340           color->blue = blue << 8;
341           return TRUE;
342         }
343       fclose(fh);
344     }
345
346   return FALSE;
347 }
348
349 void
350 gdk_colormap_free_colors (GdkColormap *colormap,
351                           GdkColor    *colors,
352                           gint         ncolors)
353 {
354   GdkColormapPrivateFB *private;
355   gint i;
356
357   g_return_if_fail (colormap != NULL);
358   g_return_if_fail (colors != NULL);
359
360   private = (GdkColormapPrivateFB*) colormap;
361
362   if ((private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
363       (private->base.visual->type != GDK_VISUAL_GRAYSCALE))
364     return;
365
366   for (i=0; i<ncolors; i++)
367     {
368       gulong pixel = colors[i].pixel;
369       
370       if (private->info[pixel].ref_count)
371         {
372           private->info[pixel].ref_count--;
373
374           if (private->info[pixel].ref_count == 0)
375             {
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;
379             }
380         }
381     }
382 }
383
384 /********************
385  * Color allocation *
386  ********************/
387
388 /* Try to allocate a single color using XAllocColor. If it succeeds,
389  * cache the result in our colormap, and store in ret.
390  */
391 static gboolean 
392 gdk_colormap_alloc1 (GdkColormap *colormap,
393                      GdkColor    *color,
394                      GdkColor    *ret)
395 {
396   GdkColormapPrivateFB *private;
397   int i;
398
399   private = (GdkColormapPrivateFB*) colormap;
400
401   if(private->base.visual->type != GDK_VISUAL_GRAYSCALE
402      && private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR)
403     return FALSE;
404
405   *ret = *color;
406   if(!color->red && !color->green && !color->blue) /* black */
407     {
408       ret->pixel = 0;
409       private->info[ret->pixel].ref_count++;
410       return TRUE;
411     }
412
413   if(color->red == 65535 && color->green == 65535 && color->blue == 65535) /* white */
414     {
415       ret->pixel = 255;
416       private->info[ret->pixel].ref_count++;
417       return TRUE;
418     }
419
420   for(i = 1; i < (colormap->size - 1); i++)
421     {
422       if(!private->info[i].ref_count)
423         {
424           guint16 red = color->red, green = color->green, blue = color->blue;
425           struct fb_cmap fbc;
426           fbc.len = 1;
427           fbc.start = i;
428           fbc.red = &red;
429           fbc.green = &green;
430           fbc.blue = &blue;
431
432           ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
433
434           ret->pixel = i;
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]);
440           return TRUE;
441         }
442     }
443
444   return FALSE;
445 }
446
447 static gint
448 gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
449                                   GdkColor    *colors,
450                                   gint         ncolors,
451                                   gboolean     writeable,
452                                   gboolean     best_match,
453                                   gboolean    *success)
454 {
455   GdkColormapPrivateFB *private;
456   gint i, index;
457   gint nremaining = 0;
458   gint nfailed = 0;
459
460   private = (GdkColormapPrivateFB*) colormap;
461   index = -1;
462
463   for (i=0; i<ncolors; i++)
464     {
465       if (!success[i])
466         {
467           if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
468             success[i] = TRUE;
469           else
470             nremaining++;
471         }
472     }
473
474
475   if (nremaining > 0 && best_match)
476     {
477       gchar *available = g_new (gchar, colormap->size);
478
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));
482       
483       while (nremaining > 0)
484         {
485           for (i=0; i<ncolors; i++)
486             {
487               if (!success[i])
488                 {
489                   index = gdk_colormap_match_color (colormap, &colors[i], available);
490                   if (index != -1)
491                     {
492                       if (private->info[index].ref_count)
493                         {
494                           private->info[index].ref_count++;
495                           colors[i] = colormap->colors[index];
496                           success[i] = TRUE;
497                           nremaining--;
498                         }
499                       else
500                         {
501                           if (gdk_colormap_alloc1 (colormap, 
502                                                    &colormap->colors[index],
503                                                    &colors[i]))
504                             {
505                               success[i] = TRUE;
506                               nremaining--;
507                               break;
508                             }
509                           else
510                             {
511                               available[index] = FALSE;
512                             }
513                         }
514                     }
515                   else
516                     {
517                       nfailed++;
518                       nremaining--;
519                       success[i] = 2; /* flag as permanent failure */
520                     }
521                 }
522             }
523         }
524       g_free (available);
525     }
526
527   /* Change back the values we flagged as permanent failures */
528   if (nfailed > 0)
529     {
530       for (i=0; i<ncolors; i++)
531         if (success[i] == 2)
532           success[i] = FALSE;
533       nremaining = nfailed;
534     }
535   
536   return (ncolors - nremaining);
537 }
538
539 static gint
540 gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
541                                        GdkColor    *colors,
542                                        gint         ncolors,
543                                        gboolean     writeable,
544                                        gboolean     best_match,
545                                        gboolean    *success)
546 {
547   GdkColormapPrivateFB *private;
548   GdkColor *lookup_color;
549   gint i;
550   gint nremaining = 0;
551
552   private = (GdkColormapPrivateFB*) colormap;
553
554   /* Check for an exact match among previously allocated colors */
555
556   for (i=0; i<ncolors; i++)
557     {
558       if (!success[i])
559         {
560           lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
561           if (lookup_color)
562             {
563               private->info[lookup_color->pixel].ref_count++;
564               colors[i].pixel = lookup_color->pixel;
565               success[i] = TRUE;
566             }
567           else
568             nremaining++;
569         }
570     }
571
572   /* If that failed, we try to allocate a new color, or approxmiate
573    * with what we can get if best_match is TRUE.
574    */
575   if (nremaining > 0)
576     return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
577   else
578     return 0;
579 }
580
581 gint
582 gdk_colormap_alloc_colors (GdkColormap *colormap,
583                            GdkColor    *colors,
584                            gint         ncolors,
585                            gboolean     writeable,
586                            gboolean     best_match,
587                            gboolean    *success)
588 {
589   GdkColormapPrivateFB *private;
590   GdkVisual *visual;
591   gint i;
592   gint nremaining = 0;
593
594   g_return_val_if_fail (colormap != NULL, FALSE);
595   g_return_val_if_fail (colors != NULL, FALSE);
596
597   private = (GdkColormapPrivateFB*) colormap;
598
599   for (i=0; i<ncolors; i++)
600     success[i] = FALSE;
601
602   switch (private->base.visual->type)
603     {
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);
610       break;
611
612     case GDK_VISUAL_DIRECT_COLOR:
613     case GDK_VISUAL_TRUE_COLOR:
614       visual = private->base.visual;
615
616       for (i=0; i<ncolors; i++)
617         {
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));
621           success[i] = TRUE;
622         }
623       break;
624     }
625   return nremaining;
626 }
627
628 gboolean
629 gdk_color_change (GdkColormap *colormap,
630                   GdkColor    *color)
631 {
632   GdkColormapPrivateFB *private;
633   struct fb_cmap fbc = {0, 1};
634
635   g_return_val_if_fail (colormap != NULL, FALSE);
636   g_return_val_if_fail (color != NULL, FALSE);
637
638   private = (GdkColormapPrivateFB*) colormap;
639
640   switch(private->base.visual->type)
641     {
642     case GDK_VISUAL_GRAYSCALE:
643       color->red = color->green = color->blue = (color->red + color->green + color->blue)/3;
644
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);
651       break;
652
653     default:
654       break;
655     }
656
657   return TRUE;
658 }
659
660 static gint
661 gdk_colormap_match_color (GdkColormap *cmap,
662                           GdkColor    *color,
663                           const gchar *available)
664 {
665   GdkColor *colors;
666   guint sum, max;
667   gint rdiff, gdiff, bdiff;
668   gint i, index;
669
670   g_return_val_if_fail (cmap != NULL, 0);
671   g_return_val_if_fail (color != NULL, 0);
672
673   colors = cmap->colors;
674   max = 3 * (65536);
675   index = -1;
676
677   for (i = 0; i < cmap->size; i++)
678     {
679       if ((!available) || (available && available[i]))
680         {
681           rdiff = (color->red - colors[i].red);
682           gdiff = (color->green - colors[i].green);
683           bdiff = (color->blue - colors[i].blue);
684
685           sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
686
687           if (sum < max)
688             {
689               index = i;
690               max = sum;
691             }
692         }
693     }
694
695   return index;
696 }
697
698 gint gdk_colors_alloc    (GdkColormap   *colormap,
699                           gboolean       contiguous,
700                           gulong        *planes,
701                           gint           nplanes,
702                           gulong        *pixels,
703                           gint           npixels)
704 {
705   return 0;
706 }
707
708 void
709 gdk_colors_free  (GdkColormap   *colormap,
710                   gulong        *pixels,
711                   gint           npixels,
712                   gulong         planes)
713 {
714 }
715
716 gulong
717 gdk_color_context_get_pixel(GdkColorContext *cc,
718                             gushort         red,
719                             gushort         green,
720                             gushort         blue,
721                             gint           *failed)
722 {
723   g_error("NYI");
724
725   return 0;
726 }
727
728 GdkColorContext *
729 gdk_color_context_new(GdkVisual   *visual,
730                       GdkColormap *colormap)
731 {
732   g_error("NYI");
733
734   return NULL;
735 }
736
737 GdkColorContext *
738 gdk_color_context_new_mono(GdkVisual   *visual,
739                            GdkColormap *colormap)
740 {
741   g_error("NYI");
742
743   return NULL;
744 }
745
746 void
747 gdk_color_context_free(GdkColorContext *cc)
748 {
749   g_error("NYI");
750 }
751
752 gint
753 gdk_color_context_query_color(GdkColorContext *cc,
754                               GdkColor     *color)
755 {
756   g_error("NYI");
757
758   return 0;
759 }