[comp.windows.x] Mouseproofing

tsf@theory.cs.cmu.edu (Timothy Freeman) (06/23/87)

Ever had the problem where your application doesn't read mouse events
for a while, but the user keeps generating them anyway, then
eventually the pipes fill up and the X server destroys all your
windows?  Since I like to use X with lisp, this used to happen quite
often, because during program development we spend a lot of time
dealing with bugs and thus not reading mouse events.

Well, at the cost of running one extra process and having one more
file descriptor open, I have a fix for that.  Here is a shar of the
files in the XV10R4 distribution I changed to get this to work.  The
files are:

XOpenDisplay.c   \
Xlib.h            \  All these replace files from the Xlib distribution
XlibInternal.c    /
XlibInternal.h   /
xdiffs               Context diffs between my version of the above
                     files and the originals.
quick.c              A little test program.  It opens a window and
                     doesn't read mouse events from it.  You can wave
                     your mouse at the window as long as you want, and
                     the server won't hang or kill the window.
xmouseproofserver.c  The extra process used.  Compile this and put it
                     somewhere on your path.

If you take these files and put them in the relevant places and
rebuild libX.a, then you have a new routine named "XProofOpenDisplay"
which has exactly the same interface as XOpenDisplay except that the
display connection is guaranteed not to be closed due to filling up
with unread mouse events.  The extra mouse events will be discarded.

If those people who understand how the X server works would build this
into the server, that would be great.

The old version of XOpenDisplay had an obnoxious habit of killing your
program if it tried to open a display which it was not permitted to
open due to the access list controlled by the xhost program.  This
version of XOpenDisplay returns 0 in this case, and errno is set to
reflect a broken pipe error.

This code is known to work on a Sun 3 running release 3.3 of Sun's
operating system.  It uses sigvec and longjmp, which may cause
problems for some people.  Other than this, it ought to work on other
operating systems.

#
# type    sh thenameofthefileyouputthistextinto   to unpack this archive.
#
echo extracting XOpenDisplay.c...
cat >XOpenDisplay.c <<'!E!O!F!'
#include <X/mit-copyright.h>
/* $Header: XOpenDisplay.c,v 10.12 86/12/24 09:07:53 swick Exp $ */
/* Copyright    Massachusetts Institute of Technology    1985	*/
 
#include "XlibInternal.h"
#include <sys/socket.h>
#include <strings.h>
#include <sys/un.h>
#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>

/*This routine determines whether a given error code represents an error.  
If it does, then we print an error message and bomb.  If it doesn't, then
the code is the returned value of check.*/

static int check (code)
int code;
{
  if (code < 0) {
    fprintf (stderr, "Unanticipated error:\n");
    perror ("");
    exit (1);
  }
  return (code);
}

jmp_buf env;

/* This is the X error handler.  We define an X error handler for the */
 /* duration of the display open operation so we can trap broken pipe */
 /* errors.  Broken pipe errors happen whenever you try to open a */
 /* display which has a server running on it, but you aren't on the */
 /* server's host list.  This is fairly frequent, so we want to be */
 /* able to handle the error instead of bombing. */
int myhandler (disp)
     Display *disp;
{
  longjmp (env, 1);
}

