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