Setting colors in the X Window System

Introduction

Most X applications have a way to specify the colors of displayed components. Even text presentation programs, like less and vim, can display text in many different colors, chosen according to context. And of course programs like browsers and graphics are full of color specifications; PostScript files can color text as well as graphics.

Usually, default colors are specified in a configuration file; sometimes colors can even be changed while a program is running. But every application seems to set its colors in a different way. This causes problems when you want to make two programs work together, as they may use different names for some colors.

This guide begins with the color naming systems used in X. Then comes an explanation of how to change a bad color. Finally, there are some examples.

For a simple introduction to the complicated topic of color, see my introductory page on this subject. There's also a more technical discussion of color perception that you might find useful. The page you are reading is more computer-oriented.

How colors are managed

Get ready

Remember that every text app running under X may behave a little differently than it does in a framebuffer console. That's because X uses startup files in /etc/X11/app-defaults  that set defaults for most applications. (The specific files mentioned here are the Debian defaults; if you are using some other distribution of Linux, you may find various configuration files in other directories.) If you find mysterious things happening, remember to check those startup defaults. Some have many helpful comments; for example, /etc/X11/app-defaults/UXTerm-color  has useful information about color selections.

You will find some color-oriented utilities helpful. I have found colortest-python handy for showing the colors available in whatever terminal emulator I'm using. The program xcolors that comes in its own package shows many (but not all) of the colors available in X, with their indexed names; see its man page. The xcolorsel color selector can show all the colors, a few at a time, and has a color-picker to identify the color of any pixel on your screen.

There's also a Debian package called gpick that provides a nice color-picker, which is useful for identifying the color of any pixel you see on the screen. Unfortunately, its documentation is so skimpy that some experimentation is needed to use it. (In particular, it is reluctant to give up control of the mouse pointer, because it normally runs as a daemon in the background; so use the <ESC> key, or the left mouse button, to get out of it.) Some help is available at www.gpick.org. If you just want to find the rgb code for one pixel, run gpick -s -o and move the cursor (which moves the sample-picker) to the pixel you want, then press the left mouse button.

How many colors?

Although the X Window System can display millions of different colors, applications that run in a terminal-emulation window need only a few colors. So terminal emulators like xterm , rxvt , and urxvt index a few colors for distribution to programs like vim and mutt.

The color-terminal programs originally could show only 8 colors; later, this limited gamut was extended to 16, to provide both dark and light colors of each hue. Today, most “cterms” index 88 colors by default, and sometimes as many as 256 colors. Still more colors are defined in the file /usr/share/X11/rgb.txt , where they are associated with English names like green or magenta , or more fanciful names like BlanchedAlmond , MediumSlateBlue , LightGoldenrodYellow , and LemonChiffon4 . These colors can be referred to either by name or by index number.

To see the colors and their index numbers offered by a cterm, you can install the colortest-python package, and run the command

 colortest-python -n
in the cterm's window. That produces a display like this: default colors in an 88-color terminal


To maintain backward compatibility with the old 8- and 16-color terminals, the 88-color ones assign the first 16 index entries to a traditional set. Its first 8 (colors 0 to 7) are nominally “dark” colors — usually, but not always, in the order
Black   Red    Green   Yellow   Blue   Magenta   Cyan    White
— and the second 8 (8 to 15) are “light” versions of the same colors. (The “light black”, number 8, is actually a dark gray, and the “dark white”, number 7, is a light gray; so the last dark color [in the top row] is usually lighter than the first light color [in the second row].) Because the short-wavelength cones do not contribute to the sensation of lightness, even a pure blue of maximum brightness is pretty dark; that's color 12 in the image here. Lighter blues require the addition of green (changing their hue, as in colors 23 and 27), or both red and green (reducing saturation: color 39). Likewise, a true dark yellow appears olive (color 3); so the dark yellow slot is often set to brown.

