[comp.windows.x] Wanted: Example code using DirectColor 24 bit Visual

markv@pixar.com (Mark VandeWettering) (04/11/91)

I am having trouble with a current project that requires the use of a 
24 bit directcolor visual under X windows.  Everytime I do a XCreateWindow,
I get a XBadMatch error, which I cannot figure out the cause of. (gosh, 
leave that preposition dangling).

The steps I need to do is:

	1.  Use XMatchVisual to decide if a 24 bit visual is available
	    (it is not my default visual)
	2.  Use XCreateWindow to create a window.
	3.  Create an XImage to be used with the window.

If anyone has a simple program or program fragment that you know works, then
please send it to me.  I am also open to any hints on how to proceed, as
I am strictly a novice X programmer.

If it helps, I have tested this on an HP9000 300 series, which supports
X11R3.  

Thanks in advance.

	Mark VandeWettering (markv%pixar.uucp@ucbvax.berkeley.edu)

rthomson@mesa.dsd.es.com (Rich Thomson) (04/14/91)

In article <1991Apr10.190204.20085@pixar.com>
	markv@pixar.com (Mark VandeWettering) writes:
>I am having trouble with a current project that requires the use of a 
>24 bit directcolor visual under X windows.  Everytime I do a XCreateWindow,
>I get a XBadMatch error, which I cannot figure out the cause of. (gosh, 
>leave that preposition dangling).
>
>The steps I need to do is:
>
>	1.  Use XMatchVisual to decide if a 24 bit visual is available
>	    (it is not my default visual)
>	2.  Use XCreateWindow to create a window.
>	3.  Create an XImage to be used with the window.

Try creating a colormap and explicitly setting the colormap,
foreground/background pixel entries in the window attributes
structure.  Chances are you're getting a bad match because the root
window isn't the same visual type as your directcolor window.  If you
don't supply the needed attributes the server attempts to inherit them
from the parent window (I assume the root window in your case), where
they won't be properly matched for the new window's visual.

Here's a little program that opens up a directcolor window on our
server (which supports TrueColor, DirectColor and PseudoColor visuals).
This program is from the MIT X11R4 contrib software.

							-- Rich

/*
 * worm.c: draw wiggly worms.
 *
 * Adapted from a concept in the Dec 87 issue of Scientific American.
 * Makes a nice lockscreen via "lockscreen nice worm".
 *
 * compile: cc worm.c -o worm -lm -lsuntool -lsunwindow -lpixrect
 *
 * usage: worm [-l length] [-s size] [-n number]
 *	where "length" is length of each worm in segments (default 50)
 *	      "size" is size of each segment (default 2)
 *	      "number" is number of worms to draw (default 64)
 *
 * This program looks best on a color monitor. Try these options:
 * worm -n 1	   Just one really fast worm
 * worm -l 2       Paramecia
 * worm -s 500     Mondrian painting (actually enormous worms)
 * worm -l -1      Jackson Pollack painting (actually infinite length worms)
 *
 * -- Thu Dec 17 09:58:48 PST 1987
 * -- Brad Taylor (brad@sun)
 */

/*
 * hacked to use X11 by Dave Lemke (lemke@sun.com)
 * Wed Dec 23 09:57:32 PST 1987
 *
 * additional options:
 *	-S -R -C [-g geometry] [-d display]
 *	
 *	-S	screen saver mode - covers screen
 *	-R	rotate colormap while running
 *	-C	chromocolor worms - colors change as they crawl
 */

/************************************************************
Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.

		All Rights Reserved

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, 
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in 
supporting documentation, and that the names of Sun or MIT not be
used in advertising or publicity pertaining to distribution of the
software without specific prior written permission. Sun and M.I.T. 
make no representations about the suitability of this software for 
any purpose. It is provided "as is" without any express or implied warranty.

SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOFTWARE.
************************************************************/

#include	<stdio.h>
#include	<sys/types.h>
#include	<math.h>
#include	<X11/Xos.h>
#include	<X11/Xlib.h>
#include	<X11/Xutil.h>

