1 /* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
2 * by Jamie Zawinski <jwz@jwz.org>
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
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...)
19 #include "resources.h" /* for get_string_resource() */
23 #include <X11/Xutil.h>
25 extern char *progname;
29 # define isupper(c) ((c) >= 'A' && (c) <= 'Z')
32 # define _tolower(c) ((c) - 'A' + 'a')
36 static Visual *pick_best_visual (Screen *, Bool, Bool);
37 static Visual *pick_mono_visual (Screen *);
38 static Visual *pick_best_visual_of_class (Screen *, int);
39 static Visual *pick_best_gl_visual (Screen *);
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
48 #define SPECIFIC_VISUAL -7
51 get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
54 char *v = (string ? strdup(string) : 0);
61 for (tmp = v; *tmp; tmp++)
62 if (isupper (*tmp)) *tmp = _tolower (*tmp);
64 if (!v || !*v) vclass = BEST_VISUAL;
65 else if (!strcmp (v, "default")) vclass = DEFAULT_VISUAL;
66 else if (!strcmp (v, "best")) vclass = BEST_VISUAL;
67 else if (!strcmp (v, "mono")) vclass = MONO_VISUAL;
68 else if (!strcmp (v, "monochrome")) vclass = MONO_VISUAL;
69 else if (!strcmp (v, "gray")) vclass = GRAY_VISUAL;
70 else if (!strcmp (v, "grey")) vclass = GRAY_VISUAL;
71 else if (!strcmp (v, "color")) vclass = COLOR_VISUAL;
72 else if (!strcmp (v, "gl")) vclass = GL_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, "greyscale")) vclass = GrayScale;
78 else if (!strcmp (v, "pseudocolor")) vclass = PseudoColor;
79 else if (!strcmp (v, "directcolor")) vclass = DirectColor;
80 else if (1 == sscanf (v, " %ld %c", &id, &c)) vclass = SPECIFIC_VISUAL;
81 else if (1 == sscanf (v, " 0x%lx %c", &id, &c)) vclass = SPECIFIC_VISUAL;
84 fprintf (stderr, "%s: unrecognized visual \"%s\".\n", progname, v);
85 vclass = DEFAULT_VISUAL;
88 if (vclass == DEFAULT_VISUAL)
89 result = DefaultVisualOfScreen (screen);
90 else if (vclass == BEST_VISUAL)
91 result = pick_best_visual (screen, prefer_writable_cells, False);
92 else if (vclass == MONO_VISUAL)
94 result = pick_mono_visual (screen);
95 if (!result && verbose_p)
96 fprintf (stderr, "%s: no monochrome visuals.\n", progname);
98 else if (vclass == GRAY_VISUAL)
100 if (prefer_writable_cells)
101 result = pick_best_visual_of_class (screen, GrayScale);
103 result = pick_best_visual_of_class (screen, StaticGray);
105 result = pick_best_visual_of_class (screen, GrayScale);
106 if (!result && verbose_p)
107 fprintf (stderr, "%s: no GrayScale or StaticGray visuals.\n",
110 else if (vclass == COLOR_VISUAL)
113 /* First see if the default visual will do. */
114 result = DefaultVisualOfScreen (screen);
115 class = visual_class(screen, result);
116 if (class != TrueColor &&
117 class != PseudoColor &&
118 class != DirectColor &&
119 class != StaticColor)
121 if (result && visual_depth(screen, result) <= 1)
124 /* Else, find the best non-default color visual */
126 result = pick_best_visual (screen, prefer_writable_cells, True);
128 if (!result && verbose_p)
129 fprintf (stderr, "%s: no color visuals.\n", progname);
131 else if (vclass == GL_VISUAL)
133 Visual *visual = pick_best_gl_visual (screen);
137 fprintf (stderr, "%s: no visual suitable for GL.\n", progname);
139 else if (vclass == SPECIFIC_VISUAL)
141 result = id_to_visual (screen, id);
142 if (!result && verbose_p)
143 fprintf (stderr, "%s: no visual with id 0x%x.\n", progname,
148 Visual *visual = pick_best_visual_of_class (screen, vclass);
152 fprintf (stderr, "%s: no visual of class %s.\n", progname, v);
160 get_visual_resource (Screen *screen, char *name, char *class,
161 Bool prefer_writable_cells)
163 char *string = get_string_resource (name, class);
164 Visual *v = get_visual (screen, string, prefer_writable_cells, True);
170 return DefaultVisualOfScreen (screen);
175 pick_best_visual (Screen *screen, Bool prefer_writable_cells, Bool color_only)
179 if (!prefer_writable_cells)
181 /* If we don't prefer writable cells, then the "best" visual is the one
182 on which we can allocate the largest range and number of colors.
184 Therefore, a TrueColor visual which is at least 16 bits deep is best.
185 (The assumption here being that a TrueColor of less than 16 bits is
186 really just a PseudoColor visual with a pre-allocated color cube.)
188 The next best thing is a PseudoColor visual of any type. After that
189 come the non-colormappable visuals, and non-color visuals.
191 if ((visual = pick_best_visual_of_class (screen, TrueColor)) &&
192 visual_depth (screen, visual) >= 16)
196 #define TRY_CLASS(CLASS) \
197 if ((visual = pick_best_visual_of_class (screen, CLASS)) && \
198 (!color_only || visual_depth(screen, visual) > 1)) \
200 TRY_CLASS(PseudoColor);
201 TRY_CLASS(TrueColor);
202 TRY_CLASS(DirectColor);
203 TRY_CLASS(StaticColor);
206 TRY_CLASS(GrayScale);
207 TRY_CLASS(StaticGray);
211 visual = DefaultVisualOfScreen (screen);
212 if (!color_only || visual_depth(screen, visual) > 1)
219 pick_mono_visual (Screen *screen)
221 Display *dpy = DisplayOfScreen (screen);
222 XVisualInfo vi_in, *vi_out;
226 vi_in.screen = screen_number (screen);
227 vi_out = XGetVisualInfo (dpy, (VisualDepthMask | VisualScreenMask),
231 Visual *v = (out_count > 0 ? vi_out [0].visual : 0);
232 if (v && vi_out[0].depth != 1)
234 XFree ((char *) vi_out);
243 pick_best_visual_of_class (Screen *screen, int visual_class)
245 /* The best visual of a class is the one which on which we can allocate
246 the largest range and number of colors, which means the one with the
247 greatest depth and number of cells.
249 (But actually, for XDaliClock, all visuals of the same class are
250 probably equivalent - either we have writable cells or we don't.)
252 Display *dpy = DisplayOfScreen (screen);
253 XVisualInfo vi_in, *vi_out;
256 vi_in.class = visual_class;
257 vi_in.screen = screen_number (screen);
258 vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask),
262 /* choose the 'best' one, if multiple */
265 /* for (i = 0, best = 0; i < out_count; i++) */
266 for (i = out_count-1, best = i; i >= 0; i--) /* go backwards */
267 /* It's better if it's deeper, or if it's the same depth with
268 more cells (does that ever happen? Well, it could...) */
269 if ((vi_out [i].depth > vi_out [best].depth) ||
270 ((vi_out [i].depth == vi_out [best].depth) &&
271 (vi_out [i].colormap_size > vi_out [best].colormap_size)))
273 visual = (best < out_count ? vi_out [best].visual : 0);
274 XFree ((char *) vi_out);
282 pick_best_gl_visual (Screen *screen)
284 /* The best visual for GL is a TrueColor visual that is half as deep as
285 the screen. If such a thing doesn't exist, then TrueColor is best.
286 Failing that, the deepest available color visual is best.
288 Compare this function to get_gl_visual() in visual-gl.c.
289 This function tries to find the best GL visual using Xlib calls,
290 whereas that function does the same thing using GLX calls.
292 Display *dpy = DisplayOfScreen (screen);
293 XVisualInfo vi_in, *vi_out;
298 int *depths = XListDepths (dpy, screen_number (screen), &ndepths);
299 int screen_depth = depths[ndepths];
302 vi_in.class = TrueColor;
303 vi_in.screen = screen_number (screen);
304 vi_in.depth = screen_depth / 2;
305 vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
309 result = vi_out[0].visual;
312 XFree ((char *) vi_out);
314 if (!result && screen_depth > 24)
316 /* If it's a 32-deep screen and we didn't find a depth-16 visual,
317 see if there's a depth-12 visual. */
318 vi_in.class = TrueColor;
319 vi_in.screen = screen_number (screen);
321 vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
325 result = vi_out[0].visual;
329 /* No half-depth TrueColor? Ok, try for any TrueColor (the deepest.) */
330 result = pick_best_visual_of_class (screen, TrueColor);
333 /* No TrueColor? Ok, try for anything. */
334 result = pick_best_visual (screen, False, False);
341 id_to_visual (Screen *screen, int id)
343 Display *dpy = DisplayOfScreen (screen);
344 XVisualInfo vi_in, *vi_out;
346 vi_in.screen = screen_number (screen);
348 vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
352 Visual *v = vi_out[0].visual;
353 XFree ((char *) vi_out);
360 visual_depth (Screen *screen, Visual *visual)
362 Display *dpy = DisplayOfScreen (screen);
363 XVisualInfo vi_in, *vi_out;
365 vi_in.screen = screen_number (screen);
366 vi_in.visualid = XVisualIDFromVisual (visual);
367 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
369 if (! vi_out) abort ();
370 d = vi_out [0].depth;
371 XFree ((char *) vi_out);
377 /* You very probably don't want to be using this.
378 Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
379 the depth of protocol-level on-the-wire pixmap data, that is, XImages.
380 To get this info, you should be looking at XImage->bits_per_pixel
381 instead. (And allocating the data for your XImage structures by
382 multiplying ximage->bytes_per_line by ximage->height.)
385 visual_pixmap_depth (Screen *screen, Visual *visual)
387 Display *dpy = DisplayOfScreen (screen);
388 int vdepth = visual_depth (screen, visual);
391 XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
393 /* Return the first matching depth in the pixmap formats. If there are no
394 matching pixmap formats (which shouldn't be able to happen at all) then
395 return the visual depth instead. */
396 for (i = 0; i < pfvc; i++)
397 if (pfv[i].depth == vdepth)
399 pdepth = pfv[i].bits_per_pixel;
410 visual_class (Screen *screen, Visual *visual)
412 Display *dpy = DisplayOfScreen (screen);
413 XVisualInfo vi_in, *vi_out;
415 vi_in.screen = screen_number (screen);
416 vi_in.visualid = XVisualIDFromVisual (visual);
417 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
419 if (! vi_out) abort ();
420 c = vi_out [0].class;
421 XFree ((char *) vi_out);
426 has_writable_cells (Screen *screen, Visual *visual)
428 switch (visual_class (screen, visual))
430 case GrayScale: /* Mappable grays. */
431 case PseudoColor: /* Mappable colors. */
432 case DirectColor: /* Like TrueColor, but with three colormaps:
433 one each for red, green, and blue. */
435 case StaticGray: /* Fixed grays. */
436 case TrueColor: /* Fixed colors. */
437 case StaticColor: /* Like PseudoColor with an unmodifiable colormap. */
446 describe_visual (FILE *f, Screen *screen, Visual *visual, Bool private_cmap_p)
449 Display *dpy = DisplayOfScreen (screen);
450 XVisualInfo vi_in, *vi_out;
452 vi_in.screen = screen_number (screen);
453 vi_in.visualid = XVisualIDFromVisual (visual);
454 vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
456 if (! vi_out) abort ();
458 sprintf(n, "%3d", vi_out->colormap_size);
460 strcpy(n, "default");
462 fprintf (f, "0x%02x (%s depth: %2d, cmap: %s)\n",
463 (unsigned int) vi_out->visualid,
464 (vi_out->class == StaticGray ? "StaticGray, " :
465 vi_out->class == StaticColor ? "StaticColor," :
466 vi_out->class == TrueColor ? "TrueColor, " :
467 vi_out->class == GrayScale ? "GrayScale, " :
468 vi_out->class == PseudoColor ? "PseudoColor," :
469 vi_out->class == DirectColor ? "DirectColor," :
472 XFree ((char *) vi_out);
476 screen_number (Screen *screen)
478 Display *dpy = DisplayOfScreen (screen);
480 for (i = 0; i < ScreenCount (dpy); i++)
481 if (ScreenOfDisplay (dpy, i) == screen)
488 visual_cells (Screen *screen, Visual *visual)
490 Display *dpy = DisplayOfScreen (screen);
491 XVisualInfo vi_in, *vi_out;
493 vi_in.screen = screen_number (screen);
494 vi_in.visualid = XVisualIDFromVisual (visual);
495 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
497 if (! vi_out) abort ();
498 c = vi_out [0].colormap_size;
499 XFree ((char *) vi_out);
504 find_similar_visual(Screen *screen, Visual *old_visual)
506 Display *dpy = DisplayOfScreen (screen);
507 XVisualInfo vi_in, *vi_out;
511 vi_in.screen = screen_number (screen);
512 vi_in.class = visual_class (screen, old_visual);
513 vi_in.depth = visual_depth (screen, old_visual);
515 /* Look for a visual of the same class and depth.
517 vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask |
520 if (vi_out && out_count > 0)
521 result = vi_out[0].visual;
522 if (vi_out) XFree (vi_out);
525 /* Failing that, look for a visual of the same class.
529 vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask),
531 if (vi_out && out_count > 0)
532 result = vi_out[0].visual;
533 if (vi_out) XFree (vi_out);
537 /* Failing that, return the default visual. */
539 result = DefaultVisualOfScreen (screen);