Colour in X

Introduction

  • X applications need to be careful in their use of colour, most colour workstations use a colour map, that is part of the display hardware and not part of the windows on the screen
  • all the windows on the screen must share the same hardware colour map
  • there are two ways in which this can be done
    1. Each application has its own colour map, when the user moves the mouse into one of the application’s windows its colour map is used. This gives each application a full colour map, but the colours on the screen change as the user moves the mouse from one application to another
    2. Applications share colour maps. Most applications only need a few colours, so they can share a colour map. If they use the same colours as another application they can share colour map entries, otherwise they get their own entries. The screen looks better since there is no colour flashing between applications, but each application has a smaller range of colours
  • X supports both of these approaches, but we will only use the second approach since it is the preferred approach
  • the XColor structure is used to represent colours in X, this structure is defined in the following way:
        typedef struct {
    	 unsigned long       pixel;
    	 unsigned short      red, green, blue;
    	 char           flags;
    	 char           pad;
        } XColor;
    
  • the pixel field is the colour map index for the colour and red, green, and blue are the three components of the colour, these values range from 0 to 65535, with 65535 giving the maximum amount of colour
  • the value of the pixel field is used in other routines to specify the colour, the red, green and blue fields are only used for defining the entries in colour maps
  • since we won’t be creating new colour maps we need some way of determining the colour map that is currently used by the application, this can be done using DefaultColormap:
        Colormap DefaultColourmap(display, screen_number)
        Display   *display;
        int  screen_number;
    
  • so given a widget, w, we can get its colour map in the following way:
        Colormap cmap;
    
        cmap = DefaultColormap(XtDisplay(w),
    	 DefaultScreen(XtDisplay(w)));
    
  • to allocate a colour in the colour map the XAllocColor procedure is used, which has the following declaration:
        int XAllocColor(display, colormap, color)
        Display        *display;
        Colormap  colormap;
        Xcolor         *color;
    
  • before calling XAllocColor, the red, green and blue fields of color must be set to the desired color, on return the pixel field of this structure will contain the colour map index for the colour
  • if the colour already exists in the colour map, its existing index is returned, otherwise a new colour map entry is created
  • if XAllocColor is successful it returns a non-zero value, otherwise it returns a zero value
  • X also maintains a standard database of colours, this database is stored in /usr/lib/X11, the file rgb.txt is a human readable version of the database
  • the database consists of a collection of colour names and their corresponding red, green and blue values
  • there are two routines that can be used to access this database
  • the XlookupColor procedure can be used to retrieve an XColor structure corresponding to a named colour, the declaration of this procedure is:
        int XLookupColor(display, colormap, name, exact, screen)
        Display        *display;
        Colormap  colormap;
        char      *name;
        XColor         *exact, *screen;
    
  • this procedure lookups the names colour in the standard X colour database, if the colour is found the value of this procedure is non-zero, and if the colour isn’t in the database the return value is zero
  • two XColor structures are returned by this procedure, the exact structure contains the exact definition of the colour in the database, and the screen structure contains the best approximation to that colour using the current display device, this is the colour that will actually be seen by the user
  • the display and colormap parameters are used to identify the display device being used
  • the XAllocNamedColor procedure can be used to lookup a colour in the database and then install it in the colour map, the declaration of this procedure is:
        int XAllocNamedColor(display, colormap, name, exact,
    	      screen)
        Display        *display;
        Colormap  colormap;
        char      *name;
        XColor         *exact, *screen;
    
  • to make using colours easier we can write two library routines that do most of the work for us
  • the colourindexrgb procedure creates a colour index given the red, green and blue components of the colour, the resulting index can then be used as a resource value or any other place that a colour is required
  • the colourindexname procedure create a colour index given the name of the colour, the colour name must be in the X11 colour database, again this routine returns a colour index
      /**************************************************
       *
       *               color.c
       *
       *  Two simple functions for adding colours to
       *  the current colour map.  The colourindexrgb
       *  function creates a colour map entry based on
       *  the red, green and blue components of the
       *  colour and returns the index of the colour.
       *  The colourindexname function creates a colour
       *  map entry based on the name of the colour and
       *  returns the colour map index.
       *
       ***************************************************/
    
      #include <X11/StringDefs.h>
      #include <X11/Intrinsic.h>
    
      int colourindexrgb(w, r, g, b)
      Widget w;
      int r, g, b; {
           Display *display;
           int  screen;
           Colormap cmap;
           XColor    color;
    
           display = XtDisplay(w);
           screen = DefaultScreen(display);
           cmap = DefaultColormap(display, screen);
    
           color.red = r;
           color.green = g;
           color.blue = b;
    
           if(XAllocColor(display, cmap, &color;))
    	    return(color.pixel);
           else {
    	    printf("Warning: can't allocate requested colour\n");
    	    return(BlackPixel(display, screen));
           }
      }
    
    
      int colourindexname(w, name)
      Widget w;
      char *name; {
           Display *display;
           int  screen;
           Colormap cmap;
           XColor    color, exact;
    
           display = XtDisplay(w);
           screen = DefaultScreen(display);
           cmap = DefaultColormap(display, screen);
    
    
    
           if(XAllocNamedColor(display, cmap, name,  &color;, &exact;))
    	    return(color.pixel);
           else {
    	    printf("Warning: can't allocate requested colour\n");
    	    return(BlackPixel(display, screen));
           }
      }
    
      /**************************************************
       *
       *                   ctest.c
       *
       *  A simple test program for the colourindex
       *  procedures
       *
       *************************************************/
    
      #include <X11/StringDefs.h>
      #include <X11/Intrinsic.h>
      #include <X11/Xaw/Label.h>
      #include <X11/Xaw/Box.h>
      #include "lib.h"
    
      main(argc,argv)
      int argc;
      char **argv; {
           Widget toplevel;
           Widget box;
           Widget quit;
           Widget label;
           int n;
           Arg wargs[10];
           int fg;
           int bg;
    
           toplevel = XtInitialize(argv[0],"ctest", NULL, 0,
    		 &argc;, argv);
    
           box = XtCreateManagedWidget("box",boxWidgetClass,
    		 toplevel, NULL, 0);
    
           quit = quit_button(box);
    
           label = XtCreateManagedWidget("colour",labelWidgetClass,
    		 box, NULL, 0);
    
           fg = colourindexrgb(label, 65000, 0, 0);
           bg = colourindexname(label,"navy");
    
           n = 0;
           XtSetArg(wargs[n], XtNforeground, fg); n++;
           XtSetArg(wargs[n], XtNbackground, bg); n++;
           XtSetValues(label, wargs, n);
    
           XtRealizeWidget(toplevel);
    
           XtMainLoop();
    
      }