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