-/* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
- * by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1993-2017 by Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
#include "resources.h" /* for get_string_resource() */
#include "visual.h"
+#include <string.h>
+#ifndef HAVE_ANDROID
#include <X11/Xutil.h>
+#else
+#include "../android/android-visual.h"
+#endif
extern char *progname;
-
#ifndef isupper
# define isupper(c) ((c) >= 'A' && (c) <= 'Z')
#endif
static Visual *pick_best_visual (Screen *, Bool, Bool);
static Visual *pick_mono_visual (Screen *);
static Visual *pick_best_visual_of_class (Screen *, int);
-static Visual *id_to_visual (Screen *, int);
-static Visual *id_to_visual (Screen *screen, int id);
+static Visual *pick_best_gl_visual (Screen *);
#define DEFAULT_VISUAL -1
#define MONO_VISUAL -3
#define GRAY_VISUAL -4
#define COLOR_VISUAL -5
-#define SPECIFIC_VISUAL -6
+#define GL_VISUAL -6
+#define SPECIFIC_VISUAL -7
Visual *
get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
for (tmp = v; *tmp; tmp++)
if (isupper (*tmp)) *tmp = _tolower (*tmp);
- if (!v) vclass = BEST_VISUAL;
+ if (!v || !*v) vclass = BEST_VISUAL;
else if (!strcmp (v, "default")) vclass = DEFAULT_VISUAL;
else if (!strcmp (v, "best")) vclass = BEST_VISUAL;
else if (!strcmp (v, "mono")) vclass = MONO_VISUAL;
else if (!strcmp (v, "gray")) vclass = GRAY_VISUAL;
else if (!strcmp (v, "grey")) vclass = GRAY_VISUAL;
else if (!strcmp (v, "color")) vclass = COLOR_VISUAL;
+ else if (!strcmp (v, "gl")) vclass = GL_VISUAL;
else if (!strcmp (v, "staticgray")) vclass = StaticGray;
else if (!strcmp (v, "staticcolor")) vclass = StaticColor;
else if (!strcmp (v, "truecolor")) vclass = TrueColor;
else if (!strcmp (v, "greyscale")) vclass = GrayScale;
else if (!strcmp (v, "pseudocolor")) vclass = PseudoColor;
else if (!strcmp (v, "directcolor")) vclass = DirectColor;
- else if (1 == sscanf (v, " %ld %c", &id, &c)) vclass = SPECIFIC_VISUAL;
+ else if (1 == sscanf (v, " %lu %c", &id, &c)) vclass = SPECIFIC_VISUAL;
else if (1 == sscanf (v, " 0x%lx %c", &id, &c)) vclass = SPECIFIC_VISUAL;
else
{
if (!result && verbose_p)
fprintf (stderr, "%s: no color visuals.\n", progname);
}
+ else if (vclass == GL_VISUAL)
+ {
+ Visual *visual = pick_best_gl_visual (screen);
+ if (visual)
+ result = visual;
+ else if (verbose_p)
+ fprintf (stderr, "%s: no visual suitable for GL.\n", progname);
+ }
else if (vclass == SPECIFIC_VISUAL)
{
result = id_to_visual (screen, id);
get_visual_resource (Screen *screen, char *name, char *class,
Bool prefer_writable_cells)
{
- char *string = get_string_resource (name, class);
+ char *string = get_string_resource (DisplayOfScreen (screen), name, class);
Visual *v = get_visual (screen, string, prefer_writable_cells, True);
if (string)
free(string);
/* choose the 'best' one, if multiple */
int i, best;
Visual *visual;
- for (i = 0, best = 0; i < out_count; i++)
+/* for (i = 0, best = 0; i < out_count; i++) */
+ for (i = out_count-1, best = i; i >= 0; i--) /* go backwards */
/* It's better if it's deeper, or if it's the same depth with
more cells (does that ever happen? Well, it could...) */
if ((vi_out [i].depth > vi_out [best].depth) ||
}
static Visual *
-id_to_visual (Screen *screen, int id)
+pick_best_gl_visual (Screen *screen)
{
+ /* The best visual for GL is a TrueColor visual that is half as deep as
+ the screen. If such a thing doesn't exist, then TrueColor is best.
+ Failing that, the deepest available color visual is best.
+
+ Compare this function to get_gl_visual() in visual-gl.c.
+ This function tries to find the best GL visual using Xlib calls,
+ whereas that function does the same thing using GLX calls.
+ */
Display *dpy = DisplayOfScreen (screen);
XVisualInfo vi_in, *vi_out;
int out_count;
+ Visual *result = 0;
+
+ int ndepths = 0;
+ int *depths = XListDepths (dpy, screen_number (screen), &ndepths);
+ int screen_depth = (depths && ndepths) ? depths[ndepths - 1] : 0;
+ XFree (depths);
+
+ vi_in.class = TrueColor;
vi_in.screen = screen_number (screen);
- vi_in.visualid = id;
- vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
+ vi_in.depth = screen_depth / 2;
+ vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
+ VisualDepthMask),
&vi_in, &out_count);
+ if (out_count > 0)
+ result = vi_out[0].visual;
+
+ if (vi_out)
+ XFree ((char *) vi_out);
+
+ if (!result && screen_depth > 24)
+ {
+ /* If it's a 32-deep screen and we didn't find a depth-16 visual,
+ see if there's a depth-12 visual. */
+ vi_in.class = TrueColor;
+ vi_in.screen = screen_number (screen);
+ vi_in.depth = 12;
+ vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
+ VisualDepthMask),
+ &vi_in, &out_count);
+ if (out_count > 0)
+ result = vi_out[0].visual;
+ }
+
+ if (!result)
+ /* No half-depth TrueColor? Ok, try for any TrueColor (the deepest.) */
+ result = pick_best_visual_of_class (screen, TrueColor);
+
+ if (!result)
+ /* No TrueColor? Ok, try for anything. */
+ result = pick_best_visual (screen, False, False);
+
+ return result;
+}
+
+
+static XVisualInfo *
+visual_info_id (Screen *screen, int id)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XVisualInfo vi_in;
+ int out_count;
+ vi_in.screen = screen_number (screen);
+ vi_in.visualid = id;
+ return XGetVisualInfo (dpy, VisualScreenMask | VisualIDMask,
+ &vi_in, &out_count);
+}
+
+static XVisualInfo *
+visual_info (Screen *screen, Visual *visual)
+{
+ XVisualInfo *vi_out = visual_info_id (screen, XVisualIDFromVisual (visual));
+ if (! vi_out) abort ();
+ return vi_out;
+}
+
+Visual *
+id_to_visual (Screen *screen, int id)
+{
+ XVisualInfo *vi_out = visual_info_id (screen, id);
if (vi_out)
{
Visual *v = vi_out[0].visual;
int
visual_depth (Screen *screen, Visual *visual)
{
- Display *dpy = DisplayOfScreen (screen);
- XVisualInfo vi_in, *vi_out;
- int out_count, d;
- vi_in.screen = screen_number (screen);
- vi_in.visualid = XVisualIDFromVisual (visual);
- vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
- &vi_in, &out_count);
- if (! vi_out) abort ();
- d = vi_out [0].depth;
+ XVisualInfo *vi_out = visual_info (screen, visual);
+ int d = vi_out [0].depth;
XFree ((char *) vi_out);
return d;
}
-#if 0
/* You very probably don't want to be using this.
Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
the depth of protocol-level on-the-wire pixmap data, that is, XImages.
To get this info, you should be looking at XImage->bits_per_pixel
instead. (And allocating the data for your XImage structures by
multiplying ximage->bytes_per_line by ximage->height.)
+
+ Still, it can be useful to know bits_per_pixel before the XImage exists.
+
+ XCreateImage calls _XGetBitsPerPixel to figure this out, but that function
+ is private to Xlib.
+
+ For some reason, _XGetBitsPerPixel tries a hard-coded list of depths if
+ it doesn't find a matching pixmap format, but I (Dave Odell) couldn't
+ find any justification for this in the X11 spec. And the XFree86 CVS
+ repository doesn't quite go back far enough to shed any light on what
+ the deal is with that.
+ http://cvsweb.xfree86.org/cvsweb/xc/lib/X11/ImUtil.c
+
+ The hard-coded list apparently was added between X11R5 and X11R6.
+ See <ftp://ftp.x.org/pub/>.
*/
int
visual_pixmap_depth (Screen *screen, Visual *visual)
XFree (pfv);
return pdepth;
}
-#endif /* 0 */
int
visual_class (Screen *screen, Visual *visual)
{
- Display *dpy = DisplayOfScreen (screen);
- XVisualInfo vi_in, *vi_out;
- int out_count, c;
- vi_in.screen = screen_number (screen);
- vi_in.visualid = XVisualIDFromVisual (visual);
- vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
- &vi_in, &out_count);
- if (! vi_out) abort ();
- c = vi_out [0].class;
+ XVisualInfo *vi_out = visual_info (screen, visual);
+ int c = vi_out [0].class;
XFree ((char *) vi_out);
return c;
}
{
case GrayScale: /* Mappable grays. */
case PseudoColor: /* Mappable colors. */
+ case DirectColor: /* Like TrueColor, but with three colormaps:
+ one each for red, green, and blue. */
return True;
case StaticGray: /* Fixed grays. */
case TrueColor: /* Fixed colors. */
- case StaticColor: /* (What's the difference again?) */
- case DirectColor: /* DirectColor visuals are like TrueColor, but have
- three colormaps - one for each component of RGB.
- Screw it. */
+ case StaticColor: /* Like PseudoColor with an unmodifiable colormap. */
return False;
default:
abort();
describe_visual (FILE *f, Screen *screen, Visual *visual, Bool private_cmap_p)
{
char n[10];
- Display *dpy = DisplayOfScreen (screen);
- XVisualInfo vi_in, *vi_out;
- int out_count;
- vi_in.screen = screen_number (screen);
- vi_in.visualid = XVisualIDFromVisual (visual);
- vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
- &vi_in, &out_count);
- if (! vi_out) abort ();
+ XVisualInfo *vi_out = visual_info (screen, visual);
if (private_cmap_p)
sprintf(n, "%3d", vi_out->colormap_size);
else
int
visual_cells (Screen *screen, Visual *visual)
{
- Display *dpy = DisplayOfScreen (screen);
- XVisualInfo vi_in, *vi_out;
- int out_count, c;
- vi_in.screen = screen_number (screen);
- vi_in.visualid = XVisualIDFromVisual (visual);
- vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
- &vi_in, &out_count);
- if (! vi_out) abort ();
- c = vi_out [0].colormap_size;
+ XVisualInfo *vi_out = visual_info (screen, visual);
+ int c = vi_out [0].colormap_size;
XFree ((char *) vi_out);
return c;
}
return result;
}
+
+
+void
+visual_rgb_masks (Screen *screen, Visual *visual, unsigned long *red_mask,
+ unsigned long *green_mask, unsigned long *blue_mask)
+{
+ XVisualInfo *vi_out = visual_info (screen, visual);
+ *red_mask = vi_out->red_mask;
+ *green_mask = vi_out->green_mask;
+ *blue_mask = vi_out->blue_mask;
+ XFree ((char *) vi_out);
+}