Back to index

kdeartwork  4.3.2
xs_visual.c
Go to the documentation of this file.
00001 /* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
00002  *  by Jamie Zawinski <jwz@jwz.org>
00003  *
00004  * Permission to use, copy, modify, distribute, and sell this software and its
00005  * documentation for any purpose is hereby granted without fee, provided that
00006  * the above copyright notice appear in all copies and that both that
00007  * copyright notice and this permission notice appear in supporting
00008  * documentation.  No representations are made about the suitability of this
00009  * software for any purpose.  It is provided "as is" without express or 
00010  * implied warranty.
00011  */
00012 
00013 /* This file contains some code for intelligently picking the best visual
00014    (where "best" is biased in the direction of either: high color counts;
00015    or: having writable color cells...)
00016  */
00017 
00018 #include "xs_utils.h"
00019 
00020 #include "xs_visual.h"
00021 
00022 #include <X11/Xutil.h>
00023 
00024 /* extern char *progname; */
00025 
00026 
00027 #ifndef isupper
00028 # define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
00029 #endif
00030 #ifndef _tolower
00031 # define _tolower(c)  ((c) - 'A' + 'a')
00032 #endif
00033 
00034 
00035 static Visual *pick_best_visual (Screen *, Bool, Bool);
00036 static Visual *pick_mono_visual (Screen *);
00037 static Visual *pick_best_visual_of_class (Screen *, int);
00038 static Visual *id_to_visual (Screen *, int);
00039 static Visual *id_to_visual (Screen *screen, int id);
00040 
00041 
00042 #define DEFAULT_VISUAL      -1
00043 #define BEST_VISUAL  -2
00044 #define MONO_VISUAL  -3
00045 #define GRAY_VISUAL  -4
00046 #define COLOR_VISUAL -5
00047 #define SPECIFIC_VISUAL     -6
00048 
00049 Visual *
00050 get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
00051            Bool verbose_p)
00052 {
00053   char *v = (string ? strdup(string) : 0);
00054   char c, *tmp;
00055   int vclass;
00056   unsigned long id;
00057   Visual *result = 0;
00058 
00059   if (v)
00060     for (tmp = v; *tmp; tmp++)
00061       if (isupper (*tmp)) *tmp = _tolower (*tmp);
00062 
00063   if (!v)                                   vclass = BEST_VISUAL;
00064   else if (!strcmp (v, "default"))          vclass = DEFAULT_VISUAL;
00065   else if (!strcmp (v, "best"))             vclass = BEST_VISUAL;
00066   else if (!strcmp (v, "mono"))             vclass = MONO_VISUAL;
00067   else if (!strcmp (v, "monochrome"))              vclass = MONO_VISUAL;
00068   else if (!strcmp (v, "gray"))             vclass = GRAY_VISUAL;
00069   else if (!strcmp (v, "grey"))             vclass = GRAY_VISUAL;
00070   else if (!strcmp (v, "color"))            vclass = COLOR_VISUAL;
00071   else if (!strcmp (v, "staticgray"))              vclass = StaticGray;
00072   else if (!strcmp (v, "staticcolor"))             vclass = StaticColor;
00073   else if (!strcmp (v, "truecolor"))               vclass = TrueColor;
00074   else if (!strcmp (v, "grayscale"))               vclass = GrayScale;
00075   else if (!strcmp (v, "greyscale"))               vclass = GrayScale;
00076   else if (!strcmp (v, "pseudocolor"))             vclass = PseudoColor;
00077   else if (!strcmp (v, "directcolor"))             vclass = DirectColor;
00078   else if (1 == sscanf (v, " %ld %c", &id, &c))    vclass = SPECIFIC_VISUAL;
00079   else if (1 == sscanf (v, " 0x%lx %c", &id, &c)) vclass = SPECIFIC_VISUAL;
00080   else
00081     {
00082       fprintf (stderr, "%s: unrecognized visual \"%s\".\n", "kscreensaver", v);
00083       vclass = DEFAULT_VISUAL;
00084     }
00085 
00086   if (vclass == DEFAULT_VISUAL)
00087     result = DefaultVisualOfScreen (screen);
00088   else if (vclass == BEST_VISUAL)
00089     result = pick_best_visual (screen, prefer_writable_cells, False);
00090   else if (vclass == MONO_VISUAL)
00091     {
00092       result = pick_mono_visual (screen);
00093       if (!result && verbose_p)
00094        fprintf (stderr, "%s: no monochrome visuals.\n", "kscreensaver");
00095     }
00096   else if (vclass == GRAY_VISUAL)
00097     {
00098       if (prefer_writable_cells)
00099        result = pick_best_visual_of_class (screen, GrayScale);
00100       if (!result)
00101        result = pick_best_visual_of_class (screen, StaticGray);
00102       if (!result)
00103        result = pick_best_visual_of_class (screen, GrayScale);
00104       if (!result && verbose_p)
00105        fprintf (stderr, "%s: no GrayScale or StaticGray visuals.\n",
00106                "kscreensaver");
00107     }
00108   else if (vclass == COLOR_VISUAL)
00109     {
00110       int class;
00111       /* First see if the default visual will do. */
00112       result = DefaultVisualOfScreen (screen);
00113       class = visual_class(screen, result);
00114       if (class != TrueColor &&
00115          class != PseudoColor &&
00116          class != DirectColor &&
00117          class != StaticColor)
00118        result = 0;
00119       if (result && visual_depth(screen, result) <= 1)
00120        result = 0;
00121 
00122       /* Else, find the best non-default color visual */
00123       if (!result)
00124        result = pick_best_visual (screen, prefer_writable_cells, True);
00125 
00126       if (!result && verbose_p)
00127        fprintf (stderr, "%s: no color visuals.\n", "kscreensaver");
00128     }
00129   else if (vclass == SPECIFIC_VISUAL)
00130     {
00131       result = id_to_visual (screen, id);
00132       if (!result && verbose_p)
00133        fprintf (stderr, "%s: no visual with id 0x%x.\n", "kscreensaver",
00134                (unsigned int) id);
00135     }
00136   else
00137     {
00138       Visual *visual = pick_best_visual_of_class (screen, vclass);
00139       if (visual)
00140        result = visual;
00141       else if (verbose_p)
00142        fprintf (stderr, "%s: no visual of class %s.\n", "kscreensaver", v);
00143     }
00144 
00145   if (v) free (v);
00146   return result;
00147 }
00148 
00149 Visual *
00150 get_visual_resource (Screen *screen, char *name, char *class,
00151                    Bool prefer_writable_cells)
00152 {
00153 /*
00154   char *string = get_string_resource (name, class);
00155   Visual *v = get_visual (screen, string, prefer_writable_cells, True);
00156   if (string)
00157     free(string);
00158   if (v)
00159     return v;
00160   else
00161 */
00162     return DefaultVisualOfScreen (screen);
00163 }
00164 
00165 
00166 static Visual *
00167 pick_best_visual (Screen *screen, Bool prefer_writable_cells, Bool color_only)
00168 {
00169   Visual *visual;
00170 
00171   if (!prefer_writable_cells)
00172     {
00173       /* If we don't prefer writable cells, then the "best" visual is the one
00174         on which we can allocate the largest range and number of colors.
00175 
00176         Therefore, a TrueColor visual which is at least 16 bits deep is best.
00177         (The assumption here being that a TrueColor of less than 16 bits is
00178         really just a PseudoColor visual with a pre-allocated color cube.)
00179 
00180         The next best thing is a PseudoColor visual of any type.  After that
00181         come the non-colormappable visuals, and non-color visuals.
00182        */
00183       if ((visual = pick_best_visual_of_class (screen, TrueColor)) &&
00184          visual_depth (screen, visual) >= 16)
00185        return visual;
00186     }
00187 
00188 #define TRY_CLASS(CLASS) \
00189   if ((visual = pick_best_visual_of_class (screen, CLASS)) && \
00190       (!color_only || visual_depth(screen, visual) > 1)) \
00191     return visual
00192   TRY_CLASS(PseudoColor);
00193   TRY_CLASS(TrueColor);
00194   TRY_CLASS(DirectColor);
00195   TRY_CLASS(StaticColor);
00196   if (!color_only)
00197     {
00198       TRY_CLASS(GrayScale);
00199       TRY_CLASS(StaticGray);
00200     }
00201 #undef TRY_CLASS
00202 
00203   visual = DefaultVisualOfScreen (screen);
00204   if (!color_only || visual_depth(screen, visual) > 1)
00205     return visual;
00206   else
00207     return 0;
00208 }
00209 
00210 static Visual *
00211 pick_mono_visual (Screen *screen)
00212 {
00213   Display *dpy = DisplayOfScreen (screen);
00214   XVisualInfo vi_in, *vi_out;
00215   int out_count;
00216 
00217   vi_in.depth = 1;
00218   vi_in.screen = screen_number (screen);
00219   vi_out = XGetVisualInfo (dpy, (VisualDepthMask | VisualScreenMask),
00220                         &vi_in, &out_count);
00221   if (vi_out)
00222     {
00223       Visual *v = (out_count > 0 ? vi_out [0].visual : 0);
00224       if (v && vi_out[0].depth != 1)
00225        v = 0;
00226       XFree ((char *) vi_out);
00227       return v;
00228     }
00229   else
00230     return 0;
00231 }
00232 
00233 
00234 static Visual *
00235 pick_best_visual_of_class (Screen *screen, int visual_class)
00236 {
00237   /* The best visual of a class is the one which on which we can allocate
00238      the largest range and number of colors, which means the one with the
00239      greatest depth and number of cells.
00240 
00241      (But actually, for XDaliClock, all visuals of the same class are
00242      probably equivalent - either we have writable cells or we don't.)
00243    */
00244   Display *dpy = DisplayOfScreen (screen);
00245   XVisualInfo vi_in, *vi_out;
00246   int out_count;
00247 
00248   vi_in.class = visual_class;
00249   vi_in.screen = screen_number (screen);
00250   vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask),
00251                         &vi_in, &out_count);
00252   if (vi_out)
00253     {
00254       /* choose the 'best' one, if multiple */
00255       int i, best;
00256       Visual *visual;
00257       for (i = 0, best = 0; i < out_count; i++)
00258        /* It's better if it's deeper, or if it's the same depth with
00259           more cells (does that ever happen?  Well, it could...) */
00260        if ((vi_out [i].depth > vi_out [best].depth) ||
00261            ((vi_out [i].depth == vi_out [best].depth) &&
00262             (vi_out [i].colormap_size > vi_out [best].colormap_size)))
00263          best = i;
00264       visual = (best < out_count ? vi_out [best].visual : 0);
00265       XFree ((char *) vi_out);
00266       return visual;
00267     }
00268   else
00269     return 0;
00270 }
00271 
00272 static Visual *
00273 id_to_visual (Screen *screen, int id)
00274 {
00275   Display *dpy = DisplayOfScreen (screen);
00276   XVisualInfo vi_in, *vi_out;
00277   int out_count;
00278   vi_in.screen = screen_number (screen);
00279   vi_in.visualid = id;
00280   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
00281                         &vi_in, &out_count);
00282   if (vi_out)
00283     {
00284       Visual *v = vi_out[0].visual;
00285       XFree ((char *) vi_out);
00286       return v;
00287     }
00288   return 0;
00289 }
00290 
00291 int
00292 visual_depth (Screen *screen, Visual *visual)
00293 {
00294   Display *dpy = DisplayOfScreen (screen);
00295   XVisualInfo vi_in, *vi_out;
00296   int out_count, d;
00297   vi_in.screen = screen_number (screen);
00298   vi_in.visualid = XVisualIDFromVisual (visual);
00299   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
00300                         &vi_in, &out_count);
00301   if (! vi_out) abort ();
00302   d = vi_out [0].depth;
00303   XFree ((char *) vi_out);
00304   return d;
00305 }
00306 
00307 
00308 #if 0
00309 /* You very probably don't want to be using this.
00310    Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
00311    the depth of protocol-level on-the-wire pixmap data, that is, XImages.
00312    To get this info, you should be looking at XImage->bits_per_pixel
00313    instead.  (And allocating the data for your XImage structures by
00314    multiplying ximage->bytes_per_line by ximage->height.)
00315  */
00316 int
00317 visual_pixmap_depth (Screen *screen, Visual *visual)
00318 {
00319   Display *dpy = DisplayOfScreen (screen);
00320   int vdepth = visual_depth (screen, visual);
00321   int pdepth = vdepth;
00322   int i, pfvc = 0;
00323   XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
00324 
00325   /* Return the first matching depth in the pixmap formats.  If there are no
00326      matching pixmap formats (which shouldn't be able to happen at all) then
00327      return the visual depth instead. */
00328   for (i = 0; i < pfvc; i++)
00329     if (pfv[i].depth == vdepth)
00330       {
00331        pdepth = pfv[i].bits_per_pixel;
00332        break;
00333       }
00334   if (pfv)
00335     XFree (pfv);
00336   return pdepth;
00337 }
00338 #endif /* 0 */
00339 
00340 
00341 int
00342 visual_class (Screen *screen, Visual *visual)
00343 {
00344   Display *dpy = DisplayOfScreen (screen);
00345   XVisualInfo vi_in, *vi_out;
00346   int out_count, c;
00347   vi_in.screen = screen_number (screen);
00348   vi_in.visualid = XVisualIDFromVisual (visual);
00349   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
00350                         &vi_in, &out_count);
00351   if (! vi_out) abort ();
00352   c = vi_out [0].class;
00353   XFree ((char *) vi_out);
00354   return c;
00355 }
00356 
00357 Bool
00358 has_writable_cells (Screen *screen, Visual *visual)
00359 {
00360   switch (visual_class (screen, visual))
00361     {
00362     case GrayScale:  /* Mappable grays. */
00363     case PseudoColor:       /* Mappable colors. */
00364       return True;
00365     case StaticGray: /* Fixed grays. */
00366     case TrueColor:  /* Fixed colors. */
00367     case StaticColor:       /* (What's the difference again?) */
00368     case DirectColor:       /* DirectColor visuals are like TrueColor, but have
00369                         three colormaps - one for each component of RGB.
00370                         Screw it. */
00371       return False;
00372     default:
00373       abort();
00374     }
00375 }
00376 
00377 void
00378 describe_visual (FILE *f, Screen *screen, Visual *visual, Bool private_cmap_p)
00379 {
00380   char n[10];
00381   Display *dpy = DisplayOfScreen (screen);
00382   XVisualInfo vi_in, *vi_out;
00383   int out_count;
00384   vi_in.screen = screen_number (screen);
00385   vi_in.visualid = XVisualIDFromVisual (visual);
00386   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
00387                         &vi_in, &out_count);
00388   if (! vi_out) abort ();
00389   if (private_cmap_p)
00390     sprintf(n, "%3d", vi_out->colormap_size);
00391   else
00392     strcpy(n, "default");
00393 
00394   fprintf (f, "0x%02x (%s depth: %2d, cmap: %s)\n",
00395           (unsigned int) vi_out->visualid,
00396           (vi_out->class == StaticGray  ? "StaticGray, " :
00397            vi_out->class == StaticColor ? "StaticColor," :
00398            vi_out->class == TrueColor   ? "TrueColor,  " :
00399            vi_out->class == GrayScale   ? "GrayScale,  " :
00400            vi_out->class == PseudoColor ? "PseudoColor," :
00401            vi_out->class == DirectColor ? "DirectColor," :
00402                                       "UNKNOWN:    "),
00403           vi_out->depth, n);
00404   XFree ((char *) vi_out);
00405 }
00406 
00407 int
00408 screen_number (Screen *screen)
00409 {
00410   Display *dpy = DisplayOfScreen (screen);
00411   int i;
00412   for (i = 0; i < ScreenCount (dpy); i++)
00413     if (ScreenOfDisplay (dpy, i) == screen)
00414       return i;
00415   abort ();
00416 }
00417 
00418 int
00419 visual_cells (Screen *screen, Visual *visual)
00420 {
00421   Display *dpy = DisplayOfScreen (screen);
00422   XVisualInfo vi_in, *vi_out;
00423   int out_count, c;
00424   vi_in.screen = screen_number (screen);
00425   vi_in.visualid = XVisualIDFromVisual (visual);
00426   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
00427                         &vi_in, &out_count);
00428   if (! vi_out) abort ();
00429   c = vi_out [0].colormap_size;
00430   XFree ((char *) vi_out);
00431   return c;
00432 }
00433 
00434 Visual *
00435 find_similar_visual(Screen *screen, Visual *old_visual)
00436 {
00437   Display *dpy = DisplayOfScreen (screen);
00438   XVisualInfo vi_in, *vi_out;
00439   Visual *result = 0;
00440   int out_count;
00441 
00442   vi_in.screen = screen_number (screen);
00443   vi_in.class  = visual_class (screen, old_visual);
00444   vi_in.depth  = visual_depth (screen, old_visual);
00445 
00446   /* Look for a visual of the same class and depth.
00447    */
00448   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask |
00449                              VisualDepthMask),
00450                         &vi_in, &out_count);
00451   if (vi_out && out_count > 0)
00452     result = vi_out[0].visual;
00453   if (vi_out) XFree (vi_out);
00454   vi_out = 0;
00455 
00456   /* Failing that, look for a visual of the same class.
00457    */
00458   if (!result)
00459     {
00460       vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask),
00461                             &vi_in, &out_count);
00462       if (vi_out && out_count > 0)
00463        result = vi_out[0].visual;
00464       if (vi_out) XFree (vi_out);
00465       vi_out = 0;
00466     }
00467 
00468   /* Failing that, return the default visual. */
00469   if (!result)
00470     result = DefaultVisualOfScreen (screen);
00471 
00472   return result;
00473 }