ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-1.25.tar.Z
[xscreensaver] / utils / visual.c
1 /* xscreensaver, Copyright (c) 1993, 1994, 1995 Jamie Zawinski <jwz@mcom.com>
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 high color counts...)
14  */
15
16 #if __STDC__
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #endif
21
22 #include <stdio.h>
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25
26 #if __STDC__
27 # define P(x)x
28 #else
29 #define P(x)()
30 #endif
31
32 #ifndef isupper
33 # define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
34 #endif
35 #ifndef _tolower
36 # define _tolower(c)  ((c) - 'A' + 'a')
37 #endif
38
39 extern char *progname;
40 extern char *get_string_resource P((char *, char *));
41
42 static Visual *pick_best_visual P ((Screen *));
43 static Visual *pick_best_visual_of_class P((Screen *, int));
44 static Visual *id_to_visual P((Screen *, int));
45 static int screen_number P((Screen *));
46 static Visual *id_to_visual P((Screen *screen, int id));
47 int get_visual_depth P((Display *dpy, Visual *visual));
48
49
50 #define DEFAULT_VISUAL  -1
51 #define BEST_VISUAL     -2
52 #define SPECIFIC_VISUAL -3
53
54 Visual *
55 get_visual_resource (dpy, name, class)
56      Display *dpy;
57      char *name, *class;
58 {
59   Screen *screen = DefaultScreenOfDisplay (dpy);
60   char c, *v = get_string_resource (name, class);
61   char *tmp;
62   int vclass;
63   unsigned long id;
64
65   if (v)
66     for (tmp = v; *tmp; tmp++)
67       if (isupper (*tmp)) *tmp = _tolower (*tmp);
68
69   if (!v)                                         vclass = BEST_VISUAL;
70   else if (!strcmp (v, "default"))                vclass = DEFAULT_VISUAL;
71   else if (!strcmp (v, "best"))                   vclass = BEST_VISUAL;
72   else if (!strcmp (v, "staticgray"))             vclass = StaticGray;
73   else if (!strcmp (v, "staticcolor"))            vclass = StaticColor;
74   else if (!strcmp (v, "truecolor"))              vclass = TrueColor;
75   else if (!strcmp (v, "grayscale"))              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   if (v) free (v);
86
87   if (vclass == DEFAULT_VISUAL)
88     return DefaultVisualOfScreen (screen);
89   else if (vclass == BEST_VISUAL)
90     return pick_best_visual (screen);
91   else if (vclass == SPECIFIC_VISUAL)
92     {
93       Visual *visual = id_to_visual (screen, id);
94       if (visual) return visual;
95       fprintf (stderr, "%s: no visual with id 0x%x.\n", progname,
96                (unsigned int) id);
97       return DefaultVisualOfScreen (screen);
98     }
99   else
100     {
101       Visual *visual = pick_best_visual_of_class (screen, vclass);
102       if (visual) return visual;
103       fprintf (stderr, "%s: no visual of class %s.\n", progname, v);
104       return DefaultVisualOfScreen (screen);
105     }
106 }
107
108 static Visual *
109 pick_best_visual (screen)
110         Screen *screen;
111 {
112   /* The "best" visual is the one on which we can allocate the largest
113      range and number of colors.
114
115      Therefore, a TrueColor visual which is at least 16 bits deep is best.
116      (The assumption here being that a TrueColor of less than 16 bits is
117      really just a PseudoColor visual with a pre-allocated color cube.)
118
119      The next best thing is a PseudoColor visual of any type.  After that
120      come the non-colormappable visuals, and non-color visuals.
121    */
122   Display *dpy = DisplayOfScreen (screen);
123   Visual *visual;
124   if ((visual = pick_best_visual_of_class (screen, TrueColor)) &&
125       get_visual_depth (dpy, visual) >= 16)
126     return visual;
127   if ((visual = pick_best_visual_of_class (screen, PseudoColor)))
128     return visual;
129   if ((visual = pick_best_visual_of_class (screen, TrueColor)))
130     return visual;
131   if ((visual = pick_best_visual_of_class (screen, DirectColor)))
132     return visual;
133   if ((visual = pick_best_visual_of_class (screen, GrayScale)))
134     return visual;
135   if ((visual = pick_best_visual_of_class (screen, StaticGray)))
136     return visual;
137   return DefaultVisualOfScreen (screen);
138 }
139
140 static Visual *
141 pick_best_visual_of_class (screen, visual_class)
142      Screen *screen;
143      int visual_class;
144 {
145   /* The best visual of a class is the one which on which we can allocate
146      the largest range and number of colors, which means the one with the
147      greatest depth and number of cells.
148    */
149   Display *dpy = DisplayOfScreen (screen);
150   XVisualInfo vi_in, *vi_out;
151   int out_count;
152
153   vi_in.class = visual_class;
154   vi_in.screen = screen_number (screen);
155   vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask),
156                            &vi_in, &out_count);
157   if (vi_out)
158     {
159       /* choose the 'best' one, if multiple */
160       int i, best;
161       Visual *visual;
162       for (i = 0, best = 0; i < out_count; i++)
163         /* It's better if it's deeper, or if it's the same depth with
164            more cells (does that ever happen?  Well, it could...) */
165         if ((vi_out [i].depth > vi_out [best].depth) ||
166             ((vi_out [i].depth == vi_out [best].depth) &&
167              (vi_out [i].colormap_size > vi_out [best].colormap_size)))
168           best = i;
169       visual = vi_out [best].visual;
170       XFree ((char *) vi_out);
171       return visual;
172     }
173   else
174     return 0;
175 }
176
177 static Visual *
178 id_to_visual (screen, id)
179      Screen *screen;
180      int id;
181 {
182   Display *dpy = DisplayOfScreen (screen);
183   XVisualInfo vi_in, *vi_out;
184   int out_count;
185   vi_in.screen = screen_number (screen);
186   vi_in.visualid = id;
187   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
188                            &vi_in, &out_count);
189   if (vi_out)
190     {
191       Visual *v = vi_out[0].visual;
192       XFree ((char *) vi_out);
193       return v;
194     }
195   return 0;
196 }
197
198 int
199 get_visual_depth (dpy, visual)
200      Display *dpy;
201      Visual *visual;
202 {
203   XVisualInfo vi_in, *vi_out;
204   int out_count, d;
205   vi_in.screen = DefaultScreen (dpy);
206   vi_in.visualid = XVisualIDFromVisual (visual);
207   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
208                            &vi_in, &out_count);
209   if (! vi_out) abort ();
210   d = vi_out [0].depth;
211   XFree ((char *) vi_out);
212   return d;
213 }
214
215
216 int
217 get_visual_class (dpy, visual)
218      Display *dpy;
219      Visual *visual;
220 {
221   XVisualInfo vi_in, *vi_out;
222   int out_count, c;
223   vi_in.screen = DefaultScreen (dpy);
224   vi_in.visualid = XVisualIDFromVisual (visual);
225   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
226                            &vi_in, &out_count);
227   if (! vi_out) abort ();
228   c = vi_out [0].class;
229   XFree ((char *) vi_out);
230   return c;
231 }
232
233 void
234 describe_visual (f, dpy, visual)
235      FILE *f;
236      Display *dpy;
237      Visual *visual;
238 {
239   Screen *screen = DefaultScreenOfDisplay (dpy);
240   XVisualInfo vi_in, *vi_out;
241   int out_count;
242   vi_in.screen = screen_number (screen);
243   vi_in.visualid = XVisualIDFromVisual (visual);
244   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
245                            &vi_in, &out_count);
246   if (! vi_out) abort ();
247   fprintf (f, "0x%02x (%s depth: %2d, cmap: %3d)\n",
248            (unsigned int) vi_out->visualid,
249            (vi_out->class == StaticGray  ? "StaticGray, " :
250             vi_out->class == StaticColor ? "StaticColor," :
251             vi_out->class == TrueColor   ? "TrueColor,  " :
252             vi_out->class == GrayScale   ? "GrayScale,  " :
253             vi_out->class == PseudoColor ? "PseudoColor," :
254             vi_out->class == DirectColor ? "DirectColor," :
255                                            "UNKNOWN:    "),
256            vi_out->depth, vi_out->colormap_size /*, vi_out->bits_per_rgb*/);
257   XFree ((char *) vi_out);
258 }
259
260 static int
261 screen_number (screen)
262         Screen *screen;
263 {
264   Display *dpy = DisplayOfScreen (screen);
265   int i;
266   for (i = 0; i < ScreenCount (dpy); i++)
267     if (ScreenOfDisplay (dpy, i) == screen)
268       return i;
269   abort ();
270 }
271
272 int
273 visual_cells (dpy, visual)
274         Display *dpy;
275         Visual *visual;
276 {
277   XVisualInfo vi_in, *vi_out;
278   int out_count, c;
279   vi_in.screen = DefaultScreen (dpy);
280   vi_in.visualid = XVisualIDFromVisual (visual);
281   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
282                            &vi_in, &out_count);
283   if (! vi_out) abort ();
284   c = vi_out [0].colormap_size;
285   XFree ((char *) vi_out);
286   return c;
287 }