1: #include <X/mit-copyright.h> 2: 3: /* Copyright Massachusetts Institute of Technology 1985 */ 4: 5: /* 6: * XlibInternal.c - Internal support routines for the C subroutine 7: * interface library (Xlib) to the X Window System Protocol V8.0. 8: */ 9: 10: #include "XlibInternal.h" 11: #include <sys/uio.h> 12: 13: /* 14: * The following routines are internal routines used by Xlib for protocol 15: * packet transmission and reception. 16: * 17: * XIOError(Display *) will be called if any sort of system call error occurs. 18: * This is assumed to be a fatal condition, i.e., XIOError should not return. 19: * 20: * XError(Display *, XErrorEvent *) will be called whenever an X_Error event is 21: * received. This is not assumed to be a fatal condition, i.e., it is 22: * acceptable for this procedure to return. However, XError should NOT 23: * perform any operations (directly or indirectly) on the DISPLAY. 24: * 25: * Routines declared with a return type of 'Status' return 0 on failure, 26: * and non 0 on success. Routines with no declared return type don't 27: * return anything. Whenever possible routines that create objects return 28: * the object they have created. 29: */ 30: 31: #ifndef lint 32: static char rcsid[] = "$Header: XlibInternal.c,v 10.12 86/02/01 15:42:11 tony Rel $"; 33: #endif 34: 35: Display *_XlibCurrentDisplay = NULL; /* default display to use in library */ 36: _QEvent *_qfree = NULL; /* NULL _QEvent. */ 37: 38: static int padlength[4] = {0, 3, 2, 1}; 39: /* lookup table for adding padding bytes to data that is read from 40: or written to the X socket. */ 41: 42: /* 43: * _XFlush - Flush the X request buffer. If the buffer is empty, no 44: * action is taken. This routine correctly handles incremental writes. 45: */ 46: _XFlush (dpy) 47: register Display *dpy; 48: { 49: register int size; 50: register int write_stat; 51: register char *bufindex; 52: 53: size = dpy->bufptr - dpy->buffer; 54: bufindex = dpy->bufptr = dpy->buffer; 55: /* 56: * While write has not written the entire buffer, keep looping 57: * untill the entire buffer is written. bufindex will be incremented 58: * and size decremented as buffer is written out. 59: */ 60: while (size) { 61: if ((write_stat = write(dpy->fd, bufindex, size)) == -1) { 62: /* Write failed! */ 63: /* errno set by write system call. */ 64: _XIOError(dpy); 65: } 66: size -= write_stat; 67: bufindex += write_stat; 68: } 69: dpy->lastdraw = NULL; 70: } 71: 72: 73: /* 74: * _XRead - Read bytes from the socket taking into account incomplete 75: * reads. 76: */ 77: _XRead (dpy, data, size) 78: register Display *dpy; 79: register char *data; 80: register int size; 81: { 82: register int bytes_read; 83: 84: while ((bytes_read = read(dpy->fd, data, size)) != size) { 85: 86: if (bytes_read > 0) { 87: size -= bytes_read; 88: data += bytes_read; 89: } 90: 91: else if (bytes_read == 0) { 92: /* Read failed because of end of file! */ 93: errno = EPIPE; 94: _XIOError(dpy); 95: } 96: 97: else /* bytes_read is less than 0; presumably -1 */ { 98: /* If it's a system call interrupt, it's not an error. */ 99: if (errno != EINTR) 100: _XIOError(dpy); 101: } 102: } 103: } 104: 105: /* 106: * _XReadPad - Read bytes from the socket taking into account incomplete 107: * reads. If the number of bytes is not 0 mod 32, read additional pad 108: * bytes. 109: */ 110: _XReadPad (dpy, data, size) 111: register Display *dpy; 112: register char *data; 113: register int size; 114: { 115: register int bytes_read; 116: struct iovec iov[2]; 117: char pad[3]; 118: 119: iov[0].iov_len = size; 120: iov[0].iov_base = data; 121: /* 122: * The following hack is used to provide 32 bit long-word 123: * aligned padding. The [1] vector is of length 0, 1, 2, or 3, 124: * whatever is needed. 125: */ 126: 127: iov[1].iov_len = padlength[size & 3]; 128: iov[1].iov_base = pad; 129: size += iov[1].iov_len; 130: 131: while ((bytes_read = readv (dpy->fd, iov, 2)) != size) { 132: 133: if (bytes_read > 0) { 134: size -= bytes_read; 135: if ((iov[0].iov_len -= bytes_read) < 0) { 136: iov[1].iov_len += iov[0].iov_len; 137: iov[1].iov_base -= iov[0].iov_len; 138: iov[0].iov_len = 0; 139: } 140: else 141: iov[0].iov_base += bytes_read; 142: } 143: 144: else if (bytes_read == 0) { 145: /* Read failed because of end of file! */ 146: errno = EPIPE; 147: _XIOError(dpy); 148: } 149: 150: else /* bytes_read is less than 0; presumably -1 */ { 151: /* If it's a system call interrupt, it's not an error. */ 152: if (errno != EINTR) 153: _XIOError(dpy); 154: } 155: } 156: 157: } 158: 159: /* 160: * _XSend - Flush the buffer and send the client data. 32 bit word aligned 161: * transmission is used, if size is not 0 mod 4, extra bytes are transmitted. 162: */ 163: _XSend (dpy, data, size) 164: register Display *dpy; 165: char *data; 166: register int size; 167: { 168: register int len; 169: struct iovec iov[3]; 170: char pad[3]; 171: 172: iov[0].iov_len = len = dpy->bufptr - dpy->buffer; 173: iov[0].iov_base = dpy->bufptr = dpy->buffer; 174: iov[1].iov_len = size; 175: iov[1].iov_base = data; 176: /* 177: * The following hack is used to provide 32 bit long-word 178: * aligned padding. The [2] vector is of length 0, 1, 2, or 3, 179: * whatever is needed. 180: */ 181: iov[2].iov_len = padlength[size & 3]; 182: iov[2].iov_base = pad; 183: len += (size + 3) & ~3; 184: /* 185: * Use while to allow for incremental writes. 186: */ 187: while ((size = writev(dpy->fd, iov, 3)) != len) { 188: if (size < 0) _XIOError(dpy); 189: len -= size; 190: if ((iov[0].iov_len -= size) < 0) { 191: iov[1].iov_len += iov[0].iov_len; 192: iov[1].iov_base -= iov[0].iov_len; 193: iov[0].iov_len = 0; 194: if (iov[1].iov_len < 0) { 195: iov[2].iov_len += iov[1].iov_len; 196: iov[2].iov_base -= iov[1].iov_len; 197: iov[1].iov_len = 0; 198: } 199: } 200: else { 201: iov[0].iov_base += size; 202: } 203: } 204: dpy->lastdraw = NULL; 205: } 206: 207: /* 208: * _XReply - Wait for a reply packet and copy its contents into the 209: * specified rep. Mean while we must handle error and event packets that 210: * we may encounter. 211: */ 212: Status _XReply (dpy, rep) 213: register Display *dpy; 214: register XRep *rep; 215: { 216: _XFlush(dpy); 217: while (1) { 218: _XRead(dpy, (char *)rep, sizeof(XRep)); 219: switch ((int)rep->code) { 220: 221: case X_Reply: 222: /* Reply recieved. */ 223: return(1); 224: 225: case X_Error: 226: { 227: /* X_Error packet encountered! */ 228: int current_request = dpy->request; 229: XErrorEvent *error = (XErrorEvent *) rep; 230: 231: if (error->serial == current_request) 232: /* do not die on "no such font", "can't allocate", 233: "can't grab" failures */ 234: switch (error->error_code) { 235: case BadFont: 236: if (error->request_code != X_GetFont) 237: break; 238: case BadAlloc: 239: case BadColor: 240: case BadGrab: 241: return (0); 242: } 243: _XError(dpy, error); 244: if (error->serial == current_request) 245: return(0); 246: } 247: break; 248: default: 249: _XEnq(dpy, (XEvent *) rep); 250: break; 251: } 252: } 253: } 254: 255: 256: /* 257: * _XEnq - Place event packets on the display's queue. 258: */ 259: _XEnq (dpy, event) 260: register Display *dpy; 261: register XEvent *event; 262: { 263: register _QEvent *qelt; 264: extern char *malloc(); 265: 266: if ( 267: /* If we are squishing MouseMoved events AND ... */ 268: dpy->squish && 269: /* the current event is a MouseMoved event AND ... */ 270: (event->type == MouseMoved) && 271: /* if there is a last event on the display queue AND ... */ 272: (qelt = dpy->tail) && 273: /* if that last event is also a MouseMoved event AND ... */ 274: (qelt->event.type == MouseMoved) && 275: /* it has the same event window as the current event ... */ 276: (event->window == qelt->event.window) 277: ) { 278: /* then replace the last event with the current event! */ 279: qelt->event = *event; 280: return; 281: } 282: if (qelt = _qfree) { 283: /* If _qfree is non-NULL do this, else malloc a new one. */ 284: _qfree = qelt->next; 285: } 286: else if ((qelt = (_QEvent *) malloc((unsigned)sizeof(_QEvent))) == NULL) { 287: /* Malloc call failed! */ 288: errno = ENOMEM; 289: _XIOError(dpy); 290: } 291: qelt->next = NULL; 292: qelt->event = *event; 293: if (dpy->tail) { 294: dpy->tail->next = qelt; 295: } 296: else { 297: dpy->head = qelt; 298: } 299: dpy->tail = qelt; 300: dpy->qlen++; 301: } 302: 303: 304: /* 305: * Undefine the routine pointers so we can define the following default 306: * routines. 307: */ 308: #undef _XError 309: #undef _XIOError 310: 311: 312: /* 313: * _XIOError - Default fatal system error reporting routine. Called when 314: * an X internal system error is encountered. 315: */ 316: /*ARGSUSED*/ 317: _XIOError (dpy) 318: Display *dpy; 319: { 320: perror("XIO"); 321: exit(1); 322: } 323: 324: 325: /* 326: * _XError - Default non-fatal error reporting routine. Called when an 327: * X_Error packet is encountered in the input stream. 328: */ 329: _XError (dpy, rep) 330: Display *dpy; 331: XErrorEvent *rep; 332: { 333: fprintf(stderr, "X Error: %s\n", XErrDescrip (rep->error_code)); 334: fprintf(stderr, " Request code: %d\n", rep->request_code); 335: fprintf(stderr, " Request function: %d\n", rep->func); 336: fprintf(stderr, " Request window 0x%x\n", rep->window); 337: fprintf(stderr, " Error Serial #%d\n", rep->serial); 338: fprintf(stderr, " Current serial #%d\n", dpy->request); 339: exit(1); 340: } 341: 342: int (*_XIOErrorFunction)() = _XIOError; 343: int (*_XErrorFunction)() = _XError;