#define	NUM_COLORS	256
#define	MIN_COLORS	16
#define SEGMENTS  36
#define PI 3.14159265358979323844

extern char *malloc();
extern long random();

typedef struct _wormstuff {
	int *xcirc;
	int *ycirc;
	int dir;
	int tail;
	int x;
	int y;
}	wormstuff;


wormstuff *worm_init();
int wormlength = 50;
int circsize = 2;
int nworms = 64;
int sintab[SEGMENTS];
int costab[SEGMENTS];
int ncolors;

XWMHints	xwmh =	{
	(InputHint | StateHint), True, NormalState, 0, 0, 0, 0, 0, 0,
};

Display	*dpy;
Window	w;
int	screen;
GC	gc, wgc;
Colormap	cmap;
Bool	is_color = True;
Bool	is_dynamic = False;
Bool	screen_saver = False;
Bool	rotate = False;
Bool	chromocolor = False;
XColor	colors[NUM_COLORS];
extern char	*getenv();
char	*defgeo = "=500x500+10+10";
Visual	*visual;
int	depth = 1;
long	backpixel;
Atom	protocol_atom, kill_atom;

main(argc, argv)
	int argc;
	char **argv;
{
	char	*display = NULL;
	char	*geo = NULL;
	int xsize = 500;
	int ysize = 500;
	int	x = 0, y = 0;
	register int i;
	wormstuff **worm;
	char *cmd;
	char	c;
	extern int optind;
	extern char *optarg;
	XSizeHints	xsh;
	XWindowAttributes	xwa;
	int	vmask;
	XSetWindowAttributes	values;
	Bool	freeze = False;
	Bool	is_visible = True;

	cmd = argv[0];
	while ((c = getopt(argc, argv, "SCRl:n:g:d:s:")) != EOF)
		switch(c)	{
		case 'l':
			wormlength = atoi(optarg);
			break;
		case 'n':
			nworms = atoi(optarg);
			break;
		case 's':
			circsize = atoi(optarg);
			break;
		case 'd':
			display = optarg;
			break;
		case 'g':
			geo = optarg;
			break;
		case 'S':
			screen_saver = True;
			break;
		case 'C':
			chromocolor = True;
			break;
		case 'R':
			rotate = True;
			break;
		case '?':
			usage(cmd);
			}

	srandom(getpid());
	for (i = 0; i < SEGMENTS; i++) {
		sintab[i] = round(circsize * sin(i * 2 * PI / SEGMENTS));
		costab[i] = round(circsize * cos(i * 2 * PI / SEGMENTS));
	}
	if ((dpy = XOpenDisplay(display)) == NULL)	{
		fprintf(stderr,"Can\'t open %s\n", 
			(display ? display : getenv("DISPLAY")));
		exit(0);
		}
	screen = DefaultScreen(dpy);
	ncolors = NUM_COLORS;

	if (screen_saver)	{
		xsize = DisplayWidth(dpy, screen);
		ysize = DisplayHeight(dpy, screen);
		x = 0; y = 0;
		}
	else		{
		int	flags;

		if (geo == NULL)
			geo = defgeo;
		flags = XParseGeometry(geo, &x, &y, &xsize, &ysize);
		if ((flags & XValue) && (flags & XNegative))
			x += DisplayWidth(dpy, screen) - xsize;
		if ((flags & YValue) && (flags & YNegative))
			y += DisplayHeight(dpy, screen) - ysize;
		}

	visual = DefaultVisual(dpy, screen);
	depth = DefaultDepth(dpy, screen);
	cmap = DefaultColormap(dpy, screen);

	/* set up the color map */
	if (DisplayCells(dpy, screen) > 2)
		cmap_init(w);
	else	{
		is_color = False;
		backpixel = BlackPixel(dpy, screen);
		}

	vmask = CWBackPixel | CWColormap;
	values.background_pixel = backpixel;
	values.colormap = cmap;

	w = XCreateWindow(dpy, RootWindow(dpy, screen), x, y, xsize, ysize, 0, 
		depth, InputOutput, visual, vmask, &values);

	xsh.flags = (PPosition | PSize);
	xsh.x = x; xsh.y = y;
	xsh.width = xsize; xsh.height = ysize;
	XSetStandardProperties(dpy, w, "Worms", "Worms", None, 
		argv, argc, &xsh);
	XSetWMHints(dpy, w, &xwmh);

	protocol_atom = XInternAtom(dpy, "WM_PROTOCOLS", False);
	kill_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
	XSetWMProtocols(dpy, w, &kill_atom, 1);

	XMapRaised(dpy, w);
	XSelectInput(dpy, w, ExposureMask | StructureNotifyMask | 
#ifdef DUMB_WM
		EnterWindowMask | LeaveWindowMask |
#endif
		KeyPressMask | VisibilityChangeMask);
	gc = XCreateGC(dpy, w, 0, 0);
	wgc = XCreateGC(dpy, w, 0, 0);
	XSetForeground(dpy, wgc, WhitePixel(dpy, screen));

	worm = (wormstuff **)malloc((unsigned)(sizeof(wormstuff) * nworms));
	for (i = 0; i < nworms; i++)	{
		worm[i] = worm_init(xsize, ysize, wormlength);
		}

	for (;;) {
		XEvent	e;
		register int	wcolor, chromo;	/* chromo looks best with HSB */

		if (XPending(dpy))	{
			XNextEvent(dpy, &e);

			if (e.type == VisibilityNotify)	{
				XVisibilityEvent *ev = (XVisibilityEvent *) &e;
				if (ev->state == VisibilityFullyObscured)
					is_visible = False;
				else is_visible = True;
				}
			else if (e.type == KeyPress)	{
				if (freeze == False)
					freeze = True;
				else freeze = False;
				}
			else if (e.type == ConfigureNotify)	{
				XConfigureEvent *ev = (XConfigureEvent *) &e;

				xsize = ev->width; ysize = ev->height;
				for (i = 0; i < nworms; i++)	{
					free(worm[i]->xcirc); 
					free(worm[i]->ycirc);
					free(worm[i]);
					worm[i] = worm_init(xsize, ysize, 
						wormlength);
					}
				XClearWindow(dpy, w);
/* really want to remove all the pending graphics requests - can't figure out
 * how...
 * attempted to use GraphicsExposure, but it put so much crap into the
 * queue that the configure was never found... */
				XFlush(dpy);
				}
			else if (e.type == ClientMessage)	{
			XClientMessageEvent *ev = (XClientMessageEvent *)&e;

			if (ev->message_type == protocol_atom && 
			    ev->data.l[0] == kill_atom)
				exit(0);
			}
#ifdef DUMB_WM
			else if (e.type == EnterNotify)
				XInstallColormap(dpy, cmap);
			else if (e.type == LeaveNotify)
				XUninstallColormap(dpy, cmap);
#endif
			/*
			 * since visibvility notify doesn't allow for 
			 * the totally obscured -> partially obscured
			 * case, we have to depend on exposure instead.
			 */
			else if (e.type == Expose)
				is_visible = True;
			}
		if (is_visible)	{
			if (rotate && is_color && is_dynamic)   {
				rotate_colors();
				}
			if (!freeze)	{
			    for (i = 0; i < nworms; i++) {
				wcolor = (((i * ncolors) / nworms) + chromo) 
					% ncolors;
				worm_doit(worm[i], xsize, ysize, 
					colors[wcolor].pixel);
				}
			    }
			/* note that there is a little jump in the worms
			 * if they are frozen and no rotation exists.
			 * doesn't seem to be possible to (easily) get away 
			 * from this */
			}
		if (chromocolor)
			chromo++;
	}
}

