Using colors to paint the rainbow
Up until now, all our painting operation were done using black and white. We will (finally) see now how to draw using colors.
Color maps
In the beginning, there were not enough colors. Screen controllers could only support a limited number of colors simultaneously (initially 2, then 4, 16 and 256). Because of this, an application could not just ask to draw in a "light purple-red" color, and expect that color to be available. Each application allocated the colors it needed, and when all the color entries (4, 16, 256 colors) were in use, the next color allocation would fail.
Thus, the notion of "a color map" was introduced. A color map is a table whose size is the same as the number of simultaneous colors a given screen controller. Each entry contained the RGB (Red, Green and Blue) values of a different color (all colors can be drawn using some combination of red, green and blue). When an application wants to draw on the screen, it does not specify which color to use. Rather, it specifies which color entry of some color map to be used during this drawing. Change the value in this color map entry and the drawing will use a different color.
In order to be able to draw using colors that got something to do with what the programmer intended, color map allocation functions are supplied. You could ask to allocate entry for a color with a set of RGB values. If one already existed, you would get its index in the table. If none existed, and the table was not full, a new cell would be allocated to contain the given RGB values, and its index returned. If the table was full, the procedure would fail. You could then ask to get a color map entry with a color that is closest to the one you were asking for. This would mean that the actual drawing on the screen would be done using colors similar to what you wanted, but not the same.
On today's more modern screens where one runs an X server with support for 16 million colors, this limitation looks a little silly, but remember that there are still older computers with older graphics cards out there. Using color map, support for these screen becomes transparent to you. On a display supporting 16 million colors, any color entry allocation request would succeed. On a display supporting a limited number of colors, some color allocation requests would return similar colors. It won't look as good, but your application would still work.
Allocating and freeing Color Maps
When you draw using XCB, you can choose to use the standard color map of the screen your window is displayed on, or you can allocate a new color map and apply it to a window. In the latter case, each time the mouse moves onto your window, the screen color map will be replaced by your window's color map, and you'll see all the other windows on screen change their colors into something quite bizzare. In fact, this is the effect you get with X applications that use the "-install" command line option.
In XCB, a color map is (as often in X) an Id:
typedef uint32_t xcb_colormap_t;
typedef uint32_t xcb_colormap_t;
In order to access the screen's default color map, you just have to retrieve the
default_colormap
field of thexcb_screen_t
structure (see Section Checking basic information about a connection):#include <stdio.h> #include <xcb/xcb.h> int main () { xcb_connection_t *c; xcb_screen_t *screen; xcb_colormap_t colormap; /* Open the connection to the X server and get the first screen */ c = xcb_connect (NULL, NULL); screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data; colormap = screen->default_colormap; return 0; }
#include <stdio.h> #include <xcb/xcb.h> int main () { xcb_connection_t *c; xcb_screen_t *screen; xcb_colormap_t colormap; /* Open the connection to the X server and get the first screen */ c = xcb_connect (NULL, NULL); screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data; colormap = screen->default_colormap; return 0; }
This will return the color map used by default on the first screen (again, remember that an X server may support several different screens, each of which might have its own resources).
The other option, that of allocating a new colormap, works as follows. We first ask the X server to give an Id to our color map, with this function:
xcb_colormap_t xcb_generate_id (xcb_connection_t *c);
xcb_colormap_t xcb_generate_id (xcb_connection_t *c);
Then, we create the color map with
xcb_void_cookie_t xcb_create_colormap (xcb_connection_t *c, /* Pointer to the xcb_connection_t structure */ uint8_t alloc, /* Colormap entries to be allocated (AllocNone or AllocAll) */ xcb_colormap_t mid, /* Id of the color map */ xcb_window_t window, /* Window on whose screen the colormap will be created */ xcb_visualid_t visual); /* Id of the visual supported by the screen */
xcb_void_cookie_t xcb_create_colormap (xcb_connection_t *c, /* Pointer to the xcb_connection_t structure */ uint8_t alloc, /* Colormap entries to be allocated (AllocNone or AllocAll) */ xcb_colormap_t mid, /* Id of the color map */ xcb_window_t window, /* Window on whose screen the colormap will be created */ xcb_visualid_t visual); /* Id of the visual supported by the screen */
Here is an example of creation of a new color map:
#include <xcb/xcb.h> int main () { xcb_connection_t *c; xcb_screen_t *screen; xcb_window_t win; xcb_colormap_t cmap /* Open the connection to the X server and get the first screen */ c = xcb_connect (NULL, NULL); screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data; /* We create the window win here*/ cmap = xcb_generate_id (c); xcb_create_colormap (c, XCB_COLORMAP_ALLOC_NONE, cmap, win, screen->root_visual); return 0; }
#include <xcb/xcb.h> int main () { xcb_connection_t *c; xcb_screen_t *screen; xcb_window_t win; xcb_colormap_t cmap /* Open the connection to the X server and get the first screen */ c = xcb_connect (NULL, NULL); screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data; /* We create the window win here*/ cmap = xcb_generate_id (c); xcb_create_colormap (c, XCB_COLORMAP_ALLOC_NONE, cmap, win, screen->root_visual); return 0; }
Note that the window parameter is only used to allow the X server to create the color map for the given screen. We can then use this color map for any window drawn on the same screen.
To free a color map, it suffices to use this function:
xcb_void_cookie_t xcb_free_colormap (xcb_connection_t *c, /* The connection */ xcb_colormap_t cmap); /* The color map */
xcb_void_cookie_t xcb_free_colormap (xcb_connection_t *c, /* The connection */ xcb_colormap_t cmap); /* The color map */
Comparison Xlib/XCB- XCreateColormap ()
- xcb_generate_id ()
- xcb_create_colormap ()
- XFreeColormap ()
- xcb_free_colormap ()
Allocating and freeing a color entry
Once we got access to some color map, we can start allocating colors. The informations related to a color are stored in the following structure:
typedef struct { uint8_t response_type; uint8_t pad0; uint16_t sequence; uint32_t length; uint16_t red; /* The red component */ uint16_t green; /* The green component */ uint16_t blue; /* The blue component */ uint8_t pad1[2]; uint32_t pixel; /* The entry in the color map, supplied by the X server */ } xcb_alloc_color_reply_t;
typedef struct { uint8_t response_type; uint8_t pad0; uint16_t sequence; uint32_t length; uint16_t red; /* The red component */ uint16_t green; /* The green component */ uint16_t blue; /* The blue component */ uint8_t pad1[2]; uint32_t pixel; /* The entry in the color map, supplied by the X server */ } xcb_alloc_color_reply_t;
XCB supplies these two functions to fill it:
xcb_alloc_color_cookie_t xcb_alloc_color (xcb_connection_t *c, xcb_colormap_t cmap, uint16_t red, uint16_t green, uint16_t blue); xcb_alloc_color_reply_t *xcb_alloc_color_reply (xcb_connection_t *c, xcb_alloc_color_cookie_t cookie, xcb_generic_error_t **e);
xcb_alloc_color_cookie_t xcb_alloc_color (xcb_connection_t *c, xcb_colormap_t cmap, uint16_t red, uint16_t green, uint16_t blue); xcb_alloc_color_reply_t *xcb_alloc_color_reply (xcb_connection_t *c, xcb_alloc_color_cookie_t cookie, xcb_generic_error_t **e);
The fuction
xcb_alloc_color()
takes the 3 RGB components as parameters (red, green and blue). Here is an example of using these functions:#include <malloc.h> #include <xcb/xcb.h> int main () { xcb_connection_t *c; xcb_screen_t *screen; xcb_window_t win; xcb_colormap_t cmap; xcb_alloc_color_reply_t *rep; /* Open the connection to the X server and get the first screen */ c = xcb_connect (NULL, NULL); screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data; /* We create the window win here*/ cmap = xcb_generate_id (c); xcb_create_colormap (c, XCB_COLORMAP_ALLOC_NONE, cmap, win, screen->root_visual); rep = xcb_alloc_color_reply (c, xcb_alloc_color (c, cmap, 65535, 0, 0), NULL); if (!rep) return 0; /* Do something with r->pixel or the components */ free (rep); return 0; }
#include <malloc.h> #include <xcb/xcb.h> int main () { xcb_connection_t *c; xcb_screen_t *screen; xcb_window_t win; xcb_colormap_t cmap; xcb_alloc_color_reply_t *rep; /* Open the connection to the X server and get the first screen */ c = xcb_connect (NULL, NULL); screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data; /* We create the window win here*/ cmap = xcb_generate_id (c); xcb_create_colormap (c, XCB_COLORMAP_ALLOC_NONE, cmap, win, screen->root_visual); rep = xcb_alloc_color_reply (c, xcb_alloc_color (c, cmap, 65535, 0, 0), NULL); if (!rep) return 0; /* Do something with r->pixel or the components */ free (rep); return 0; }
As
xcb_alloc_color_reply()
allocates memory, you have to freerep
.TODO: Talk about freeing colors.