зеркало из https://github.com/mozilla/pjs.git
327 строки
10 KiB
C
327 строки
10 KiB
C
|
/* -*- 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;
|
|||
|
}
|