[comp.windows.x] problem with clipping on color displays

luke@umnstat.stat.umn.edu (Luke Tierney) (10/13/89)

I have run into a problem with clipping in X on color displays and was
wondering if anyone out there might be able to help.

I have a program that uses an offscreen Pixmap to construct an image
and then copies that image into a window. To make some things easier I
want to be able to clip some of the drawing in the pixmap and the
window to a rectangle. The code I have seems to work fine on
monochrome displays but not on color sun or DEC3100 displays. I have
narrowed the problem down to the attached short program.

The program opens a window.  It uses two GC's, one for erasing and one
for drawing. The ease_gc has both fore and background color set to
WhitePixel, the drawing gc has fore color set to BlackPixel and
background to WhitePixel.

The window handles only Expose and ButtonPress events. On an expose
event it

	clips the gc's to the size specified for the window
	erases a rectangle in the the Pixmap by filling with erase_gc
	fills the same rectangle with black using gc
	copies the rectangle to the window with XCopyArea

On a ButtonPress event it does the same thing but without the
clipping.  The idea is that the clip region should not have changed
since it was set in response to an Expose event. The routine doing the
drawing is called `draw'. Expose events call it with clip=TRUE,
ButtonPress events with clip=FALSE.

On a color sparcstation running MIT R3 with fixes and using twm or
olwm as the window manager the window comes up black, as it should,
but when I click the mouse in it only the lower right two thirds are
black, the rest is white.
	
Exactly how much is black seems to depend on where the window is
placed.  Under olwm if the window is forced to appear at the top left
corner of the screen the amount of the shift in the black area seems
to be equal to the border width in the horizontal and the height of
the title bar in the vertical direction.

The problem does not occur if I use only one gc and change its fore
color before each XFillRectangle call.

Here is the code; any help would be greatly appreciated.

------------------
#include <X11/Xlib.h>
#include <stdio.h>

#define TRUE 1
#define FALSE 0

#define TOP 100
#define LEFT 100
#define WIDTH 400
#define HEIGHT 400

Display *dpy;
int screen;
GC gc, erase_gc;
Pixmap WorkPort;
Window win;

main()
{
  char *display_name = NULL;
  unsigned long valuemask;
  XGCValues values;
  XEvent report;

  /* connect to X server */
  if ((dpy = XOpenDisplay(display_name)) == NULL) {
    fprintf(stderr, "%s: can't connect to X server %s\n", "bug",
	    XDisplayName(display_name));
    exit(-1);
  }

  /* get the default screen */
  screen = DefaultScreen(dpy);
  
  /* make GC's */
  valuemask = 0; /* ignore XGCValues and use defaults */
  gc = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  XSetForeground(dpy, gc, BlackPixel(dpy, screen));
  XSetBackground(dpy, gc, WhitePixel(dpy, screen));

  erase_gc = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  XSetForeground(dpy, erase_gc, WhitePixel(dpy, screen));
  XSetBackground(dpy, erase_gc, WhitePixel(dpy, screen));

  /* create the window */
  win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
			    LEFT, TOP, WIDTH, HEIGHT, 1,
			    BlackPixel(dpy, screen), 
			    WhitePixel(dpy, screen));
  XSelectInput(dpy, win, ExposureMask | ButtonPressMask);

  /* Display (map) the window */
  XMapWindow(dpy, win);

  MakeWorkPort();

  while (TRUE) {
    XNextEvent(dpy, &report);
    if (win == report.xany.window) {
      switch(report.type) {
      case Expose: if (report.xexpose.count == 0) draw(TRUE); break;
      case ButtonPress: draw(FALSE); break;
      default:
	break;
      }
    }
  }
}

/**************************************************************************/
/**                                                                      **/
/**                           Drawing Functions                          **/
/**                                                                      **/
/**************************************************************************/

draw(clip) 
     int clip;
{
  XRectangle r;

  if (clip) {
    r.x = 0;
    r.y = 0;
    r.width = WIDTH;
    r.height = HEIGHT;
    XSetClipRectangles(dpy, gc, 0, 0, &r, 1, Unsorted);
    XSetClipRectangles(dpy, erase_gc, 0, 0, &r, 1, Unsorted);
  }
  XFillRectangle(dpy, WorkPort, erase_gc, 0, 0, WIDTH, HEIGHT);
  XFillRectangle(dpy, WorkPort, gc, 0, 0, WIDTH, HEIGHT);
  XCopyArea(dpy, WorkPort, win, gc, 0, 0, WIDTH, HEIGHT, 0, 0);
}

/**************************************************************************/
/**                                                                      **/
/**                         Buffering Functions                          **/
/**                                                                      **/
/**************************************************************************/

MakeWorkPort()
{
  int width, height;

  width = DisplayWidth(dpy, screen);
  height = DisplayHeight(dpy, screen);
  WorkPort = XCreatePixmap(dpy, RootWindow(dpy, screen),
			   width, height, DefaultDepth(dpy, screen));

  /* it is not clear whether this is the proper error check */
  if (WorkPort == NULL) {
    fprintf(stderr, "work port allocation failed");
    exit(-1);
  }
}

rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (10/13/89)

    On a color sparcstation running MIT R3 with fixes and using twm or
    olwm as the window manager the window comes up black, as it should,
    but when I click the mouse in it only the lower right two thirds are
    black, the rest is white.

Works fine on an R4-server-to-be.  Looking at our logs, it appears that
we have fixed a clipping bug in the cfb code, when switching a gc
between a window and a pixmap, but I don't have an easy way of generating
a simple diff for you, sorry.