home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkError.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-16  |  9.2 KB  |  302 lines

  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-1993 The Regents of the University of California.
  10.  * All rights reserved.
  11.  *
  12.  * Permission is hereby granted, without written agreement and without
  13.  * license or royalty fees, to use, copy, modify, and distribute this
  14.  * software and its documentation for any purpose, provided that the
  15.  * above copyright notice and the following two paragraphs appear in
  16.  * all copies of this software.
  17.  * 
  18.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  19.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  20.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  21.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22.  *
  23.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  24.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  25.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  26.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  27.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  28.  */
  29.  
  30. #ifndef lint
  31. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkError.c,v 1.12 93/06/16 17:14:52 ouster Exp $ SPRITE (Berkeley)";
  32. #endif
  33.  
  34. #include "tkConfig.h"
  35. #include "tkInt.h"
  36.  
  37. /*
  38.  * Forward references to procedures declared later in this file:
  39.  */
  40.  
  41. static int    ErrorProc _ANSI_ARGS_((Display *display,
  42.             XErrorEvent *errEventPtr));
  43.  
  44. /*
  45.  *--------------------------------------------------------------
  46.  *
  47.  * Tk_CreateErrorHandler --
  48.  *
  49.  *    Arrange for all a given procedure to be invoked whenever
  50.  *    certain errors occur.
  51.  *
  52.  * Results:
  53.  *    The return value is a token identifying the handler;
  54.  *    it must be passed to Tk_DeleteErrorHandler to delete the
  55.  *    handler.
  56.  *
  57.  * Side effects:
  58.  *    If an X error occurs that matches the error, request,
  59.  *    and minor arguments, then errorProc will be invoked.
  60.  *    ErrorProc should have the following structure:
  61.  *
  62.  *    int
  63.  *    errorProc(clientData, errorEventPtr)
  64.  *        caddr_t clientData;
  65.  *        XErrorEvent *errorEventPtr;
  66.  *    {
  67.  *    }
  68.  *
  69.  *    The clientData argument will be the same as the clientData
  70.  *    argument to this procedure, and errorEvent will describe
  71.  *    the error.  If errorProc returns 0, it means that it
  72.  *    completely "handled" the error:  no further processing
  73.  *    should be done.  If errorProc returns 1, it means that it
  74.  *    didn't know how to deal with the error, so we should look
  75.  *    for other error handlers, or invoke the default error
  76.  *    handler if no other handler returns zero.  Handlers are
  77.  *    invoked in order of age:  youngest handler first.
  78.  *
  79.  *    Note:  errorProc will only be called for errors associated
  80.  *    with X requests made AFTER this call, but BEFORE the handler
  81.  *    is deleted by calling Tk_DeleteErrorHandler.
  82.  *
  83.  *--------------------------------------------------------------
  84.  */
  85.  
  86. Tk_ErrorHandler
  87. Tk_CreateErrorHandler(display, error, request, minorCode, errorProc, clientData)
  88.     Display *display;        /* Display for which to handle
  89.                  * errors. */
  90.     int error;            /* Consider only errors with this
  91.                  * error_code (-1 means consider
  92.                  * all errors). */
  93.     int request;        /* Consider only errors with this
  94.                  * major request code (-1 means
  95.                  * consider all major codes). */
  96.     int minorCode;        /* Consider only errors with this
  97.                  * minor request code (-1 means
  98.                  * consider all minor codes). */
  99.     Tk_ErrorProc *errorProc;    /* Procedure to invoke when a
  100.                  * matching error occurs.  NULL means
  101.                  * just ignore matching errors. */
  102.     ClientData clientData;    /* Arbitrary value to pass to
  103.                  * errorProc. */
  104. {
  105.     register TkErrorHandler *errorPtr;
  106.     register TkDisplay *dispPtr;
  107.  
  108.     /*
  109.      * Find the display.  If Tk doesn't know about this display then
  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.      * Make sure that X calls us whenever errors occur.
  124.      */
  125.  
  126.     if (dispPtr->defaultHandler == NULL) {
  127.     dispPtr->defaultHandler = XSetErrorHandler(ErrorProc);
  128.     }
  129.  
  130.     /*
  131.      * Create the handler record.
  132.      */
  133.  
  134.     errorPtr = (TkErrorHandler *) ckalloc(sizeof(TkErrorHandler));
  135.     errorPtr->dispPtr = dispPtr;
  136.     errorPtr->firstRequest = NextRequest(display);
  137.     errorPtr->lastRequest = -1;
  138.     errorPtr->error = error;
  139.     errorPtr->request = request;
  140.     errorPtr->minorCode = minorCode;
  141.     errorPtr->errorProc = errorProc;
  142.     errorPtr->clientData = clientData;
  143.     errorPtr->nextPtr = dispPtr->errorPtr;
  144.     dispPtr->errorPtr = errorPtr;
  145.  
  146.     return (Tk_ErrorHandler) errorPtr;
  147. }
  148.  
  149. /*
  150.  *--------------------------------------------------------------
  151.  *
  152.  * Tk_DeleteErrorHandler --
  153.  *
  154.  *    Do not use an error handler anymore.
  155.  *
  156.  * Results:
  157.  *    None.
  158.  *
  159.  * Side effects:
  160.  *    The handler denoted by the "handler" argument will not
  161.  *    be invoked for any X errors associated with requests
  162.  *    made after this call.  However, if errors arrive later
  163.  *    for requests made BEFORE this call, then the handler
  164.  *    will still be invoked.  Call XSync if you want to be
  165.  *    sure that all outstanding errors have been received
  166.  *    and processed.
  167.  *
  168.  *--------------------------------------------------------------
  169.  */
  170.  
  171. void
  172. Tk_DeleteErrorHandler(handler)
  173.     Tk_ErrorHandler handler;    /* Token for handler to delete;
  174.                  * was previous return value from
  175.                  * Tk_CreateErrorHandler. */
  176. {
  177.     register TkErrorHandler *errorPtr = (TkErrorHandler *) handler;
  178.     register TkDisplay *dispPtr = errorPtr->dispPtr;
  179.  
  180.     errorPtr->lastRequest = NextRequest(dispPtr->display) - 1;
  181.  
  182.     /*
  183.      * Every once-in-a-while, cleanup handlers that are no longer
  184.      * active.  We probably won't be able to free the handler that
  185.      * was just deleted (need to wait for any outstanding requests to
  186.      * be processed by server), but there may be previously-deleted
  187.      * handlers that are now ready for garbage collection.  To reduce
  188.      * the cost of the cleanup, let a few dead handlers pile up, then
  189.      * clean them all at once.  This adds a bit of overhead to errors
  190.      * that might occur while the dead handlers are hanging around,
  191.      * but reduces the overhead of scanning the list to clean up
  192.      * (particularly if there are many handlers that stay around
  193.      * forever).
  194.      */
  195.  
  196.     dispPtr->deleteCount += 1;
  197.     if (dispPtr->deleteCount >= 10) {
  198.     register TkErrorHandler *prevPtr;
  199.     TkErrorHandler *nextPtr;
  200.     int lastSerial;
  201.  
  202.     dispPtr->deleteCount = 0;
  203.     lastSerial = LastKnownRequestProcessed(dispPtr->display);
  204.     errorPtr = dispPtr->errorPtr;
  205.     for (errorPtr = dispPtr->errorPtr, prevPtr = NULL;
  206.         errorPtr != NULL;  errorPtr = nextPtr) {
  207.         nextPtr = errorPtr->nextPtr;
  208.         if ((errorPtr->lastRequest != -1)
  209.             && (errorPtr->lastRequest <= lastSerial)) {
  210.         if (prevPtr == NULL) {
  211.             dispPtr->errorPtr = nextPtr;
  212.         } else {
  213.             prevPtr->nextPtr = nextPtr;
  214.         }
  215.         ckfree((char *) errorPtr);
  216.         continue;
  217.         }
  218.         prevPtr = errorPtr;
  219.     }
  220.     }
  221. }
  222.  
  223. /*
  224.  *--------------------------------------------------------------
  225.  *
  226.  * ErrorProc --
  227.  *
  228.  *    This procedure is invoked by the X system when error
  229.  *    events arrive.
  230.  *
  231.  * Results:
  232.  *    If it returns, the return value is zero.  However,
  233.  *    it is possible that one of the error handlers may
  234.  *    just exit.
  235.  *
  236.  * Side effects:
  237.  *    This procedure does two things.  First, it uses the
  238.  *    serial #  in the error event to eliminate handlers whose
  239.  *    expiration serials are now in the past.  Second, it
  240.  *    invokes any handlers that want to deal with the error.
  241.  *
  242.  *--------------------------------------------------------------
  243.  */
  244.  
  245. static int
  246. ErrorProc(display, errEventPtr)
  247.     Display *display;            /* Display for which error
  248.                      * occurred. */
  249.     register XErrorEvent *errEventPtr;    /* Information about error. */
  250. {
  251.     register TkDisplay *dispPtr;
  252.     register TkErrorHandler *errorPtr;
  253.  
  254.     /*
  255.      * See if we know anything about the display.  If not, then
  256.      * invoke the default error handler.
  257.      */
  258.  
  259.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  260.     if (dispPtr == NULL) {
  261.         goto couldntHandle;
  262.     }
  263.     if (dispPtr->display == display) {
  264.         break;
  265.     }
  266.     }
  267.  
  268.     /*
  269.      * Otherwise invoke any relevant handlers for the error, in order.
  270.      */
  271.  
  272.     for (errorPtr = dispPtr->errorPtr; errorPtr != NULL;
  273.         errorPtr = errorPtr->nextPtr) {
  274.     if ((errorPtr->firstRequest > errEventPtr->serial)
  275.         || ((errorPtr->error != -1)
  276.             && (errorPtr->error != errEventPtr->error_code))
  277.         || ((errorPtr->request != -1)
  278.             && (errorPtr->request != errEventPtr->request_code))
  279.         || ((errorPtr->minorCode != -1)
  280.             && (errorPtr->minorCode != errEventPtr->minor_code))
  281.         || ((errorPtr->lastRequest != -1)
  282.             && (errorPtr->lastRequest < errEventPtr->serial))) {
  283.         continue;
  284.     }
  285.     if (errorPtr->errorProc == NULL) {
  286.         return 0;
  287.     } else {
  288.         if ((*errorPtr->errorProc)(errorPtr->clientData,
  289.             errEventPtr) == 0) {
  290.         return 0;
  291.         }
  292.     }
  293.     }
  294.  
  295.     /*
  296.      * We couldn't handle the error.  Use the default handler.
  297.      */
  298.  
  299.     couldntHandle:
  300.     return (*dispPtr->defaultHandler)(display, errEventPtr);
  301. }
  302.