rotate_colors()
{
register int	i;
long	temp;

	temp = colors[1].pixel;		/* start at 1 - don't want the black */
	for (i = 1; i < ncolors - 1; i++)	{
		colors[i].pixel = colors[i+1].pixel;
		}
	colors[ncolors - 1].pixel = temp;
	XStoreColors(dpy, cmap, colors, ncolors);
}

wormstuff *
worm_init(xsize, ysize, wormlength)
	int xsize;
	int ysize;
	int wormlength;
{
	register int i;
	wormstuff *ws;

	ws = (wormstuff *)malloc(sizeof(wormstuff));
	if (wormlength > 0) {
		ws->xcirc = (int *)malloc((unsigned)(wormlength * 
						     sizeof(int)));
		ws->ycirc = (int *)malloc((unsigned)(wormlength * 
						     sizeof(int)));
		for (i = 0; i < wormlength; i++) {
			ws->xcirc[i] = xsize / 2;
			ws->ycirc[i] = ysize / 2;
		}
	}
	ws->dir = (unsigned) random() % SEGMENTS;
	ws->tail = 0;
	ws->x = xsize / 2;
	ws->y = ysize / 2;
	return (ws);
}

worm_doit(ws, xsize, ysize, color)
	register wormstuff *ws;
	int xsize;
	int ysize;
	unsigned long color;
{
	register int x, y;

	if (wormlength > 0) {
		ws->tail = (ws->tail + 1) % wormlength;
		x = ws->xcirc[ws->tail];
		y = ws->ycirc[ws->tail];
		XClearArea(dpy, w, x, y, circsize, circsize, False);
	}
	if (random() & 1) {
		ws->dir = (ws->dir + 1) % SEGMENTS;
	} else {
		ws->dir = (ws->dir + SEGMENTS - 1) % SEGMENTS;
	}
	x = (ws->x + costab[ws->dir] + xsize) % xsize;
	y = (ws->y + sintab[ws->dir] + ysize) % ysize;
	if (wormlength > 0) {
		ws->xcirc[ws->tail] = x;
		ws->ycirc[ws->tail] = y;
	}
	if (is_color)
		drawseg(x, y, color);
	else	{
		XFillRectangle(dpy, w, wgc, x, y, circsize, circsize);
		}
	ws->x = x;
	ws->y = y;
}


