diff options
author | Reinhard Tartler <siretart@tauware.de> | 2011-10-10 17:43:39 +0200 |
---|---|---|
committer | Reinhard Tartler <siretart@tauware.de> | 2011-10-10 17:43:39 +0200 |
commit | f4092abdf94af6a99aff944d6264bc1284e8bdd4 (patch) | |
tree | 2ac1c9cc16ceb93edb2c4382c088dac5aeafdf0f /nx-X11/lib/dps/dpsXcmu.c | |
parent | a840692edc9c6d19cd7c057f68e39c7d95eb767d (diff) | |
download | nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.tar.gz nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.tar.bz2 nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.zip |
Imported nx-X11-3.1.0-1.tar.gznx-X11/3.1.0-1
Summary: Imported nx-X11-3.1.0-1.tar.gz
Keywords:
Imported nx-X11-3.1.0-1.tar.gz
into Git repository
Diffstat (limited to 'nx-X11/lib/dps/dpsXcmu.c')
-rw-r--r-- | nx-X11/lib/dps/dpsXcmu.c | 1602 |
1 files changed, 1602 insertions, 0 deletions
diff --git a/nx-X11/lib/dps/dpsXcmu.c b/nx-X11/lib/dps/dpsXcmu.c new file mode 100644 index 000000000..502649d51 --- /dev/null +++ b/nx-X11/lib/dps/dpsXcmu.c @@ -0,0 +1,1602 @@ +/* + * dpsXcmu.c -- Simple color management/allocation utility + * + * (c) Copyright 1988-1994 Adobe Systems Incorporated. + * All rights reserved. + * + * Permission to use, copy, modify, distribute, and sublicense this software + * and its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notices appear in all copies and that + * both those copyright notices and this permission notice appear in + * supporting documentation and that the name of Adobe Systems Incorporated + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. No trademark license + * to use the Adobe trademarks is hereby granted. If the Adobe trademark + * "Display PostScript"(tm) is used to describe this software, its + * functionality or for any other purpose, such use shall be limited to a + * statement that this software works in conjunction with the Display + * PostScript system. Proper trademark attribution to reflect Adobe's + * ownership of the trademark shall be given whenever any such reference to + * the Display PostScript system is made. + * + * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR + * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. + * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON- INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE + * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT + * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE. + * + * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems + * Incorporated which may be registered in certain jurisdictions + * + * Portions Copyright 1989 by the Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Adobe Systems Incorporated and Donna Converse, MIT X Consortium + */ +/* $XFree86: xc/lib/dps/dpsXcmu.c,v 1.4 2000/09/26 15:56:59 tsi Exp $ */ + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/Xresource.h> +#include <X11/Xos.h> +#include <stdlib.h> +#include <stdio.h> +#include <pwd.h> + +#include "dpsassert.h" +#include "cslibint.h" + +/* Defines for standard colormap routines */ + +#define PrivSort qsort +#include <stddef.h> + +static char redsName[] = "reds"; +static char greensName[] = "greens"; +static char bluesName[] = "blues"; +static char graysName[] = "grays"; + +/* Database containing DPS default color cube values */ + +typedef struct _dpyRec { + Display *dpy; + XrmDatabase db; + Atom XA_GRAY_DEFAULT_MAP; + struct _dpyRec *next; +} DpyRec; + +static DpyRec *dpyRec = NULL; +static DpyRec *curDpyRec; +static DpyRec *FindDpyRec(Display *); + +typedef struct { + unsigned long *pixels; + int npixels; +} PixelRec; + +static Bool AllocateColor(Display *, Colormap, XColor *); +static Bool AllocateColormap(Display *, XStandardColormap *, XVisualInfo *, int *, PixelRec *, int *, int *, unsigned long); +static Bool CheckCube(XColor *, XColor *, XStandardColormap *); +static Bool CubicCube(XStandardColormap *); +static Bool GetColorCubeFromProperty(Display *, XVisualInfo *, XStandardColormap *, XStandardColormap **, int *); +static Bool GetGrayRampFromProperty(Display *, XVisualInfo *, XStandardColormap *, XStandardColormap **, int *); +Status XDPSCreateStandardColormaps(Display *, Drawable, Visual *, int, int, int, int, XStandardColormap *, XStandardColormap *, Bool); +static Status contiguous(unsigned long *, int, int *, unsigned long, int *, int *); +static XVisualInfo *PickCorrectVisual(Display *, XVisualInfo *, int, Colormap); +static int FindRampSize(XColor *, XColor *); +static long NumColors(char *, char *, char *); +static void AllocateColorCube(Display *, XVisualInfo *, XStandardColormap *, PixelRec *); +static void AllocateGrayRamp(Display *, XVisualInfo *, XStandardColormap *, XStandardColormap *, PixelRec *); +static void ColorValuesFromMask(unsigned long, unsigned long *, unsigned long *); +static void CreateDefaultsDb(Display *); +static void DefineProperty(Display *, XStandardColormap *, XVisualInfo *, XStandardColormap *, int, Atom); +static void FindStaticColorCube(Display *, XVisualInfo *, XStandardColormap *); +static void FindStaticGrayRamp(Display *, XVisualInfo *, XStandardColormap *, XStandardColormap *); +static void GetDatabaseValues(Display *, XVisualInfo *, XStandardColormap *, XStandardColormap *); +static void GetHomeDir(char *); +static void SetRamp(XColor *, XColor *, int, int *, unsigned long *); +static void ShrinkMapToFit(XStandardColormap *, int *, XVisualInfo *); +static void UseGrayCorners(XStandardColormap *, XStandardColormap *); +static void UseGrayDiagonal(XStandardColormap *, XStandardColormap *); + +#define SCALE 65535 +#undef ABS +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +void XDPSGetDefaultColorMaps( + Display *dpy, + Screen *screen, + Drawable drawable, + XStandardColormap *colorCube, + XStandardColormap *grayRamp) +{ + Window root; + Visual *visual; + XStandardColormap g; + + /* If there is a screen specified, use it; otherwise use the drawable */ + + if (screen == NULL) { + if (drawable == None || ScreenCount(dpy) == 1) { + root = DefaultRootWindow(dpy); + screen = DefaultScreenOfDisplay(dpy); + } else { + /* Have to get the root for this drawable */ + int x, y; + int i; + unsigned int width, height, bwidth, depth; + if (!XGetGeometry(dpy, drawable, &root, &x, &y, &width, &height, + &bwidth, &depth)) root = DefaultRootWindow(dpy); + for (i = 0; + i < ScreenCount(dpy) && root != RootWindow(dpy, i); + i++) {} + screen = ScreenOfDisplay(dpy, i); + } + } else root = RootWindowOfScreen(screen); + + if (grayRamp == NULL) grayRamp = &g; + + visual = DefaultVisualOfScreen(screen); + grayRamp->colormap = DefaultColormapOfScreen(screen); + if (colorCube != NULL) colorCube->colormap = grayRamp->colormap; + + (void) XDPSCreateStandardColormaps(dpy, root, visual, + 0, 0, 0, 0, colorCube, grayRamp, True); +} + +Status XDPSCreateStandardColormaps( + Display *dpy, + Drawable drawable, + Visual *visual, + int reds, int greens, int blues, int grays, + XStandardColormap *colorCube, + XStandardColormap *grayRamp, + Bool retain) +{ + XVisualInfo vtemp, *vinfo; + int nvis; + XStandardColormap *propCube = NULL, *propRamp = NULL; + int nPropCube = 0, nPropRamp = 0; + Bool gotCube = False, gotRamp; + PixelRec pixels; + + if (grayRamp == NULL) return 0; + if (colorCube != NULL && + colorCube->colormap != grayRamp->colormap) return 0; + + if (dpy == NULL || (drawable == None && visual == NULL)) return 0; + + if (visual == NULL) { + XWindowAttributes attr; + if (XGetWindowAttributes(dpy, drawable, &attr) == 0) return 0; + visual = attr.visual; + } + + if (grayRamp->colormap == None && drawable == None) return 0; + + curDpyRec = FindDpyRec(dpy); + if (curDpyRec == NULL) return 0; + + vtemp.visualid = XVisualIDFromVisual(visual); + vinfo = XGetVisualInfo(dpy, VisualIDMask, &vtemp, &nvis); + if (nvis == 0) return 0; + + if (nvis > 1) { + vinfo = PickCorrectVisual(dpy, vinfo, nvis, grayRamp->colormap); + } + if (vinfo == NULL) return 0; + + if (grays <= 1) grayRamp->red_max = 0; + else grayRamp->red_max = grays - 1; + + if (colorCube != NULL) { + if (reds <= 1) colorCube->red_max = 0; + else colorCube->red_max = reds - 1; + if (greens <= 1) colorCube->green_max = 0; + else colorCube->green_max = greens - 1; + if (blues <= 1) colorCube->blue_max = 0; + else colorCube->blue_max = blues - 1; + } + + if ((vinfo->class == StaticGray || vinfo->class == GrayScale) && + colorCube != NULL) { + /* Can't do a color cube in a gray visual! */ + colorCube->red_max = colorCube->green_max = colorCube->blue_max = + colorCube->red_mult = colorCube->green_mult = colorCube->blue_mult = + colorCube->base_pixel = 0; + colorCube = NULL; + } + + if (retain) { + Display *newDpy = XOpenDisplay(XDisplayString(dpy)); + if (newDpy == NULL) retain = False; + else dpy = newDpy; + XGrabServer(dpy); + } + + if (grayRamp->colormap == None) { + grayRamp->colormap = XCreateColormap(dpy, drawable, vinfo->visual, + AllocNone); + if (colorCube != NULL) colorCube->colormap = grayRamp->colormap; + } + + if (colorCube != NULL) { + gotCube = GetColorCubeFromProperty(dpy, vinfo, colorCube, + &propCube, &nPropCube); + } + gotRamp = GetGrayRampFromProperty(dpy, vinfo, grayRamp, + &propRamp, &nPropRamp); + + if (!gotRamp || (colorCube != NULL && !gotCube)) { + /* Couldn't find at least one thing we wanted, so let's look in the + database */ + + GetDatabaseValues(dpy, vinfo, colorCube, grayRamp); + + pixels.pixels = NULL; + pixels.npixels = 0; + + if (colorCube != NULL) { + if (colorCube->red_max != 0) { + AllocateColorCube(dpy, vinfo, colorCube, &pixels); + } + if (colorCube->red_max == 0) { + colorCube->green_max = colorCube->blue_max = + colorCube->red_mult = colorCube->green_mult = + colorCube->blue_mult = 0; + } + } + + if (grayRamp->red_max != 0) { + AllocateGrayRamp(dpy, vinfo, grayRamp, colorCube, &pixels); + } + + if (pixels.pixels != NULL) { + if (pixels.npixels != 0) { + XFreeColors(dpy, grayRamp->colormap, + pixels.pixels, pixels.npixels, 0); + } + free((char *) pixels.pixels); + } + + if (retain) { + Pixmap p; + + /* Create something to put in killid field so the entries can + be deleted sometime */ + p = XCreatePixmap(dpy, RootWindow(dpy, vinfo->screen), 1, 1, 1); + if (colorCube != NULL && !gotCube && colorCube->red_max != 0) { + colorCube->visualid = vinfo->visualid; + colorCube->killid = p; + DefineProperty(dpy, colorCube, vinfo, propCube, nPropCube, + XA_RGB_DEFAULT_MAP); + } + if (!gotRamp && grayRamp->red_max != 0) { + grayRamp->visualid = vinfo->visualid; + grayRamp->killid = p; + DefineProperty(dpy, grayRamp, vinfo, propRamp, nPropRamp, + (vinfo->class == GrayScale ? XA_RGB_GRAY_MAP : + curDpyRec->XA_GRAY_DEFAULT_MAP)); + } + XSetCloseDownMode(dpy, RetainTemporary); + } + } + + if (grayRamp->red_max == 0) { + /* Use special magic values. If this is a default colormap, + the server recognizes a gray ramp with red_max=1, red_mult=1, + base_pixel=0 to mean a 2 gray ramp with BlackPixel being + the lowest intensity gray and WhitePixel being the highest + intensity gray. If it's not a default colormap, then the + server will either generate a BadValue error, or just happily + use pixel values 0 and 1; either is better than the alternative, + silently converting into a null device. */ + grayRamp->red_max = 1; + grayRamp->red_mult = 1; + grayRamp->base_pixel = 0; + } + + if (retain) { + XUngrabServer(dpy); + XCloseDisplay(dpy); + } + if (propCube != NULL) XFree((void *) propCube); + if (propRamp != NULL) XFree((void *) propRamp); + XFree((void *) vinfo); + return 1; +} + +static DpyRec *FindDpyRec(Display *dpy) +{ + DpyRec *d; + + for (d = dpyRec; d != NULL; d = d->next) { + if (d->dpy == dpy) return d; + } + + d = (DpyRec *) malloc(sizeof(DpyRec)); + if (d == NULL) return NULL; + d->XA_GRAY_DEFAULT_MAP = XInternAtom(dpy, "DEFAULT_GRAY", False); + d->db = NULL; + d->next = dpyRec; + dpyRec = d; + return d; +} + +static XVisualInfo *PickCorrectVisual( + Display *dpy, + XVisualInfo *vlist, + int n, + Colormap cmap) +{ + register int i; + register int screen_number; + Bool def_cmap = False; + + /* A visual id may be valid on multiple screens. Also, there may + * be multiple visuals with identical visual ids at different depths. + * If the colormap is the Default Colormap, use the Default Visual. + * Otherwise, arbitrarily, use the deepest visual. + */ + + for (screen_number = ScreenCount(dpy); --screen_number >= 0; /**/) { + if (cmap == DefaultColormap(dpy, screen_number)) { + def_cmap = True; + break; + } + } + + if (def_cmap) { + for (i = 0; i < n; i++, vlist++) { + if (vlist->visual == DefaultVisual(dpy, screen_number)) { + return vlist; + } + } + return NULL; /* Visual does not match colormap */ + } else { + int maxdepth = 0; + XVisualInfo *v = 0; + + for (i = 0; i < n; i++, vlist++) { + if (vlist->depth > maxdepth) { + maxdepth = vlist->depth; + v = vlist; + } + } + return v; + } +} + +/* Do some rudimentary checking of the properties to avoid obviously bad ones. + How did they get there, anyway? */ + +static Bool ValidCube( + XStandardColormap *c, + XVisualInfo *vinfo) +{ + unsigned long max = 1 << vinfo->depth; + unsigned long pixel; + + if (c->red_max < 1 || c->green_max < 1 || c->blue_max < 1) return False; + if (c->base_pixel > max) return False; + pixel = (c->red_max * c->red_mult + c->green_max * c->green_mult + + c->blue_max * c->blue_mult + c->base_pixel) & 0xFFFFFFFF; + if (pixel > max) return False; + + return True; +} + +static Bool ValidRamp( + XStandardColormap *c, + XVisualInfo *vinfo) +{ + unsigned long max = 1 << vinfo->depth; + unsigned long pixel; + + if (c->red_max < 1) return False; + if (c->base_pixel > max) return False; + pixel = (c->red_max * c->red_mult + c->base_pixel) & 0xFFFFFFFF; + if (pixel > max) return False; + + return True; +} + +static Bool GetColorCubeFromProperty( + Display *dpy, + XVisualInfo *vinfo, + XStandardColormap *colorCube, + XStandardColormap **cube, + int *ncube) +{ + int gotCube; + int i; + register XStandardColormap *c; + + gotCube = XGetRGBColormaps(dpy, RootWindow(dpy, vinfo->screen), cube, + ncube, XA_RGB_DEFAULT_MAP); + + if (gotCube) { + /* Try to find a match with the visual */ + c = *cube; + for (i = 0; i < *ncube; i++) { + if (c->colormap == colorCube->colormap && + c->visualid == vinfo->visualid && + ValidCube(c, vinfo)) { + colorCube->red_max = c->red_max; + colorCube->red_mult = c->red_mult; + colorCube->green_max = c->green_max; + colorCube->green_mult = c->green_mult; + colorCube->blue_max = c->blue_max; + colorCube->blue_mult = c->blue_mult; + colorCube->base_pixel = c->base_pixel; + colorCube->visualid = c->visualid; + colorCube->killid = c->killid; + break; + } + c++; + } + if (i == *ncube) gotCube = False; + } + return gotCube; +} + +static Bool GetGrayRampFromProperty( + Display *dpy, + XVisualInfo *vinfo, + XStandardColormap *grayRamp, + XStandardColormap **ramp, + int *nramp) +{ + int gotRamp; + int i; + Atom grayAtom; + register XStandardColormap *c; + + if (vinfo->class == GrayScale) grayAtom = XA_RGB_GRAY_MAP; + else grayAtom = curDpyRec->XA_GRAY_DEFAULT_MAP; + + gotRamp = XGetRGBColormaps(dpy, RootWindow(dpy, vinfo->screen), ramp, + nramp, grayAtom); + + if (gotRamp) { + /* Try to find a match with the visual */ + c = *ramp; + for (i = 0; i < *nramp; i++) { + if (c->colormap == grayRamp->colormap && + c->visualid == vinfo->visualid && + ValidRamp(c, vinfo)) { + grayRamp->red_max = c->red_max; + grayRamp->red_mult = c->red_mult; + grayRamp->base_pixel = c->base_pixel; + grayRamp->visualid = c->visualid; + grayRamp->killid = c->killid; + break; + } + c++; + } + if (i == *nramp) gotRamp = False; + } + return gotRamp; +} + +static void GetDatabaseValues( + Display *dpy, + XVisualInfo *vinfo, + XStandardColormap *colorCube, + XStandardColormap *grayRamp) +{ + char *class, *depth; + char namePrefix[40], classPrefix[40]; + unsigned long max; + XStandardColormap fakeCube; + + switch (vinfo->class) { + default: + case StaticGray: class = "StaticGray."; break; + case GrayScale: class = "GrayScale."; break; + case StaticColor: class = "StaticColor."; break; + case PseudoColor: class = "PseudoColor."; break; + case TrueColor: class = "TrueColor."; break; + case DirectColor: class = "DirectColor."; break; + } + + if (vinfo->depth >= 24) depth = "24."; + else if (vinfo->depth >= 12) depth = "12."; + else if (vinfo->depth >= 8) depth = "8."; + else if (vinfo->depth >= 4) depth = "4."; + else if (vinfo->depth >= 2) depth = "2."; + else depth = "1."; + + (void) strcpy(namePrefix, "dpsColorCube."); + (void) strcat(strcat(namePrefix, class), depth); + (void) strcpy(classPrefix, "DPSColorCube."); + (void) strcat(strcat(classPrefix, class), depth); + + CreateDefaultsDb(dpy); + + if (colorCube == NULL && vinfo->class == TrueColor) { + /* We'll need the color cube information to compute the gray ramp, + even if it wasn't asked for, so make colorCube point to a + temporary structure */ + colorCube = &fakeCube; + } + + if (colorCube != NULL) { + switch (vinfo->class) { + case StaticGray: + case GrayScale: + /* We can't do a color cube for these visuals */ + break; + + case TrueColor: + /* Rewrite whatever was there before with real values */ + ColorValuesFromMask(vinfo->red_mask, &colorCube->red_max, + &colorCube->red_mult); + ColorValuesFromMask(vinfo->green_mask, &colorCube->green_max, + &colorCube->green_mult); + ColorValuesFromMask(vinfo->blue_mask, &colorCube->blue_max, + &colorCube->blue_mult); + colorCube->base_pixel = 0; + break; + + case DirectColor: + /* Get the mults from the masks; ignore maxes */ + ColorValuesFromMask(vinfo->red_mask, &max, + &colorCube->red_mult); + ColorValuesFromMask(vinfo->green_mask, &max, + &colorCube->green_mult); + ColorValuesFromMask(vinfo->blue_mask, &max, + &colorCube->blue_mult); + /* Get the maxes from the database */ + if (colorCube->red_max == 0) { + colorCube->red_max = + NumColors(namePrefix, classPrefix, redsName) - 1; + } + if (colorCube->green_max == 0) { + colorCube->green_max = + NumColors(namePrefix, classPrefix, greensName) - 1; + } + if (colorCube->blue_max == 0) { + colorCube->blue_max = + NumColors(namePrefix, classPrefix, bluesName) - 1; + } + colorCube->base_pixel = 0; + break; + + case PseudoColor: + if (colorCube->red_max == 0) { + colorCube->red_max = + NumColors(namePrefix, classPrefix, redsName) - 1; + } + if (colorCube->green_max == 0) { + colorCube->green_max = + NumColors(namePrefix, classPrefix, greensName) - 1; + } + if (colorCube->blue_max == 0) { + colorCube->blue_max = + NumColors(namePrefix, classPrefix, bluesName) - 1; + } + colorCube->red_mult = (colorCube->green_max + 1) * + (colorCube->blue_max + 1); + colorCube->green_mult = colorCube->blue_max + 1; + colorCube->blue_mult = 1; + break; + + case StaticColor: + FindStaticColorCube(dpy, vinfo, colorCube); + break; + } + } + + switch (vinfo->class) { + case GrayScale: + case PseudoColor: + case DirectColor: + if (grayRamp->red_max == 0) { + grayRamp->red_max = + NumColors(namePrefix, classPrefix, graysName) - 1; + } + grayRamp->red_mult = 1; + break; + + case TrueColor: + /* If the color cube is truly a cube, use its diagonal. Otherwise + were SOL and have to use a two-element ramp. */ + if (CubicCube(colorCube)) UseGrayDiagonal(colorCube, grayRamp); + else UseGrayCorners(colorCube, grayRamp); + break; + + case StaticColor: + case StaticGray: + FindStaticGrayRamp(dpy, vinfo, grayRamp, colorCube); + break; + } +} + +static Bool CubicCube(XStandardColormap *cube) +{ + return cube->red_max == cube->green_max && cube->red_max == + cube->blue_max; +} + +static void UseGrayDiagonal(XStandardColormap *cube, XStandardColormap *ramp) +{ + ramp->red_max = cube->red_max; + ramp->red_mult = cube->red_mult + cube->green_mult + cube->blue_mult; + ramp->base_pixel = cube->base_pixel; +} + +static void UseGrayCorners(XStandardColormap *cube, XStandardColormap *ramp) +{ + ramp->red_max = 1; + ramp->red_mult = (cube->red_max + 1) * (cube->green_max + 1) * + (cube->blue_max + 1) - 1; + if (* (int *) &(cube->red_mult) < 0) ramp->red_mult *= -1; + ramp->base_pixel = cube->base_pixel; +} + +static void ColorValuesFromMask( + unsigned long mask, + unsigned long *maxColor, + unsigned long *mult) +{ + *mult = 1; + while ((mask & 1) == 0) { + *mult <<= 1; + mask >>= 1; + } + *maxColor = mask; +} + +/* +Resource definitions for default color cube / gray ramp sizes +are based on visual class and depth. Working from least choices +to most, here's motivation for the defaults: + +If unspecified, default is 0 values for red, green, and blue, +and 2 (black and white) for grays. This covers StaticGray, StaticColor, +and depths less than 4 of the other visual classes. + +If we have a choice, we try to allocate a gray ramp with an odd number +of colors; this is so 50% gray can be rendered without dithering. +In general we don't want to allocate a large cube (even when many +colormap entries are available) because allocation of each entry +requires a round-trip to the server (entries allocated read-only +via XAllocColor). + +For GrayScale, any depth less than 4 is treated as monochrome. + +PseudoColor depth 4 we try for a 2x2x2 cube with the gray ramp on +the diagonal. Depth 8 uses a 4x4x4 cube with a separate 9 entry +gray ramp. Depth 12 uses a 6x6x5 "cube" with a separate 17 entry gray +ramp. The cube is non-symmetrical; we don't want to use the diagonal +for a gray ramp and we can get by with fewer blues than reds or greens. + +For DirectColor, allocating a gray ramp separate from the color cube +is wasteful of map entries, so we specify a symmetrical cube and +share the diagonal entries for the gray ramp. + +For TrueColor, # color shades is set equal to the # shades / primary; +we don't actually allocate map entries, but it's handy to be able to +do the resource lookup blindly and get the right value. +*/ + +static char dpsDefaults[] = "\ +*reds: 0\n\ +*greens: 0\n\ +*blues: 0\n\ +*grays: 2\n\ +\ +*GrayScale.4.grays: 9\n\ +*GrayScale.8.grays: 17\n\ +\ +*PseudoColor.4.reds: 2\n\ +*PseudoColor.4.greens: 2\n\ +*PseudoColor.4.blues: 2\n\ +*PseudoColor.4.grays: 2\n\ +*PseudoColor.8.reds: 4\n\ +*PseudoColor.8.greens: 4\n\ +*PseudoColor.8.blues: 4\n\ +*PseudoColor.8.grays: 9\n\ +*PseudoColor.12.reds: 6\n\ +*PseudoColor.12.greens: 6\n\ +*PseudoColor.12.blues: 5\n\ +*PseudoColor.12.grays: 17\n\ +\ +*DirectColor.8.reds: 4\n\ +*DirectColor.8.greens: 4\n\ +*DirectColor.8.blues: 4\n\ +*DirectColor.8.grays: 4\n\ +*DirectColor.12.reds: 6\n\ +*DirectColor.12.greens: 6\n\ +*DirectColor.12.blues: 6\n\ +*DirectColor.12.grays: 6\n\ +*DirectColor.24.reds: 7\n\ +*DirectColor.24.greens: 7\n\ +*DirectColor.24.blues: 7\n\ +*DirectColor.24.grays: 7\n\ +\ +*TrueColor.12.reds: 16\n\ +*TrueColor.12.greens: 16\n\ +*TrueColor.12.blues: 16\n\ +*TrueColor.12.grays: 16\n\ +*TrueColor.24.reds: 256\n\ +*TrueColor.24.greens: 256\n\ +*TrueColor.24.blues: 256\n\ +*TrueColor.24.grays: 256\n\ +"; + +static XrmDatabase defaultDB = NULL; + +static void CreateDefaultsDb(Display *dpy) +{ + char home[256], *dpyDefaults; + + if (defaultDB == NULL) defaultDB = XrmGetStringDatabase(dpsDefaults); + + if (curDpyRec->db != NULL) return; + + dpyDefaults = XResourceManagerString(dpy); + if (dpyDefaults != NULL) { + curDpyRec->db = XrmGetStringDatabase(dpyDefaults); + } + + if (curDpyRec->db == NULL) { + GetHomeDir(home); + strcpy(home, "/.Xdefaults"); + curDpyRec->db = XrmGetFileDatabase(home); + } +} + +static void GetHomeDir(char *buf) +{ +#ifndef X_NOT_POSIX + uid_t uid; +#else + int uid; + extern int getuid(); +#ifndef SYSV386 + extern struct passwd *getpwuid(), *getpwnam(); +#endif +#endif + struct passwd *pw; + static char *ptr = NULL; + + if (ptr == NULL) { + if (!(ptr = getenv("HOME"))) { + if ((ptr = getenv("USER")) != 0) pw = getpwnam(ptr); + else { + uid = getuid(); + pw = getpwuid(uid); + } + if (pw) ptr = pw->pw_dir; + else { + ptr = NULL; + *buf = '\0'; + } + } + } + + if (ptr) + (void) strcpy(buf, ptr); + + buf += strlen(buf); + *buf = '/'; + buf++; + *buf = '\0'; + return; +} + +static long NumColors(char *namePrefix, char *classPrefix, char *color) +{ + char name[40], class[40]; + XrmValue rtnValue; + char *rtnType; + long value; + + (void) strcpy(name, namePrefix); + (void) strcpy(class, classPrefix); + if (! XrmGetResource(curDpyRec->db, strcat(name, color), + strcat(class, color), &rtnType, &rtnValue)) { + if (! XrmGetResource(defaultDB, name, class, &rtnType, &rtnValue)) { + /* This should never happen, as our defaults cover all cases */ + return 0; + } + } + + /* Resource value is number of shades of specified color. If value + is not an integer, atoi returns 0, so we return 0. If value + is less than 2, it is invalid (need at least 2 shades of a color). + Explicitly setting 0 is ok for colors (means to not use a color + cube) but merits a warning for gray. */ + + if (strcmp(rtnValue.addr, "0") == 0 && strcmp(color, "grays") != 0) { + return 0; + } + + value = atol(rtnValue.addr); + if (value < 2) { + char mbuf[512]; + sprintf(mbuf, "%% Value '%s' is invalid for %s resource\n", + rtnValue.addr, name); + DPSWarnProc(NULL, mbuf); + } + return value; +} + +/* Query the entire colormap in the static color case, then try to find + a color cube. Check pairs of black and white cells trying to find + a cube between them and take the first one you find. */ + +static void FindStaticColorCube( + Display *dpy, + XVisualInfo *vinfo, + XStandardColormap *colorCube) +{ + XColor *ramp, *black, *white, *altBlack, *altWhite; + int i, entries; + + entries = 1 << vinfo->depth; + ramp = (XColor *) calloc(entries, sizeof(XColor)); + + if (ramp == NULL) { + colorCube->red_max = 0; + return; + } + + /* Query the colormap */ + for (i = 0; i < entries; i++) ramp[i].pixel = i; + XQueryColors(dpy, colorCube->colormap, ramp, entries); + + /* Find the white and black entries */ + + black = white = altBlack = altWhite = NULL; + for (i = 0; i < entries; i++) { + if (ramp[i].flags != (DoRed | DoBlue | DoGreen)) continue; + if (ramp[i].red == 0 && ramp[i].blue == 0 && + ramp[i].green == 0) { + if (black == NULL) black = ramp+i; + else if (altBlack == NULL) altBlack = ramp+i; + } else if (ramp[i].red == SCALE && ramp[i].blue == SCALE && + ramp[i].green == SCALE) { + if (white == NULL) white = ramp+i; + else if (altWhite == NULL) altWhite = ramp+i; + } + } + + if (black == NULL || white == NULL) { + colorCube->red_max = 0; + free(ramp); + return; + } + + /* Look for cubes between pairs of black & white */ + if (!CheckCube(black, white, colorCube) && + !CheckCube(altBlack, white, colorCube) && + !CheckCube(black, altWhite, colorCube) && + !CheckCube(altBlack, altWhite, colorCube)) { + colorCube->red_max = 0; + } + + free(ramp); +} + +#define R 1 +#define G 2 +#define B 4 +#define C 8 +#define M 16 +#define Y 32 + +#define SMALLSCALE 255 +#define CheckColor(color,r,g,b) ((((color)->red >> 8) == (r) * SMALLSCALE) && \ + (((color)->green >> 8) == (g) * SMALLSCALE) && \ + (((color)->blue >> 8) == (b) * SMALLSCALE)) + +static Bool CheckCube( + XColor *black, + XColor *white, + XStandardColormap *cube) +{ + int r = 0, g = 0, b = 0, c = 0, m = 0, y = 0, k, w; + XColor *color; + unsigned int found = 0; + int small, middle, large; + int smallMult, smallMax, middleMult, middleMax, largeMult, largeMax; + Bool backwards = False; + int mult = 1; + XStandardColormap test; /* Test cube */ + int i; + int size; + + if (black == NULL || white == NULL) return False; + + k = black->pixel; + w = white->pixel - k; + + size = ABS(w); + if (w < 0) { + backwards = True; + mult = -1; + } + + for (i = 1; i < size; i++) { + color = black + i*mult; + if (color->flags != (DoRed | DoBlue | DoGreen)) return False; + + /* If black or white is in the middle of the cube, can't work */ + if (CheckColor(color, 0, 0, 0)) return False; + if (CheckColor(color, 1, 1, 1)) return False; + + /* Check for red, green, blue, cyan, magenta, and yellow */ + if (CheckColor(color, 1, 0, 0)) {r = color->pixel-k; found |= R;} + else if (CheckColor(color, 0, 1, 0)) {g = color->pixel-k; found |= G;} + else if (CheckColor(color, 0, 0, 1)) {b = color->pixel-k; found |= B;} + else if (CheckColor(color, 0, 1, 1)) {c = color->pixel-k; found |= C;} + else if (CheckColor(color, 1, 0, 1)) {m = color->pixel-k; found |= M;} + else if (CheckColor(color, 1, 1, 0)) {y = color->pixel-k; found |= Y;} + } + + /* If any color is missing no cube is possible */ + if (found != (R | G | B | C | M | Y)) return False; + + /* Next test. Make sure B + G = C, R + B = M, R + G = Y, + and R + G + B = W */ + if (b + g != c) return False; + if (r + b != m) return False; + if (r + g != y) return False; + if (r + g + b != w) return False; + + /* Looking good! Compensate for backwards cubes */ + if (backwards) { + w = ABS(w); + r = ABS(r); + g = ABS(g); + b = ABS(b); + } + + /* Find the smallest, middle, and largest difference */ + if (r < b && b < g) { + small = r; middle = b; large = g; + } else if (r < g && g < b) { + small = r; middle = g; large = b; + } else if (b < r && r < g) { + small = b; middle = r; large = g; + } else if (b < g && g < r) { + small = b; middle = g; large = r; + } else if (g < r && r < b) { + small = g; middle = r; large = b; + } else { + small = g; middle = b; large = r; + } + + /* The smallest must divide the middle, and the middle the large */ + if ((middle % (small + 1)) != 0) return False; + if ((large % (small + middle + 1)) != 0) return False; + + /* OK, we believe we have a cube. Compute the description */ + smallMult = 1; + smallMax = small; + middleMult = small + 1; + middleMax = middle / middleMult; + largeMult = small + middle + 1; + largeMax = large / largeMult; + + if (small == r) { + test.red_max = smallMax; test.red_mult = smallMult; + if (middle == b) { + test.blue_max = middleMax; test.blue_mult = middleMult; + test.green_max = largeMax; test.green_mult = largeMult; + } else { + test.green_max = middleMax; test.green_mult = middleMult; + test.blue_max = largeMax; test.blue_mult = largeMult; + } + } else if (small == g) { + test.green_max = smallMax; test.green_mult = smallMult; + if (middle == b) { + test.blue_max = middleMax; test.blue_mult = middleMult; + test.red_max = largeMax; test.red_mult = largeMult; + } else { + test.red_max = middleMax; test.red_mult = middleMult; + test.blue_max = largeMax; test.blue_mult = largeMult; + } + } else { /* small == b */ + test.blue_max = smallMax; test.blue_mult = smallMult; + if (middle == r) { + test.red_max = middleMax; test.red_mult = middleMult; + test.green_max = largeMax; test.green_mult = largeMult; + } else { + test.green_max = middleMax; test.green_mult = middleMult; + test.red_max = largeMax; test.red_mult = largeMult; + } + } + + /* Re-compensate for backwards cube */ + if (backwards) { + test.red_mult *= -1; + test.green_mult *= -1; + test.blue_mult *= -1; + } + + /* Finally, test the hypothesis! The answer must be correct within 1 + bit. Only look at the top 8 bits; the others are too noisy */ + + for (i = 1; i < size; i++) { +#define calc(i, max, mult) ((((i / test.mult) % \ + (test.max + 1)) * SCALE) / test.max) + r = ((unsigned short) calc(i, red_max, red_mult) >> 8) - + (black[i*mult].red >> 8); + g = ((unsigned short) calc(i, green_max, green_mult) >> 8) - + (black[i*mult].green >> 8); + b = ((unsigned short) calc(i, blue_max, blue_mult) >> 8) - + (black[i*mult].blue >> 8); +#undef calc + if (ABS(r) > 2 || ABS(g) > 2 || ABS(b) > 2) return False; + } + cube->red_max = test.red_max; + cube->red_mult = test.red_mult; + cube->green_max = test.green_max; + cube->green_mult = test.green_mult; + cube->blue_max = test.blue_max; + cube->blue_mult = test.blue_mult; + cube->base_pixel = k; + return True; +} + +#undef R +#undef G +#undef B +#undef C +#undef M +#undef Y + +/* Query the entire colormap in the static gray case, then try to find + a gray ramp. This handles there being 2 white or black entries + in the colormap and finds the longest linear ramp between pairs of + white and black. If there is a color cube, also check its diagonal and + use its corners if we need to */ + +static void FindStaticGrayRamp( + Display *dpy, + XVisualInfo *vinfo, + XStandardColormap *grayRamp, + XStandardColormap *colorCube) +{ + XColor *ramp, *black, *white, *altBlack, *altWhite; + int i, r0, r1, r2, r3, size, entries, redMult; + unsigned long base; + + entries = 1 << vinfo->depth; + ramp = (XColor *) calloc(entries, sizeof(XColor)); + + if (ramp == NULL) { + grayRamp->red_max = 0; + return; + } + + /* Query the colormap */ + for (i = 0; i < entries; i++) ramp[i].pixel = i; + XQueryColors(dpy, grayRamp->colormap, ramp, entries); + + /* Find the white and black entries */ + + black = white = altBlack = altWhite = NULL; + for (i = 0; i < entries; i++) { + if (ramp[i].flags != (DoRed | DoBlue | DoGreen)) continue; + if (CheckColor(ramp+i, 0, 0, 0)) { + if (black == NULL) black = ramp+i; + else if (altBlack == NULL) altBlack = ramp+i; + } else if (CheckColor(ramp+i, 1, 1, 1)) { + if (white == NULL) white = ramp+i; + else if (altWhite == NULL) altWhite = ramp+i; + } + } + + if (black == NULL || white == NULL) { + grayRamp->red_max = 0; + free(ramp); + return; + } + + /* Find out how large a ramp exists between pairs of black & white */ + r0 = FindRampSize(black, white); + r1 = FindRampSize(altBlack, white); + r2 = FindRampSize(black, altWhite); + r3 = FindRampSize(altBlack, altWhite); + + size = r0; + if (r1 > size) size = r1; + if (r2 > size) size = r2; + if (r3 > size) size = r3; + if (size == r0) SetRamp(black, white, size, &redMult, &base); + else if (size == r1) SetRamp(altBlack, white, size, &redMult, &base); + else if (size == r2) SetRamp(black, altWhite, size, &redMult, &base); + else if (size == r3) SetRamp(altBlack, altWhite, size, &redMult, &base); + + if (colorCube != NULL && CubicCube(colorCube) && + colorCube->red_max > size) { + UseGrayDiagonal(colorCube, grayRamp); + } else { + grayRamp->red_max = size; + grayRamp->red_mult = redMult; + grayRamp->base_pixel = base; + } + + free(ramp); +} + +static int FindRampSize(XColor *black, XColor *white) +{ + XColor *c; + int r; + int mult = 1; + int i, size; + + if (black == NULL || white == NULL) return 0; + size = ABS(white - black); + + /* See if we have a backwards ramp */ + if (black > white) mult = -1; + + /* See if all cells between black and white are linear, to within 1 bit. + Only look at the high order 8 bits */ + + for (i = 1; i < size; i++) { + c = &black[i*mult]; + if (c->red != c->blue || c->red != c->green) return 1; + r = ((unsigned short) ((i * SCALE) / size) >> 8) - (c->red >> 8); + if (ABS(r) > 2) return 1; + } + return size; +} + +static void SetRamp( + XColor *black, + XColor *white, + int size, + int *mult, + unsigned long *base) +{ + *base = black->pixel; + *mult = (white - black) / size; +} + +#define lowbit(x) ((x) & (~(x) + 1)) + +static unsigned long shiftdown(unsigned long x) +{ + while ((x & 1) == 00) { + x = x >> 1; + } + return x; +} + +static void AllocateColorCube( + Display *dpy, + XVisualInfo *vinfo, + XStandardColormap *colorCube, + PixelRec *pixels) +{ + int count, first, remain, n, j; + unsigned long i; + Colormap cmap = colorCube->colormap; + unsigned long delta; + XColor color; + + /* We do no allocation for TrueColor or StaticColor */ + if (vinfo->class == TrueColor || vinfo->class == StaticColor) return; + + if (vinfo->class == DirectColor) { + if ((i = shiftdown(vinfo->red_mask)) > colorCube->red_max) + colorCube->red_max = i; + if ((i = shiftdown(vinfo->green_mask)) > colorCube->green_max) + colorCube->green_max = i; + if ((i = shiftdown(vinfo->blue_mask)) > colorCube->blue_max) + colorCube->blue_max = i; + + /* We only handle symmetric DirectColor */ + count = colorCube->red_max + 1; + if (colorCube->blue_max + 1 < count) count = colorCube->blue_max + 1; + if (colorCube->green_max + 1 < count) count = colorCube->green_max + 1; + colorCube->red_max = colorCube->blue_max = colorCube->green_max = + count - 1; + + delta = lowbit(vinfo->red_mask) + lowbit(vinfo->green_mask) + + lowbit(vinfo->blue_mask); + } else { + count = (colorCube->red_max + 1) * (colorCube->blue_max + 1) * + (colorCube->green_max + 1); + delta = 1; + } + + colorCube->base_pixel = 0; /* temporary, may change */ + + pixels->pixels = (unsigned long *) calloc(vinfo->colormap_size, + sizeof(unsigned long)); + if (pixels->pixels == NULL) { + colorCube->red_max = 0; + return; + } + + if (!AllocateColormap(dpy, colorCube, vinfo, &count, pixels, + &first, &remain, delta)) { + free((char *) pixels->pixels); + pixels->pixels = NULL; + colorCube->red_max = 0; + return; + } + + colorCube->base_pixel = pixels->pixels[first]; + color.flags = DoRed | DoGreen | DoBlue; + + /* Define colors */ + for (n = 0, j = 0; j < count; ++j, n += delta) { + color.pixel = n + pixels->pixels[first]; + if (vinfo->class == PseudoColor) { +#define calc(i, max, mult) ((((i / colorCube->mult) % \ + (colorCube->max + 1)) * SCALE) / colorCube->max) + color.red = (unsigned short) calc(n, red_max, red_mult); + color.green = (unsigned short) calc(n, green_max, green_mult); + color.blue = (unsigned short) calc(n, blue_max, blue_mult); +#undef calc + } else { + color.red = color.green = color.blue = + (j * SCALE) / colorCube->red_max; + } + if (!AllocateColor(dpy, cmap, &color)) { + XFreeColors(dpy, cmap, pixels->pixels, count+first+remain, 0); + free((char *) pixels->pixels); + pixels->pixels = NULL; + colorCube->red_max = 0; + return; + } + } + + /* Smush down unused pixels, if any */ + + for (j = 0; j < remain; j++) { + pixels->pixels[first+j] = pixels->pixels[first+count+j]; + } + pixels->npixels -= count; +} + +static void AllocateGrayRamp( + Display *dpy, + XVisualInfo *vinfo, + XStandardColormap *grayRamp, + XStandardColormap *colorCube, + PixelRec *pixels) +{ + int count, first, remain, n, i; + Colormap cmap = grayRamp->colormap; + XColor color; + unsigned long delta; + + /* Allocate cells in read/write visuals only */ + if (vinfo->class != PseudoColor && vinfo->class != GrayScale && + vinfo->class != DirectColor) return; + + if (vinfo->class == DirectColor) { + delta = lowbit(vinfo->red_mask) + lowbit(vinfo->green_mask) + + lowbit(vinfo->blue_mask); + } else delta = 1; + + /* First of all see if there's a usable gray ramp in the color cube */ + + if (colorCube != NULL) { + if (CubicCube(colorCube)) { + if (colorCube->red_max >= grayRamp->red_max) { + /* diagonal is long enough! use it */ + UseGrayDiagonal(colorCube, grayRamp); + return; + } + } + } + + grayRamp->base_pixel = 0; /* temporary, may change */ + + count = grayRamp->red_max + 1; + + if (pixels->pixels == NULL) { + pixels->pixels = (unsigned long *) calloc(vinfo->colormap_size, + sizeof(unsigned long)); + if (pixels->pixels == NULL) { + grayRamp->red_max = 0; + return; + } + } + + if (!AllocateColormap(dpy, grayRamp, vinfo, &count, pixels, + &first, &remain, delta)) { + /* Last gasp: try any diagonal or the corners of the color cube */ + if (colorCube != NULL) { + if (CubicCube(colorCube)) UseGrayDiagonal(colorCube, grayRamp); + else UseGrayCorners(colorCube, grayRamp); + } else { + grayRamp->red_max = 0; + } + return; + } + + grayRamp->base_pixel = pixels->pixels[first]; + color.flags = DoRed | DoGreen | DoBlue; + + /* Define colors */ + for (n = 0, i = 0; i < count; ++i, n += delta) { + color.pixel = n + pixels->pixels[first]; + color.red = (unsigned short)((n * SCALE) / (grayRamp->red_max)); + color.green = color.red; + color.blue = color.red; + + if (!AllocateColor(dpy, cmap, &color)) { + /* Don't need to free pixels here; we'll do it on return */ + grayRamp->red_max = 0; + return; + } + } + + /* Smush down unused pixels, if any */ + + for (i = 0; i < remain; i++) { + pixels->pixels[first+i] = pixels->pixels[first+count+i]; + } + pixels->npixels -= count; +} + +static int compare(const void *a1, const void *a2) +{ + register unsigned long *e1 = (unsigned long *) a1, + *e2 = (unsigned long *) a2; + + if (*e1 < *e2) return -1; + if (*e1 > *e2) return 1; + return 0; +} + +static Bool AllocateColormap( + Display *dpy, + XStandardColormap *map, + XVisualInfo *vinfo, + int *count, + PixelRec *pixels, + int *first, int *remain, + unsigned long delta) +{ + Colormap cmap = map->colormap; + int npixels, ok, i; + Bool success = False; + + if (pixels->npixels == 0) { + /* First try to allocate the entire colormap */ + npixels = vinfo->colormap_size; + ok = XAllocColorCells(dpy, cmap, 1, NULL, 0, pixels->pixels, npixels); + if (ok) success = True; + else { + int total; + int top, mid = 0; + + /* If it's a gray ramp or direct color we need at least 2; + others 8 */ + if (map->blue_max == 0 || vinfo->class == DirectColor) total = 2; + else total = 8; + + /* Allocate all available cells, using binary backoff */ + top = vinfo->colormap_size - 1; + while (total <= top) { + mid = total + ((top - total + 1) / 2); + ok = XAllocColorCells(dpy, cmap, 1, NULL, 0, + pixels->pixels, mid); + if (ok) { + if (mid == top) { + success = True; + break; + } else { + XFreeColors(dpy, cmap, pixels->pixels, mid, 0); + total = mid; + } + } else top = mid - 1; + } + if (success) npixels = mid; + else npixels = 0; + } + } else { + /* We must be in the gray ramp case, so we need at least 2 entries */ + npixels = pixels->npixels; + if (map->blue_max != 0 || npixels >= 2) success = True; + } + + if (success) { + /* Avoid pessimal case by testing to see if already sorted */ + for (i = 0; i < npixels-1; ++i) { + if (pixels->pixels[i] != pixels->pixels[i+1]-1) break; + } + + if (i < npixels-1) { + PrivSort((char *)pixels->pixels, npixels, + sizeof(unsigned long), compare); + } + + if (!contiguous(pixels->pixels, npixels, count, delta, + first, remain)) { + /* If there are enough free cells, shrink the map to fit. + Otherwise fail; we'll free the pixels later */ + if (((map->blue_max == 0 || vinfo->class == DirectColor) && + *count >= 2) || *count >=8) { + ShrinkMapToFit(map, count, vinfo); + *remain = npixels - *first - *count; + } else success = False; + } + } + + pixels->npixels = npixels; + return success; +} + +static Bool contiguous( + unsigned long pixels[], /* specifies allocated pixels */ + int npixels, /* specifies count of alloc'd pixels */ + int *ncolors, /* specifies needed sequence length + If not available, returns max + available contiguous sequence */ + unsigned long delta, + int *first, /* returns first index of sequence */ + int *rem) /* returns first index after sequence, + * or 0, if none follow */ +{ + register int i = 1; /* walking index into the pixel array */ + register int count = 1; /* length of sequence discovered so far */ + int max = 1; /* longest sequence we found */ + int maxstart = 0; + + *first = 0; + while (count < *ncolors && i < npixels) { + if (pixels[i-1] + delta == pixels[i]) count++; + else { + if (count > max) { + max = count; + maxstart = *first; + } + count = 1; + *first = i; + } + i++; + } + if (i == npixels && count > max) { + max = count; + maxstart = *first; + } + *rem = npixels - i; + if (count != *ncolors) { + *ncolors = max; + *first = maxstart; + return False; + } return True; +} + +static Bool AllocateColor( + Display *dpy, + Colormap cmap, + XColor *color) +{ + unsigned long pix = color->pixel; + XColor request; + int ok; + + request = *color; + + /* Free RW, Alloc RO, if fails, try RW */ + XFreeColors(dpy, cmap, &pix, 1, 0); + ok = XAllocColor(dpy, cmap, &request); + + /* If the pixel we get back isn't the request one, probably RO + White or Black, so shove it in RW so our cube is correct. + If alloc fails, try RW. */ + + if (!ok || request.pixel != color->pixel) { + ok = XAllocColorCells(dpy, cmap, 0, NULL, 0, &pix, 1); + + if (pix != color->pixel) XFreeColors(dpy, cmap, &pix, 1, 0); + if (!ok || pix != color->pixel) { + return False; + } + request = *color; + XStoreColor(dpy, cmap, &request); + } + return True; +} + +static void ShrinkMapToFit( + XStandardColormap *map, + int *space, + XVisualInfo *vinfo) +{ + if (map->blue_max == 0) map->red_max = *space - 1; + else if (vinfo->class == DirectColor) { + if (map->red_max > *space - 1) map->red_max = *space - 1; + if (map->green_max > *space - 1) map->green_max = *space - 1; + if (map->blue_max > *space - 1) map->blue_max = *space - 1; + } else { + int which = 2; + while ((map->red_max + 1) * (map->green_max + 1) * + (map->blue_max + 1) > *space) { + if (which == 0) { + if (map->red_max > 1) map->red_max--; + which = 1; + } else if (which == 1) { + if (map->green_max > 1) map->green_max--; + which = 2; + } else { + if (map->blue_max > 1) map->blue_max--; + which = 0; + } + } + *space = (map->red_max + 1) * (map->green_max + 1) * + (map->blue_max + 1); + + map->red_mult = (map->green_max + 1) * (map->blue_max + 1); + map->green_mult = map->blue_max + 1; + map->blue_mult = 1; + } +} + +static void DefineProperty( + Display *dpy, + XStandardColormap *map, + XVisualInfo *vinfo, + XStandardColormap *prop, + int nProp, + Atom atom) +{ + XStandardColormap *copy; + int i; + + if (nProp == 0) { + XSetRGBColormaps(dpy, RootWindow(dpy, vinfo->screen), map, 1, atom); + return; + } + + copy = (XStandardColormap *) calloc(nProp+1, sizeof(XStandardColormap)); + + /* Hm. If I can't allocate the list, is it better to just put our + property on, or to leave the ones there? I'll guess the latter... */ + if (copy == NULL) return; + + if (vinfo->visual == DefaultVisual(dpy, vinfo->screen) && + map->colormap == DefaultColormap(dpy, vinfo->screen)) { + /* Put new entry first; it's more likely to be useful */ + for (i = 0; i < nProp; i++) copy[i+1] = prop[i]; + i = 0; + } else { + /* Put it at the end */ + for (i = 0; i < nProp; i++) copy[i] = prop[i]; + /* i = nProp; (it does already) */ + } + + copy[i] = *map; + XSetRGBColormaps(dpy, RootWindow(dpy, vinfo->screen), copy, nProp+1, atom); + + free((void *) copy); +} |