Colormap FAQ List

Last Updated: 13th March 1998
Copyright 1994-98 Sun Microsystems, Inc.

Permission is granted to distribute this document freely, provided it remains unaltered.
This permission does not extend to the targets of any links.

This document is written and maintained by [email protected] or [email protected]

I maintain this FAQ purely for the fun of it, and because if I didn't it wouldn't get done. If you've found it helpful, please let me know. Or better still, let my manager [email protected] know!

I am keen to receive any corrections, updates, suggestions, etc.
I can be contacted by email as [email protected] or by post at
UMTV16-218, 901 San Antonio Road Palo Alto, California 94303

Customers please note:

If you have a technical question that is not answered by this FAQ, please don't send it to me, contact your local Answer Centre. If you don't know the number, ask your sales representative or contact your local Sun office.


Eliminate Colormap Flashing!

I've created a small library that will eliminate colormap flashing in many cases, though not all. It works by intercepting calls to XAllocColor, and checking the return. If the allocation failed, it returns the closest read-only match. Feedback is welcome. You can download the source (freely distributable) and the library compiled for Solaris 2.5.1

To use, simply set the LD_PRELOAD environmental variable, thus:

	% setenv LD_PRELOAD /(mydir)/libnoflash.so.1
and the library will be picked up automagically.

NB: If you are using Java applications this library can cause Java to crash with a segmentation violation. This is related to bug 4028760, but fortunately there's a simple work-around; it does not crash if you also preload the Motif library, thus:

    % setenv LD_PRELOAD "/(mydir)/libnoflash.so.1 /usr/dt/lib/libXm.so.3"

Get informed of updates automatically

The Colormap FAQ is updated occasionally. By registering this URL with NetMind you will receive an email notification when the page is updated. This service is free. I have no connection with NetMind.

Note for Sun Internal users: You will have to register one of the mirror sites.


Getting the latest copy of the FAQ

From within Sun, go to From outside Sun, try these sites: If you want to host a mirror site, please send me email so I can notify you of updates. Glowing letters of praise should be addressed to my manager and/or to the Webmaster at this site.

I do try to maintain the accuracy of the information; your assistance is appreciated. No responsibility is taken for any inaccuracies.

A Note On Spelling

Being English, I tend to refer to colours rather than colors. Where I've used the latter spelling, it's because X requires it. Rather than add to the confusion, I've consistently used the term colormap throughout.


Contents

Click on the "?" logo to get back to here
Background

1. What is Colormap Flashing?

2. How can I tell how many colours are allocated?

3. How do I stop the colours flashing as I move the cursor around?

4. Can I protect any of the colours against flashing?

5. Why do I get white or coloured text when I exit OpenWindows?

6. How does XView handle colour?

7. My canvas requires a lot of colours. How can I reduce flashing?

8. Can I guarantee the pixel values of any colours, e.g. Black and White?

9. Can I share colormaps across different frame buffers?

10. Lines drawn using logical operations appear in odd colours.

11. How does Display PostScript handle colour?

12. Where is clear_colormap for Solaris 2.3?

13. Why do Imagetool and Pageview flash?

14. How does NeWS handle colour?

15. Does the X server support the Standard colormaps?

16. How does Wabi access the colormap?

17. How do I find out what visuals are available?

18. How does CDE handle colour?

19. How can I reduce colormap flashing with Netscape?

20. How do PC based X servers handle colours?

21. What is gamma correction?

Is there anything else I should look at?

Code Fragments

A. Example of reduced colormap flashing using XView

B. Allocating and using the RGB_BEST_MAP standard colormap

C. Source to libnoflash.so

Background

If you are unfamiliar with any of the terms and concepts used, please look at Chapter 7 of the Xlib Programming Manual (Volume One) published by O'Reilly & Associates Inc. The explanations given there are very well written and easy to read.

1. What is Colormap Flashing?

The default colormap which is created when OpenWindows is invoked has a fixed number of elements, normally 256. This means that up to 256 different colours can be allocated (note that not all will necessarily be visible at the time).

If an application attempts to allocate a new colour and there is no space in the colormap, it will get an error returned from the server. At this point the application has two alternatives: to accept the limitation and use only those colours which are already defined, or to create a new colormap for its sole use.