Display *IntXOpenDisplay (display, proofp)
	register char *display;
{
	register Display *dpy;		/* New Display object being created. */
	char displaybuf[256];		/* Display string buffer. */
	register char *displayptr;	/* Display string buffer pointer. */
	char buf[4];			/* place to form display string */
	struct sockaddr_in inaddr;	/* INET socket address. */
	struct sockaddr_un unaddr;	/* UNIX socket address. */
	struct sockaddr *addr;		/* address to connect to */
	int addrlen;			/* length of address */
	int dispnum;			/* display number. */
	int indian;			/* to determine which indian. */
	struct hostent *host_ptr;
#ifdef DNETCONN
	char objname[20];		/* Object name buffer */
	int dnet = 0;			/* flag to indicate DECnet connect */
#endif
 
	register XReq *req;		/* XReq request packet pointer. */
	XRep rep;			/* XRep reply packet. */
	struct sigvec ovec;             /* Used to hold previous state of SIGPIPE signal. */
 
	/* External declarations. */
	extern char *getenv();
	extern char *malloc();
	extern struct hostent *gethostbyname();

	/*
	 * Extract the host name and display number from the display
	 * specifier string.  The display specifier string is supplied
	 * as an argument to this routine.  If it is NULL or a pointer
	 * to NULL
	 */
	if (display == NULL || *display == '\0') {
		strncpy (displaybuf, XDisplayName(display), sizeof(displaybuf));
		if (*displaybuf == '\0') return (NULL);
	}
	else {
		/* Display is non-NULL, copy it into the display buffer. */
		strncpy(displaybuf, display, sizeof(displaybuf));
	}
	/* 
	 * Find the ':' seperator and cut out the hostname and the
	 * display number.
	 * NOTE - if DECnet is to be used, the display name is formated
	 * as "host::number"
	 */
	if ((displayptr = index(displaybuf,':')) == NULL) return (NULL);
#ifdef DNETCONN
	if (*(displayptr + 1) == ':') {
	    dnet++;
	    *(displayptr++) = '\0';
	}
#endif
	*(displayptr++) = '\0';
 
	/* displaybuf now contains only a null-terminated host name;
	 * displayptr points to the display number */
 
	/* If the display number is missing there is an error.
	 * Otherwise, convert string to an integer we can use */
	if (*displayptr == '\0') return(NULL);
	dispnum = atoi(displayptr);
 
	check (sigvec (SIGPIPE, 0, &ovec));
	check (signal (SIGPIPE, SIG_IGN));
	if (setjmp (env)) {
	  check (sigvec (SIGPIPE, &ovec, 0));
	  return (0);
	}
	XIOErrorHandler (myhandler);
	if (strcmp("unix", displaybuf) == 0) {
	    /* Connect locally using Unix domain. */
	    unaddr.sun_family = AF_UNIX;
	    strcpy(unaddr.sun_path, X_UNIX_PATH);
	    strcat(unaddr.sun_path, displayptr);
	    addr = (struct sockaddr *) &unaddr;
	    addrlen = strlen(unaddr.sun_path) + 2;
	} else {
#ifdef DNETCONN
	    if (!dnet) {
#endif
		/* If the hostname is missing default to the local host. */
		if (displaybuf[0] == '\0')
		    gethostname (displaybuf, sizeof (displaybuf));
		/* Get the statistics on the specified host. */
		if ((inaddr.sin_addr.s_addr = inet_addr(displaybuf)) == -1) {
			if ((host_ptr = gethostbyname(displaybuf)) == NULL) {
				/* No such host! */
				errno = EINVAL;
				check (sigvec (SIGPIPE, &ovec, 0));
				return(NULL);
			}
			/* Check the address type for an internet host. */
			if (host_ptr->h_addrtype != AF_INET) {
				/* Not an Internet host! */
				errno = EPROTOTYPE;
				check (sigvec (SIGPIPE, &ovec, 0));
				return(NULL);
			}
 
			/* Set up the socket data. */
			inaddr.sin_family = host_ptr->h_addrtype;
			bcopy((char *)host_ptr->h_addr, 
			      (char *)&inaddr.sin_addr, 
			      sizeof(inaddr.sin_addr));
		} else {
			inaddr.sin_family = AF_INET;
		}
		addr = (struct sockaddr *) &inaddr;
		addrlen = sizeof (struct sockaddr_in);
		inaddr.sin_port = dispnum;
		indian = 1;
		if (*(char *) &indian)
		    inaddr.sin_port += X_TCP_LI_PORT;
		else
		    inaddr.sin_port += X_TCP_BI_PORT;
		inaddr.sin_port = htons(inaddr.sin_port);
#ifdef DNETCONN
	    } else {
		/* If the nodename is missing default to the local node. */
		if (displaybuf[0] == '\0')
		    strcpy (displaybuf, "0");
		/* build the target object name. */
		sprintf (objname, "X%d", dispnum);
	    }
#endif
	}
 
	/* Malloc the new Display. */
	if ((dpy = (Display *)malloc(sizeof(Display))) == NULL) {
		/* Malloc call failed! */
		errno = ENOMEM;
		check (sigvec (SIGPIPE, &ovec, 0));
		return(NULL);
	}
 
	dpy->height = dpy->width = 0;
	    /* If DisplayWidth or DisplayWidth is subsequently called,
	       these will be replaced by "real" values. */
 
	/* Open the network socket. */
#ifdef DNETCONN
	if (!dnet) {
#endif
	    if ((dpy->fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) {
		    /* Socket call failed! */
		    /* errno set by system call. */
		    free ((char *)dpy);
		    check (sigvec (SIGPIPE, &ovec, 0));
		    return(NULL);
	    }
 
	    /* Open the connection to the specified X server. */
	    if (connect(dpy->fd, addr, addrlen) == -1) {
		    /* Connection call failed! */
		    /* errno set by system call. */
		    close (dpy->fd);
		    free ((char *)dpy);
		    check (sigvec (SIGPIPE, &ovec, 0));
		    return(NULL);
	    }
#ifdef DNETCONN
	} else {
	    if ((dpy->fd = dnet_conn(displaybuf, objname, SOCK_STREAM, 0, 0, 0, 0)) < 0) {
		    /* connect failed! */
		    /* errno set by dnet_conn. */
		    free ((char *)dpy);
		    check (sigvec (SIGPIPE, &ovec, 0));
		    return(NULL);
	    }
	}
#endif
	if (proofp) {
	  int fd = dpy -> fd;
	  int readpipes [2], writepipes [2];

	  check (pipe (readpipes));
	  check (pipe (writepipes));
	  if (check (vfork ())) {
	    /* Parent */
	    close (readpipes [1]);
	    dpy -> fd = readpipes [0];
	    close (writepipes [0]);
	    dpy -> writefd = writepipes [1];
	  } else {
	    /* Child */
	    check (close (readpipes [0]));
	    check (close (writepipes [1]));
	    check (dup2 (readpipes [1], 1));
	    check (dup2 (writepipes [0], 0));
	    check (close (readpipes [1]));
	    check (close (writepipes [0]));
	    check (dup2 (fd, 4));
	    check (close (fd));
	    /* Make sure the socket stays open when the server executes. */
	    check (fcntl (4, F_SETFD, 0));
	    execlp (MOUSEPROOFSERVER, 0);
	    fprintf (stderr, "Couldn't run server %s.\n", MOUSEPROOFSERVER);
	    _exit (1);
	  }
	}

	dpy->mouseproofedp = proofp;
 
	/* Salt away the host:display string for later use */
	buf[0] = ':';
#ifdef DNETCONN
	{
	    int b = 1;
	    if (dnet) buf[b++] = ':';
	    buf[b++] = '0' + dispnum;
	    buf[b] = '\0';
	}
#else DNETCONN
	buf[2] = '\0';
	buf[1] = '0' + dispnum;
#endif DNETCONN
	strcat(displaybuf, buf);
	if ((dpy->displayname = malloc(strlen(displaybuf) + 1)) == NULL) {
		close (dpy->fd);
		free ((char *)dpy);
		errno = ENOMEM;
		check (sigvec (SIGPIPE, &ovec, 0));
		return(NULL);
	}
	strcpy (dpy->displayname, displaybuf);
 
	/* Set up the output buffers. */
	if ((dpy->bufptr = dpy->buffer = malloc(BUFSIZE)) == NULL) {
		/* Malloc call failed! */
	    	close (dpy->fd);
		free ((char *)dpy);
		errno = ENOMEM;
		check (sigvec (SIGPIPE, &ovec, 0));
		return(NULL);
	}
	dpy->bufmax = dpy->buffer + BUFSIZE;
 
	/* Set up the input event queue and input event queue parameters. */
	dpy->head = dpy->tail = NULL;
	dpy->qlen = 0;
	/* Initialize MouseMoved event squishing. */
	dpy->squish = 1;
 
	_XlibCurrentDisplay = dpy;
 
	/* Send an X_SetUp request to the server. */
	GetReq(X_SetUp, 0);
 
	/* Send X_MakePixmap requests to get black and white
         * constant tile Pixmaps */
        GetReq(X_MakePixmap, 0);
	req->param.l[0] = 0;  /* no bitmap */
	req->paramu2 = BlackPixel;
	GetReq(X_MakePixmap, 0);
	req->param.l[0] = 0;
	req->paramu2 = WhitePixel;
	
	/* The following is needed to synchronize properly with errors,
	 * since three requests are outstanding and no replies have
	 * yet been read
	 */
	dpy->request = 1;
	
	/* Get reply to X_SetUp */
	if (!_XReply(dpy, &rep)) {
		/* There was an error in retrieving the reply. */
	    	close (dpy->fd);
		free (dpy->buffer);
		free ((char *)dpy);
		check (sigvec (SIGPIPE, &ovec, 0));
		return(NULL);
	}
 
	/* Set the Display data returned by the X_SetUp call. */
	dpy->root = rep.param.l[0];	/* Root window id. */
	dpy->vnumber = rep.params2;	/* X protocol version number. */
	dpy->dtype = rep.params3;	/* Server's display type. */
	dpy->dplanes = rep.params4;	/* Number of display bit planes. */
	dpy->dcells = rep.paramu5;	/* Number of display color map cell. */
	
	/* Get reply to MakePixmap (black) */
	dpy->request++;
	if (!_XReply (dpy, &rep)) {
	    close (dpy->fd);
	    free (dpy->buffer);
	    free ((char *)dpy);
	    check (sigvec (SIGPIPE, &ovec, 0));
	    return (NULL);
	    }
	dpy->black = rep.param.l[0];
 
	/* Get reply to MakePixmap (white) */
	dpy->request++;
	if (!_XReply (dpy, &rep)) {
	    close (dpy->fd);
	    free (dpy->buffer);
	    free ((char *)dpy);
	    check (sigvec (SIGPIPE, &ovec, 0));
	    return (NULL);
	    }
	dpy->white = rep.param.l[0];
 
	check (sigvec (SIGPIPE, &ovec, 0));
	return(dpy);
}

/* 
 * Connects to a server, creates a Display object and returns a pointer to
 * the newly created Display back to the caller.
 */
Display *XOpenDisplay (display)
     char *display;
{
  return (IntXOpenDisplay (display, FALSE));
}

Display *XProofOpenDisplay (display)
     char *display;
{
  return (IntXOpenDisplay (display, TRUE));
}

!E!O!F!
#
# type    sh /usrea0/tsf/xchange/../xchangeshar   to unpack this archive.
#
echo extracting Xlib.h...
cat >Xlib.h <<'!E!O!F!'

#include <X/mit-copyright.h>

/* $Header: Xlib.h,v 10.20 86/12/16 17:17:31 tony Exp $ */
/* Copyright    Massachusetts Institute of Technology    1985	*/

/*
 *	Xlib.h - Header definition and support file for the C subroutine
 *	interface library (Xlib) to the X Window System Protocol.
 *
 */

extern char *malloc(), *calloc(), *realloc(), *alloca();
#ifdef notdef
#include <sys/types.h>
#endif
#include <X/X.h>

#define Status int
#define XId long
#define XClearVertexFlag() (_XlibCurrentDisplay->lastdraw = NULL)
#define XMakePattern(pattern, patlen, patmul)\
	((Pattern)(((patmul) << 20) | (((patlen) - 1) << 16) | (pattern) ))
#define dpyno() (_XlibCurrentDisplay->fd)
#define RootWindow (_XlibCurrentDisplay->root)
#define BlackPixmap (_XlibCurrentDisplay->black)
#define WhitePixmap (_XlibCurrentDisplay->white)
#define AllPlanes (~0)
#define QLength() (_XlibCurrentDisplay->qlen)
#define DisplayType() (_XlibCurrentDisplay->dtype)
#define DisplayPlanes() (_XlibCurrentDisplay->dplanes)
#define DisplayCells() (_XlibCurrentDisplay->dcells)
#define ProtocolVersion() (_XlibCurrentDisplay->vnumber)
#define DisplayName() (_XlibCurrentDisplay->displayname)

/* Bitmask returned by XParseGeometry().  Each bit tells if the corresponding
   value (x, y, width, height) was found in the parsed string. */

#define NoValue	0x0000
#define XValue  0x0001
#define YValue	0x0002
#define WidthValue  0x0004
#define HeightValue  0x0008
#define AllValues 0x000F
#define XNegative 0x0010
#define YNegative 0x0020

/* Definition of a generic event.  It must be cast to a specific event
 * type before one can read event-specific data */

typedef struct _XEvent {
    	unsigned long type;   /* of event (KeyPressed, ExposeWindow, etc.) */
	Window window;	      /* which selected this event */
	long pad_l1, pad_l2;  /* event-specific data */
	Window subwindow;     /* child window (if any) event actually happened in */
	long pad_l4; 	      /* event-specific data */
} XEvent;


/*
 * _QEvent datatype for use in input queueing.
 */
typedef struct _qevent {
	struct _qevent *next;
	XEvent event;
} _QEvent;


/*
 * Display datatype maintaining display specific data.
 */
typedef struct _display {
	int fd;			/* Network socket (used only for */
				/* reading, if we are using */
				/* mouseproofing). */
	Window root;		/* Root window id. */
	int vnumber;		/* X protocol version number. */
	int dtype;		/* X server display device type. */
	int dplanes;		/* Number of display bit planes. */
	int dcells;		/* Number of display color map cells. */
	_QEvent *head, *tail;	/* Input event queue. */
	int qlen;		/* Length of input event queue */
	int request;		/* Id of last request. */
	char * lastdraw;	/* Last draw request. */
	char *buffer;		/* Output buffer starting address. */
	char *bufptr;		/* Output buffer index pointer. */
	char *bufmax;		/* Output buffer maximum+1 address. */
	int squish;		/* Squish MouseMoved events? */
	Pixmap black, white;    /* Constant tile pixmaps */
	char *displayname;	/* "host:display" string used on this connect*/
	int width, height;	/* width and height of display */
	int mouseproofedp;      /* Lets us know whether this display is mouseproofed. */
	int writefd;            /* Network socket for writing.  Only */
				/* used if we are mouseproofing; */
				/* otherwise not used at all. */
} Display;


/*
 * XAssoc - Association elements used in the XAssocTable data structure.
 * XAssoc's are used as bucket entries in the association table.
 */
typedef struct _x_assoc {
    struct _x_assoc *next;	/* Next object in this bucket. */
    struct _x_assoc *prev;	/* Previous obejct in this bucket. */
    Display *display;		/* Display which ownes the id. */
    XId x_id;			/* X Window System id. */
    char *data;			/* Pointer to untyped memory. */
} XAssoc;

/* 
 * XAssocTable - X Window System id to data structure pointer association
 * table.  An XAssocTable is a hash table who's buckets are circular
 * queue's of XAssoc's.  The XAssocTable is constructed from an array of
 * XAssoc's which are the circular queue headers (bucket headers).  
 * An XAssocTable consists an XAssoc pointer that points to the first
 * bucket in the bucket array and an integer that indicates the number
 * of buckets in the array.
 */
typedef struct _x_assoc_table {
    struct _x_assoc *buckets;	/* Pointer to first bucket in bucket array.*/
    int size;			/* Table size (number of buckets). */
} XAssocTable;

/*
 * Declare the XAssocTable routines that don't return int.
 */
extern char *XLookUpAssoc();
XAssocTable *XCreateAssocTable();


/* 
 * Data returned by XQueryWindow.
 */
typedef struct _WindowInfo {
	short width, height;	/* Width and height. */
	short x, y;		/* X and y coordinates. */
	short bdrwidth;		/* Border width. */
	short mapped;		/* IsUnmapped, IsMapped or IsInvisible.*/
	short type;		/* IsTransparent, IsOpaque or IsIcon. */
	Window assoc_wind;	/* Associated icon or opaque Window. */
} WindowInfo;


/* 
 * Data returned by XQueryFont.
 */
typedef struct _FontInfo {
	Font id;
	short height, width, baseline, fixedwidth;
	unsigned char firstchar, lastchar;
	short *widths;		/* pointer to width array in OpenFont */
} FontInfo;


/*
 * Data structure used by color operations; ints rather than shorts
 * to keep 16 bit protocol limitation out of the library.
 */
typedef struct _Color {
	int pixel;
	unsigned short red, green, blue;
} Color;


/*
 * Data structure use by XCreateTiles.
 */
typedef struct _TileFrame {
	int pixel;		/* Pixel color for constructing the tile. */
	Pixmap pixmap;		/* Pixmap id of the pixmap, filled in later. */
} TileFrame;


/*
 * Data structures used by XCreateWindows XCreateTransparencies and
 * XCreateWindowBatch.
 */
typedef struct _OpaqueFrame {
	Window self;		/* window id of the window, filled in later */
	short x, y;		/* where to create the window */
	short width, height;	/* width and height */
	short bdrwidth;		/* border width */
	Pixmap border;		/* border pixmap */
	Pixmap background;	/* background */
} OpaqueFrame;

typedef struct _TransparentFrame {
	Window self;		/* window id of the window, filled in later */
	short x, y;		/* where to create the window */
	short width, height;	/* width and height */
} TransparentFrame;

typedef struct _BatchFrame {
	short type;		/* One of (IsOpaque, IsTransparent). */
	Window parent;		/* Window if of the window's parent. */
	Window self;		/* Window id of the window, filled in later. */
	short x, y;		/* Where to create the window. */
	short width, height;	/* Window width and height. */
	short bdrwidth;		/* Window border width. */
	Pixmap border;		/* Window border pixmap */
	Pixmap background;	/* Window background pixmap. */
} BatchFrame;


/*
 * Definitions of specific events
 * In all of the following, fields whose names begin with "pad" contain
 * no meaningful value.
 */

struct _XKeyOrButtonEvent {
	unsigned long type;	/* of event (KeyPressed, ButtonReleased, etc.) */
	Window window;		/* which selected this event */
	unsigned short time B16;  /* in 10 millisecond ticks */
	short detail B16;	/* event-dependent data (key state, etc.) */
	short x B16;		/* mouse x coordinate within event window */
	short y B16;		/* mouse y coordinate within event window */
	Window subwindow;	/* child window (if any) mouse was in */
	Locator location;	/* absolute coordinates of mouse */
};

typedef struct _XKeyOrButtonEvent XKeyOrButtonEvent;

typedef struct _XKeyOrButtonEvent XKeyEvent;
typedef struct _XKeyOrButtonEvent XKeyPressedEvent;
typedef struct _XKeyOrButtonEvent XKeyReleasedEvent;

typedef struct _XKeyOrButtonEvent XButtonEvent;
typedef struct _XKeyOrButtonEvent XButtonPressedEvent;
typedef struct _XKeyOrButtonEvent XButtonReleasedEvent;

struct _XMouseOrCrossingEvent {
	unsigned long type;	/* EnterWindow, LeaveWindow, or MouseMoved */
	Window window;		/* which selected this event */
	short pad_s2 B16; 	      
	short detail B16;	/* event-dependent data (key state, etc. ) */
	short x B16;		/* mouse x coordinate within event window */
	short y B16;		/* mouse y coordinate within event window */
	Window subwindow;	/* child window (if any) mouse was in */
	Locator location;	/* absolute coordinates of mouse */
};

typedef struct _XMouseOrCrossingEvent XMouseOrCrossingEvent;

typedef struct _XMouseOrCrossingEvent XMouseEvent;
typedef struct _XMouseOrCrossingEvent XMouseMovedEvent;

typedef struct _XMouseOrCrossingEvent XCrossingEvent;
typedef struct _XMouseOrCrossingEvent XEnterWindowEvent;
typedef struct _XMouseOrCrossingEvent XLeaveWindowEvent;

struct _XExposeEvent {
	unsigned long type;	/* ExposeWindow or ExposeRegion */
	Window window;		/* that selected this event */
	short pad_s2 B16; 	      
	short detail B16;	/* 0 or ExposeCopy */
	short width B16;	/* width of exposed area */
	short height B16;	/* height of exposed area */
	Window subwindow;	/* child window (if any) actually exposed */
	short y B16;		/* top of exposed area (0 for ExposeWindow) */
	short x B16;		/* left edge of exposed area (0 for ExposeWindow) */
};

typedef struct _XExposeEvent XExposeEvent;
typedef struct _XExposeEvent XExposeWindowEvent;
typedef struct _XExposeEvent XExposeRegionEvent;

typedef struct _XExposeCopyEvent {
    	unsigned long type;   /* ExposeCopy */
	Window window;	      /* that selected this event */
	long pad_l1;
	long pad_l2;	      
	Window subwindow;     /* child window (if any) actually exposed */
	long pad_l4;	      
} XExposeCopyEvent;
	
typedef struct _XUnmapEvent {
	unsigned long type;   /* UnmapWindow */
	Window window;	      /* that selected this event */
	long pad_l1;
	long pad_l2;	      
	Window subwindow;     /* child window (if any) actually unmapped */
	long pad_l4;	      
} XUnmapEvent;

typedef struct _XFocusChangeEvent {
	unsigned long type;   /* FocusChange */
	Window window;	      /* that selected this event */
	short pad_s2 B16;
	short detail B16;     /* EnterWindow or LeaveWindow */
	long pad_l2;	      
	Window subwindow;     /* child window (if any) of actual focus change*/
	long pad_l4;	      
} XFocusChangeEvent;

typedef struct _XErrorEvent {
	long pad;
	long serial;		/* serial number of failed request */
	char error_code;    	/* error code of failed request */
	char request_code;	/* request code of failed request */
	char func;  	        /* function field of failed request */
	char pad_b7;
	Window window;	    	/* Window of failed request */
	long pad_l3;
	long pad_l4;
} XErrorEvent;

/*
 * Line pattern related definitions for the library.
 */
typedef long Pattern;

#define DashedLine XMakePattern(0xf0f0, 16, 1)
#define DottedLine XMakePattern(0xaaaa, 16, 1)
#define DotDashLine XMakePattern(0xf4f4, 16, 1)
#define SolidLine  XMakePattern(1,1,1)

typedef short KeyMapEntry [8];

/* define values for keyboard map table */
/* these values will vanish in the next version; DO NOT USE THEM! */
#define SHFT	(short) -2
#define CNTL	(short) -3
#define LOCK	(short) -4
#define SYMBOL	(short) -5
#define KEYPAD	(short) -6
#define CURSOR	(short) -7
#define PFX	(short) -8
#define FUNC1	(short) -9
#define FUNC2	(short) -10
#define FUNC3	(short) -11
#define FUNC4	(short) -12
#define FUNC5	(short) -13
#define FUNC6	(short) -14
#define FUNC7	(short) -15
#define FUNC8	(short) -16
#define FUNC9	(short) -17
#define FUNC10	(short) -18
#define FUNC11	(short) -19
#define FUNC12	(short) -20
#define FUNC13	(short) -21
#define FUNC14	(short) -22
#define FUNC15	(short) -23
#define FUNC16	(short) -24
#define FUNC17	(short) -25
#define FUNC18	(short) -26
#define FUNC19	(short) -27
#define FUNC20	(short) -28
#define E1	(short) -29
#define E2	(short) -30
#define E3	(short) -31
#define E4	(short) -32
#define E5	(short) -33
#define E6	(short) -34


/* 
 * X function declarations.
 */
Display *XOpenDisplay();

char *XFetchBytes();
char * XFetchBuffer();

char *XErrDescrip();
char *XLookupMapping();

short *XFontWidths();
FontInfo *XOpenFont();
extern Display *_XlibCurrentDisplay;
char *XGetDefault();
Bitmap XCharBitmap(), XStoreBitmap();
Pixmap XMakePixmap(), XMakeTile(), XStorePixmapXY(), XStorePixmapZ();
Pixmap XPixmapSave();
Cursor XCreateCursor(), XStoreCursor();
Window XCreate(), XCreateTerm(), XCreateTransparency(), XCreateWindow();
Window XGetIconWindow();
Font XGetFont();
Status XFetchName(), XGetColorCells(), XGetColor(), XGetHardwareColor();
Status XGetResizeHint(), XGrabButton(), XGrabMouse(), XInterpretLocator();
Status XParseColor(), XPixmapGetXY(), XPixmapGetZ(), XQueryMouseButtons();
Status XQueryFont(), XQueryMouse(), XQueryTree(), XQueryWindow();
Status XReadBitmapFile(), XUpdateMouse();
XAssocTable *XCreateAssocTable();
!E!O!F!
#
# type    sh /usrea0/tsf/xchange/../xchangeshar   to unpack this archive.
#
echo extracting XlibInternal.c...
cat >XlibInternal.c <<'!E!O!F!'
#include <X/mit-copyright.h>

/* Copyright    Massachusetts Institute of Technology    1985	*/

/*
 *	XlibInternal.c - Internal support routines for the C subroutine
 *	interface library (Xlib) to the X Window System Protocol V8.0.
 */

#include "XlibInternal.h"
#include <sys/uio.h>

/*
 * The following routines are internal routines used by Xlib for protocol
 * packet transmission and reception.
 *
 * XIOError(Display *) will be called if any sort of system call error occurs.
 * This is assumed to be a fatal condition, i.e., XIOError should not return.
 *
 * XError(Display *, XErrorEvent *) will be called whenever an X_Error event is
 * received.  This is not assumed to be a fatal condition, i.e., it is
 * acceptable for this procedure to return.  However, XError should NOT
 * perform any operations (directly or indirectly) on the DISPLAY.
 *
 * Routines declared with a return type of 'Status' return 0 on failure,
 * and non 0 on success.  Routines with no declared return type don't 
 * return anything.  Whenever possible routines that create objects return
 * the object they have created.
 */

#ifndef lint
static char rcsid[] = "$Header: XlibInternal.c,v 10.13 86/04/22 15:30:52 jg Rel $";
#endif

#ifdef titan
#define iovbase iov_base.saddr
#else
#define iovbase iov_base
#endif
Display *_XlibCurrentDisplay = NULL;	/* default display to use in library */
_QEvent *_qfree = NULL;			/* NULL _QEvent. */

static int padlength[4] = {0, 3, 2, 1};
    /* lookup table for adding padding bytes to data that is read from
    	or written to the X socket.  */

/*
 * _XFlush - Flush the X request buffer.  If the buffer is empty, no
 * action is taken.  This routine correctly handles incremental writes.
 */
_XFlush (dpy)
	register Display *dpy;
{
	register int size;
	register int write_stat;
	register char *bufindex;

	size = dpy->bufptr - dpy->buffer;
	bufindex = dpy->bufptr = dpy->buffer;
	/*
	 * While write has not written the entire buffer, keep looping
	 * until the entire buffer is written.  bufindex will be incremented
	 * and size decremented as buffer is written out.
	 */
	while (size) {
		if ((write_stat = write((dpy->mouseproofedp?dpy->writefd:dpy->fd), bufindex, size)) == -1) {
			/* Write failed! */
			/* errno set by write system call. */
			_XIOError(dpy);
		}
		size -= write_stat;
		bufindex += write_stat;
	}
	dpy->lastdraw = NULL;
}


/* 
 * _XRead - Read bytes from the socket taking into account incomplete
 * reads.
 */
_XRead (dpy, data, size)
	register Display *dpy;
	register char *data;
	register int size;
{
	register int bytes_read;

	while ((bytes_read = read(dpy->fd, data, size)) != size) {

	    	if (bytes_read > 0) {
		    size -= bytes_read;
		    data += bytes_read;
		    }

		else if (bytes_read == 0) {
		    /* Read failed because of end of file! */
		    errno = EPIPE;
		    _XIOError(dpy);
		    }

		else  /* bytes_read is less than 0; presumably -1 */ {
		    /* If it's a system call interrupt, it's not an error. */
		    if (errno != EINTR)
		    	_XIOError(dpy);
		    }
	    	 }
}

/*
 * _XReadPad - Read bytes from the socket taking into account incomplete
 * reads.  If the number of bytes is not 0 mod 32, read additional pad
 * bytes.
 */
_XReadPad (dpy, data, size)
    	register Display *dpy;	
	register char *data;
	register int size;
{
    	register int bytes_read;
	struct iovec iov[2];
	char pad[3];

	iov[0].iov_len = size;
	iov[0].iovbase = data;
	/* 
	 * The following hack is used to provide 32 bit long-word
	 * aligned padding.  The [1] vector is of length 0, 1, 2, or 3,
	 * whatever is needed.
	 */

	iov[1].iov_len = padlength[size & 3];
	iov[1].iovbase = pad;
	size += iov[1].iov_len;

	while ((bytes_read = readv (dpy->fd, iov, 2)) != size) {

	    if (bytes_read > 0) {
		size -= bytes_read;
	    	if ((iov[0].iov_len -= bytes_read) < 0) {
		    iov[1].iov_len += iov[0].iov_len;
		    iov[1].iovbase -= iov[0].iov_len;
		    iov[0].iov_len = 0;
		    }
	    	else
	    	    iov[0].iovbase += bytes_read;
	    	}

	    else if (bytes_read == 0) {
		/* Read failed because of end of file! */
		errno = EPIPE;
		_XIOError(dpy);
		}
	    
	    else  /* bytes_read is less than 0; presumably -1 */ {
		/* If it's a system call interrupt, it's not an error. */
		if (errno != EINTR)
		    _XIOError(dpy);
		}
	    }

}

/*
 * _XSend - Flush the buffer and send the client data. 32 bit word aligned
 * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
 */
_XSend (dpy, data, size)
	register Display *dpy;
	char *data;
	register int size;
{
	register int len;
	struct iovec iov[3];
	char pad[3];

	iov[0].iov_len = len = dpy->bufptr - dpy->buffer;
	iov[0].iovbase = dpy->bufptr = dpy->buffer;
	iov[1].iov_len = size;
	iov[1].iovbase = data;
	/* 
	 * The following hack is used to provide 32 bit long-word
	 * aligned padding.  The [2] vector is of length 0, 1, 2, or 3,
	 * whatever is needed.
	 */
	iov[2].iov_len = padlength[size & 3];
	iov[2].iovbase = pad;
	len += (size + 3) & ~3;
	/*
	 * Use while to allow for incremental writes.
	 */
	while ((size = writev((dpy->mouseproofedp?dpy->writefd:dpy->fd), iov, 3)) != len) {
	    	if (size < 0) _XIOError(dpy);
		len -= size;
		if ((iov[0].iov_len -= size) < 0) {
		    iov[1].iov_len += iov[0].iov_len;
		    iov[1].iovbase -= iov[0].iov_len;
		    iov[0].iov_len = 0;
		    if (iov[1].iov_len < 0) {
	    	    	iov[2].iov_len += iov[1].iov_len;
			iov[2].iovbase -= iov[1].iov_len;
			iov[1].iov_len = 0;
		    }
		}
		else {
			iov[0].iovbase += size;
		}
	}
	dpy->lastdraw = NULL;
}

/*
 * _XReply - Wait for a reply packet and copy its contents into the
 * specified rep.  Mean while we must handle error and event packets that
 * we may encounter.
 */
Status _XReply (dpy, rep)
    register Display *dpy;
    register XRep *rep;
{
    _XFlush(dpy);
    while (1) {
	_XRead(dpy, (char *)rep, sizeof(XRep));
	switch ((int)rep->code) {

	    case X_Reply:
	        /* Reply recieved. */
	        return(1);
		 
    	    case X_Error:
	    	{
	    	/* X_Error packet encountered! */
		int current_request = dpy->request;
		XErrorEvent *error = (XErrorEvent *) rep;

		if (error->serial == current_request)
			/* do not die on "no such font", "can't allocate",
			   "can't grab" failures */
			switch (error->error_code) {
			case BadFont:
				if (error->request_code != X_GetFont)
					break;
			case BadAlloc:
			case BadColor:
			case BadGrab:
				return (0);
			}
		_XError(dpy, error);
		if (error->serial == current_request)
		    return(0);
		}
		break;
	    default:
		_XEnq(dpy, (XEvent *) rep);
		break;
	    }
	}
}   


/*
 * _XEnq - Place event packets on the display's queue.
 */
_XEnq (dpy, event)
	register Display *dpy;
	register XEvent *event;
{
	register _QEvent *qelt;
	extern char *malloc();

	if (
		/* If we are squishing MouseMoved events AND ... */
		dpy->squish && 
		/* the current event is a MouseMoved event AND ... */
		(event->type == MouseMoved) &&
		/* if there is a last event on the display queue AND ... */
		(qelt = dpy->tail) && 
		/* if that last event is also a MouseMoved event AND ... */
		(qelt->event.type == MouseMoved) &&
		/* it has the same event window as the current event ... */
		(event->window == qelt->event.window)
	) {
		/* then replace the last event with the current event! */
		qelt->event = *event;
		return;
	}
	if (qelt = _qfree) {
		/* If _qfree is non-NULL do this, else malloc a new one. */
		_qfree = qelt->next;
	}
	else if ((qelt = (_QEvent *) malloc((unsigned)sizeof(_QEvent))) == NULL) {
		/* Malloc call failed! */
		errno = ENOMEM;
		_XIOError(dpy);
	}
	qelt->next = NULL;
	qelt->event = *event;
	if (dpy->tail) {
		dpy->tail->next = qelt;
	}
	else {
		dpy->head = qelt;
	}
	dpy->tail = qelt;
	dpy->qlen++;
}


/*
 * Undefine the routine pointers so we can define the following default
 * routines.
 */
#undef _XError
#undef _XIOError


/*
 * _XIOError - Default fatal system error reporting routine.  Called when
 * an X internal system error is encountered.
 */
/*ARGSUSED*/
_XIOError (dpy)
	Display *dpy;
{
	perror("XIO");
	exit(1);
}


/*
 * _XError - Default non-fatal error reporting routine.  Called when an
 * X_Error packet is encountered in the input stream.
 */
_XError (dpy, rep)
    Display *dpy;
    XErrorEvent *rep;
{
    fprintf(stderr, "X Error: %s\n", XErrDescrip (rep->error_code));
    fprintf(stderr, "         Request code: %d\n", rep->request_code);
    fprintf(stderr, "         Request function: %d\n", rep->func);
    fprintf(stderr, "         Request window 0x%x\n", rep->window);
    fprintf(stderr, "         Error Serial #%d\n", rep->serial);
    fprintf(stderr, "         Current serial #%d\n", dpy->request);
    exit(1);
}

int (*_XIOErrorFunction)() = _XIOError;
int (*_XErrorFunction)() = _XError;

#ifdef BIGSHORTS
UnpackShorts(from, to, bytes)
	ushort_p *from;
	short *to;
	unsigned bytes;
{
	unsigned i;
	for (i = 0; i < (bytes/psizeof(short)); i++)
		if (i&1)
			to[i] = from[i>>1].right;
		else
			to[i] = from[i>>1].left;
}

char packbuffer[1000];
PackData(dpy, data, len)
    register Display *dpy;
    short *data;
    unsigned len;
{
	if (dpy->bufptr + len < dpy->bufmax) {
		PackShorts(data, dpy->bufptr, len);
		dpy->bufptr += (len + 3) & ~3;
	} else {
		PackShorts(data, packbuffer, len);
		_XSend(dpy, packbuffer, len);
	}
}

PackShorts(from, to, bytes)
	short *from;
	char *to;
	unsigned bytes;
{
	unsigned i, n, offset;
	ushort_p *uto;

	uto = (ushort_p *)to;
	offset = ((int)to & 2) >> 1; /* lost 2 bits of pointer */
	n = (bytes / 2) + offset;
	for (i = offset; i < n; i++) {
		if (i&1)
			uto[i>>1].right = from[i-offset];
		else
			uto[i>>1].left = from[i-offset];
	}
}
#endif
!E!O!F!
#
# type    sh /usrea0/tsf/xchange/../xchangeshar   to unpack this archive.
#
echo extracting XlibInternal.h...
cat >XlibInternal.h <<'!E!O!F!'
#include <X/mit-copyright.h>

/* $Header: XlibInternal.h,v 10.9 86/04/22 15:22:19 jg Rel $ */
/* Copyright 1984, 1985  Massachusetts Institute of Technology */

/*
 *	XlibInternal.h - Header definition and support file for the internal
 *	support routines (XlibInternal) used by the C subroutine interface
 *	library (Xlib) to the X Window System.
 *
 */

#include <sys/types.h>
#include "Xlib.h"
#include "../X/Xproto.h"
#include <stdio.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <errno.h>

extern int errno;			/* Internal system error number. */
extern char *malloc();			/* commonly used in the library. */
extern char *realloc();			/* used with some frequency.	 */

extern Display *_XlibCurrentDisplay;	/* Currently active Display. */

extern (*_XIOErrorFunction)();		/* X system error reporting routine. */
extern (*_XErrorFunction)();		/* X_Error event reporting routine. */

/*
 * Boolean datatype.
 */

typedef enum _bool {FALSE, TRUE} Bool;

/* Pointers to the above routines. */
#define _XIOError (*_XIOErrorFunction)
#define _XError (*_XErrorFunction)

#define BUFSIZE 2048			/* X output buffer size. */
#define MOUSEPROOFSERVER "xmouseproofserver"

/*
 * X Protocol packetizing macros.
 */


/*
 * GetReq - Get the next avilable X request packet in the buffer and
 * return it. 
 *
 * "cd" is the X protocol code.
 * "id" is the window id of the requesting window.
 */
#define GetReq(cd, id) \
	dpy = _XlibCurrentDisplay;\
	if ((dpy->bufptr + sizeof(XReq)) > dpy->bufmax)\
		_XFlush(dpy);\
	req = (XReq *)dpy->bufptr;\
	req->code = cd;\
	req->windowId = id;\
	dpy->bufptr += sizeof(XReq);\
	dpy->request++;\
	dpy->lastdraw = NULL

/*
 * Data - Place data in the buffer and pad the end to provide
 * 32 bit word alignment.  Transmit if the buffer fills.
 *
 * "dpy" is a pointer to a Display.
 * "data" is a pinter to a data buffer.
 * "len" is the length of the data buffer.
 */
#define Data(dpy, data, len) \
	if (dpy->bufptr + len < dpy->bufmax) {\
		bcopy(data, dpy->bufptr, len);\
		dpy->bufptr += (len + 3) & ~3;\
	} else\
		_XSend(dpy, data, len)

#ifndef BIGSHORTS
#define PackData(dpy, data, len) Data(dpy, (char *) data, len)
#define PackShorts(f, t, n)  bcopy((char *)f, t, n)
#endif



!E!O!F!
#
# type    sh /usrea0/tsf/xchange/../xchangeshar   to unpack this archive.
#
echo extracting quick.c...
cat >quick.c <<'!E!O!F!'
#include <stdio.h>
#include <X/Xlib.h>
main (argc, argv)
int argc;
char **argv;
{
  char ch;
  Window w;
  if (XProofOpenDisplay (argv [1]) == 0) {
    perror ("XOpenDisplay");
    exit (1);
  };
  w = XCreateWindow (RootWindow, 0, 0, 100, 100, 10, WhitePixmap, BlackPixmap);
  XSelectInput (w, MouseMoved);
  XMapWindow (w);
  XFlush();
  read (0, &ch, 1);
  for (;;) {
    XEvent e;
    XNextEvent (&e);
    printf ("X is %d, Y is %d.\n", ((XKeyEvent *) &e) -> x, ((XKeyEvent *) &e) -> y);
  }
}

!E!O!F!
#
# type    sh /usrea0/tsf/xchange/../xchangeshar   to unpack this archive.
#
echo extracting xdiffs...
cat >xdiffs <<'!E!O!F!'
[b.ergo]/usr/misc/X/Xlib% sccs sccsdiff -r1.1 -r1.3 -c3 Xlib.h
*** /tmp/geta11039	Tue Jun 23 00:38:39 1987
--- /tmp/getb11039	Tue Jun 23 00:38:39 1987
***************
*** 70,76 ****
   * Display datatype maintaining display specific data.
   */
  typedef struct _display {
! 	int fd;			/* Network socket. */
  	Window root;		/* Root window id. */
  	int vnumber;		/* X protocol version number. */
  	int dtype;		/* X server display device type. */
--- 70,78 ----
   * Display datatype maintaining display specific data.
   */
  typedef struct _display {
! 	int fd;			/* Network socket (used only for */
! 				/* reading, if we are using */
! 				/* mouseproofing). */
  	Window root;		/* Root window id. */
  	int vnumber;		/* X protocol version number. */
  	int dtype;		/* X server display device type. */
***************
*** 87,92 ****
--- 89,98 ----
  	Pixmap black, white;    /* Constant tile pixmaps */
  	char *displayname;	/* "host:display" string used on this connect*/
  	int width, height;	/* width and height of display */
+ 	int mouseproofedp;      /* Lets us know whether this display is mouseproofed. */
+ 	int writefd;            /* Network socket for writing.  Only */
+ 				/* used if we are mouseproofing; */
+ 				/* otherwise not used at all. */
  } Display;
  
  
[b.ergo]/usr/misc/X/Xlib% sccs sccsdiff -r1.1 -r1.2 -c3 XlibInternal.h
*** /tmp/geta11051	Tue Jun 23 00:39:20 1987
--- /tmp/getb11051	Tue Jun 23 00:39:20 1987
***************
*** 39,45 ****
  #define _XError (*_XErrorFunction)
  
  #define BUFSIZE 2048			/* X output buffer size. */
! 
  
  /*
   * X Protocol packetizing macros.
--- 39,45 ----
  #define _XError (*_XErrorFunction)
  
  #define BUFSIZE 2048			/* X output buffer size. */
! #define MOUSEPROOFSERVER "xmouseproofserver"
  
  /*
   * X Protocol packetizing macros.
[b.ergo]/usr/misc/X/Xlib% sccs sccsdiff -r1.1 -r1.3 -c3 XOpenDisplay.c
*** /tmp/geta11063	Tue Jun 23 00:39:55 1987
--- /tmp/getb11063	Tue Jun 23 00:39:55 1987
***************
*** 6,17 ****
  #include <sys/socket.h>
  #include <strings.h>
  #include <sys/un.h>
!  
! /* 
!  * Connects to a server, creates a Display object and returns a pointer to
!  * the newly created Display back to the caller.
!  */
! Display *XOpenDisplay (display)
  	register char *display;
  {
  	register Display *dpy;		/* New Display object being created. */
--- 6,46 ----
  #include <sys/socket.h>
  #include <strings.h>
  #include <sys/un.h>
! #include <fcntl.h>
! #include <setjmp.h>
! #include <signal.h>
! #include <stdio.h>
! 
! /*This routine determines whether a given error code represents an error.  
! If it does, then we print an error message and bomb.  If it doesn't, then
! the code is the returned value of check.*/
! 
! static int check (code)
! int code;
! {
!   if (code < 0) {
!     fprintf (stderr, "Unanticipated error:\n");
!     perror ("");
!     exit (1);
!   }
!   return (code);
! }
! 
! jmp_buf env;
! 
! /* This is the X error handler.  We define an X error handler for the */
!  /* duration of the display open operation so we can trap broken pipe */
!  /* errors.  Broken pipe errors happen whenever you try to open a */
!  /* display which has a server running on it, but you aren't on the */
!  /* server's host list.  This is fairly frequent, so we want to be */
!  /* able to handle the error instead of bombing. */
! int myhandler (disp)
!      Display *disp;
! {
!   longjmp (env, 1);
! }
! 
! Display *IntXOpenDisplay (display, proofp)
  	register char *display;
  {
  	register Display *dpy;		/* New Display object being created. */
***************
*** 32,43 ****
   
  	register XReq *req;		/* XReq request packet pointer. */
  	XRep rep;			/* XRep reply packet. */
   
  	/* External declarations. */
  	extern char *getenv();
  	extern char *malloc();
  	extern struct hostent *gethostbyname();
!  
  	/*
  	 * Extract the host name and display number from the display
  	 * specifier string.  The display specifier string is supplied
--- 61,73 ----
   
  	register XReq *req;		/* XReq request packet pointer. */
  	XRep rep;			/* XRep reply packet. */
+ 	struct sigvec ovec;             /* Used to hold previous state of SIGPIPE signal. */
   
  	/* External declarations. */
  	extern char *getenv();
  	extern char *malloc();
  	extern struct hostent *gethostbyname();
! 
  	/*
  	 * Extract the host name and display number from the display
  	 * specifier string.  The display specifier string is supplied
***************
*** 75,80 ****
--- 105,117 ----
  	if (*displayptr == '\0') return(NULL);
  	dispnum = atoi(displayptr);
   
+ 	check (sigvec (SIGPIPE, 0, &ovec));
+ 	check (signal (SIGPIPE, SIG_IGN));
+ 	if (setjmp (env)) {
+ 	  check (sigvec (SIGPIPE, &ovec, 0));
+ 	  return (0);
+ 	}
+ 	XIOErrorHandler (myhandler);
  	if (strcmp("unix", displaybuf) == 0) {
  	    /* Connect locally using Unix domain. */
  	    unaddr.sun_family = AF_UNIX;
***************
*** 94,99 ****
--- 131,137 ----
  			if ((host_ptr = gethostbyname(displaybuf)) == NULL) {
  				/* No such host! */
  				errno = EINVAL;
+ 				check (sigvec (SIGPIPE, &ovec, 0));
  				return(NULL);
  			}
  			/* Check the address type for an internet host. */
***************
*** 100,105 ****
--- 138,144 ----
  			if (host_ptr->h_addrtype != AF_INET) {
  				/* Not an Internet host! */
  				errno = EPROTOTYPE;
+ 				check (sigvec (SIGPIPE, &ovec, 0));
  				return(NULL);
  			}
   
***************
*** 135,140 ****
--- 174,180 ----
  	if ((dpy = (Display *)malloc(sizeof(Display))) == NULL) {
  		/* Malloc call failed! */
  		errno = ENOMEM;
+ 		check (sigvec (SIGPIPE, &ovec, 0));
  		return(NULL);
  	}
   
***************
*** 150,155 ****
--- 190,196 ----
  		    /* Socket call failed! */
  		    /* errno set by system call. */
  		    free ((char *)dpy);
+ 		    check (sigvec (SIGPIPE, &ovec, 0));
  		    return(NULL);
  	    }
   
***************
*** 159,164 ****
--- 200,206 ----
  		    /* errno set by system call. */
  		    close (dpy->fd);
  		    free ((char *)dpy);
+ 		    check (sigvec (SIGPIPE, &ovec, 0));
  		    return(NULL);
  	    }
  #ifdef DNETCONN
***************
*** 167,176 ****
--- 209,250 ----
  		    /* connect failed! */
  		    /* errno set by dnet_conn. */
  		    free ((char *)dpy);
+ 		    check (sigvec (SIGPIPE, &ovec, 0));
  		    return(NULL);
  	    }
  	}
  #endif
