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


Previous Contents Index

6.4 Drawing Rectangles and Arcs

As with routines that draw points and lines, Xlib provides clients the choice of drawing either single or multiple rectangles and arcs. If a client is drawing more than one rectangle or arc, use the multiple-drawing routines for most efficiency.

6.4.1 Drawing Rectangles

To draw a single rectangle, use the DRAW RECTANGLE routine, specifying the coordinates of the upper left corner and the dimensions of the rectangle, as in the following:


int x=50 
int y=100;      
int width=25; 
int length=50;      
                    .
                    .
                    .
XDrawRectangle(display, window, gc, x, y, width, length); 

Figure 6-3 illustrates how Xlib interprets coordinate and dimension parameters. The x- and y-coordinates are relative to the origin of the drawable.

Figure 6-3 Rectangle Coordinates and Dimensions


To draw multiple rectangles, use the following method:

  1. Define an array of rectangles using the rectangle data structure.
  2. Call the DRAW RECTANGLES routine, specifying the array that defines rectangle origin, width, and height, and the number of array elements.

The server draws each rectangle as shown in Figure 6-4.

Figure 6-4 Rectangle Drawing


For a specified rectangle, the server draws each pixel only once. If rectangles intersect, the server draws intersecting pixels multiple times.

Xlib includes the rectangle data structure to enable clients to define an array of rectangles easily. The following illustrates the data structure:


typedef struct { 
    short x, y; 
    unsigned short width, height; 
} XRectangle; 

Table 6-3 describes the members of the rectangle data structure.

Table 6-3 Rectangle Data Structure Members
Member Name Contents
x Defines the x value of the rectangle origin
y Defines the y value of the rectangle origin
width Defines the width of the rectangle
height Defines the height of the rectangle

When drawing either single or multiple rectangles, the server refers to the following members of the GC data structure to define rectangle characteristics:
Function Plane mask
Foreground Background
Line width Line style
Join style Fill style
Tile Stipple
Tile/stipple x origin Tile/stipple y origin
Subwindow mode Clip x origin
Clip y origin Clip mask
Dash offset Dashes

Chapter 4 describes the GC data structure members.

Example 6-3 illustrates using the DRAW RECTANGLES routine. Figure 6-5 shows the resulting output.

Example 6-3 Drawing Multiple Rectangles

                         .
                         .
                         .
/***** Handle events *****/ 
static void doHandleEvents( ) 
{ 
    XEvent event;         
 
    for ( ; ; ) { 
        XNextEvent(dpy, &event); 
        switch (event.type) { 
            case Expose:                doExpose(&event); break; 
            case ButtonPress:           doButtonPress(&event); break; 
        } 
    }                                           
} 
                                                          
/***** Write a message *****/ 
(1)static void doExpose(eventP) 
XEvent *eventP; 
{ 
    char message1 [ ] = {"To draw multiple rectangles, click MB1"}; 
    char message2 [ ] = {"To exit, click MB2"}; 
 
    XDrawImageString(dpy, win, gc, 150, 25, message1, strlen(message1)); 
    XDrawImageString(dpy, win, gc, 150, 50, message2, strlen(message2)); 
}                
 
 
/***** Draw the rectangles  *****/ 
static void doButtonPress(eventP) 
XEvent *eventP; 
{ 
#define REC_CNT 40             
#define STEP 15                                         
    XRectangle rec_arr[REC_CNT]; 
    int i; 
(2)  if (eventP->xbutton.button == Button2) sys$exit (1); 
 
    for (i=0;i<REC_CNT;i++) { 
        rec_arr[i].x = STEP * i; 
        rec_arr[i].y = STEP * i; 
        rec_arr[i].width = STEP*2; 
        rec_arr[i].height = STEP*3;    
    }                                    
 
(3)   XDrawRectangles(dpy, win, gc, &rec_arr, REC_CNT); 
} 

  1. When the client receives notification that the server has mapped the window, the doExpose routine writes two messages into the window. For information about using the DRAW IMAGE STRING routine, see Chapter 8.
  2. If the user clicks any mouse button, the client calls the doButtonPress routine. If the user clicks MB1, the client draws rectangles defined in the initialization loop. If the user clicks MB2, the client exits the system. The client determines which button the user has clicked by referring to the button member of the button event data structure. For more information about the button event data structure, see Chapter 9.
  3. The DRAW RECTANGLE routine has the following format:

    XDrawRectangles(display, drawable_id, gc_id, rectangles,
    num_rectangles)

