.de Su \" if $1 = +, this gives a superscript; $1 = - gives a subscript. . \" If 2 args, $1=super/subscripted text with post-space . \" If 3 args, $2=regular text; $3=super/subscripted text w/pre-space .if "\\$1"+" \{\ . if \\n(.$=3 \\$2\v'-4p'\s-3\\$3\v'4p'\s0 . if \\n(.$=2 \v'-4p'\s-3\\$2\v'4p'\s0\} .if "\\$1"-" \{\ . if \\n(.$=3 \\$2\v'3p'\s-3\h'2p'\\$3\v'-3p'\s0 . if \\n(.$=2 \v'3p'\s-3\\$2\v'-3p'\s0\h'2p'\} .. .\ "MIT header page and copyright notice .\" MIT page header and footers .ps 10 .nr PS 10 .nr LL 5.75i .nr PO .75i .EH '''' .OH '''' .EF '''' .OF '''' \.".EQ \."delim !! \.".EN .ad b .sp 8 .ce 4 \s+1\fBColor\fP\s-1 .sp \s+1\fBA Chapter from O'Reilly and Associates\fP\s-1 .br \s+1\fBXlib Programming Manual\fP\s-1 .sp 6 .ce 2 \s-1Adrian Nye .sp 6p \s-1O'Reilly and Associates, Inc.\s+1 .sp 2 .sp 8 .sp .5 The X Window System is a trademark of the X Consortium. .sp .5 Copyright \(co 1990 O'Reilly and Associates, Inc. .sp .5 Permission to use, copy, modify and distribute this documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of O'Reilly and Associates, Inc. not be used in in advertising or publicity pertaining to distribution of the software without specific, written prior permission. O'Reilly and Associates, Inc makes no representations about the suitability of the software described herein for any purpose. It is provided ``as is'' without express or implied warranty. .bp .sp 1 .ce \s+1\fBAcknowledgments\fP\s-1 .sp 2 We'd like to thank Robert Scheifler for reviewing this document. His comments on an earlier draft are represented here, but he has not seen this draft, and it is not certain that his view is fully and correctly represented. .sp .5 Al Tabayoyon, Paul Shearer, and others at Tektronix also provided valuable comments on earlier drafts. .pn +170 .bp .nr HM .75i .nr FM 3i .ad b .af PN 1 .EH '''' .OH '''' .EF '%''\f(HIXlib Programming Manual\fR' .OF '\f(HIColor\fR''%' .sp 3 .ti 5.65i \s24\f(HB7\fR\s10 .sp .ti 5i \s20\f(HBColor\fR\s10 .sp 4 .IP "" 6n .Ti "Xlib Programming Manual" .ds u: \o'u\(..' .Se "7" "Color" .St "Color" A typical X application allows the user to specify colors for the background and border of each of its windows, colors for the cursor, and foreground and background colors to be set in GCs for drawing text and graphics. More complex applications (such as Computer Aided Design (CAD) applications) might use color to distinguish physical or logical layers. Still more complex applications, such as in imaging, might use fine gradations of color to represent real-world data. Yet in discussing the background and border window attributes and how to set the foreground and background members of the GC, we have spoken only of pixel values. .sp .5 .\" I don't like this PP now How are these pixel values translated to colors? And how must an X client manage color if it is to run successfully on the wide variety of screen hardware available in the X environment? .sp .5 Because X must support a wide variety of systems with differing screen hardware, the Xlib color-handling mechanisms are fairly complex. Even programmers who have previously written color graphics applications will find there are some new concepts to learn. .sp .5 This chapter starts out by describing the different types of screens that an X application may run on and the mechanisms Xlib provides for determining the screen type. It then describes the simplest color-allocation mechanisms, which could be used by applications whose principal use of color is for decoration. It proceeds to discuss more complex color applications and concludes with a section on writing applications that will be portable across different types of color and monochrome screens. .IP \s+4\f(HB7.1\fR\s-4 6n \s+4\f(HBBasic Color Terms and Concepts\fR\s-4 .sp Most color screens on the market today are based on the RGB color model. Each pixel on the screen is actually made up of three phosphors: one red, one green, and one blue. Each of these three phosphors is sensitive to a separate electron beam. When all three phosphors are fully illuminated, the pixel appears white to the human eye. When all three are dark, the pixel appears black. When the illumination of each primary color varies, the three phosphors generate an additive color that might seem surprising. For example, equal portions of red and green, with no admixture of blue, make yellow. Most people are more familiar with subtractive color mixing, used in paints, where red, yellow, and blue are the three primary colors from which all other colors (except white and shades of gray) can be made. .sp .5 You, no doubt, know that a color screen uses multiple bits per pixel (also referred to as multiple planes) to specify colors. A \fIcolormap\fP is used to translate each pixel's value into the visible colors you see on the screen. .sp .5 A colormap is no more than a lookup table stored in the server. Any given pixel value is used as an index into this table\(emfor example, a pixel value of 16 will select the sixteenth element, or \fIcolorcell\fP. .sp .5 On the most common type of color system, each colorcell contains separate 16-bit intensity values for each of the three primary colors. .sp .5 As shown in Figure 1, a pixel value uniquely identifies a particular colorcell. Each pixel value in the visible portions of a window is continuously read out of screen memory and looked up in the colormap. The RGB values in the specified colorcell control the intensity of the three primary colors and thus determine the color that is displayed at that point on the screen. .sp Note: Figure 1 "Pixel value to RGB mapping with the colormap on a color screen" here. .sp The range of colors possible on the screen is a function of the number of bits available in the colormap for RGB specification. If eight bits is available for each primary, then the range of possible colors is .Su + 256 3 (about 16 million colors). .sp .5 However, the number of different colors that can be displayed on the screen at any one time is a function of the number of planes. A 4-plane system could index .Su + 2 4 .hw distinct colorcells (16\ distinct colors); an 8-plane system could index .Su + 2 8 colorcells (256 distinct colors); and a 24-plane system could index .Su + 2 24 colorcells (over 16 million distinct colors). .sp .5 A client attempting to use color does not \fIspecify\fP a pixel value .\" (read-only or read/write) and the color to be put in that cell in order to draw in a given color. Instead, it requests access to a colorcell in a colormap (managed by the server) and is \fIreturned\fP a pixel value. This is called \fIallocating\fR a color. When a client allocates a color, it asks the server, "Which colorcell can I use?" and the server responds by saying, "You can use the colorcell specified by this pixel value." There are three functions that allocate colors, which are described in detail and demonstrated in later sections in this chapter. .sp .5 .IP \s+2\f(HB7.1.1\fR\s-2 6n \s+2\f(HBThe Color Name Database\fR\s-2 .sp .5 In order to simplify color specification and to promote sharing of colors, X provides a color database that translates string color names into RGB values. As described above, sharing of colorcells can happen only if two clients allocate a read-only cell with the exact same RGB values. If both clients allocate a color specified by one of the 300-odd string names, there is a much better chance of them selecting the exact same RGB values and thereby sharing a cell than if they use one of the .Su + 2 48 possible combinations of RGB values. .sp .5 Because of differences in screen hardware, the same RGB values may generate quite different colors on different hardware. Therefore, server implementors will change the RGB values corresponding to each color name to make sure that the appropriate color appears on their screen. This is called \fIgamma correction\fR. By using names from this database, you are more sure of getting a color close to the one you request. If the server implementor has not provided a gamma-corrected color database, there is no way a program can tell exactly what color is being displayed even when it knows the RGB values. .sp .5 It is also important to note that the color names are not specified by the X11 protocol or Xlib. Therefore, server implementors may change them, but more often, they will simply add to the list. (Note that some servers allow users to customize this file. For more information, see VOL3.) .sp .5 Table 1 shows the color names and corresponding RGB values in the default color database for R3. The R4 database is much more extensive. The text version of this database in the standard distribution on a UNIX-based system is in the file \fI/usr/lib/X11/rgb.txt\fP. The location of this file may vary. .sp .5 The color names in the color database are strings in which each character uses the ISO Latin-1 encoding. The ISO (International Standards Organization) encoding is used by virtually all workstations manufacturers. What this means is that the first 127 character codes correspond to 7-bit ASCII and are the normal English characters that appear on U.S. keyboards. But ISO characters are 8-bit, and the characters from 128 to 255 are used for characters with accents and other variations, necessary for other Western languages. .sp .5 Server vendors should be able to supply a color database file for each foreign language. The RGB values would be the same, but the names would be different. In the English file, the entry for green is encoded with the ISO character codes 103\ (g), 114\ (r), 101\ (e), 101\ (e), 110\ (n). In German, the same entry would be for \fIgr\*(u:n\fR, encoded with the ISO codes 103\ (g), 114\ (r), 252\ (\*(u:), 110\ (n). In a workstation configured for German, there will be an easy way to type \fI\*(u:\fR. .sp .5 Note that keysyms also use the ISO Latin standard. .sp "The R3 Color Database*" .sp .TS H linesize(2); l | l | l | l l | n | n | n. English Words Red Green Blue .sp 2p _ .sp 2p .TH aquamarine 112 219 147 black 0 0 0 blue 0 0 255 blue violet 159 95 159 brown 165 42 42 cadet blue 95 159 159 coral 255 127 0 cornflower blue 66 66 111 cyan 0 255 255 dark green 47 79 47 dark olive green 79 79 47 dark orchid 153 50 204 dark slate blue 107 35 142 dark slate gray 47 79 79 dark slate grey 47 79 79 dark turquoise 112 147 219 dim gray 84 84 84 dim grey 84 84 84 firebrick 142 35 35 forest green 35 142 35 gold 204 127 50 goldenrod 219 219 112 gray 192 192 192 green 0 255 0 green yellow 147 219 112 grey 192 192 192 indian red 79 47 47 khaki 159 159 95 light blue 191 216 216 light gray 168 168 168 light grey 168 168 168 light steel blue 143 143 188 lime green 50 204 50 magenta 255 0 255 maroon 142 35 107 medium aquamarine 50 204 153 .sp 5p _ .TE .in 2.85i .rt 1.295i .TS H linesize(2); l | l | l | l l | n | n | n. English Words Red Green Blue .sp 2p _ .sp 2p .TH medium blue 50 50 204 medium forest green 107 142 35 medium goldenrod 234 234 173 medium orchid 147 112 219 medium sea green 66 111 66 medium slate blue 127 0 255 medium spring green 127 255 0 medium turquoise 112 219 219 medium violet red 219 112 147 midnight blue 47 47 79 navy 35 35 142 navy blue 35 35 142 orange 204 50 50 orange red 255 0 127 orchid 219 112 219 pale green 143 188 143 pink 188 143 143 plum 234 173 234 purple 176 0 255 red 255 0 0 salmon 111 66 66 sea green 35 142 107 sienna 142 107 35 sky blue 50 153 204 slate blue 0 127 255 spring green 0 255 127 steel blue 35 107 142 tan 219 147 112 thistle 216 191 216 turquoise 173 234 234 violet 79 47 79 violet red 204 50 153 wheat 216 216 191 white 252 252 252 yellow 255 255 0 yellow green 153 204 50 .sp 5p _ .TE .in -2.75i .sp 10p _______________ .br .vs 10 \s-2*Also defined are the color names "gray0" through "gray100", spelled with an "e" or an "a". "gray0" is black and "gray100" is white. .in 0 .vs .sp .5 .IP \s+2\f(HB7.1.2\fR\s-2 6n \s+2\f(HBHexadecimal Color Specification\fR\s-2 .sp .5 It is also possible to specify colors using a hexadecimal string. .sp .5 The hexadecimal form of color specification is necessary, since you may want the user to be able to specify an exact color, not just the rough approximation allowed by an string name. The hexadecimal specification must be in one of the following formats: .sp .5 \s-1\f(CW .nf #RGB (\fI4 bits each of red, green, and blue\fP) #RRGGBB (\fI8 bits each of red, green, and blue\fP) #RRRGGGBBB (\fI12 bits each of red, green, and blue\fP) #RRRRGGGGBBBB (\fI16 bits each of red, green, and blue\fP) \fR\s0 .fi .sp .5 Each of the letters represents a hexadecimal digit. In the shorter formats, the specified values are interpreted as the most significant bits of a 16-bit value. For example, \f(CW#3a7\fP and \f(CW#3000a0007000\fP are equivalent. .sp .5 Use of hexadecimal color specifications does not preclude colorcell sharing, since the user could specify the same hexadecimal value for the color for two or more clients. However, it probably tends to make sharing less likely, since a window manager might allocate all the colors in the color database as read-only cells, and then any client that uses hexadecimal specifications will probably be allocating a separate cell instead of sharing. .IP \s+4\f(HB7.2\fR\s-4 6n \s+4\f(HBDifferences in Display Hardware\fR\s-4 .sp The description of color mapping given in the previous section was actually somewhat over-simplified. There are significant differences in how the colormap is used on mid-range color screens, monochrome and gray-scale screens, and high performance color screens. Color handling in X was designed to work with any of these hardware types. .sp .5 .IP \s+2\f(HB7.2.1\fR\s-2 6n \s+2\f(HBMid-range Color Displays\fR\s-2 .sp .5 The most common type of color screen has between four and eight planes and uses the colormap indexing technique described above. This type of screen is so widespread because it provides a flexible color system while being moderately priced. The mapping of pixel values to colorcells, with arbitrary RGB values stored in each colorcell, allows a very large range of possible colors, even though a more limited number can be shown .ne 2 on the screen at any one time. .sp .5 Mid-range color screens usually have only one hardware colormap. In other words, the pixel values in all the windows on the screen are mapped to colors using the same colormap. On most of these systems, however, the color in any colorcell in the hardware colormap can be individually changed, and therefore, the entire colormap can be replaced with a new set of values. X provides the concept of the \fIvirtual colormap\fR, so that more than one set of colorcells can be maintained, even though only one of them can be in use at a time. Virtual colormaps are swapped in and out of the hardware colormap by the window manager. This makes it possible for an application that has special color needs to create its own virtual colormap, which the window manager will load into the hardware colormap when that application is in use. However, since only one hardware colormap is available and all applications share it, when any one application creates a new virtual colormap and the window manager installs it, all other applications will screen in false colors, since the pixel values they use now point to cells in the other client's colormap. This is acceptable, since the window manager always installs the correct colormap for the application in use, but it is obviously not ideal. On high performance systems, described below, this problem is solved by having multiple hardware colormaps. .sp .5 .IP \s+2\f(HB7.2.2\fR\s-2 6n \s+2\f(HBMonochrome and Gray Scale\fR\s-2 .sp .5 Monochrome (black and white) screens have only a single plane of screen memory. Each pixel is made up of a single phosphor, which can be either on or off. .sp .5 Gray-scale screens are sometimes used for publishing applications, since pixels made up of a single phosphor are smaller than those made up of three phosphors and the resolution is, therefore, better. As shown in Figure 2, a gray-scale screen works by looking up the intensity of the pixel in the colormap, which, for this screen type, contains only a single value. This controls the intensity of a single electron beam. Gray scale can be simulated on a color screen by making the red, green, and blue values equal in a given colorcell to determine the brightness of gray pixels on the screen. .sp Note: Figure 2 "Pixel value to RGB mapping \(em gray scale and monochrome screens" here. .sp A gray-scale screen might have a read-only colormap, so that the gray levels in each cell could not be changed. A monochrome screen is an example of this type; it is a single-plane screen with a two-element read-only colormap. .sp .5 .IP \s+2\f(HB7.2.3\fR\s-2 6n \s+2\f(HBHigh Performance Color Displays\fR\s-2 .sp .5 As memory has become cheaper and applications more advanced, workstations with 24\ planes and more have become more common. With 24 bits per pixel, it is possible to screen every discernable color at the same time. This makes it possible to do smooth shading and other applications that use a large number of closely spaced colors. .sp .5 The problem with having so many planes is that a colormap of the style used in mid-range color screens would be impossibly large: it would contain over 16 million entries. Instead, the available bits per pixel are broken down into three separate colormap indices, one for each primary color, as shown in Figure 3. This approach still allows the full range of colors to be generated but makes the job of loading the colormap much more manageable. This scheme requires three primary colormaps of only 256 entries each to specify all 16 million colors on a 24-plane system. .sp Note: Figure 3 "Pixel value to RGB mapping \(em high performance color screens" here. .sp In high performance screens, having a read-only colormap makes just as much sense as having it read/write, because nearly every color imaginable can be simultaneously available. With a read-only colormap, there is a fixed relationship between the pixel values used to select a color and the actual RGB values generated. This makes possible applications that want to calculate pixel values directly instead of having to calculate colors and then determine which pixel value represents that color, as is necessary when the colormap is read/write. .sp .5 In reality, most screens in this class let you use the color resources in either fashion, using virtual colormaps. There can be one read-only virtual colormap and one read/write virtual colormap. However, unlike on mid-range color screen hardware, most high performance color systems have multiple hardware colormaps, so that both virtual colormaps can be installed and used at the same time. In fact, on many of these systems, each window can have its own virtual colormap installed in the hardware at the same time. .sp .5 .IP \s+2\f(HB7.2.4\fR\s-2 6n \s+2\f(HBHow X Describes Color Support with Visuals\fR\s-2 .sp .5 A \fIvisual\fR describes the characteristics of a virtual colormap that has been or can be created for use on a particular screen. As used by Xlib, a visual is actually a pointer to a structure (of type \f(CWVisual\fP) containing information about one way of using a particular screen. A visual must be specified when creating a colormap or a window, and the same visual must be used in creating a window as is used to create the colormap to be used in that window. .sp .5 Most windows inherit their parent's visual, and windows will often share the root window's visual, which is known as the default visual. The default visual describes, naturally, the default colormap. If you create all your windows with \f(CWXCreateSimpleWindow\fP, you will be using the default visual and colormap. .\"If you need to get a pointer to the default visual, you can do so .\"with the \f(CWDefaultVisual\fP macro. .sp .5 The \f(CWVisual\fP structure is intended to be opaque; programs are not supposed to access its contents. This is so that Xlib implementors can change the structure without breaking existing clients. The procedure used to avoid accessing its members is not all that cumbersome but is just beginning to come into use by application writers. Up to this point, most programmers have broken this rule. We will show you only the correct method here, since it adds only a few lines to the application. .sp .5 Even more existing applications have avoided visuals altogether and used only the \f(CWDefaultDepth\fP or \f(CWDisplayPlanes\fP macros to attempt to determine whether the screen is monochrome or color. However, this does not work in general, because it does not distinguish between gray-scale screens and color screens (both have more than one plane). The only way to make this distinction is to get information about visuals. .sp .5 Remember that a visual is only one way to use color on a particular screen. There may be a list of supported visuals on a screen, with .hw write-ability each visual describing a different depth and writeability of the colormap. On a color system, there may be both monochrome and color visuals available. .sp .5 The correct method to get information about the visuals supported on a particular screen is to use \f(CWXMatchVisualInfo\fP or \f(CWXGetVisualInfo\fP. These functions return \f(CWXVisualInfo\fP structures that contain information about the available visuals and are public so their fields can be safely accessed. .Nd 8 .sp .5 The \f(CWclass\fP member of \f(CWXVisualInfo\fP contains a constant specifying one of six different visual classes,* .FS *Do not confuse \fIvisual\fR class with \fIwindow\fR class. While both are represented in certain structures as the \f(CWclass\fR member and both are set when a window is created and cannot be changed, they are quite different. The window class is \f(CWInputOutput\fP or \f(CWInputOnly\fP. The visual class is only part of the overall visual, which is the way color is represented for a window. .FE corresponding to the basic ways of using a screen: \f(CWDirectColor\fP, \f(CWGrayScale\fP, \f(CWPseudoColor\fP, \f(CWStaticColor\fP, \f(CWStaticGray\fP, or \f(CWTrueColor\fP. .sp .5 As summarized in Table 2, the visual classes distinguish between color or monochrome, whether the colormap is read/write or read-only, and whether a pixel value provides a single index to the colormap or is decomposed into separate indices for red, green, and blue values. .sp Table 2: "Comparison of Visual Classes" .sp .TS linesize(2), tab(@); l | l | l l | lp9fCW | lp9fCW. Colormap Type@Read/Write@Read-only .sp 2p _ .sp 2p Monochrome/Gray@GrayScale@StaticGray Single Index for RG&B@PseudoColor@StaticColor Decomposed Index for RG&B@DirectColor@TrueColor .sp 5p _ .TE There may be more than one way of using color on a particular screen, and therefore, there may be more than one supported visual. This is usually true of high-end workstations. There are ways to search through the available visuals to select the one that most closely meets the needs of your application, as will be described later. Several visuals of the same class may be provided but at different depths. On high performance screens, it is possible to create the colormap as read/write or as read-only. Both methods have certain advantages and would be used for different applications. There would be a separate visual for each of these ways of using the screen hardware. One of these visuals would be \f(CWTrueColor\fP class and the other \f(CWDirectColor\fP class. Some 24-plane screens allow the screen to be treated as two separate 12-plane \f(CWPseudoColor\fP visuals. (This allows for "double-buffering," a technique useful for animation, or for storing distance data to simplify hidden line and plane calculations in 3-D applications.) In fact, on some advanced workstations, you can use a different visual in each window. .sp .5 Figure 4 schematically represents the visual classes that can theoretically be supported by each type of screen hardware. A screen that supports the \f(CWDirectColor\fP class can theoretically support any of the six visual classes. A screen that supports the \f(CWPseudoColor\fP visual class can support \f(CWGrayScale\fP, \f(CWPseudoColor\fP, \f(CWStaticColor\fP, or \f(CWStaticGray\fP visual classes. A screen that supports the \f(CWGrayScale\fP visual class can also support \f(CWStaticGray\fP visual classes. The three types of screen with read-only colormaps can only support visuals of their own class. But remember that just because a certain visual class can theoretically be supported by a certain screen hardware does not mean that the server implementors will decide to support that class. .sp Note: Figure 4 "Hierarchy of visual classes" here. .sp .IP \s+2\f(HB7.2.5\fR\s-2 6n \s+2\f(HBShareability vs. Changeability\fR\s-2 .sp .5 Notice that \f(CWDirectColor\fP, \f(CWGrayScale\fP, and \f(CWPseudoColor\fP visuals have changeable colormaps, but \f(CWStaticColor\fP, \f(CWStaticGray\fP, and \f(CWTrueColor\fP have immutable colormaps. Within the changeable colormaps, it is possible to have two types of colorcells: read-only and read/write. The color in a read-only cell is set once by one client and from then on can be shared by any client but not changed. A read/write cell can have its color changed at any time by the client that allocated it but cannot be shared by other clients. In immutable colormaps, you are limited to only read-only cells. .sp .5 One advantage of immutable colormaps is that all the cells are read-only and can be shared between clients, so all the cells are available to every client. Immutable colormaps also make it possible to calculate pixel values from the colors desired without querying the server, since the mapping between pixel values and colors is predictable. This technique is necessary for smooth shading and 3-D rendering algorithms. As you will see, this is usually not possible with changeable colormaps. The disadvantages of immutable colormaps are that there may not be the exact color you desire (if there are a small number of planes) and you cannot allocate read/write cells, so you cannot change a colorcell to change the color of existing pixels on the screen. To change a color, you have to redraw the graphics with a new pixel value. .sp .5 In general, the advantage of changeable colormaps is that you can have both private read/write cells and shareable read-only cells. That is why \f(CWPseudoColor\fP and \f(CWDirectColor\fP are the most useful visuals, when a screen supports them. \f(CWPseudoColor\fP and \f(CWDirectColor\fP allow you to decide whether your client really needs read/write cells or whether it can use read-only cells. Read-only usage is preferred, since these cells can be shared by all clients, which means that the colormap is less likely to run out of free cells. .Nd 2 .sp .5 Try not to confuse the writeability of colormaps with the writeability of colorcells. A colorcell in a read/write colormap can be allocated read/write or read-only. A colorcell in a read-only colormap can only be allocated read-only. A changeable colormap could be made entirely read-only if the window manager or any other client allocates all available colorcells read-only. .sp .5 The advantages of read/write colorcells, available only in changeable colormaps, are that your program can select exactly the color you want (as long as it is physically possible on the screen) and you can change the color at will, which instantly changes the visible color of everything drawn with that pixel value if the colormap is currently installed. Although any other client can also change the values in a read/write cell, it is a convention that only the client that allocated the cell should change its contents. You \fIown\fR that pixel value. Since most clients cannot be satisfied with having no control over their displayed colors, this pixel value is not shareable. That means that if several clients that use read/write colorcells are running, all the colorcells might be used. Then some client will be forced to create its own colormap, with the negative consequences described in Section 7.7. .IP \s+4\f(HB7.3\fR\s-4 6n \s+4\f(HBAllocating Shared Colors\fR\s-4 .sp Since free colorcells can quickly become a scarce resource when clients store private color values, simple clients that mainly use color for decoration are encouraged always to allocate read-only colors, so that these colorcells can be shared by other clients that allocate the same colors read-only. .sp .5 The returned pixel value can be used to set the \f(CWbackground_pixel\fP or \f(CWborder_pixel\fP attribute of a window or to set the \f(CWforeground\fP or \f(CWbackground\fP member of a GC, which are used by drawing requests. (See Chapters 4 and 5 for more information.) .sp .5 Read-only colorcells can be allocated with the following routines: .IP "\f(CWXAllocColor\fP" 22n Returns the index of the colorcell (a pixel value) that contains the RGB values requested or that contains the closest RGB values physically possible on the screen. .IP "\f(CWXAllocNamedColor\fP" 22n Returns the index of the colorcell that contains the RGB values associated with a specified color name from the string color name database or the closest RGB values physically possible on the screen. .sp .5 By convention, clients allow the user to specify colors on the command line or in the resource database using a color name. When the RGB values are chosen from the color database by specifying color name strings, sharing of read-only colorcells is much more likely than if colors are specified as raw RGB values or using hexadecimal specifications. .sp .5 \f(CWXParseColor\fP parses a color name string or a hexadecimal color specification string and returns RGB values. It can be used with \f(CWXAllocColor\fP or the routines that allocate read/write cells, which will be described later. For color names, it gets the RGB values from the server's color database just like \f(CWXAllocNamedColor\fP. You may have noticed that \f(CWXAllocNamedColor\fP is very similar to the combination of \f(CWXParseColor\fP and \f(CWXAllocColor\fP. The difference is slight: \f(CWXAllocNamedColor\fP can interpret color names but not hexadecimal specifications\(embut hexadecimal specifications are rarely made by users anyway. The two-routine combination is more often used because it allows you to separately report errors in parsing the color specified and allocating the colorcell. .sp .5 Using \f(CWXQueryColor\fP and \f(CWXQueryColors\fP you can find out what RGB values are in each colorcell. But there is no way to determine whether a given cell is read-only or read/write or how many cells are currently unallocated. .sp .5 A request to allocate a color may fail because there are no free colormap cells and, for read-only colorcells, because no existing colorcell contains the closest color possible on the hardware to the exact color requested. Applications must allocate colors by trial and error. The routines that allocate colorcells all have \f(CWStatus\fP return values. If the call to allocate colorcells returns \f(CWFalse\fP, the client may modify the arguments and try again. If repeated attempts fail, the client can settle with \f(CWBlackPixel\fP and \f(CWWhitePixel\fP or, if these colors are inadequate, create a new virtual colormap. An application with picky color needs that cannot be satisfied can simply report to the user that its color needs cannot be met and exit. .sp .5 .IP \s+2\f(HB7.3.1\fR\s-2 6n \s+2\f(HBThe XColor Structure\fR\s-2 .sp .5 Both \f(CWXAllocColor\fP and \f(CWXAllocNamedColor\fP (as well as other functions that manipulate colorcells) take as an argument an \f(CWXColor\fP structure. This structure is used to specify the desired RGB values, as well as to return the pixel value. .sp .5 The \f(CWXColor\fP structure is shown in Example 1. The information it contains closely matches the information in each cell of the colormap. .sp .5 \s-1\f(CW .nf .ta 4.5n 3i typedef struct { unsigned long pixel; /* Pixel value */ unsigned short red, green, blue; /* RGB values */ char flags; /* DoRed, DoGreen, and/or * DoBlue */ char pad; /* Unused; pads structure * to even word boundary */ } XColor; \fR\s0 .fi .sp .5 Example 1: "The XColor structure" .sp In \f(CWXAllocColor\fP and \f(CWXAllocNamedColor\fP, the \f(CWpixel\fP member returns the pixel value that will be used to set the foreground or background pixel value in the GC or window attributes. In \f(CWXStoreColor\fP and \f(CWXQueryColor\fP, which you will see later, the \f(CWpixel\fP .ne 2 member indicates which cell in the colormap is having its color set (read/write cells only) or is having its RGB values queried. .sp .5 The \f(CWred\fP, \f(CWgreen\fP, and \f(CWblue\fP members are 16-bit values. Full brightness in a color is a value of 65535, half brightness is 32767, and off is 0. (The server automatically scales these values if the hardware colormap includes fewer bits for RGB values.) .sp .5 .hw DoGreen The \f(CWflags\fP member of the \f(CWXColor\fP structure is a bitwise OR of the symbols \f(CWDoRed\fP, \f(CWDoGreen\fP, and \f(CWDoBlue\fP. These flags are used to specify which of the red, green, and blue values should be read while changing the RGB values in a read/write colorcell. .sp .5 .IP \s+2\f(HB7.3.2\fR\s-2 6n \s+2\f(HBCode to Allocate Read-only Colors\fR\s-2 .sp .5 As we have said, applications that have basic color needs should allocate read-only, shareable color cells. Example 2 shows code to allocate a color specified using a name from the color name database. In this case, we have simply hardcoded the color name strings. In a real application, you would hardcode the default color but allow user specification of the string, as is done in \fIbasecalc\fR, described in Chapter 12. .sp .5 This routine uses \f(CWXMatchVisualInfo\fP to determine whether color is supported on the screen. If any of the four color visual classes are supported, it proceeds to attempt to allocate read-only colors. Whenever anything fails or if color is not supported, the routine uses black and white. For some applications, this could be modified to allocate levels of gray on GrayScale visual class screens. .sp .5 The code for all the examples in this chapter is in the example source in the directory \fI/basicwin/color/\fR. This example is called \fIbasic.ro\fR. .sp .5 \s-1\f(CW .nf #include #include #include #include extern Display *display; extern int screen_num; extern Screen *screen_ptr; extern unsigned long foreground_pixel, background_pixel, border_pixel; extern char *progname; #define MAX_COLORS 3 /* This is just so we can print the visual class intelligibly */ static char *visual_class[] = { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor" }; get_colors() { int default_depth; Visual *default_visual; static char *name[] = {"Red", "Yellow", "Green"}; XColor exact_def; Colormap default_cmap; int ncolors = 0; int colors[MAX_COLORS]; int i = 5; XVisualInfo visual_info; /* Try to allocate colors for PseudoColor, TrueColor, * DirectColor, and StaticColor; use black and white * for StaticGray and GrayScale */ default_depth = DefaultDepth(display, screen_num); default_visual = DefaultVisual(display, screen_num); default_cmap = DefaultColormap(display, screen_num); if (default_depth == 1) { /* Must be StaticGray, use black and white */ border_pixel = BlackPixel(display, screen_num); background_pixel = WhitePixel(display, screen_num); foreground_pixel = BlackPixel(display, screen_num); return(0); } while (!XMatchVisualInfo(display, screen_num, default_depth, /* visual class */i--, &visual_info)) ; printf("%s: found a %s class visual at default depth.\en", progname, visual_class[++i]); if (i < StaticColor) { /* Color visual classes are 2 to 5 */ /* No color visual available at default depth; * some applications might call XMatchVisualInfo * here to try for a GrayScale visual if they * can use gray to advantage, before giving up * and using black and white */ border_pixel = BlackPixel(display, screen_num); background_pixel = WhitePixel(display, screen_num); foreground_pixel = BlackPixel(display, screen_num); return(0); } /* Otherwise, got a color visual at default depth */ /* The visual we found is not necessarily the default * visual, and therefore it is not necessarily the one * we used to create our window; however, we now know * for sure that color is supported, so the following * code will work (or fail in a controlled way) */ /* Let's check just out of curiosity: */ if (visual_info.visual != default_visual) { printf("%s: %s class visual at default depth\en", progname, visual_class[i]); printf("is not default visual! Continuing anyway...\en"); } for (i = 0; i < MAX_COLORS; i++) { printf("allocating %s\en", name[i]); if (!XParseColor (display, default_cmap, name[i], &exact_def)) { fprintf(stderr, "%s: color name %s not in database", progname, name[i]); exit(0); } printf("The RGB values from the database are %d, %d, %d\en", exact_def.red, exact_def.green, exact_def.blue); if (!XAllocColor(display, default_cmap, &exact_def)) { fprintf(stderr, "%s: can't allocate color:\en", progname); fprintf(stderr, "All colorcells allocated and\en"); fprintf(stderr, "no matching cell found.\en"); exit(0); } printf("The RGB values actually allocated are %d, %d, %d\en", exact_def.red, exact_def.green, exact_def.blue); colors[i] = exact_def.pixel; ncolors++; } printf("%s: allocated %d read-only color cells\en", progname, ncolors); border_pixel = colors[0]; background_pixel = colors[1]; foreground_pixel = colors[2]; return(1); } \fR\s0 .fi .sp .5 Example 2: "Allocating read-only colorcells" .sp This code begins by setting variables to the default depth, visual, and colormap for later use. If the default depth is one, then the application is displaying on a monochrome screen, and black and white are returned. Then the code calls \f(CWXMatchVisualInfo\fP in a loop to look for a color visual at the default depth\(emit is called up to four times, until a color visual is found. If none is found, it again returns black and white, since this screen must support only a \f(CWGrayScale\fP visual (at this depth, anyway). Some applications may wish to allocate grays in this branch. The rest of the code loops through the list of color names to be allocated, looks them up in the color database, and then allocates them. If either the lookup stage or the allocation stage fails for any color, the routine prints an error and exits. It could instead simply fall back on black and white again; your choice. .sp .5 As noted in the code, the visual found might not necessarily be the default visual. This does not always matter, because if any color visual is available, it is a good bet that the default visual is also color, and so colors can be allocated without doing any further research. With \f(CWXMatchVisualInfo\fP, it is difficult to develop an algorithm that is guaranteed to find the default visual. This is much easier with \f(CWXGetVisualInfo\fP, which returns a list of available visual structures that match a set of criteria you specify. If you pass no criteria, it simply returns the entire list of available visuals. You can then search through the list matching the \f(CWvisual\fP member of the \f(CWXVisualInfo\fP structures to the default visual. .sp .5 The \f(CWXParseColor\fP call specifies a color name, and the RGB values corresponding to that name are returned from the color database in the passed \f(CWXColor\fP structure. This structure is then passed to \f(CWXAllocColor\fP, and the pixel value allocated is returned in the \f(CWpixel\fP field of the structure. .sp .5 The same calls would be used to parse a hexadecimal color string. Pink could be specified in the call to \f(CWXParseColor\fP as "\f(CW#bc8f8f\fP" instead of "\f(CWpink\fP". But, as we have said before, color names are preferred, because there is a better chance that they will specify a color already allocated or later to be allocated by another client. .sp .5 It is also possible to specify the desired RGB values explicitly. This is good for default colors because it saves a call to \f(CWXParseColor\fP, but on the other hand, you might not get a consistent color on all systems because you are bypassing the gamma correction implemented through the color database. Simply declare an \f(CWXColor\fP structure and set its \f(CWred\fP, \f(CWgreen\fP, and \f(CWblue\fP members to the desired RGB values. Of course, these values can be specified as integers, hexadecimal values, or any other way that the C language allows. Then pass this structure to \f(CWXAllocColor\fP. But remember, as we have said, it is better to use color names when allocating read-only colorcells than to use any of these explicit RGB values. .sp .5 .IP \s+2\f(HB7.3.3\fR\s-2 6n \s+2\f(HBHighlighting in Two Colors\fR\s-2 .sp .5 It is easy to highlight graphics on a monochrome system. The simplest way is to set the GC to the \f(CWGXxor\fP logical function and draw your graphics once to draw them and again to undraw them. You must grab the server between the drawing and undrawing so that no other client changes the same pixels in between (by, for example, covering part of the area with another window). On a monochrome system, this always changes white to black and black to white if you set the foreground in the GC to \f(CW1\fP (setting it to \f(CWBlackPixel\fP or \f(CWWhitePixel\fP is not guaranteed to work on all systems, because either may be \f(CW0\fP). .sp .5 When drawing in \f(CWBlackPixel\fP and \f(CWWhitePixel\fP on a color system, the color drawn by the \f(CWGXxor\fP operation is random if \f(CWBlackPixel\fP or \f(CWWhitePixel\fP are used for the foreground pixel value in the GC. This is because there is no restriction on which pixel value \f(CWBlackPixel\fP and \f(CWWhitePixel\fP can be on a server\(emthey are not necessarily \f(CW1\fP and \f(CW0\fP and not necessarily different by just one bit. For example, the pixel value drawn if the foreground pixel value in the GC is \f(CWBlackPixel\fP and the pixel value on the screen is \f(CWWhitePixel\fP is \f(CWBlackPixel\fP XOR \f(CWWhitePixel\fP, which, unless \f(CWBlackPixel\fP and WhitePixel are different by only one bit, is a third pixel value not allocated by this client. The colorcell identified by this pixel value might contain black, in which case the operation would not change the screen. .sp .5 The solution to this problem, which works on monochrome and color systems, is to set the foreground pixel value in the GC used in drawing with \f(CWGXxor\fP to the exclusive OR of \f(CWBlackPixel\fP and \f(CWWhitePixel\fP or by setting the logical function to \f(CWGXinvert\fP and using a plane mask which is the exclusive OR of \f(CWWhitePixel\fP and \f(CWBlackPixel\fP. All applications that highlight graphics drawn in \f(CWBlackPixel\fP and \f(CWWhitePixel\fP on a color system should use one of these two methods. The following example illustrates how this works using two arbitrarily chosen pixel values (which could be \f(CWBlackPixel\fP and \f(CWWhitePixel\fP or could be any two colors). .sp .5 Let's assume that we draw in two pixel values, which we will call \f(CWcolor1\fP and \f(CWcolor2\fP. The pixel values for these could be: .sp .5 \s-1\f(CW .nf color1 = 11111111111111110000000000000000 color2 = 00000000111111111111111100000000 .fi \fR\s0 .fi .sp .5 The pixel value we will use to draw is generated by taking the exclusive OR of \f(CWcolor1\fP and \f(CWcolor2\fP: .sp .5 \s-1\f(CW color1 XOR color2 = 11111111000000001111111100000000 \fR\s0 .sp .5 Now we set the \f(CWforeground\fP in the GC to this pixel value and the \f(CWfunction\fP in the GC to \f(CWGXxor\fP and draw. This changes existing pixels that contained \f(CWcolor1\fP to \f(CWcolor2\fP and existing pixels that were \f(CWcolor2\fP to \f(CWcolor1\fP. .sp .5 \s-1\f(CW .nf foreground = 11111111000000001111111100000000 existing pixel (color1) = 11111111111111110000000000000000 resulting pixel (color2) = 00000000111111111111111100000000 .fi \fR\s0 .sp .5 The other way to do this is to set the \f(CWplane_mask\fP in the GC to (\f(CWcolor1\fP\ \f(CW^\fP\ \f(CWcolor2\fP) and then use a logical function of \f(CWGXinvert\fP. This is equally effective. .sp .5 .IP \s+2\f(HB7.3.4\fR\s-2 6n \s+2\f(HBChoosing Default Colors\fR\s-2 .sp .5 A client that uses color should allow the user to specify the colors either on the command line or in the resource database, or both. The resource manager (described in Chapter 11) can be used to merge these preferences with the defaults of the program. However, the client needs to have reasonable default colors in case the user does not specify any preferences. .sp .5 Follow these guidelines for your application's default colors:* .sp .FS *Courtesy Oliver Jones, Apollo Computer. .FE .RS .IP \(bu 5 Use string color names for read-only colorcells if possible, since this maximizes the chance of sharing cells. .IP \(bu 5 Use colors with large contributions from two or all three primary colors\(emthey light the screen more brightly. .IP \(bu 5 Avoid shades of pure blue\(emthe human eye is relatively insensitive to and unable to focus on images made of pure blue light. Mix blue shades with white (white contains equal parts of all three primary colors). .IP \(bu 5 Remember that some users are color blind. Do not use the same intensity of green and red for "safe" and "danger"\(emuse colors with differing intensity. .RE .sp 2 .IP \s+4\f(HB7.4\fR\s-4 6n \s+4\f(HBAllocating Private Colors\fR\s-4 .sp In colormaps of the \f(CWPseudoColor\fP or \f(CWTrueColor\fP visual classes, a client can allocate read/write cells. Read/write colorcells should be allocated when: .sp .RS .IP \(bu 5 The application draws something whose color must be changed dynamically without redrawing it. For example, in a color mixing program, the palette must be drawn in colors that change frequently. If this were done with read-only colors, cells would have to be allocated and freed frequently and the palette area redrawn with each new color. However, with read/write colorcells, the steps of allocation and color setting are separate, so that the color of an already allocated cell can be changed at will. Anything drawn using the pixel value of this colorcell will change color immediately when the RGB values in the colorcell are changed. .IP \(bu 5 The application needs to overlay graphics on top of other graphics in such a way that the overlayed graphics can be erased without disturbing the underlying graphics. For example, in a Computer Aided Design (CAD) package for chip design, it is often useful to overlay the various layers of a chip in different colors on the screen. When one of the layers is removed, you want to avoid having to redraw all the underlying layers. How to do this by allocating read/write cells will be described. .IP \(bu 5 The system has a huge colormap, and the application needs to set a large number of colorcells. The calls for manipulating read/write colorcells allow you to manipulate multiple cells per call, whereas with read-only cells, you are limited to one cell per call. .RE .sp 2 Note that read/write colorcell allocation never works on \f(CWTrueColor\fP or \f(CWStaticColor\fP visuals. Therefore, on systems that only support these visuals, an application that uses read/write colorcells cannot work. Read/write colorcells should only be used when really needed. .sp .5 \f(CWXAllocColorCells\fP allocates read/write colorcells. At its simplest, it allows you to allocate read/write cells so you can change the RGB values dynamically. .sp .5 But to simply allocate just a few cells, you set the \f(CIncolors\fP argument to the number of colorcells desired and \f(CInplanes\fP to \f(CW0\fP, and all the pixel values you need will be returned in the \f(CIpixels\fP array. The real reason for the \f(CInplanes\fP and \f(CIplane_masks\fP arguments will become clear in Section 7.5.2. The RGB values of the allocated cells are set with \f(CWXStoreColor\fP, \f(CWXStoreColors\fP, or \f(CWXStoreNamedColor\fP. .sp .5 \f(CWXAllocColorPlanes\fP, on the other hand, is only used when you want to be able to vary a primary color component of graphics already drawn without redrawing them. It allocates read/write cells, so that a preset number of bits are reserved for each primary color. Primarily for \f(CWDirectColor\fP, it also allows you to simulate a small \f(CWDirectColor\fP colormap on a \f(CWPseudoColor\fP visual but uses up colorcells quickly. It treats the colormap as three separate lookup tables, allocating \f(CIncolors\fR\ \f(CW*\fP .Su + \f(CW2\fR \f(CInreds\fR entries in the red lookup table, \f(CIncolors\fR\ \f(CW*\fP .Su + \f(CW2\fR \f(CIngreens\fR entries in the green lookup table, and \f(CIncolors\fR\ \f(CW*\fP .Su + \f(CW2\fR \f(CInblues\fR entries in the blue lookup table. .Nd 4 .sp .5 The following routines are used to actually store colors into read/write colorcells once they are allocated: .IP "\f(CWXStoreColor\fP" 22n Changes the read/write colormap cell corresponding to the specified pixel value to the hardware color that most closely matches the RGB values specified.* .FS *Even when storing explicit RGB values, you may not get the precise color you specify. For example, if the hardware colormap supports only four bits of intensity in each primary and you specify eight-bit values, the server will scale the values you provide to the closest possible equivalent on the hardware. .FE The flags \f(CWDoRed\fP, \f(CWDoGreen\fP, and \f(CWDoBlue\fP in the \f(CWXColor\fP structure indicate which primary colors in the cell are to be changed. .IP "\f(CWXStoreColors\fP" 22n Like \f(CWXStoreColor\fP, except it does multiple cells per call. Changes the read/write colormap cell corresponding to the specified pixel value to the hardware color that most closely matches the RGB values specified. The flags \f(CWDoRed\fP, \f(CWDoGreen\fP, and \f(CWDoBlue\fP in each \f(CWXColor\fP structure indicate which primary colors in each cell are to be changed. .IP "\f(CWXStoreNamedColor\fP" 22n Performs the same function as \f(CWStoreColor\fP, except that it stores the RGB values associated with a string color name in the RGB database. This call would be useful for loading a private colormap with each of the default named colors. .sp .5 .IP \s+2\f(HB7.4.1\fR\s-2 6n \s+2\f(HBAllocating Read/Write Colorcells for Dynamic Colors\fR\s-2 .sp .5 As described above, the simplest use of read/write colors is to allocate colorcells whose colors can by changed at any time. Example 3 is analogous to the code just shown to allocate read-only colors, except that it allocates read/write colors instead. Note that it calls \f(CWXAllocColorCells\fP with the \f(CIncolors\fP argument set to the number of colorcells desired and \f(CInplanes\fP set to zero. .sp .5 \s-1\f(CW .nf #include #include #include #include extern Display *display; extern int screen_num; extern unsigned long foreground_pixel, background_pixel, border_pixel; #define MAX_COLORS 3 get_colors() { int default_depth; Visual *default_visual; static char *name[] = {"Red", "Yellow", "Green"}; XColor exact_defs[MAX_COLORS]; Colormap default_cmap; int ncolors = MAX_COLORS; int plane_masks[1]; int colors[MAX_COLORS]; int i; XVisualInfo visual_info; int class; class = PseudoColor; default_depth = DefaultDepth(display, screen_num); default_visual = DefaultVisual(display, screen_num); default_cmap = DefaultColormap(display, screen_num); if (default_depth == 1) { /* Must be StaticGray, use black and white */ border_pixel = BlackPixel(display, screen_num); background_pixel = WhitePixel(display, screen_num); foreground_pixel = BlackPixel(display, screen_num); return(0); } if (!XMatchVisualInfo(display, screen_num, default_depth, PseudoColor, &visual_info)) { if (!XMatchVisualInfo(display, screen_num, default_depth, DirectColor, &visual_info)) { /* No PseudoColor visual available at default_depth; * some applications might try for a GrayScale * visual here if they can use gray to advantage, * before giving up and using black and white */ border_pixel = BlackPixel(display, screen_num); background_pixel = WhitePixel(display, screen_num); foreground_pixel = BlackPixel(display, screen_num); return(0); } } /* Got PseudoColor or DirectColor visual at default_depth */ /* The visual we found is not necessarily the default * visual, and therefore it is not necessarily the one * we used to create our window; however, we now know * for sure that color is supported, so the following * code will work (or fail in a controlled way) */ /* Allocate as many cells as we can */ ncolors = MAX_COLORS; while (1) { if (XAllocColorCells (display, default_cmap, False, plane_masks, /* nplanes */0, colors, ncolors)) break; ncolors--; if (ncolors = 0) fprintf(stderr, "basic: couldn't allocate read/write \ colors\en"); exit(0); } printf("basic: allocated %d read/write color cells\en", ncolors); for (i = 0; i < ncolors; i++) { if (!XParseColor (display, default_cmap, name[i], &exact_defs[i])) { fprintf(stderr, "basic: color name %s not in database", name[i]); exit(0); } /* Set pixel value in struct to the allocated one */ exact_defs[i].pixel = colors[i]; exact_defs[i].flags = DoRed | DoGreen | DoBlue; } /* This sets the color of read/write cell */ XStoreColors (display, default_cmap, exact_defs, ncolors); border_pixel = colors[0]; background_pixel = colors[1]; foreground_pixel = colors[2]; } \fR\s0 .fi .sp .5 Example 3: "Allocating read/write colorcells for dynamic colors" .sp The \f(CWmain\fP that calls this \f(CWget_colors\fP function, shown in Example 4 contains an \f(CWXQueryColor\fP call that gets the current RGB values in the colorcell (necessary because \f(CWmain\fP and \f(CWget_colors\fP are in separate source files and the RGB values used in \f(CWget_colors\fP are not global variables) and an \f(CWXStoreColor\fP call that changes the color of what is drawn in the foreground pixel value every time you press a button in the window. In the example source, this application is in the directory \fIbasicwin/color/\fR and is called \fIbasic.rw\fR. .sp .5 \s-1\f(CW .nf . . . void main(argc, argv) int argc; char **argv; { . . . XColor color; unsigned short red, green, blue; . . . /* Open display, etc. */ color.pixel = foreground_pixel; XQueryColor(display, DefaultColormap(display, screen_num), &color); printf("red is %d, green is %d, blue is %d\en", color.red, color.green, color.blue); while (1) { XNextEvent(display, &report); switch (report.type) { . . . case ButtonPress: color.red += 5000; color.green -= 5000; color.blue += 3000; printf("red is %d, green is %d, blue is %d\en", color.red, color.green, color.blue); XStoreColor(display, DefaultColormap(display, screen_num), &color); break; . . . } } \fR\s0 .fi .sp .5 Example 4: "Main of basic.rw \(em changing colors of dynamic colorcells" .sp .IP \s+2\f(HB7.4.2\fR\s-2 6n \s+2\f(HBAllocating Read/Write Colorcells for Overlays\fR\s-2 .sp .5 \f(CWXAllocColorCells\fP has another use: it allows you to nondestructively overlay one set of graphics over another. The underlying graphics will not be visible where the overlay is drawn, but they can be refreshed by simply setting or clearing one or more complete planes in the drawable. This technique can improve the performance of a client by reducing the amount of complicated graphics that have to be redrawn. It can be useful for highlighting graphics for selection. However, as noted earlier, read/write colorcells can only be allocated in \f(CWPseudoColor\fP and \f(CWDirectColor\fP visuals, so any application that attempts to use this technique should also provide a fallback technique for use on other visuals or in case of failure. .sp .5 The trick that allows drawing without destroying what is already drawn relies on the fact that we can draw in one plane of the drawable, changing the pixel values and therefore the color, without changing any other plane. This is possible using the \f(CWplane_mask\fP component of the GC. It is these other planes that contain the information about the drawing that was already there. The disadvantage of this approach is that we have to allocate more colorcells than we would normally need. Some of the colorcells will need to be loaded with duplicate RGB values. Because of this waste of colorcells, this technique should be used only when the graphics being preserved are slow for the client or the server to redraw. .Nd 20 .sp .5 To illustrate this trick, we are going to draw in one color (the foreground in the GC), set the \f(CWbackground_pixel\fP attribute of the window to a second color, and then draw something temporary over the top with a third color.* .FS *Note that the background of a window is redrawn by the server when \f(CWExpose\fP events occur, but this does not effect the process of drawing and removing overlays, because no \f(CWExpose\fP event will be triggered in this process. In other words, even though the background color is set as a window attribute and drawn by the server, the response to other graphics drawn on top is the same as if the background were drawn by the application. The background counts as a color that must be preserved. .FE To do this, we need to allocate four colorcells with \f(CWXAllocColorCells\fP. The pixel values allocated will look something like this: .sp .5 .sp .5 \s-1\f(CW 3n .nf \fRColor\v'1p'\h'-\w'Color'u'\l'\w'Color'u\(ul'\v'-1p' Important Bits\v'1p'\h'-\w'Important Bits'u'\l'\w'Important Bits'u\(ul'\v'-1p' Remaining bits\v'1p'\h'-\w'Remaining bits'u'\l'\w'Remaining bits'u\(ul'\v'-1p'\f(CW foreground: ----0--0------------------------ \fIall other bits don't matter\fP background: ----0--1------------------------ \fIall other bits don't matter\fP highlight1: ----1--0------------------------ \fIall other bits don't matter\fP highlight2: ----1--1------------------------ \fIall other bits don't matter\fP \fR\s0 .fi .sp .5 .sp .5 The bits indicated could have been any bits, but it is significant that only two bits distinguish the four pixel values. The first pixel value is used for the foreground, and the second for the background. We draw overlays in the third or fourth pixel value. Since we do not want to erase what was drawn in the foreground and background pixel values, we use a plane mask to restrict the drawing of the highlighting pixel value to a single plane, the one where bits in the highlighting pixel values are set to 1. When this entire plane (indicated by the 1 in pixel values \f(CWhighlight1\fP and \f(CWhighlight2\fP) is cleared, anything drawn in \f(CWhighlight1\fP or \f(CWhighlight2\fP disappears, and anything that was drawn in the foreground or background will reappear. The color in the colorcell indicated by \f(CWhighlight2\fP must be the same as the color of colorcell \f(CWhighlight1\fP so that the same highlighting color appears regardless of the bit already in the drawable that distinguishes the foreground and background pixel values. .sp .5 \f(CWXAllocColorCells\fP does not return these four pixel values directly. Instead it returns the arrays \f(CIcolors\fP and \f(CIplane_masks\fP that are more convenient for actually using the overlays than a single array of pixel values. (Each of these arrays has the number of members that was specified in the \f(CIncolors\fP and \f(CInplanes\fP arguments.) Both arrays consist of unsigned long values like pixel values. One array contains the plane masks of the overlay planes, and the other contains the pixel values that can be used for drawing independent of the overlay planes. Here are the values returned in each array after we call \f(CWXAllocColorCells\fP with \f(CIncolors\f(CW\ =\ 2\fR and \f(CInplanes\f(CW\ =\ 1\fR. These values are then used to generate the pixel values shown above. .sp .5 .sp .5 \s-1\f(CW 3n .nf \fRArray Members\v'1p'\h'-\w'Array Members'u'\l'\w'Array Members'u\(ul'\v'-1p' Important Bits\v'1p'\h'-\w'Important Bits'u'\l'\w'Important Bits'u\(ul'\v'-1p' Remaining Bits\v'1p'\h'-\w'Remaining Bits'u'\l'\w'Remaining Bits'u\(ul'\v'-1p'\f(CW colors[0] = ----0--0------------------------ \fIother bits don't matter\fP colors[1] = ----0--1------------------------ plane_masks[0] = ----1--------------------------- \fIall other bits 0\fR \fR\s0 .fi .sp .5 .sp .5 The two members of the \f(CIcolors\fP array are used for the foreground and background. Pixel values \f(CWhighlight1\fP and \f(CWhighlight2\fP are composed by combining with a bitwise OR each item in the \f(CIcolors\fP array with each item in the \f(CIplane_masks\fP array. In this case, \f(CWhighlight1\fP is (\f(CIcolors\f(CW[0]\ |\ \f(CIplane_masks\f(CW[0]\fR). The \f(CWplane_mask\fP in the GC used when highlighting should be set to the OR of the members of \f(CIplane_masks\fP used to make the highlighting pixel value. In this simplest case, highlighting should be done with the \f(CWplane_mask\fP in the GC set to \f(CIplane_masks\f(CW[0]\fR. .sp .5 Note that \f(CWhighlight2\fP, generated with (\f(CIcolors\f(CW[1]\ |\ \f(CIplane_masks\f(CW[0]\fR), can be useful. As mentioned earlier, \f(CWhighlight2\fP can be used .hw highlight interchangeably with \f(CWhighlight1\fP, as long as the \f(CWplane_mask\fP in the GC is set to \f(CIplane_masks\f(CW[0]\fR. But \f(CWhighlight2\fP has another use. With a GC that does not have its \f(CWplane_mask\fP set to \f(CIplane_masks\f(CW[0]\fR (the GC used for drawing with the foreground or background), this fourth pixel value can be used for drawing in the highlighting color while wiping out the underlying graphics, so that when the highlight is removed, the background color appears regardless of the contents of the drawable before the highlighting. .sp .5 We have been hinting at the fact that this overlay technique can be used with more than two colors and more than one plane. \f(CIncolors\fP specifies the number of colors than can be drawn and preserved while drawing in the overlays. \f(CInplanes\fP specifies how many separate one-color overlays you may have or how many bits of color are available in a single overlay. The pixel values in the \f(CIcolors\fP array are the ones that will be preserved through overlays. By ORing together each \f(CIcolors\fP with any combination of \f(CIplane_masks\fP, you get the pixel values that are used for drawing the overlays. Note, however, that the plane mask of the GC used for the overlaying must be the OR of the same combination of members of the \f(CIplane_masks\fP array as were used to generate the pixel value. .sp .5 The total number of pixel values (colorcells) allocated by \f(CWXAllocColorCells\fP is \f(CIncolors\fR\ \f(CW*\fR .Su + \f(CW2\fR \f(CInplanes\fR .\".Ns R .\"Remove this note if 2 ^ nplanes (superscript) appears above it. .\".Ne \&. Note that the more planes you try to allocate, the less likely this request is to succeed, particularly on \f(CWPseudoColor\fP visuals. Therefore, if you are trying for multiple overlays or one multicolor overlay, this will probably work reliably only on \f(CWDirectColor\fP visuals, so make sure you have a backup plan for more common systems. In most cases, the underlying graphics can be redrawn if the overlays that would preserve them cannot be allocated. It is also possible to use backing store (which can save selective planes) or to manage your own off-screen pixmaps for use in fast redrawing of complicated graphics. .sp .5 \f(CWXAllocColorCells\fP takes a \f(CIcontig\fP argument that specifies whether the planes returned in \f(CIplane_masks\fP must be contiguous. The \f(CIcontig\fP argument is normally set to \f(CWFalse\fP, specifying that the allocated planes need not be contiguous, because then the chances of success of the \f(CWXAllocColorCells\fP call are greater. There are more likely to be a number of noncontiguous planes available than the same number of contiguous planes. The \f(CIcontig\fP argument may have to be set to \f(CWTrue\fP for imaging applications that want to be able to perform mathematical operations on the pixel values. It is easier to perform operations by shifting bits with contiguous planes than to achieve the same effect with random planes. .sp .5 Each plane mask has one bit for \f(CWGrayScale\fP and \f(CWPseudoColor\fP or three bits for \f(CWDirectColor\fP or \f(CWTrueColor\fP, and none of the masks have bits in common. .sp .5 Example 5 demonstrates allocating the read/write cells for a single overlay plane. It implements the overlay scheme described above. If this overlay plan fails, it allocates three colors so that a highlight can still be implemented even though the underlying graphics will have to be redrawn. If the color allocation fails completely, it uses black and white, which can be highlighted using the \f(CWGXxor\fP logical function to invert the color, as described in Section\ 7.3.3. .sp .5 \s-1\f(CW .nf #include #include #include #include extern Display *display; extern int screen_num; extern unsigned long foreground, background_pixel, overlay_pixel_1, overlay_pixel_2; extern unsigned long overlay_plane_mask; #define MAX_COLORS 2 #define MAX_PLANES 1 #define MAX_CELLS 4 /* MAX_COLORS * 2 ^ MAX_PLANES */ #define CANNOT_OVERLAY 0 #define CAN_OVERLAY 1 int get_colors() { int default_depth; static char *name[] = {"Red", "Yellow", "Green", "Green"}; XColor exact_defs[MAX_CELLS]; Colormap default_cmap; int ncolors = 4; int plane_masks[MAX_PLANES]; int colors[MAX_COLORS]; int i; XVisualInfo visual_info; int class; default_depth = DefaultDepth(display, screen_num); default_cmap = DefaultColormap(display, screen_num); if (default_depth == 1) { /* Must be StaticGray, use black and white */ background_pixel = WhitePixel(display, screen_num); foreground = BlackPixel(display, screen_num); printf("using black and white\en"); return(CANNOT_OVERLAY); } if (!XMatchVisualInfo(display, screen_num, default_depth, PseudoColor, &visual_info)) { if (!XMatchVisualInfo(display, screen_num, default_depth, DirectColor, &visual_info)) { /* No PseudoColor or TrueColor visual available * at default_depth; some applications might try * for a GrayScale visual here if they can use * gray to advantage, before giving up and using * black and white */ background_pixel = WhitePixel(display, screen_num); foreground = BlackPixel(display, screen_num); printf("using black and white\en"); return(CANNOT_OVERLAY); } } /* Got PseudoColor or TrueColor visual at default depth */ /* The visual we found is not necessarily the default * visual, and therefore it is not necessarily the one * we used to create our window; however, we now know * for sure that color is supported, so the following * code will work (or fail in a controlled way) */ if (XAllocColorCells (display, default_cmap, False, plane_masks, 1, colors, 2) == 0) { /* Can't get enough read/write cells to overlay; * try at least to get three colors */ if (XAllocColorCells (display, default_cmap, False, plane_masks, 0, colors, 3) == 0) { /* Can't even get that; give up and use * black and white */ background_pixel = WhitePixel(display, screen_num); foreground = BlackPixel(display, screen_num); printf("using black and white\en"); return(CANNOT_OVERLAY); } else ncolors = 3; } /* Allocated three or four colorcells succesfully, * now set their colors -- three and four are set * to the same RGB values */ for (i = 0; i < ncolors; i++) { if (!XParseColor (display, default_cmap, name[i], &exact_defs[i])) { fprintf(stderr, "basic: color name %s not in database", name[i]); exit(0); } /* This needed before calling XStoreColors */ exact_defs[i].flags = DoRed | DoGreen | DoBlue; } printf("got RGB values\en"); /* Set pixel value in struct to the allocated ones */ exact_defs[0].pixel = colors[0]; exact_defs[1].pixel = colors[1]; exact_defs[2].pixel = colors[0] | plane_masks[0]; exact_defs[3].pixel = colors[1] | plane_masks[0]; /* This sets the color of the read/write cells */ XStoreColors (display, default_cmap, exact_defs, ncolors); printf("stored colors\en"); background_pixel = exact_defs[0].pixel; foreground = exact_defs[1].pixel; if (ncolors == 4) { overlay_pixel_1 = exact_defs[2].pixel; overlay_pixel_2 = exact_defs[3].pixel; overlay_plane_mask = plane_masks[0]; printf("set can\en"); return(CAN_OVERLAY); } else { /* This must be used as a normal color, not overlay */ overlay_pixel_1 = exact_defs[2].pixel; printf("set can't\en"); return(CANNOT_OVERLAY); } } \fR\s0 .fi .sp .5 Example 5: "Using XAllocColorCells to allocate read/write colorcells for overlay plane" .sp .IP \s+2\f(HB7.4.3\fR\s-2 6n \s+2\f(HBUsing XAllocColorPlanes\fR\s-2 .sp .5 \f(CWXAllocColorPlanes\fP also allocates read/write colorcells but in a different way than \f(CWXAllocColorCells\fP. \f(CWXAllocColorPlanes\fP is used when you want to be able to change the amount of a primary color in graphics without having to redraw them. In other words, perhaps you are looking at an image and would like to increase the redness of it. The best way to do this is to increase the amount of red in every pixel value. \f(CWXAllocColorPlanes\fP would be the way to allocate colors to allow this. It is rarely used except in imaging applications and 3-D graphics and will rarely work except on 24-plane workstations with a \f(CWDirectColor\fP visual. .sp .5 Note that for applications like a paint mixing program, in which you have three bars for the three primary colors and a palette that shows the mixed color, you would not use \f(CWXAllocColorPlanes\fP. The correct way to implement this is to allocate a single read/write color for the palette and to change it dynamically. (If the primary colors are displayed, they should be allocated using read-only colors.) .sp .5 The piece of code shown in Example 6 is similar to Example 5 but it uses \f(CWXAllocColorPlanes\fP. It is somewhat sketchy, because real applications that use \f(CWXAllocColorPlanes\fP are complicated. .sp .5 After allocating colors with \f(CWXAllocColorPlanes\fP, you can then use \f(CWXStoreColors\fP to set the colors. When \f(CInred\fP, \f(CIngreen\fP, and \f(CInblue\fP are each \f(CW8\fP, only one call to \f(CWXAllocColorPlanes\fP and one call to \f(CWXStoreColors\fP are necessary to allocate and set all 16\ million colors of an entire 24-plane colormap. .Nd 10 .sp .5 \s-1\f(CW .nf #define PIXELS 256 Display *display; int screen_num; int contig = False; /* Noncontiguous planes */ unsigned long pixels[PIXELS]; /* Return of pixel values */ /* Number of independent pixel values allocate */ unsigned int ncolors = PIXELS; /* Need PIXELS * 2 ^ maxplanes defs, where maxplanes * is the largest of nred, ngreen, and nblue */ XColor defs[2048]; /* Number of planes to allocate for each primary */ unsigned int nreds = 3, ngreens = 3, nblues = 2; /* Returned masks, which bits of pixel value for each primary */ unsigned long \f(CWred_mask\fP, \f(CWgreen_mask\fP, \f(CWblue_mask\fP; Colormap colormap; Status status; /* Open display, etc. */ /* Get or create large DirectColor colormap */ while (status = \f(CWXAllocColorPlanes\fP(display, colormap, contig, pixels, ncolors, nreds, ngreens, nblues, &red_mask, &green_mask, &blue_mask) == 0) { /* Make contig False if it was True; reduce value of * ncolors; reduce value of nreds, ngreens, and/or * nblues; or try allocating new map; break when * you give up */ break; } if (status == 0) { fprintf(stderr, "%s: couldn't allocate requested colorcells", argv[0]); exit(-1); } /* Define desired colors in defs */ while (status = XStoreColors(display, colormap, defs, ncolors) == 0) { fprintf(stderr, "%s: can't store colors", argv[0]); /* Try to fix problem here, exit or break */ exit(-1); } /* Draw your shaded stuff! */ \fR\s0 .fi .sp .5 Example 6: "Using XAllocColorPlanes to allocate colorcells for DirectColor" .sp .IP \s+4\f(HB7.5\fR\s-4 6n \s+4\f(HBGetting Complete Visual Information\fR\s-4 .sp As mentioned earlier, some systems define more than one visual. The default visual might not be the most appropriate for your application. Moreover, the visual found using the technique described in Section 7.4.2 using \f(CWXMatchVisualInfo\fP is fine for applications with routine color needs but is not necessarily the best. As you may recall, \f(CWXMatchVisualInfo\fP returns a single visual arbitrarily selected from the list that matches the passed visual class and depth. The most thorough method is to get a complete list of visual information for every available visual using \f(CWXGetVisualInfo\fP and then choose from these. .sp .5 \f(CWXGetVisualInfo\fP returns a list of visual structures that match the attributes specified by template and mask arguments. The template is an \f(CWXVisualInfo\fP structure with members set to the required values, and the mask indicates which members are matched with the list of available .ne 2 visuals. By passing an empty template structure, you can get a complete list of \f(CWXVisualInfo\fP structures. .sp .5 .IP \s+2\f(HB7.5.1\fR\s-2 6n \s+2\f(HBThe XVisualInfo Structure\fR\s-2 .sp .5 The \f(CWXVisualInfo\fP structure returns information about the available visuals. It is used both to select a visual type from those available and as a source of information while using a particular visual. .sp .5 The \f(CWXVisualInfo\fP structure is shown in Example 7. .sp .5 \s-1\f(CW .nf typedef struct { Visual *visual; VisualID visualid; int screen_num; unsigned int depth; int class; unsigned long red_mask; unsigned long green_mask; unsigned long blue_mask; int colormap_size; /* Same as map_entries member of Visual */ int bits_per_rgb; } XVisualInfo; \fR\s0 .fi .sp .5 Example 7: "The XVisualInfo structure" .sp The \f(CWvisual\fP member is a pointer to the internal \f(CWVisual\fP structure. This pointer is used as the \f(CIvisual\fP argument of \f(CWXCreateWindow\fP and \f(CWXCreateColormap\fP. .sp .5 The \f(CWvisualid\fP member is not normally needed by applications. .sp .5 As discussed earlier, the \f(CWclass\fP member specifies whether the screen is to be considered color or monochrome and changeable or immutable. The \f(CWclass\fP member can be one of the constants \f(CWDirectColor\fP, \f(CWGrayScale\fP, \f(CWPseudoColor\fP, \f(CWStaticColor\fP, \f(CWStaticGray\fP, or \f(CWTrueColor\fP. .sp .5 The \f(CWred_mask\fP, \f(CWgreen_mask\fP, and \f(CWblue_mask\fP members are used only for the \f(CWDirectColor\fP and \f(CWTrueColor\fP visual classes, where there is a separate map .hw primary for each primary color. They define which bits of the pixel value index into the colormap for each primary color. Each mask has one contiguous set of bits, with no bits in common with the other masks. These values are zero for monochrome and most four- to eight-plane color systems. .sp .5 The \f(CWcolormap_size\fP member of the structure tells you how many different pixel values are valid with this visual. For a monochrome screen, this value is two. For the default visual of an eight-plane color system, this value is typically 254 or 256 (two colors are often reserved for the cursor). For \f(CWDirectColor\fP and \f(CWTrueColor\fP, \f(CWcolormap_size\fP will be the number of cells for the biggest individual pixel subfield. The \f(CWcolormap_size\fP member is the same as the \f(CWmap_entries\fP member of the visual structure. .sp .5 The \f(CWbits_per_rgb\fP member specifies how many bits in each of the red, green, and blue values in a colorcell are used to drive the RGB gun in the screen. For a monochrome screen, this value is one. For the default visual of an eight-plane color system, this value is typically eight. The pixel subfields (the red, green, and blue values in each colorcell) are 16-bit unsigned short values, but only the highest \f(CWbits_per_rgb\fP bits are used to drive the RGB gun in the screen. This number corresponds the number of bits of resolution in the Digital to Analog Converter (DAC) in the screen hardware. .sp .5 .IP \s+2\f(HB7.5.2\fR\s-2 6n \s+2\f(HBExample of Choosing a Visual\fR\s-2 .sp .5 Example 8 shows a routine that uses \f(CWXGetVisualInfo\fP to get all the visuals of depth 8 on the current screen, as defined by the X server, and then creates a colormap and window. .sp .5 \s-1\f(CW .nf #include #include visual() { Display *display; Colormap colormap; Window window; XSetWindowAttributes attributes; unsigned long valuemask; int screen_num; . . . XVisualInfo vTemplate; /* Template of the visual we want */ XVisualInfo *visualList; /* List of XVisualInfo structs that * match */ int visualsMatched; /* Number of visuals that match */ . . . /* Set up the XVisualInfo template so that it returns a list * of all the visuals of depth 8 defined on the current screen * by the X server */ vTemplate.screen = screen_num; vTemplate.depth = 8; visualList = XGetVisualInfo (display, VisualScreenMask | VisualDepthMask, &vTemplate, &visualsMatched); if ( visualsMatched == 0 ) fatalError ("No matching visuals\en"); /* Create a colormap for a window using the first of the * visuals in the list ov XVisualInfo structs returned by * XGetVisualInfo */ colormap = XCreateColormap (display, RootWindow(display, screen_num), visualList[0].visual, AllocNone); /* Must specify colormap attribute if using nondefault visual */ attributes.colormap = colormap; valuemask |= CWColormap; . . . window = XCreateWindow (display, RootWindow(display, screen_num), x, y, width, height, border_width, vTemplate.depth, InputOutput, visualList[0].visual, valuemask, &attributes); XSetWindowColormap(display, window, colormap); /* All done with visual information; free it */ XFree(visualList); . . . } /* End routine */ \fR\s0 .fi .sp .5 Example 8: "Code to match visuals" .sp Notice that the list of \f(CWXVisualInfo\fP structures is freed with \f(CWXFree\fP after use. .IP \s+4\f(HB7.6\fR\s-4 6n \s+4\f(HBThe GrayScale Visual\fR\s-4 .sp On a gray-scale workstation or a \f(CWGrayScale\fP visual on a color workstation, a color application should still work correctly. The only problem might be that when colors are allocated, the closest physically possible colors (returned by \f(CWXAllocColor\fP) will result in shades of gray that provide insufficient contrast. The best way to avoid this is to explicitly check for the \f(CWStaticGray\fP visual. For true bulletproof operation, it is a good idea to check any user-specified colors to make sure they contrast. .sp .5 The color names "gray0" through "gray100", spelled with an "e" or an "a", can be used with \f(CWXParseColor\fP to get RGB values for various grays. .sp .5 You must set the red, green, and blue values to be equal. Some servers only use one of the values, and others combine all three according to the NTSC standard that makes color television signals work on black-and-white televisions: .sp .5 \s-1\f(CW intensity = (.30 * red) + (.59 * green) + (.11 * blue) \fR\s0 .fi .sp .5 .Nd 3 The X Consortium's implementations use a least-squares algorithm that determines the closest RGB values in the (gray) colormap to the RGB values specified. Exactly what algorithm is used is up to the server implementor. .IP \s+4\f(HB7.7\fR\s-4 6n \s+4\f(HBCreating and Installing Colormaps\fR\s-4 .sp .\" remove have In discussing colormaps earlier in this chapter, we mentioned that there are hardware colormaps and virtual colormaps, but we did not discuss the ramifications of this fact. .sp .5 A hardware colormap is a physical register from which the screen hardware reads the RGB intensity values that generate the colors on the screen. Most workstations have only one hardware colormap, in which case all windows on the screen are interpreted using the same colormap. Some high performance workstations have multiple hardware colormaps, in which case separate windows may have their own independent colormaps. .sp .5 .\" ATTENTION NEEDED HERE If the hardware colormap cannot be changed, it is termed \fIimmutable\fR. Monochrome systems normally have an immutable colormap, since it does little good to swap the two entries or make them both black or white. Some low-cost color systems and X terminals have immutable hardware colormaps. The \f(CWStaticColor\fP, \f(CWStaticGray\fP, and \f(CWTrueColor\fP visuals are the only visuals that can possibly work on systems that have immutable hardware colormaps. In immutable colormaps, no client can allocate private colorcells and all RGB values are preset. On these systems, \f(CWXCreateColormap\fP succeeds, but it just gives you another copy of the default colormap (or one of the default colormaps if there are multiple immutable colormaps). The application should check for this when creating colormaps. .sp .5 On most color workstations, you can write new values into the hardware colormap or colormaps to change that mapping. These hardware colormaps are termed \fIchangeable\fR. The \f(CWDirectColor\fP, \f(CWGrayScale\fP, and \f(CWPseudoColor\fP visuals are available only on systems that have changeable colormaps. .sp .5 X manages multiple colormaps by keeping \fIvirtual colormaps\fR in memory and installing them as instructed by the window manager. \fIInstalling\fR a colormap is the process of moving a virtual colormap into the hardware colormap. Only installed colormaps are used to determine the colors appearing on the screen. When there is only one hardware colormap and a new virtual colormap is installed, the virtual colormap that was previously installed becomes \fIuninstalled\fR. .sp .5 Up to this point in this chapter, we have been allocating colors out of the default colormap, which is created and installed when the server starts up. On the most common color workstations, with four to eight planes, it is quite easy for clients that require precise colors to allocate all the available colorcells. Virtual colormaps are a response to this problem. When a client cannot get the colorcells it needs from the installed colormap, it can create a new virtual one. The window manager will then install this virtual colormap when this application is in use. .sp .5 When a virtual colormap is installed and there is only one hardware colormap, all the clients that used the old colormap will be displayed in false colors, since the pixel values in their windows will be interpreted according to the new colormap. .sp .5 When an application creates a virtual colormap, it must set the colormap window attribute of its top-level window so that the window manager can find out what colormap to install. By default, this attribute indicates the default colormap. If its subwindows use different colormaps from the main window, there is a property that can be set to tell this to the window manager, as described in Chapter 10. .sp .5 Several of the older window managers do not install colormaps properly. Under these, an application that creates its own colormap also has to install it. However, as these window managers are revised or go out of use, it becomes a hard rule that application should never install their own colormaps. This is required by the current conventions described in Chapter 10. .sp .5 By now you should be getting the idea that it is much better to arrange to share the default colormap with the other applications than to try to create one of your own. The only time when you should really need to create a special colormap is when you are doing smooth shading or similar applications that need many strangely distributed colors. On the other hand, creating a virtual colormap might be the only way to make your application that has demanding color needs work on a system that provides only a \f(CWPseudoColor\fP visual. On systems with multiple hardware colormaps, you can create your own colormap and have it installed without affecting other applications. You can use \f(CWXListInstalledColormaps\fP to get information about how many colormaps are installed into the hardware. .sp .5 .IP \s+2\f(HB7.7.1\fR\s-2 6n \s+2\f(HBFunctions for Manipulating Colormaps\fR\s-2 .sp .5 The following functions should be used by applications only if they need a special purpose colormap: .IP "\f(CWXCreateColormap\fP" 25n Creates a virtual colormap resource, either with no allocated entries or with all allocated read/write, that matches the passed visual. If no entries are allocated, they can be allocated either as read/write or as read-only cells. If all entries are allocated read/write, the colormap is completely private and just needs its colors set with \f(CWXStoreColors\fP. .IP "\f(CWXFreeColormap\fP" 25n Uninstalls the specified virtual colormap and frees the resources associated with the colormap. Applications are allowed to use this. Sends a \f(CWColormapNotify\fP event to any windows that were using the colormap. .IP "\f(CWXListInstalledColormaps\fP" 25n .br Lists the installed colormaps. .IP "\f(CWXCopyColormapAndFree\fP" 25n .br Moves all the client's existing colormap entries to a new colormap and frees those entries of the old colormap. This is used when colorcell allocation fails and some cells have already been allocated. It saves needing to create a colormap and start from the beginning allocating colors. For applications with special color needs that can't make do, they can call \f(CWXCopyColormapAndFree\fP, set their colormap window attribute, and continue allocating colors in the new colormap where they left off. .IP "\f(CWXSetWindowColormap\fP" 25n Sets the colormap window attribute of a window. .sp .5 The following functions are use by the window manager to install and uninstall colormaps: .IP "\f(CWXInstallColormap\fP" 25n A function only to be used by window managers to install a colormap. Any window using that colormap ID as its colormap attribute receives a \f(CWColormapNotify\fP event. .IP "\f(CWXUninstallColormap\fP" 25n A function only to be used by window managers to uninstall a colormap. Removes a virtual colormap from the set of installed hardware colormaps. On systems with only one hardware colormap, the default colormap is reinstalled. Sends \f(CWColormapNotify\fP event to windows that are using the specified map. .sp .5 .IP \s+2\f(HB7.7.2\fR\s-2 6n \s+2\f(HBThe ColormapNotify Event\fR\s-2 .sp .5 \f(CWColormapNotify\fP events notify an application when the colormap specified in the colormap attribute for a particular window has been installed, uninstalled, or freed or when the attribute itself has been changed. The former is used by applications, and the latter by window managers. .sp .5 If your application wants to know when your colormap is installed or uninstalled, it should watch for these events and act accordingly. To receive \f(CWColormapNotify\fP events, pass \f(CWColormapChangeMask\fP (ORed with the other masks you need) to \f(CWXSelectInput\fP. Example 9 shows the \f(CWXColormapEvent\fP structure. .sp .5 \s-1\f(CW .nf .ta 4.5n 2i typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* True if this came from SendEvent * request */ Display *display; /* Display the event was read from */ Window window; Colormap colormap; /* Colormap or None */ Bool new; int state; /* ColormapInstalled, ColormapUninstalled */ } XColormapEvent; \fR\s0 .fi .sp .5 Example 9: "The ColormapEvent structure" .sp .Nd 10 Here is a brief explanation of each member of the \f(CWXColormapEvent\fP structure: .IP "\f(CWwindow\fP" 15n The window for which this event was selected, whose colormap attribute was changed or whose colormap specified in that attribute was installed, uninstalled, or freed. .Nd 4 .IP "\f(CWcolormap\fP" 15n The colormap associated with the window, either a colormap ID or the constant \f(CWNone\fP. It will be \f(CWNone\fP only if this event was in response to an \f(CWXFreeColormap\fP call. .IP "\f(CWnew\fP" 15n \f(CWTrue\fP when the colormap attribute has been changed, or \f(CWFalse\fP when the colormap is installed or uninstalled. .IP "\f(CWstate\fP" 15n Either \f(CWColormapInstalled\fP or \f(CWColormapUninstalled\fP; it indicates whether the colormap is installed or uninstalled. .sp .5 \f(CWXFreeColormap\fR, \f(CWXInstallColormap\fR, and \f(CWXUninstallColormap\fR generate this event for windows that have their colormap attribute set to the colormap that was affected. \f(CWXSetWindowColormap\fP and \f(CWXChangeWindowAttributes\fP can also generate this event. From the information in the structure, you can tell which of these calls generated the event and what the current status of the colormap is. See Chapter 10 in this manual and the ICCCM for an additional description of the conventions regarding colormaps. .sp .5 .IP \s+2\f(HB7.7.3\fR\s-2 6n \s+2\f(HBThe Required Colormap List\fR\s-2 .sp .5 The X protocol specifies that each server can specify a required list of colormaps, which affects what happens when other colormaps are installed or uninstalled. Here is what the protocol specification says about the required list (translated into Xlib terms): .QP At any time, there is a subset of the installed maps, viewed as an ordered list, called the required list. The length of the required list is at most \f(CWmin_maps\fP, where \f(CWmin_maps\fP is a member of the \f(CWDisplay\fP structure. The required list is maintained as follows. When a colormap is an explicit argument to \f(CWXInstallColormap\fP, it is added to the head of the list, and the list is truncated at the tail if necessary to keep the length of the list to at most \f(CWmin_maps\fP. When a colormap is an explicit argument to \f(CWXUninstallColormap\fP and it is in the required list, it is removed from the list. A colormap is not added to the required list when it is installed implicitly by the server, and the server cannot implicitly uninstall a colormap that is in the required list. .sp .5 In less precise words, the \f(CWmin_maps\fP most recently installed maps are guaranteed to be installed. This number will often be one; clients needing multiple colormaps should beware. .IP \s+4\f(HB7.8\fR\s-4 6n \s+4\f(HBStandard Colormaps\fR\s-4 .sp A \fIstandard colormap\fR is one in which the mapping between pixel values and colors is predictable. The purpose of standard colormaps is to encourage sharing of entire colormaps (not just individual cells) between applications that have too demanding color needs to be able to allocate read-only colors out of the default colormaps. .sp .5 X defines a set of properties that contain information describing commonly used colormaps. An application reads these properties by calling \f(CWXGetRGBColormaps\fP (\f(CWXGetStandardColormap\fP prior to R4). This call returns an \f(CWXStandardColormap\fP structure that contains enough information so that the application can calculate the colors in every colormap cell (or a certain range within the colormap). This structure may also include the ID of a colormap matching this description that was created by the window manager or another client. Otherwise, the application then creates a new colormap and uses this information to allocate and set the colors according to the information in the property. .sp .5 But how does the sharing work? After creating this colormap, the application sets the ID of the created colormap into the \f(CWcolormap\fP field of the \f(CWXStandardColormap\fP structure and then calls \f(CWXSetRGBColormaps\fP (\f(CWXSetStandardColormap\fP prior to R4). This resets the property, so that the next time another client calls \f(CWXGetRGBColormaps\fP, the \f(CWcolormap\fP field of the returned structure will actually contain the ID of the appropriate colormap. .sp .5 Therefore, although an application must have the code to create, allocate, and set colors in a standard colormap, in some cases this code will not be executed because some other client will have already done the work. After calling \f(CWXGetRGBColormaps\fP, if the \f(CWcolormap\fP field is zero, the application must create the colormap. Otherwise, the \f(CWcolormap\fP field holds the ID of an appropriate colormap. .sp .5 When an application uses standard colormaps, two (or more) instances of the application can run at the same time without increasing the load on the system caused by creating multiple copies of the same colormap. Applications that do not use standard colormaps will end up creating separate but identical colormaps. The window manager will switch these in and out of the hardware colormap whenever a different instance is in use. Although nothing on the screen will change color because both the colormaps are identical, the server will be performing unnecessary installing and uninstalling, and the extra colormaps will waste server memory. .sp .5 In some cases, the window manager or even the server will create one or more standard colormaps. This does not change how applications work at all. Applications do not care whether it was the window manager, the server, or some other client that created a standard colormap. .sp .5 If your application does not create or use a custom colormap, you can skip this section if pressed for time. .sp .5 Applications can also use the knowledge about a standard colormap to optimize the process of figuring out which existing pixel values correspond to required colors and which colors must be allocated and set from scratch. .sp .5 .IP \s+2\f(HB7.8.1\fR\s-2 6n \s+2\f(HBThe Standard Colormap Properties\fR\s-2 .sp .5 The standard colormap properties contain information about a few commonly used colormaps. However, note that even if an application creates a custom colormap unlike any of these, it should still use the standard property mechanism by creating its own standard colormap structure. .sp .5 Properties were introduced in Section 2.1.4. For a more complete description of properties, see Section 10.1. .sp .5 In the call to \f(CWXGetRGBColormaps\fP (or \f(CWXGetStandardColormap\fP), you specify one of these atoms like \f(CWXA_RGB_BEST_MAP\fP (or, if necessary, one unique to your application). .sp .5 The following list names the atoms and describes the colormap associated with each one: .IP "\f(CWXA_RGB_DEFAULT_MAP\fP" 10n .br This property defines part of the system default colormap. This colormap may be initially completely unallocated, or it may contain a selection of read-only colorcells with the RGB values from the color database and a few unallocated cells for use by applications that need read/write cells. A typical allocation of the \f(CWXA_RGB_DEFAULT_MAP\fP on eight-plane screens is all the colors produced from any combination of six reds, six greens, and six blues. This gives 216 uniformly distributed colors and leaves 40 for other programs or for special purpose colors for text, borders, and so on. A typical allocation for the \f(CWXA_RGB_DEFAULT_MAP\fP on 24-plane screens is 64\ reds, 64 greens, and 64 blues. This gives about one\ million uniformly distributed colors (64 intensities of 4096 different hues) and leaves lots of colorcells available for other purposes. .IP "\f(CWXA_RGB_BEST_MAP\fP" 10n .br This property defines the "best" RGB colormap available on the screen. Of course, this is a subjective evaluation. Many image-processing and 3-D programs need to use all available colormap cells and to distribute as many perceptually distinct colors as possible over those cells. In this case, there may be more green values available than red and more green or red than blue. .sp .5 On an eight-plane \f(CWDirectColor\fP visual, \f(CWXA_RGB_BEST_MAP\fP is usually a 3/3/2 allocation. On a 24-plane \f(CWDirectColor\fP visual, \f(CWXA_RGB_BEST_MAP\fP is usually an 8/8/8 allocation. On other screens, \f(CWXA_RGB_BEST_MAP\fP is purely up to the implementor of the server. .IP "\f(CWXA_RGB_RED_MAP\fP,\ \f(CWXA_RGB_GREEN_MAP\fP,\ \f(CWXA_RGB_BLUE_MAP\fP" 10n .br These properties define all-red, all-green, and all-blue colormaps, respectively. These maps are used by programs that make color-separated images. For example, a user might generate a full color image on an eight-plane screen by rendering an image once with high color resolution in red, once with green, and once with blue and exposing a single frame in a camera with three images. .IP "\f(CWXA_RGB_GRAY_MAP\fP" 10n .br This property describes the "best" gray-scale colormap available on the screen. .sp .5 .IP \s+2\f(HB7.8.2\fR\s-2 6n \s+2\f(HBThe XStandardColormap Structure\fR\s-2 .sp .5 As described above, an application that wants to use a standard colormap must get the structure that contains the specification for the colormap using \f(CWXGetRGBColormaps\fP (\f(CWXGetStandardColormap\fP prior to R4). Some servers and window managers, particularly on high performance workstations, create some or all of the standard colormaps when they initialize. If the desired colormap has already been created, it is returned in the \f(CWcolormap\fP member of the \f(CWXStandardColormap\fP structure shown in Example 10. If the colormap does not yet exist, the \f(CWcolormap\fP member will be zero. In that case, the application can create a colormap and allocate entries to match the specification in the members of \f(CWXStandardColormap\fP, then call \f(CWXSetRGBColormaps\fP (\f(CWXSetStandardColormap\fP prior to R4) to allow other clients to share this colormap. .sp .5 \s-1\f(CW .nf typedef struct _XStandardColormap { Colormap colormap; unsigned long red_max, green_max, blue_max; unsigned long red_mult, green_mult, blue_mult; unsigned long base_pixel; VisualID visualid; /* Added in R4: ICCCM version 1 */ XID killid; /* Added in R4: ICCCM version 1 */ } XStandardColormap; \fR\s0 .fi .sp .5 Example 10: "The XStandardColormap structure" .sp The members of the \f(CWXStandardColormap\fP structure are as follows: .sp .RS .IP \(bu 5 The \f(CWcolormap\fR member is the ID of a colormap created by the \f(CWXCreateColormap\fP function or the default colormap. This ID can be used to install a virtual colormap into the hardware colormap. .IP \(bu 5 The \f(CWred_max\fP, \f(CWgreen_max\fP, and \f(CWblue_max\fP fields give the maximum red, green, and blue values, respectively. A typical allocation that provides .Su 6 3 =\ 216 read-only, shareable colors in a \f(CWPseudoColor\fP colormap on a standard eight-plane workstation is \f(CWred_max\fP\ =\ 5, \f(CWgreen_max\fP\ =\ 5, and \f(CWblue_max\fP\ =\ 5. This leaves 40 cells available for special colors and private, nonshareable purposes. .\"On the \f(CWStellarStation\fP, On a 24-plane workstation, there would be eight bits available for each color in a \f(CWTrueColor\fP visual, which would allow 256 shades of each primary color. In this case, \f(CWred_max\fP\ =\ 255, \f(CWgreen_max\fP\ =\ 255, and \f(CWblue_max\fP\ =\ 255. This map would include .Su 256 3 =\ 16.38 million total colors. .IP \(bu 5 The \f(CWred_mult\fP, \f(CWgreen_mult\fP, and \f(CWblue_mult\fP fields scale each pixel subfield into the proper range in the 16-bit RGB value in the colorcell with the range 0 to 65535. The red pixel subfield is moved \f(CWred_mult\fP bits toward the most significant bit of the pixel value. .sp .5 For a 3/3/2 \f(CWDirectColor\fP allocation (eight reds, eight greens, four blues), \f(CWred_mult\fP might be 32, \f(CWgreen_mult\fP might be 4, and \f(CWblue_mult\fP might be 1 (as shown in Figure 5). These effectively move the red value into the most significant bits of the RGB value in the colorcell, the green into the middle, and the blue into the least significant bits. This arrangement is arbitrary but useful. For a six-colors-each allocation, which must be \f(CWPseudoColor\fP since the planes cannot be evenly allocated to separate primaries, \f(CWred_mult\fP might be 36, \f(CWgreen_mult\fP might be 6, and \f(CWblue_mult\fP might be\ 1. .IP \(bu 5 The \f(CWbase_pixel\fP field gives the base value that is added to the pixel value calculated from the RGB values and scale factors. Usually the \f(CWbase_pixel\fP is obtained from a call to the \f(CWXAllocColorPlanes\fP function. .IP \(bu 5 The \f(CWvisualid\fP field is the ID of a server resource associated with each visual, of type \f(CWVisualID\fP. You will need this ID only if you intend to use standard colormaps. This field was added in R4 because only with this information can standard colormaps be used with other than the default visual. Prior to R4, standard colormaps were not in wide use, partly because they could only be used with the default visual. .IP \(bu 5 The \f(CWkillid\fP field returns a number that is used if the application needs to free the colormap for some reason. If \f(CWkillid\fP is greater than one, then the resources should be freed by calling \f(CWXKillClient\fP with the \f(CWkillid\fP field as the argument. If \f(CWkillid\fP is one, then the resources should be freed by calling \f(CWXFreeColormap\fP with the \f(CWcolormap\fP field as the argument. If \f(CWkillid\fP is zero, then no attempt should be made to free the resources. .RE .sp 2 Only the \f(CWcolormap\fP, \f(CWred_max\fP, \f(CWred_mult\fP, and \f(CWbase_pixel\fP fields of the \f(CWXStandardColormap\fP structure are use for \f(CWGrayScale\fP colormaps. .sp .5 .IP \s+2\f(HB7.8.3\fR\s-2 6n \s+2\f(HBThe 3/3/2 Standard Colormap\fR\s-2 .sp .5 Now let's look at a typical standard colormap. The following example describes the 3/3/2 \f(CWDirectColor\fP standard colormap used on eight-plane screens. Three planes are used for red, three planes for green, and two planes for blue. This 3/3/2 allocation allows values in the range of: .sp .5 \s-1\f(CW .nf red 0-7 \fR\s+1thus\s-1\fP red_max = 7 green 0-7 green_max = 7 blue 0-3 blue_max = 3 \fR\s0 .fi .sp .5 To obtain the pixel value, these RGB values must be shifted to their corresponding planes. If the red value is contained in the three most significant planes or bits, the green values in the three next most significant planes or bits, and the blue value in the two least significant planes or bits, then the pixel can be constructed as shown in Figure 5. .sp Note: Figure 5 "Shifting pixel subfields into pixel value" here. .sp In a \f(CWDirectColor\fP system like this, the multiples are equal to .Su + 2 \fIn\fP , where \fIn\fR is their lowest plane or bit position. If the red, green, and blue were stored in a different order, the multiples would not be 32, 4, 1 but would still be calculated from the above description and formula. The 3/3/2 standard colormap allocation is fairly standard. .sp .5 .IP \s+2\f(HB7.8.4\fR\s-2 6n \s+2\f(HBCreating and Using a Standard Colormap\fR\s-2 .sp .5 Two members were added to the \f(CWXStandardColormap\fP structure in Release 4 to comply with the ICCCM (interclient communication conventions, described in Chapter 10). Because of this, there are two different sets of routines that manage standard colormaps, one for use with R3 (and earlier) and the other for use with R4 (and later). The R3 routines will also work under R4, but an application using them will not comply with current conventions. The R3 routines are \f(CWXGetStandardColormap\fP and \f(CWXSetStandardColormap\fP, and the R4 routines are \f(CWXGetRGBColormaps\fP and \f(CWXSetRGBColormaps\fP. The reason for the plural form of the R4 routine \f(CWXGetRGBColormaps\fP is that it returns a list of colormaps; it also has a \f(CIcount\fP argument not present in the R3 routine. According to the ICCCM, only queries of the \f(CWXA_RGB_DEFAULT_MAP\fP standard colormap can return more than one structure. .sp .5 Example 11: gets information about the \f(CWXA_RGB_BEST_MAP\fP standard colormap, creates it if no other client already has, calculates pixel values from it, and sets the colormap window attribute of the window. Note that under R3, the created colormap can be used only with windows created using the default visual, because the standard colormap information under R3 does not include a visual. This example gives up and falls back on read-only colorcell allocation if the standard colormap property is not defined by the server or if creating a colormap returns the default colormap (which happens on systems with an immutable hardware colormap). .Nd 10 .sp .5 \s-1\f(CW .nf . . . #define USE_DEFAULT_COLORMAP 1 #define USE_STANDARD_COLORMAP 0 void main(argc, argv) int argc; char **argv; { XStandardColormap best_map_info; XColor *exact_defs; XSetWindowAttributes attrib; unsigned long attribmask; int i, j, k, l; int ncells; XVisualInfo *vlist, vinfo_template, *v; int num_vis; int count; Visual *visual; int strategy = USE_STANDARD_COLORMAP; . . . /* Open display */ visual = DefaultVisual(display, screen_num); #ifdef X11R3 if (XGetStandardColormap(display, RootWindow(display, screen_num), &best_map_info, XA_RGB_BEST_MAP) == 0) { #else /* R4 or later */ if (XGetRGBColormaps(display, RootWindow(display, screen_num), &best_map_info, &count, XA_RGB_BEST_MAP) == 0) { #endif /* X11R3 */ printf("%s: RGB_BEST_MAP colormap property not set.\en", argv[0]); /* Give up standard colormaps; use one of the * basic color strategies */ get_colors(); strategy = USE_DEFAULT_COLORMAP; } else if (best_map_info.colormap) { /* Someone else created the map we need; make sure * it's valid, then we'll use it below */ if (best_map_info.red_max == 0) { printf("%s: RGB_BEST_MAP colormap property is set\en", argv[0]); printf("but is missing data.\en"); strategy = USE_DEFAULT_COLORMAP; } attrib.colormap = best_map_info.colormap; } else if (best_map_info.visualid == 0) { printf("%s: Standard colormap property is set\en", argv[0]); printf("but is missing data."); /* Some systems define the properties but don't * place any data in them; this is a server bug, * but we'll check for it anyway */ /* Fall back on a basic color strategy */ strategy = USE_DEFAULT_COLORMAP; } else { /* Got information, but the described colormap * has not been created yet; create it and * allocate all cells read/write */ /* XCreateColormap requires a visual argument * (pointer to a Visual structure); however, the * XStandardColormap structure returns a VisualID, * which might not be the default visual; * Converting between these two is painful */ vlist = XGetVisualInfo(display, VisualNoMask, &vinfo_template, &num_vis); for (v = vlist; v < vlist + num_vis; v++) { if (v->visualid == best_map_info.visualid) { visual = v->visual; break; } } best_map_info.colormap = XCreateColormap(display, RootWindow(display, screen_num), visual, AllocAll); if (best_map_info.colormap == DefaultColormap(display, screen_num)) { printf("%s: hardware colormap is immutable:\en", argv[0]); printf("cannot create new colormap.\en"); } attrib.colormap = best_map_info.colormap; ncells = best_map_info.base_pixel + ((best_map_info.red_max + 1) * (best_map_info.green_max + 1) * (best_map_info.blue_max + 1)); exact_defs = (XColor *) calloc(sizeof(XColor), ncells); /* Permute the levels of red, green, and blue */ l = best_map_info.base_pixel; for (i = 0; i < best_map_info.blue_max; i++) { exact_defs[l].blue = 65536 * i / best_map_info.blue_max; for (j = 0; j < best_map_info.green_max; j++) { exact_defs[l].green = 65536 * j / best_map_info.green_max; for (k = 0; k < best_map_info.red_max; k++) { exact_defs[l].red = 65536 * k / best_map_info.red_max; l++; } } } XStoreColors (display, best_map_info.colormap, exact_defs, ncells); /* If to be used in a window not created with the * default visual, must create the window first and * use instead of RootWindow in this call; here we * assume the default visual */ #ifdef X11R3 XSetStandardColormap(display, RootWindow(display, screen_num), &best_map_info, XA_RGB_BEST_MAP); #else /* R4 or later */ XSetRGBColormaps(display, RootWindow(display, screen_num), count, &best_map_info, XA_RGB_BEST_MAP); #endif /* X11R3 */ } if (strategy == USE_STANDARD_COLORMAP) { /* We must not have called get_colors above, * must be using standard colormaps strategy */ /* Note that we act like we have already allocated pixel * pixel values, even though actually another client did */ background_pixel = best_map_info.base_pixel + (best_map_info.red_max * best_map_info.red_mult) + (best_map_info.green_max * best_map_info.green_mult) + (best_map_info.blue_max * best_map_info.blue_mult); attribmask = CWBackPixel | CWColormap; foreground_pixel = (best_map_info.green_max * best_map_info.green_mult / 2) + best_map_info.base_pixel; border_pixel = (best_map_info.blue_max * best_map_info.blue_mult / 2) + best_map_info.base_pixel; } /* Create opaque window */ win = XCreateWindow(display, RootWindow(display,screen_num), x, y, width, height, borderwidth, DefaultDepth(display, screen_num), InputOutput, visual, attribmask, &attrib); . . . } \fR\s0 .fi .sp .5 Example 11: "Code to create and use XA_RGB_BEST_MAP" .sp .hw XGetRGB-Colormaps This code begins by reading the \f(CWXA_RGB_BEST_MAP\fP property using the \f(CWXGetRGBColormaps\fP or \f(CWXGetStandardColormap\fP call. (The name \f(CWXGetRGBColormaps\fP suggests that the function returns a description of multiple colormaps\(embut this is true only for \f(CWXA_RGB_DEFAULT_MAP\fP. Therefore, the R3 and R4 functions are truly equivalent as used here.) If one of these calls succeeds, the property is defined and its contents have been placed in the \f(CWbest_map_info\fP structure. Since any other, perhaps buggy, client might have set this property (like your own application while you are debugging it), it is a good idea not to trust its contents any more than necessary. (Properties set on the root window remain defined even after the client that set them has exited.) The code checks to make sure that the fields contain reasonable values before using them. .sp .5 If the \f(CWcolormap\fP field of \f(CWbest_map_info\fP is nonzero, it should be the ID of a standard colormap that another client has created. Your application can immediately proceed to use the pixel values in this colormap as though your application had already allocated them read-only, even though in reality some other client allocated them read/write. .sp .5 On the other hand, if the \f(CWcolormap\fP field is zero, your application needs to create, allocate, and set the values of the standard colormap itself. You allocate the cells read/write, because this allows you to explicitly set the RGB values of each pixel value. Even though you allocate the cells read/write, you should use them as if they were read-only, so that other applications can share them after you reset the \f(CWXA_RGB_BEST_MAP\fP property to include the new colormap ID. As this suggests, a read/write cell, even though described earlier as being private and changeable by that one client, can be public if all the applications agree not to change its RGB values. .sp .5 The algorithm used to store RGB values into the cells in the colormap is somewhat arbitrary. Conventions for it will probably be adopted by the X Consortium when there is more interest in standard colormaps. Any algorithm is good enough to allow two instances of the same application to share a colormap. But for two different applications to share the colormap, each must know exactly what RGB values the other would place in the colormap if the other were run before the colormap was created. .sp .5 The \f(CWXGetVisualInfo\fP call is described in Section 7.5.2. .sp .5 If you pass \f(CWAllocAll\fP to \f(CWXCreateColormap\fP, you do not need to make an \f(CWXAllocColorCells\fP call to allocate all the cells read/write. However, you can use \f(CWAllocAll\fP only if you intend the entire colormap to be read-only to all clients. Some clients want a few cells preserved to be rewriteable for dynamically changing colors. If yours is that way, you must use \f(CWAllocNone\fP and then call \f(CWXAllocColorCells\fP once to create the standard portion of the colormap and again to allocate the cells your application will treat as private. .sp .5 Once the colormap window attribute of a window is set, the window manager will take care of installing the colormap. When there is only one hardware colormap, the window manager usually installs an application's colormap when that application contains the pointer (for real-estate type window managers) or is given the keyboard focus (for click-to-type style window managers). .sp .5 When a window manager creates a standard colormap, it can use a slightly different technique to make sure that the standard colormap remains defined even after the window manager exits. Assuming that it has already checked to see whether some other client has created a standard colormap and none has, it performs the following sequence of steps: .sp .RS .IP \(bu 5 Create a new connection to the same server. .IP \(bu 5 Determine the color capabilities of the screen. Choose a visual. .IP \(bu 5 Create a colormap (not required for \f(CWXA_RGB_DEFAULT_MAP\fP). .IP \(bu 5 Call \f(CWXAllocColorPlanes\fP or \f(CWXAllocColorCells\fP to allocate cells in the colormap (if did not use \f(CWAllocAll\fP flag when creating the colormap). .IP \(bu 5 Call \f(CWXStoreColors\fP to store appropriate color values in the colormap. .IP \(bu 5 Fill in the descriptive fields in the \f(CWXStandardColormap\fP structure, including the ID of the created colormap. .IP \(bu 5 Call \f(CWXSetRGBColormaps\fP or \f(CWXSetStandardColormap\fP to set the property on the root window. Under R4, the \f(CWkillid\fP field should be set to the colormap ID. .Nd 4 .IP \(bu 5 Use \f(CWXSetCloseDownMode\fR to make the resource permanent. .IP \(bu 5 Close the new connection to the server. .RE .sp 2 .IP \s+2\f(HB7.8.5\fR\s-2 6n \s+2\f(HBRGB-to-Pixel Conversion\fR\s-2 .sp .5 The standard colormaps such as \f(CWXA_RGB_BEST_MAP\fP are useful when you want to calculate pixel values from RGB values. .sp .5 Consider a 3-D display program that draws a smoothly shaded sphere. At each pixel in the image of the sphere, the program computes the intensity and color of light reflected to the viewer. The result of each computation is a triple of red, green, and blue coefficients in the range 0.0 to 1.0. To draw the sphere, the program needs a colormap that provides a large range of uniformly distributed colors. The colormap must be arranged so that the program can convert its RGB triples into pixel values very quickly, because drawing the entire sphere will require many such conversions. An example of one such calculation is shown in Example 12. Example 10 demonstrated how to do this for integral RGB values. .sp .5 \s-1\f(CW .nf XStandardColormap best_map_info; float red, green, blue; unsigned long pixelvalue; pixelvalue = best_map_info.base_pixel + ((unsigned long)(0.5 + (red * best_map_info.red_max)) * best_map_info.red_mult) + ((unsigned long)(0.5 + (green * best_map_info.green_max)) * best_map_info.green_mult) + ((unsigned long)(0.5 + (blue * best_map_info.blue_max)) * best_map_info.blue_mult); \fR\s0 .fi .sp .5 Example 12: "Calculating pixel values from floating point RGB values" .sp For gray scale colormaps, only the \f(CWcolormap\fP, \f(CWred_max\fP, \f(CWred_mult\fP, and \f(CWbase_pixel\fP fields of the \f(CWXStandardColormap\fP structure are defined. The other fields are ignored. Pixel values for a \f(CWStaticGray\fP or \f(CWGrayScale\fP visual must be in the range: .sp .5 \s-1\f(CW .nf base_pixel <= pixel_value < (red_max * red_mult) + base_pixel \fR\s0 .fi .sp .5 To compute a gray pixel value, use the following expression: .sp .5 \s-1\f(CW .nf pixel_value = gray * red_mult + base_pixel; \fR\s0 .fi .sp .5 where: .in +5n .TS linesize(2), tab(@); lfCW l l. gray@\=@the gray value you desire (0 to \f(CWred_max\fP) red_mult@\=@value from \f(CWXStandardColormap\fP structure base_pixel@\=@value from \f(CWXStandardColormap\fP structure .TE .in -5n .IP \s+4\f(HB7.9\fR\s-4 6n \s+4\f(HBMiscellaneous Color-handling Functions\fR\s-4 .sp The following miscellaneous functions provide additional ways to use the color database, to find out the RGB values in a colormap cell, and to free cells that are no longer needed: .IP "\f(CWXLookupColor\fP" 18n Looks up a string color name in the color database and returns separate color structures containing the exact RGB values specified in the database for that name and the closest RGB values available on the hardware. This function does not look at any cells in the colormap, even though it has a \f(CIcolormap\fP argument! This argument specifies which screen the color should be looked up on. The difference between \f(CWXLookupColor\fP and \f(CWXParseColor\fP is that \f(CWXParseColor\fP accepts the hexadecimal color specification (which \f(CWXLookupColor\fP does not), while \f(CWXLookupColor\fP returns the closest colors available on the hardware (which \f(CWXParseColor\fP does not). \f(CWXLookupColor\fP might be useful for making sure that user-specified colors are contrasting. .Nd 3 .IP "\f(CWXQueryColor\fP" Fills an \f(CWXColor\fP structure with the RGB values corresponding to the colormap cell indicated by a pixel value. Also sets the \f(CWflags\fP member of the structure to (\f(CWDoRed\ |\ DoGreen\ |\ DoBlue\fR). .IP "\f(CWXQueryColors\fR" Fills multiple \f(CWXColor\fP structures with the RGB values and flags corresponding to the colormap cells indicated by a pixel values. Also sets each \f(CWflags\fP member to (\f(CWDoRed\ |\ DoGreen\ | DoBlue\fR). .IP "\f(CWXFreeColors\fR" 18n Frees the colormap cells associated with the given pixel values and/or frees the given planes. Since all the colorcells an application allocates are freed when the application exits, this routine is needed only when an application is finished with cells before it exits. Freeing a read/write colorcell makes that cell available to other applications. Freeing a read-only cell may make the cell unallocated, but only if no other application is sharing that cell.