+ 	if (proofp) {
+ 	  int fd = dpy -> fd;
+ 	  int readpipes [2], writepipes [2];
+ 
+ 	  check (pipe (readpipes));
+ 	  check (pipe (writepipes));
+ 	  if (check (vfork ())) {
+ 	    /* Parent */
+ 	    close (readpipes [1]);
+ 	    dpy -> fd = readpipes [0];
+ 	    close (writepipes [0]);
+ 	    dpy -> writefd = writepipes [1];
+ 	  } else {
+ 	    /* Child */
+ 	    check (close (readpipes [0]));
+ 	    check (close (writepipes [1]));
+ 	    check (dup2 (readpipes [1], 1));
+ 	    check (dup2 (writepipes [0], 0));
+ 	    check (close (readpipes [1]));
+ 	    check (close (writepipes [0]));
+ 	    check (dup2 (fd, 4));
+ 	    check (close (fd));
+ 	    /* Make sure the socket stays open when the server executes. */
+ 	    check (fcntl (4, F_SETFD, 0));
+ 	    execlp (MOUSEPROOFSERVER, 0);
+ 	    fprintf (stderr, "Couldn't run server %s.\n", MOUSEPROOFSERVER);
+ 	    _exit (1);
+ 	  }
+ 	}
+ 
+ 	dpy->mouseproofedp = proofp;
   
  	/* Salt away the host:display string for later use */
  	buf[0] = ':';
