[comp.windows.x] using visuals correctly

lemke@SUN.COM (Dave Lemke) (10/05/88)

Having just seen the dozenth or so program that uses visuals
incorrectly, I think its about time to try to make the X community pay
closer attention to the problem.  The MIT X servers all expose dynamic
PseudoColor visuals as the default visual for multi-plane displays.
This has led to people using contructs such as:

	if (DisplayCells(dpy) > 2)	{	/* must be color */
		cmap = XCreateColormap(dpy, XDefaultRootWindow(dpy),
			XDefaultVisual(dpy, XDefaultScreen(dpy)),
			AllocNone);
		XAllocColorCells(dpy, cmap, .....);
	}

This is WRONG.  It will work on MIT X servers because of implementation
details, but it is not a correct usage of the X protocol, and will
fail on servers that have different implementation details.

1) More than 2 display cells doesn't mean you're on a color display.
It may be an 4 bit static gray scale, for example.  DisplayPlanes is
also commonly used, and can also be the wrong thing in this situation.

2) Even if it was a color display, XAllocColorCells needs a colormap
with a dynamic visual, and since the colormap was created with the
default, the code will fail on servers where the default visual
is a static visual.

This often doesn't show up until the client tries to do the first 
StoreColors into the color cells, at which point there's an access
error and Xlib (with the default error handler) exits the client.

The proper solution is to use the Visual info calls described in
section 10.8 of the Xlib manual.  The exact usage depends on what the
appication really needs dynamic color cells for, but if the client
simply wants a dynamic visual, it could do the following:

	visinfo = (XVisualInfo *) 0;
	vlist = XGetVisualInfo(dpy, VisualNoMask, &vinfo_template, &num_vis);
	/* find the first dynamic visual and break out of the loop */
	for (v = vlist; v < vlist + num_vis; v++)
		/* dynamic classed visuals are odd-numbered - see X.h */
		if (v->class & 0x1)	{
			visinfo = v;
			break;
		}
	if (visinfo == (XVisualInfo *) 0)	[
		fprintf(stderr,"couldn't get dynamic visual - exiting\n");
		exit(0);
	}
	/* make the colormap with the proper visual */
	cmap = XCreateColormap(dpy, XDefaultRootWindow(dpy), visinfo->visual,
		AllocNone);
	/* etc... */

Be aware also that all windows that wish to use this colormap also
need to use the matched visual -- CopyFromParent may not work.

People need to read the manual carefully.  X is only portable if you
make it portable.  Its very easy to make the mistake of taking
shortcuts to take advantage of implementation details which will cause
your code to break on servers other than the one you developed the code
on.

Dave Lemke
lemke@sun.com

PS.  and BlackPixel isn't necessarily 0, either...