Figure 6-5 Rectangles Drawn Using the DRAW RECTANGLES Routine


6.4.2 Drawing Arcs

Xlib routines enable clients to draw either single or multiple arcs. To draw a single arc, use the DRAW ARC routine, specifying a rectangle that defines the boundaries of the arc and two angles that determine the start and extent of the arc, as in the following:


int x=50 
int y=100;      
int width=25; 
int length=50; 
int angle1=5760; 
int angle2=5760;      
                    .
                    .
                    .
XDrawArc(display, window, gc, x, y, width, height, 
     angle1, angle2); 

The server draws an arc within a rectangle. The client specifies the upper left corner of the rectangle, relative to the origin of the drawable. The center of the rectangle is the center of the arc. The width and height of the rectangle are the major and minor axes of the arc, respectively.

Two angles specify the start and extent of the arc. The angles are signed integers in degrees scaled up by 64. For example, a client would specify a 90-degree arc as 64*90 or 5760 . The start of the arc is specified by the first angle, relative to the three o'clock position from the center of the rectangle. The extent of the arc is specified by the second angle, relative to the start of the arc. Positive integers indicate counterclockwise motion; negative integers indicate clockwise motion.

To draw multiple arcs, use the following method:

  1. Define an array of arc data structures.
  2. Call the DRAW ARCS routine, specifying the array that defines the arcs and the number of array elements.

The following illustrates the arc data structure:


typedef struct { 
    short x, y; 
    unsigned short width, height; 
    short angle1, angle2; 
} XArc; 

Table 6-4 describes the members of the arc data structure.

Table 6-4 Arc Data Structure Members
Member Name Contents
x Defines the x-coordinate value of the rectangle in which the server draws the arc
y Defines the y-coordinate value of the rectangle in which the server draws the arc
width Defines the major axis of the arc
height Defines the minor axis of the arc
angle1 Defines the starting point of the arc relative to the 3-o'clock position from the center of the rectangle
angle2 Defines the extent of the arc relative to the starting point

When drawing either single or multiple arcs, the server refers to the following members of the GC data structure to define arc characteristics:
Function Plane mask
Foreground Background
Line width Line style
Join style Cap style
Fill style Tile
Tile/stipple x origin Tile/stipple y origin
Clip x origin Clip y origin
Clip mask Dash offset
Dashes Stipple
Subwindow mode  

Chapter 4 describes the GC data structure members.

If the last point in one arc coincides with the first point in the following arc, the two arcs join. If the first point in the first arc coincides with the last point in the last arc, the two arcs join.

If two arcs join, the line width is greater than zero, and the arcs intersect, the server draws all pixels only once. Otherwise, it may draw intersecting pixels multiple times.

Example 6-4 illustrates using the DRAW ARCS routine.

Example 6-4 Drawing Multiple Arcs

                         .
                         .
                         .
/***** Handle events *****/ 
static void doHandleEvents( ) 
{ 
    XEvent event;         
 
    for ( ; ; ) { 
        XNextEvent(dpy, &event); 
        switch (event.type) { 
            case Expose:                doExpose(&event); break; 
            case ButtonPress:           doButtonPress(&event); break; 
        } 
    }                                           
} 
                                                          
