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