diff options
Diffstat (limited to 'tcl/unix/tkUnixXId.c')
-rw-r--r-- | tcl/unix/tkUnixXId.c | 613 |
1 files changed, 0 insertions, 613 deletions
diff --git a/tcl/unix/tkUnixXId.c b/tcl/unix/tkUnixXId.c deleted file mode 100644 index 64fb9250c2d..00000000000 --- a/tcl/unix/tkUnixXId.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * tkUnixXId.c -- - * - * This file provides a replacement function for the default X - * resource allocator (_XAllocID). The problem with the default - * allocator is that it never re-uses ids, which causes long-lived - * applications to crash when X resource identifiers wrap around. - * The replacement functions in this file re-use old identifiers - * to prevent this problem. - * - * The code in this file is based on similar implementations by - * George C. Kaplan and Michael Hoegeman. - * - * Copyright (c) 1993 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id$ - */ - -/* - * The definition below is needed on some systems so that we can access - * the resource_alloc field of Display structures in order to replace - * the resource allocator. - */ - -#define XLIB_ILLEGAL_ACCESS 1 - -#include "tkUnixInt.h" -#include "tkPort.h" - -/* - * A structure of the following type is used to hold one or more - * available resource identifiers. There is a list of these structures - * for each display. - */ - -#define IDS_PER_STACK 10 -typedef struct TkIdStack { - XID ids[IDS_PER_STACK]; /* Array of free identifiers. */ - int numUsed; /* Indicates how many of the entries - * in ids are currently in use. */ - TkDisplay *dispPtr; /* Display to which ids belong. */ - struct TkIdStack *nextPtr; /* Next bunch of free identifiers - * for the same display. */ -} TkIdStack; - -/* - * Forward declarations for procedures defined in this file: - */ - -static XID AllocXId _ANSI_ARGS_((Display *display)); -static Tk_RestrictAction CheckRestrictProc _ANSI_ARGS_(( - ClientData clientData, XEvent *eventPtr)); -static void WindowIdCleanup _ANSI_ARGS_((ClientData clientData)); -static void WindowIdCleanup2 _ANSI_ARGS_((ClientData clientData)); - -/* - *---------------------------------------------------------------------- - * - * TkInitXId -- - * - * This procedure is called to initialize the id allocator for - * a given display. - * - * Results: - * None. - * - * Side effects: - * The official allocator for the display is set up to be AllocXId. - * - *---------------------------------------------------------------------- - */ - -void -TkInitXId(dispPtr) - TkDisplay *dispPtr; /* Tk's information about the - * display. */ -{ - dispPtr->idStackPtr = NULL; - dispPtr->defaultAllocProc = (XID (*) _ANSI_ARGS_((Display *display))) - dispPtr->display->resource_alloc; - dispPtr->display->resource_alloc = AllocXId; - dispPtr->windowStackPtr = NULL; - dispPtr->idCleanupScheduled = (Tcl_TimerToken) 0; -} - -/* - *---------------------------------------------------------------------- - * - * TkFreeXId -- - * - * This procedure is called to free resources for the id allocator - * for a given display. - * - * Results: - * None. - * - * Side effects: - * Frees the id and window stack pools. - * - *---------------------------------------------------------------------- - */ - -void -TkFreeXId(dispPtr) - TkDisplay *dispPtr; /* Tk's information about the - * display. */ -{ - TkIdStack *stackPtr, *freePtr; - - if (dispPtr->idCleanupScheduled) { - Tcl_DeleteTimerHandler(dispPtr->idCleanupScheduled); - } - - for (stackPtr = dispPtr->idStackPtr; stackPtr != NULL; ) { - freePtr = stackPtr; - stackPtr = stackPtr->nextPtr; - ckfree((char *) freePtr); - } - dispPtr->idStackPtr = NULL; - - for (stackPtr = dispPtr->windowStackPtr; stackPtr != NULL; ) { - freePtr = stackPtr; - stackPtr = stackPtr->nextPtr; - ckfree((char *) freePtr); - } - dispPtr->windowStackPtr = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * AllocXId -- - * - * This procedure is invoked by Xlib as the resource allocator - * for a display. - * - * Results: - * The return value is an X resource identifier that isn't currently - * in use. - * - * Side effects: - * The identifier is removed from the stack of free identifiers, - * if it was previously on the stack. - * - *---------------------------------------------------------------------- - */ - -static XID -AllocXId(display) - Display *display; /* Display for which to allocate. */ -{ - TkDisplay *dispPtr; - TkIdStack *stackPtr; - - /* - * Find Tk's information about the display. - */ - - dispPtr = TkGetDisplay(display); - - /* - * If the topmost chunk on the stack is empty then free it. Then - * check for a free id on the stack and return it if it exists. - */ - - stackPtr = dispPtr->idStackPtr; - if (stackPtr != NULL) { - while (stackPtr->numUsed == 0) { - dispPtr->idStackPtr = stackPtr->nextPtr; - ckfree((char *) stackPtr); - stackPtr = dispPtr->idStackPtr; - if (stackPtr == NULL) { - goto defAlloc; - } - } - stackPtr->numUsed--; - return stackPtr->ids[stackPtr->numUsed]; - } - - /* - * No free ids in the stack: just get one from the default - * allocator. - */ - - defAlloc: - return (*dispPtr->defaultAllocProc)(display); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FreeXId -- - * - * This procedure is called to indicate that an X resource identifier - * is now free. - * - * Results: - * None. - * - * Side effects: - * The identifier is added to the stack of free identifiers for its - * display, so that it can be re-used. - * - *---------------------------------------------------------------------- - */ - -void -Tk_FreeXId(display, xid) - Display *display; /* Display for which xid was - * allocated. */ - XID xid; /* Identifier that is no longer - * in use. */ -{ - TkDisplay *dispPtr; - TkIdStack *stackPtr; - - /* - * Find Tk's information about the display. - */ - - dispPtr = TkGetDisplay(display); - - /* - * Add a new chunk to the stack if the current chunk is full. - */ - - stackPtr = dispPtr->idStackPtr; - if ((stackPtr == NULL) || (stackPtr->numUsed >= IDS_PER_STACK)) { - stackPtr = (TkIdStack *) ckalloc(sizeof(TkIdStack)); - stackPtr->numUsed = 0; - stackPtr->dispPtr = dispPtr; - stackPtr->nextPtr = dispPtr->idStackPtr; - dispPtr->idStackPtr = stackPtr; - } - - /* - * Add the id to the current chunk. - */ - - stackPtr->ids[stackPtr->numUsed] = xid; - stackPtr->numUsed++; -} - -/* - *---------------------------------------------------------------------- - * - * TkFreeWindowId -- - * - * This procedure is invoked instead of TkFreeXId for window ids. - * See below for the reason why. - * - * Results: - * None. - * - * Side effects: - * The id given by w will eventually be freed, so that it can be - * reused for other resources. - * - * Design: - * Freeing window ids is very tricky because there could still be - * events pending for a window in the event queue (or even in the - * server) at the time the window is destroyed. If the window - * id were to get reused immediately for another window, old - * events could "drop in" on the new window, causing unexpected - * behavior. - * - * Thus we have to wait to re-use a window id until we know that - * there are no events left for it. Right now this is done in - * two steps. First, we wait until we know that the server - * has seen the XDestroyWindow request, so we can be sure that - * it won't generate more events for the window and that any - * existing events are in our queue. Second, we make sure that - * there are no events whatsoever in our queue (this is conservative - * but safe). - * - * The first step is done by remembering the request id of the - * XDestroyWindow request and using LastKnownRequestProcessed to - * see what events the server has processed. If multiple windows - * get destroyed at about the same time, we just remember the - * most recent request number for any of them (again, conservative - * but safe). - * - * There are a few other complications as well. When Tk destroys a - * sub-tree of windows, it only issues a single XDestroyWindow call, - * at the very end for the root of the subtree. We can't free any of - * the window ids until the final XDestroyWindow call. To make sure - * that this happens, we have to keep track of deletions in progress, - * hence the need for the "destroyCount" field of the display. - * - * One final problem. Some servers, like Sun X11/News servers still - * seem to have problems with ids getting reused too quickly. I'm - * not completely sure why this is a problem, but delaying the - * recycling of ids appears to eliminate it. Therefore, we wait - * an additional few seconds, even after "the coast is clear" - * before reusing the ids. - * - *---------------------------------------------------------------------- - */ - -void -TkFreeWindowId(dispPtr, w) - TkDisplay *dispPtr; /* Display that w belongs to. */ - Window w; /* X identifier for window on dispPtr. */ -{ - TkIdStack *stackPtr; - - /* - * Put the window id on a separate stack of window ids, rather - * than the main stack, so it won't get reused right away. Add - * a new chunk to the stack if the current chunk is full. - */ - - stackPtr = dispPtr->windowStackPtr; - if ((stackPtr == NULL) || (stackPtr->numUsed >= IDS_PER_STACK)) { - stackPtr = (TkIdStack *) ckalloc(sizeof(TkIdStack)); - stackPtr->numUsed = 0; - stackPtr->dispPtr = dispPtr; - stackPtr->nextPtr = dispPtr->windowStackPtr; - dispPtr->windowStackPtr = stackPtr; - } - - /* - * Add the id to the current chunk. - */ - - stackPtr->ids[stackPtr->numUsed] = w; - stackPtr->numUsed++; - - /* - * Schedule a call to WindowIdCleanup if one isn't already - * scheduled. - */ - - if (!dispPtr->idCleanupScheduled) { - dispPtr->idCleanupScheduled = - Tcl_CreateTimerHandler(100, WindowIdCleanup, (ClientData) dispPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * WindowIdCleanup -- - * - * See if we can now free up all the accumulated ids of - * deleted windows. - * - * Results: - * None. - * - * Side effects: - * If it's safe to move the window ids back to the main free - * list, we schedule this to happen after a few mores seconds - * of delay. If it's not safe to move them yet, a timer handler - * gets invoked to try again later. - * - *---------------------------------------------------------------------- - */ - -static void -WindowIdCleanup(clientData) - ClientData clientData; /* Pointer to TkDisplay for display */ -{ - TkDisplay *dispPtr = (TkDisplay *) clientData; - int anyEvents, delta; - Tk_RestrictProc *oldProc; - ClientData oldData; - static Tcl_Time timeout = {0, 0}; - - dispPtr->idCleanupScheduled = (Tcl_TimerToken) 0; - - /* - * See if it's safe to recycle the window ids. It's safe if: - * (a) no deletions are in progress. - * (b) the server has seen all of the requests up to the last - * XDestroyWindow request. - * (c) there are no events in the event queue; the only way to - * test for this right now is to create a restrict proc that - * will filter the events, then call Tcl_DoOneEvent to see if - * the procedure gets invoked. - */ - - if (dispPtr->destroyCount > 0) { - goto tryAgain; - } - delta = LastKnownRequestProcessed(dispPtr->display) - - dispPtr->lastDestroyRequest; - if (delta < 0) { - XSync(dispPtr->display, False); - } - anyEvents = 0; - oldProc = Tk_RestrictEvents(CheckRestrictProc, (ClientData) &anyEvents, - &oldData); - TkUnixDoOneXEvent(&timeout); - Tk_RestrictEvents(oldProc, oldData, &oldData); - if (anyEvents) { - goto tryAgain; - } - - /* - * These ids look safe to recycle, but we still need to delay a bit - * more (see comments for TkFreeWindowId). Schedule the final freeing. - */ - - if (dispPtr->windowStackPtr != NULL) { - Tcl_CreateTimerHandler(5000, WindowIdCleanup2, - (ClientData) dispPtr->windowStackPtr); - dispPtr->windowStackPtr = NULL; - } - return; - - /* - * It's still not safe to free up the ids. Try again a bit later. - */ - - tryAgain: - dispPtr->idCleanupScheduled = - Tcl_CreateTimerHandler(500, WindowIdCleanup, (ClientData) dispPtr); -} - -/* - *---------------------------------------------------------------------- - * - * WindowIdCleanup2 -- - * - * This procedure is the last one in the chain that recycles - * window ids. It takes all of the ids indicated by its - * argument and adds them back to the main id free list. - * - * Results: - * None. - * - * Side effects: - * Window ids get added to the main free list for their display. - * - *---------------------------------------------------------------------- - */ - -static void -WindowIdCleanup2(clientData) - ClientData clientData; /* Pointer to TkIdStack list. */ -{ - TkIdStack *stackPtr = (TkIdStack *) clientData; - TkIdStack *lastPtr; - - lastPtr = stackPtr; - while (lastPtr->nextPtr != NULL) { - lastPtr = lastPtr->nextPtr; - } - lastPtr->nextPtr = stackPtr->dispPtr->idStackPtr; - stackPtr->dispPtr->idStackPtr = stackPtr; -} - -/* - *---------------------------------------------------------------------- - * - * CheckRestrictProc -- - * - * This procedure is a restrict procedure, called by Tcl_DoOneEvent - * to filter X events. All it does is to set a flag to indicate - * that there are X events present. - * - * Results: - * Sets the integer pointed to by the argument, then returns - * TK_DEFER_EVENT. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static Tk_RestrictAction -CheckRestrictProc(clientData, eventPtr) - ClientData clientData; /* Pointer to flag to set. */ - XEvent *eventPtr; /* Event to filter; not used. */ -{ - int *flag = (int *) clientData; - *flag = 1; - return TK_DEFER_EVENT; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetPixmap -- - * - * Same as the XCreatePixmap procedure except that it manages - * resource identifiers better. - * - * Results: - * Returns a new pixmap. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Pixmap -Tk_GetPixmap(display, d, width, height, depth) - Display *display; /* Display for new pixmap. */ - Drawable d; /* Drawable where pixmap will be used. */ - int width, height; /* Dimensions of pixmap. */ - int depth; /* Bits per pixel for pixmap. */ -{ - return XCreatePixmap(display, d, (unsigned) width, (unsigned) height, - (unsigned) depth); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FreePixmap -- - * - * Same as the XFreePixmap procedure except that it also marks - * the resource identifier as free. - * - * Results: - * None. - * - * Side effects: - * The pixmap is freed in the X server and its resource identifier - * is saved for re-use. - * - *---------------------------------------------------------------------- - */ - -void -Tk_FreePixmap(display, pixmap) - Display *display; /* Display for which pixmap was allocated. */ - Pixmap pixmap; /* Identifier for pixmap. */ -{ - XFreePixmap(display, pixmap); - Tk_FreeXId(display, (XID) pixmap); -} - -/* - *---------------------------------------------------------------------- - * - * TkpWindowWasRecentlyDeleted -- - * - * Checks whether the window was recently deleted. This is called - * by the generic error handler to detect asynchronous notification - * of errors due to operations by Tk on a window that was already - * deleted by the server. - * - * Results: - * 1 if the window was deleted recently, 0 otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkpWindowWasRecentlyDeleted(win, dispPtr) - Window win; /* The window to check for. */ - TkDisplay *dispPtr; /* The window belongs to this display. */ -{ - TkIdStack *stackPtr; - int i; - - for (stackPtr = dispPtr->windowStackPtr; - stackPtr != NULL; - stackPtr = stackPtr->nextPtr) { - for (i = 0; i < stackPtr->numUsed; i++) { - if ((Window) stackPtr->ids[i] == win) { - return 1; - } - } - } - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * TkpScanWindowId -- - * - * Given a string, produce the corresponding Window Id. - * - * Results: - * The return value is normally TCL_OK; in this case *idPtr - * will be set to the Window value equivalent to string. If - * string is improperly formed then TCL_ERROR is returned and - * an error message will be left in the interp's result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkpScanWindowId(interp, string, idPtr) - Tcl_Interp *interp; - CONST char *string; - Window *idPtr; -{ - int value; - if (Tcl_GetInt(interp, string, &value) != TCL_OK) { - return TCL_ERROR; - } - *idPtr = (Window) value; - return TCL_OK; -} - |