diff options
-rw-r--r-- | generic/tkWindow.c | 207 |
1 files changed, 100 insertions, 107 deletions
diff --git a/generic/tkWindow.c b/generic/tkWindow.c index 4384c45..aa07b2d 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWindow.c,v 1.44 2002/04/05 08:41:24 hobbs Exp $ + * RCS: @(#) $Id: tkWindow.c,v 1.45 2002/04/12 10:20:27 hobbs Exp $ */ #include "tkPort.h" @@ -217,6 +217,59 @@ static void UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr)); /* *---------------------------------------------------------------------- * + * TkCloseDisplay -- + * Closing the display can lead to order of deletion problems. + * We defer it until exit handling for Mac/Win, but since Unix can + * use many displays, try and clean it up as best as possible. + * + * Results: + * None. + * + * Side effects: + * Resources associated with the display will be free. + * The display may not be referenced at all after this. + *---------------------------------------------------------------------- + */ + +static void +TkCloseDisplay(TkDisplay *dispPtr) +{ + TkClipCleanup(dispPtr); + + if (dispPtr->name != NULL) { + ckfree(dispPtr->name); + } + + Tcl_DeleteHashTable(&dispPtr->winTable); + + if (dispPtr->atomInit) { + Tcl_DeleteHashTable(&dispPtr->nameTable); + Tcl_DeleteHashTable(&dispPtr->atomTable); + dispPtr->atomInit = 0; + } + + if (dispPtr->errorPtr != NULL) { + TkErrorHandler *errorPtr; + for (errorPtr = dispPtr->errorPtr; + errorPtr != NULL; + errorPtr = dispPtr->errorPtr) { + dispPtr->errorPtr = errorPtr->nextPtr; + ckfree((char *) errorPtr); + } + } + + TkGCCleanup(dispPtr); + + TkpCloseDisplay(dispPtr); + + /* + * There is more to clean up, we leave it at this for the time being. + */ +} + +/* + *---------------------------------------------------------------------- + * * CreateTopLevelWindow -- * * Make a new window that will be at top-level (its parent will @@ -397,82 +450,34 @@ GetScreen(interp, screenName, screenPtr) * then open a new connection. */ - for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) { + for (dispPtr = tsdPtr->displayList; ; dispPtr = dispPtr->nextPtr) { if (dispPtr == NULL) { + /* + * The private function zeros out dispPtr when it is created, + * so we only need to initialize the non-zero items. + */ dispPtr = TkpOpenDisplay(screenName); if (dispPtr == NULL) { Tcl_AppendResult(interp, "couldn't connect to display \"", screenName, "\"", (char *) NULL); return (TkDisplay *) NULL; } - dispPtr->nextPtr = TkGetDisplayList(); - dispPtr->name = (char *) ckalloc((unsigned) (length+1)); + dispPtr->nextPtr = tsdPtr->displayList; /* TkGetDisplayList(); */ + tsdPtr->displayList = dispPtr; + dispPtr->lastEventTime = CurrentTime; - dispPtr->borderInit = 0; - dispPtr->atomInit = 0; dispPtr->bindInfoStale = 1; - dispPtr->modeModMask = 0; - dispPtr->metaModMask = 0; - dispPtr->altModMask = 0; - dispPtr->numModKeyCodes = 0; - dispPtr->modKeyCodes = NULL; - dispPtr->bitmapInit = 0; - dispPtr->bitmapAutoNumber = 0; - dispPtr->numIdSearches = 0; - dispPtr->numSlowSearches = 0; - dispPtr->colorInit = 0; - dispPtr->stressPtr = NULL; - dispPtr->cursorInit = 0; - dispPtr->cursorString[0] = '\0'; dispPtr->cursorFont = None; - dispPtr->errorPtr = NULL; - dispPtr->deleteCount = 0; - dispPtr->delayedMotionPtr = NULL; - dispPtr->focusDebug = 0; - dispPtr->implicitWinPtr = NULL; - dispPtr->focusPtr = NULL; - dispPtr->gcInit = 0; - dispPtr->geomInit = 0; - dispPtr->uidInit = 0; - dispPtr->grabWinPtr = NULL; - dispPtr->eventualGrabWinPtr = NULL; - dispPtr->buttonWinPtr = NULL; - dispPtr->serverWinPtr = NULL; - dispPtr->firstGrabEventPtr = NULL; - dispPtr->lastGrabEventPtr = NULL; - dispPtr->grabFlags = 0; - dispPtr->mouseButtonState = 0; - dispPtr->warpInProgress = 0; dispPtr->warpWindow = None; - dispPtr->warpX = 0; - dispPtr->warpY = 0; - dispPtr->gridInit = 0; - dispPtr->imageId = 0; - dispPtr->packInit = 0; - dispPtr->placeInit = 0; - dispPtr->selectionInfoPtr = NULL; dispPtr->multipleAtom = None; - dispPtr->clipWindow = NULL; - dispPtr->clipboardActive = 0; - dispPtr->clipboardAppPtr = NULL; - dispPtr->clipTargetPtr = NULL; - dispPtr->commTkwin = NULL; - dispPtr->wmTracing = 0; - dispPtr->firstWmPtr = NULL; - dispPtr->foregroundWmPtr = NULL; - dispPtr->destroyCount = 0; - dispPtr->lastDestroyRequest = 0; - dispPtr->cmapPtr = NULL; + Tcl_InitHashTable(&dispPtr->winTable, TCL_ONE_WORD_KEYS); - dispPtr->refCount = 0; + dispPtr->name = (char *) ckalloc((unsigned) (length+1)); strncpy(dispPtr->name, screenName, length); dispPtr->name[length] = '\0'; - dispPtr->useInputMethods = 0; - TkInitXId(dispPtr); - dispPtr->deletionEpoch = 0L; - tsdPtr->displayList = dispPtr; + TkInitXId(dispPtr); break; } if ((strncmp(dispPtr->name, screenName, length) == 0) @@ -1428,6 +1433,7 @@ Tk_DestroyWindow(tkwin) TkBindFree(winPtr->mainPtr); TkDeleteAllImages(winPtr->mainPtr); TkFontPkgFree(winPtr->mainPtr); + TkFocusFree(winPtr->mainPtr); /* * When embedding Tk into other applications, make sure @@ -1437,7 +1443,7 @@ Tk_DestroyWindow(tkwin) */ if (winPtr->flags & TK_EMBEDDED) { - XSync(winPtr->display,False) ; + XSync(winPtr->display, False); } ckfree((char *) winPtr->mainPtr); @@ -1445,15 +1451,22 @@ Tk_DestroyWindow(tkwin) * If no other applications are using the display, close the * display now and relinquish its data structures. */ - + +#if !defined(WIN32) && !defined(MAC_TCL) && defined(NOT_YET) if (dispPtr->refCount <= 0) { -#ifdef NOT_YET /* * I have disabled this code because on Windows there are * still order dependencies in close-down. All displays * and resources will get closed down properly anyway at - * exit, through the exit handler. + * exit, through the exit handler. -- jyl */ + /* + * Ideally this should be enabled, as unix Tk can use multiple + * displays. However, there are order issues still, as well + * as the handling of queued events and such that must be + * addressed before this can be enabled. The current cleanup + * works except for send event issues. -- hobbs 04/2002 + */ TkDisplay *theDispPtr, *backDispPtr; @@ -1461,7 +1474,7 @@ Tk_DestroyWindow(tkwin) * Splice this display out of the list of displays. */ - for (theDispPtr = displayList, backDispPtr = NULL; + for (theDispPtr = tsdPtr->displayList, backDispPtr = NULL; (theDispPtr != winPtr->dispPtr) && (theDispPtr != NULL); theDispPtr = theDispPtr->nextPtr) { @@ -1471,36 +1484,24 @@ Tk_DestroyWindow(tkwin) panic("could not find display to close!"); } if (backDispPtr == NULL) { - displayList = theDispPtr->nextPtr; + tsdPtr->displayList = theDispPtr->nextPtr; } else { backDispPtr->nextPtr = theDispPtr->nextPtr; } - - /* - * Found and spliced it out, now actually do the cleanup. - */ - - if (dispPtr->name != NULL) { - ckfree(dispPtr->name); - } - - Tcl_DeleteHashTable(&(dispPtr->winTable)); - - /* - * Cannot yet close the display because we still have - * order of deletion problems. Defer until exit handling - * instead. At that time, the display will cleanly shut - * down (hopefully..). (JYL) - */ - TkpCloseDisplay(dispPtr); + /* + * Calling XSync creates X server traffic, but addresses a + * focus issue on close (but not the send issue). -- hobbs + XSync(dispPtr->display, True); + */ /* - * There is lots more to clean up, we leave it at this for - * the time being. + * Found and spliced it out, now actually do the cleanup. */ -#endif + + TkCloseDisplay(dispPtr); } +#endif } } Tcl_EventuallyFree((ClientData) winPtr, TCL_DYNAMIC); @@ -2604,11 +2605,11 @@ static void DeleteWindowsExitProc(clientData) ClientData clientData; /* Not used. */ { - TkDisplay *displayPtr, *nextPtr; + TkDisplay *dispPtr, *nextPtr; Tcl_Interp *interp; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - + while (tsdPtr->mainWindowList != NULL) { /* * We must protect the interpreter while deleting the window, @@ -2622,21 +2623,17 @@ DeleteWindowsExitProc(clientData) Tk_DestroyWindow((Tk_Window) tsdPtr->mainWindowList->winPtr); Tcl_Release((ClientData) interp); } - - displayPtr = tsdPtr->displayList; - tsdPtr->displayList = NULL; - + /* * Iterate destroying the displays until no more displays remain. * It is possible for displays to get recreated during exit by any * code that calls GetScreen, so we must destroy these new displays * as well as the old ones. */ - - for (displayPtr = tsdPtr->displayList; - displayPtr != NULL; - displayPtr = tsdPtr->displayList) { + for (dispPtr = tsdPtr->displayList; + dispPtr != NULL; + dispPtr = tsdPtr->displayList) { /* * Now iterate over the current list of open displays, and first * set the global pointer to NULL so we will be able to notice if @@ -2645,18 +2642,14 @@ DeleteWindowsExitProc(clientData) * the old display as it is being destroyed, when it wants to see * if it needs to dispatch a message. */ - - for (tsdPtr->displayList = NULL; displayPtr != NULL; - displayPtr = nextPtr) { - nextPtr = displayPtr->nextPtr; - if (displayPtr->name != (char *) NULL) { - ckfree(displayPtr->name); - } - Tcl_DeleteHashTable(&(displayPtr->winTable)); - TkpCloseDisplay(displayPtr); + + for (tsdPtr->displayList = NULL; dispPtr != NULL; + dispPtr = nextPtr) { + nextPtr = dispPtr->nextPtr; + TkCloseDisplay(dispPtr); } } - + tsdPtr->numMainWindows = 0; tsdPtr->mainWindowList = NULL; tsdPtr->initialized = 0; |