From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / utils / visual.c
index a570bcc4342e9653bf70efe53bdc8e0043610b99..89b4f33e69f3d7af84fc2a5931ae594c1916a47e 100644 (file)
@@ -1,5 +1,4 @@
-/* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
- *  by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1993-2014 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
@@ -35,8 +38,7 @@ extern char *progname;
 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
@@ -44,7 +46,8 @@ static Visual *id_to_visual (Screen *screen, int id);
 #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,
@@ -60,7 +63,7 @@ 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;
@@ -68,6 +71,7 @@ get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
   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;
@@ -75,7 +79,7 @@ get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
   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
     {
@@ -126,6 +130,14 @@ get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
       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);
@@ -150,7 +162,7 @@ Visual *
 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);
@@ -252,7 +264,8 @@ pick_best_visual_of_class (Screen *screen, int visual_class)
       /* 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) ||
@@ -268,6 +281,65 @@ pick_best_visual_of_class (Screen *screen, int visual_class)
 }
 
 static Visual *
+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.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;
+}
+
+
+Visual *
 id_to_visual (Screen *screen, int id)
 {
   Display *dpy = DisplayOfScreen (screen);
@@ -359,13 +431,12 @@ has_writable_cells (Screen *screen, Visual *visual)
     {
     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();
@@ -471,3 +542,48 @@ find_similar_visual(Screen *screen, Visual *old_visual)
 
   return result;
 }
+
+
+int
+get_bits_per_pixel(Display *dpy, int depth)
+{
+  unsigned i = 0;
+  int count, result;
+  XPixmapFormatValues *formats = XListPixmapFormats(dpy, &count);
+
+  /* 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/>.
+   */
+
+  if (!formats) return 0;
+
+  for (;;)
+    {
+      if (i == (unsigned)count)
+        {
+          result = 0;
+          break;
+        }
+
+      if (formats[i].depth == depth)
+        {
+          result = formats[i].bits_per_pixel;
+          break;
+        }
+
+      ++i;
+    }
+
+  XFree (formats);
+  return result;
+}