#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"
#define PrivSort qsort
#include <stddef.h>
static char redsName[] = "reds";
static char greensName[] = "greens";
static char bluesName[] = "blues";
static char graysName[] = "grays";
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 (screen == NULL) {
if (drawable == None || ScreenCount(dpy) == 1) {
root = DefaultRootWindow(dpy);
screen = DefaultScreenOfDisplay(dpy);
} else {
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) {
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)) {
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;
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) {
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;
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;
} 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;
}
}
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) {
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) {
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) {
colorCube = &fakeCube;
}
if (colorCube != NULL) {
switch (vinfo->class) {
case StaticGray:
case GrayScale:
break;
case TrueColor:
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:
ColorValuesFromMask(vinfo->red_mask, &max,
&colorCube->red_mult);
ColorValuesFromMask(vinfo->green_mask, &max,
&colorCube->green_mult);
ColorValuesFromMask(vinfo->blue_mask, &max,
&colorCube->blue_mult);
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 (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;
}
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)) {
return 0;
}
}
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;
}
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;
}
for (i = 0; i < entries; i++) ramp[i].pixel = i;
XQueryColors(dpy, colorCube->colormap, ramp, 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;
}
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;
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 (CheckColor(color, 0, 0, 0)) return False;
if (CheckColor(color, 1, 1, 1)) return False;
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 (found != (R | G | B | C | M | Y)) return False;
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;
if (backwards) {
w = ABS(w);
r = ABS(r);
g = ABS(g);
b = ABS(b);
}
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;
}
if ((middle % (small + 1)) != 0) return False;
if ((large % (small + middle + 1)) != 0) return False;
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 {
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;
}
}
if (backwards) {
test.red_mult *= -1;
test.green_mult *= -1;
test.blue_mult *= -1;
}
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
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;
}
for (i = 0; i < entries; i++) ramp[i].pixel = i;
XQueryColors(dpy, grayRamp->colormap, ramp, 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;
}
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);
if (black > white) mult = -1;
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;
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;
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;
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;
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;
}
}
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;
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;
if (colorCube != NULL) {
if (CubicCube(colorCube)) {
if (colorCube->red_max >= grayRamp->red_max) {
UseGrayDiagonal(colorCube, grayRamp);
return;
}
}
}
grayRamp->base_pixel = 0;
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)) {
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;
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)) {
grayRamp->red_max = 0;
return;
}
}
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) {
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 (map->blue_max == 0 || vinfo->class == DirectColor) total = 2;
else total = 8;
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 {
npixels = pixels->npixels;
if (map->blue_max != 0 || npixels >= 2) success = True;
}
if (success) {
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 (((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[],
int npixels,
int *ncolors,
unsigned long delta,
int *first,
int *rem)
{
register int i = 1;
register int count = 1;
int max = 1;
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;
XFreeColors(dpy, cmap, &pix, 1, 0);
ok = XAllocColor(dpy, cmap, &request);
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));
if (copy == NULL) return;
if (vinfo->visual == DefaultVisual(dpy, vinfo->screen) &&
map->colormap == DefaultColormap(dpy, vinfo->screen)) {
for (i = 0; i < nProp; i++) copy[i+1] = prop[i];
i = 0;
} else {
for (i = 0; i < nProp; i++) copy[i] = prop[i];
}
copy[i] = *map;
XSetRGBColormaps(dpy, RootWindow(dpy, vinfo->screen), copy, nProp+1, atom);
free((void *) copy);
}