|
|
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.