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