VMS DECwindows Guide to Xlib (Release 4) Programming: MIT C Binding


Previous Contents Index

5.2.3 Determining Multiple Visual Types

On some systems, a single display can support multiple screens. Each screen can have several different visual types supported at different depths. Xlib provides routines that allow a client to search and choose the appropriate visual type on the system by using the visual info data structure.

The following illustrates the visual info data structure:


typedef struc { 
        Visual *visual; 
        VisualID *visualid; 
        int screen; 
        int depth; 
        int class; 
        unsigned long red_mask; 
        unsigned long green_mask; 
        unsigned long blue_mask; 
        int colormap_size; 
        int bits_per_rgb; 
}XVisualInfo; 

Table 5-1 describes the members of the visual info data structure.

Table 5-1 Visual Info Data Structure Members
Member Name Contents
visual A pointer to a visual data structure that is returned to the client.
visualid The id of the visual that is returned by the server.
screen The specified screen of the display.
depth The depth in planes of the screen.
class The class of the visual (PseudoColor, GrayScale, DirectColor, TrueColor, StaticGray, StaticColor).
red_mask Definition of the red mask. 1
green_mask Definition of the green mask. 1
blue_mask Definition of the blue mask. 1
colormap_size Number of available color map entries.
bits_per_rgb Number of bits that specifies the number of distinct red, green and blue values. Actual RGB values are unsigned 16-bit numbers.


1The red mask, green mask, and blue mask are defined only for the direct color and true color visual types.

Use the GET VISUAL INFO routine to return a list of visual structures that match a specified template.

The GET VISUAL INFO routine has the following format:

XGetVisualInfo(display, vinfo_mask, vinfo_template, num_items_return)

Example 5-4 illustrates using the GET VISUAL INFO routine.

Use the MATCH VISUAL INFO routine to return the visual information for a visual type that matches the specified depth and class for a screen. Because multiple visual types that match the specified depth and class can exist, the exact visual chosen is undefined.

Note that the MATCH VISUAL INFO routine is a convenience routine that matches one visual of a particular class and depth. The GET VISUAL INFO routine, however, can find any number of visuals that match any combination of characteristics.

Example 5-1 illustrates using the MATCH VISUAL INFO routine to find a pseudocolor visual type on a 24-plane system.

Example 5-1 Matching Visual Information

            .
            .
            .
(1)#define max_supported_planes 24 
(2)XVisualInfo vInfo; 
            .
            .
            .
screen = XDefaultScreenOfDisplay(dpy); 
scrNum = XDefaultScreen(dpy); 
            .
            .
            .
/***** Match the visual *****/ 
static void doMatchVisual( ) 
{ 
    for (i = 4; (i <= max_supported_planes && !status); i++) 
(3)   status = XMatchVisualInfo(dpy, scrNum, i, PseudoColor, &vInfo); 
 
    if (!status){ 
        printf ("Could not find a Pseudocolor visual on this system"); 
        exit(1); 
        } 
 
} 
 
