|
|
1.1 ! root 1: /* ! 2: * tkError.c -- ! 3: * ! 4: * This file provides a high-performance mechanism for ! 5: * selectively dealing with errors that occur in talking ! 6: * to the X server. This is useful, for example, when ! 7: * communicating with a window that may not exist. ! 8: * ! 9: * Copyright 1990 Regents of the University of California. ! 10: * Permission to use, copy, modify, and distribute this ! 11: * software and its documentation for any purpose and without ! 12: * fee is hereby granted, provided that the above copyright ! 13: * notice appear in all copies. The University of California ! 14: * makes no representations about the suitability of this ! 15: * software for any purpose. It is provided "as is" without ! 16: * express or implied warranty. ! 17: */ ! 18: ! 19: #ifndef lint ! 20: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkError.c,v 1.10 92/04/12 17:02:08 ouster Exp $ SPRITE (Berkeley)"; ! 21: #endif ! 22: ! 23: #include "tkconfig.h" ! 24: #include "tkint.h" ! 25: ! 26: static initialized = 0; ! 27: ! 28: /* ! 29: * Forward references to procedures declared later in this file: ! 30: */ ! 31: ! 32: static int ErrorProc _ANSI_ARGS_((Display *display, ! 33: XErrorEvent *errEventPtr)); ! 34: ! 35: /* ! 36: *-------------------------------------------------------------- ! 37: * ! 38: * Tk_CreateErrorHandler -- ! 39: * ! 40: * Arrange for all a given procedure to be invoked whenever ! 41: * certain errors occur. ! 42: * ! 43: * Results: ! 44: * The return value is a token identifying the handler; ! 45: * it must be passed to Tk_DeleteErrorHandler to delete the ! 46: * handler. ! 47: * ! 48: * Side effects: ! 49: * If an X error occurs that matches the error, request, ! 50: * and minor arguments, then errorProc will be invoked. ! 51: * ErrorProc should have the following structure: ! 52: * ! 53: * int ! 54: * errorProc(clientData, errorEventPtr) ! 55: * caddr_t clientData; ! 56: * XErrorEvent *errorEventPtr; ! 57: * { ! 58: * } ! 59: * ! 60: * The clientData argument will be the same as the clientData ! 61: * argument to this procedure, and errorEvent will describe ! 62: * the error. If errorProc returns 0, it means that it ! 63: * completely "handled" the error: no further processing ! 64: * should be done. If errorProc returns 1, it means that it ! 65: * didn't know how to deal with the error, so we should look ! 66: * for other error handlers, or invoke the default error ! 67: * handler if no other handler returns zero. Handlers are ! 68: * invoked in order of age: youngest handler first. ! 69: * ! 70: * Note: errorProc will only be called for errors associated ! 71: * with X requests made AFTER this call, but BEFORE the handler ! 72: * is deleted by calling Tk_DeleteErrorHandler. ! 73: * ! 74: *-------------------------------------------------------------- ! 75: */ ! 76: ! 77: Tk_ErrorHandler ! 78: Tk_CreateErrorHandler(display, error, request, minorCode, errorProc, clientData) ! 79: Display *display; /* Display for which to handle ! 80: * errors. */ ! 81: int error; /* Consider only errors with this ! 82: * error_code (-1 means consider ! 83: * all errors). */ ! 84: int request; /* Consider only errors with this ! 85: * major request code (-1 means ! 86: * consider all major codes). */ ! 87: int minorCode; /* Consider only errors with this ! 88: * minor request code (-1 means ! 89: * consider all minor codes). */ ! 90: Tk_ErrorProc *errorProc; /* Procedure to invoke when a ! 91: * matching error occurs. NULL means ! 92: * just ignore matching errors. */ ! 93: ClientData clientData; /* Arbitrary value to pass to ! 94: * errorProc. */ ! 95: { ! 96: register TkErrorHandler *errorPtr; ! 97: register TkDisplay *dispPtr; ! 98: ! 99: /* ! 100: * Make sure that X calls us whenever errors occur. ! 101: */ ! 102: ! 103: if (!initialized) { ! 104: XSetErrorHandler(ErrorProc); ! 105: initialized = 1; ! 106: } ! 107: ! 108: /* ! 109: * Find the display. If Tk doesn't know about this display, ! 110: * it's an error: panic. ! 111: */ ! 112: ! 113: for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { ! 114: if (dispPtr->display == display) { ! 115: break; ! 116: } ! 117: if (dispPtr == NULL) { ! 118: panic("Unknown display passed to Tk_CreateErrorHandler"); ! 119: } ! 120: } ! 121: ! 122: /* ! 123: * Create the handler record. ! 124: */ ! 125: ! 126: errorPtr = (TkErrorHandler *) ckalloc(sizeof(TkErrorHandler)); ! 127: errorPtr->dispPtr = dispPtr; ! 128: errorPtr->firstRequest = NextRequest(display); ! 129: errorPtr->lastRequest = -1; ! 130: errorPtr->error = error; ! 131: errorPtr->request = request; ! 132: errorPtr->minorCode = minorCode; ! 133: errorPtr->errorProc = errorProc; ! 134: errorPtr->clientData = clientData; ! 135: errorPtr->nextPtr = dispPtr->errorPtr; ! 136: dispPtr->errorPtr = errorPtr; ! 137: ! 138: return (Tk_ErrorHandler) errorPtr; ! 139: } ! 140: ! 141: /* ! 142: *-------------------------------------------------------------- ! 143: * ! 144: * Tk_DeleteErrorHandler -- ! 145: * ! 146: * Do not use an error handler anymore. ! 147: * ! 148: * Results: ! 149: * None. ! 150: * ! 151: * Side effects: ! 152: * The handler denoted by the "handler" argument will not ! 153: * be invoked for any X errors associated with requests ! 154: * made after this call. However, if errors arrive later ! 155: * for requests made BEFORE this call, then the handler ! 156: * will still be invoked. Call XSync if you want to be ! 157: * sure that all outstanding errors have been received ! 158: * and processed. ! 159: * ! 160: *-------------------------------------------------------------- ! 161: */ ! 162: ! 163: void ! 164: Tk_DeleteErrorHandler(handler) ! 165: Tk_ErrorHandler handler; /* Token for handler to delete; ! 166: * was previous return value from ! 167: * Tk_CreateErrorHandler. */ ! 168: { ! 169: register TkErrorHandler *errorPtr = (TkErrorHandler *) handler; ! 170: register TkDisplay *dispPtr = errorPtr->dispPtr; ! 171: ! 172: errorPtr->lastRequest = NextRequest(dispPtr->display) - 1; ! 173: ! 174: /* ! 175: * Every once-in-a-while, cleanup handlers that are no longer ! 176: * active. We probably won't be able to free the handler that ! 177: * was just deleted (need to wait for any outstanding requests to ! 178: * be processed by server), but there may be previously-deleted ! 179: * handlers that are now ready for garbage collection. To reduce ! 180: * the cost of the cleanup, let a few dead handlers pile up, then ! 181: * clean them all at once. This adds a bit of overhead to errors ! 182: * that might occur while the dead handlers are hanging around, ! 183: * but reduces the overhead of scanning the list to clean up ! 184: * (particularly if there are many handlers that stay around ! 185: * forever). ! 186: */ ! 187: ! 188: dispPtr->deleteCount += 1; ! 189: if (dispPtr->deleteCount >= 10) { ! 190: register TkErrorHandler *prevPtr; ! 191: TkErrorHandler *nextPtr; ! 192: int lastSerial; ! 193: ! 194: dispPtr->deleteCount = 0; ! 195: lastSerial = LastKnownRequestProcessed(dispPtr->display); ! 196: errorPtr = dispPtr->errorPtr; ! 197: for (errorPtr = dispPtr->errorPtr, prevPtr = NULL; ! 198: errorPtr != NULL; errorPtr = nextPtr) { ! 199: nextPtr = errorPtr->nextPtr; ! 200: if ((errorPtr->lastRequest != -1) ! 201: && (errorPtr->lastRequest <= lastSerial)) { ! 202: if (prevPtr == NULL) { ! 203: dispPtr->errorPtr = nextPtr; ! 204: } else { ! 205: prevPtr->nextPtr = nextPtr; ! 206: } ! 207: ckfree((char *) errorPtr); ! 208: continue; ! 209: } ! 210: prevPtr = errorPtr; ! 211: } ! 212: } ! 213: } ! 214: ! 215: /* ! 216: *-------------------------------------------------------------- ! 217: * ! 218: * ErrorProc -- ! 219: * ! 220: * This procedure is invoked by the X system when error ! 221: * events arrive. ! 222: * ! 223: * Results: ! 224: * If it returns, the return value is zero. However, ! 225: * it is possible that one of the error handlers may ! 226: * just exit. ! 227: * ! 228: * Side effects: ! 229: * This procedure does two things. First, it uses the ! 230: * serial # in the error event to eliminate handlers whose ! 231: * expiration serials are now in the past. Second, it ! 232: * invokes any handlers that want to deal with the error. ! 233: * ! 234: *-------------------------------------------------------------- ! 235: */ ! 236: ! 237: static int ! 238: ErrorProc(display, errEventPtr) ! 239: Display *display; /* Display for which error ! 240: * occurred. */ ! 241: register XErrorEvent *errEventPtr; /* Information about error. */ ! 242: { ! 243: register TkDisplay *dispPtr; ! 244: register TkErrorHandler *errorPtr; ! 245: extern int _XDefaultError(); ! 246: ! 247: /* ! 248: * See if we know anything about the display. If not, then ! 249: * invoke the default error handler. ! 250: */ ! 251: ! 252: for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { ! 253: if (dispPtr == NULL) { ! 254: goto couldntHandle; ! 255: } ! 256: if (dispPtr->display == display) { ! 257: break; ! 258: } ! 259: } ! 260: ! 261: /* ! 262: * Otherwise invoke any relevant handlers for the error, in order. ! 263: */ ! 264: ! 265: for (errorPtr = dispPtr->errorPtr; errorPtr != NULL; ! 266: errorPtr = errorPtr->nextPtr) { ! 267: if ((errorPtr->firstRequest > errEventPtr->serial) ! 268: || ((errorPtr->error != -1) ! 269: && (errorPtr->error != errEventPtr->error_code)) ! 270: || ((errorPtr->request != -1) ! 271: && (errorPtr->request != errEventPtr->request_code)) ! 272: || ((errorPtr->minorCode != -1) ! 273: && (errorPtr->minorCode != errEventPtr->minor_code)) ! 274: || ((errorPtr->lastRequest != -1) ! 275: && (errorPtr->lastRequest < errEventPtr->serial))) { ! 276: continue; ! 277: } ! 278: if (errorPtr->errorProc == NULL) { ! 279: return 0; ! 280: } else { ! 281: if ((*errorPtr->errorProc)(errorPtr->clientData, ! 282: errEventPtr) == 0) { ! 283: return 0; ! 284: } ! 285: } ! 286: } ! 287: ! 288: /* ! 289: * We couldn't handle the error. Use the default handler. ! 290: */ ! 291: ! 292: couldntHandle: ! 293: return _XDefaultError(display, errEventPtr); ! 294: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.