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 *
get_visual(Screen * screen,const char * string,Bool prefer_writable_cells,Bool verbose_p)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 *
get_visual_resource(Screen * screen,char * name,char * class,Bool prefer_writable_cells)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 *
pick_best_visual(Screen * screen,Bool prefer_writable_cells,Bool color_only)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 *
pick_mono_visual(Screen * screen)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 *
pick_best_visual_of_class(Screen * screen,int visual_class)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 *
pick_best_gl_visual(Screen * screen)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 *
visual_info_id(Screen * screen,int id)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 *
visual_info(Screen * screen,Visual * visual)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 *
id_to_visual(Screen * screen,int id)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
visual_depth(Screen * screen,Visual * visual)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
visual_pixmap_depth(Screen * screen,Visual * visual)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
visual_class(Screen * screen,Visual * visual)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
has_writable_cells(Screen * screen,Visual * visual)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
describe_visual(FILE * f,Screen * screen,Visual * visual,Bool private_cmap_p)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
screen_number(Screen * screen)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
visual_cells(Screen * screen,Visual * visual)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 *
find_similar_visual(Screen * screen,Visual * old_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
visual_rgb_masks(Screen * screen,Visual * visual,unsigned long * red_mask,unsigned long * green_mask,unsigned long * blue_mask)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 }
556