***************
*** 190,195 ****
--- 264,270 ----
  		close (dpy->fd);
  		free ((char *)dpy);
  		errno = ENOMEM;
+ 		check (sigvec (SIGPIPE, &ovec, 0));
  		return(NULL);
  	}
  	strcpy (dpy->displayname, displaybuf);
***************
*** 200,205 ****
--- 275,281 ----
  	    	close (dpy->fd);
  		free ((char *)dpy);
  		errno = ENOMEM;
+ 		check (sigvec (SIGPIPE, &ovec, 0));
  		return(NULL);
  	}
  	dpy->bufmax = dpy->buffer + BUFSIZE;
***************
*** 236,241 ****
--- 312,318 ----
  	    	close (dpy->fd);
  		free (dpy->buffer);
  		free ((char *)dpy);
+ 		check (sigvec (SIGPIPE, &ovec, 0));
  		return(NULL);
  	}
   
***************
*** 252,257 ****
--- 329,335 ----
  	    close (dpy->fd);
  	    free (dpy->buffer);
  	    free ((char *)dpy);
+ 	    check (sigvec (SIGPIPE, &ovec, 0));
  	    return (NULL);
  	    }
  	dpy->black = rep.param.l[0];
***************
*** 262,270 ****
--- 340,367 ----
  	    close (dpy->fd);
  	    free (dpy->buffer);
  	    free ((char *)dpy);
