Clipping origin

The module cliporigin.c uses a clipping mask which is much smaller than the screen. This may save memory in cases in which only part of the screen is modified between two shots. In the case of the ball of ball.c, only the region around the ball is modified when the ball is moved, so there is no need to allocate a clipping mask as large as the whole screen.

In the previous page we have seen how the clipping mask can be given using a bitmap. In particular, the bitmap was as large as the double buffer. In fact, the clipping mask may be smaller than that. If this is the case, only the upper-left region is copied. The general rule is: all points that are inside the clipping mask, and are set to 1 in the clipping mask, are copied.

In the case of the ball, the area to be copied is always small, as the part of the screen that changes between two consecutive shots is only the one around the ball. This means that we can use a small clipping mask, but also that we have to specify that this clipping mask does not refer to the upper-left corner of the screen. In Xlib, this is done by setting the clipping origin, which is a point of the area to be copied. The command to tell X that the clipping origin is (x,y) is: XSetClipOrigin(dpy, g, x, y). This tells Xlib that, whenever an area is copied using the graphic context g, the clipping mask is to be positioned with its origin (left-upper point) in the point of coordinates (x,y). In other words, the upper-left point of the clipping mask (the one of coordinates (0,0) in the clipping mask) tells X whether the point of coordinates (x,y) is to be copied or not, the point on its right (coordinates (1,0) in the clipping mask) tells whether to copy the point (x+1,y) and so on. Executing instruction XSetClipOrigin(dpy, g, x, y) is like moving the clipping mask from the origin (0,0) to the point (x,y).

In order to use a clipping mask, it must be created. It must be large enough to contain all points that may be changed between two successive shots. Since the ball is inside a square whose edge is 40 pixel long, and it is moved by one position at time, a squared area of edge 42 is always large enough to contain all pixels of the old and new positions of the ball. As a result, we can allocate a bitmap (pixmap of depth 1) of edge 42 to be the clipping mask. Not all points of this area needs to be copied, so only a part of the points of the bitmap have to be set to 1. However, we set all of them to 1 for simplicity.

  /* create the clipping mask */
  clip_mask = XCreatePixmap(dpy, double_buffer, 42, 42, 1);
  gc=XCreateGC (dpy, clip_mask, 0, NULL);

  /* fill the clipping mask with 1 */
  XSetForeground(dpy, gc, 1);
  XFillRectangle(dpy, clip_mask, gc, 0, 0, 42, 42);

  /* set it to be the clipping mask of g */
  XSetClipMask(dpy, g, clip_mask);

This square is now the clipping mask of the graphic context g. In other words, if a copying operation is done using g, we are copying only the points in the square of edge 42, and whose upper-left corner is in (0,0). Since the points to be copied may be in other parts of the screen, we have to specify a different position for this square. This is done by setting the clipping origin.

Since the new position of the ball is (x,y), a square whose upper-left corner is in (x-1,y-1), and have edge 42, always contains all points of the old and the new position of the ball. As a result, we can set the clipping origin in (x-1,y-1) right before copying the area.

      /* move the clip mask */
      XSetClipOrigin(dpy, g, x-1, y-1);

This completes the module cliporigin.c.

Next: redrawing under other windows.