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