Assuming that the latter approach is taken, whenever the user moves the mouse cursor over the application window the server will automatically switch in the custom colormap to replace the default. In doing so, the colours of various items and windows may well be affected. In some cases other windows may become illegible, due to odd combinations of foreground and background colours - making it difficult to view multiple windows simultaneously.

2. How can I tell how many colours are allocated?

There is no easy way to do this - all you can do is to ask for a colour and see if you get a successful return or not. If you want to see which colours are allocated, run the program xcolor which is in the OpenWindows bin directory.

When an application frees a colour, the server does not necessarily reset that colour back to any default value; it retains its value until over-written by another application. When you move your cursor into the xcolor window, it will load a new colormap which contains a band of bright colours. When you move the cursor out again, those colours which are currently unallocated will keep the bright colour, those which are allocated will revert to the correct colour. If you do not want to use this function you can disable it with the option -noinst

3. How do I stop the colours flashing as I move the cursor around?

One option to reduce the flashing is to "lock" a colormap, so that as the cursor is moved around the server does not load in new colormaps. This can be done by setting a resource in the .Xdefaults file. Remember to run xrdb -merge or to restart OpenWindows after editing the file or the changes will not take effect.
(These resources are documented in the manual page for olwm.)

olwm.ColorFocusLocked:

If True, this instructs the server to keep the current colormap locked into the hardware, and not to change it as the mouse is moved around. The default is False.

olwm.AutoColorFocus:

If True, this instructs the server to load the colormap for a new window into the hardware as it is displayed, regardless of whether the mouse is over it. The default is False.

olwm.KeyboardCommand.LockColormap:

This allows the user to change the key sequence which locks the window's colormap into the hardware. The default is Control-L2.

olwm.KeyboardCommand.UnlockColormap:

This allows the user to change the key sequence which unlocks the colormap. The default is Control-L4.

4. Can I protect any of the colours against flashing?

There is a program called cmap_compact which is automatically executed by the script $OPENWINHOME/lib/openwin-sys when OpenWindows is started. This program will look for a file .owcolors in your home directory, and if found will load those colours at the top end of the colormap, thus reducing the likelihood of their being over-written.

.owcolors is a binary file, and thus is difficult for the user to edit. It is created by calling cmap_compact with the argument save - this will store ALL the currently allocated colours in your home directory.

The best way to use this is to run cmap_compact save as soon as you start OpenWindows - this will save only those colours which are used by applications in your .openwin-init file. (Note however that if you invoke any NeWS applications on startup, the entire NeWS cube will also be saved unless you free it first - see below).

If you want to add extra colours to the protected set (for example, the six primary and secondary colours Red, Green, Blue, Cyan, Magenta, Yellow - this can be very helpful if you intend to run NeWS applications) it is necessary to first get them into the colourmap. The easiest way I have found is to simply start additional shelltools with the appropriate colours as their foreground or background colours
(ie shelltool -fg blue -bg yellow &)
before calling cmap_compact - it's inelegant but it works.

It's worth pointing out that the .owcolors file may not be portable across all platforms, and that other users will most likely have changed the colours of their background or window borders, so the file should be treated as any other user-defined configuration file.

5. Why do I get white or coloured text when I exit OpenWindows?

A bug in the OpenWindows V3.3 server means that the last entry in the colormap, #255, does not get reset to black when the server quits. The system uses this colour to write to the console outside OpenWindows. The worst part of this is that the startup banner puts white into colour cell 255. As a result the text can be white-on-white, thus the users never sees the prompt, even if they press L1-A. The bug ID is 1136010 As a workaround, start openwin with the -nobanner flag. The problem should be fixed by installing patch 101362.

6. How does XView handle colour?

XView adds a second level of indirection to colour allocation by using a COLORMAP SEGMENT (CMS). This is an XView (as opposed to Xlib) entity, and is explained in detail in Chapter 21 of the XView Programming Manual.

If XView can fit all the available colours within the default colormap it will do so, otherwise it will create a new colormap and will copy all the colours into it. Unfortunately it will copy these colours to the beginning of the colormap, which makes the effects of flashing more obvious - the colours which handle background, foreground, backdrop (ie root window) and window decoration tend to be at the start of the default colormap, since they are among the first to be allocated.

7. My canvas requires a lot of colours. How can I reduce flashing?

The effects of flashing can be reduced by creating a colormap, copying the colours across from the default colormap, and avoiding over-writing the most sensitive areas. These tend to be the first few and the last two entries (caveat: if you over-write the colours which have been protected by cmap_compact you will make things worse, not better.)

