ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-2.07.tar.gz
[xscreensaver] / utils / visual.c
1 /* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997
2  *  by Jamie Zawinski <jwz@netscape.com>
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 <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 *id_to_visual (Screen *, int);
39 static Visual *id_to_visual (Screen *screen, int id);
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 SPECIFIC_VISUAL -6
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)                                         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, "staticgray"))             vclass = StaticGray;
72   else if (!strcmp (v, "staticcolor"))            vclass = StaticColor;
73   else if (!strcmp (v, "truecolor"))              vclass = TrueColor;
74   else if (!strcmp (v, "grayscale"))              vclass = GrayScale;
75   else if (!strcmp (v, "greyscale"))              vclass = GrayScale;
76   else if (!strcmp (v, "pseudocolor"))            vclass = PseudoColor;
77   else if (!strcmp (v, "directcolor"))            vclass = DirectColor;
78   else if (1 == sscanf (v, " %ld %c", &id, &c))   vclass = SPECIFIC_VISUAL;
79   else if (1 == sscanf (v, " 0x%lx %c", &id, &c)) vclass = SPECIFIC_VISUAL;
80   else
81     {
82       fprintf (stderr, "%s: unrecognized visual \"%s\".\n", progname, v);
83       vclass = DEFAULT_VISUAL;
84     }
85
86   if (vclass == DEFAULT_VISUAL)
87     result = DefaultVisualOfScreen (screen);
88   else if (vclass == BEST_VISUAL)
89     result = pick_best_visual (screen, prefer_writable_cells, False);
90   else if (vclass == MONO_VISUAL)
91     {
92       result = pick_mono_visual (screen);
93       if (!result && verbose_p)
94         fprintf (stderr, "%s: no monochrome visuals.\n", progname);
95     }
96   else if (vclass == GRAY_VISUAL)
97     {
98       if (prefer_writable_cells)
99         result = pick_best_visual_of_class (screen, GrayScale);
100       if (!result)
101         result = pick_best_visual_of_class (screen, StaticGray);
102       if (!result)
103         result = pick_best_visual_of_class (screen, GrayScale);
104       if (!result && verbose_p)
105         fprintf (stderr, "%s: no GrayScale or StaticGray visuals.\n",
106                  progname);
107     }
108   else if (vclass == COLOR_VISUAL)
109     {
110       int class;
111       /* First see if the default visual will do. */
112       result = DefaultVisualOfScreen (screen);
113       class = visual_class(screen, result);
114       if (class != TrueColor &&
115           class != PseudoColor &&
116           class != DirectColor &&
117           class != StaticColor)
118         result = 0;
119       if (result && visual_depth(screen, result) <= 1)
120         result = 0;
121
122       /* Else, find the best non-default color visual */
123       if (!result)
124         result = pick_best_visual (screen, prefer_writable_cells, True);
125
126       if (!result && verbose_p)
127         fprintf (stderr, "%s: no color visuals.\n", progname);
128     }
129   else if (vclass == SPECIFIC_VISUAL)
130     {
131       result = id_to_visual (screen, id);
132       if (!result && verbose_p)
133         fprintf (stderr, "%s: no visual with id 0x%x.\n", progname,
134                  (unsigned int) id);
135     }
136   else
137     {
138       Visual *visual = pick_best_visual_of_class (screen, vclass);
139       if (visual)
140         result = visual;
141       else if (verbose_p)
142         fprintf (stderr, "%s: no visual of class %s.\n", progname, v);
143     }
144
145   if (v) free (v);
146   return result;
147 }
148
149 Visual *
150 get_visual_resource (Screen *screen, char *name, char *class,
151                      Bool prefer_writable_cells)
152 {
153   char *string = get_string_resource (name, class);
154   Visual *v = get_visual (screen, string, prefer_writable_cells, True);
155   if (string)
156     free(string);
157   if (v)
158     return v;
159   else
160     return DefaultVisualOfScreen (screen);
161 }
162
163
164 static Visual *
165 pick_best_visual (Screen *screen, Bool prefer_writable_cells, Bool color_only)
166 {
167   Visual *visual;
168
169   if (!prefer_writable_cells)
170     {
171       /* If we don't prefer writable cells, then the "best" visual is the one
172          on which we can allocate the largest range and number of colors.
173
174          Therefore, a TrueColor visual which is at least 16 bits deep is best.
175          (The assumption here being that a TrueColor of less than 16 bits is
176          really just a PseudoColor visual with a pre-allocated color cube.)
177
178          The next best thing is a PseudoColor visual of any type.  After that
179          come the non-colormappable visuals, and non-color visuals.
180        */
181       if ((visual = pick_best_visual_of_class (screen, TrueColor)) &&
182           visual_depth (screen, visual) >= 16)
183         return visual;
184     }
185
186 #define TRY_CLASS(CLASS) \
187   if ((visual = pick_best_visual_of_class (screen, CLASS)) && \
188       (!color_only || visual_depth(screen, visual) > 1)) \
189     return visual
190   TRY_CLASS(PseudoColor);
191   TRY_CLASS(TrueColor);
192   TRY_CLASS(DirectColor);
193   TRY_CLASS(StaticColor);
194   if (!color_only)
195     {
196       TRY_CLASS(GrayScale);
197       TRY_CLASS(StaticGray);
198     }
199 #undef TRY_CLASS
200
201   visual = DefaultVisualOfScreen (screen);
202   if (!color_only || visual_depth(screen, visual) > 1)
203     return visual;
204   else
205     return 0;
206 }
207
208 static Visual *
209 pick_mono_visual (Screen *screen)
210 {
211   Display *dpy = DisplayOfScreen (screen);
212   XVisualInfo vi_in, *vi_out;
213   int out_count;
214
215   vi_in.depth = 1;
216   vi_in.screen = screen_number (screen);
217   vi_out = XGetVisualInfo (dpy, (VisualDepthMask | VisualScreenMask),
218                            &vi_in, &out_count);
219   if (vi_out)
220     {
221       Visual *v = (out_count > 0 ? vi_out [0].visual : 0);
222       if (v && vi_out[0].depth != 1)
223         v = 0;
224       XFree ((char *) vi_out);
225       return v;
226     }
227   else
228     return 0;
229 }
230
231
232 static Visual *
233 pick_best_visual_of_class (Screen *screen, int visual_class)
234 {
235   /* The best visual of a class is the one which on which we can allocate
236      the largest range and number of colors, which means the one with the
237      greatest depth and number of cells.
238
239      (But actually, for XDaliClock, all visuals of the same class are
240      probably equivalent - either we have writable cells or we don't.)
241    */
242   Display *dpy = DisplayOfScreen (screen);
243   XVisualInfo vi_in, *vi_out;
244   int out_count;
245
246   vi_in.class = visual_class;
247   vi_in.screen = screen_number (screen);
248   vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask),
249                            &vi_in, &out_count);
250   if (vi_out)
251     {
252       /* choose the 'best' one, if multiple */
253       int i, best;
254       Visual *visual;
255       for (i = 0, best = 0; i < out_count; i++)
256         /* It's better if it's deeper, or if it's the same depth with
257            more cells (does that ever happen?  Well, it could...) */
258         if ((vi_out [i].depth > vi_out [best].depth) ||
259             ((vi_out [i].depth == vi_out [best].depth) &&
260              (vi_out [i].colormap_size > vi_out [best].colormap_size)))
261           best = i;
262       visual = (best < out_count ? vi_out [best].visual : 0);
263       XFree ((char *) vi_out);
264       return visual;
265     }
266   else
267     return 0;
268 }
269
270 static Visual *
271 id_to_visual (Screen *screen, int id)
272 {
273   Display *dpy = DisplayOfScreen (screen);
274   XVisualInfo vi_in, *vi_out;
275   int out_count;
276   vi_in.screen = screen_number (screen);
277   vi_in.visualid = id;
278   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
279                            &vi_in, &out_count);
280   if (vi_out)
281     {
282       Visual *v = vi_out[0].visual;
283       XFree ((char *) vi_out);
284       return v;
285     }
286   return 0;
287 }
288
289 int
290 visual_depth (Screen *screen, Visual *visual)
291 {
292   Display *dpy = DisplayOfScreen (screen);
293   XVisualInfo vi_in, *vi_out;
294   int out_count, d;
295   vi_in.screen = screen_number (screen);
296   vi_in.visualid = XVisualIDFromVisual (visual);
297   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
298                            &vi_in, &out_count);
299   if (! vi_out) abort ();
300   d = vi_out [0].depth;
301   XFree ((char *) vi_out);
302   return d;
303 }
304
305
306 int
307 visual_class (Screen *screen, Visual *visual)
308 {
309   Display *dpy = DisplayOfScreen (screen);
310   XVisualInfo vi_in, *vi_out;
311   int out_count, c;
312   vi_in.screen = screen_number (screen);
313   vi_in.visualid = XVisualIDFromVisual (visual);
314   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
315                            &vi_in, &out_count);
316   if (! vi_out) abort ();
317   c = vi_out [0].class;
318   XFree ((char *) vi_out);
319   return c;
320 }
321
322 Bool
323 has_writable_cells (Screen *screen, Visual *visual)
324 {
325   switch (visual_class (screen, visual))
326     {
327     case GrayScale:     /* Mappable grays. */
328     case PseudoColor:   /* Mappable colors. */
329       return True;
330     case StaticGray:    /* Fixed grays. */
331     case TrueColor:     /* Fixed colors. */
332     case StaticColor:   /* (What's the difference again?) */
333     case DirectColor:   /* DirectColor visuals are like TrueColor, but have
334                            three colormaps - one for each component of RGB.
335                            Screw it. */
336       return False;
337     default:
338       abort();
339     }
340 }
341
342 void
343 describe_visual (FILE *f, Screen *screen, Visual *visual)
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 = XVisualIDFromVisual (visual);
350   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
351                            &vi_in, &out_count);
352   if (! vi_out) abort ();
353   fprintf (f, "0x%02x (%s depth: %2d, cmap: %3d)\n",
354            (unsigned int) vi_out->visualid,
355            (vi_out->class == StaticGray  ? "StaticGray, " :
356             vi_out->class == StaticColor ? "StaticColor," :
357             vi_out->class == TrueColor   ? "TrueColor,  " :
358             vi_out->class == GrayScale   ? "GrayScale,  " :
359             vi_out->class == PseudoColor ? "PseudoColor," :
360             vi_out->class == DirectColor ? "DirectColor," :
361                                            "UNKNOWN:    "),
362            vi_out->depth, vi_out->colormap_size /*, vi_out->bits_per_rgb*/);
363   XFree ((char *) vi_out);
364 }
365
366 int
367 screen_number (Screen *screen)
368 {
369   Display *dpy = DisplayOfScreen (screen);
370   int i;
371   for (i = 0; i < ScreenCount (dpy); i++)
372     if (ScreenOfDisplay (dpy, i) == screen)
373       return i;
374   abort ();
375 }
376
377 int
378 visual_cells (Screen *screen, Visual *visual)
379 {
380   Display *dpy = DisplayOfScreen (screen);
381   XVisualInfo vi_in, *vi_out;
382   int out_count, c;
383   vi_in.screen = screen_number (screen);
384   vi_in.visualid = XVisualIDFromVisual (visual);
385   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
386                            &vi_in, &out_count);
387   if (! vi_out) abort ();
388   c = vi_out [0].colormap_size;
389   XFree ((char *) vi_out);
390   return c;
391 }
392
393 Visual *
394 find_similar_visual(Screen *screen, Visual *old_visual)
395 {
396   Display *dpy = DisplayOfScreen (screen);
397   XVisualInfo vi_in, *vi_out;
398   Visual *result = 0;
399   int out_count;
400
401   vi_in.screen = screen_number (screen);
402   vi_in.class  = visual_class (screen, old_visual);
403   vi_in.depth  = visual_depth (screen, old_visual);
404
405   /* Look for a visual of the same class and depth.
406    */
407   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask |
408                                  VisualDepthMask),
409                            &vi_in, &out_count);
410   if (vi_out && out_count > 0)
411     result = vi_out[0].visual;
412   if (vi_out) XFree (vi_out);
413   vi_out = 0;
414
415   /* Failing that, look for a visual of the same class.
416    */
417   if (!result)
418     {
419       vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask),
420                                &vi_in, &out_count);
421       if (vi_out && out_count > 0)
422         result = vi_out[0].visual;
423       if (vi_out) XFree (vi_out);
424       vi_out = 0;
425     }
426
427   /* Failing that, return the default visual. */
428   if (!result)
429     result = DefaultVisualOfScreen (screen);
430
431   return result;
432 }