You are on page 1of 4

Freeing Colormap Cells

Whether you are using shared or private colormap cells, you should free the colors when they are
no longer needed. When an application terminates, the X server automatically frees the colors used
by that application. However, if your application allocates colors often (for example, every time an
image is displayed in a window), you should call XFreeColors to free the colors you no longer
need:
Display *p_disp;
Colormap colormap; f* Cells freed in this colormap *f
unsigned long pixels[]; f* Identifies cells being freed *f
int numpix; f* Number of cells being freed *j
unsigned long planes; f* Identifies planes being freed *f

XFreeColors frees colors allocated by anyone of these functions: XAllocColor, XAllocNamedColor,


XAllocColorCells, or XAllocColorPlanes. When freeing one or more read-only cells allocated
by XAllocColor or XAllocNamedColor, provide the array of pixel values, their number, and a 0
for the planes argument.

For private, read-write cells, use a logical OR of rhe plane masks rhat were rerurned by an earlier call
to XAllocColorCells.

Sometimes your application needs more colors than there are free entries in the default colormap.
To display a multicolored image, you may need all available color cells supported by the display
hardware. In these cases, you have to create and set up your own colormap.

Using Your Own Colormap


The first step in setting up a colormap is to select a visual. The visual is required as an argument to
the XAllocColormap function that you use to create a colormap. As with any resource in X, when
you create a colormap, you receive a resource identifier that you can use to identify the colormap in
subsequent function calls that manipulate colors. After a colormap is created, you have to set up the
color cells using a function such as XStoreColors.