Under XView, the only way to do this is by bypassing the CMS and using Xlib calls to create and install a colormap. There are one or two "gotcha"s here, in particular the use of an X atom to instruct the server to load the colormap when the cursor is moved over the window.

Consequently an example demonstrating how to do this has been written and is attached ath the end of this document. (All the usual disclaimers apply)

This is a fairly drastic solution, and should only be considered in situations where the previously mentioned solutions of setting resources or using cmap_compact have been rejected.

The example works by automatically installing a special colormap for the canvas paint window. This colormap is not used by the rest of the XView application, so if you wish to set colours for individual panel items, such as buttons, then you must do so by creating a CMS. This is likely to cause flashing, so you may wish to reconsider whether or not this is a good idea.

8. Can I guarantee the pixel values of any colours, e.g. Black and White?

As of V3.3, openwin supports two new options - -whitepixel and -blackpixel. These allow you to specify index values for black and white (in the range 0-255).

Prior to 3.3 you could only guarantee that "black" and "white" colours would be allocated, and that BlackPixel and WhitePixel would return the appropriate pixel values.
Depending on whether or not cmap_compact has been run, the default pixel values will almost certainly be either 0 and 1 or 254 and 255, but these values cannot be relied on. Other colours will need to be allocated by the user.

9. Can I share colormaps across different frame buffers?

No. It is important to realise that if a machine has two frame buffers, then each will have a completely different colormap table. Thus, if a pixel value of 5 corresponds to green on the first frame buffer, there is no guarantee that 5 will correspond to green on the second.

This can cause problems if an application intends to create windows on multiple screens and wants to use the same pixel values on each. One solution would be to attempt to allocate a large number of cells on each screen, and then only to use those cells which were common to both. Another solution would be to allocate a custom colormap on each screen and then to lock it using the techniques detailed above.

10. Lines drawn using logical operations appear in odd colours.

It is a common misconception when drawing lines using logical operations such as XOR that the line will appear in the opposite colour; ie a black line will appear in white, and a green line will appear in magenta. Unfortunately this is not the case; the values used for the calculations are the pixel values - ie the index into the colormap. Thus if the program allocates the colour Yellow in position 5 then drawing in XOR will generate a pixel value of 250. This position may contain a black pixel value (i.e. all zeroes); alternatively if xcolor is running it will probably contain a red value.

More significantly, this colour cell is either unallocated or is owned by another program - either way, its value can change at any time, causing unexpected effects to be seen.

The way around this is to ensure that the appropriate colour cell is allocated and contains the expected colour. To prevent colormap flashing it may be preferable to allocate a block of colours in the centre of the colormap, since in an 8 bit environment the negation of 127 is 128.

11. How does Display PostScript handle colour?

The first time a DPS application is started, by default a colour "cube" is allocated. The DPS cube is much smaller than the default NeWS cube; it defaults to a 4x4x4 cube (64 colours) and 9 grays for a total of 73 colormap cells. This is configurable by using X resources of the form:

	DPSColorCube."visualname"."depth"."color": "size"
for example:

	DPSColorCube.PseudoColor.8.reds: 6
See Adobe's Orange Book page CLX-9 for more information.

DPS does not use a "closest match" algorithm for choosing colours as NeWS did. Instead, it uses colour halftoning to produce the best possible representation of the requested colour for a device. This is why DPS has to have a proper colour cube rather than miscellaneous colour cells.

In the simplest case, DPS uses the X Standard Colormap RGB_DEFAULT_CMAP mechanism to leave a pointer to the colour cube it creates in the default colormap. This is done "in a valiant attempt to share its colormap resources with other applications, both DPS and non-DPS". As a consequence, the colormap entries are not cleared when the client is exited.

To force the server to clear this data, enter the command

	xstdcmap -delete default
This will delete the cube, regardless of whether any clients are using it, so this mechanism must be used with care. However, unlike NeWS applications, subsequent DPS clients will re-allocate this cube.

