#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/Xmu/StdCmap.h>
#define lowbit(x) ((x) & (~(x) + 1))
static Status valid_args(XVisualInfo*, unsigned long, unsigned long,
unsigned long, Atom);
XStandardColormap *
XmuStandardColormap(Display *dpy, int screen, VisualID visualid,
unsigned int depth, Atom property, Colormap cmap,
unsigned long red_max, unsigned long green_max,
unsigned long blue_max)
{
XStandardColormap *stdcmap;
Status status;
XVisualInfo vinfo_template, *vinfo;
long vinfo_mask;
int n;
vinfo_template.visualid = visualid;
vinfo_template.screen = screen;
vinfo_template.depth = depth;
vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask;
if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
return NULL;
if (! valid_args(vinfo, red_max, green_max, blue_max, property)
|| ((stdcmap = XAllocStandardColormap()) == NULL)) {
XFree((char *) vinfo);
return NULL;
}
if (cmap == DefaultColormap(dpy, screen)) {
Window win = XCreateWindow(dpy, RootWindow(dpy, screen), 1, 1, 1, 1,
0, 0, InputOnly, vinfo->visual,
(unsigned long) 0,
(XSetWindowAttributes *)NULL);
stdcmap->killid = (XID) XCreatePixmap(dpy, win, 1, 1, depth);
XDestroyWindow(dpy, win);
stdcmap->colormap = cmap;
} else {
stdcmap->killid = ReleaseByFreeingColormap;
stdcmap->colormap = XCreateColormap(dpy, RootWindow(dpy, screen),
vinfo->visual, AllocNone);
}
stdcmap->red_max = red_max;
stdcmap->green_max = green_max;
stdcmap->blue_max = blue_max;
if (property == XA_RGB_GRAY_MAP)
stdcmap->red_mult = stdcmap->green_mult = stdcmap->blue_mult = 1;
else if (vinfo->class == TrueColor || vinfo->class == DirectColor) {
stdcmap->red_mult = lowbit(vinfo->red_mask);
stdcmap->green_mult = lowbit(vinfo->green_mask);
stdcmap->blue_mult = lowbit(vinfo->blue_mask);
} else {
stdcmap->red_mult = (red_max > 0)
? (green_max + 1) * (blue_max + 1) : 0;
stdcmap->green_mult = (green_max > 0) ? blue_max + 1 : 0;
stdcmap->blue_mult = (blue_max > 0) ? 1 : 0;
}
stdcmap->base_pixel = 0;
stdcmap->visualid = vinfo->visualid;
status = XmuCreateColormap(dpy, stdcmap);
XFree((char *) vinfo);
if (!status) {
if (stdcmap->killid == ReleaseByFreeingColormap)
XFreeColormap(dpy, stdcmap->colormap);
else if (stdcmap->killid != None)
XFreePixmap(dpy, stdcmap->killid);
XFree((char *) stdcmap);
return (XStandardColormap *) NULL;
}
return stdcmap;
}
static Status
valid_args(XVisualInfo *vinfo, unsigned long red_max, unsigned long green_max,
unsigned long blue_max, Atom property)
{
unsigned long ncolors;
if ((vinfo->class == DirectColor) || (vinfo->class == TrueColor)) {
unsigned long mask;
mask = vinfo->red_mask;
while (!(mask & 1))
mask >>= 1;
if (red_max > mask)
return 0;
mask = vinfo->green_mask;
while (!(mask & 1))
mask >>= 1;
if (green_max > mask)
return 0;
mask = vinfo->blue_mask;
while (!(mask & 1))
mask >>= 1;
if (blue_max > mask)
return 0;
} else if (property == XA_RGB_GRAY_MAP) {
ncolors = red_max + green_max + blue_max + 1;
if (ncolors > vinfo->colormap_size)
return 0;
} else {
ncolors = (red_max + 1) * (green_max + 1) * (blue_max + 1);
if (ncolors > vinfo->colormap_size)
return 0;
}
switch (property)
{
case XA_RGB_DEFAULT_MAP:
if (red_max == 0 || green_max == 0 || blue_max == 0)
return 0;
break;
case XA_RGB_RED_MAP:
if (red_max == 0)
return 0;
break;
case XA_RGB_GREEN_MAP:
if (green_max == 0)
return 0;
break;
case XA_RGB_BLUE_MAP:
if (blue_max == 0)
return 0;
break;
case XA_RGB_BEST_MAP:
if (red_max == 0 || green_max == 0 || blue_max == 0)
return 0;
break;
case XA_RGB_GRAY_MAP:
if (red_max == 0 || blue_max == 0 || green_max == 0)
return 0;
break;
default:
return 0;
}
return 1;
}