OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkError.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.