When the colormap is ready, you have to associate the colormap with the window in which you
plan to use the colors. Because most displays support only one colormap at a time, you have to
install your colormap before its effects can be seen. The X Window System's rules of eriquette dic-
tate that applications should not insrall colormaps haphazardly. Instead, a window manager should
decide when to install the colormap--usually when the window in question has the input focus.
}
Consult your window manager's documentation and the Inter-Client Communication
else
Conventiom.Manual (ICCCM) for information on using multiple colormaps. {
/* Failed to find a visual. Exit, if application cannot do
.* without this visual.
*/

S~ecting a Visual
;[he first step in creating a colormap is to pick a visual. In particular, the visual's class determines
how the color cells in the colormap are interpreted and used; its depth determines the number of After returning from XMatchVisualInfo, the vis_info structure will have the necessary informa-
entries in the colormap. This is the number of colors you can display simultaneously. If the default tion to use the matched visual. In particular, when a function needs a Visual * argument, you
visual meets your needs (it has enough depth and is of the right class),you can use the Defaul tVisual should use vis info. visual.
macro wherever you have to specifYa visual.

Visual Matching One problem with XmatchVisualInfo is that it fails ifboth the depth and the class do not ex-
If the default visual does not meet your needs, you do not have to give up. Many X displays provide actly match one of the visuals supported by the display. In many instances, all you need is a visual
more than one visual. If you know the exact depth and class of visual you want, you can use the that is better than some minimum acceptable level. For example, if you want to handle an image
XMatchVisualInfo function to locate a matching visual. This function returns a nonzero value if with 3-bit pixel values, a visual of depth greater than 3 will suffice. For these situations, you can use
a matching visual is found and fills in certain fields in an XVisualInfo structure, which is defined another approach to determine a suitable visual:
in <X11/Xutil. h> as the following: 1. Use XGetVisualInfo to retrieve a list of visuals supported by the screen you plan to use.
typedef struct To do this, set the screen member in an XVisualInfo structure and call
{ XGetVisualInfo:
Visual *visual; /* Pointer to Vi~ual struct */
VisualIO visualid; /* Visual resource 10 */ XVisualInfo *vis_list, Vis_template;
int screen; /* Screen number. */ int num_visuals,
int depth; /* Bits per pixel value */
int class; /* One of: OirectColor, */
/* TrueColor, PseudoColor, */ /* Get a list of all visuals for this screen */
/* StaticColor, GrayScale, */ vis_template.screen = theScreen;
/* or StaticGray */
unsigned long red_mask; Vis_list XGetVisual1nfo(theOisplay,
/* Identifies bits in pixel */
unsigned long green_mask; /* value used for the red, */ VisualScreenMask, &vis_template,
unsigned long blue_mask; /* green, and blue levels */ &num_visuals)j
int colormap_size; /* Max. colormap cells */
int if(num_visuals == 0)
bits_perJgb; /* Hardware uses these many */
/* bits to store each of red*/
/* green and blue levels */ fprintf(stderr, 'No visuals foundl\n');
exit(0);
For example, if you want a PseudoColor visual of depth 4, you can call XMatchVisualInfo:
Display *p_disp; Here, the VisualScreenMask constant in the argument list asks XGetVisualInfo to
XVisual1nfo Vis_info; return all visuals for the screen specified by vis_template. screen. The number of visuals
is returned in the integer whose address you provide as the last argument to
XGetVisualInfo. The return value from XGetVisualInfo is a pointer to an array of
XVisualInfo structures.
if(XMatchVisual1nfo(p_disp, screen, 4, PseudoColor, &xvis_info))
{
2. Search through this list and locate a visual that meets your needs. For example, here is the
pick_visual function used in the viewpcx program of Chapter 12, "Pixmaps, Bitmaps, Suppose you want a copy of the default colormap (assume that the default visual meets your needs).
and Images," to pick a visual with class matching class_wanted and depth greater than You can create such a colormap with the following block of code:
or equal to depth_wanted: Display *p_disp;
XVisualInfo int screen, i;
*vis_list; 1* List of visuals returned by *1 XColor 'colors;
1* prior call to: XGetVisualInfo *1 Colormap new_colormap;
int num_visuals; 1* Number of visuals in Vis_list *1
Visual screen = DefaultScreen(p_disp);
theVisual; 1* Selected visual *1 colormap_size = DisplayCells(p_disp, screen);
int Vis_depth; 1* Depth of selected visual *1

if«colors = (XColor *)calloc(colormap_size,


sizeof(XColor))) == NULL)
I' - - - - - - -- - - - - - - - - - - - - - . . __.. . _.I
I' pic k _ vis u a 1 fprintf(stderr, "No memory for setting \
up colormap\n");
exit(l) ;
Select a visual of appropriate "class" and "depth" from
the list of visuals. Return 1 if successful, 0 if no I' Initialize parts of the colors array *1
matching visuals found. for(i = 0; i < colormap_size; i++)
*1 {
colors[ii·pixel i',
static int pick_visual(int depth_wanted, int Class_wanted) colors [i] .flags DoRed

XVisualInfo 'p_visinfo;
1* Get RGB values from default colormap *1
int i, status = 0;
XQueryColors(p_disp, DefaultColormap(p_disp, screen),
colors, colormap_size);
forti = 0, p_visinfo = Vis_list; i < num_visuals;
1* Create the new colormap *1
i++, p_visinfo++)
new colormap = XCreateColormap(p_disp,
- RootWindow(p_disp, screen),
if(p_visinfo->class == class_wanted && DefaultVisual(p_disp, screen),
AllocAll) ;
p_visinfo->depth > depth_wanted)
1* Store the colors in the new colormap *1
theVisual p_visinfo->visual; XStoreColors(p_disp, new_colormap, colors, color.map_size);
viS_depth p_visinfo->depth; 1* Now we can release the memory used by the colors
status = 1; * because the X server already has this information.
break; *1

Assodating the Colormap with a Window


After you have a visual and a colormap, use them to create the window in which you will use the
colors. When you create a window with the XCreateSimpleWindow function, the newly created
Setting Up the .colormap window uses its parent's visual. To use a visual other than the parent's, ~ou have to use
XCreateWindow. You can associate the colormap with the window as you create It:
Once you have a visual, you should first set up an array ofXColor structures with information for
the colormap Eellsof your colormap. Then you can call XCreateColormap to set up the colormap. Display
Visual
ATOM_WM_COLMAP_WIN =XInternAtom(p_disp,
Window new_win, theMain;
XSetWindowAttributes xswaj "WM_COLORMAP _WINDOWS", False);
XChangeProperty(p_disp, theMain, ATOM_WM_COLMAP_WIN,
XA_WINDOW, 32, PropModeReplace,
(unsigned char *)&new_win, 1);

(For further discussion of properties, see Chaptrr 16, "Advanced Topics in X.")
xswa.colormap = new_colormapj
Once this properry has been defined, mwmalso enables you to switch colormaps interactively. To do
xswa.background_pixel = WhitePixel(p_disp,
DefaultScreen(p_disp»; this, bind the function f. next_cmap to one of the keys or mouse buttons. This is done in the . mwmrc
file in your home directory. (See Chapter 2, "Clients, Servers, and Window Managers," for more
xswa.border_pixel = BlackPixel(p_disp,
information on the OSF/Motif window manager.)
DefaultScreen(p_disp»j
Suppose you want the colormaps to switch when you press the Alt key together with the third mouse
/* Window at (xpos, ypos) with dimensions width x height
* w1th border width bdwidth. Visual's depth is vis depth. button, with the mouse pointer in the subwindow that has its own colormap. For this to work,
* The parent window's ID "theMain" - make sure the following line appears in the button-binding section of the. mwmrcfile (in the
*/
DefaultButtonBindings, ExplicitButtonBindings, and PointerButtonBindings sections):
new_win XCreateWindow(p_disp, theMain, xpos, ypos,
Width, height, bdwidth, Vis_depth,
InputOutput, visual,
CWColormap : CWBackPixel : CWBorderPixel,
&xswa) ;

Informing the Window Manager


If you associa~ea new colormap with a top-level window (a window whose parent is the root win- Using a new colormap for your application may seem enticing, but it does have one
dow), most wmdow mana~ers wi~linstall t,hecolormap when your window gains the input focus. If drawback: when the window manager. switches colormaps to satisfYyour application's need,
you have colorn~aps assocl~ted with subwmdows, the situation becomes complicated. In fact, you the other windows on the screen will be in the wrong color. By the same token, whep your
have to check With your wmdo~ man~ger:s documentation to see how you can ensure a switching application does not have the focus, the colors in your application's windows will not look
of the colormap when you are dlsplaymg m that subwindow. right. Another problem is the flashing that occurs when colormaps are switched rapidly.
This is more of a problem when the focus is determined by the location of the pointer, As
The ~otif,wind.o,,: ma~ager, mwm,pays attention to a subwindow's colormap, provided that the user moves the mouse, the windows gain and lose focus rapidly with attendant changes
subwmdow s 10 ISlIsted m a property named WMCOLORMAP WINDOWS I'nth I'" . in the colormap. This causes considerable flashing. In cases where the user has to click on a
d '. - - e app lcatlOn stop wm-
ow. P~opertles.are descnbed later, but here is some sample code that sets up the property in a top- window to change fo~us (the default behavior in OSF/Motif), the situation is better
level wmdow With the 10 theMain: .
because mere movement of the mouse does not cause switching of colormaps.

Display *P_disp;
Colormap new_colormapj
Window
int
new_win, theMain;
screen;
Summary
Atom ATOM_WM~COLMAP_WIN; This chapter describes how ou can use color in your X applications. Although X displays vary,in
how co or IS andled inlli!lally, ill h_avecertam commo
-- -......... .
screen DefaultScreen(p_uisp); •. They use fmme b!!ffers with one or more bit planes.
/* Set the WM_COLORMAP_WINDOWS property so that the OSF/Motif •. Colors ar~ composed from different intensities of the primary colors: red, green, and blue
w1ndow manager knows about windows with their (RGB).
:/own colormap. In this case, we have only 1 such window.
•. The hardware uses a colormap or a gra,yscalemap to convert pixel values in the frame
if(new_colormap != DefaultColormap(p_disp, screen» buffer into colors or intensities on the screen.
{