/***** Write a message *****/ 
static void doExpose(eventP) 
XEvent *eventP; 
{ 
    char message1[ ] = {"To create arcs, click MB1"};  
    char message2[ ] = {"Each click creates a new circle of arcs."};  
    char message3[ ] = {"To exit, click MB2"}; 
    
    XDrawImageString(dpy, win, gc, 150, 25, message1, strlen(message1)); 
    XDrawImageString(dpy, win, gc, 150, 50, message2, strlen(message2)); 
    XDrawImageString(dpy, win, gc, 150, 75, message3, strlen(message3)); 
} 
 
 
/***** Draw the arcs *****/ 
static void doButtonPress(eventP) 
XEvent *eventP; 
{ 
#define ARC_CNT 16               
#define RADIUS 50                                         
#define INNER_RADIUS  20    
    XArc arc_arr[ARC_CNT]; 
    int i; 
(1)  int x = eventP->xbutton.x; 
    int y = eventP->xbutton.y; 
 
    if (eventP->xbutton.button == Button2) sys$exit (1); 
 
    for (i=0;i<ARC_CNT;i++) { 
        arc_arr[i].angle1 = (64*360)/ARC_CNT * i; 
        arc_arr[i].angle2 = (64*360)/ARC_CNT*3; 
        arc_arr[i].width = RADIUS*2; 
        arc_arr[i].height = RADIUS*2;    
        arc_arr[i].x = x - RADIUS + sin(2*3.14159/ARC_CNT*i) * INNER_RADIUS; 
        arc_arr[i].y = y - RADIUS + cos(2*3.14159/ARC_CNT*i) * INNER_RADIUS; 
    }                                    
 
(2)  XDrawArcs(dpy, win, gc, &arc_arr, ARC_CNT); 
} 

  1. The x and y variables specify the upper left corner of the rectangle that defines the boundary of the arc. The client determines the rectangle coordinates by taking the values of the x and y arguments from the button event data structure. Because these values indicate the position of the cursor when the user clicks the mouse button, the server draws the arcs relative to the position of the cursor. For more information about the button event data structure, see Chapter 9.
  2. The DRAW ARCS routine has the following format:

    XDrawArcs(display,drawable_id,gc_id,arcs,num_arcs)

Figure 6-6 illustrates the resulting output.

Figure 6-6 Multiple Arcs Drawn Using the DRAW ARCS Routine


6.5 Filling Areas

This section describes using Xlib routines to fill single rectangles, arcs, and polygons, and multiple rectangles and arcs.

6.5.1 Filling Rectangles and Arcs

The FILL RECTANGLE, FILL RECTANGLES, FILL ARC, and FILL ARCS routines create single and multiple rectangles or arcs and fill them using the fill style that the client specifies in a graphics context data structure.

The method of calling the fill routines is identical to that for drawing rectangles and arcs. For example, to create rectangles filled solidly with foreground color in Example 6-3, the client needs only to call the FILL RECTANGLES routine instead of DRAW RECTANGLES. The default value of the GC data structure fill style member is solid. If the client were to specify a tile or stipple for filling the rectangles, the client would have to change the graphics context used by the FILL RECTANGLES routine.

The server refers to the following members of the GC data structure to define characteristics of the rectangles and arcs it fills:
Function Plane mask
Foreground Background
Fill style Tile
Stipple Subwindow mode
Tile/stipple x origin Tile/stipple y origin
Clip x origin Clip y origin
Clip mask  

Additionally, the server refers to the arc mode member if filling arcs.

For information about using graphics context, see Chapter 4.

6.5.2 Filling a Polygon

To fill a polygon, use the following method:

  1. Define an array of point data structures.
  2. Call the FILL POLYGON routine, specifying the array that defines the points of the polygon, the number of points the server is to draw, the shape of the polygon, and the coordinate system the server is to use. The server draws the points in the order specified by the array.

See Section 6.3.1 for an illustration of the point data structure.

To improve performance, clients can specify whether the shape of the polygon is complex, convex, or nonconvex, as follows:

When filling the polygon, the server draws each pixel only once.

The server determines the location of points as follows:

If the last point does not coincide with the first point, the server closes the polygon automatically.

The server refers to the following members of the GC data structure to define the characteristics of the polygon it fills:
Function Plane mask
Foreground Fill style
Fill rule (if polygon is complex) Tile
Tile/stipple x origin Tile/stipple y origin
Clip x origin Clip y origin
Subwindow mode Clip mask
Stipple Background

Chapter 4 describes GC data structure members.

Example 6-5 uses the FILL POLYGON routine to draw and fill the star created in Example 6-2.

Example 6-5 Filling a Polygon

                         .
                         .
                         .
