http://svn.poeml.de/viewvc/ppc/src-unpacked/xscreensaver/xscreensaver-4.12.tar.bz2...
[xscreensaver] / utils / visual.c
1 /* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2003
2  * 
3  *  by Jamie Zawinski <jwz@jwz.org>
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation.  No representations are made about the suitability of this
10  * software for any purpose.  It is provided "as is" without express or 
11  * implied warranty.
12  */
13
14 /* This file contains some code for intelligently picking the best visual
15    (where "best" is biased in the direction of either: high color counts;
16    or: having writable color cells...)
17  */
18
19 #include "utils.h"
20 #include "resources.h"  /* for get_string_resource() */
21 #include "visual.h"
22
23 #include <string.h>
24 #include <X11/Xutil.h>
25
26 extern char *progname;
27
28
29 #ifndef isupper
30 # define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
31 #endif
32 #ifndef _tolower
33 # define _tolower(c)  ((c) - 'A' + 'a')
34 #endif
35
36
37 static Visual *pick_best_visual (Screen *, Bool, Bool);
38 static Visual *pick_mono_visual (Screen *);
39 static Visual *pick_best_visual_of_class (Screen *, int);
40 static Visual *pick_best_gl_visual (Screen *);
41
42
43 #define DEFAULT_VISUAL  -1
44 #define BEST_VISUAL     -2
45 #define MONO_VISUAL     -3
46 #define GRAY_VISUAL     -4
47 #define COLOR_VISUAL    -5
48 #define GL_VISUAL       -6
49 #define SPECIFIC_VISUAL -7
50
51 Visual *
52 get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
53             Bool verbose_p)
54 {
55   char *v = (string ? strdup(string) : 0);
56   char c, *tmp;
57   int vclass;
58   unsigned long id;
59   Visual *result = 0;
60
61   if (v)
62     for (tmp = v; *tmp; tmp++)
63       if (isupper (*tmp)) *tmp = _tolower (*tmp);
64
65   if (!v || !*v)                                  vclass = BEST_VISUAL;
66   else if (!strcmp (v, "default"))                vclass = DEFAULT_VISUAL;
67   else if (!strcmp (v, "best"))                   vclass = BEST_VISUAL;
68   else if (!strcmp (v, "mono"))                   vclass = MONO_VISUAL;
69   else if (!strcmp (v, "monochrome"))             vclass = MONO_VISUAL;
70   else if (!strcmp (v, "gray"))                   vclass = GRAY_VISUAL;
71   else if (!strcmp (v, "grey"))                   vclass = GRAY_VISUAL;
72   else if (!strcmp (v, "color"))                  vclass = COLOR_VISUAL;
73   else if (!strcmp (v, "gl"))                     vclass = GL_VISUAL;
74   else if (!strcmp (v, "staticgray"))             vclass = StaticGray;
75   else if (!strcmp (v, "staticcolor"))            vclass = StaticColor;
76   else if (!strcmp (v, "truecolor"))              vclass = TrueColor;
77   else if (!strcmp (v, "grayscale"))              vclass = GrayScale;
78   else if (!strcmp (v, "greyscale"))              vclass = GrayScale;
79   else if (!strcmp (v, "pseudocolor"))            vclass = PseudoColor;
80   else if (!strcmp (v, "directcolor"))            vclass = DirectColor;
81   else if (1 == sscanf (v, " %lu %c", &id, &c))   vclass = SPECIFIC_VISUAL;
82   else if (1 == sscanf (v, " 0x%lx %c", &id, &c)) vclass = SPECIFIC_VISUAL;
83   else
84     {
85       fprintf (stderr, "%s: unrecognized visual \"%s\".\n", progname, v);
86       vclass = DEFAULT_VISUAL;
87     }
88
89   if (vclass == DEFAULT_VISUAL)
90     result = DefaultVisualOfScreen (screen);
91   else if (vclass == BEST_VISUAL)
92     result = pick_best_visual (screen, prefer_writable_cells, False);
93   else if (vclass == MONO_VISUAL)
94     {
95       result = pick_mono_visual (screen);
96       if (!result && verbose_p)
97         fprintf (stderr, "%s: no monochrome visuals.\n", progname);
98     }
99   else if (vclass == GRAY_VISUAL)
100     {
101       if (prefer_writable_cells)
102         result = pick_best_visual_of_class (screen, GrayScale);
103       if (!result)
104         result = pick_best_visual_of_class (screen, StaticGray);
105       if (!result)
106         result = pick_best_visual_of_class (screen, GrayScale);
107       if (!result && verbose_p)
108         fprintf (stderr, "%s: no GrayScale or StaticGray visuals.\n",
109                  progname);
110     }
111   else if (vclass == COLOR_VISUAL)
112     {
113       int class;
114       /* First see if the default visual will do. */
115       result = DefaultVisualOfScreen (screen);
116       class = visual_class(screen, result);
117       if (class != TrueColor &&
118           class != PseudoColor &&
119           class != DirectColor &&
120           class != StaticColor)
121         result = 0;
122       if (result && visual_depth(screen, result) <= 1)
123         result = 0;
124
125       /* Else, find the best non-default color visual */
126       if (!result)
127         result = pick_best_visual (screen, prefer_writable_cells, True);
128
129       if (!result && verbose_p)
130         fprintf (stderr, "%s: no color visuals.\n", progname);
131     }
132   else if (vclass == GL_VISUAL)
133     {
134       Visual *visual = pick_best_gl_visual (screen);
135       if (visual)
136         result = visual;
137       else if (verbose_p)
138         fprintf (stderr, "%s: no visual suitable for GL.\n", progname);
139     }
140   else if (vclass == SPECIFIC_VISUAL)
141     {
142       result = id_to_visual (screen, id);
143       if (!result && verbose_p)
144         fprintf (stderr, "%s: no visual with id 0x%x.\n", progname,
145                  (unsigned int) id);
146     }
147   else
148     {
149       Visual *visual = pick_best_visual_of_class (screen, vclass);
150       if (visual)
151         result = visual;
152       else if (verbose_p)
153         fprintf (stderr, "%s: no visual of class %s.\n", progname, v);
154     }
155
156   if (v) free (v);
157   return result;
158 }
159
160 Visual *
161 get_visual_resource (Screen *screen, char *name, char *class,
162                      Bool prefer_writable_cells)
163 {
164   char *string = get_string_resource (name, class);
165   Visual *v = get_visual (screen, string, prefer_writable_cells, True);
166   if (string)
167     free(string);
168   if (v)
169     return v;
170   else
171     return DefaultVisualOfScreen (screen);
172 }
173
174
175 static Visual *
176 pick_best_visual (Screen *screen, Bool prefer_writable_cells, Bool color_only)
177 {
178   Visual *visual;
179
180   if (!prefer_writable_cells)
181     {
182       /* If we don't prefer writable cells, then the "best" visual is the one
183          on which we can allocate the largest range and number of colors.
184
185          Therefore, a TrueColor visual which is at least 16 bits deep is best.
186          (The assumption here being that a TrueColor of less than 16 bits is
187          really just a PseudoColor visual with a pre-allocated color cube.)
188
189          The next best thing is a PseudoColor visual of any type.  After that
190          come the non-colormappable visuals, and non-color visuals.
191        */
192       if ((visual = pick_best_visual_of_class (screen, TrueColor)) &&
193           visual_depth (screen, visual) >= 16)
194         return visual;
195     }
196
197 #define TRY_CLASS(CLASS) \
198   if ((visual = pick_best_visual_of_class (screen, CLASS)) && \
199       (!color_only || visual_depth(screen, visual) > 1)) \
200     return visual
201   TRY_CLASS(PseudoColor);
202   TRY_CLASS(TrueColor);
203   TRY_CLASS(DirectColor);
204   TRY_CLASS(StaticColor);
205   if (!color_only)
206     {
207       TRY_CLASS(GrayScale);
208       TRY_CLASS(StaticGray);
209     }
210 #undef TRY_CLASS
211
212   visual = DefaultVisualOfScreen (screen);
213   if (!color_only || visual_depth(screen, visual) > 1)
214     return visual;
215   else
216     return 0;
217 }
218
219 static Visual *
220 pick_mono_visual (Screen *screen)
221 {
222   Display *dpy = DisplayOfScreen (screen);
223   XVisualInfo vi_in, *vi_out;
224   int out_count;
225
226   vi_in.depth = 1;
227   vi_in.screen = screen_number (screen);
228   vi_out = XGetVisualInfo (dpy, (VisualDepthMask | VisualScreenMask),
229                            &vi_in, &out_count);
230   if (vi_out)
231     {
232       Visual *v = (out_count > 0 ? vi_out [0].visual : 0);
233       if (v && vi_out[0].depth != 1)
234         v = 0;
235       XFree ((char *) vi_out);
236       return v;
237     }
238   else
239     return 0;
240 }
241
242
243 static Visual *
244 pick_best_visual_of_class (Screen *screen, int visual_class)
245 {
246   /* The best visual of a class is the one which on which we can allocate
247      the largest range and number of colors, which means the one with the
248      greatest depth and number of cells.
249
250      (But actually, for XDaliClock, all visuals of the same class are
251      probably equivalent - either we have writable cells or we don't.)
252    */
253   Display *dpy = DisplayOfScreen (screen);
254   XVisualInfo vi_in, *vi_out;
255   int out_count;
256
257   vi_in.class = visual_class;
258   vi_in.screen = screen_number (screen);
259   vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask),
260                            &vi_in, &out_count);
261   if (vi_out)
262     {
263       /* choose the 'best' one, if multiple */
264       int i, best;
265       Visual *visual;
266 /*      for (i = 0, best = 0; i < out_count; i++) */
267       for (i = out_count-1, best = i; i >= 0; i--) /* go backwards */
268         /* It's better if it's deeper, or if it's the same depth with
269            more cells (does that ever happen?  Well, it could...) */
270         if ((vi_out [i].depth > vi_out [best].depth) ||
271             ((vi_out [i].depth == vi_out [best].depth) &&
272              (vi_out [i].colormap_size > vi_out [best].colormap_size)))
273           best = i;
274       visual = (best < out_count ? vi_out [best].visual : 0);
275       XFree ((char *) vi_out);
276       return visual;
277     }
278   else
279     return 0;
280 }
281
282 static Visual *
283 pick_best_gl_visual (Screen *screen)
284 {
285   /* The best visual for GL is a TrueColor visual that is half as deep as
286      the screen.  If such a thing doesn't exist, then TrueColor is best.
287      Failing that, the deepest available color visual is best.
288
289      Compare this function to get_gl_visual() in visual-gl.c.
290      This function tries to find the best GL visual using Xlib calls,
291      whereas that function does the same thing using GLX calls.
292    */
293   Display *dpy = DisplayOfScreen (screen);
294   XVisualInfo vi_in, *vi_out;
295   int out_count;
296   Visual *result = 0;
297
298   int ndepths = 0;
299   int *depths = XListDepths (dpy, screen_number (screen), &ndepths);
300   int screen_depth = depths[ndepths];
301   XFree (depths);
302
303   vi_in.class = TrueColor;
304   vi_in.screen = screen_number (screen);
305   vi_in.depth = screen_depth / 2;
306   vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
307                                  VisualDepthMask),
308                            &vi_in, &out_count);
309   if (out_count > 0)
310     result = vi_out[0].visual;
311
312   if (vi_out)
313     XFree ((char *) vi_out);
314
315   if (!result && screen_depth > 24)
316     {
317       /* If it's a 32-deep screen and we didn't find a depth-16 visual,
318          see if there's a depth-12 visual. */
319       vi_in.class = TrueColor;
320       vi_in.screen = screen_number (screen);
321       vi_in.depth = 12;
322       vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
323                                      VisualDepthMask),
324                                &vi_in, &out_count);
325       if (out_count > 0)
326         result = vi_out[0].visual;
327     }
328
329   if (!result)
330     /* No half-depth TrueColor?  Ok, try for any TrueColor (the deepest.) */
331     result = pick_best_visual_of_class (screen, TrueColor);
332
333   if (!result)
334     /* No TrueColor?  Ok, try for anything. */
335     result = pick_best_visual (screen, False, False);
336
337   return result;
338 }
339
340
341 Visual *
342 id_to_visual (Screen *screen, int id)
343 {
344   Display *dpy = DisplayOfScreen (screen);
345   XVisualInfo vi_in, *vi_out;
346   int out_count;
347   vi_in.screen = screen_number (screen);
348   vi_in.visualid = id;
349   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
350                            &vi_in, &out_count);
351   if (vi_out)
352     {
353       Visual *v = vi_out[0].visual;
354       XFree ((char *) vi_out);
355       return v;
356     }
357   return 0;
358 }
359
360 int
361 visual_depth (Screen *screen, Visual *visual)
362 {
363   Display *dpy = DisplayOfScreen (screen);
364   XVisualInfo vi_in, *vi_out;
365   int out_count, d;
366   vi_in.screen = screen_number (screen);
367   vi_in.visualid = XVisualIDFromVisual (visual);
368   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
369                            &vi_in, &out_count);
370   if (! vi_out) abort ();
371   d = vi_out [0].depth;
372   XFree ((char *) vi_out);
373   return d;
374 }
375
376
377 #if 0
378 /* You very probably don't want to be using this.
379    Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
380    the depth of protocol-level on-the-wire pixmap data, that is, XImages.
381    To get this info, you should be looking at XImage->bits_per_pixel
382    instead.  (And allocating the data for your XImage structures by
383    multiplying ximage->bytes_per_line by ximage->height.)
384  */
385 int
386 visual_pixmap_depth (Screen *screen, Visual *visual)
387 {
388   Display *dpy = DisplayOfScreen (screen);
389   int vdepth = visual_depth (screen, visual);
390   int pdepth = vdepth;
391   int i, pfvc = 0;
392   XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
393
394   /* Return the first matching depth in the pixmap formats.  If there are no
395      matching pixmap formats (which shouldn't be able to happen at all) then
396      return the visual depth instead. */
397   for (i = 0; i < pfvc; i++)
398     if (pfv[i].depth == vdepth)
399       {
400         pdepth = pfv[i].bits_per_pixel;
401         break;
402       }
403   if (pfv)
404     XFree (pfv);
405   return pdepth;
406 }
407 #endif /* 0 */
408
409
410 int
411 visual_class (Screen *screen, Visual *visual)
412 {
413   Display *dpy = DisplayOfScreen (screen);
414   XVisualInfo vi_in, *vi_out;
415   int out_count, c;
416   vi_in.screen = screen_number (screen);
417   vi_in.visualid = XVisualIDFromVisual (visual);
418   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
419                            &vi_in, &out_count);
420   if (! vi_out) abort ();
421   c = vi_out [0].class;
422   XFree ((char *) vi_out);
423   return c;
424 }
425
426 Bool
427 has_writable_cells (Screen *screen, Visual *visual)
428 {
429   switch (visual_class (screen, visual))
430     {
431     case GrayScale:     /* Mappable grays. */
432     case PseudoColor:   /* Mappable colors. */
433     case DirectColor:   /* Like TrueColor, but with three colormaps:
434                            one each for red, green, and blue. */
435       return True;
436     case StaticGray:    /* Fixed grays. */
437     case TrueColor:     /* Fixed colors. */
438     case StaticColor:   /* Like PseudoColor with an unmodifiable colormap. */
439       return False;
440     default:
441       abort();
442       return False;
443     }
444 }
445
446 void
447 describe_visual (FILE *f, Screen *screen, Visual *visual, Bool private_cmap_p)
448 {
449   char n[10];
450   Display *dpy = DisplayOfScreen (screen);
451   XVisualInfo vi_in, *vi_out;
452   int out_count;
453   vi_in.screen = screen_number (screen);
454   vi_in.visualid = XVisualIDFromVisual (visual);
455   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
456                            &vi_in, &out_count);
457   if (! vi_out) abort ();
458   if (private_cmap_p)
459     sprintf(n, "%3d", vi_out->colormap_size);
460   else
461     strcpy(n, "default");
462
463   fprintf (f, "0x%02x (%s depth: %2d, cmap: %s)\n",
464            (unsigned int) vi_out->visualid,
465            (vi_out->class == StaticGray  ? "StaticGray, " :
466             vi_out->class == StaticColor ? "StaticColor," :
467             vi_out->class == TrueColor   ? "TrueColor,  " :
468             vi_out->class == GrayScale   ? "GrayScale,  " :
469             vi_out->class == PseudoColor ? "PseudoColor," :
470             vi_out->class == DirectColor ? "DirectColor," :
471                                            "UNKNOWN:    "),
472            vi_out->depth, n);
473   XFree ((char *) vi_out);
474 }
475
476 int
477 screen_number (Screen *screen)
478 {
479   Display *dpy = DisplayOfScreen (screen);
480   int i;
481   for (i = 0; i < ScreenCount (dpy); i++)
482     if (ScreenOfDisplay (dpy, i) == screen)
483       return i;
484   abort ();
485   return 0;
486 }
487
488 int
489 visual_cells (Screen *screen, Visual *visual)
490 {
491   Display *dpy = DisplayOfScreen (screen);
492   XVisualInfo vi_in, *vi_out;
493   int out_count, c;
494   vi_in.screen = screen_number (screen);
495   vi_in.visualid = XVisualIDFromVisual (visual);
496   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
497                            &vi_in, &out_count);
498   if (! vi_out) abort ();
499   c = vi_out [0].colormap_size;
500   XFree ((char *) vi_out);
501   return c;
502 }
503
504 Visual *
505 find_similar_visual(Screen *screen, Visual *old_visual)
506 {
507   Display *dpy = DisplayOfScreen (screen);
508   XVisualInfo vi_in, *vi_out;
509   Visual *result = 0;
510   int out_count;
511
512   vi_in.screen = screen_number (screen);
513   vi_in.class  = visual_class (screen, old_visual);
514   vi_in.depth  = visual_depth (screen, old_visual);
515
516   /* Look for a visual of the same class and depth.
517    */
518   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask |
519                                  VisualDepthMask),
520                            &vi_in, &out_count);
521   if (vi_out && out_count > 0)
522     result = vi_out[0].visual;
523   if (vi_out) XFree (vi_out);
524   vi_out = 0;
525
526   /* Failing that, look for a visual of the same class.
527    */
528   if (!result)
529     {
530       vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask),
531                                &vi_in, &out_count);
532       if (vi_out && out_count > 0)
533         result = vi_out[0].visual;
534       if (vi_out) XFree (vi_out);
535       vi_out = 0;
536     }
537
538   /* Failing that, return the default visual. */
539   if (!result)
540     result = DefaultVisualOfScreen (screen);
541
542   return result;
543 }