tkError.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:9k
源码类别:

通讯编程

开发平台:

Visual C++

  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 (c) 1990-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tkError.c,v 1.2 1998/09/14 18:23:09 stanton Exp $
  16.  */
  17. #include "tkPort.h"
  18. #include "tkInt.h"
  19. /*
  20.  * The default X error handler gets saved here, so that it can
  21.  * be invoked if an error occurs that we can't handle.
  22.  */
  23. static int (*defaultHandler) _ANSI_ARGS_((Display *display,
  24.     XErrorEvent *eventPtr)) = NULL;
  25. /*
  26.  * Forward references to procedures declared later in this file:
  27.  */
  28. static int ErrorProc _ANSI_ARGS_((Display *display,
  29.     XErrorEvent *errEventPtr));
  30. /*
  31.  *--------------------------------------------------------------
  32.  *
  33.  * Tk_CreateErrorHandler --
  34.  *
  35.  * Arrange for all a given procedure to be invoked whenever
  36.  * certain errors occur.
  37.  *
  38.  * Results:
  39.  * The return value is a token identifying the handler;
  40.  * it must be passed to Tk_DeleteErrorHandler to delete the
  41.  * handler.
  42.  *
  43.  * Side effects:
  44.  * If an X error occurs that matches the error, request,
  45.  * and minor arguments, then errorProc will be invoked.
  46.  * ErrorProc should have the following structure:
  47.  *
  48.  * int
  49.  * errorProc(clientData, errorEventPtr)
  50.  *     caddr_t clientData;
  51.  *     XErrorEvent *errorEventPtr;
  52.  * {
  53.  * }
  54.  *
  55.  * The clientData argument will be the same as the clientData
  56.  * argument to this procedure, and errorEvent will describe
  57.  * the error.  If errorProc returns 0, it means that it
  58.  * completely "handled" the error:  no further processing
  59.  * should be done.  If errorProc returns 1, it means that it
  60.  * didn't know how to deal with the error, so we should look
  61.  * for other error handlers, or invoke the default error
  62.  * handler if no other handler returns zero.  Handlers are
  63.  * invoked in order of age:  youngest handler first.
  64.  *
  65.  * Note:  errorProc will only be called for errors associated
  66.  * with X requests made AFTER this call, but BEFORE the handler
  67.  * is deleted by calling Tk_DeleteErrorHandler.
  68.  *
  69.  *--------------------------------------------------------------
  70.  */
  71. Tk_ErrorHandler
  72. Tk_CreateErrorHandler(display, error, request, minorCode, errorProc, clientData)
  73.     Display *display; /* Display for which to handle
  74.  * errors. */
  75.     int error; /* Consider only errors with this
  76.  * error_code (-1 means consider
  77.  * all errors). */
  78.     int request; /* Consider only errors with this
  79.  * major request code (-1 means
  80.  * consider all major codes). */
  81.     int minorCode; /* Consider only errors with this
  82.  * minor request code (-1 means
  83.  * consider all minor codes). */
  84.     Tk_ErrorProc *errorProc; /* Procedure to invoke when a
  85.  * matching error occurs.  NULL means
  86.  * just ignore matching errors. */
  87.     ClientData clientData; /* Arbitrary value to pass to
  88.  * errorProc. */
  89. {
  90.     register TkErrorHandler *errorPtr;
  91.     register TkDisplay *dispPtr;
  92.     /*
  93.      * Find the display.  If Tk doesn't know about this display then
  94.      * it's an error:  panic.
  95.      */
  96.     dispPtr = TkGetDisplay(display);
  97.     if (dispPtr == NULL) {
  98. panic("Unknown display passed to Tk_CreateErrorHandler");
  99.     }
  100.     /*
  101.      * Make sure that X calls us whenever errors occur.
  102.      */
  103.     if (defaultHandler == NULL) {
  104. defaultHandler = XSetErrorHandler(ErrorProc);
  105.     }
  106.     /*
  107.      * Create the handler record.
  108.      */
  109.     errorPtr = (TkErrorHandler *) ckalloc(sizeof(TkErrorHandler));
  110.     errorPtr->dispPtr = dispPtr;
  111.     errorPtr->firstRequest = NextRequest(display);
  112.     errorPtr->lastRequest = (unsigned) -1;
  113.     errorPtr->error = error;
  114.     errorPtr->request = request;
  115.     errorPtr->minorCode = minorCode;
  116.     errorPtr->errorProc = errorProc;
  117.     errorPtr->clientData = clientData;
  118.     errorPtr->nextPtr = dispPtr->errorPtr;
  119.     dispPtr->errorPtr = errorPtr;
  120.     return (Tk_ErrorHandler) errorPtr;
  121. }
  122. /*
  123.  *--------------------------------------------------------------
  124.  *
  125.  * Tk_DeleteErrorHandler --
  126.  *
  127.  * Do not use an error handler anymore.
  128.  *
  129.  * Results:
  130.  * None.
  131.  *
  132.  * Side effects:
  133.  * The handler denoted by the "handler" argument will not
  134.  * be invoked for any X errors associated with requests
  135.  * made after this call.  However, if errors arrive later
  136.  * for requests made BEFORE this call, then the handler
  137.  * will still be invoked.  Call XSync if you want to be
  138.  * sure that all outstanding errors have been received
  139.  * and processed.
  140.  *
  141.  *--------------------------------------------------------------
  142.  */
  143. void
  144. Tk_DeleteErrorHandler(handler)
  145.     Tk_ErrorHandler handler; /* Token for handler to delete;
  146.  * was previous return value from
  147.  * Tk_CreateErrorHandler. */
  148. {
  149.     register TkErrorHandler *errorPtr = (TkErrorHandler *) handler;
  150.     register TkDisplay *dispPtr = errorPtr->dispPtr;
  151.     errorPtr->lastRequest = NextRequest(dispPtr->display) - 1;
  152.     /*
  153.      * Every once-in-a-while, cleanup handlers that are no longer
  154.      * active.  We probably won't be able to free the handler that
  155.      * was just deleted (need to wait for any outstanding requests to
  156.      * be processed by server), but there may be previously-deleted
  157.      * handlers that are now ready for garbage collection.  To reduce
  158.      * the cost of the cleanup, let a few dead handlers pile up, then
  159.      * clean them all at once.  This adds a bit of overhead to errors
  160.      * that might occur while the dead handlers are hanging around,
  161.      * but reduces the overhead of scanning the list to clean up
  162.      * (particularly if there are many handlers that stay around
  163.      * forever).
  164.      */
  165.     dispPtr->deleteCount += 1;
  166.     if (dispPtr->deleteCount >= 10) {
  167. register TkErrorHandler *prevPtr;
  168. TkErrorHandler *nextPtr;
  169. int lastSerial;
  170. dispPtr->deleteCount = 0;
  171. lastSerial = LastKnownRequestProcessed(dispPtr->display);
  172. errorPtr = dispPtr->errorPtr;
  173. for (prevPtr = NULL; errorPtr != NULL; errorPtr = nextPtr) {
  174.     nextPtr = errorPtr->nextPtr;
  175.     if ((errorPtr->lastRequest != (unsigned long) -1)
  176.     && (errorPtr->lastRequest <= (unsigned long) lastSerial)) {
  177. if (prevPtr == NULL) {
  178.     dispPtr->errorPtr = nextPtr;
  179. } else {
  180.     prevPtr->nextPtr = nextPtr;
  181. }
  182. ckfree((char *) errorPtr);
  183. continue;
  184.     }
  185.     prevPtr = errorPtr;
  186. }
  187.     }
  188. }
  189. /*
  190.  *--------------------------------------------------------------
  191.  *
  192.  * ErrorProc --
  193.  *
  194.  * This procedure is invoked by the X system when error
  195.  * events arrive.
  196.  *
  197.  * Results:
  198.  * If it returns, the return value is zero.  However,
  199.  * it is possible that one of the error handlers may
  200.  * just exit.
  201.  *
  202.  * Side effects:
  203.  * This procedure does two things.  First, it uses the
  204.  * serial #  in the error event to eliminate handlers whose
  205.  * expiration serials are now in the past.  Second, it
  206.  * invokes any handlers that want to deal with the error.
  207.  *
  208.  *--------------------------------------------------------------
  209.  */
  210. static int
  211. ErrorProc(display, errEventPtr)
  212.     Display *display; /* Display for which error
  213.  * occurred. */
  214.     register XErrorEvent *errEventPtr; /* Information about error. */
  215. {
  216.     register TkDisplay *dispPtr;
  217.     register TkErrorHandler *errorPtr;
  218.     /*
  219.      * See if we know anything about the display.  If not, then
  220.      * invoke the default error handler.
  221.      */
  222.     dispPtr = TkGetDisplay(display);
  223.     if (dispPtr == NULL) {
  224. goto couldntHandle;
  225.     }
  226.     /*
  227.      * Otherwise invoke any relevant handlers for the error, in order.
  228.      */
  229.     for (errorPtr = dispPtr->errorPtr; errorPtr != NULL;
  230.     errorPtr = errorPtr->nextPtr) {
  231. if ((errorPtr->firstRequest > errEventPtr->serial)
  232. || ((errorPtr->error != -1)
  233.     && (errorPtr->error != errEventPtr->error_code))
  234. || ((errorPtr->request != -1)
  235.     && (errorPtr->request != errEventPtr->request_code))
  236. || ((errorPtr->minorCode != -1)
  237.     && (errorPtr->minorCode != errEventPtr->minor_code))
  238. || ((errorPtr->lastRequest != (unsigned long) -1)
  239.     && (errorPtr->lastRequest < errEventPtr->serial))) {
  240.     continue;
  241. }
  242. if (errorPtr->errorProc == NULL) {
  243.     return 0;
  244. } else {
  245.     if ((*errorPtr->errorProc)(errorPtr->clientData,
  246.     errEventPtr) == 0) {
  247. return 0;
  248.     }
  249. }
  250.     }
  251.     /*
  252.      * See if the error is a BadWindow error.  If so, and it refers
  253.      * to a window that still exists in our window table, then ignore
  254.      * the error.  Errors like this can occur if a window owned by us
  255.      * is deleted by someone externally, like a window manager.  We'll
  256.      * ignore the errors at least long enough to clean up internally and
  257.      * remove the entry from the window table.
  258.      *
  259.      * NOTE: For embedding, we must also check whether the window was
  260.      * recently deleted. If so, it may be that Tk generated operations on
  261.      * windows that were deleted by the container. Now we are getting
  262.      * the errors (BadWindow) after Tk already deleted the window itself.
  263.      */
  264.     if ((errEventPtr->error_code == BadWindow) &&
  265.             ((Tk_IdToWindow(display, (Window) errEventPtr->resourceid) !=
  266.                     NULL) ||
  267.                 (TkpWindowWasRecentlyDeleted((Window) errEventPtr->resourceid,
  268.                         dispPtr)))) {
  269. return 0;
  270.     }
  271.     /*
  272.      * We couldn't handle the error.  Use the default handler.
  273.      */
  274.     couldntHandle:
  275.     return (*defaultHandler)(display, errEventPtr);
  276. }