An advantage to using the "simple" connection which uses the default colormap, is that it will automatically be able to run in CDE's allocation of the default colormap and probably OpenStep's as well (given that it's based on DPS). This will (hopefully) be a good example of where DPS's colormap sharing scheme works to it's best advantage.

DPS must have a gray ramp, even if it is only black and white. Color, on the other hand, it considers optional. If you don't have your colour cube allocated in the same colormap as your gray ramp, it will go with the gray ramp. It uses the non-standard property "DEFAULT_GRAY" for all colormap types except GrayScale, for which it uses RGB_DEFAULT_GRAY, due to a caveat in the Xlib specification. If you need to delete the gray ramp, use the command

	xprop -root -remove DEFAULT_GRAY
The same caveats apply.

Thanks to [email protected] and [email protected] for these tips.

John has written a utility called rst_dcmap which will search for and delete colormap cells that have been allocated and recorded as standard colormaps.

12. Where is clear_colormap for Solaris 2.3?

clear_colormap is no longer supplied as part of OpenWindows. [email protected] has written a small utility, cmap to perform the same function.

Carl has also provided a utility called cls, which will turn off the white screen on a second display when exiting OpenWindows.

13. Why do Imagetool and Pageview flash?

As noted above, DPS allocates a small colorcube to share with other applications. Unfortunately, some applications, notably ImageTool, do not want to "play ball" and allocate their own private colormaps for each instance of the tool. This approach is not recommended, and is why these tools cause such dreadful colormap flashing. Apart from locking the colormap, there is nothing the user can do.

14. How does NeWS handle colour?

The first time a NeWS application is started, by default a colour "cube" is allocated, and the server does a "closest match" whenever a colour is requested. Unfortunately the server has no way of knowing when NeWS has actually finished with a colour, so the cube remains allocated until the server is terminated.

By default a "small" cube is allocated, using 140 of the 256 colormap entries. If the user is concerned primarily with NeWS applications it is possible to allocate a large colour cube, which will take up 240 of the 256 colours. This is done by invoking the xnews server or openwin with the option -cubesize large. This will improve the rendering of NeWS images, but will greatly increase the likelihood of colormap flashing. For further details see the manual page for xnews.

Once allocated, the NeWS colour cube can be freed using the following script (taken from the text of bug ID 1101904):

	#!/bin/sh
	psh << '%EOF'
	/NeWS 3 0 findpackage beginpackage
	framebuffer /Colormap get freecube
	%EOF
(Note: This script will not work if openwin/xnews was started with the -favorstatic option.)

However, once freed it will NOT be re-allocated. The "closest match" algorithm doesn't seem to be too smart, and many NeWS programs will suffer as a result. In particular, CG3270 and Frame Maker are adversely affected. CG3270 may display in barely readable characters, while Frame Maker may exhibit corruption of the Frame logo, the buttons and the grid among others.

This may also be evident if there is not sufficient space in the default colormap to allocate the NeWS cube. NeWS applications will not create a custom colormap, and therefore will not in themselves exhibit colormap flashing.

You can alleviate this problem by using cmap_compact described above. (If you intend to run CG3270, you are advised to save the 6 Primary and Secondary colours, otherwise the display will be poor.)

15. Does the X server support the Standard colormaps?

The X standard defines a set of atoms which refer to "Standard" colormaps. These include: XA_RGB_BEST_MAP, XA_RGB_RED_MAP, XA_RGB_GREEN_MAP, XA_RGB_BLUE_MAP and XA_RGB_GRAY_MAP. This is documented in Section 7.8 of the Xlib Programming Manual (Volume One of the O'Reilley series).

By default, neither xnews nor Xsun allocate any of these colormaps, however the user may create his/her own and associate them with these defined atoms. There are a couple of tricks to doing this, so an example routine is given at the end of this document.

16. How does Wabi access the colormap?

When Wabi is initialised, it uses a technique which seemed to the designers to be the best way of reducing colormap flashing - it allocates the entire colormap, and fills it with a colour cube and a selection of other colours. The theory behind this was that, when an application asked for a new colour there would be a colour available which was reasonably close to that requested, if not matching exactly. The server would offer this to the application and there would be no flashing.

Unfortunately, when XAllocColor returns saying that it could not allocate the colour, rather than accept this "close match" practically every application ever written goes away and allocates a private colormap. Few of them use the techniques outlined in this document, so the net result is that colormap flashing is exacerbated rather than reduced! The solution therefore is to start Wabi after all other colormap intensive programs have been started (particularly SunPC, and DPS or NeWS applications)

Newer releases of Wabi (1.1 and later) use a much better technique. They still allocate the entire colormap as far as they can, but they then create a private colormap, copy in the default colormap, and finally free a percentage of the colours in the default colormap. This value defaults to 50% but is user configurable from 0% (ie the current situation) to 100% (freeing all colours).

17. How do I find out what visuals are available?

Programatically, if you are not concerned about the visual, you can use the DefaultVisual macro - this value is dependent on the frame buffer and any options that the user gave when starting the Xsun or xnews server. If you want a particular depth or visual which may not be the default but is supported by the frame buffer, you should use the command XMatchVisualInfo.

The command xdpyinfo will list all the visual types and depths that the current display device supports. This is dependent on the frame buffer available.

The GX series frame buffers support PseudoColor, DirectColor, StaticColor, TrueColor, StaticGray and GrayScale visuals with a depth of 8 bits. 24 bit frame buffers, such as the ZX and SX, support 24 bit TrueColor visuals. Under Solaris 2.4, the ZX and A24 frame buffers also support 24 bit DirectColor visuals.

For more information on frame buffers, see the Frame Buffer FAQ. For more information on why software should choose its visual rather than accept the default, see the Multimedia Ambassadors OpenWindows page.

18. How does CDE handle colour?

The CDE group used to maintain a FAQ page of their own. Foolishly I linked to it rather than taking a copy of my own, and it appears that the server no longer exists.

I'm still looking for a new copy of the CDE FAQ.

19. How can I reduce colormap flashing with Netscape?

Netscape has some useful features to help you deal with colormap flashing. If you start up OpenWindows in StaticColor mode:
	openwin -dev /dev/fb defclass StaticColor
you can then instruct Netscape to use the StaticColor visual (by default it will still try to use PseudoColor) with the command
	netscape -visual 0x25
Alternatively, you can ask Netscape to use fewer colours initially, with the command
	netscape -ncols number_of_colours

20. How do PC based X servers handle colours?

Thanks to Wojtek Jarosz of Attachmate Canada Inc. for this information.

PC based X servers usually use the MS Windows palette to handle colours. As far as I know this is how all the servers I have heard of work: eXceed, Xoftware, XVision, PCXware and EXTRA! X. This imposes some restrictions on what can be done with colormaps on such servers; in particular it is not possible to overwrite cells 0 and 255 which Windows reserves for black and white respectively.

Because some applications require to have the ability to write over these reserved cells, some servers actually pretend to the application that the write is successful while in reality no colour changes occur. As far as I know this is e.g. what the eXceed server does and also XVision (which has an explicit configuration option to enable this feature - I am currently in the process of getting more information on this).

Related to this is the so-called "white pixel option" which some servers posses and which defines black and white at positions 0 and 1 in the colormap. At present I am aware of only one server which provides this feature explicitly as a configuration option: Xoftware. The configuration option is called: "Change White Value". When selected, it reserves pixel position 1 for white (black is already at 0 as Windows default). It should be noted that the following help text associated with this option in Xoftware is incorrect and confusing:

When you dig a bit deeper in the product you can find the following - more correct description:

Note that whenever this option is selected, white is still defined at position 255 (which cannot be changed) and what changes is that it is also defined at position 1. This can be seen easily e.g. by running the Sun-based "xcolor" test client, which attempts to load the entire colormap with a range of colours, while (optionally) preserving black and white: it is never possible to overwrite positions 0 and 255 which stay at black and white respectively, though one can observer white appearing at position 1 if the white pixel option is set.

I am not really certain why the white pixel option is provided, other than either:

21. What is gamma correction?

This question (and many others) is addressed in the Frame Buffer FAQ, also available at this site.

Is there anything else I should look at?

Other commands which can have an effect on the colormap include reservecolors and xstdcmap - these are used to allocate entries in the default colormap which are not freed when the program exits.

There is also an additional colormap information document, written by [email protected].

A. Example of reduced colormap flashing using XView


#include <sys/types.h>
#include <xview/xview.h>
#include <xview/canvas.h>
#include <xview/cms.h>
#include <xview/xv_xrect.h>
#include <X11/Xatom.h>

#define FAILED -1

#define	IMAGEWIDTH	512
#define	IMAGEHEIGHT	 64
#define	CMAPSIZE	 64
#define	OFFSET		128

unsigned long *colours;

u_char *malloc();
void quit();
void canvas_repaint();

Frame frame;
Canvas canvas;
u_char *image;
u_char *cmap;
XImage *ximage;
Atom catom;


/*
 * GetImage supplies two pointers, one to the image we want to display
 * and the other to an array of rgb values.
 */
u_char
GetImage()
{

	int width, height;
	int i, n;
	u_char *im;

	/*
	 * Now generate an image, this entirely artificial but good enough
	 * to demonstrate the principles involved.
	 */
	image = malloc((unsigned)(IMAGEHEIGHT * IMAGEWIDTH * sizeof(u_char)));
	if (image == NULL) {
		perror("Image data 'malloc' failed, giving up!\n");
		exit(FAILED);
	}

	/*
	 * Get some space for the colour map data.
	 */
	cmap = malloc((unsigned) ((CMAPSIZE) * 3 * sizeof(u_char)));
	if (cmap == NULL) {
		perror("Colour map data 'malloc' failed, giving up!\n");
		exit(FAILED);
	}

	/*
	 * We now have an empty array 512 * 64
	 * Now fill it with some image data
	 * This will render as 64 level grey scale image
	 * with the correct colourmap installed.
	 */
	im = image;
	for (height = 1; height <= IMAGEHEIGHT; height++) {
		for (width = 0; width < IMAGEWIDTH; width++) {
			*im++ = (u_char)((CMAPSIZE + OFFSET) - height);
		}
	}

	/*
	 * Now generate colour map, this information would normally
	 * be extracted from the image data.
	 * This colour map will display the image as a 64 level grey scale,
	 * the principles are the same for a colour image.
	 */
	n = 0;
	for (i = 0; i < CMAPSIZE; i++) {
		cmap[n++] = (CMAPSIZE - i) * 4;
		cmap[n++] = (CMAPSIZE - i) * 4;
		cmap[n++] = (CMAPSIZE - i) * 4;
	}

}


main(argc, argv)
int argc;
char *argv[];
{
	Display     *display;
	XID         win;
	int  			scrn;

	Colormap ycmap, xcmap;
	XColor xcolours[CMAPSIZE + OFFSET];
	XColor xc;
	unsigned long pixels[CMAPSIZE + OFFSET];
	int plane_masks[1];
	int i, n;
	XSetWindowAttributes window_attr;
	Window pw;


	/*
	 * Get image data.
	 */
	GetImage();

	/*
	 * initalize Xview, create frame and canvas.
	 */
	xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);

	 frame = (Frame)xv_create(NULL, FRAME,
		FRAME_SHOW_HEADER, TRUE,
		FRAME_LABEL,    argv[0],
		XV_HEIGHT, IMAGEHEIGHT,
		XV_WIDTH, IMAGEWIDTH,
		NULL);

	canvas = xv_create(frame, CANVAS,
		CANVAS_HEIGHT, IMAGEHEIGHT,
		CANVAS_WIDTH, IMAGEWIDTH,
		CANVAS_REPAINT_PROC, canvas_repaint,
		CANVAS_X_PAINT_WINDOW, TRUE,
		WIN_DYNAMIC_VISUAL, TRUE,
		NULL);

	/*
	 * Get the XID's for various X objects that we need.
	 * Most of the colour/drawing work will be done with Xlib
	 * call rather than Xview.
	 */
	 pw = (Window)xv_get(frame, XV_XID);
	 display = (Display *)xv_get(frame, XV_DISPLAY);
    	win = (XID)xv_get(canvas_paint_window(canvas), XV_XID);
	 scrn = DefaultScreen(display);

	/*
	 * Create an X pixmap.
	 */
 	 ximage = XCreateImage(display, DefaultVisual(display,scrn), 8, 
 	 	ZPixmap, 0, image, IMAGEWIDTH, IMAGEHEIGHT, 8, IMAGEWIDTH);

	/*
	 * Create an X colour map
	 */
	xcmap = XCreateColormap(display, win, 
		DefaultVisual(display, scrn), AllocNone);

  	ycmap = DefaultColormap(display, DefaultScreen(display));

	for (n = 0; n < OFFSET + CMAPSIZE; n++)
		xcolours[n].pixel = (long) n;
	XQueryColors(display, ycmap, &xcolours[0], OFFSET);


	/*
	 * Get colour cells
	 */
	if (!XAllocColorCells(display, xcmap, TRUE, NULL, 0, 
						pixels, CMAPSIZE + OFFSET))
		printf("Failed to allocate colour map info\n");

	/*
	 * Now we need to install the colour map values extracted from the image.
	 * We need to translate these values into an XColor structure.
	 */
	i = 0;
	for (n = OFFSET; n < CMAPSIZE + OFFSET; n++) {
		xcolours[n].red = (u_short)(cmap[i++] << 8);
		xcolours[n].blue = (u_short)(cmap[i++] << 8);
		xcolours[n].green = (u_short)(cmap[i++] << 8);
		xcolours[n].flags = DoRed | DoGreen | DoBlue;

	} 
	XStoreColors(display, xcmap, &xcolours[0], CMAPSIZE + OFFSET);

    	catom = XInternAtom (display, "WM_COLORMAP_WINDOWS", False);
    	XChangeProperty (display, xv_get(frame, XV_XID), catom, XA_WINDOW, 32,
                   PropModeAppend, &win, 1);

    	/* associate it with the window */

    	window_attr.colormap = xcmap ;
    	XChangeWindowAttributes(display, win, CWColormap, &window_attr);

	xv_main_loop(frame);
	exit(0);
}

void
canvas_repaint(canvas, pw, display, xid, xrects)
Canvas canvas;
Xv_window pw;
Display *display;
Window xid;
Xv_xrectlist *xrects;
{
	GC gc = DefaultGC(display, DefaultScreen(display));
	XPutImage(display, xid, gc, ximage, 0, 0, 0, 0, IMAGEWIDTH, IMAGEHEIGHT);
}

B. Allocating and using the RGB_BEST_MAP standard colormap

create_rgb_colormap()
{
	int i, j, k, maps, base;
	XStandardColormap *mapinfo;
	XColor  *exact;
	Pixel pix;
	Visual *viz;
	Window win;
	Display *display;
	Widget w;

/*
**	Check if the RGB_BEST_MAP resource has already been defined
*/
	display = XOpenDisplay(NULL);
	win = RootWindow(display, 0);
	viz = DefaultVisual(display, 0);
/*
**	If XGetRGBColormaps returns non-zero then the colormap 
**	is returned in mapinfo->colormap. 
**	This can then be used as detailed in the previous example.
*/
	if (XGetRGBColormaps(display, win, &mapinfo, &maps, XA_RGB_BEST_MAP)) {
		printf("XA_RGB_BEST_MAP is already defined \n");
		XCloseDisplay(display);
		return;
	}
/*
**	Allocate the XStandardColormap structure and create the Colormap
*/
	mapinfo = (XStandardColormap *) malloc(sizeof(XStandardColormap));
	mapinfo->colormap = XCreateColormap(display, win, viz, AllocAll);
/*
**	The following values are specific to the user's needs
*/
	mapinfo->red_max = 7;
	mapinfo->green_max = 7;
	mapinfo->blue_max = 3;
	mapinfo->red_mult = 32;
	mapinfo->green_mult = 4;
	mapinfo->blue_mult = 1;
	mapinfo->base_pixel = 0;
/*
**	These are necessary.
*/
	mapinfo->visualid = XVisualIDFromVisual(viz);
	mapinfo->killid = (XID) mapinfo->colormap; 
/*
**	Now we create the RGB colour cube.
*/
	exact = (XColor *) calloc(sizeof(XColor), 256);
	base = mapinfo->base_pixel;
	for (i = 0; i < mapinfo->red_max + 1; i++) {
		for (j = 0; j < mapinfo->green_max + 1; j++) {
			for (k = 0; k < mapinfo->blue_max + 1; k++) {
				exact[base].blue = 65535 * k / mapinfo->blue_max;
				exact[base].green = 65535 * j/mapinfo->green_max;
				exact[base].red = 65535 * i / mapinfo->red_max;
				exact[base].flags = DoRed | DoGreen | DoBlue;
				exact[base].pixel = base++;
			}
		}
	}
/*
**	Transfer the RGB values to the colormap
*/
	XStoreColors(display, mapinfo->colormap, exact, 256);
/*
**	Tell the server to use this colormap as the RGB BEST MAP
*/
	XSetRGBColormaps(display, win, mapinfo, 1, XA_RGB_BEST_MAP);
/*
**	Mark this clients resources as permanent, then return.
*/
	XSetCloseDownMode(display, RetainPermanent);
	XCloseDisplay(display);
	return;
}

To use the colormap, you will need to calculate the pixel values using a "Best Match" algorithm such as the one given below. In this example, values are in the range 0 to 1. This colour is a kind of Magenta: 90% red, 70% blue, 10% green

pix = mapinfo->base_pixel +
	((unsigned long) (0.5 + 0.9 * mapinfo->red_max)) * mapinfo->red_mult +
	((unsigned long) (0.5 + 0.7 * mapinfo->blue_max)) * mapinfo->blue_mult +
	((unsigned long) (0.5 + 0.1 * mapinfo->green_max)) * mapinfo->green_mult;

C. Source to libnoflash.so

/*
**	A utility to prevent colormap flashing by performing
**	a closest match when the allocation fails.
**
**	V1.01 dated 26th March 1997.
**	Written by David Tong, Sun Microsystems Inc.
**
**	To use, first build and then
**		setenv LD_PRELOAD //libnoflash.so.1
*/	

/*
**	Makefile follows:
**
all:	libnoflash.so.1

libnoflash.so.1:	preload.c
	cc -g -K PIC preload.c -c -I. -I/usr/openwin/include
	ld -G -ztext preload.o -R/usr/lib -ldl -lc -o libnoflash.so
	mv libnoflash.so libnoflash.so.1
**
*/

#include	
#include	
#include	
#include	
#include	
#define NEED_REPLIES
#include	

#include 

void *X11 = NULL;

void init();

Status (*_XAllocColor) (Display*, Colormap, XColor*);
int (*_XFreeColors) (Display*, Colormap, unsigned long*, int, unsigned long);

#define COLOR_FACTOR       3
#define BRIGHTNESS_FACTOR  1

Status XAllocColor(register Display *dpy, Colormap cmap, XColor *xcolor)
{
	Status retstat;

	if (!X11)
		init();

	if (!(retstat = _XAllocColor(dpy, cmap, xcolor))) {
		XColor *cols;
		unsigned int ncols, i, closepix;
		long int closediff;

		ncols = 1 << DefaultDepth(dpy, DefaultScreen(dpy));

		cols = (XColor * )calloc(ncols, sizeof(XColor));
		for (i = 0; i < ncols; ++i) 
			cols[i].pixel = i;
		XQueryColors(dpy, cmap, cols, ncols);

		do {
		    for (i = 0, closediff = 0x7FFFFFFF; i < ncols; ++i) {

				long int	newclosediff = 
				  COLOR_FACTOR *(
					abs((long)xcolor->red   -(long)cols[i].red)   + 
					abs((long)xcolor->green -(long)cols[i].green) + 
					abs((long)xcolor->blue  -(long)cols[i].blue)) + 
				  BRIGHTNESS_FACTOR *abs(
					((long)xcolor->red + (long)xcolor->green + (long)xcolor->blue) -
					((long)cols[i].red + (long)cols[i].green + (long)cols[i].blue));

				if (newclosediff < closediff) { 
					closepix = i; 
					closediff = newclosediff; 
				}
		    }

		    xcolor->red   = cols[closepix].red;
		    xcolor->green = cols[closepix].green;
		    xcolor->blue  = cols[closepix].blue;
		    /*
		    ** Now paint it black so we don't loop
		    ** in the case that this colour is read-write.
		    */
		    cols[closepix].red = 0;
		    cols[closepix].green = 0;
		    cols[closepix].blue = 0;
		    retstat = _XAllocColor(dpy, cmap, xcolor);
		} while (retstat == 0);
		free(cols);
	}
	return(retstat);
}

void init()
{

	/* Tip from John Martin - don't hard-code the library path */

	_XAllocColor = dlsym(RTLD_NEXT, "XAllocColor");
	_XFreeColors = dlsym(RTLD_NEXT, "XFreeColors");	/* Not currently used */
	X11 = (void *) 1;

/*
**	if ((X11 = dlopen("/usr/openwin/lib/libX11.so.4", RTLD_LAZY)) == 0) {
**		printf("%s\n", dlerror());
**		exit(1);
**	}
**
**	_XAllocColor = dlsym(X11, "XAllocColor");
**	_XFreeColors = dlsym(X11, "XFreeColors");
*/

}

Edited and maintained by [email protected] or [email protected]

SunService TS
Created and maintained using vi.