c83643601773299068623af60775a641a513c36a
[xscreensaver] / utils / visual.c
1 /* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
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 #if 0
307 /* You very probably don't want to be using this.
308    Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
309    the depth of protocol-level on-the-wire pixmap data, that is, XImages.
310    To get this info, you should be looking at XImage->bits_per_pixel
311    instead.  (And allocating the data for your XImage structures by
312    multiplying ximage->bytes_per_line by ximage->height.)
313  */
314 int
315 visual_pixmap_depth (Screen *screen, Visual *visual)
316 {
317   Display *dpy = DisplayOfScreen (screen);
318   int vdepth = visual_depth (screen, visual);
319   int pdepth = vdepth;
320   int i, pfvc = 0;
321   XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
322
323   /* Return the first matching depth in the pixmap formats.  If there are no
324      matching pixmap formats (which shouldn't be able to happen at all) then
325      return the visual depth instead. */
326   for (i = 0; i < pfvc; i++)
327     if (pfv[i].depth == vdepth)
328       {
329         pdepth = pfv[i].bits_per_pixel;
330         break;
331       }
332   if (pfv)
333     XFree (pfv);
334   return pdepth;
335 }
336 #endif /* 0 */
337
338
339 int
340 visual_class (Screen *screen, Visual *visual)
341 {
342   Display *dpy = DisplayOfScreen (screen);
343   XVisualInfo vi_in, *vi_out;
344   int out_count, c;
345   vi_in.screen = screen_number (screen);
346   vi_in.visualid = XVisualIDFromVisual (visual);
347   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
348                            &vi_in, &out_count);
349   if (! vi_out) abort ();
350   c = vi_out [0].class;
351   XFree ((char *) vi_out);
352   return c;
353 }
354
355 Bool
356 has_writable_cells (Screen *screen, Visual *visual)
357 {
358   switch (visual_class (screen, visual))
359     {
360     case GrayScale:     /* Mappable grays. */
361     case PseudoColor:   /* Mappable colors. */
362       return True;
363     case StaticGray:    /* Fixed grays. */
364     case TrueColor:     /* Fixed colors. */
365     case StaticColor:   /* (What's the difference again?) */
366     case DirectColor:   /* DirectColor visuals are like TrueColor, but have
367                            three colormaps - one for each component of RGB.
368                            Screw it. */
369       return False;
370     default:
371       abort();
372     }
373 }
374
375 void
376 describe_visual (FILE *f, Screen *screen, Visual *visual)
377 {
378   Display *dpy = DisplayOfScreen (screen);
379   XVisualInfo vi_in, *vi_out;
380   int out_count;
381   vi_in.screen = screen_number (screen);
382   vi_in.visualid = XVisualIDFromVisual (visual);
383   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
384                            &vi_in, &out_count);
385   if (! vi_out) abort ();
386   fprintf (f, "0x%02x (%s depth: %2d, cmap: %3d)\n",
387            (unsigned int) vi_out->visualid,
388            (vi_out->class == StaticGray  ? "StaticGray, " :
389             vi_out->class == StaticColor ? "StaticColor," :
390             vi_out->class == TrueColor   ? "TrueColor,  " :
391             vi_out->class == GrayScale   ? "GrayScale,  " :
392             vi_out->class == PseudoColor ? "PseudoColor," :
393             vi_out->class == DirectColor ? "DirectColor," :
394                                            "UNKNOWN:    "),
395            vi_out->depth, vi_out->colormap_size /*, vi_out->bits_per_rgb*/);
396   XFree ((char *) vi_out);
397 }
398
399 int
400 screen_number (Screen *screen)
401 {
402   Display *dpy = DisplayOfScreen (screen);
403   int i;
404   for (i = 0; i < ScreenCount (dpy); i++)
405     if (ScreenOfDisplay (dpy, i) == screen)
406       return i;
407   abort ();
408 }
409
410 int
411 visual_cells (Screen *screen, Visual *visual)
412 {
413   Display *dpy = DisplayOfScreen (screen);
414   XVisualInfo vi_in, *vi_out;
415   int out_count, c;
416   vi_in.screen = screen_number (screen);
417   vi_in.visualid = XVisualIDFromVisual (visual);
418   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
419                            &vi_in, &out_count);
420   if (! vi_out) abort ();
421   c = vi_out [0].colormap_size;
422   XFree ((char *) vi_out);
423   return c;
424 }
425
426 Visual *
427 find_similar_visual(Screen *screen, Visual *old_visual)
428 {
429   Display *dpy = DisplayOfScreen (screen);
430   XVisualInfo vi_in, *vi_out;
431   Visual *result = 0;
432   int out_count;
433
434   vi_in.screen = screen_number (screen);
435   vi_in.class  = visual_class (screen, old_visual);
436   vi_in.depth  = visual_depth (screen, old_visual);
437
438   /* Look for a visual of the same class and depth.
439    */
440   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask |
441                                  VisualDepthMask),
442                            &vi_in, &out_count);
443   if (vi_out && out_count > 0)
444     result = vi_out[0].visual;
445   if (vi_out) XFree (vi_out);
446   vi_out = 0;
447
448   /* Failing that, look for a visual of the same class.
449    */
450   if (!result)
451     {
452       vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask),
453                                &vi_in, &out_count);
454       if (vi_out && out_count > 0)
455         result = vi_out[0].visual;
456       if (vi_out) XFree (vi_out);
457       vi_out = 0;
458     }
459
460   /* Failing that, return the default visual. */
461   if (!result)
462     result = DefaultVisualOfScreen (screen);
463
464   return result;
465 }