For clipping, any number of rectangles can be used. However, the result is guaranteed to be correct only if they are non-intersecting. The most general way of implementing clipping uses a pixmap with depht 1. In this pixmap, black pixel represents points not to be copied, and white pixel are points that will be copied. After creating such a pixmap, it can be included in the graphic context using the function XSetClipMask. This is what is done in the module clipbit.c. First of all, we need a bitmap (a pixmap with depth 1), and a graphic context for it:
/* create the clipping mask */ clip_mask = XCreatePixmap(dpy, double_buffer, wa.width, wa.height, 1); gc=XCreateGC (dpy, clip_mask, 0, NULL);Each point of this bitmap tells X which pixels to copy when XCopyArea is called: a pixel set to 0 in this bitmap means that the pixel of the same coordinates is not to be copied, while a pixel set to 1 means ``copy''.
At each step, we first clean the bitmap (so points will not be copied by default):
/* clear clipping mask */
XSetBackground(dpy, gc, 0);
XFillRectangle(dpy, clip_mask, gc, 0, 0, wa.width, wa.height);
Each time we draw something in the double
buffer, we write 1 in the same points of the clipping
mask to indicate that this region has been changed in the buffer,
so it is to be copied. The erasure of the ball from the
old position becomes:
/* remove the ball from the screen */
XSetForeground(dpy, g, BlackPixelOfScreen(DefaultScreenOfDisplay(dpy)));
XFillArc(dpy, double_buffer, g, x, y, 40, 40, 0, 360*64);
/* region changed, set mask */
XSetForeground(dpy, gc, 1);
XFillArc(dpy, clip_mask, gc, x, y, 40, 40, 0, 360*64);
While the redraw in the new position is:
/* draw in the new position */
XSetForeground(dpy, g, reds.pixel);
XFillArc(dpy, double_buffer, g, x, y, 40, 40, 0, 360*64);
/* region changed, set mask */
XSetForeground(dpy, gc, 1);
XFillArc(dpy, clip_mask, gc, x, y, 40, 40, 0, 360*64);
Before actually doing the copy, we have to specify that
clip_mask is clipping mask we want to use. This
is what XSetClipMask does:
/* set clipping mask */
XSetClipMask(dpy, g, clip_mask);
/* copy the buffer to the window */
XCopyArea(dpy, double_buffer, root, g, 0, 0, wa.width, wa.height, 0, 0);
Note that gc is the graphic context to use for
drawing in the bitmap. This means that all operations on
the bitmap must use gc instead of g.
Copying an area is instead an operation on the window
and the pixmap, so the graphics context it uses is g.
The clipping mask is an element of g, and this is
why g is the second argument we pass to
XSetClipMask. This just to say that some care has
to be taken for not confusing the graphics contexts.