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