/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ /* visual.c --- hackery involving X visuals Created: Jamie Zawinski , 7-Jul-94. This file is based on code I wrote for xscreensaver, which I previously released under the standard X copyright (that is, not CopyLeft.) */ #include "mozilla.h" #include "xfe.h" static Visual *fe_pick_best_visual (Screen *screen); static Visual *fe_pick_best_visual_of_class (Screen *screen, int visual_class); static Visual *fe_id_to_visual (Screen *screen, int id); int fe_VisualDepth (Display *dpy, Visual *visual); #define DEFAULT_VISUAL -1 #define BEST_VISUAL -2 #define SPECIFIC_VISUAL -3 /* for XP_GetString() */ #include extern int XFE_UNRECOGNISED_VISUAL; extern int XFE_NO_VISUAL_WITH_ID; extern int XFE_NO_VISUAL_OF_CLASS; Visual * fe_ParseVisual (Screen *screen, const char *v) { int vclass; unsigned long id; char c; if (!v) vclass = BEST_VISUAL; else if (!XP_STRCASECMP(v, "default")) vclass = DEFAULT_VISUAL; else if (!XP_STRCASECMP(v, "best")) vclass = BEST_VISUAL; else if (!XP_STRCASECMP(v, "staticgray")) vclass = StaticGray; else if (!XP_STRCASECMP(v, "staticcolor")) vclass = StaticColor; else if (!XP_STRCASECMP(v, "truecolor")) vclass = TrueColor; else if (!XP_STRCASECMP(v, "grayscale")) vclass = GrayScale; else if (!XP_STRCASECMP(v, "pseudocolor")) vclass = PseudoColor; else if (!XP_STRCASECMP(v, "directcolor")) vclass = DirectColor; else if (1 == sscanf(v, " %ld %c", &id, &c)) vclass = SPECIFIC_VISUAL; else if (1 == sscanf(v, " 0x%lx %c", &id, &c)) vclass = SPECIFIC_VISUAL; else { fprintf (stderr, XP_GetString( XFE_UNRECOGNISED_VISUAL ), fe_progname, v); vclass = DEFAULT_VISUAL; } if (vclass == DEFAULT_VISUAL) return DefaultVisualOfScreen (screen); else if (vclass == BEST_VISUAL) return fe_pick_best_visual (screen); else if (vclass == SPECIFIC_VISUAL) { Visual *visual = fe_id_to_visual (screen, id); if (visual) return visual; fprintf (stderr, XP_GetString( XFE_NO_VISUAL_WITH_ID ), fe_progname, (unsigned int) id); return DefaultVisualOfScreen (screen); } else { Visual *visual = fe_pick_best_visual_of_class (screen, vclass); if (visual) return visual; fprintf (stderr, XP_GetString( XFE_NO_VISUAL_OF_CLASS ), fe_progname, v); return DefaultVisualOfScreen (screen); } } static Visual * fe_pick_best_visual (Screen *screen) { /* The "best" visual is the one on which we can allocate the largest range and number of colors. Therefore, a TrueColor visual which is at least 16 bits deep is best. (The assumption here being that a TrueColor of less than 16 bits is really just a PseudoColor visual with a pre-allocated color cube.) The next best thing is a PseudoColor visual of any type. After that come the non-colormappable visuals, and non-color visuals. */ Display *dpy = DisplayOfScreen (screen); Visual *visual; if ((visual = fe_pick_best_visual_of_class (screen, TrueColor)) && fe_VisualDepth (dpy, visual) >= 16) return visual; if ((visual = fe_pick_best_visual_of_class (screen, PseudoColor))) return visual; if ((visual = fe_pick_best_visual_of_class (screen, TrueColor))) return visual; #ifdef DIRECTCOLOR_WORKS if ((visual = fe_pick_best_visual_of_class (screen, DirectColor))) return visual; #endif /* If this screen has only StaticGray or GrayScale visuals then just choose the default visual if it is deep enough. This will keep us from unnecessarily installing a private colormap and causing colormap flashing. Unfortunately, it also means that if we can't install a gray ramp in the GrayScale visual's default colormap, we will look bad. Realistically, I don't expect this to ever happen and, if it does, the user can force the use of a private colormap with the -install command-line option or a resource setting. */ visual = DefaultVisualOfScreen (screen); if (fe_VisualDepth (dpy, visual) >= 8) return visual; if ((visual = fe_pick_best_visual_of_class (screen, StaticGray))) return visual; if ((visual = fe_pick_best_visual_of_class (screen, GrayScale))) return visual; return DefaultVisualOfScreen (screen); } #define XXX_IMAGE_LIBRARY_IS_SOMEWHAT_BROKEN static Visual * fe_pick_best_visual_of_class (Screen *screen, int visual_class) { /* The best visual of a class is the one which on which we can allocate the largest range and number of colors, which means the one with the greatest depth and number of cells. */ Display *dpy = DisplayOfScreen (screen); XVisualInfo vi_in, *vi_out; int out_count; vi_in.class = visual_class; vi_in.screen = fe_ScreenNumber (screen); vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask), &vi_in, &out_count); if (vi_out) { /* choose the 'best' one, if multiple */ int i, best; Visual *visual; for (i = 0, best = 0; i < out_count; i++) /* It's better if it's deeper, or if it's the same depth with more cells (does that ever happen? Well, it could...) NOTE: don't allow pseudo color to get larger than 8! */ if (((vi_out [i].depth > vi_out [best].depth) || ((vi_out [i].depth == vi_out [best].depth) && (vi_out [i].colormap_size > vi_out [best].colormap_size))) #ifdef XXX_IMAGE_LIBRARY_IS_SOMEWHAT_BROKEN /* For now, the image library doesn't like PseudoColor visuals of depths other than 1 or 8. Depths greater than 8 only occur on machines which have TrueColor anyway, so probably we'll end up using that (it is the one that `Best' would pick) but if a PseudoColor visual is explicitly specified, pick the 8 bit one. */ && (visual_class != PseudoColor || vi_out [i].depth == 1 || vi_out [i].depth == 8) #endif /* SGI has 30-bit deep visuals. Ignore them. (We only have 24-bit data anyway.) */ && (vi_out [i].depth <= 24) ) best = i; visual = vi_out [best].visual; XFree ((char *) vi_out); return visual; } else return 0; } static Visual * fe_id_to_visual (Screen *screen, int id) { Display *dpy = DisplayOfScreen (screen); XVisualInfo vi_in, *vi_out; int out_count; vi_in.screen = fe_ScreenNumber (screen); vi_in.visualid = id; vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask), &vi_in, &out_count); if (vi_out) { Visual *v = vi_out[0].visual; XFree ((char *) vi_out); return v; } return 0; } char * fe_VisualDescription (Screen *screen, Visual *visual) { Display *dpy = DisplayOfScreen (screen); XVisualInfo vi_in, *vi_out; int out_count; char buf [255]; vi_in.screen = fe_ScreenNumber (screen); vi_in.visualid = XVisualIDFromVisual (visual); vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask), &vi_in, &out_count); if (! vi_out) abort (); PR_snprintf (buf, sizeof (buf), "0x%02x (%s depth: %2d, cmap: %3d)", (unsigned int) vi_out->visualid, (vi_out->class == StaticGray ? "StaticGray, " : vi_out->class == StaticColor ? "StaticColor," : vi_out->class == TrueColor ? "TrueColor, " : vi_out->class == GrayScale ? "GrayScale, " : vi_out->class == PseudoColor ? "PseudoColor," : vi_out->class == DirectColor ? "DirectColor," : "UNKNOWN: "), vi_out->depth, vi_out->colormap_size /*, vi_out->bits_per_rgb*/); XFree ((char *) vi_out); return strdup (buf); } int fe_ScreenNumber (Screen *screen) { Display *dpy = DisplayOfScreen (screen); int i; for (i = 0; i < ScreenCount (dpy); i++) if (ScreenOfDisplay (dpy, i) == screen) return i; abort (); } /* Changing visuals */ #if 0 /* This doesn't work real well - Motif bugs apparently. */ void fe_ChangeVisualCallback (Widget widget, XtPointer closure, XtPointer call_data) { MWContext *context = (MWContext *) closure; Visual *v = fe_ReadVisual (context); if (v && v != fe_globalData.default_visual) { Display *dpy = XtDisplay (CONTEXT_WIDGET (context)); Screen *screen = XtScreen (CONTEXT_WIDGET (context)); if (v == DefaultVisualOfScreen (screen)) fe_globalData.default_cmap = DefaultColormapOfScreen (screen); else fe_globalData.default_cmap = XCreateColormap (dpy, XtWindow (CONTEXT_WIDGET (context)), v, AllocNone); } } #endif int fe_VisualDepth (Display *dpy, Visual *visual) { XVisualInfo vi_in, *vi_out; int out_count, d; /* vi_in.screen = DefaultScreen (dpy);*/ vi_in.visualid = XVisualIDFromVisual (visual); vi_out = XGetVisualInfo (dpy, /*VisualScreenMask|*/VisualIDMask, &vi_in, &out_count); if (! vi_out) abort (); d = vi_out [0].depth; XFree ((char *) vi_out); return d; } int fe_VisualPixmapDepth (Display *dpy, Visual *visual) { int visual_depth = fe_VisualDepth (dpy, visual); int pixmap_depth = visual_depth; int i, pfvc = 0; XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc); /* Return the first matching depth in the pixmap formats. If there are no matching pixmap formats (which shouldn't be able to happen) return the visual depth instead. */ for (i = 0; i < pfvc; i++) if (pfv[i].depth == visual_depth) { pixmap_depth = pfv[i].bits_per_pixel; break; } if (pfv) XFree (pfv); return pixmap_depth; } int fe_VisualCells (Display *dpy, Visual *visual) { XVisualInfo vi_in, *vi_out; int out_count, c; /* vi_in.screen = DefaultScreen (dpy);*/ 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; XFree ((char *) vi_out); return c; }