blob: 57b73151c53f6a4cd7a7c3611c08f389520bb573 [file] [log] [blame]
Daniel Stenberg9f6733f2002-03-25 14:21:30 +00001/* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999
2 * by Jamie Zawinski <jwz@jwz.org>
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
24extern 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
35static Visual *pick_best_visual (Screen *, Bool, Bool);
36static Visual *pick_mono_visual (Screen *);
37static Visual *pick_best_visual_of_class (Screen *, int);
38static Visual *pick_best_gl_visual (Screen *);
39static Visual *id_to_visual (Screen *, int);
40static Visual *id_to_visual (Screen *screen, int id);
41
42
43#define DEFAULT_VISUAL -1
44#define BEST_VISUAL -2
45#define MONO_VISUAL -3
46#define GRAY_VISUAL -4
47#define COLOR_VISUAL -5
48#define GL_VISUAL -6
49#define SPECIFIC_VISUAL -7
50
51Visual *
52get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
53 Bool verbose_p)
54{
55 char *v = (string ? strdup(string) : 0);
56 char c, *tmp;
57 int vclass;
58 unsigned long id;
59 Visual *result = 0;
60
61 if (v)
62 for (tmp = v; *tmp; tmp++)
63 if (isupper (*tmp)) *tmp = _tolower (*tmp);
64
65 if (!v || !*v) vclass = BEST_VISUAL;
66 else if (!strcmp (v, "default")) vclass = DEFAULT_VISUAL;
67 else if (!strcmp (v, "best")) vclass = BEST_VISUAL;
68 else if (!strcmp (v, "mono")) vclass = MONO_VISUAL;
69 else if (!strcmp (v, "monochrome")) vclass = MONO_VISUAL;
70 else if (!strcmp (v, "gray")) vclass = GRAY_VISUAL;
71 else if (!strcmp (v, "grey")) vclass = GRAY_VISUAL;
72 else if (!strcmp (v, "color")) vclass = COLOR_VISUAL;
73 else if (!strcmp (v, "gl")) vclass = GL_VISUAL;
74 else if (!strcmp (v, "staticgray")) vclass = StaticGray;
75 else if (!strcmp (v, "staticcolor")) vclass = StaticColor;
76 else if (!strcmp (v, "truecolor")) vclass = TrueColor;
77 else if (!strcmp (v, "grayscale")) vclass = GrayScale;
78 else if (!strcmp (v, "greyscale")) 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
89 if (vclass == DEFAULT_VISUAL)
90 result = DefaultVisualOfScreen (screen);
91 else if (vclass == BEST_VISUAL)
92 result = pick_best_visual (screen, prefer_writable_cells, False);
93 else if (vclass == MONO_VISUAL)
94 {
95 result = pick_mono_visual (screen);
96 if (!result && verbose_p)
97 fprintf (stderr, "%s: no monochrome visuals.\n", progname);
98 }
99 else if (vclass == GRAY_VISUAL)
100 {
101 if (prefer_writable_cells)
102 result = pick_best_visual_of_class (screen, GrayScale);
103 if (!result)
104 result = pick_best_visual_of_class (screen, StaticGray);
105 if (!result)
106 result = pick_best_visual_of_class (screen, GrayScale);
107 if (!result && verbose_p)
108 fprintf (stderr, "%s: no GrayScale or StaticGray visuals.\n",
109 progname);
110 }
111 else if (vclass == COLOR_VISUAL)
112 {
113 int class;
114 /* First see if the default visual will do. */
115 result = DefaultVisualOfScreen (screen);
116 class = visual_class(screen, result);
117 if (class != TrueColor &&
118 class != PseudoColor &&
119 class != DirectColor &&
120 class != StaticColor)
121 result = 0;
122 if (result && visual_depth(screen, result) <= 1)
123 result = 0;
124
125 /* Else, find the best non-default color visual */
126 if (!result)
127 result = pick_best_visual (screen, prefer_writable_cells, True);
128
129 if (!result && verbose_p)
130 fprintf (stderr, "%s: no color visuals.\n", progname);
131 }
132 else if (vclass == GL_VISUAL)
133 {
134 Visual *visual = pick_best_gl_visual (screen);
135 if (visual)
136 result = visual;
137 else if (verbose_p)
138 fprintf (stderr, "%s: no visual suitable for GL.\n", progname);
139 }
140 else if (vclass == SPECIFIC_VISUAL)
141 {
142 result = id_to_visual (screen, id);
143 if (!result && verbose_p)
144 fprintf (stderr, "%s: no visual with id 0x%x.\n", progname,
145 (unsigned int) id);
146 }
147 else
148 {
149 Visual *visual = pick_best_visual_of_class (screen, vclass);
150 if (visual)
151 result = visual;
152 else if (verbose_p)
153 fprintf (stderr, "%s: no visual of class %s.\n", progname, v);
154 }
155
156 if (v) free (v);
157 return result;
158}
159
160Visual *
161get_visual_resource (Screen *screen, char *name, char *class,
162 Bool prefer_writable_cells)
163{
164 char *string = get_string_resource (name, class);
165 Visual *v = get_visual (screen, string, prefer_writable_cells, True);
166 if (string)
167 free(string);
168 if (v)
169 return v;
170 else
171 return DefaultVisualOfScreen (screen);
172}
173
174
175static Visual *
176pick_best_visual (Screen *screen, Bool prefer_writable_cells, Bool color_only)
177{
178 Visual *visual;
179
180 if (!prefer_writable_cells)
181 {
182 /* If we don't prefer writable cells, then the "best" visual is the one
183 on which we can allocate the largest range and number of colors.
184
185 Therefore, a TrueColor visual which is at least 16 bits deep is best.
186 (The assumption here being that a TrueColor of less than 16 bits is
187 really just a PseudoColor visual with a pre-allocated color cube.)
188
189 The next best thing is a PseudoColor visual of any type. After that
190 come the non-colormappable visuals, and non-color visuals.
191 */
192 if ((visual = pick_best_visual_of_class (screen, TrueColor)) &&
193 visual_depth (screen, visual) >= 16)
194 return visual;
195 }
196
197#define TRY_CLASS(CLASS) \
198 if ((visual = pick_best_visual_of_class (screen, CLASS)) && \
199 (!color_only || visual_depth(screen, visual) > 1)) \
200 return visual
201 TRY_CLASS(PseudoColor);
202 TRY_CLASS(TrueColor);
203 TRY_CLASS(DirectColor);
204 TRY_CLASS(StaticColor);
205 if (!color_only)
206 {
207 TRY_CLASS(GrayScale);
208 TRY_CLASS(StaticGray);
209 }
210#undef TRY_CLASS
211
212 visual = DefaultVisualOfScreen (screen);
213 if (!color_only || visual_depth(screen, visual) > 1)
214 return visual;
215 else
216 return 0;
217}
218
219static Visual *
220pick_mono_visual (Screen *screen)
221{
222 Display *dpy = DisplayOfScreen (screen);
223 XVisualInfo vi_in, *vi_out;
224 int out_count;
225
226 vi_in.depth = 1;
227 vi_in.screen = screen_number (screen);
228 vi_out = XGetVisualInfo (dpy, (VisualDepthMask | VisualScreenMask),
229 &vi_in, &out_count);
230 if (vi_out)
231 {
232 Visual *v = (out_count > 0 ? vi_out [0].visual : 0);
233 if (v && vi_out[0].depth != 1)
234 v = 0;
235 XFree ((char *) vi_out);
236 return v;
237 }
238 else
239 return 0;
240}
241
242
243static Visual *
244pick_best_visual_of_class (Screen *screen, int visual_class)
245{
246 /* The best visual of a class is the one which on which we can allocate
247 the largest range and number of colors, which means the one with the
248 greatest depth and number of cells.
249
250 (But actually, for XDaliClock, all visuals of the same class are
251 probably equivalent - either we have writable cells or we don't.)
252 */
253 Display *dpy = DisplayOfScreen (screen);
254 XVisualInfo vi_in, *vi_out;
255 int out_count;
256
257 vi_in.class = visual_class;
258 vi_in.screen = screen_number (screen);
259 vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask),
260 &vi_in, &out_count);
261 if (vi_out)
262 {
263 /* choose the 'best' one, if multiple */
264 int i, best;
265 Visual *visual;
266/* for (i = 0, best = 0; i < out_count; i++) */
267 for (i = out_count-1, best = i; i >= 0; i--) /* go backwards */
268 /* It's better if it's deeper, or if it's the same depth with
269 more cells (does that ever happen? Well, it could...) */
270 if ((vi_out [i].depth > vi_out [best].depth) ||
271 ((vi_out [i].depth == vi_out [best].depth) &&
272 (vi_out [i].colormap_size > vi_out [best].colormap_size)))
273 best = i;
274 visual = (best < out_count ? vi_out [best].visual : 0);
275 XFree ((char *) vi_out);
276 return visual;
277 }
278 else
279 return 0;
280}
281
282static Visual *
283pick_best_gl_visual (Screen *screen)
284{
285 /* The best visual for GL is a TrueColor visual that is half as deep as
286 the screen. If such a thing doesn't exist, then TrueColor is best.
287 Failing that, the deepest available color visual is best.
288
289 Compare this function to get_gl_visual() in visual-gl.c.
290 This function tries to find the best GL visual using Xlib calls,
291 whereas that function does the same thing using GLX calls.
292 */
293 Display *dpy = DisplayOfScreen (screen);
294 XVisualInfo vi_in, *vi_out;
295 int out_count;
296 Visual *result = 0;
297
298 int ndepths = 0;
299 int *depths = XListDepths (dpy, screen_number (screen), &ndepths);
300 int screen_depth = depths[ndepths];
301 XFree (depths);
302
303 vi_in.class = TrueColor;
304 vi_in.screen = screen_number (screen);
305 vi_in.depth = screen_depth / 2;
306 vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
307 VisualDepthMask),
308 &vi_in, &out_count);
309 if (out_count > 0)
310 result = vi_out[0].visual;
311
312 if (vi_out)
313 XFree ((char *) vi_out);
314
315 if (!result && screen_depth > 24)
316 {
317 /* If it's a 32-deep screen and we didn't find a depth-16 visual,
318 see if there's a depth-12 visual. */
319 vi_in.class = TrueColor;
320 vi_in.screen = screen_number (screen);
321 vi_in.depth = 12;
322 vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
323 VisualDepthMask),
324 &vi_in, &out_count);
325 if (out_count > 0)
326 result = vi_out[0].visual;
327 }
328
329 if (!result)
330 /* No half-depth TrueColor? Ok, try for any TrueColor (the deepest.) */
331 result = pick_best_visual_of_class (screen, TrueColor);
332
333 if (!result)
334 /* No TrueColor? Ok, try for anything. */
335 result = pick_best_visual (screen, False, False);
336
337 return result;
338}
339
340
341static Visual *
342id_to_visual (Screen *screen, int id)
343{
344 Display *dpy = DisplayOfScreen (screen);
345 XVisualInfo vi_in, *vi_out;
346 int out_count;
347 vi_in.screen = screen_number (screen);
348 vi_in.visualid = id;
349 vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
350 &vi_in, &out_count);
351 if (vi_out)
352 {
353 Visual *v = vi_out[0].visual;
354 XFree ((char *) vi_out);
355 return v;
356 }
357 return 0;
358}
359
360int
361visual_depth (Screen *screen, Visual *visual)
362{
363 Display *dpy = DisplayOfScreen (screen);
364 XVisualInfo vi_in, *vi_out;
365 int out_count, d;
366 vi_in.screen = screen_number (screen);
367 vi_in.visualid = XVisualIDFromVisual (visual);
368 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
369 &vi_in, &out_count);
370 if (! vi_out) abort ();
371 d = vi_out [0].depth;
372 XFree ((char *) vi_out);
373 return d;
374}
375
376
377#if 0
378/* You very probably don't want to be using this.
379 Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
380 the depth of protocol-level on-the-wire pixmap data, that is, XImages.
381 To get this info, you should be looking at XImage->bits_per_pixel
382 instead. (And allocating the data for your XImage structures by
383 multiplying ximage->bytes_per_line by ximage->height.)
384 */
385int
386visual_pixmap_depth (Screen *screen, Visual *visual)
387{
388 Display *dpy = DisplayOfScreen (screen);
389 int vdepth = visual_depth (screen, visual);
390 int pdepth = vdepth;
391 int i, pfvc = 0;
392 XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
393
394 /* Return the first matching depth in the pixmap formats. If there are no
395 matching pixmap formats (which shouldn't be able to happen at all) then
396 return the visual depth instead. */
397 for (i = 0; i < pfvc; i++)
398 if (pfv[i].depth == vdepth)
399 {
400 pdepth = pfv[i].bits_per_pixel;
401 break;
402 }
403 if (pfv)
404 XFree (pfv);
405 return pdepth;
406}
407#endif /* 0 */
408
409
410int
411visual_class (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].class;
422 XFree ((char *) vi_out);
423 return c;
424}
425
426Bool
427has_writable_cells (Screen *screen, Visual *visual)
428{
429 switch (visual_class (screen, visual))
430 {
431 case GrayScale: /* Mappable grays. */
432 case PseudoColor: /* Mappable colors. */
433 return True;
434 case StaticGray: /* Fixed grays. */
435 case TrueColor: /* Fixed colors. */
436 case StaticColor: /* (What's the difference again?) */
437 case DirectColor: /* DirectColor visuals are like TrueColor, but have
438 three colormaps - one for each component of RGB.
439 Screw it. */
440 return False;
441 default:
442 abort();
443 return False;
444 }
445}
446
447void
448describe_visual (FILE *f, Screen *screen, Visual *visual, Bool private_cmap_p)
449{
450 char n[10];
451 Display *dpy = DisplayOfScreen (screen);
452 XVisualInfo vi_in, *vi_out;
453 int out_count;
454 vi_in.screen = screen_number (screen);
455 vi_in.visualid = XVisualIDFromVisual (visual);
456 vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
457 &vi_in, &out_count);
458 if (! vi_out) abort ();
459 if (private_cmap_p)
460 sprintf(n, "%3d", vi_out->colormap_size);
461 else
462 strcpy(n, "default");
463
464 fprintf (f, "0x%02x (%s depth: %2d, cmap: %s)\n",
465 (unsigned int) vi_out->visualid,
466 (vi_out->class == StaticGray ? "StaticGray, " :
467 vi_out->class == StaticColor ? "StaticColor," :
468 vi_out->class == TrueColor ? "TrueColor, " :
469 vi_out->class == GrayScale ? "GrayScale, " :
470 vi_out->class == PseudoColor ? "PseudoColor," :
471 vi_out->class == DirectColor ? "DirectColor," :
472 "UNKNOWN: "),
473 vi_out->depth, n);
474 XFree ((char *) vi_out);
475}
476
477int
478screen_number (Screen *screen)
479{
480 Display *dpy = DisplayOfScreen (screen);
481 int i;
482 for (i = 0; i < ScreenCount (dpy); i++)
483 if (ScreenOfDisplay (dpy, i) == screen)
484 return i;
485 abort ();
486 return 0;
487}
488
489int
490visual_cells (Screen *screen, Visual *visual)
491{
492 Display *dpy = DisplayOfScreen (screen);
493 XVisualInfo vi_in, *vi_out;
494 int out_count, c;
495 vi_in.screen = screen_number (screen);
496 vi_in.visualid = XVisualIDFromVisual (visual);
497 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
498 &vi_in, &out_count);
499 if (! vi_out) abort ();
500 c = vi_out [0].colormap_size;
501 XFree ((char *) vi_out);
502 return c;
503}
504
505Visual *
506find_similar_visual(Screen *screen, Visual *old_visual)
507{
508 Display *dpy = DisplayOfScreen (screen);
509 XVisualInfo vi_in, *vi_out;
510 Visual *result = 0;
511 int out_count;
512
513 vi_in.screen = screen_number (screen);
514 vi_in.class = visual_class (screen, old_visual);
515 vi_in.depth = visual_depth (screen, old_visual);
516
517 /* Look for a visual of the same class and depth.
518 */
519 vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask |
520 VisualDepthMask),
521 &vi_in, &out_count);
522 if (vi_out && out_count > 0)
523 result = vi_out[0].visual;
524 if (vi_out) XFree (vi_out);
525 vi_out = 0;
526
527 /* Failing that, look for a visual of the same class.
528 */
529 if (!result)
530 {
531 vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask),
532 &vi_in, &out_count);
533 if (vi_out && out_count > 0)
534 result = vi_out[0].visual;
535 if (vi_out) XFree (vi_out);
536 vi_out = 0;
537 }
538
539 /* Failing that, return the default visual. */
540 if (!result)
541 result = DefaultVisualOfScreen (screen);
542
543 return result;
544}