]>
git.zerfleddert.de Git - micropolis/blob - src/tk/tkerror.c
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.
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.
20 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkError.c,v 1.10 92/04/12 17:02:08 ouster Exp $ SPRITE (Berkeley)";
26 static initialized
= 0;
29 * Forward references to procedures declared later in this file:
32 static int ErrorProc
_ANSI_ARGS_((Display
*display
,
33 XErrorEvent
*errEventPtr
));
36 *--------------------------------------------------------------
38 * Tk_CreateErrorHandler --
40 * Arrange for all a given procedure to be invoked whenever
41 * certain errors occur.
44 * The return value is a token identifying the handler;
45 * it must be passed to Tk_DeleteErrorHandler to delete the
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:
54 * errorProc(clientData, errorEventPtr)
56 * XErrorEvent *errorEventPtr;
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.
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.
74 *--------------------------------------------------------------
78 Tk_CreateErrorHandler(display
, error
, request
, minorCode
, errorProc
, clientData
)
79 Display
*display
; /* Display for which to handle
81 int error
; /* Consider only errors with this
82 * error_code (-1 means consider
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
96 register TkErrorHandler
*errorPtr
;
97 register TkDisplay
*dispPtr
;
100 * Make sure that X calls us whenever errors occur.
104 XSetErrorHandler(ErrorProc
);
109 * Find the display. If Tk doesn't know about this display,
110 * it's an error: panic.
113 for (dispPtr
= tkDisplayList
; ; dispPtr
= dispPtr
->nextPtr
) {
114 if (dispPtr
->display
== display
) {
117 if (dispPtr
== NULL
) {
118 panic("Unknown display passed to Tk_CreateErrorHandler");
123 * Create the handler record.
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
;
138 return (Tk_ErrorHandler
) errorPtr
;
142 *--------------------------------------------------------------
144 * Tk_DeleteErrorHandler --
146 * Do not use an error handler anymore.
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
160 *--------------------------------------------------------------
164 Tk_DeleteErrorHandler(handler
)
165 Tk_ErrorHandler handler
; /* Token for handler to delete;
166 * was previous return value from
167 * Tk_CreateErrorHandler. */
169 register TkErrorHandler
*errorPtr
= (TkErrorHandler
*) handler
;
170 register TkDisplay
*dispPtr
= errorPtr
->dispPtr
;
172 errorPtr
->lastRequest
= NextRequest(dispPtr
->display
) - 1;
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
188 dispPtr
->deleteCount
+= 1;
189 if (dispPtr
->deleteCount
>= 10) {
190 register TkErrorHandler
*prevPtr
;
191 TkErrorHandler
*nextPtr
;
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
;
205 prevPtr
->nextPtr
= nextPtr
;
207 ckfree((char *) errorPtr
);
216 *--------------------------------------------------------------
220 * This procedure is invoked by the X system when error
224 * If it returns, the return value is zero. However,
225 * it is possible that one of the error handlers may
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.
234 *--------------------------------------------------------------
238 ErrorProc(display
, errEventPtr
)
239 Display
*display
; /* Display for which error
241 register XErrorEvent
*errEventPtr
; /* Information about error. */
243 register TkDisplay
*dispPtr
;
244 register TkErrorHandler
*errorPtr
;
245 extern int _XDefaultError();
248 * See if we know anything about the display. If not, then
249 * invoke the default error handler.
252 for (dispPtr
= tkDisplayList
; ; dispPtr
= dispPtr
->nextPtr
) {
253 if (dispPtr
== NULL
) {
256 if (dispPtr
->display
== display
) {
262 * Otherwise invoke any relevant handlers for the error, in order.
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
))) {
278 if (errorPtr
->errorProc
== NULL
) {
281 if ((*errorPtr
->errorProc
)(errorPtr
->clientData
,
289 * We couldn't handle the error. Use the default handler.
293 return _XDefaultError(display
, errEventPtr
);