gecko-dev/cmd/xfe/visual.c

327 lines
10 KiB
C
Raw Normal View History

1998-03-28 02:44:41 +00:00
/* -*- 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 <jwz@netscape.com>, 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 <xpgetstr.h>
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;
}