Dealing with colour is one of the most difficult concepts to grasp in X/Motif. In this Chapter we will look at a couple of the basic methods for dealing with colour in Motif. We have already seen some colour examples in action (The list.c in Section 12.4 for example).
Readers should note:
The X Window system was designed to run on many different computer systems over a network in a device independent manner. However, each system may implement colour in a different way. Some graphics workstations may include specialised graphics hardware, whilst others may have minimal colour support. X tries to deal with this in a generic way, in fact it can (in theory, at least) support devices that range from black/white, monochrome (grey scale) through to full 24-bit colour. Note that the quality of the intended GUI display cannot be guaranteed on minimal configurations, but at least a close resemblance to the GUI will be rendered by X.
Colour in X is based on the RGB Model : where the colour is determined by red, green and blue values. This is just like a TV set or computer monitor where an individual dot on the screen(a picture element or pixel ) has its colour controlled by RGB intensities:
We have already remarked that colour displays, available to X, can vary quite a lot although they generally fall into a few classes:
A colourmap consists of cells each of which contains 8 bit red, green blue values. The maximum length of a colourmap is usually 256 entries that correspond to a complete 8-bit colour display.
A pixel value in an image or on the screen basically provides an index to the colourmap which says how to render the appropriate colour. Figure 18.1 shows an example where a pixel value of 3 corresponds to a green entry in the colourmap at index 3.
Fig. 18.1 Colourmaps and pixels
In order to be able to support the various means of displaying colour, X allows the setting of colour in a variety of ways. Recall that the Xlib part of X performs all colour operation.
At the heart of all colour operations is the XColor structure, which uses 3 basic elements:
There are 2 basic methods that can be used to allocate colour in X.
X provides a database of colours. We simply refer to these by name and X will find the appropriate RGB values stored in the database for the given entry. We have in fact been using this style of colour programming in previous examples (Section 12.4).
The colours stored in the database are comprehensive ranging form red, green, grey, black .... to more exotic colours like light salmon and tomato.
The function we typically use to perform this is:
XAllocNamedColor(display, cmap, colour_name, &xcolour, &spare);
This assigns the appropriate pixel value in the xcolour (XColour data type) structure for a given colour_name (String) naming a colour stored in a specified Colourmap, cmap.
We would normally use the default colormap which is obtained for a given widget, w, via:
cmap = DefaultColormapOfScreen(w);
If we wish to have greater control over colour, then we may decide to program the RGB values directly. Basically we do this by setting the RGB values of a given XColour structure directly, and then set this as an entry in the colourmap.
The function:
XAllocColor(Display, Colormap, XColour);
will set the Colormap RGB entries for a given index from the pixel, red, green and blue values encoded in the XColor structure.
It is good practice to free the colormap entry before assigning new values. The following Xlib function is typically used:
XFreeColors(Display, Colormap, unsigned long pixel_index, int num_pixels, unsigned long planes_to_be_freed);
Let us look at an example program colour.c that illustrates the points raised in the previous sections.
The colour.c performs the following tasks:
Fig. 18.2 Output of colour.c
The colour.c program listing is as follows:
#include <Xm/Xm.h> #include <Xm/Form.h> #include <Xm/RowColumn.h> #include <Xm/Scale.h> #include <Xm/Label.h> /* prototype colour_change function */ void change_colour(Widget , int , XmScaleCallbackStruct *); /* Globals */ Widget label; /* this widget gets coloured by slider values for RGB */ XColor color; /* the current colour of the label */ main(int argc, char *argv[]) { Widget top_wid, form, rowcol, scale; XtAppContext app; XmString label_str, red, blue, green; top_wid = XtVaAppInitialize(&app, "Colour", NULL, 0, &argc, argv, NULL, NULL); if (DefaultDepthOfScreen(XtScreen(top_wid)) < 2) { puts("You must be using a color screen."); exit(1); } /* Set colour flags field for full RGB display */ color.flags = DoRed|DoGreen|DoBlue; /* initialize first colour */ XAllocColor(XtDisplay(top_wid), DefaultColormapOfScreen(XtScreen(top_wid)), &color); /* build form to contain label and rowcolumn */ form = XtVaCreateManagedWidget("form", xmFormWidgetClass, top_wid, NULL); label_str = XmStringCreateLocalized("Colour Me"); label = XtVaCreateManagedWidget("Label", xmLabelWidgetClass, form, XmNlabelString, label_str, XmNheight, 300, XmNwidth, 300, XmNbackground, color.pixel, /* Form Attachment resources */ XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); XmStringFree(label_str); /* Build rowcolumn to contain 3 scales for RGB input */ rowcol = XtVaCreateWidget("rowcol", xmRowColumnWidgetClass, form, XmNorientation, XmVERTICAL, /* Form Attachment resources */ XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); red = XmStringCreateLocalized("Red"); /* reuses scale widget variable */ scale = XtVaCreateManagedWidget("Red", xmScaleWidgetClass, rowcol, XmNshowValue, True, XmNorientation, XmHORIZONTAL, XmNmaximum, 255, XmNtitleString, red, NULL); XmStringFree(red); /* Trap scale valuechange and drags for callbacks */ XtAddCallback(scale, XmNdragCallback, change_colour, DoRed); XtAddCallback(scale, XmNvalueChangedCallback, change_colour, DoRed); green = XmStringCreateLocalized("Green"); scale = XtVaCreateManagedWidget("Green", xmScaleWidgetClass, rowcol, XmNshowValue, True, XmNorientation, XmHORIZONTAL, XmNmaximum, 255, XmNtitleString, green, NULL); XmStringFree(green); XtAddCallback(scale, XmNdragCallback, change_colour, DoGreen); XtAddCallback(scale, XmNvalueChangedCallback, change_colour, DoGreen); blue = XmStringCreateLocalized("Blue"); scale = XtVaCreateManagedWidget("Blue", xmScaleWidgetClass, rowcol, XmNshowValue, True, XmNorientation, XmHORIZONTAL, XmNmaximum, 255, XmNtitleString, blue, NULL); XmStringFree(blue); XtAddCallback(scale, XmNdragCallback, change_colour, DoBlue); XtAddCallback(scale, XmNvalueChangedCallback, change_colour, DoBlue); XtManageChild(rowcol); XtRealizeWidget(top_wid); XtAppMainLoop(app); } void change_colour(Widget scale_w, int rgb, XmScaleCallbackStruct *cbs) { Colormap cmap = DefaultColormapOfScreen(XtScreen(scale_w)); /* rgb variable tells us which RGB scale was selected */ switch (rgb) { case DoRed : color.red = (cbs->value << 8); break; case DoGreen : color.green = (cbs->value << 8); break; case DoBlue : color.blue = (cbs->value << 8); } /* reuse the same color index 1 */ XFreeColors(XtDisplay(scale_w), cmap, &color.pixel, 1, 0); if (!XAllocColor(XtDisplay(scale_w), cmap, &color)) puts("Couldn't XallocColor!"), exit(1); XtVaSetValues(label, XmNbackground, color.pixel, NULL); }
NEED SOME EXERCISE