+ 	    check (sigvec (SIGPIPE, &ovec, 0));
  	    return (NULL);
  	    }
  	dpy->white = rep.param.l[0];
   
+ 	check (sigvec (SIGPIPE, &ovec, 0));
  	return(dpy);
  }
+ 
+ /* 
+  * Connects to a server, creates a Display object and returns a pointer to
+  * the newly created Display back to the caller.
+  */
+ Display *XOpenDisplay (display)
+      char *display;
+ {
+   return (IntXOpenDisplay (display, FALSE));
+ }
+ 
+ Display *XProofOpenDisplay (display)
+      char *display;
+ {
+   return (IntXOpenDisplay (display, TRUE));
+ }
+ 
[b.ergo]/usr/misc/X/Xlib% sccs sccsdiff -r1.1 -r1.2 -c3 XlibInternal.c
*** /tmp/geta11075	Tue Jun 23 00:40:43 1987
--- /tmp/getb11075	Tue Jun 23 00:40:44 1987
***************
*** 59,69 ****
  	bufindex = dpy->bufptr = dpy->buffer;
  	/*
  	 * While write has not written the entire buffer, keep looping
! 	 * untill the entire buffer is written.  bufindex will be incremented
  	 * and size decremented as buffer is written out.
  	 */
  	while (size) {
! 		if ((write_stat = write(dpy->fd, bufindex, size)) == -1) {
  			/* Write failed! */
  			/* errno set by write system call. */
  			_XIOError(dpy);
--- 59,69 ----
  	bufindex = dpy->bufptr = dpy->buffer;
  	/*
  	 * While write has not written the entire buffer, keep looping
! 	 * until the entire buffer is written.  bufindex will be incremented
  	 * and size decremented as buffer is written out.
  	 */
  	while (size) {
! 		if ((write_stat = write((dpy->mouseproofedp?dpy->writefd:dpy->fd), bufindex, size)) == -1) {
  			/* Write failed! */
  			/* errno set by write system call. */
  			_XIOError(dpy);
***************
*** 189,195 ****
  	/*
  	 * Use while to allow for incremental writes.
  	 */
! 	while ((size = writev(dpy->fd, iov, 3)) != len) {
  	    	if (size < 0) _XIOError(dpy);
  		len -= size;
  		if ((iov[0].iov_len -= size) < 0) {
--- 189,195 ----
  	/*
  	 * Use while to allow for incremental writes.
  	 */
! 	while ((size = writev((dpy->mouseproofedp?dpy->writefd:dpy->fd), iov, 3)) != len) {
  	    	if (size < 0) _XIOError(dpy);
  		len -= size;
  		if ((iov[0].iov_len -= size) < 0) {
!E!O!F!
#
# type    sh /usrea0/tsf/xchange/../xchangeshar   to unpack this archive.
#
echo extracting xmouseproofserver.c...
cat >xmouseproofserver.c <<'!E!O!F!'
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
extern int errno;
static struct timeval pipetimeout = {3L, 0L};
/*This routine determines whether a given error code represents an error.  
If it does, then we print an error message and bomb.  If it doesn't, then
the code is the returned value of check.*/

static int check (code)
int code;
{
  if (code < 0) {
    fprintf (stderr, "Unanticipated error:\n");
    perror ("");
    exit (1);
  }
  return (code);
}

main ()
{
  int fd = 4;
  char buffer [2048];
  int Xmask = 1<<fd;
  int lispwritefd = 1;
  int lispreadfd = 0;
  int lispwritemask;
  int lispreadmask;
  int bothmask;			/* Used as mask in select. */
  int code;
  int nbytes;			/* Number of bytes read from last I/O operation.*/
  int blocks = 0;		/* Number of times we have been */
				/* blocked (the values are 0 for 0 and */
				/* 1 for 1 or more. */

  signal (SIGINT, SIG_IGN); /* Don't die on control-C's! */
  lispwritemask = 1<<lispwritefd;
  lispreadmask = 1 << lispreadfd;
  check (fcntl (lispwritefd, F_SETFL,
		check (fcntl (lispwritefd, F_GETFL, 0))
		| O_NDELAY));
  for (;;) {
    bothmask = Xmask | lispreadmask;
    check (select (32, &bothmask, 0, 0, 0));
    if (bothmask & Xmask) {
      nbytes = check (read (fd, buffer, sizeof (buffer)));
      if (nbytes == 0) exit (0);
      do {
	code = write (lispwritefd, buffer, nbytes);
	if (code > 0) {
	  nbytes -= code;
	  blocks = 0;
	} else if ((errno != EWOULDBLOCK) && (errno != EMSGSIZE)) {
	  check (code);
	} else {
	  if (blocks == 0) {
	    sleep (1);
	    blocks = 1;
	  } else {
	    nbytes = 0;
	  }
	}
      } while (nbytes > 0);
    } else {
      nbytes = check (read (lispreadfd, buffer, sizeof (buffer)));
      if (nbytes == 0) exit (0);
      do {
	nbytes -= check (write (fd, buffer, nbytes));
      } while (nbytes > 0);
    }
  }
}
!E!O!F!
-- 
Tim Freeman

Arpanet: tsf@theory.cs.cmu.edu
Uucp:    ...!seismo!theory.cs.cmu.edu!tsf

tsf@theory.cs.cmu.edu (Timothy Freeman) (06/30/87)

The mouseproofing stuff I posted leaves one useless process laying
around and leaks one file descriptor each time you open and close the
display.  Here are bug fixes to keep that from happening.  The files
that changed were XOpenDisplay.c, XCloseDisplay.c, and
xmouseproofserver.c.

[b.ergo]/usr/misc/X/Xlib% sccs sccsdiff -r1.2 -r1.3 xmouseproofserver.c -c3
*** /tmp/geta16818	Mon Jun 29 17:11:45 1987
--- /tmp/getb16818	Mon Jun 29 17:11:46 1987
***************
*** 36,41 ****
--- 36,45 ----
  				/* blocked (the values are 0 for 0 and */
  				/* 1 for 1 or more. */
  
+   if (check (fork ())) {
+     /* Parent */
+     exit (0); /* Keep zombies from forming. */
+   }
    signal (SIGINT, SIG_IGN); /* Don't die on control-C's! */
    lispwritemask = 1<<lispwritefd;
    lispreadmask = 1 << lispreadfd;
[b.ergo]/usr/misc/X/Xlib% sccs sccsdiff -r1.3 -r1.4 XOpenDisplay.c -c3
*** /tmp/geta16843	Mon Jun 29 17:12:34 1987
--- /tmp/getb16843	Mon Jun 29 17:12:34 1987
***************
*** 217,227 ****
  	if (proofp) {
  	  int fd = dpy -> fd;
  	  int readpipes [2], writepipes [2];
  
  	  check (pipe (readpipes));
  	  check (pipe (writepipes));
! 	  if (check (vfork ())) {
  	    /* Parent */
  	    close (readpipes [1]);
  	    dpy -> fd = readpipes [0];
  	    close (writepipes [0]);
--- 217,229 ----
  	if (proofp) {
  	  int fd = dpy -> fd;
  	  int readpipes [2], writepipes [2];
+ 	  int pid;
  
  	  check (pipe (readpipes));
  	  check (pipe (writepipes));
! 	  if (pid = check (vfork ())) {
  	    /* Parent */
+ 	    while (wait (0) != pid); /* Avoid making zombies. */
  	    close (readpipes [1]);
  	    dpy -> fd = readpipes [0];
  	    close (writepipes [0]);
[b.ergo]/usr/misc/X/Xlib% sccs sccsdiff -r1.1 -r1.2 XCloseDisplay.c -c3
*** /tmp/geta16855	Mon Jun 29 17:13:48 1987
--- /tmp/getb16855	Mon Jun 29 17:13:48 1987
***************
*** 26,31 ****
--- 26,35 ----
  		/* Argh! someone already closed the descriptor! */
  		_XIOError(_XlibCurrentDisplay);
  	}
+ 	if (dpy->mouseproofedp && (close(dpy->writefd) == -1)) {
+ 		/* Argh! someone already closed the descriptor! */
+ 		_XIOError(_XlibCurrentDisplay);
+ 	}
  	sigsetmask(sig_mask);		/* Return signals to normal. */
  	if (dpy->displayname) free(dpy->displayname);
  	free(dpy->buffer);
-- 
Tim Freeman

Arpanet: tsf@theory.cs.cmu.edu
Uucp:    ...!seismo!theory.cs.cmu.edu!tsf