You are on page 1of 7

nonintersectif.1grectangles.

When referring to regions, use a Region data type defined in the header
file <X11/ Xutil. h> as a pointer to an internal data structure. You can treat Region the same way
you do the FILE data type used in the standard I/O routines in C. You do not need to know the
details of t~e data structure-merely use the type where required.

You create regions in two ways. The first approach is to start with an empty Region, created by
calling XCreateRegion:

Then you add rectangles to the region by using the XUnionRectWithRegion function:
/* A 100x50 pixel rectangle at (10,10) */
XRectangle rect = { 10, 10, 100, 50 }j

/* Add the rectangle to the region "new_region" */


XUnionRectWithRegion(&rect, new_region, new_region);

The other approach is to create a region from the points that lie inside a polygon. Use the
XPolygonRegion function to do this:

XPoint points[3j = ./* Vertices of a polygon */


{
{ 100, 100 },
{50, 150},
{ 150, 150 }
};
int numpoints = sizeof(points) / sizeof(XPoint);

An array ofXPoint structures defines the vertices of the polygon (a triangle, in this example). The
last argument to XPolygonRegion is the fill rule used to determine whi~ points belong to the re-
gion. You can use EvenOddRule or WindingRule as the fill'rule.

After a region is created by XPolygonRegion, you can add rectangles to it with


XUnionRectWithRegion as you would to any other region.

After a region has been defined, you can use it as the clip mask in a GCby calling the XSetRegion
function:

Basic Drawing Functions


You have learned how a GCembodies all attributes that affect graphics output in X. You also have
gotten an overview of what the various attributes are and how you can use Xlib functions to ma-
nipulate them. The next logical step is to learn how to draw sim Ie ra hical sha ~nd see !;low
the GCsaffect the appearance of these graphics.
Xlib includes functions to draw points, rectangles, arcs, and polygons. By varying the arguments to
The three standard arguments are followed by the array of points and number_~J>0ints. The last
the arc drawing function, you can draw ellipses and circles. There are separate functions for draw-
argulll~,nt tells the se1:!:e~~ow to interpr~ tl:eco_ordfKaifs of the poi~ts in the array. "You can ~pecifY
ing filled rectangles, polygons, and arcs. The first three arguments to all drawing functions are the
o;;-e:Of~e following cons"tants:
same:
~ CoordModeOrigin means the coordinates are relative to the origin of the window or the
• Pointer to the Display :-.. •. -. ~ ., .. " . •.. ~~ m ; ... '"i .~

p=ap.
• The ID of a Drawable
• CoordModePrevious is used when the coordinate of each point is given in terms of the x
• A GC that controls the appearance of the figure being drawn and y displacements from the previous point. The first point is assumed to be relative to
Xlib provides separate functions for drawing several figures at once. For example, XDrawPoint draws the origin of the window.
one point, but XDraw"Points draws an entire array of points. The reason for the special"plural ver-
sions of the functions is efficiency. Because X applications draw by send' ng protocol requests to the Drawing with Points: An Example
X server, it is more efficient to send a single request for drawing several figures (of the same type)
rather than sending a separate drawing request for each figure. Consider a simple example that uses XDrawPoints to display an interesting pattern of points. List-
ing 9.1, xpoints, follows a seemingly random process that results in the pattern shown in Figure
9.10.
, Drawing Points
\ The simplest of graphics operations in X is to draw a point in a window or pixmap. You can draw Figure 9.10.
a single point at the coordinates (x, y) with the following call: An interesting pattern
with points.
Display *p_disp; /* The connection to the X server */
Window window_1; /* The drawable--a window */
GC thisGC; /* Graphics context for the drawing */
int x, Jj /* Point to be drawn */

The pixel at the location is set to the foreground color specified in the GC. Other attributes in the GC
also control the final appearance of the point. For example, the point is not drawn if it lies outside
the clip mask.

Drawing Multiple Points


If you want to draw a large number of points, all using the same GC, you can use the XDrawPoints
function to draw them all at once with a single X protocol request. You store the points in an array
ofXPoint structures. The XPoint structure is defined in <X11 /Xlib. h> as the following:
typedef struct
{
short x, y;
XPointj

You call XDrawPoints in the usual manner with a display, a drawable, and a GC as the first three
arguments:

XPoint pt [10] ;
int numpt ~ 10; /*----------. - - ------- -.- */
/* File: xpoints.c
XDrawpoil1ts(p_disp, window_1, thisGC, pt, numpt,
CoordModeOrigin); Draw an interesting pattern using a seemingly random
process (illustrates use of XDrawPoint and XDrawPoints)
# Makefile for "xpoints" shown in Listing 9.1
#
# Some common definitions ...

RM rm-f
CC cc

CFLAGS =
INCLUDES = -I. -I/usr/include -I/usr/include/Xll
LIBS = -IXll

# Rule to create .0 files from .c files


. c .0:
$(RM) $@
$(CC) -c $(CFLAGS) $(INCLUDES) $*.c

xpoints: xpoints.o initapp.o xwinutil.o xbutton.o


$(RM) $@
$(CC) -0 $@ $(CFLAGS) xpoints.o initapp.o \
xwinutil.o xbutton.o \
$(LIBS)

In addition to xpoints. c (Listing 9.1), you need the following files from Chapters 7, "Creating
and Managing Windows," and 8, "Handling Events," to build the xpoints program:

• app_glob.c (Chapter 7, Listing7.l)


• ini tapp. c (Chapter 7, Listing 7.2)
• xwins. h (Chapter 8, Listing 8.1)
• xwinutil. c (Chapter 8, Listing 8.2)
• xbutton. c (Chapte~ 8, Listirig~.3)

:f/ Drawing Lines


, There are~rawing functions:...

• XDrawLine
• XDrawSegments
• XDrawLines
You can draw several rectangles using the same GCby calling XDrawRectangles, which expects an
array of tectangles and their number as arguments: •.
~ XDrawLine(p_disp, window, thisGC, x1, y1, x2, y2); XRectangle rect[]; 1* Array of rectangles *1
int nrect; 1* Number of rectangles *1
draws a line betw.een the points (x1, y1) and (x2, y2) in the drawable, window, using the line
attributes specified in the GC,thisGC.

XD!,awSegments~draw~sever~ possibly disjointed line segments using the same graphics attributes. In this example, XRectangle is a srrucrure for storing the parametets of a recrangkjlnd is defined
The segments ate speCified USIngthe x.s..egm~structute, which is defined in <X11/ Xlib. h> as the in <X11/Xlib. h> as follows:
following: .. .._~-.
typedef struct
typedef struct {
{ short x, y; 1* Upper-left corner *1
short x1, y1; unsigned short width, height; 1* Width and height *1
1* Coordinates of start-point of segment *1
short x2, y2; XRectangle;
1* Coordinates of end-point of segment *1
XSegment;
You can draw a filled rectangle ~y calling the XFillRectangle function. Call this function the same
An array of segments is passed as an argument to X!?l:awSegments: way you do XDrawRectangle, with exactly the'Same arguments:When you draw a filled rectangle,
Display *p_disp; \ - the width and height of the filled area is exactly the width and height specified in the call to
Window window_1; xFilfRecta~gle.
GC thisGC;
XSegment lines!] = XFill~c;angles)s the function for drawing multiple filled rectangles. It is analogous to
{
xDrawRectangles and is called with the same arguments.
{100, 100, 200, 200},
{10, 20, 35, 60},
{300, 10, 300, 100}
}; ~ Drawing Polygons
int numsegs = sizeof(lines) I sizeof(XSegment);
A polygon is a figure enclosed by multiple lines. To draw the outline of a polygon, use the XDrawLines
function. For filled polygons, Xlib provides the XFillPolygon function:
XDrawSegments(p_disp, window_1, thisGC, lines, numsegs);
int shape; 1* One of: Convex, NonConvex, or Complex *1
The ~awLines functiQ!!..is.;;imilarto XDrawPoints with one difference: XDrawPoints draws points, int mode; 1* One of: CoordModeOrigin or CoordModePrevious *1
and XDraw~lnes con~ects them with a line. You call XDrawLines with the same arguments as you XPoint points[]; 1* Vertices of the polygon *1
do XDrawPoints .. ,......,~--;-.:-.,.----- int numpoints; 1* How many vertices *1

~en you draw a line using XDrawLine or XDrawSegments, the server also draws endeaps for each XFillPolygon(p_disp, window, thisGC, points, numpoints,
lIne segment. For XDrawLines, the endcaps appear only at the very beginning and at the very end. shape, mode);

You specify the vertices of the polygon in an array ofXPoint structures just as you do when draw-
Drawing and Filling Rectangles ing multiple points with XDrawPoints (see example program in Listing 9.1). The mode argument
is also interpreted the same way as it is for XDrawPoints.
Xlib inclu~es several func~ions to ~raw rectangles. The xDf;;Becta9~e function is for drawing a ~
rectangle given the coordInates of ItS upper-left corner an ~s width and height. The following is The shape argument helps the server optimize the filling algorithm. Specify Convex for this argu-
the function call: ment only if.your polygon is such that a line drawn between any two internal points lies entirely
inside the polygon. For example, triangles and rectangles are convex shapes.
XDrawRectangle(p_disp, window, thisGC, x, y, Width, height);
If the shape is not convex, but none of the edges intersect each other, you should use NonConvex as
To draw the outline around the rectangle, this function draws the following lines: the shape argument. For polygons with intersecting edges, use Complex. Note that if you are not
(x, y) to (x+width, y) sure about a polygon, you can safely specify Complex as the shape. The drawing may be a bit slower,
(x+w1dth, y) to (x+width, y+height) but the result will be correct.
(x+W1dth, y+height) to (x, y+height)
(x, Y+height) to (x,y) The fill rule in the GCdetermines which points are filled by XFillPolygon. You can set the fill rule
by calling XSetFillRule.
(Drawing Arcs, Circles, and Ellipses /'

In X, arcs, ellJpses, and ~Irclesare handled by the arc drawing functions: XDrawArcand XDrawArcs. If you have to draw more than one arc, use the XDrawArcs function. This function is used like its
Use the first one for a smgle arc, the latter for a number of arcs. counterparts XDrawPoints and XDrawRectangles. Each arc is specified in an XArcstructure, which
is defined in <X11/ Xlib. h> as follows:
You can think of the arc as a part of an ellipse. As shown in Figure 9 11 d . h . I
'fy' rawmg t e arc mvo ves typedef struct
s.peci mg ~he b!!.""!.:,:!m! rect.:!ngle, which is the smallest rectangle that compr~tely eOnclosesthe el-
0 • ,

{
IJpse to which the arc 5e1ongs. Specify the rectanp-lewith the coordinatpc of tL I_C- short .x, y; /* Parameters of the * /
. d h d' . ~p.p~corner,
o. .~_

'_J> -- --....:...- "'---


(x, y), an t e ImenSlOnsof the rectangle, widt~d height. Indicate the angle, where the ;rc unsigned short width, height; /* bounding rectangle * /
short angle1, angle2; /* Start and extent */
starts, angle1, as well as its angular extent, ~. -==- XArc;

Figure 9.11.
Specifjing an arc in X XArc arcs [1 ; / * The arcs (maybe ellipses or circles) * /
int numarcs; /* How many arcs in the array... */
(x,y)

~ • ~~h •

tr~~~
Drawing Filled Arcs
, -___ ./X 1'\ angle1 You can use XFillArc to draw a filled arc. The filling is done using the foreground color and fill
height - -"'- _ !: -:.) J _ style specified in the GC.The filled arc looks like a pie-shaped wedge if the arc_mode graphics at-

!
tribute is set to ArcPieSlice. If the arc_mode is ArcChord, the X server fills the area within the
curved edge of the arc and the chord joining its endpoints. You can alter the arc_mode by calling
---------------- the XSetArcMode function.
For filling multiple arcs, use the XFillArcs function. You call XFillArc and XFillArcs the same
way you call XDrawArc and XDrawArcs, respectively .
.,c' ~ X;"-
Creating a Simple Drawing Program
The simple drawing program, xfigures, shown in Listing 9.2, enables die user to draw one offive
The X server draws the arc: basic Igures:li~ectangle~elli~fiikd rectangle, and filled ellipse. The choices are presented in
a menubar implemented using the xmenu. c file shown in Listing 8.7. The user selects a figure and
1. ~he star~ angle, angle 1, m.easured counterclockwise, with 0 degrees along the three
o clock lme, defines the pomt where the arc begins. starts drawing by moving the cursor to the drawing area and pressing down a mouse button to in-
dicate the starting point of the figure. The drawing is completed by moving the mouse to the de-
2. ~he serv~r.starts tracing over the ellipse from this point on, in a counterclockwise direc-
sired endpoint (with the button pressed) and releasing the button.
tion, until It covers the angular extent given by angle2.

The angles angle 1 and angle2 are integer values that specify angles in units of 1/64-degre Th
Drawing Rubber-Band Figures
;0 dra,:" an arc 60 degrees wide, starting at 30 degrees from the three o'clock direction ' youe~allt~S~
rollowmg: In xfigures (as in most drawing programs for the Macintosh or Microsoft Windows), rubber-
XDrawArc(p_diSp, window, thisGC, x, y, Width, height banding occurs when the user moves the mouse while pressing a button. That is, the figure expands
30*64, 60*64); , or contracts in keeping with the mouse movements.
You ca~ draw an ellipse .by starting at 0 degrees and specifying an extent of 360x64. If the width The key to rubber-banding is to set up a GCwith the function attribute set to GXxor. Here is how
and height of the boundmg rectangle are equal, you get a circle. it is done in xfigures. c:
Listing 9.2. continued
} Generation of Expose Events
1*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .. - - - - - T * I
static void draw_figure(d, w, gc, curfig) The server generates Expose events when any of your application's windows need redrawing. This
Display *d; can happen when the window is first mapped, when an obscuring window is moved, or when you
Window w;
GC gc; clear an area of a window by calling XClearArea.
int curfig;
{
In most applications, all drawing occurs in reponse to Expose events. This is because you cannot
int x1 figures[curfig).x1, y1 figures[curfig) .y1, draw in a window until it is ready and there is no good way of knowing when it is ready. However,
x2 figures[curfig) .x2, y2 figures[curfig).y2, t; when you receive an Expose event for a window, you can be sure that it is ready for use.
1* Make sure x2 >= x1 and y2 >= y1 *1 When parts of a window need redrawing, the server generates an Expose event for every rectangu-
if(figures[curfig).type != LINE && x1 > x2)
{
lar region that is exposed. When you retrieve an Expose event by calling one ofXlib's event re-
t = x1; trieval functions (XNextEvent, for instance), the relevant information is in an XExposeEvent data
x1 x2; structure (accessed as the xexpose member of the XEvent union):
x2 = t;
} typedef struct
if(figures[curfig).type 1= LINE && y1 > y2) {
{ int type; 1* Event's type *1
t = y1; unsigned long serial; 1* Last processed request number *1
y1 y2; Bool send_event; 1* True means from a SendEvent *1
y2 = t; Display *display; 1* Display where event occurred */
} Window window; 1* Window that needs redrawing *1
sWitch(figures[curfigj .type) int x 'Y;
J 1* Origin and dimensions of the *1
{ int width, /* rectangle that has been *1
case LINE: height; 1* "exposed" *1
XDrawLine(d, w, gc, x1, y1, x2, y2); int count; I*Number of Expose events to come*1
break; XExposeEvent;
case RECT:
XDrawRectangle(d, w, gc, Xl, y1, x2-x1, y2-y1); The members x, y, width, and height identifY the rectangle whose contents are lost and have to be
break; redrawn. The last member of the structure, count, tells you how many more Expose events for the
case ELLIPSE:
XDrawArc(d, w, gc, x1, y1, x2-x1, y2-y1, 0, 360*64); same window are yet to arrive. Knowing this, you can devise a simple strategy for handling Expose
break; events.
case FILLRECT:
XFillRectangle(d, w, gc, x1, y1, x2-x1, y2·y1); Wait for the Expose event with count equal to O. Then, clear the entire window and redrawevery-
break;
thing in the window. In other words, you are ignoring the information about the specific parts that
case FILLELLIPSE:
XFillArc(d, w, gc, x1, y1. x2-x1, y2-y1, 0, 360*64); need refreshing and simply updating the whole window.
break;
Handling Expose events on count 0 works well for simple drawings, but for complex drawings, it
is better to make use of the information on the rectangle that needs redrawing. One method is to
use a region. You can use XUnionRectWi thRegion to add all the rectangles in a region. Set the clip-
ping mask of the drawing GCwith XSetRegion. Then redraw when the Expose event with count
o arrives. For maximum efficiency, your application's drawing function must be smart enough to
draw only within the regions. Because the server clips against the region, there is no harm in draw-
Handling Expose Events ing everything, but that sends unnecessary graphics requests and wastes time. The viewfile pro-
Because handling Expose events are an important part of displaying output in a window, this sec- gram in Chapter 10 demonstrates the use of this technique.
tion includes a discussion of the Expose, GraphicsExpose, and NoExpose events. You have en-
Countered Expose events in the example programs. GraphicsExpose and NoExpose events become
necessary when copying a rectangular region from one window to another. Clearing Windows and Areas
If you have all output operations in the block of code that handles Expose events, how do you handle
the need to refresh the window on purpose? The server sends Expose events only when some pre-
viously hidden parts of a window become visible again. One way to redraw the window is to clear Figure 9.13.
an area and force an Expose event. You can use the XClearArea function for this purpose: GraphicsExpose and Destination GraphicsExpose
NoExpose events. event generated
for these regions
\- - K'"'" "SJ - - - - - -

The arguments x, y, width, and height specifYthe rectangular area to be cleared. The server gen-
erates an Expose event for this rectangle if the last argument is nonzero (True).
If you specifYOsfor the width and height, the server clears the entire window. Thus, a common
method of forcing a redrawing of a window is to call XClearArea:
'"~:~D~~~
If the last argument in the call is False, the server clears the window without generating an Expose
event. The function call, XClearWindow( p_disp, window), serves the same purpose.

Area Copying
Xlib provides two functions for copying parts of one drawable to another. You can use XCopyPlane
Destination
to copy one or more selected bit planes from one rectangle to another. NoExpose

\- - - - - - - - - - - - - -I event generated

-1:]
The XCopyArea function, on the other hand, copies all pixel values from one rectangular area to in this case

another. You can copy from a window to a pixmap and vice versa. The source rectangle (the one I I
I I
you are copying from) can overlap the destination. Thus, you can use XCopyArea to move the con- I
- ---- I

tents of a window up, for instance. The viewfile program in Chapter 10 shows how to imple- Source

"
ment scrolling using the XCopyArea function.
,- - - ~ - - - - - - - -I
The XCopyArea function is often used to copy the contents of a window to a pixmap and to scroll
windows. XCopyPlane can be used to overlay images.
I
I
I
~;;/:i~.
;c. .; .•... , .,,0
I
I
Window 3

------------- I

GraphicsExpose Events
One consequence of the graphics copy operation is that sometimes the contents of the entire source
rectangle may not be available. For instance, consider Case A of Figure 9.13, which shows copying
from one rectangle to another in Window 1. Windows 2 and 3 are overlapping Window 1. More The graphics_exposures attribute in a GCcontrols whether GraphicsExpose events are sent by
importantly, Windows 2 and 3 are obscuring parts of the source rectangle. If you attempt an the server. They are enabled by default, but you can turn them off by using the
XCopyPlane or XCopyArea for the geometry shown in Case A of Figure 9.13, the server cannot XSetGraphicsExposures function. For example, to turn them off in a specific GC,call-the follow-
copy anything into the hatched areas of the destination rectangle because those parts of the source ing:
are obscured. In this case, the server generates a GraphicsExpose event for the hatched rectangles.
This is the server's way of informing your application that the contents of those areas in the desti-
nation have to be redrawn in some other way.

For the situation shown in Case B of Figure 9.13, there are no problems because all visible areas of
the destination can be filled by the server. In this case, the server sends a NoExpose event indicating
that copy is successful.