#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xmu/StdCmap.h>
static int ROmap(Display*, Colormap, unsigned long[], int, int);
static Status ROorRWcell(Display*, Colormap, unsigned long[], int,
XColor*, unsigned long);
static Status RWcell(Display*, Colormap, XColor*, XColor*, unsigned long*);
static int compare(_Xconst void*, _Xconst void*);
static Status contiguous(unsigned long[], int, int, unsigned long, int*, int*);
static void free_cells(Display*, Colormap, unsigned long[], int, int);
static Status readonly_map(Display*, XVisualInfo*, XStandardColormap*);
static Status readwrite_map(Display*, XVisualInfo*, XStandardColormap*);
#define lowbit(x) ((x) & (~(x) + 1))
#define TRUEMATCH(mult,max,mask) \
(colormap->max * colormap->mult <= vinfo->mask && \
lowbit(vinfo->mask) == colormap->mult)
Status
XmuCreateColormap(Display *dpy, XStandardColormap *colormap)
{
XVisualInfo vinfo_template;
XVisualInfo *vinfo;
XVisualInfo *vpointer;
long vinfo_mask;
int n;
int status;
vinfo_template.visualid = colormap->visualid;
vinfo_mask = VisualIDMask;
if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
return 0;
vpointer = vinfo;
if (n > 1)
{
register int i;
register int screen_number;
Bool def_cmap;
def_cmap = False;
for (screen_number = ScreenCount(dpy); --screen_number >= 0; )
if (colormap->colormap == DefaultColormap(dpy, screen_number)) {
def_cmap = True;
break;
}
if (def_cmap) {
for (i=0; i < n; i++, vinfo++) {
if (vinfo->visual == DefaultVisual(dpy, screen_number))
break;
}
} else {
int maxdepth = 0;
XVisualInfo *v = NULL;
for (i=0; i < n; i++, vinfo++)
if (vinfo->depth > maxdepth) {
maxdepth = vinfo->depth;
v = vinfo;
}
vinfo = v;
}
}
if (vinfo->class == PseudoColor || vinfo->class == DirectColor ||
vinfo->class == GrayScale)
status = readwrite_map(dpy, vinfo, colormap);
else if (vinfo->class == TrueColor)
status = TRUEMATCH(red_mult, red_max, red_mask) &&
TRUEMATCH(green_mult, green_max, green_mask) &&
TRUEMATCH(blue_mult, blue_max, blue_mask);
else
status = readonly_map(dpy, vinfo, colormap);
XFree((char *) vpointer);
return status;
}
static Status
readwrite_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
{
register unsigned long i, n;
unsigned long ncolors;
int npixels;
int first_index;
int remainder;
XColor color;
unsigned long *pixels;
unsigned long delta;
if (vinfo->class == DirectColor) {
ncolors = colormap->red_max;
if (colormap->green_max > ncolors)
ncolors = colormap->green_max;
if (colormap->blue_max > ncolors)
ncolors = colormap->blue_max;
ncolors++;
delta = lowbit(vinfo->red_mask) +
lowbit(vinfo->green_mask) +
lowbit(vinfo->blue_mask);
} else {
ncolors = colormap->red_max * colormap->red_mult +
colormap->green_max * colormap->green_mult +
colormap->blue_max * colormap->blue_mult + 1;
delta = 1;
}
if (ncolors <= 1 || (int) ncolors > vinfo->colormap_size) return 0;
if ((pixels = (unsigned long *) calloc((unsigned) vinfo->colormap_size,
sizeof(unsigned long))) == NULL)
return 0;
if ((npixels = ROmap(dpy, colormap->colormap, pixels,
vinfo->colormap_size, ncolors)) == 0) {
free((char *) pixels);
return 0;
}
qsort((char *) pixels, npixels, sizeof(unsigned long), compare);
if (!contiguous(pixels, npixels, ncolors, delta, &first_index, &remainder))
{
XFreeColors(dpy, colormap->colormap, pixels, npixels,
(unsigned long) 0);
free((char *) pixels);
return 0;
}
colormap->base_pixel = pixels[first_index];
if (colormap->red_mult == 1 && colormap->green_mult == 1 &&
colormap->blue_mult == 1)
for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
{
color.pixel = n;
color.blue = color.green = color.red =
(unsigned short) ((i * 65535) / (colormap->red_max +
colormap->green_max +
colormap->blue_max));
if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
first_index + i))
return 0;
}
else if (colormap->green_max == 0 && colormap->blue_max == 0)
for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
{
color.pixel = n;
color.red = (unsigned short) ((i * 65535) / colormap->red_max);
color.green = color.blue = 0;
if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
first_index + i))
return 0;
}
else if (colormap->red_max == 0 && colormap->blue_max == 0)
for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
{
color.pixel = n;
color.green = (unsigned short) ((i * 65535) / colormap->green_max);
color.red = color.blue = 0;
if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
first_index + i))
return 0;
}
else if (colormap->red_max == 0 && colormap->green_max == 0)
for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
{
color.pixel = n;
color.blue = (unsigned short) ((i * 65535) / colormap->blue_max);
color.red = color.green = 0;
if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
first_index + i))
return 0;
}
else
{
#define calc(max,mult) (((n / colormap->mult) % \
(colormap->max + 1)) * 65535) / colormap->max
for (n=0, i=0; i < ncolors; i++, n += delta)
{
color.pixel = n + colormap->base_pixel;
color.red = calc(red_max, red_mult);
color.green = calc(green_max, green_mult);
color.blue = calc(blue_max, blue_mult);
if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
first_index + i))
return 0;
}
#undef calc
}
if (first_index)
XFreeColors(dpy, colormap->colormap, pixels, first_index,
(unsigned long) 0);
if (remainder)
XFreeColors(dpy, colormap->colormap,
&(pixels[first_index + ncolors]), remainder,
(unsigned long) 0);
free((char *) pixels);
return 1;
}
static int
ROmap(Display *dpy, Colormap cmap, unsigned long pixels[], int m, int n)
{
register int p;
if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL,
(unsigned) 0, pixels, (unsigned) m))
return m;
m--;
while (n <= m) {
p = n + ((m - n + 1) / 2);
if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL,
(unsigned) 0, pixels, (unsigned) p)) {
if (p == m)
return p;
else {
XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
n = p;
}
}
else
m = p - 1;
}
return 0;
}
static Status
contiguous(unsigned long pixels[], int npixels, int ncolors,
unsigned long delta, int *first, int *rem)
{
register int i = 1;
register int count = 1;
*first = 0;
if (npixels == ncolors) {
*rem = 0;
return 1;
}
*rem = npixels - 1;
while (count < ncolors && ncolors - count <= *rem)
{
if (pixels[i-1] + delta == pixels[i])
count++;
else {
count = 1;
*first = i;
}
i++;
(*rem)--;
}
if (count != ncolors)
return 0;
return 1;
}
static Status
ROorRWcell(Display *dpy, Colormap cmap, unsigned long pixels[],
int npixels, XColor *color, unsigned long p)
{
unsigned long pixel;
XColor request;
pixel = color->pixel;
request.red = color->red;
request.green = color->green;
request.blue = color->blue;
XFreeColors(dpy, cmap, &pixel, 1, (unsigned long) 0);
if (! XAllocColor(dpy, cmap, color)
|| (color->pixel != pixel &&
(!RWcell(dpy, cmap, color, &request, &pixel))))
{
free_cells(dpy, cmap, pixels, npixels, (int)p);
return 0;
}
return 1;
}
static void
free_cells(Display *dpy, Colormap cmap, unsigned long pixels[],
int npixels, int p)
{
XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
XFreeColors(dpy, cmap, &(pixels[p+1]), npixels - p - 1, (unsigned long) 0);
free((char *) pixels);
}
static Status
RWcell(Display *dpy, Colormap cmap, XColor *color, XColor *request,
unsigned long *pixel)
{
unsigned long n = *pixel;
XFreeColors(dpy, cmap, &(color->pixel), 1, (unsigned long)0);
if (! XAllocColorCells(dpy, cmap, (Bool) 0, (unsigned long *) NULL,
(unsigned) 0, pixel, (unsigned) 1))
return 0;
if (*pixel != n)
{
XFreeColors(dpy, cmap, pixel, 1, (unsigned long) 0);
return 0;
}
color->pixel = *pixel;
color->flags = DoRed | DoGreen | DoBlue;
color->red = request->red;
color->green = request->green;
color->blue = request->blue;
XStoreColors(dpy, cmap, color, 1);
return 1;
}
static int
compare(_Xconst void *e1, _Xconst void *e2)
{
return ((int)(*(long *)e1 - *(long *)e2));
}
static Status
readonly_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
{
int i, last_pixel;
XColor color;
last_pixel = (colormap->red_max + 1) * (colormap->green_max + 1) *
(colormap->blue_max + 1) + colormap->base_pixel - 1;
for(i=colormap->base_pixel; i <= last_pixel; i++) {
color.pixel = (unsigned long) i;
color.red = (unsigned short)
(((i/colormap->red_mult) * 65535) / colormap->red_max);
if (vinfo->class == StaticColor) {
color.green = (unsigned short)
((((i/colormap->green_mult) % (colormap->green_max + 1)) *
65535) / colormap->green_max);
color.blue = (unsigned short)
(((i%colormap->green_mult) * 65535) / colormap->blue_max);
}
else
color.green = color.blue = color.red;
XAllocColor(dpy, colormap->colormap, &color);
if (color.pixel != (unsigned long) i)
return 0;
}
return 1;
}