1 |
578 |
markom |
/*
|
2 |
|
|
* tkUnixXId.c --
|
3 |
|
|
*
|
4 |
|
|
* This file provides a replacement function for the default X
|
5 |
|
|
* resource allocator (_XAllocID). The problem with the default
|
6 |
|
|
* allocator is that it never re-uses ids, which causes long-lived
|
7 |
|
|
* applications to crash when X resource identifiers wrap around.
|
8 |
|
|
* The replacement functions in this file re-use old identifiers
|
9 |
|
|
* to prevent this problem.
|
10 |
|
|
*
|
11 |
|
|
* The code in this file is based on similar implementations by
|
12 |
|
|
* George C. Kaplan and Michael Hoegeman.
|
13 |
|
|
*
|
14 |
|
|
* Copyright (c) 1993 The Regents of the University of California.
|
15 |
|
|
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
|
16 |
|
|
*
|
17 |
|
|
* See the file "license.terms" for information on usage and redistribution
|
18 |
|
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
19 |
|
|
*
|
20 |
|
|
* RCS: @(#) $Id: tkUnixXId.c,v 1.1.1.1 2002-01-16 10:26:02 markom Exp $
|
21 |
|
|
*/
|
22 |
|
|
|
23 |
|
|
/*
|
24 |
|
|
* The definition below is needed on some systems so that we can access
|
25 |
|
|
* the resource_alloc field of Display structures in order to replace
|
26 |
|
|
* the resource allocator.
|
27 |
|
|
*/
|
28 |
|
|
|
29 |
|
|
#define XLIB_ILLEGAL_ACCESS 1
|
30 |
|
|
|
31 |
|
|
#include "tkInt.h"
|
32 |
|
|
#include "tkPort.h"
|
33 |
|
|
#include "tkUnixInt.h"
|
34 |
|
|
|
35 |
|
|
/*
|
36 |
|
|
* A structure of the following type is used to hold one or more
|
37 |
|
|
* available resource identifiers. There is a list of these structures
|
38 |
|
|
* for each display.
|
39 |
|
|
*/
|
40 |
|
|
|
41 |
|
|
#define IDS_PER_STACK 10
|
42 |
|
|
typedef struct TkIdStack {
|
43 |
|
|
XID ids[IDS_PER_STACK]; /* Array of free identifiers. */
|
44 |
|
|
int numUsed; /* Indicates how many of the entries
|
45 |
|
|
* in ids are currently in use. */
|
46 |
|
|
TkDisplay *dispPtr; /* Display to which ids belong. */
|
47 |
|
|
struct TkIdStack *nextPtr; /* Next bunch of free identifiers
|
48 |
|
|
* for the same display. */
|
49 |
|
|
} TkIdStack;
|
50 |
|
|
|
51 |
|
|
/*
|
52 |
|
|
* Forward declarations for procedures defined in this file:
|
53 |
|
|
*/
|
54 |
|
|
|
55 |
|
|
static XID AllocXId _ANSI_ARGS_((Display *display));
|
56 |
|
|
static Tk_RestrictAction CheckRestrictProc _ANSI_ARGS_((
|
57 |
|
|
ClientData clientData, XEvent *eventPtr));
|
58 |
|
|
static void WindowIdCleanup _ANSI_ARGS_((ClientData clientData));
|
59 |
|
|
static void WindowIdCleanup2 _ANSI_ARGS_((ClientData clientData));
|
60 |
|
|
|
61 |
|
|
/*
|
62 |
|
|
*----------------------------------------------------------------------
|
63 |
|
|
*
|
64 |
|
|
* TkInitXId --
|
65 |
|
|
*
|
66 |
|
|
* This procedure is called to initialize the id allocator for
|
67 |
|
|
* a given display.
|
68 |
|
|
*
|
69 |
|
|
* Results:
|
70 |
|
|
* None.
|
71 |
|
|
*
|
72 |
|
|
* Side effects:
|
73 |
|
|
* The official allocator for the display is set up to be Tk_AllocXID.
|
74 |
|
|
*
|
75 |
|
|
*----------------------------------------------------------------------
|
76 |
|
|
*/
|
77 |
|
|
|
78 |
|
|
void
|
79 |
|
|
TkInitXId(dispPtr)
|
80 |
|
|
TkDisplay *dispPtr; /* Tk's information about the
|
81 |
|
|
* display. */
|
82 |
|
|
{
|
83 |
|
|
dispPtr->idStackPtr = NULL;
|
84 |
|
|
dispPtr->defaultAllocProc = (XID (*) _ANSI_ARGS_((Display *display)))
|
85 |
|
|
dispPtr->display->resource_alloc;
|
86 |
|
|
dispPtr->display->resource_alloc = AllocXId;
|
87 |
|
|
dispPtr->windowStackPtr = NULL;
|
88 |
|
|
dispPtr->idCleanupScheduled = 0;
|
89 |
|
|
}
|
90 |
|
|
|
91 |
|
|
/*
|
92 |
|
|
*----------------------------------------------------------------------
|
93 |
|
|
*
|
94 |
|
|
* AllocXId --
|
95 |
|
|
*
|
96 |
|
|
* This procedure is invoked by Xlib as the resource allocator
|
97 |
|
|
* for a display.
|
98 |
|
|
*
|
99 |
|
|
* Results:
|
100 |
|
|
* The return value is an X resource identifier that isn't currently
|
101 |
|
|
* in use.
|
102 |
|
|
*
|
103 |
|
|
* Side effects:
|
104 |
|
|
* The identifier is removed from the stack of free identifiers,
|
105 |
|
|
* if it was previously on the stack.
|
106 |
|
|
*
|
107 |
|
|
*----------------------------------------------------------------------
|
108 |
|
|
*/
|
109 |
|
|
|
110 |
|
|
static XID
|
111 |
|
|
AllocXId(display)
|
112 |
|
|
Display *display; /* Display for which to allocate. */
|
113 |
|
|
{
|
114 |
|
|
TkDisplay *dispPtr;
|
115 |
|
|
TkIdStack *stackPtr;
|
116 |
|
|
|
117 |
|
|
/*
|
118 |
|
|
* Find Tk's information about the display.
|
119 |
|
|
*/
|
120 |
|
|
|
121 |
|
|
dispPtr = TkGetDisplay(display);
|
122 |
|
|
|
123 |
|
|
/*
|
124 |
|
|
* If the topmost chunk on the stack is empty then free it. Then
|
125 |
|
|
* check for a free id on the stack and return it if it exists.
|
126 |
|
|
*/
|
127 |
|
|
|
128 |
|
|
stackPtr = dispPtr->idStackPtr;
|
129 |
|
|
if (stackPtr != NULL) {
|
130 |
|
|
while (stackPtr->numUsed == 0) {
|
131 |
|
|
dispPtr->idStackPtr = stackPtr->nextPtr;
|
132 |
|
|
ckfree((char *) stackPtr);
|
133 |
|
|
stackPtr = dispPtr->idStackPtr;
|
134 |
|
|
if (stackPtr == NULL) {
|
135 |
|
|
goto defAlloc;
|
136 |
|
|
}
|
137 |
|
|
}
|
138 |
|
|
stackPtr->numUsed--;
|
139 |
|
|
return stackPtr->ids[stackPtr->numUsed];
|
140 |
|
|
}
|
141 |
|
|
|
142 |
|
|
/*
|
143 |
|
|
* No free ids in the stack: just get one from the default
|
144 |
|
|
* allocator.
|
145 |
|
|
*/
|
146 |
|
|
|
147 |
|
|
defAlloc:
|
148 |
|
|
return (*dispPtr->defaultAllocProc)(display);
|
149 |
|
|
}
|
150 |
|
|
|
151 |
|
|
/*
|
152 |
|
|
*----------------------------------------------------------------------
|
153 |
|
|
*
|
154 |
|
|
* Tk_FreeXId --
|
155 |
|
|
*
|
156 |
|
|
* This procedure is called to indicate that an X resource identifier
|
157 |
|
|
* is now free.
|
158 |
|
|
*
|
159 |
|
|
* Results:
|
160 |
|
|
* None.
|
161 |
|
|
*
|
162 |
|
|
* Side effects:
|
163 |
|
|
* The identifier is added to the stack of free identifiers for its
|
164 |
|
|
* display, so that it can be re-used.
|
165 |
|
|
*
|
166 |
|
|
*----------------------------------------------------------------------
|
167 |
|
|
*/
|
168 |
|
|
|
169 |
|
|
void
|
170 |
|
|
Tk_FreeXId(display, xid)
|
171 |
|
|
Display *display; /* Display for which xid was
|
172 |
|
|
* allocated. */
|
173 |
|
|
XID xid; /* Identifier that is no longer
|
174 |
|
|
* in use. */
|
175 |
|
|
{
|
176 |
|
|
TkDisplay *dispPtr;
|
177 |
|
|
TkIdStack *stackPtr;
|
178 |
|
|
|
179 |
|
|
/*
|
180 |
|
|
* Find Tk's information about the display.
|
181 |
|
|
*/
|
182 |
|
|
|
183 |
|
|
dispPtr = TkGetDisplay(display);
|
184 |
|
|
|
185 |
|
|
/*
|
186 |
|
|
* Add a new chunk to the stack if the current chunk is full.
|
187 |
|
|
*/
|
188 |
|
|
|
189 |
|
|
stackPtr = dispPtr->idStackPtr;
|
190 |
|
|
if ((stackPtr == NULL) || (stackPtr->numUsed >= IDS_PER_STACK)) {
|
191 |
|
|
stackPtr = (TkIdStack *) ckalloc(sizeof(TkIdStack));
|
192 |
|
|
stackPtr->numUsed = 0;
|
193 |
|
|
stackPtr->dispPtr = dispPtr;
|
194 |
|
|
stackPtr->nextPtr = dispPtr->idStackPtr;
|
195 |
|
|
dispPtr->idStackPtr = stackPtr;
|
196 |
|
|
}
|
197 |
|
|
|
198 |
|
|
/*
|
199 |
|
|
* Add the id to the current chunk.
|
200 |
|
|
*/
|
201 |
|
|
|
202 |
|
|
stackPtr->ids[stackPtr->numUsed] = xid;
|
203 |
|
|
stackPtr->numUsed++;
|
204 |
|
|
}
|
205 |
|
|
|
206 |
|
|
/*
|
207 |
|
|
*----------------------------------------------------------------------
|
208 |
|
|
*
|
209 |
|
|
* TkFreeWindowId --
|
210 |
|
|
*
|
211 |
|
|
* This procedure is invoked instead of TkFreeXId for window ids.
|
212 |
|
|
* See below for the reason why.
|
213 |
|
|
*
|
214 |
|
|
* Results:
|
215 |
|
|
* None.
|
216 |
|
|
*
|
217 |
|
|
* Side effects:
|
218 |
|
|
* The id given by w will eventually be freed, so that it can be
|
219 |
|
|
* reused for other resources.
|
220 |
|
|
*
|
221 |
|
|
* Design:
|
222 |
|
|
* Freeing window ids is very tricky because there could still be
|
223 |
|
|
* events pending for a window in the event queue (or even in the
|
224 |
|
|
* server) at the time the window is destroyed. If the window
|
225 |
|
|
* id were to get reused immediately for another window, old
|
226 |
|
|
* events could "drop in" on the new window, causing unexpected
|
227 |
|
|
* behavior.
|
228 |
|
|
*
|
229 |
|
|
* Thus we have to wait to re-use a window id until we know that
|
230 |
|
|
* there are no events left for it. Right now this is done in
|
231 |
|
|
* two steps. First, we wait until we know that the server
|
232 |
|
|
* has seen the XDestroyWindow request, so we can be sure that
|
233 |
|
|
* it won't generate more events for the window and that any
|
234 |
|
|
* existing events are in our queue. Second, we make sure that
|
235 |
|
|
* there are no events whatsoever in our queue (this is conservative
|
236 |
|
|
* but safe).
|
237 |
|
|
*
|
238 |
|
|
* The first step is done by remembering the request id of the
|
239 |
|
|
* XDestroyWindow request and using LastKnownRequestProcessed to
|
240 |
|
|
* see what events the server has processed. If multiple windows
|
241 |
|
|
* get destroyed at about the same time, we just remember the
|
242 |
|
|
* most recent request number for any of them (again, conservative
|
243 |
|
|
* but safe).
|
244 |
|
|
*
|
245 |
|
|
* There are a few other complications as well. When Tk destroys a
|
246 |
|
|
* sub-tree of windows, it only issues a single XDestroyWindow call,
|
247 |
|
|
* at the very end for the root of the subtree. We can't free any of
|
248 |
|
|
* the window ids until the final XDestroyWindow call. To make sure
|
249 |
|
|
* that this happens, we have to keep track of deletions in progress,
|
250 |
|
|
* hence the need for the "destroyCount" field of the display.
|
251 |
|
|
*
|
252 |
|
|
* One final problem. Some servers, like Sun X11/News servers still
|
253 |
|
|
* seem to have problems with ids getting reused too quickly. I'm
|
254 |
|
|
* not completely sure why this is a problem, but delaying the
|
255 |
|
|
* recycling of ids appears to eliminate it. Therefore, we wait
|
256 |
|
|
* an additional few seconds, even after "the coast is clear"
|
257 |
|
|
* before reusing the ids.
|
258 |
|
|
*
|
259 |
|
|
*----------------------------------------------------------------------
|
260 |
|
|
*/
|
261 |
|
|
|
262 |
|
|
void
|
263 |
|
|
TkFreeWindowId(dispPtr, w)
|
264 |
|
|
TkDisplay *dispPtr; /* Display that w belongs to. */
|
265 |
|
|
Window w; /* X identifier for window on dispPtr. */
|
266 |
|
|
{
|
267 |
|
|
TkIdStack *stackPtr;
|
268 |
|
|
|
269 |
|
|
/*
|
270 |
|
|
* Put the window id on a separate stack of window ids, rather
|
271 |
|
|
* than the main stack, so it won't get reused right away. Add
|
272 |
|
|
* a new chunk to the stack if the current chunk is full.
|
273 |
|
|
*/
|
274 |
|
|
|
275 |
|
|
stackPtr = dispPtr->windowStackPtr;
|
276 |
|
|
if ((stackPtr == NULL) || (stackPtr->numUsed >= IDS_PER_STACK)) {
|
277 |
|
|
stackPtr = (TkIdStack *) ckalloc(sizeof(TkIdStack));
|
278 |
|
|
stackPtr->numUsed = 0;
|
279 |
|
|
stackPtr->dispPtr = dispPtr;
|
280 |
|
|
stackPtr->nextPtr = dispPtr->windowStackPtr;
|
281 |
|
|
dispPtr->windowStackPtr = stackPtr;
|
282 |
|
|
}
|
283 |
|
|
|
284 |
|
|
/*
|
285 |
|
|
* Add the id to the current chunk.
|
286 |
|
|
*/
|
287 |
|
|
|
288 |
|
|
stackPtr->ids[stackPtr->numUsed] = w;
|
289 |
|
|
stackPtr->numUsed++;
|
290 |
|
|
|
291 |
|
|
/*
|
292 |
|
|
* Schedule a call to WindowIdCleanup if one isn't already
|
293 |
|
|
* scheduled.
|
294 |
|
|
*/
|
295 |
|
|
|
296 |
|
|
if (!dispPtr->idCleanupScheduled) {
|
297 |
|
|
dispPtr->idCleanupScheduled = 1;
|
298 |
|
|
Tcl_CreateTimerHandler(100, WindowIdCleanup, (ClientData) dispPtr);
|
299 |
|
|
}
|
300 |
|
|
}
|
301 |
|
|
|
302 |
|
|
/*
|
303 |
|
|
*----------------------------------------------------------------------
|
304 |
|
|
*
|
305 |
|
|
* WindowIdCleanup --
|
306 |
|
|
*
|
307 |
|
|
* See if we can now free up all the accumulated ids of
|
308 |
|
|
* deleted windows.
|
309 |
|
|
*
|
310 |
|
|
* Results:
|
311 |
|
|
* None.
|
312 |
|
|
*
|
313 |
|
|
* Side effects:
|
314 |
|
|
* If it's safe to move the window ids back to the main free
|
315 |
|
|
* list, we schedule this to happen after a few mores seconds
|
316 |
|
|
* of delay. If it's not safe to move them yet, a timer handler
|
317 |
|
|
* gets invoked to try again later.
|
318 |
|
|
*
|
319 |
|
|
*----------------------------------------------------------------------
|
320 |
|
|
*/
|
321 |
|
|
|
322 |
|
|
static void
|
323 |
|
|
WindowIdCleanup(clientData)
|
324 |
|
|
ClientData clientData; /* Pointer to TkDisplay for display */
|
325 |
|
|
{
|
326 |
|
|
TkDisplay *dispPtr = (TkDisplay *) clientData;
|
327 |
|
|
int anyEvents, delta;
|
328 |
|
|
Tk_RestrictProc *oldProc;
|
329 |
|
|
ClientData oldData;
|
330 |
|
|
static Tcl_Time timeout = {0, 0};
|
331 |
|
|
|
332 |
|
|
dispPtr->idCleanupScheduled = 0;
|
333 |
|
|
|
334 |
|
|
/*
|
335 |
|
|
* See if it's safe to recycle the window ids. It's safe if:
|
336 |
|
|
* (a) no deletions are in progress.
|
337 |
|
|
* (b) the server has seen all of the requests up to the last
|
338 |
|
|
* XDestroyWindow request.
|
339 |
|
|
* (c) there are no events in the event queue; the only way to
|
340 |
|
|
* test for this right now is to create a restrict proc that
|
341 |
|
|
* will filter the events, then call Tcl_DoOneEvent to see if
|
342 |
|
|
* the procedure gets invoked.
|
343 |
|
|
*/
|
344 |
|
|
|
345 |
|
|
if (dispPtr->destroyCount > 0) {
|
346 |
|
|
goto tryAgain;
|
347 |
|
|
}
|
348 |
|
|
delta = LastKnownRequestProcessed(dispPtr->display)
|
349 |
|
|
- dispPtr->lastDestroyRequest;
|
350 |
|
|
if (delta < 0) {
|
351 |
|
|
XSync(dispPtr->display, False);
|
352 |
|
|
}
|
353 |
|
|
anyEvents = 0;
|
354 |
|
|
oldProc = Tk_RestrictEvents(CheckRestrictProc, (ClientData) &anyEvents,
|
355 |
|
|
&oldData);
|
356 |
|
|
TkUnixDoOneXEvent(&timeout);
|
357 |
|
|
Tk_RestrictEvents(oldProc, oldData, &oldData);
|
358 |
|
|
if (anyEvents) {
|
359 |
|
|
goto tryAgain;
|
360 |
|
|
}
|
361 |
|
|
|
362 |
|
|
/*
|
363 |
|
|
* These ids look safe to recycle, but we still need to delay a bit
|
364 |
|
|
* more (see comments for TkFreeWindowId). Schedule the final freeing.
|
365 |
|
|
*/
|
366 |
|
|
|
367 |
|
|
if (dispPtr->windowStackPtr != NULL) {
|
368 |
|
|
Tcl_CreateTimerHandler(5000, WindowIdCleanup2,
|
369 |
|
|
(ClientData) dispPtr->windowStackPtr);
|
370 |
|
|
dispPtr->windowStackPtr = NULL;
|
371 |
|
|
}
|
372 |
|
|
return;
|
373 |
|
|
|
374 |
|
|
/*
|
375 |
|
|
* It's still not safe to free up the ids. Try again a bit later.
|
376 |
|
|
*/
|
377 |
|
|
|
378 |
|
|
tryAgain:
|
379 |
|
|
dispPtr->idCleanupScheduled = 1;
|
380 |
|
|
Tcl_CreateTimerHandler(500, WindowIdCleanup, (ClientData) dispPtr);
|
381 |
|
|
}
|
382 |
|
|
|
383 |
|
|
/*
|
384 |
|
|
*----------------------------------------------------------------------
|
385 |
|
|
*
|
386 |
|
|
* WindowIdCleanup2 --
|
387 |
|
|
*
|
388 |
|
|
* This procedure is the last one in the chain that recycles
|
389 |
|
|
* window ids. It takes all of the ids indicated by its
|
390 |
|
|
* argument and adds them back to the main id free list.
|
391 |
|
|
*
|
392 |
|
|
* Results:
|
393 |
|
|
* None.
|
394 |
|
|
*
|
395 |
|
|
* Side effects:
|
396 |
|
|
* Window ids get added to the main free list for their display.
|
397 |
|
|
*
|
398 |
|
|
*----------------------------------------------------------------------
|
399 |
|
|
*/
|
400 |
|
|
|
401 |
|
|
static void
|
402 |
|
|
WindowIdCleanup2(clientData)
|
403 |
|
|
ClientData clientData; /* Pointer to TkIdStack list. */
|
404 |
|
|
{
|
405 |
|
|
TkIdStack *stackPtr = (TkIdStack *) clientData;
|
406 |
|
|
TkIdStack *lastPtr;
|
407 |
|
|
|
408 |
|
|
lastPtr = stackPtr;
|
409 |
|
|
while (lastPtr->nextPtr != NULL) {
|
410 |
|
|
lastPtr = lastPtr->nextPtr;
|
411 |
|
|
}
|
412 |
|
|
lastPtr->nextPtr = stackPtr->dispPtr->idStackPtr;
|
413 |
|
|
stackPtr->dispPtr->idStackPtr = stackPtr;
|
414 |
|
|
}
|
415 |
|
|
|
416 |
|
|
/*
|
417 |
|
|
*----------------------------------------------------------------------
|
418 |
|
|
*
|
419 |
|
|
* CheckRestrictProc --
|
420 |
|
|
*
|
421 |
|
|
* This procedure is a restrict procedure, called by Tcl_DoOneEvent
|
422 |
|
|
* to filter X events. All it does is to set a flag to indicate
|
423 |
|
|
* that there are X events present.
|
424 |
|
|
*
|
425 |
|
|
* Results:
|
426 |
|
|
* Sets the integer pointed to by the argument, then returns
|
427 |
|
|
* TK_DEFER_EVENT.
|
428 |
|
|
*
|
429 |
|
|
* Side effects:
|
430 |
|
|
* None.
|
431 |
|
|
*
|
432 |
|
|
*----------------------------------------------------------------------
|
433 |
|
|
*/
|
434 |
|
|
|
435 |
|
|
static Tk_RestrictAction
|
436 |
|
|
CheckRestrictProc(clientData, eventPtr)
|
437 |
|
|
ClientData clientData; /* Pointer to flag to set. */
|
438 |
|
|
XEvent *eventPtr; /* Event to filter; not used. */
|
439 |
|
|
{
|
440 |
|
|
int *flag = (int *) clientData;
|
441 |
|
|
*flag = 1;
|
442 |
|
|
return TK_DEFER_EVENT;
|
443 |
|
|
}
|
444 |
|
|
|
445 |
|
|
/*
|
446 |
|
|
*----------------------------------------------------------------------
|
447 |
|
|
*
|
448 |
|
|
* Tk_GetPixmap --
|
449 |
|
|
*
|
450 |
|
|
* Same as the XCreatePixmap procedure except that it manages
|
451 |
|
|
* resource identifiers better.
|
452 |
|
|
*
|
453 |
|
|
* Results:
|
454 |
|
|
* Returns a new pixmap.
|
455 |
|
|
*
|
456 |
|
|
* Side effects:
|
457 |
|
|
* None.
|
458 |
|
|
*
|
459 |
|
|
*----------------------------------------------------------------------
|
460 |
|
|
*/
|
461 |
|
|
|
462 |
|
|
Pixmap
|
463 |
|
|
Tk_GetPixmap(display, d, width, height, depth)
|
464 |
|
|
Display *display; /* Display for new pixmap. */
|
465 |
|
|
Drawable d; /* Drawable where pixmap will be used. */
|
466 |
|
|
int width, height; /* Dimensions of pixmap. */
|
467 |
|
|
int depth; /* Bits per pixel for pixmap. */
|
468 |
|
|
{
|
469 |
|
|
return XCreatePixmap(display, d, (unsigned) width, (unsigned) height,
|
470 |
|
|
(unsigned) depth);
|
471 |
|
|
}
|
472 |
|
|
|
473 |
|
|
/*
|
474 |
|
|
*----------------------------------------------------------------------
|
475 |
|
|
*
|
476 |
|
|
* Tk_FreePixmap --
|
477 |
|
|
*
|
478 |
|
|
* Same as the XFreePixmap procedure except that it also marks
|
479 |
|
|
* the resource identifier as free.
|
480 |
|
|
*
|
481 |
|
|
* Results:
|
482 |
|
|
* None.
|
483 |
|
|
*
|
484 |
|
|
* Side effects:
|
485 |
|
|
* The pixmap is freed in the X server and its resource identifier
|
486 |
|
|
* is saved for re-use.
|
487 |
|
|
*
|
488 |
|
|
*----------------------------------------------------------------------
|
489 |
|
|
*/
|
490 |
|
|
|
491 |
|
|
void
|
492 |
|
|
Tk_FreePixmap(display, pixmap)
|
493 |
|
|
Display *display; /* Display for which pixmap was allocated. */
|
494 |
|
|
Pixmap pixmap; /* Identifier for pixmap. */
|
495 |
|
|
{
|
496 |
|
|
XFreePixmap(display, pixmap);
|
497 |
|
|
Tk_FreeXId(display, (XID) pixmap);
|
498 |
|
|
}
|
499 |
|
|
|
500 |
|
|
/*
|
501 |
|
|
*----------------------------------------------------------------------
|
502 |
|
|
*
|
503 |
|
|
* TkpWindowWasRecentlyDeleted --
|
504 |
|
|
*
|
505 |
|
|
* Checks whether the window was recently deleted. This is called
|
506 |
|
|
* by the generic error handler to detect asynchronous notification
|
507 |
|
|
* of errors due to operations by Tk on a window that was already
|
508 |
|
|
* deleted by the server.
|
509 |
|
|
*
|
510 |
|
|
* Results:
|
511 |
|
|
* 1 if the window was deleted recently, 0 otherwise.
|
512 |
|
|
*
|
513 |
|
|
* Side effects:
|
514 |
|
|
* None.
|
515 |
|
|
*
|
516 |
|
|
*----------------------------------------------------------------------
|
517 |
|
|
*/
|
518 |
|
|
|
519 |
|
|
int
|
520 |
|
|
TkpWindowWasRecentlyDeleted(win, dispPtr)
|
521 |
|
|
Window win; /* The window to check for. */
|
522 |
|
|
TkDisplay *dispPtr; /* The window belongs to this display. */
|
523 |
|
|
{
|
524 |
|
|
TkIdStack *stackPtr;
|
525 |
|
|
int i;
|
526 |
|
|
|
527 |
|
|
for (stackPtr = dispPtr->windowStackPtr;
|
528 |
|
|
stackPtr != NULL;
|
529 |
|
|
stackPtr = stackPtr->nextPtr) {
|
530 |
|
|
for (i = 0; i < stackPtr->numUsed; i++) {
|
531 |
|
|
if ((Window) stackPtr->ids[i] == win) {
|
532 |
|
|
return 1;
|
533 |
|
|
}
|
534 |
|
|
}
|
535 |
|
|
}
|
536 |
|
|
return 0;
|
537 |
|
|
}
|