]> git.zerfleddert.de Git - micropolis/blob - src/tk/tkerror.c
search sounds and player in $ResourceDir
[micropolis] / src / tk / tkerror.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 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 \f
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 \f
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 \f
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 }
Impressum, Datenschutz