/***** Create the color *****/ 
static void doCreateColor( ) 
{ 
(4)   if (vInfo.visual != DefaultVisual(dpy,scrNum)) 
         map = XCreateColormap(dpy,RootWindow(dpy,scrNum),vInfo.visual, 
            AllocNone); 
     else map = XDefaultColormapOfScreen(screen); 
            .
            .
            .

  1. The client defines the maximum number of planes, or depth, supported on the system.
  2. Storage is assigned for the visual info data structure.
  3. The MATCH VISUAL INFO routine searches for a pseudocolor visual type beginning at the fourth plane. If a match is found, MATCH VISUAL INFO returns the visual information to the visual info data structure. If a match is not found, the next depth is checked for a pseudocolor visual.
    The MATCH VISUAL INFO routine has the following format:

    XMatchVisualInfo(display, screen_number, depth, class,
    vinfo_return)

  4. The client compares the visual member of the visual info data structure returned by the MATCH VISUAL INFO routine with the default visual. If the default visual is a pseudocolor type, then the client uses the default color map. If the visual is not the default visual, the client creates a color map.
    Refer to Section 5.4.1 for more information about creating color maps.

5.3 Sharing Color Resources

Xlib provides the following ways to share color resources:

The choice of using a named color or specifying an exact color depends on the needs of the client. For instance, if the client is producing a bar graph, specifying the named VMS DECwindows color "Red" as a color value may be sufficient, regardless of the hue that VMS DECwindows names "Red". However, if the client is reproducing a portrait, specifying an exact red color value might be necessary to produce accurate skin tones. For a list of named colors, see the SYS$MANAGER:DECW$RGB.COM file.

Note that because of differences in hardware, no two monitors display colors exactly the same, even though the same named colors are specified.

5.3.1 Using Named Colors

VMS DECwindows includes named colors that clients can share. To use a named color, call the ALLOC NAMED COLOR routine. ALLOC NAMED COLOR determines whether the color map defines a value for the specified color. If the color exists, the server returns the index to the color map. If the color does not exist, the server returns an error.

Example 5-2 illustrates specifying a color using ALLOC NAMED COLOR.

Example 5-2 Using Named VMS DECwindows Colors

static int doDefineColor(n) 
{ 
    int pixel; 
(1)  XColor exact_color,screen_color; 
(2)  char *colors[ ] = { 
        "dark slate blue", 
        "light grey", 
        "firebrick" 
        }; 
 
    if ((XDefaultVisualOfScreen(screen))->class == TrueColor 
         ||  (XDefaultVisualOfScreen(screen))->class == 
              PseudoColor 
         ||  (XDefaultVisualOfScreen(screen))->class == 
              DirectColor 
         ||  (XDefaultVisualOfScreen(screen))->class == 
              StaticColor)                                   
        { 
(3)      if (XAllocNamedColor(dpy, DefaultColormapOfScreen(screen), 
            colors[n-1], &screen_color, &exact_color)) 
                return screen_color.pixel; 
            else                         
                printf("Color not allocated!"); 
 
        } 
    else 
        printf("Not a color device!");  
               .
               .
               .

  1. The client allocates storage for two color data structures: exact_color defines the RGB values specified by the VMS DECwindows named color. Screen_color defines the closest RGB values supported by the hardware.
    For an illustration of the color data structure, see Section 5.3.2.
  2. An array of characters stores the names of the predefined VMS DECwindows colors that the client uses.
  3. The ALLOC NAMED COLOR routine has the following format:

    XAllocNamedColor(display, colormap_id, color_name,
    screen_def_return, exact_def_return)


    The client passes the names of VMS DECwindows colors by referring to the array colors.

5.3.2 Specifying Exact Color Values

To specify exact color values, use the following method:

  1. Assign values to a color data structure.
  2. Call the ALLOC COLOR routine, specifying the color map from which the client allocates the definition. ALLOC COLOR returns a pixel value and changes the RGB values to indicate the closest color supported by the hardware.

Xlib provides a color data structure enabling clients to specify exact color values when sharing colors. (Routines that allocate colors for exclusive use and that query available colors also use the color data structure. For information about using the color data structure for these purposes, see Section 5.4.)

The following illustrates the color data structure:


typedef struct { 
        unsigned long pixel; 
        unsigned short red, green, blue; 
        char flags;  
        char pad; 
} XColor; 

Table 5-2 describes the members of the color data structure.

Table 5-2 Color Data Structure Members
Member Name Contents
pixel Pixel value
red Specifies the red value of the pixel 1
green Specifies the green value of the pixel 1
blue Specifies the blue value of the pixel 1
flags Defines which color components are to be changed in the color map. Possible flags are as follows:
DoRed Sets red values
DoGreen Sets green values
DoBlue Sets blue values
pad Makes the data structure an even length


1Color values are scaled between 0 and 65535. "On full" in a color is a value of 65535, independent of the number of planes of the display. Half brightness in a color is a value of 32767; off is a value of 0. This representation gives uniform results for color values across displays with different color resolution.

Example 5-3 illustrates how to specify exact color definitions.

Example 5-3 Specifying Exact Color Values

/***** Create color *****/ 
static int doDefineColor(n) 
{ 
    int pixel; 
    XColor colors[3]; 
 
    if ((XDefaultVisualOfScreen(screen))->class == TrueColor 
         ||  (XDefaultVisualOfScreen(screen))->class == 
              PseudoColor 
         ||  (XDefaultVisualOfScreen(screen))->class == 
              DirectColor 
         ||  (XDefaultVisualOfScreen(screen))->class == 
              StaticColor) 
        switch (n){ 
                 case 1:{                       
(1)                   colors[n - 1].red = 59904; 
                     colors[n - 1].green = 44288; 
                     colors[n - 1].blue = 59904;    
(2)                   if (XAllocColor(dpy, XDefaultColormapOfScreen(screen), 
                          &colors[n - 1])) 
                               return colors[n - 1].pixel; 
                          else 
                               printf("Color not allocated!"); 
                     return; 
                     } 
                 case 2:{                      
                     colors[n - 1].red = 65280; 
                     colors[n - 1].green = 0; 
                     colors[n - 1].blue = 32512; 
                     if (XAllocColor(dpy, XDefaultColormapOfScreen(screen), 
                          &colors[n - 1])) 
                               return colors[n - 1].pixel; 
                          else 
                               printf("Color not allocated!"); 
                     return; 
                     } 
                 case 3:{                      
                     colors[n - 1].red = 37632; 
                     colors[n - 1].green = 56064; 
                     colors[n - 1].blue = 28672; 
                     if (XAllocColor(dpy, XDefaultColormapOfScreen(screen), 
                         &colors[n - 1])) 
                               return colors[n - 1].pixel; 
                          else 
                               printf("Color not allocated!"); 
                     return; 
                     }    
        } 
     else 
        switch (n) { 
            case 1:             return XBlackPixelOfScreen(screen); break; 
            case 2:             return XWhitePixelOfScreen(screen); break; 
            case 3:             return XBlackPixelOfScreen(screen); break; 
        } 
}   

  1. Define color values in the first of three color data structures.
  2. After defining RGB values, call the ALLOC COLOR routine. ALLOC COLOR allocates shared color cells on the default color map and returns a pixel value for the color that matches the specified color most closely.

5.4 Allocating Colors for Exclusive Use

If a client does not need to change color values, it should share colors by using the methods described in Section 5.3. Sharing colors saves resources. However, a client that changes color values must allocate them for its exclusive use.

Xlib provides two methods for allocating colors for a client's exclusive use. First, the client can allocate cells and store color values in the default color map. Second, if the default color map does not contain enough storage, or if the default color map is read-only (such as true color), the client can create its own color map using a writable visual type and store color values in it. In addition, when creating a color map, the client can allocate all entries in the color map for its exclusive use. Refer to the CREATE COLORMAP routine in Section 5.4.1 for more information about allocating all entries in a color map.

This section describes how to specify a color map, how to allocate cells for exclusive use, and how to store values in the color cells.

5.4.1 Specifying a Color Map

Clients can either use the default color map and allocate its color cells for exclusive use or create their own color maps.

If possible, use the default color map. Although a client can create color maps for its own use, the hardware color map storage is limited. When a client creates its own color map, the map must be installed into the hardware color map before the client map can be used. If the client color map is not installed, the client may use a different color map and possibly display the wrong color. Using the default color map eliminates this problem. See Section 5.1 for information about how Xlib handles color maps.

To specify the default color map, use the DEFAULT COLORMAP routine. DEFAULT COLORMAP returns the identifier of the default color map.

If the default color map does not contain enough resources, the client can create its own color map.

To create a color map, use the following method:

  1. Using one of the methods described in Section 5.2, determine the visual type of a specified screen.
  2. Call the CREATE COLORMAP routine.

The CREATE COLORMAP routine creates a color map for the specified window and visual type. Note that CREATE COLORMAP can only be used with pseudocolor, gray scale, and direct color visual types.

The CREATE COLORMAP routine has the following format:

XCreateColormap(display, window_id, visual_struc, alloc)

The alloc argument specifies whether the client creating the color map allocates all of the color map entries for its exclusive use or creates a color map with no defined color map entries. To allocate all entries for exclusive use, specify the constant AllocAll. To allocate no defined map entries, specify the constant AllocNone. The latter is useful when two or more clients are to share the newly created color map.

See Section 5.4.2 for information about allocating colors. See Example 5-4 for an example of creating a color map.

5.4.2 Allocating Color Cells

After specifying a color map, allocate color cells in it.

Use the ALLOC COLOR CELLS routine or ALLOC COLOR PLANES to allocate color resources. Either routine can be used; however, ALLOC COLOR CELLS allocates colors according to the pseudocolor model. The ALLOC COLOR PLANES routine allocates color resources according to a direct color model. See Section 5.2 for information about these color models.

Example 5-4 illustrates how to allocate colors for exclusive use. The program creates a color wheel that rotates when the user presses MB1.

Example 5-4 Allocating Colors for Exclusive Use

#include <decw$include/Xlib.h> 
#include <decw$include/Xutil.h> 
#include <stdio.h> 
#include math; 
 
#define winW 600 
#define winH 600 
#define backW 800 
#define backH 800 
             
Display *dpy; 
Window win; 
Pixmap pixmap; 
Colormap map; 
GC gc; 
Screen *screen; 
int scrNum; 
XColor *colors; 
int offsetX, offsetY; 
int fullcount; 
int ButtonIsDown = 0; 
int n, exposeflag = 0; 
int ihop=1; 
int whiteValue; 
XSetWindowAttributes xswa; 
XVisualInfo *pVisualInfo; 
static void doInitialize( ); 
static void doGetVisual(); 
static void doCreateWindows( ); 
static void doCreateGraphicsContext( ); 
static void doCreatePixmap( ); 
static void doCreateColor( ); 
static void doCreateWheel( ); 
static void doMapWindows( ); 
static void doHandleEvents( ); 
static void doExpose( ); 
static void doButtonPress( ); 
static void doButtonRelease( ); 
static void doChangeColors( ); 
static void doLoadColormap( ); 
static void doHLS_to_RGB( ); 
static void doConfigure( ); 
 
/***** The main program *****/ 
 
static int main() 
{          
    doInitialize( ); 
    doHandleEvents( ); 
}                                        
 
/***** doInitialize *****/ 
static void doInitialize( ) 
{ 
    dpy = XOpenDisplay(0); 
 
    screen = DefaultScreenOfDisplay(dpy);   /* This is the screen structure */ 
    scrNum = DefaultScreen(dpy);     /* This is the screen index number*/ 
 
    doGetVisual(); 
 
    doCreateColor( ); 
 
    doCreateWindows( ); 
 
    doCreateGraphicsContext( ); 
 
    doCreatePixmap( ); 
 
    doCreateWheel( ); 
 
    doMapWindows( );  
} 
/***** doGetVisual *****/ 
static void doGetVisual( ) 
{ 
(1)  XVisualInfo vInfoTemplate; 
    int usableClasses[3] = {PseudoColor,DirectColor,GrayScale},i,nVis; 
 
    vInfoTemplate.screen = scrNum; 
    for (i = 0;  i < 3;  i++) 
        { 
        vInfoTemplate.class = usableClasses[i]; 
(2)      pVisualInfo = XGetVisualInfo(dpy,VisualClassMask|VisualScreenMask, 
                                         &vInfoTemplate,&nVis); 
        if (pVisualInfo) break; 
        } 
    if (!pVisualInfo) 
        { 
        fprintf(stderr,"Unable to find a dynamic visual class"); 
        exit(1); 
        } 
} 
/***** Create the windows *****/ 
static void doCreateWindows( ) 
{   
    int winX = 100; 
    int winY = 100; 
    
    /* Create the win window */ 
 
    xswa.event_mask = ExposureMask | ButtonPressMask | 
        ButtonReleaseMask | StructureNotifyMask; 
    xswa.background_pixel = whiteValue; 
    xswa.border_pixel = whiteValue; /* Note: you must set this for a non-  
           default depth and class! */ 
 
    win = XCreateWindow(dpy, RootWindowOfScreen(screen), 
        winX, winY, winW, winH, 0, 
        pVisualInfo->depth, InputOutput,pVisualInfo->visual, 
        CWBorderPixel |CWEventMask | CWBackPixel | CWColormap, &xswa); 
 
    /* Create the name of the window */ 
    XStoreName(dpy, win, "Color Wheel: Press MB1 to Rotate or MB2 to Exit."); 
} 
 
/***** Create the graphics context *****/    
static void doCreateGraphicsContext( ) 
{                                                
    gc = XCreateGC(dpy, win, 0, 0); 
} 
 
/***** Create the pixmap *****/ 
static void doCreatePixmap( ) 
{ 
 
(3)  pixmap = XCreatePixmap(dpy, XRootWindow(dpy, XDefaultScreen(dpy)), 
        backW, backH, pVisualInfo->depth); 
    XSetForeground(dpy,gc,whiteValue); 
    XFillRectangle(dpy, pixmap, gc, 0, 0, backW, backH); 
} 
 
/***** Create the color ******/ 
 
(4)static void doCreateColor( ) 
{ 
int *pixels; 
int contig; 
int *plane_masks; 
 
        if (pVisualInfo->visual != DefaultVisual(dpy,scrNum)) 
(5)          map=XCreateColormap(dpy,RootWindow(dpy,scrNum),pVisualInfo->visual, 
                AllocNone); 
        else map = XDefaultColormapOfScreen(screen); 
 
 
        xswa.colormap = map; 
        fullcount = XDisplayCells(dpy, scrNum)/2; 
        if (fullcount > 128) fullcount = 128; 
        pixels = malloc(sizeof(int)*fullcount); 
        colors = malloc(sizeof(XColor)*fullcount); 
 
        /* Get a value for white (Use colors[0] temporarily) */ 
 
        colors[0].red = colors[0].blue = colors[0].green = 0xffff; 
        XAllocColor(dpy,map,&colors[0]); 
        whiteValue = colors[0].pixel; 
 
        /* Now get writable pixels for the color wheel */ 
 
        if (!XAllocColorCells(dpy, map, contig, plane_masks, 
            0, pixels, fullcount)) 
            { 
                sys$exit(1); 
            } 
        doLoadColormap(pixels); 
} 
                            
 
/***** Create the wheel *****/ 
 
(6)static void doCreateWheel( ) 
{ 
int pixel, i, j; 
XPoint *pgon; 
int xcent, ycent;                   
 
    /* Now set up wheel.  It is really a set of triangles*/ 
        pgon = malloc(sizeof(XPoint)*3*fullcount+1); 
        xcent=backW/2;             
        ycent=backH/2; 
(7)       pgon[0].x = backW;      
        pgon[0].y = backH/2; 
                            
    /* Fill in coordinate for center point in all triangles */ 
 
        for (i=0;i<fullcount*3;i+=3) 
            { 
            pgon[i+1].x = xcent;    
            pgon[i+1].y = ycent; 
            } 
 
                                 
     /* Calculate the triangle points on the outer circle */ 
 
         for (pixel=0,i=0;pixel<fullcount;i+=3, pixel++) 
             {               
             double x,y,xcent_f,ycent_f; 
             xcent_f = (double)xcent; 
             ycent_f = (double)ycent; 
             x=cos( (((double)pixel+1.)/(double)fullcount)*2.*3.14159); 
             y=sin( (((double)pixel+1.)/(double)fullcount)*2.*3.14159); 
             pgon[i+2].x = (int)(x*xcent_f)+xcent; 
             pgon[i+2].y = (int)(y*ycent_f)+ycent; 
             pgon[i+3].x = pgon[i+2].x; 
             pgon[i+3].y = pgon[i+2].y; 
             XSetForeground(dpy, gc, colors[i/3].pixel); 
             XFillPolygon(dpy, pixmap, gc, &pgon[i], 3, Convex, CoordModeOrigin); 
             } 
    offsetX = (backW - winW)/2; 
    offsetY = (backH - winH)/2; 
    return; 
} 
 
/***** Map the windows *****/ 
static void doMapWindows( )                                           
{ 
    XMapWindow(dpy, win); 
} 
 
/***** Handle the events *****/ 
static void doHandleEvents( ) 
{ 
    XEvent event;               
                                 
    for ( ; ; ) { 
        XNextEvent(dpy, &event); 
 
        switch (event.type) { 
            case Expose:                doExpose(&event); break; 
            case ButtonPress:           doButtonPress(&event); break; 
            case ButtonRelease:         doButtonRelease(&event); break; 
            case ConfigureNotify:       doConfigure(&event); break; 
        } 
    }                                           
} 
 
/***** Handle window exposures *****/ 
static void doExpose(eventP) 
XEvent *eventP;                            
{ 
 
(8)  XCopyArea(dpy, pixmap, win, gc, offsetX + eventP->xexpose.x, 
        offsetY + eventP->xexpose.y, eventP->xexpose.width, 
        eventP->xexpose.height, eventP->xexpose.x, eventP->xexpose.y);        
} 
 
/***** Button Press ******/ 
static void doButtonPress(eventP) 
XEvent *eventP; 
{ 
       if (eventP ->xbutton.button == Button2) { 
           sys$exit (1); 
       } 
       ButtonIsDown = 1; 
       if (ButtonIsDown) doChangeColors( ); 
       return;                                      
} 
 
/***** Button Release *****/                   
static void doButtonRelease(eventP)  /* Quit rotate when MB1 released */ 
XEvent *eventP; 
{                               
       ButtonIsDown = 0; 
       return;      
} 
 
/***** Configure notify *****/ 
static void doConfigure(eventP) 
XEvent *eventP;                            
{ 
(9)  offsetX = (backW - eventP->xconfigure.width)/2; 
    offsetY = (backH - eventP->xconfigure.height)/2; 
} 
 
/***** Change the colors *****/  
(10)static void doChangeColors( ) 
{ 
      for (;!(XPending(dpy));){ 
                unsigned int i,temp; 
                double h,r,g,b; 
 
                temp = colors[0].pixel; 
                for (i=0;i<fullcount-1;i++) 
                      colors[i].pixel = colors[i+1].pixel; 
                colors[fullcount-1].pixel = temp; 
                XStoreColors(dpy, map, colors, fullcount); 
      }                          
} 
 
/***** Load the colormap *****/ 
(11)static void doLoadColormap(pPixels) 
int *pPixels; 
{ 
                                                          
    unsigned int i,j; 
    double h,r,g,b; 
 
        for (i=0;i < fullcount;i++) { 
            colors[i].pixel=pPixels[i]; 
            colors[i].flags = DoRed | DoGreen |DoBlue; 
        } 
        for (i=0; i < fullcount ; i++) { 
(12)          h = (double)i*360/((double)fullcount+1); 
            doHLS_to_RGB(&h,&.5,&.5,&r,&g,&b);            
            colors[i].red = r * 65535.0; 
            colors[i].green = g * 65535.0; 
            colors[i].blue = b * 65535.0; 
        } 
      XStoreColors(dpy, map, colors, fullcount); 
} 
 
/***** Convert to RGB *****/ 
static void doHLS_to_RGB (h,l,s, r,g,b) 
double *h,*l,*s,*r,*g,*b;                                 
{ 
     double m1,m2; 
     double value(); 
    
     m2 = (*l < 0.5) ? (*l)*(1+*s) : *l + *s- (*l)*(*s) ; 
     m1 = 2*(*l) - m2; 
        if ( *s == 0 ) 
          { (*r)=(*g)=(*b)=(*l); }      /*Gray shade*/ 
        else 
          { *r=value(m1,m2,(double)(*h+120.)); 
            *g=value(m1,m2,(double)(*h+000.)); 
            *b=value(m1,m2,(double)(*h-120.)); 
          } 
        return; 
}                                                         
double value (n1,n2,hue) 
double n1,n2,hue; 
{ 
        double val; 
    
        if (hue>360.)  hue -= 360.; 
        if (hue<0.  )  hue += 360.; 
    
        if (hue<60) 
          val = n1+(n2-n1)*hue/60.; 
        else if (hue<180.) 
          val = n2; 
        else if (hue<240.) 
          val = n1+(n2-n1)*(240.-hue)/60.;                
        else 
          val = n1; 
        return (val); 
 } 


Previous Next Contents Index