round(x)
	float x;
{
	return ((int) rint((double)x));
}

drawseg(x, y, c)
	int	x, y;
	unsigned long	c;
{
	XSetForeground(dpy, gc, c);
	XFillRectangle(dpy, w, gc, x, y, circsize, circsize);
}

usage(cmd)
	char *cmd;
{
	(void)fprintf(stderr, 
"usage: %s -S -C -R [-l length] [-s size] [-n number]\n[-g geometry] [-d display]\n -S screensaver\n -C chromocolor\n -R Rotate colormap\n",
		       cmd);
	exit(1);
}

cmap_init(win)
	Window	win;
{
int	pixels[NUM_COLORS];
int	pmasks;
register int	i;
XVisualInfo	vinfo;
int	num_vis, vmask;
XColor	stat_colors[NUM_COLORS];
int	planes;

#define	VALUES	256
#define	rnd(x)	(random() % x)

/* #define	RANDOM		/* use an random colormap - messy */
#define	HSB		/* use an HSB colormap - makes colorwheel look neat */

	planes = DisplayPlanes(dpy, screen);
	/* see what kind of visual we're dealing with */
	if (XMatchVisualInfo(dpy, screen, planes, PseudoColor, &vinfo)
		|| XMatchVisualInfo(dpy, screen, planes, GrayScale, &vinfo)
		|| XMatchVisualInfo(dpy, screen, planes, DirectColor, &vinfo))
	    goto read_write_map;
	else
	    goto read_only_map;

read_write_map:
	visual = vinfo.visual;
	depth = vinfo.depth;
	cmap = XCreateColormap(dpy, RootWindow(dpy, screen), visual, AllocNone);
	ncolors = vinfo.colormap_size;
	/* grab as many color cells as we can */
	for (i = ncolors; i > MIN_COLORS; i--)	{
		if (XAllocColorCells(dpy, cmap, False, &pmasks, 0, pixels, i))
			break;
		}
	if (i == MIN_COLORS)	{
		fprintf(stderr,
		    "Couldn't allocate even %d colors - exiting\n", MIN_COLORS);
		exit(0);
		}
	ncolors = i;
#ifdef RANDOM
	/* make the black for background */
	backpixel = colors[0].pixel = pixels[0];
	colors[0].red = colors[0].green = colors[0].blue = 0;
	colors[0].flags = DoRed | DoGreen | DoBlue;
	for (i = 1; i < ncolors; i++)	{
		colors[i].pixel = pixels[i];
		colors[i].red = rnd(VALUES) << 8;
		colors[i].green = rnd(VALUES) << 8;
		colors[i].blue = rnd(VALUES) << 8;
		colors[i].flags = DoRed | DoGreen | DoBlue;
		}
	XStoreColors(dpy, cmap, colors, ncolors);
#else
#ifdef HSB
/* this colormap makes things look a lot nicer when worms goes
 * into freeze mode.
 */
	{
	double	hue, sat, bright, r, g, b;

	sat = 0.9;
	bright = 1.0;

	/* make the black for background */
	backpixel = colors[0].pixel = pixels[0];
	colors[0].red = colors[0].green = colors[0].blue = 0;
	colors[0].flags = DoRed | DoGreen | DoBlue;
	for (i = 1; i < ncolors; i++)	{
		hue = (float) i / (float) ncolors;
		hsb2rgb(hue, sat, bright, &r, &g, &b);
		colors[i].pixel = pixels[i];
		colors[i].red = (int) (r * 255.0) << 8;
		colors[i].green = (int) (g * 255.0) << 8;
		colors[i].blue = (int) (b * 255.0) << 8;
		colors[i].flags = DoRed | DoGreen | DoBlue;
		}
	XStoreColors(dpy, cmap, colors, ncolors);
	}
#else
	for (i = 0; i < ncolors; i++)
		stat_colors[i].pixel = i;
	XQueryColors(dpy, DefaultColormap(dpy, screen), stat_colors, ncolors);
	XStoreColors(dpy, cmap, stat_colors, ncolors);
	bcopy(stat_colors, colors, ncolors * sizeof(XColor));
#endif
#endif
	is_dynamic = True;

	return;

read_only_map:

	is_dynamic = False;
	visual = vinfo.visual;
	depth = vinfo.depth;
	/* for a Static colormap, just make each worm a random pixel */
	for (i = 0; i < NUM_COLORS; i++)	{
		colors[i].pixel = rnd(NUM_COLORS);
		}
}

