Subsections

Colour

   

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 11.4 for example).

Readers should note:

Why is colour so complex?

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 Basics

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:

Displaying Colour

We have already remarked that colour displays, available to X, can vary quite a lot although they generally fall into a few classes:

Black/White
-- where 1 bit per pixel is used. The bits are sometimes called planes.
8-bit displays
-- True colour displays tend to be expensive as they need a lot of memory and involve more complex programming to handle the large amounts of data present. 8-bit displays are the most common. These are capable of only supporting 256 colours at any one time. However, the 256 colours can be chosen from the whole palette of the true colour range. Colourmaps or colour look up tables are used to enable this (see Below).
True Colour or Full Colour
-- 24 bits per pixel (8 bits each for RGB band) are used to display around 16.5 million possible colours at the same time.

Colourmaps

 

A colourmap consists of cells each of which contains 8 bit red, green and 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 17.1 shows an example where a pixel value of 3 corresponds to a green entry in the colourmap at index 3.

 

Fig. 17.1 Colourmaps and pixels

Colour in X/Motif

  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:

pixel
  -- the colour index to the colourmap. It is an unsigned long data type.
red, green, blue
  -- Direct coding of RGB values. The values of theses can range from 0 (off) - 65535 (full) as they are defined as unsigned shorts.
flag
-- allow specification of which RGB values are used. Or together DoRed, DoGreen, DoBlue as required.

There are 2 basic methods that can be used to allocate colour in X.

Colour Database

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 11.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);

Explicit Colour Coding

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);
 

The Colour.c program

 

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. 17.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);
}


Dave Marshall
1/5/1999