From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / utils / visual.c
1 /* xscreensaver, Copyright (c) 1993-2017 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 #ifndef HAVE_ANDROID
23 #include <X11/Xutil.h>
24 #else
25 #include "../android/android-visual.h"
26 #endif
27
28 extern char *progname;
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) ? depths[ndepths - 1] : 0;
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 static XVisualInfo *
343 visual_info_id (Screen *screen, int id)
344 {
345   Display *dpy = DisplayOfScreen (screen);
346   XVisualInfo vi_in;
347   int out_count;
348   vi_in.screen = screen_number (screen);
349   vi_in.visualid = id;
350   return XGetVisualInfo (dpy, VisualScreenMask | VisualIDMask,
351                          &vi_in, &out_count);
352 }
353
354 static XVisualInfo *
355 visual_info (Screen *screen, Visual *visual)
356 {
357   XVisualInfo *vi_out = visual_info_id (screen, XVisualIDFromVisual (visual));
358   if (! vi_out) abort ();
359   return vi_out;
360 }
361
362 Visual *
363 id_to_visual (Screen *screen, int id)
364 {
365   XVisualInfo *vi_out = visual_info_id (screen, id);
366   if (vi_out)
367     {
368       Visual *v = vi_out[0].visual;
369       XFree ((char *) vi_out);
370       return v;
371     }
372   return 0;
373 }
374
375 int
376 visual_depth (Screen *screen, Visual *visual)
377 {
378   XVisualInfo *vi_out = visual_info (screen, visual);
379   int d = vi_out [0].depth;
380   XFree ((char *) vi_out);
381   return d;
382 }
383
384
385 /* You very probably don't want to be using this.
386    Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
387    the depth of protocol-level on-the-wire pixmap data, that is, XImages.
388    To get this info, you should be looking at XImage->bits_per_pixel
389    instead.  (And allocating the data for your XImage structures by
390    multiplying ximage->bytes_per_line by ximage->height.)
391
392    Still, it can be useful to know bits_per_pixel before the XImage exists.
393
394    XCreateImage calls _XGetBitsPerPixel to figure this out, but that function
395    is private to Xlib.
396
397    For some reason, _XGetBitsPerPixel tries a hard-coded list of depths if
398    it doesn't find a matching pixmap format, but I (Dave Odell) couldn't
399    find any justification for this in the X11 spec. And the XFree86 CVS
400    repository doesn't quite go back far enough to shed any light on what
401    the deal is with that.
402    http://cvsweb.xfree86.org/cvsweb/xc/lib/X11/ImUtil.c
403
404    The hard-coded list apparently was added between X11R5 and X11R6.
405    See <ftp://ftp.x.org/pub/>.
406  */
407 int
408 visual_pixmap_depth (Screen *screen, Visual *visual)
409 {
410   Display *dpy = DisplayOfScreen (screen);
411   int vdepth = visual_depth (screen, visual);
412   int pdepth = vdepth;
413   int i, pfvc = 0;
414   XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
415
416   /* Return the first matching depth in the pixmap formats.  If there are no
417      matching pixmap formats (which shouldn't be able to happen at all) then
418      return the visual depth instead. */
419   for (i = 0; i < pfvc; i++)
420     if (pfv[i].depth == vdepth)
421       {
422         pdepth = pfv[i].bits_per_pixel;
423         break;
424       }
425   if (pfv)
426     XFree (pfv);
427   return pdepth;
428 }
429
430
431 int
432 visual_class (Screen *screen, Visual *visual)
433 {
434   XVisualInfo *vi_out = visual_info (screen, visual);
435   int c = vi_out [0].class;
436   XFree ((char *) vi_out);
437   return c;
438 }
439
440 Bool
441 has_writable_cells (Screen *screen, Visual *visual)
442 {
443   switch (visual_class (screen, visual))
444     {
445     case GrayScale:     /* Mappable grays. */
446     case PseudoColor:   /* Mappable colors. */
447     case DirectColor:   /* Like TrueColor, but with three colormaps:
448                            one each for red, green, and blue. */
449       return True;
450     case StaticGray:    /* Fixed grays. */
451     case TrueColor:     /* Fixed colors. */
452     case StaticColor:   /* Like PseudoColor with an unmodifiable colormap. */
453       return False;
454     default:
455       abort();
456       return False;
457     }
458 }
459
460 void
461 describe_visual (FILE *f, Screen *screen, Visual *visual, Bool private_cmap_p)
462 {
463   char n[10];
464   XVisualInfo *vi_out = visual_info (screen, visual);
465   if (private_cmap_p)
466     sprintf(n, "%3d", vi_out->colormap_size);
467   else
468     strcpy(n, "default");
469
470   fprintf (f, "0x%02x (%s depth: %2d, cmap: %s)\n",
471            (unsigned int) vi_out->visualid,
472            (vi_out->class == StaticGray  ? "StaticGray, " :
473             vi_out->class == StaticColor ? "StaticColor," :
474             vi_out->class == TrueColor   ? "TrueColor,  " :
475             vi_out->class == GrayScale   ? "GrayScale,  " :
476             vi_out->class == PseudoColor ? "PseudoColor," :
477             vi_out->class == DirectColor ? "DirectColor," :
478                                            "UNKNOWN:    "),
479            vi_out->depth, n);
480   XFree ((char *) vi_out);
481 }
482
483 int
484 screen_number (Screen *screen)
485 {
486   Display *dpy = DisplayOfScreen (screen);
487   int i;
488   for (i = 0; i < ScreenCount (dpy); i++)
489     if (ScreenOfDisplay (dpy, i) == screen)
490       return i;
491   abort ();
492   return 0;
493 }
494
495 int
496 visual_cells (Screen *screen, Visual *visual)
497 {
498   XVisualInfo *vi_out = visual_info (screen, visual);
499   int 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 }
544
545
546 void
547 visual_rgb_masks (Screen *screen, Visual *visual, unsigned long *red_mask,
548                   unsigned long *green_mask, unsigned long *blue_mask)
549 {
550   XVisualInfo *vi_out = visual_info (screen, visual);
551   *red_mask = vi_out->red_mask;
552   *green_mask = vi_out->green_mask;
553   *blue_mask = vi_out->blue_mask;
554   XFree ((char *) vi_out);
555 }