hsb2rgb(h, s, i, r, g, b)
double	h, s, i;
double	*r, *g, *b;
{
register int	j;
register double	f, p, q, t;

	if (s == 0.0)
		*r = *g = *b = i;
	else	{
		h -= floor(h);	/* remove anything over 1 */
		h *= 6.0;
		j = floor(h);
		f = h - (float) j;
		p = i * (1.0 - s);
		q = i * (1.0 - s * f);
		t = i * (1.0 - (s * (1.0 - f)));

		switch(j)	{
			case	0:
				*r = i;
				*g = t;
				*b = p;
				break;
			case	1:
				*r = q;
				*g = i;
				*b = p;
				break;
			case	2:
				*r = p;
				*g = i;
				*b = t;
				break;
			case	3:
				*r = p;
				*g = q;
				*b = i;
				break;
			case	4:
				*r = t;
				*g = p;
				*b = i;
				break;
			case	5:
				*r = i;
				*g = p;
				*b = q;
				break;
			}
		}
}
-- 
  ``Read my MIPS -- no new VAXes!!'' -- George Bush after sniffing freon
	    Disclaimer: I speak for myself, except as noted.
UUCP: ...!uunet!dsd.es.com!rthomson		Rich Thomson
ARPA: rthomson@dsd.es.com			PEXt Programmer