You can find how many colors are indexed by your terminal program by opening a text window, and starting vim . (You don't even need to open a file.) Then, just type the vim command

 :set t_Co 
and vim will reply
 t_Co=88 
(assuming your terminal indexes the usual 88 colors). “t_Co” is the terminfo code for the number of colors your terminal has; vim gets this information from your TERM setting.

Colors are made available to text applications by the X11 terminal in which they run. So there is a hierarchy of configuration files: a moderate-sized palette of colors is assigned to an application by the app's file in the /etc/X11/app-defaults/ directory, or in the .Xresources file in a user's home directory. Then a subset of those colors is chosen in the configuration files of a text application like  vim   or  mutt . See the RESOURCES section about 2/3 of the way through the  man 7 X  page for details.

Unfortunately, a text application like an editor has access only to the list of color names indexed by the cterm in which it runs. To see what colors are available to an application, you can consult the cterm's entries for it in the /etc/X11/app-defaults/ directory. But you are not limited to these defaults, because you can override them with entries in your .Xresources file. It's only the total number of different colors that's fixed, for each X11 application.

You can change any of the indexed colors by editing the part of your ~/.Xresources that refers to your cterm. If you only want to change one color, just put a line for that indexed color in your .Xresources file. After editing .Xresources, you can make X aware of the changes by doing  xrdb −merge .Xresources  in any terminal window that is running a shell. You can replace any default color with a completely arbitrary color, by specifying a replacement in .Xresources. The replacement does not have to be one of the standard defaults; it can be any  valid color specification.

Besides the index-number names like “color32” and the English names like “Turquoise”, there is a third color-designation system used in X: a numerical specification in some standard color space, such as rgb. The cterm's entries in .Xresources can associate a numerical color specification with an index name, which can then be used by applications like editors.

Color designations in X

Colors in X applications are defined by three digital signals sent to the red, green, and blue inputs to each pixel on the screen. So a typical color specification has either the form “#rrggbb” (now deprecated), or a color-space name followed by numerical values, such as “rgb:12/34/ff”, where the numbers are given in hexadecimal digits (0 through f ). For details, see the COLOR NAMES section of man 7 X.

Unfortunately, the numerical values in the common rgb system do not obey the rules of additive color mixing.

The gamma problem

How we got into this mess

When computers began to use color screens, they inherited CRT display hardware originally used in color television sets. Those displays had a very nonlinear relation between the voltage sent to the device and the resulting brightness on the screen: the brightness was proportional to about the 2.2 power of the electrical signal. This contrast exponent was denoted “gamma” (a term borrowed from photography). Transforming between the desired brightness and the digital value of the corresponding signal to the display is called “gamma correction”.

The television industry uses a standard transfer curve between actual image intensities and electrical signal levels. The International Telecommunication Union adopted this function in its Recommendation 709 in 1990. Soon after that, the computer industry adopted a similar, but slightly different, transfer function for color screens on computers; this is known as sRGB. By confusing two different international organizations involved in color science and telecommunications, the computer people started calling this standard “CIE Rec. 709”. So, for example, the image processing utility pnmgamma uses an option called -cieramp in converting between RGB values and screen brightnesses — although the CIE has nothing to do with it.

More about gamma correction

In fact, the actual sRGB transfer curve is not a simple power law. The numerical R, G, and B values used in image formats like JPEG, and in X applications in general, are proportional to the signals  sent to the color channels of a standard RGB CRT monitor, not  to the relative luminances on the screen. So one must always be aware of the need for gamma correction in trying to produce a desired color and brightness on a computer monitor.

And because of the nonlinear response of the eye, colors spaced uniformly in linear brightness do not appear evenly spaced. For example, the default RGB values in the “4x4x4 color cube” shown above use only the hexadecimal values 00, 8b, cd, and ff; the corresponding decimal values are 0, 139, 205, and 255 — hardly evenly spaced. However, when the gamma corrections are removed, the relative intensities produced are close to 0, 1/3, 2/3, and unity. But the resulting colors certainly do not appear uniformly spaced.

As Charles Poynton explained in his well-known guide to the gamma correction, the nonlinearity of the visual perception of lightness is even greater than the nonlinearity of computer displays. This is why the gray that looks about midway between black and white to the eye corresponds to about the 74% gray in the set of grays offered by the xcolorsel utility that comes with X. The medium gray (simply, “gray”, or “gray190” on the 0 to 255 scale of grays at the end of that list) does indeed appear to be about halfway between white and black.

This nonlinearity makes colors that are spaced evenly in rgb numerical value produce barely distinguishable screen colors when some rgb values are less than about half of the largest component, or 128 on the 0 to 255 scale.

So the customary defaults used by the common X terminal simulators (xterm, rxvt, and urxvt — alias rxvt-unicode — are not very satisfactory. In particular, the less-saturated colors in the 88 default colors recognized by these cterms are not at all uniformly spaced perceptually, and change in hue and saturation as their lightness changes. The problem is evident in the choices offered by the xcolors program: look at the sequence from CadetBlue1 to CadetBlue4 , or PaleGreen1 to PaleGreen4 , or OliveDrab1 to OliveDrab4 , or the similarly numbered sets of khaki or tan or orange or wheat or LightAnything or even red. In all these sets, the variant ending in 1 is always a little more on the short-wavelength side in hue, and considerably more saturated, than the one ending in 4, which is yellower (for the blues and greens) or more purple (for the oranges and reds), as well as much less saturated. Indeed, all the colors ending in 4 are barely distinguishable; they are all slightly tinted shades of dark gray. In fact, all those rgb.txt colors ending in a digit from 1 to 4 have their dominant component set to 255, 238, 205, and 139 — all of which (except for 238) were in the set of relative intensities enumerated above for the “4x4x4 color cube”.

So the lighter colors in rgb.txt look garish, or even fluorescent, when used as foreground colors in a text window; and the darker colors are hardly different from black.

Solving the gamma problem

Fortunately, it turns out that X can also convert from one color space to another. In particular, it supports an RGB space that uses intensities instead of the nonlinear numerical values discussed above. (According to Chapter 6 of the Xlib manual, the nonlinear numbers are called RGB Device values, as opposed to RGB Intensity values.) So it's possible to specify colors in this RGBi space, where the values obey ordinary additive color mixing. The actual values themselves are stored as 16-bit integers, so good precision and a large dynamic range are possible.

The linear RGB Intensity string specification uses the prefix “rgbi:” followed by three floating-point values between 0.0 and 1.0, where 0 means zero intensity and 1 means maximum intensity. Notice that this is still a device-dependent specification; the usual device is either an sRGB CRT, or some other type of display that is supposedly adjusted to behave like the sRGB standard. Some standard device-independent color spaces can also be specified, such as the CIEXYZ and CIELab spaces.

However, because millions of different colors can be specified, the structures that store the X colormaps can become very large; so to conserve memory, the sharing of maps between different X programs is encouraged. So it is not surprising that the colors used by an editor are taken from the colormap of its parent cterm.

And the default colormap of the cterm is derived from that of the root X window, handed down by the window manager. This part of colormap management is described in the Inter-Client Communication Conventions Manual, which is available on the x.org website, and should be found on a Debian system at /usr/share/doc/xorg-docs/icccm/iccm.pdf.gz; see its Chapter 4, “Client-to-Window-Manager Communication”. Chapter 7 of that Manual, “Device Color Characterization”, deals with the color-space transformations briefly mentioned above.

Redundant colors

Because of the problems discussed in the previous section, the 64 colors of the “4x4x4 color cube” occur in subsets of four colors that are very similar. If we regard each group of 4 similar colors as only one color, for practical purposes, this “color cube” only contributes 16 really different colors. So the 88 index values offer the user only 40 choices.

But the number of different colors is even less than that, because 9 of the indices point to exactly the same color elsewhere in the set of 88. Here's a table of the identical pairs:

Indices 16 = 0 64 = 9 28 = 10 76 = 11 19 = 12 67 = 13 31 = 14 79 = 15 83 = 37
Color name   Black Red Green Yellow Blue Magenta Cyan White (dark gray)

So the default colors assigned to the usual 88 slots end up providing only about 31 distinct colors.

Eight of the exactly duplicated colors have one member in the basic set of 16. It seems unlikely that anyone is really using color 16 for Black; so it's probably safe to assign some completely new and different color to color16.

Copyright © 2021, 2025 Andrew T. Young


Back to the . . .
main LaTeX page

or the website overview page

or the alphabetic index page

or the GF home page