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