/***** Handle events *****/ 
static void doHandleEvents( ) 
{ 
    XEvent event;         
 
    for ( ; ; ) { 
        XNextEvent(dpy, &event); 
        switch (event.type) { 
            case Expose:                doExpose(&event); break; 
        } 
    }                                           
}                      
/***** Expose event ****/ 
static void doExpose(eventP) 
XEvent *eventP; 
{ 
    XPoint pt_arr[6]; 
 
(1)  pt_arr[0].x = 75;       
    pt_arr[0].y = 500;           
    pt_arr[1].x = 300;            
    pt_arr[1].y = 100;                                
    pt_arr[2].x = 525; 
    pt_arr[2].y = 500; 
    pt_arr[3].x = 50; 
    pt_arr[3].y = 225; 
    pt_arr[4].x = 575; 
    pt_arr[4].y = 225; 
    pt_arr[5].x = 75; 
    pt_arr[5].y = 500; 
 
(2)   XFillPolygon(dpy, win, gc, &pt_arr, 6, Complex, CoordModeOrigin); 
} 
                         .
                         .
                         .

  1. Use an array of point data structures to specify the points that define the polygon.
  2. The call to fill the polygon refers to a graphics context (gc), which the client has previously defined, and an array of point data structures. The constant Complex indicates that the path of the line that draws the polygon intersects itself. The constant CoordModeOrigin indicates that all points are relative to the origin of win (100,100).

Figure 6-7 illustrates the resulting output.

Figure 6-7 Filled Star Created Using the FILL POLYGON Routine


6.6 Clearing and Copying Areas

Xlib includes routines that enable clients to clear or copy a specified area of a drawable. Because pixmaps do not have defined backgrounds, clients clearing an area of a pixmap must use the FILL RECTANGLE routine described in Section 6.5.1. For more information about pixmaps, see Chapter 7.

This section describes how to clear windows and copy areas of windows and pixmaps.

6.6.1 Clearing Window Areas

To clear an area of a window, use the CLEAR AREA or CLEAR WINDOW routine. The CLEAR AREA routine clears a specified area and generates an expose event, if the client directs the server to do so.

The CLEAR WINDOW routine clears the entire area of the specified window. If the window has a defined background tile, the window is retiled. If the window has no defined background, the server does not change the window contents.

Example 6-6 illustrates clearing a window.

Example 6-6 Clearing a Window

                    .
                    .
                    .
/***** Draw multiple arcs  *****/ 
static void doButtonPress(eventP) 
XEvent *eventP;         
{ 
#define ARC_CNT 16               
#define RADIUS 50                                         
#define INNER_RADIUS  20    
    XArc arc_arr[ARC_CNT]; 
    int i; 
    int x = eventP->xbutton.x; 
    int y = eventP->xbutton.y; 
 
    if (eventP->xbutton.button == Button2) sys$exit (1); 
    if (eventP->xbutton.button == Button3) 
    { 
        XClearWindow(dpy, win); 
        return; 
    } 
 
    for (i=0;i<ARC_CNT;i++) { 
        arc_arr[i].angle1 = (64*360)/ARC_CNT * i; 
        arc_arr[i].angle2 = (64*360)/ARC_CNT*3; 
        arc_arr[i].width = RADIUS*2; 
        arc_arr[i].height = RADIUS*2;    
        arc_arr[i].x = x - RADIUS + sin(2*3.14159/ARC_CNT*i) * INNER_RADIUS; 
        arc_arr[i].y = y - RADIUS + cos(2*3.14159/ARC_CNT*i) * INNER_RADIUS; 
    }                                    
 
    XDrawArcs(dpy, win, gc, &arc_arr, ARC_CNT); 
} 

The example modifies the doButtonPress routine of Example 6-4 to clear the window when the user clicks MB3.

To clear multiple areas, using the FILL RECTANGLES routine is faster than using the CLEAR WINDOW or CLEAR AREA routine. To clear multiple areas on a monochrome screen, first set the function member of the GC data structure to the value specified by the constant GXclear. Then call the FILL RECTANGLES routine. If the screen is a color type, set the value of the background to the background of the window before calling FILL RECTANGLES.


Previous Next Contents Index