/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkwindow.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkwindow.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

to_be_filed/sf_code/esrgpcpj/shared/tk_base/tkwindow.c revision 29 by dashley, Sat Oct 8 07:08:47 2016 UTC projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwindow.c revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkwindow.c,v 1.1.1.1 2001/06/13 05:12:54 dtashley Exp $ */  
   
 /*  
  * tkWindow.c --  
  *  
  *      This file provides basic window-manipulation procedures,  
  *      which are equivalent to procedures in Xlib (and even  
  *      invoke them) but also maintain the local Tk_Window  
  *      structure.  
  *  
  * Copyright (c) 1989-1994 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: tkwindow.c,v 1.1.1.1 2001/06/13 05:12:54 dtashley Exp $  
  */  
   
 #include "tkPort.h"  
 #include "tkInt.h"  
   
 #if !defined(__WIN32__) && !defined(MAC_TCL)  
 #include "tkUnixInt.h"  
 #endif  
   
   
 typedef struct ThreadSpecificData {  
     int numMainWindows;    /* Count of numver of main windows currently  
                             * open in this thread. */  
     TkMainInfo *mainWindowList;  
                            /* First in list of all main windows managed  
                             * by this thread. */  
     TkDisplay *displayList;  
                            /* List of all displays currently in use by  
                             * the current thread. */  
     int initialized;       /* 0 means the structures above need  
                             * initializing. */  
 } ThreadSpecificData;  
 static Tcl_ThreadDataKey dataKey;  
   
 /*  
  * The Mutex below is used to lock access to the Tk_Uid structs above.  
  */  
   
 TCL_DECLARE_MUTEX(windowMutex)  
   
 /*  
  * Default values for "changes" and "atts" fields of TkWindows.  Note  
  * that Tk always requests all events for all windows, except StructureNotify  
  * events on internal windows:  these events are generated internally.  
  */  
   
 static XWindowChanges defChanges = {  
     0, 0, 1, 1, 0, 0, Above  
 };  
 #define ALL_EVENTS_MASK \  
     KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \  
     EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \  
     VisibilityChangeMask|PropertyChangeMask|ColormapChangeMask  
 static XSetWindowAttributes defAtts= {  
     None,                       /* background_pixmap */  
     0,                          /* background_pixel */  
     CopyFromParent,             /* border_pixmap */  
     0,                          /* border_pixel */  
     NorthWestGravity,           /* bit_gravity */  
     NorthWestGravity,           /* win_gravity */  
     NotUseful,                  /* backing_store */  
     (unsigned) ~0,              /* backing_planes */  
     0,                          /* backing_pixel */  
     False,                      /* save_under */  
     ALL_EVENTS_MASK,            /* event_mask */  
     0,                          /* do_not_propagate_mask */  
     False,                      /* override_redirect */  
     CopyFromParent,             /* colormap */  
     None                        /* cursor */  
 };  
   
 /*  
  * The following structure defines all of the commands supported by  
  * Tk, and the C procedures that execute them.  
  */  
   
 typedef struct {  
     char *name;                 /* Name of command. */  
     Tcl_CmdProc *cmdProc;       /* Command's string-based procedure. */  
     Tcl_ObjCmdProc *objProc;    /* Command's object-based procedure. */  
     int isSafe;                 /* If !0, this command will be exposed in  
                                  * a safe interpreter. Otherwise it will be  
                                  * hidden in a safe interpreter. */  
     int passMainWindow;         /* 0 means provide NULL clientData to  
                                  * command procedure; 1 means pass main  
                                  * window as clientData to command  
                                  * procedure. */  
 } TkCmd;  
   
 static TkCmd commands[] = {  
     /*  
      * Commands that are part of the intrinsics:  
      */  
   
     {"bell",            NULL,                   Tk_BellObjCmd,          0, 1},  
     {"bind",            Tk_BindCmd,             NULL,                   1, 1},  
     {"bindtags",        Tk_BindtagsCmd,         NULL,                   1, 1},  
     {"clipboard",       Tk_ClipboardCmd,        NULL,                   0, 1},  
     {"destroy",         NULL,                   Tk_DestroyObjCmd,       1, 1},  
     {"event",           NULL,                   Tk_EventObjCmd,         1, 1},  
     {"focus",           NULL,                   Tk_FocusObjCmd,         1, 1},  
     {"font",            NULL,                   Tk_FontObjCmd,          1, 1},  
     {"grab",            Tk_GrabCmd,             NULL,                   0, 1},  
     {"grid",            Tk_GridCmd,             NULL,                   1, 1},  
     {"image",           NULL,                   Tk_ImageObjCmd,         1, 1},  
     {"lower",           NULL,                   Tk_LowerObjCmd,         1, 1},  
     {"option",          NULL,                   Tk_OptionObjCmd,        1, 1},  
     {"pack",            Tk_PackCmd,             NULL,                   1, 1},  
     {"place",           Tk_PlaceCmd,            NULL,                   1, 1},  
     {"raise",           NULL,                   Tk_RaiseObjCmd,         1, 1},  
     {"selection",       Tk_SelectionCmd,        NULL,                   0, 1},  
     {"tk",              NULL,                   Tk_TkObjCmd,            0, 1},  
     {"tkwait",          Tk_TkwaitCmd,           NULL,                   1, 1},  
 #if defined(__WIN32__) || defined(MAC_TCL)  
     {"tk_chooseColor",  NULL,                   Tk_ChooseColorObjCmd,   0, 1},  
     {"tk_chooseDirectory", NULL,                Tk_ChooseDirectoryObjCmd, 0, 1},  
     {"tk_getOpenFile",  NULL,                   Tk_GetOpenFileObjCmd,   0, 1},  
     {"tk_getSaveFile",  NULL,                   Tk_GetSaveFileObjCmd,   0, 1},  
 #endif  
 #ifdef __WIN32__  
     {"tk_messageBox",   NULL,                   Tk_MessageBoxObjCmd,    0, 1},  
 #endif  
     {"update",          NULL,                   Tk_UpdateObjCmd,        1, 1},  
     {"winfo",           NULL,                   Tk_WinfoObjCmd,         1, 1},  
     {"wm",              Tk_WmCmd,               NULL,                   0, 1},  
   
     /*  
      * Widget class commands.  
      */  
   
     {"button",          NULL,                   Tk_ButtonObjCmd,        1, 0},  
     {"canvas",          NULL,                   Tk_CanvasObjCmd,        1, 1},  
     {"checkbutton",     NULL,                   Tk_CheckbuttonObjCmd,   1, 0},  
     {"entry",           NULL,                   Tk_EntryObjCmd,         1, 0},  
     {"frame",           NULL,                   Tk_FrameObjCmd,         1, 1},  
     {"label",           NULL,                   Tk_LabelObjCmd,         1, 0},  
     {"listbox",         NULL,                   Tk_ListboxObjCmd,       1, 0},  
     {"menubutton",      NULL,                   Tk_MenubuttonObjCmd,    1, 0},  
     {"message",         Tk_MessageCmd,          NULL,                   1, 1},  
     {"radiobutton",     NULL,                   Tk_RadiobuttonObjCmd,   1, 0},  
     {"scale",           NULL,                   Tk_ScaleObjCmd,         1, 0},  
     {"scrollbar",       Tk_ScrollbarCmd,        NULL,                   1, 1},  
     {"text",            Tk_TextCmd,             NULL,                   1, 1},  
     {"toplevel",        NULL,                   Tk_ToplevelObjCmd,      0, 1},  
   
     /*  
      * Misc.  
      */  
   
 #ifdef MAC_TCL  
     {"unsupported1",    TkUnsupported1Cmd,      NULL,                   1, 1},  
 #endif  
     {(char *) NULL,     (int (*) _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **))) NULL, NULL, 0}  
 };  
   
 /*  
  * The variables and table below are used to parse arguments from  
  * the "argv" variable in Tk_Init.  
  */  
   
 static int synchronize = 0;  
 static char *name = NULL;  
 static char *display = NULL;  
 static char *geometry = NULL;  
 static char *colormap = NULL;  
 static char *use = NULL;  
 static char *visual = NULL;  
 static int rest = 0;  
   
 static Tk_ArgvInfo argTable[] = {  
     {"-colormap", TK_ARGV_STRING, (char *) NULL, (char *) &colormap,  
         "Colormap for main window"},  
     {"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,  
         "Display to use"},  
     {"-geometry", TK_ARGV_STRING, (char *) NULL, (char *) &geometry,  
         "Initial geometry for window"},  
     {"-name", TK_ARGV_STRING, (char *) NULL, (char *) &name,  
         "Name to use for application"},  
     {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,  
         "Use synchronous mode for display server"},  
     {"-visual", TK_ARGV_STRING, (char *) NULL, (char *) &visual,  
         "Visual for main window"},  
     {"-use", TK_ARGV_STRING, (char *) NULL, (char *) &use,  
         "Id of window in which to embed application"},  
     {"--", TK_ARGV_REST, (char *) 1, (char *) &rest,  
         "Pass all remaining arguments through to script"},  
     {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,  
         (char *) NULL}  
 };  
   
 /*  
  * Forward declarations to procedures defined later in this file:  
  */  
   
 static Tk_Window        CreateTopLevelWindow _ANSI_ARGS_((Tcl_Interp *interp,  
                             Tk_Window parent, char *name, char *screenName));  
 static void             DeleteWindowsExitProc _ANSI_ARGS_((  
                             ClientData clientData));  
 static TkDisplay *      GetScreen _ANSI_ARGS_((Tcl_Interp *interp,  
                             char *screenName, int *screenPtr));  
 static int              Initialize _ANSI_ARGS_((Tcl_Interp *interp));  
 static int              NameWindow _ANSI_ARGS_((Tcl_Interp *interp,  
                             TkWindow *winPtr, TkWindow *parentPtr,  
                             char *name));  
 static void             OpenIM _ANSI_ARGS_((TkDisplay *dispPtr));  
 static void             UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr));  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * CreateTopLevelWindow --  
  *  
  *      Make a new window that will be at top-level (its parent will  
  *      be the root window of a screen).  
  *  
  * Results:  
  *      The return value is a token for the new window, or NULL if  
  *      an error prevented the new window from being created.  If  
  *      NULL is returned, an error message will be left in  
  *      the interp's result.  
  *  
  * Side effects:  
  *      A new window structure is allocated locally.  An X  
  *      window is NOT initially created, but will be created  
  *      the first time the window is mapped.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static Tk_Window  
 CreateTopLevelWindow(interp, parent, name, screenName)  
     Tcl_Interp *interp;         /* Interpreter to use for error reporting. */  
     Tk_Window parent;           /* Token for logical parent of new window  
                                  * (used for naming, options, etc.).  May  
                                  * be NULL. */  
     char *name;                 /* Name for new window;  if parent is  
                                  * non-NULL, must be unique among parent's  
                                  * children. */  
     char *screenName;           /* Name of screen on which to create  
                                  * window.  NULL means use DISPLAY environment  
                                  * variable to determine.  Empty string means  
                                  * use parent's screen, or DISPLAY if no  
                                  * parent. */  
 {  
     register TkWindow *winPtr;  
     register TkDisplay *dispPtr;  
     int screenId;  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
   
     if (!tsdPtr->initialized) {  
         tsdPtr->initialized = 1;  
   
         /*  
          * Create built-in image types.  
          */  
       
         Tk_CreateImageType(&tkBitmapImageType);  
         Tk_CreateImageType(&tkPhotoImageType);  
       
         /*  
          * Create built-in photo image formats.  
          */  
       
         Tk_CreatePhotoImageFormat(&tkImgFmtGIF);  
         Tk_CreateOldPhotoImageFormat(&tkImgFmtPPM);  
   
         /*  
          * Create exit handler to delete all windows when the application  
          * exits.  
          */  
   
         Tcl_CreateExitHandler(DeleteWindowsExitProc, (ClientData) NULL);  
     }  
   
     if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {  
         dispPtr = ((TkWindow *) parent)->dispPtr;  
         screenId = Tk_ScreenNumber(parent);  
     } else {  
         dispPtr = GetScreen(interp, screenName, &screenId);  
         if (dispPtr == NULL) {  
             return (Tk_Window) NULL;  
         }  
     }  
   
     winPtr = TkAllocWindow(dispPtr, screenId, (TkWindow *) parent);  
   
     /*  
      * Force the window to use a border pixel instead of border pixmap.  
      * This is needed for the case where the window doesn't use the  
      * default visual.  In this case, the default border is a pixmap  
      * inherited from the root window, which won't work because it will  
      * have the wrong visual.  
      */  
   
     winPtr->dirtyAtts |= CWBorderPixel;  
   
     /*  
      * (Need to set the TK_TOP_LEVEL flag immediately here;  otherwise  
      * Tk_DestroyWindow will core dump if it is called before the flag  
      * has been set.)  
      */  
   
     winPtr->flags |= TK_TOP_LEVEL;  
   
     if (parent != NULL) {  
         if (NameWindow(interp, winPtr, (TkWindow *) parent, name) != TCL_OK) {  
             Tk_DestroyWindow((Tk_Window) winPtr);  
             return (Tk_Window) NULL;  
         }  
     }  
     TkWmNewWindow(winPtr);  
   
     return (Tk_Window) winPtr;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * GetScreen --  
  *  
  *      Given a string name for a display-plus-screen, find the  
  *      TkDisplay structure for the display and return the screen  
  *      number too.  
  *  
  * Results:  
  *      The return value is a pointer to information about the display,  
  *      or NULL if the display couldn't be opened.  In this case, an  
  *      error message is left in the interp's result.  The location at  
  *      *screenPtr is overwritten with the screen number parsed from  
  *      screenName.  
  *  
  * Side effects:  
  *      A new connection is opened to the display if there is no  
  *      connection already.  A new TkDisplay data structure is also  
  *      setup, if necessary.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static TkDisplay *  
 GetScreen(interp, screenName, screenPtr)  
     Tcl_Interp *interp;         /* Place to leave error message. */  
     char *screenName;           /* Name for screen.  NULL or empty means  
                                  * use DISPLAY envariable. */  
     int *screenPtr;             /* Where to store screen number. */  
 {  
     register TkDisplay *dispPtr;  
     char *p;  
     int screenId;  
     size_t length;  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
   
     /*  
      * Separate the screen number from the rest of the display  
      * name.  ScreenName is assumed to have the syntax  
      * <display>.<screen> with the dot and the screen being  
      * optional.  
      */  
   
     screenName = TkGetDefaultScreenName(interp, screenName);  
     if (screenName == NULL) {  
         Tcl_SetResult(interp,  
                 "no display name and no $DISPLAY environment variable",  
                 TCL_STATIC);  
         return (TkDisplay *) NULL;  
     }  
     length = strlen(screenName);  
     screenId = 0;  
     p = screenName+length-1;  
     while (isdigit(UCHAR(*p)) && (p != screenName)) {  
         p--;  
     }  
     if ((*p == '.') && (p[1] != '\0')) {  
         length = p - screenName;  
         screenId = strtoul(p+1, (char **) NULL, 10);  
     }  
   
     /*  
      * See if we already have a connection to this display.  If not,  
      * then open a new connection.  
      */  
   
     for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) {  
         if (dispPtr == NULL) {  
             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->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;  
             strncpy(dispPtr->name, screenName, length);  
             dispPtr->name[length] = '\0';  
             dispPtr->useInputMethods = 0;  
             OpenIM(dispPtr);  
             TkInitXId(dispPtr);  
   
             tsdPtr->displayList = dispPtr;  
             break;  
         }  
         if ((strncmp(dispPtr->name, screenName, length) == 0)  
                 && (dispPtr->name[length] == '\0')) {  
             break;  
         }  
     }  
     if (screenId >= ScreenCount(dispPtr->display)) {  
         char buf[32 + TCL_INTEGER_SPACE];  
           
         sprintf(buf, "bad screen number \"%d\"", screenId);  
         Tcl_SetResult(interp, buf, TCL_VOLATILE);  
         return (TkDisplay *) NULL;  
     }  
     *screenPtr = screenId;  
     return dispPtr;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TkGetDisplay --  
  *  
  *      Given an X display, TkGetDisplay returns the TkDisplay  
  *      structure for the display.  
  *  
  * Results:  
  *      The return value is a pointer to information about the display,  
  *      or NULL if the display did not have a TkDisplay structure.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 TkDisplay *  
 TkGetDisplay(display)  
      Display *display;          /* X's display pointer */  
 {  
     TkDisplay *dispPtr;  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
   
     for (dispPtr = tsdPtr->displayList; dispPtr != NULL;  
             dispPtr = dispPtr->nextPtr) {  
         if (dispPtr->display == display) {  
             break;  
         }  
     }  
     return dispPtr;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TkGetDisplayList --  
  *  
  *      This procedure returns a pointer to the thread-local  
  *      list of TkDisplays corresponding to the open displays.  
  *  
  * Results:  
  *      The return value is a pointer to the first TkDisplay  
  *      structure in thread-local-storage.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
 TkDisplay *  
 TkGetDisplayList()  
 {  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
       
     return tsdPtr->displayList;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TkGetMainInfoList --  
  *  
  *      This procedure returns a pointer to the list of structures  
  *      containing information about all main windows for the  
  *      current thread.  
  *  
  * Results:  
  *      The return value is a pointer to the first TkMainInfo  
  *      structure in thread local storage.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
 TkMainInfo *  
 TkGetMainInfoList()  
 {  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
       
     return tsdPtr->mainWindowList;  
 }  
 /*  
  *--------------------------------------------------------------  
  *  
  * TkAllocWindow --  
  *  
  *      This procedure creates and initializes a TkWindow structure.  
  *  
  * Results:  
  *      The return value is a pointer to the new window.  
  *  
  * Side effects:  
  *      A new window structure is allocated and all its fields are  
  *      initialized.  
  *  
  *--------------------------------------------------------------  
  */  
   
 TkWindow *  
 TkAllocWindow(dispPtr, screenNum, parentPtr)  
     TkDisplay *dispPtr;         /* Display associated with new window. */  
     int screenNum;              /* Index of screen for new window. */  
     TkWindow *parentPtr;        /* Parent from which this window should  
                                  * inherit visual information.  NULL means  
                                  * use screen defaults instead of  
                                  * inheriting. */  
 {  
     register TkWindow *winPtr;  
   
     winPtr = (TkWindow *) ckalloc(sizeof(TkWindow));  
     winPtr->display = dispPtr->display;  
     winPtr->dispPtr = dispPtr;  
     winPtr->screenNum = screenNum;  
     if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)  
             && (parentPtr->screenNum == winPtr->screenNum)) {  
         winPtr->visual = parentPtr->visual;  
         winPtr->depth = parentPtr->depth;  
     } else {  
         winPtr->visual = DefaultVisual(dispPtr->display, screenNum);  
         winPtr->depth = DefaultDepth(dispPtr->display, screenNum);  
     }  
     winPtr->window = None;  
     winPtr->childList = NULL;  
     winPtr->lastChildPtr = NULL;  
     winPtr->parentPtr = NULL;  
     winPtr->nextPtr = NULL;  
     winPtr->mainPtr = NULL;  
     winPtr->pathName = NULL;  
     winPtr->nameUid = NULL;  
     winPtr->classUid = NULL;  
     winPtr->changes = defChanges;  
     winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;  
     winPtr->atts = defAtts;  
     if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)  
             && (parentPtr->screenNum == winPtr->screenNum)) {  
         winPtr->atts.colormap = parentPtr->atts.colormap;  
     } else {  
         winPtr->atts.colormap = DefaultColormap(dispPtr->display, screenNum);  
     }  
     winPtr->dirtyAtts = CWEventMask|CWColormap|CWBitGravity;  
     winPtr->flags = 0;  
     winPtr->handlerList = NULL;  
 #ifdef TK_USE_INPUT_METHODS  
     winPtr->inputContext = NULL;  
 #endif /* TK_USE_INPUT_METHODS */  
     winPtr->tagPtr = NULL;  
     winPtr->numTags = 0;  
     winPtr->optionLevel = -1;  
     winPtr->selHandlerList = NULL;  
     winPtr->geomMgrPtr = NULL;  
     winPtr->geomData = NULL;  
     winPtr->reqWidth = winPtr->reqHeight = 1;  
     winPtr->internalBorderWidth = 0;  
     winPtr->wmInfoPtr = NULL;  
     winPtr->classProcsPtr = NULL;  
     winPtr->instanceData = NULL;  
     winPtr->privatePtr = NULL;  
   
     return winPtr;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * NameWindow --  
  *  
  *      This procedure is invoked to give a window a name and insert  
  *      the window into the hierarchy associated with a particular  
  *      application.  
  *  
  * Results:  
  *      A standard Tcl return value.  
  *  
  * Side effects:  
  *      See above.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 NameWindow(interp, winPtr, parentPtr, name)  
     Tcl_Interp *interp;         /* Interpreter to use for error reporting. */  
     register TkWindow *winPtr;  /* Window that is to be named and inserted. */  
     TkWindow *parentPtr;        /* Pointer to logical parent for winPtr  
                                  * (used for naming, options, etc.). */  
     char *name;                 /* Name for winPtr;   must be unique among  
                                  * parentPtr's children. */  
 {  
 #define FIXED_SIZE 200  
     char staticSpace[FIXED_SIZE];  
     char *pathName;  
     int new;  
     Tcl_HashEntry *hPtr;  
     int length1, length2;  
   
     /*  
      * Setup all the stuff except name right away, then do the name stuff  
      * last.  This is so that if the name stuff fails, everything else  
      * will be properly initialized (needed to destroy the window cleanly  
      * after the naming failure).  
      */  
     winPtr->parentPtr = parentPtr;  
     winPtr->nextPtr = NULL;  
     if (parentPtr->childList == NULL) {  
         parentPtr->childList = winPtr;  
     } else {  
         parentPtr->lastChildPtr->nextPtr = winPtr;  
     }  
     parentPtr->lastChildPtr = winPtr;  
     winPtr->mainPtr = parentPtr->mainPtr;  
     winPtr->mainPtr->refCount++;  
     winPtr->nameUid = Tk_GetUid(name);  
   
     /*  
      * Don't permit names that start with an upper-case letter:  this  
      * will just cause confusion with class names in the option database.  
      */  
   
     if (isupper(UCHAR(name[0]))) {  
         Tcl_AppendResult(interp,  
                 "window name starts with an upper-case letter: \"",  
                 name, "\"", (char *) NULL);  
         return TCL_ERROR;  
     }  
   
     /*  
      * To permit names of arbitrary length, must be prepared to malloc  
      * a buffer to hold the new path name.  To run fast in the common  
      * case where names are short, use a fixed-size buffer on the  
      * stack.  
      */  
   
     length1 = strlen(parentPtr->pathName);  
     length2 = strlen(name);  
     if ((length1+length2+2) <= FIXED_SIZE) {  
         pathName = staticSpace;  
     } else {  
         pathName = (char *) ckalloc((unsigned) (length1+length2+2));  
     }  
     if (length1 == 1) {  
         pathName[0] = '.';  
         strcpy(pathName+1, name);  
     } else {  
         strcpy(pathName, parentPtr->pathName);  
         pathName[length1] = '.';  
         strcpy(pathName+length1+1, name);  
     }  
     hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new);  
     if (pathName != staticSpace) {  
         ckfree(pathName);  
     }  
     if (!new) {  
         Tcl_AppendResult(interp, "window name \"", name,  
                 "\" already exists in parent", (char *) NULL);  
         return TCL_ERROR;  
     }  
     Tcl_SetHashValue(hPtr, winPtr);  
     winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr);  
     return TCL_OK;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TkCreateMainWindow --  
  *  
  *      Make a new main window.  A main window is a special kind of  
  *      top-level window used as the outermost window in an  
  *      application.  
  *  
  * Results:  
  *      The return value is a token for the new window, or NULL if  
  *      an error prevented the new window from being created.  If  
  *      NULL is returned, an error message will be left in  
  *      the interp's result.  
  *  
  * Side effects:  
  *      A new window structure is allocated locally;  "interp" is  
  *      associated with the window and registered for "send" commands  
  *      under "baseName".  BaseName may be extended with an instance  
  *      number in the form "#2" if necessary to make it globally  
  *      unique.  Tk-related commands are bound into interp.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tk_Window  
 TkCreateMainWindow(interp, screenName, baseName)  
     Tcl_Interp *interp;         /* Interpreter to use for error reporting. */  
     char *screenName;           /* Name of screen on which to create  
                                  * window.  Empty or NULL string means  
                                  * use DISPLAY environment variable. */  
     char *baseName;             /* Base name for application;  usually of the  
                                  * form "prog instance". */  
 {  
     Tk_Window tkwin;  
     int dummy;  
     int isSafe;  
     Tcl_HashEntry *hPtr;  
     register TkMainInfo *mainPtr;  
     register TkWindow *winPtr;  
     register TkCmd *cmdPtr;  
     ClientData clientData;  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
       
     /*  
      * Panic if someone updated the TkWindow structure without  
      * also updating the Tk_FakeWin structure (or vice versa).  
      */  
   
     if (sizeof(TkWindow) != sizeof(Tk_FakeWin)) {  
         panic("TkWindow and Tk_FakeWin are not the same size");  
     }  
   
     /*  
      * Create the basic TkWindow structure.  
      */  
   
     tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName,  
             screenName);  
     if (tkwin == NULL) {  
         return NULL;  
     }  
       
     /*  
      * Create the TkMainInfo structure for this application, and set  
      * up name-related information for the new window.  
      */  
   
     winPtr = (TkWindow *) tkwin;  
     mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo));  
     mainPtr->winPtr = winPtr;  
     mainPtr->refCount = 1;  
     mainPtr->interp = interp;  
     Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS);  
     TkEventInit();  
     TkBindInit(mainPtr);  
     TkFontPkgInit(mainPtr);  
     mainPtr->tlFocusPtr = NULL;  
     mainPtr->displayFocusPtr = NULL;  
     mainPtr->optionRootPtr = NULL;  
     Tcl_InitHashTable(&mainPtr->imageTable, TCL_STRING_KEYS);  
     mainPtr->strictMotif = 0;  
     if (Tcl_LinkVar(interp, "tk_strictMotif", (char *) &mainPtr->strictMotif,  
             TCL_LINK_BOOLEAN) != TCL_OK) {  
         Tcl_ResetResult(interp);  
     }  
     mainPtr->nextPtr = tsdPtr->mainWindowList;  
     tsdPtr->mainWindowList = mainPtr;  
     winPtr->mainPtr = mainPtr;  
     hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy);  
     Tcl_SetHashValue(hPtr, winPtr);  
     winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr);  
   
     /*  
      * We have just created another Tk application; increment the refcount  
      * on the display pointer.  
      */  
   
     winPtr->dispPtr->refCount++;  
   
     /*  
      * Register the interpreter for "send" purposes.  
      */  
   
     winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, baseName));  
   
     /*  
      * Bind in Tk's commands.  
      */  
   
     isSafe = Tcl_IsSafe(interp);  
     for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {  
         if ((cmdPtr->cmdProc == NULL) && (cmdPtr->objProc == NULL)) {  
             panic("TkCreateMainWindow: builtin command with NULL string and object procs");  
         }  
         if (cmdPtr->passMainWindow) {  
             clientData = (ClientData) tkwin;  
         } else {  
             clientData = (ClientData) NULL;  
         }  
         if (cmdPtr->cmdProc != NULL) {  
             Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc,  
                     clientData, (void (*) _ANSI_ARGS_((ClientData))) NULL);  
         } else {  
             Tcl_CreateObjCommand(interp, cmdPtr->name, cmdPtr->objProc,  
                     clientData, NULL);  
         }  
         if (isSafe) {  
             if (!(cmdPtr->isSafe)) {  
                 Tcl_HideCommand(interp, cmdPtr->name, cmdPtr->name);  
             }  
         }  
     }  
   
     TkCreateMenuCmd(interp);  
   
     /*  
      * Set variables for the intepreter.  
      */  
   
     Tcl_SetVar(interp, "tk_patchLevel", TK_PATCH_LEVEL, TCL_GLOBAL_ONLY);  
     Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY);  
   
     tsdPtr->numMainWindows++;  
     return tkwin;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_CreateWindow --  
  *  
  *      Create a new internal or top-level window as a child of an  
  *      existing window.  
  *  
  * Results:  
  *      The return value is a token for the new window.  This  
  *      is not the same as X's token for the window.  If an error  
  *      occurred in creating the window (e.g. no such display or  
  *      screen), then an error message is left in the interp's result and  
  *      NULL is returned.  
  *  
  * Side effects:  
  *      A new window structure is allocated locally.  An X  
  *      window is not initially created, but will be created  
  *      the first time the window is mapped.  
  *  
  *--------------------------------------------------------------  
  */  
   
 Tk_Window  
 Tk_CreateWindow(interp, parent, name, screenName)  
     Tcl_Interp *interp;         /* Interpreter to use for error reporting.  
                                  * the interp's result is assumed to be  
                                  * initialized by the caller. */  
     Tk_Window parent;           /* Token for parent of new window. */  
     char *name;                 /* Name for new window.  Must be unique  
                                  * among parent's children. */  
     char *screenName;           /* If NULL, new window will be internal on  
                                  * same screen as its parent.  If non-NULL,  
                                  * gives name of screen on which to create  
                                  * new window;  window will be a top-level  
                                  * window. */  
 {  
     TkWindow *parentPtr = (TkWindow *) parent;  
     TkWindow *winPtr;  
   
     if ((parentPtr != NULL) && (parentPtr->flags & TK_ALREADY_DEAD)) {  
         Tcl_AppendResult(interp,  
                 "can't create window: parent has been destroyed",  
                 (char *) NULL);  
         return NULL;  
     } else if ((parentPtr != NULL) &&  
             (parentPtr->flags & TK_CONTAINER)) {  
         Tcl_AppendResult(interp,  
                 "can't create window: its parent has -container = yes",  
                 (char *) NULL);  
         return NULL;  
     }  
     if (screenName == NULL) {  
         winPtr = TkAllocWindow(parentPtr->dispPtr, parentPtr->screenNum,  
                 parentPtr);  
         if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) {  
             Tk_DestroyWindow((Tk_Window) winPtr);  
             return NULL;  
         } else {  
             return (Tk_Window) winPtr;  
         }  
     } else {  
         return CreateTopLevelWindow(interp, parent, name, screenName);  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_CreateWindowFromPath --  
  *  
  *      This procedure is similar to Tk_CreateWindow except that  
  *      it uses a path name to create the window, rather than a  
  *      parent and a child name.  
  *  
  * Results:  
  *      The return value is a token for the new window.  This  
  *      is not the same as X's token for the window.  If an error  
  *      occurred in creating the window (e.g. no such display or  
  *      screen), then an error message is left in the interp's result and  
  *      NULL is returned.  
  *  
  * Side effects:  
  *      A new window structure is allocated locally.  An X  
  *      window is not initially created, but will be created  
  *      the first time the window is mapped.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tk_Window  
 Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName)  
     Tcl_Interp *interp;         /* Interpreter to use for error reporting.  
                                  * the interp's result is assumed to be  
                                  * initialized by the caller. */  
     Tk_Window tkwin;            /* Token for any window in application  
                                  * that is to contain new window. */  
     char *pathName;             /* Path name for new window within the  
                                  * application of tkwin.  The parent of  
                                  * this window must already exist, but  
                                  * the window itself must not exist. */  
     char *screenName;           /* If NULL, new window will be on same  
                                  * screen as its parent.  If non-NULL,  
                                  * gives name of screen on which to create  
                                  * new window;  window will be a top-level  
                                  * window. */  
 {  
 #define FIXED_SPACE 5  
     char fixedSpace[FIXED_SPACE+1];  
     char *p;  
     Tk_Window parent;  
     int numChars;  
   
     /*  
      * Strip the parent's name out of pathName (it's everything up  
      * to the last dot).  There are two tricky parts: (a) must  
      * copy the parent's name somewhere else to avoid modifying  
      * the pathName string (for large names, space for the copy  
      * will have to be malloc'ed);  (b) must special-case the  
      * situation where the parent is ".".  
      */  
   
     p = strrchr(pathName, '.');  
     if (p == NULL) {  
         Tcl_AppendResult(interp, "bad window path name \"", pathName,  
                 "\"", (char *) NULL);  
         return NULL;  
     }  
     numChars = p-pathName;  
     if (numChars > FIXED_SPACE) {  
         p = (char *) ckalloc((unsigned) (numChars+1));  
     } else {  
         p = fixedSpace;  
     }  
     if (numChars == 0) {  
         *p = '.';  
         p[1] = '\0';  
     } else {  
         strncpy(p, pathName, (size_t) numChars);  
         p[numChars] = '\0';  
     }  
   
     /*  
      * Find the parent window.  
      */  
   
     parent = Tk_NameToWindow(interp, p, tkwin);  
     if (p != fixedSpace) {  
         ckfree(p);  
     }  
     if (parent == NULL) {  
         return NULL;  
     }  
     if (((TkWindow *) parent)->flags & TK_ALREADY_DEAD) {  
         Tcl_AppendResult(interp,  
             "can't create window: parent has been destroyed", (char *) NULL);  
         return NULL;  
     } else if (((TkWindow *) parent)->flags & TK_CONTAINER) {  
         Tcl_AppendResult(interp,  
             "can't create window: its parent has -container = yes",  
                 (char *) NULL);  
         return NULL;  
     }  
   
     /*  
      * Create the window.  
      */  
   
     if (screenName == NULL) {  
         TkWindow *parentPtr = (TkWindow *) parent;  
         TkWindow *winPtr;  
   
         winPtr = TkAllocWindow(parentPtr->dispPtr, parentPtr->screenNum,  
                 parentPtr);  
         if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1)  
                 != TCL_OK) {  
             Tk_DestroyWindow((Tk_Window) winPtr);  
             return NULL;  
         } else {  
             return (Tk_Window) winPtr;  
         }  
     } else {  
         return CreateTopLevelWindow(interp, parent, pathName+numChars+1,  
                 screenName);  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_DestroyWindow --  
  *  
  *      Destroy an existing window.  After this call, the caller  
  *      should never again use the token.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The window is deleted, along with all of its children.  
  *      Relevant callback procedures are invoked.  
  *  
  *--------------------------------------------------------------  
  */  
   
 void  
 Tk_DestroyWindow(tkwin)  
     Tk_Window tkwin;            /* Window to destroy. */  
 {  
     TkWindow *winPtr = (TkWindow *) tkwin;  
     TkDisplay *dispPtr = winPtr->dispPtr;  
     XEvent event;  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
   
     if (winPtr->flags & TK_ALREADY_DEAD) {  
         /*  
          * A destroy event binding caused the window to be destroyed  
          * again.  Ignore the request.  
          */  
   
         return;  
     }  
     winPtr->flags |= TK_ALREADY_DEAD;  
   
     /*  
      * Some cleanup needs to be done immediately, rather than later,  
      * because it needs information that will be destoyed before we  
      * get to the main cleanup point.  For example, TkFocusDeadWindow  
      * needs to access the parentPtr field from a window, but if  
      * a Destroy event handler deletes the window's parent this  
      * field will be NULL before the main cleanup point is reached.  
      */  
   
     TkFocusDeadWindow(winPtr);  
   
     /*  
      * If this is a main window, remove it from the list of main  
      * windows.  This needs to be done now (rather than later with  
      * all the other main window cleanup) to handle situations where  
      * a destroy binding for a window calls "exit".  In this case  
      * the child window cleanup isn't complete when exit is called,  
      * so the reference count of its application doesn't go to zero  
      * when exit calls Tk_DestroyWindow on ".", so the main window  
      * doesn't get removed from the list and exit loops infinitely.  
      * Even worse, if "destroy ." is called by the destroy binding  
      * before calling "exit", "exit" will attempt to destroy  
      * mainPtr->winPtr, which no longer exists, and there may be a  
      * core dump.  
      *  
      * Also decrement the display refcount so that if this is the  
      * last Tk application in this process on this display, the display  
      * can be closed and its data structures deleted.  
      */  
   
     if (winPtr->mainPtr->winPtr == winPtr) {  
         dispPtr->refCount--;  
         if (tsdPtr->mainWindowList == winPtr->mainPtr) {  
             tsdPtr->mainWindowList = winPtr->mainPtr->nextPtr;  
         } else {  
             TkMainInfo *prevPtr;  
   
             for (prevPtr = tsdPtr->mainWindowList;  
                     prevPtr->nextPtr != winPtr->mainPtr;  
                     prevPtr = prevPtr->nextPtr) {  
                 /* Empty loop body. */  
             }  
             prevPtr->nextPtr = winPtr->mainPtr->nextPtr;  
         }  
         tsdPtr->numMainWindows--;  
     }  
   
     /*  
      * Recursively destroy children.  
      */  
   
     dispPtr->destroyCount++;  
     while (winPtr->childList != NULL) {  
         TkWindow *childPtr;  
         childPtr = winPtr->childList;  
         childPtr->flags |= TK_DONT_DESTROY_WINDOW;  
         Tk_DestroyWindow((Tk_Window) childPtr);  
         if (winPtr->childList == childPtr) {  
             /*  
              * The child didn't remove itself from the child list, so  
              * let's remove it here.  This can happen in some strange  
              * conditions, such as when a Delete event handler for a  
              * window deletes the window's parent.  
              */  
   
             winPtr->childList = childPtr->nextPtr;  
             childPtr->parentPtr = NULL;  
         }  
     }  
     if ((winPtr->flags & (TK_CONTAINER|TK_BOTH_HALVES))  
             == (TK_CONTAINER|TK_BOTH_HALVES)) {  
         /*  
          * This is the container for an embedded application, and  
          * the embedded application is also in this process.  Delete  
          * the embedded window in-line here, for the same reasons we  
          * delete children in-line (otherwise, for example, the Tk  
          * window may appear to exist even though its X window is  
          * gone; this could cause errors).  Special note: it's possible  
          * that the embedded window has already been deleted, in which  
          * case TkpGetOtherWindow will return NULL.  
          */  
   
         TkWindow *childPtr;  
         childPtr = TkpGetOtherWindow(winPtr);  
         if (childPtr != NULL) {  
             childPtr->flags |= TK_DONT_DESTROY_WINDOW;  
             Tk_DestroyWindow((Tk_Window) childPtr);  
         }  
     }  
   
     /*  
      * Generate a DestroyNotify event.  In order for the DestroyNotify  
      * event to be processed correctly, need to make sure the window  
      * exists.  This is a bit of a kludge, and may be unnecessarily  
      * expensive, but without it no event handlers will get called for  
      * windows that don't exist yet.  
      *  
      * Note: if the window's pathName is NULL it means that the window  
      * was not successfully initialized in the first place, so we should  
      * not make the window exist or generate the event.  
      */  
   
     if (winPtr->pathName != NULL) {  
         if (winPtr->window == None) {  
             Tk_MakeWindowExist(tkwin);  
         }  
         event.type = DestroyNotify;  
         event.xdestroywindow.serial =  
                 LastKnownRequestProcessed(winPtr->display);  
         event.xdestroywindow.send_event = False;  
         event.xdestroywindow.display = winPtr->display;  
         event.xdestroywindow.event = winPtr->window;  
         event.xdestroywindow.window = winPtr->window;  
         Tk_HandleEvent(&event);  
     }  
   
     /*  
      * Cleanup the data structures associated with this window.  
      */  
   
     if (winPtr->flags & TK_TOP_LEVEL) {  
         TkWmDeadWindow(winPtr);  
     } else if (winPtr->flags & TK_WM_COLORMAP_WINDOW) {  
         TkWmRemoveFromColormapWindows(winPtr);  
     }  
     if (winPtr->window != None) {  
 #if defined(MAC_TCL) || defined(__WIN32__)  
         XDestroyWindow(winPtr->display, winPtr->window);  
 #else  
         if ((winPtr->flags & TK_TOP_LEVEL)  
                 || !(winPtr->flags & TK_DONT_DESTROY_WINDOW)) {  
             /*  
              * The parent has already been destroyed and this isn't  
              * a top-level window, so this window will be destroyed  
              * implicitly when the parent's X window is destroyed;  
              * it's much faster not to do an explicit destroy of this  
              * X window.  
              */  
   
             dispPtr->lastDestroyRequest = NextRequest(winPtr->display);  
             XDestroyWindow(winPtr->display, winPtr->window);  
         }  
 #endif  
         TkFreeWindowId(dispPtr, winPtr->window);  
         Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->winTable,  
                 (char *) winPtr->window));  
         winPtr->window = None;  
     }  
     dispPtr->destroyCount--;  
     UnlinkWindow(winPtr);  
     TkEventDeadWindow(winPtr);  
     TkBindDeadWindow(winPtr);  
 #ifdef TK_USE_INPUT_METHODS  
     if (winPtr->inputContext != NULL) {  
         XDestroyIC(winPtr->inputContext);  
     }  
 #endif /* TK_USE_INPUT_METHODS */  
     if (winPtr->tagPtr != NULL) {  
         TkFreeBindingTags(winPtr);  
     }  
     TkOptionDeadWindow(winPtr);  
     TkSelDeadWindow(winPtr);  
     TkGrabDeadWindow(winPtr);  
     if (winPtr->mainPtr != NULL) {  
         if (winPtr->pathName != NULL) {  
             Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable,  
                     (ClientData) winPtr->pathName);  
             Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable,  
                     winPtr->pathName));  
         }  
         winPtr->mainPtr->refCount--;  
         if (winPtr->mainPtr->refCount == 0) {  
             register TkCmd *cmdPtr;  
   
             /*  
              * We just deleted the last window in the application.  Delete  
              * the TkMainInfo structure too and replace all of Tk's commands  
              * with dummy commands that return errors.  Also delete the  
              * "send" command to unregister the interpreter.  
              *  
              * NOTE: Only replace the commands it if the interpreter is  
              * not being deleted. If it *is*, the interpreter cleanup will  
              * do all the needed work.  
              */  
   
             if ((winPtr->mainPtr->interp != NULL) &&  
                     (!Tcl_InterpDeleted(winPtr->mainPtr->interp))) {  
                 for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {  
                     Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name,  
                             TkDeadAppCmd, (ClientData) NULL,  
                             (void (*) _ANSI_ARGS_((ClientData))) NULL);  
                 }  
                 Tcl_CreateCommand(winPtr->mainPtr->interp, "send",  
                         TkDeadAppCmd, (ClientData) NULL,  
                         (void (*) _ANSI_ARGS_((ClientData))) NULL);  
                 Tcl_UnlinkVar(winPtr->mainPtr->interp, "tk_strictMotif");  
             }  
                   
             Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable);  
             TkBindFree(winPtr->mainPtr);  
             TkDeleteAllImages(winPtr->mainPtr);  
             TkFontPkgFree(winPtr->mainPtr);  
   
             /*  
              * When embedding Tk into other applications, make sure  
              * that all destroy events reach the server. Otherwise  
              * the embedding application may also attempt to destroy  
              * the windows, resulting in an X error  
              */  
   
             if (winPtr->flags & TK_EMBEDDED) {  
                 XSync(winPtr->display,False) ;  
             }  
             ckfree((char *) winPtr->mainPtr);  
   
             /*  
              * If no other applications are using the display, close the  
              * display now and relinquish its data structures.  
              */  
               
             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.  
                  */  
                   
                 TkDisplay *theDispPtr, *backDispPtr;  
                   
                 /*  
                  * Splice this display out of the list of displays.  
                  */  
                   
                 for (theDispPtr = displayList, backDispPtr = NULL;  
                          (theDispPtr != winPtr->dispPtr) &&  
                              (theDispPtr != NULL);  
                          theDispPtr = theDispPtr->nextPtr) {  
                     backDispPtr = theDispPtr;  
                 }  
                 if (theDispPtr == NULL) {  
                     panic("could not find display to close!");  
                 }  
                 if (backDispPtr == NULL) {  
                     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);  
   
                 /*  
                  * There is lots more to clean up, we leave it at this for  
                  * the time being.  
                  */  
 #endif  
             }  
         }  
     }  
     ckfree((char *) winPtr);  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_MapWindow --  
  *  
  *      Map a window within its parent.  This may require the  
  *      window and/or its parents to actually be created.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The given window will be mapped.  Windows may also  
  *      be created.  
  *  
  *--------------------------------------------------------------  
  */  
   
 void  
 Tk_MapWindow(tkwin)  
     Tk_Window tkwin;            /* Token for window to map. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
     XEvent event;  
   
     if (winPtr->flags & TK_MAPPED) {  
         return;  
     }  
     if (winPtr->window == None) {  
         Tk_MakeWindowExist(tkwin);  
     }  
     if (winPtr->flags & TK_TOP_LEVEL) {  
         /*  
          * Lots of special processing has to be done for top-level  
          * windows.  Let tkWm.c handle everything itself.  
          */  
   
         TkWmMapWindow(winPtr);  
         return;  
     }  
     winPtr->flags |= TK_MAPPED;  
     XMapWindow(winPtr->display, winPtr->window);  
     event.type = MapNotify;  
     event.xmap.serial = LastKnownRequestProcessed(winPtr->display);  
     event.xmap.send_event = False;  
     event.xmap.display = winPtr->display;  
     event.xmap.event = winPtr->window;  
     event.xmap.window = winPtr->window;  
     event.xmap.override_redirect = winPtr->atts.override_redirect;  
     Tk_HandleEvent(&event);  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_MakeWindowExist --  
  *  
  *      Ensure that a particular window actually exists.  This  
  *      procedure shouldn't normally need to be invoked from  
  *      outside the Tk package, but may be needed if someone  
  *      wants to manipulate a window before mapping it.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      When the procedure returns, the X window associated with  
  *      tkwin is guaranteed to exist.  This may require the  
  *      window's ancestors to be created also.  
  *  
  *--------------------------------------------------------------  
  */  
   
 void  
 Tk_MakeWindowExist(tkwin)  
     Tk_Window tkwin;            /* Token for window. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
     TkWindow *winPtr2;  
     Window parent;  
     Tcl_HashEntry *hPtr;  
     int new;  
   
     if (winPtr->window != None) {  
         return;  
     }  
   
     if ((winPtr->parentPtr == NULL) || (winPtr->flags & TK_TOP_LEVEL)) {  
         parent = XRootWindow(winPtr->display, winPtr->screenNum);  
     } else {  
         if (winPtr->parentPtr->window == None) {  
             Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr);  
         }  
         parent = winPtr->parentPtr->window;  
     }  
   
     if (winPtr->classProcsPtr != NULL  
             && winPtr->classProcsPtr->createProc != NULL) {  
         winPtr->window = (*winPtr->classProcsPtr->createProc)(tkwin, parent,  
                 winPtr->instanceData);  
     } else {  
         winPtr->window = TkpMakeWindow(winPtr, parent);  
     }  
   
     hPtr = Tcl_CreateHashEntry(&winPtr->dispPtr->winTable,  
             (char *) winPtr->window, &new);  
     Tcl_SetHashValue(hPtr, winPtr);  
     winPtr->dirtyAtts = 0;  
     winPtr->dirtyChanges = 0;  
 #ifdef TK_USE_INPUT_METHODS  
     winPtr->inputContext = NULL;  
 #endif /* TK_USE_INPUT_METHODS */  
   
     if (!(winPtr->flags & TK_TOP_LEVEL)) {  
         /*  
          * If any siblings higher up in the stacking order have already  
          * been created then move this window to its rightful position  
          * in the stacking order.  
          *  
          * NOTE: this code ignores any changes anyone might have made  
          * to the sibling and stack_mode field of the window's attributes,  
          * so it really isn't safe for these to be manipulated except  
          * by calling Tk_RestackWindow.  
          */  
   
         for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL;  
                 winPtr2 = winPtr2->nextPtr) {  
             if ((winPtr2->window != None)  
                     && !(winPtr2->flags & (TK_TOP_LEVEL|TK_REPARENTED))) {  
                 XWindowChanges changes;  
                 changes.sibling = winPtr2->window;  
                 changes.stack_mode = Below;  
                 XConfigureWindow(winPtr->display, winPtr->window,  
                         CWSibling|CWStackMode, &changes);  
                 break;  
             }  
         }  
   
         /*  
          * If this window has a different colormap than its parent, add  
          * the window to the WM_COLORMAP_WINDOWS property for its top-level.  
          */  
   
         if ((winPtr->parentPtr != NULL) &&  
                 (winPtr->atts.colormap != winPtr->parentPtr->atts.colormap)) {  
             TkWmAddToColormapWindows(winPtr);  
             winPtr->flags |= TK_WM_COLORMAP_WINDOW;  
         }  
     }  
   
     /*  
      * Issue a ConfigureNotify event if there were deferred configuration  
      * changes (but skip it if the window is being deleted;  the  
      * ConfigureNotify event could cause problems if we're being called  
      * from Tk_DestroyWindow under some conditions).  
      */  
   
     if ((winPtr->flags & TK_NEED_CONFIG_NOTIFY)  
             && !(winPtr->flags & TK_ALREADY_DEAD)){  
         winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY;  
         TkDoConfigureNotify(winPtr);  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_UnmapWindow, etc. --  
  *  
  *      There are several procedures under here, each of which  
  *      mirrors an existing X procedure.  In addition to performing  
  *      the functions of the corresponding procedure, each  
  *      procedure also updates the local window structure and  
  *      synthesizes an X event (if the window's structure is being  
  *      managed internally).  
  *  
  * Results:  
  *      See the manual entries.  
  *  
  * Side effects:  
  *      See the manual entries.  
  *  
  *--------------------------------------------------------------  
  */  
   
 void  
 Tk_UnmapWindow(tkwin)  
     Tk_Window tkwin;            /* Token for window to unmap. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     if (!(winPtr->flags & TK_MAPPED) || (winPtr->flags & TK_ALREADY_DEAD)) {  
         return;  
     }  
     if (winPtr->flags & TK_TOP_LEVEL) {  
         /*  
          * Special processing has to be done for top-level windows.  Let  
          * tkWm.c handle everything itself.  
          */  
   
         TkWmUnmapWindow(winPtr);  
         return;  
     }  
     winPtr->flags &= ~TK_MAPPED;  
     XUnmapWindow(winPtr->display, winPtr->window);  
     if (!(winPtr->flags & TK_TOP_LEVEL)) {  
         XEvent event;  
   
         event.type = UnmapNotify;  
         event.xunmap.serial = LastKnownRequestProcessed(winPtr->display);  
         event.xunmap.send_event = False;  
         event.xunmap.display = winPtr->display;  
         event.xunmap.event = winPtr->window;  
         event.xunmap.window = winPtr->window;  
         event.xunmap.from_configure = False;  
         Tk_HandleEvent(&event);  
     }  
 }  
   
 void  
 Tk_ConfigureWindow(tkwin, valueMask, valuePtr)  
     Tk_Window tkwin;            /* Window to re-configure. */  
     unsigned int valueMask;     /* Mask indicating which parts of  
                                  * *valuePtr are to be used. */  
     XWindowChanges *valuePtr;   /* New values. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     if (valueMask & CWX) {  
         winPtr->changes.x = valuePtr->x;  
     }  
     if (valueMask & CWY) {  
         winPtr->changes.y = valuePtr->y;  
     }  
     if (valueMask & CWWidth) {  
         winPtr->changes.width = valuePtr->width;  
     }  
     if (valueMask & CWHeight) {  
         winPtr->changes.height = valuePtr->height;  
     }  
     if (valueMask & CWBorderWidth) {  
         winPtr->changes.border_width = valuePtr->border_width;  
     }  
     if (valueMask & (CWSibling|CWStackMode)) {  
         panic("Can't set sibling or stack mode from Tk_ConfigureWindow.");  
     }  
   
     if (winPtr->window != None) {  
         XConfigureWindow(winPtr->display, winPtr->window,  
                 valueMask, valuePtr);  
         TkDoConfigureNotify(winPtr);  
     } else {  
         winPtr->dirtyChanges |= valueMask;  
         winPtr->flags |= TK_NEED_CONFIG_NOTIFY;  
     }  
 }  
   
 void  
 Tk_MoveWindow(tkwin, x, y)  
     Tk_Window tkwin;            /* Window to move. */  
     int x, y;                   /* New location for window (within  
                                  * parent). */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->changes.x = x;  
     winPtr->changes.y = y;  
     if (winPtr->window != None) {  
         XMoveWindow(winPtr->display, winPtr->window, x, y);  
         TkDoConfigureNotify(winPtr);  
     } else {  
         winPtr->dirtyChanges |= CWX|CWY;  
         winPtr->flags |= TK_NEED_CONFIG_NOTIFY;  
     }  
 }  
   
 void  
 Tk_ResizeWindow(tkwin, width, height)  
     Tk_Window tkwin;            /* Window to resize. */  
     int width, height;          /* New dimensions for window. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->changes.width = (unsigned) width;  
     winPtr->changes.height = (unsigned) height;  
     if (winPtr->window != None) {  
         XResizeWindow(winPtr->display, winPtr->window, (unsigned) width,  
                 (unsigned) height);  
         TkDoConfigureNotify(winPtr);  
     } else {  
         winPtr->dirtyChanges |= CWWidth|CWHeight;  
         winPtr->flags |= TK_NEED_CONFIG_NOTIFY;  
     }  
 }  
   
 void  
 Tk_MoveResizeWindow(tkwin, x, y, width, height)  
     Tk_Window tkwin;            /* Window to move and resize. */  
     int x, y;                   /* New location for window (within  
                                  * parent). */  
     int width, height;          /* New dimensions for window. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->changes.x = x;  
     winPtr->changes.y = y;  
     winPtr->changes.width = (unsigned) width;  
     winPtr->changes.height = (unsigned) height;  
     if (winPtr->window != None) {  
         XMoveResizeWindow(winPtr->display, winPtr->window, x, y,  
                 (unsigned) width, (unsigned) height);  
         TkDoConfigureNotify(winPtr);  
     } else {  
         winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight;  
         winPtr->flags |= TK_NEED_CONFIG_NOTIFY;  
     }  
 }  
   
 void  
 Tk_SetWindowBorderWidth(tkwin, width)  
     Tk_Window tkwin;            /* Window to modify. */  
     int width;                  /* New border width for window. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->changes.border_width = width;  
     if (winPtr->window != None) {  
         XSetWindowBorderWidth(winPtr->display, winPtr->window,  
                 (unsigned) width);  
         TkDoConfigureNotify(winPtr);  
     } else {  
         winPtr->dirtyChanges |= CWBorderWidth;  
         winPtr->flags |= TK_NEED_CONFIG_NOTIFY;  
     }  
 }  
   
 void  
 Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr)  
     Tk_Window tkwin;            /* Window to manipulate. */  
     unsigned long valueMask;    /* OR'ed combination of bits,  
                                  * indicating which fields of  
                                  * *attsPtr are to be used. */  
     register XSetWindowAttributes *attsPtr;  
                                 /* New values for some attributes. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     if (valueMask & CWBackPixmap) {  
         winPtr->atts.background_pixmap = attsPtr->background_pixmap;  
     }  
     if (valueMask & CWBackPixel) {  
         winPtr->atts.background_pixel = attsPtr->background_pixel;  
     }  
     if (valueMask & CWBorderPixmap) {  
         winPtr->atts.border_pixmap = attsPtr->border_pixmap;  
     }  
     if (valueMask & CWBorderPixel) {  
         winPtr->atts.border_pixel = attsPtr->border_pixel;  
     }  
     if (valueMask & CWBitGravity) {  
         winPtr->atts.bit_gravity = attsPtr->bit_gravity;  
     }  
     if (valueMask & CWWinGravity) {  
         winPtr->atts.win_gravity = attsPtr->win_gravity;  
     }  
     if (valueMask & CWBackingStore) {  
         winPtr->atts.backing_store = attsPtr->backing_store;  
     }  
     if (valueMask & CWBackingPlanes) {  
         winPtr->atts.backing_planes = attsPtr->backing_planes;  
     }  
     if (valueMask & CWBackingPixel) {  
         winPtr->atts.backing_pixel = attsPtr->backing_pixel;  
     }  
     if (valueMask & CWOverrideRedirect) {  
         winPtr->atts.override_redirect = attsPtr->override_redirect;  
     }  
     if (valueMask & CWSaveUnder) {  
         winPtr->atts.save_under = attsPtr->save_under;  
     }  
     if (valueMask & CWEventMask) {  
         winPtr->atts.event_mask = attsPtr->event_mask;  
     }  
     if (valueMask & CWDontPropagate) {  
         winPtr->atts.do_not_propagate_mask  
                 = attsPtr->do_not_propagate_mask;  
     }  
     if (valueMask & CWColormap) {  
         winPtr->atts.colormap = attsPtr->colormap;  
     }  
     if (valueMask & CWCursor) {  
         winPtr->atts.cursor = attsPtr->cursor;  
     }  
   
     if (winPtr->window != None) {  
         XChangeWindowAttributes(winPtr->display, winPtr->window,  
                 valueMask, attsPtr);  
     } else {  
         winPtr->dirtyAtts |= valueMask;  
     }  
 }  
   
 void  
 Tk_SetWindowBackground(tkwin, pixel)  
     Tk_Window tkwin;            /* Window to manipulate. */  
     unsigned long pixel;        /* Pixel value to use for  
                                  * window's background. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->atts.background_pixel = pixel;  
   
     if (winPtr->window != None) {  
         XSetWindowBackground(winPtr->display, winPtr->window, pixel);  
     } else {  
         winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixmap)  
                 | CWBackPixel;  
     }  
 }  
   
 void  
 Tk_SetWindowBackgroundPixmap(tkwin, pixmap)  
     Tk_Window tkwin;            /* Window to manipulate. */  
     Pixmap pixmap;              /* Pixmap to use for window's  
                                  * background. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->atts.background_pixmap = pixmap;  
   
     if (winPtr->window != None) {  
         XSetWindowBackgroundPixmap(winPtr->display,  
                 winPtr->window, pixmap);  
     } else {  
         winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixel)  
                 | CWBackPixmap;  
     }  
 }  
   
 void  
 Tk_SetWindowBorder(tkwin, pixel)  
     Tk_Window tkwin;            /* Window to manipulate. */  
     unsigned long pixel;        /* Pixel value to use for  
                                  * window's border. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->atts.border_pixel = pixel;  
   
     if (winPtr->window != None) {  
         XSetWindowBorder(winPtr->display, winPtr->window, pixel);  
     } else {  
         winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixmap)  
                 | CWBorderPixel;  
     }  
 }  
   
 void  
 Tk_SetWindowBorderPixmap(tkwin, pixmap)  
     Tk_Window tkwin;            /* Window to manipulate. */  
     Pixmap pixmap;              /* Pixmap to use for window's  
                                  * border. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->atts.border_pixmap = pixmap;  
   
     if (winPtr->window != None) {  
         XSetWindowBorderPixmap(winPtr->display,  
                 winPtr->window, pixmap);  
     } else {  
         winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixel)  
                 | CWBorderPixmap;  
     }  
 }  
   
 void  
 Tk_DefineCursor(tkwin, cursor)  
     Tk_Window tkwin;            /* Window to manipulate. */  
     Tk_Cursor cursor;           /* Cursor to use for window (may be None). */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
 #ifdef MAC_TCL  
     winPtr->atts.cursor = (XCursor) cursor;  
 #else  
     winPtr->atts.cursor = (Cursor) cursor;  
 #endif  
       
     if (winPtr->window != None) {  
         XDefineCursor(winPtr->display, winPtr->window, winPtr->atts.cursor);  
     } else {  
         winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor;  
     }  
 }  
   
 void  
 Tk_UndefineCursor(tkwin)  
     Tk_Window tkwin;            /* Window to manipulate. */  
 {  
     Tk_DefineCursor(tkwin, None);  
 }  
   
 void  
 Tk_SetWindowColormap(tkwin, colormap)  
     Tk_Window tkwin;            /* Window to manipulate. */  
     Colormap colormap;          /* Colormap to use for window. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->atts.colormap = colormap;  
   
     if (winPtr->window != None) {  
         XSetWindowColormap(winPtr->display, winPtr->window, colormap);  
         if (!(winPtr->flags & TK_TOP_LEVEL)) {  
             TkWmAddToColormapWindows(winPtr);  
             winPtr->flags |= TK_WM_COLORMAP_WINDOW;  
         }  
     } else {  
         winPtr->dirtyAtts |= CWColormap;  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_SetWindowVisual --  
  *  
  *      This procedure is called to specify a visual to be used  
  *      for a Tk window when it is created.  This procedure, if  
  *      called at all, must be called before the X window is created  
  *      (i.e. before Tk_MakeWindowExist is called).  
  *  
  * Results:  
  *      The return value is 1 if successful, or 0 if the X window has  
  *      been already created.  
  *  
  * Side effects:  
  *      The information given is stored for when the window is created.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tk_SetWindowVisual(tkwin, visual, depth, colormap)  
     Tk_Window tkwin;            /* Window to manipulate. */  
     Visual *visual;             /* New visual for window. */  
     int depth;                  /* New depth for window. */  
     Colormap colormap;          /* An appropriate colormap for the visual. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     if( winPtr->window != None ){  
         /* Too late! */  
         return 0;  
     }  
   
     winPtr->visual = visual;  
     winPtr->depth = depth;  
     winPtr->atts.colormap = colormap;  
     winPtr->dirtyAtts |= CWColormap;  
   
     /*  
      * The following code is needed to make sure that the window doesn't  
      * inherit the parent's border pixmap, which would result in a BadMatch  
      * error.  
      */  
   
     if (!(winPtr->dirtyAtts & CWBorderPixmap)) {  
         winPtr->dirtyAtts |= CWBorderPixel;  
     }  
     return 1;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TkDoConfigureNotify --  
  *  
  *      Generate a ConfigureNotify event describing the current  
  *      configuration of a window.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      An event is generated and processed by Tk_HandleEvent.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 TkDoConfigureNotify(winPtr)  
     register TkWindow *winPtr;          /* Window whose configuration  
                                          * was just changed. */  
 {  
     XEvent event;  
   
     event.type = ConfigureNotify;  
     event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display);  
     event.xconfigure.send_event = False;  
     event.xconfigure.display = winPtr->display;  
     event.xconfigure.event = winPtr->window;  
     event.xconfigure.window = winPtr->window;  
     event.xconfigure.x = winPtr->changes.x;  
     event.xconfigure.y = winPtr->changes.y;  
     event.xconfigure.width = winPtr->changes.width;  
     event.xconfigure.height = winPtr->changes.height;  
     event.xconfigure.border_width = winPtr->changes.border_width;  
     if (winPtr->changes.stack_mode == Above) {  
         event.xconfigure.above = winPtr->changes.sibling;  
     } else {  
         event.xconfigure.above = None;  
     }  
     event.xconfigure.override_redirect = winPtr->atts.override_redirect;  
     Tk_HandleEvent(&event);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_SetClass --  
  *  
  *      This procedure is used to give a window a class.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      A new class is stored for tkwin, replacing any existing  
  *      class for it.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tk_SetClass(tkwin, className)  
     Tk_Window tkwin;            /* Token for window to assign class. */  
     char *className;            /* New class for tkwin. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->classUid = Tk_GetUid(className);  
     if (winPtr->flags & TK_TOP_LEVEL) {  
         TkWmSetClass(winPtr);  
     }  
     TkOptionClassChanged(winPtr);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TkSetClassProcs --  
  *  
  *      This procedure is used to set the class procedures and  
  *      instance data for a window.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      A new set of class procedures and instance data is stored  
  *      for tkwin, replacing any existing values.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 TkSetClassProcs(tkwin, procs, instanceData)  
     Tk_Window tkwin;            /* Token for window to modify. */  
     TkClassProcs *procs;        /* Class procs structure. */  
     ClientData instanceData;    /* Data to be passed to class procedures. */  
 {  
     register TkWindow *winPtr = (TkWindow *) tkwin;  
   
     winPtr->classProcsPtr = procs;  
     winPtr->instanceData = instanceData;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_NameToWindow --  
  *  
  *      Given a string name for a window, this procedure  
  *      returns the token for the window, if there exists a  
  *      window corresponding to the given name.  
  *  
  * Results:  
  *      The return result is either a token for the window corresponding  
  *      to "name", or else NULL to indicate that there is no such  
  *      window.  In this case, an error message is left in the interp's result.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tk_Window  
 Tk_NameToWindow(interp, pathName, tkwin)  
     Tcl_Interp *interp;         /* Where to report errors. */  
     char *pathName;             /* Path name of window. */  
     Tk_Window tkwin;            /* Token for window:  name is assumed to  
                                  * belong to the same main window as tkwin. */  
 {  
     Tcl_HashEntry *hPtr;  
   
     if (tkwin == NULL) {  
         /*  
          * Either we're not really in Tk, or the main window was destroyed and  
          * we're on our way out of the application  
          */  
         Tcl_AppendResult(interp, "NULL main window", (char *)NULL);  
         return NULL;  
     }  
       
     hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable,  
             pathName);  
     if (hPtr == NULL) {  
         Tcl_AppendResult(interp, "bad window path name \"",  
                 pathName, "\"", (char *) NULL);  
         return NULL;  
     }  
     return (Tk_Window) Tcl_GetHashValue(hPtr);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_IdToWindow --  
  *  
  *      Given an X display and window ID, this procedure returns the  
  *      Tk token for the window, if there exists a Tk window corresponding  
  *      to the given ID.  
  *  
  * Results:  
  *      The return result is either a token for the window corresponding  
  *      to the given X id, or else NULL to indicate that there is no such  
  *      window.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tk_Window  
 Tk_IdToWindow(display, window)  
     Display *display;           /* X display containing the window. */  
     Window window;              /* X window window id. */  
 {  
     TkDisplay *dispPtr;  
     Tcl_HashEntry *hPtr;  
   
     for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) {  
         if (dispPtr == NULL) {  
             return NULL;  
         }  
         if (dispPtr->display == display) {  
             break;  
         }  
     }  
   
     hPtr = Tcl_FindHashEntry(&dispPtr->winTable, (char *) window);  
     if (hPtr == NULL) {  
         return NULL;  
     }  
     return (Tk_Window) Tcl_GetHashValue(hPtr);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_DisplayName --  
  *  
  *      Return the textual name of a window's display.  
  *  
  * Results:  
  *      The return value is the string name of the display associated  
  *      with tkwin.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 char *  
 Tk_DisplayName(tkwin)  
     Tk_Window tkwin;            /* Window whose display name is desired. */  
 {  
     return ((TkWindow *) tkwin)->dispPtr->name;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * UnlinkWindow --  
  *  
  *      This procedure removes a window from the childList of its  
  *      parent.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The window is unlinked from its childList.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 UnlinkWindow(winPtr)  
     TkWindow *winPtr;                   /* Child window to be unlinked. */  
 {  
     TkWindow *prevPtr;  
   
     if (winPtr->parentPtr == NULL) {  
         return;  
     }  
     prevPtr = winPtr->parentPtr->childList;  
     if (prevPtr == winPtr) {  
         winPtr->parentPtr->childList = winPtr->nextPtr;  
         if (winPtr->nextPtr == NULL) {  
             winPtr->parentPtr->lastChildPtr = NULL;  
         }  
     } else {  
         while (prevPtr->nextPtr != winPtr) {  
             prevPtr = prevPtr->nextPtr;  
             if (prevPtr == NULL) {  
                 panic("UnlinkWindow couldn't find child in parent");  
             }  
         }  
         prevPtr->nextPtr = winPtr->nextPtr;  
         if (winPtr->nextPtr == NULL) {  
             winPtr->parentPtr->lastChildPtr = prevPtr;  
         }  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_RestackWindow --  
  *  
  *      Change a window's position in the stacking order.  
  *  
  * Results:  
  *      TCL_OK is normally returned.  If other is not a descendant  
  *      of tkwin's parent then TCL_ERROR is returned and tkwin is  
  *      not repositioned.  
  *  
  * Side effects:  
  *      Tkwin is repositioned in the stacking order.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tk_RestackWindow(tkwin, aboveBelow, other)  
     Tk_Window tkwin;            /* Token for window whose position in  
                                  * the stacking order is to change. */  
     int aboveBelow;             /* Indicates new position of tkwin relative  
                                  * to other;  must be Above or Below. */  
     Tk_Window other;            /* Tkwin will be moved to a position that  
                                  * puts it just above or below this window.  
                                  * If NULL then tkwin goes above or below  
                                  * all windows in the same parent. */  
 {  
     TkWindow *winPtr = (TkWindow *) tkwin;  
     TkWindow *otherPtr = (TkWindow *) other;  
   
     /*  
      * Special case:  if winPtr is a top-level window then just find  
      * the top-level ancestor of otherPtr and restack winPtr above  
      * otherPtr without changing any of Tk's childLists.  
      */  
   
     if (winPtr->flags & TK_TOP_LEVEL) {  
         while ((otherPtr != NULL) && !(otherPtr->flags & TK_TOP_LEVEL)) {  
             otherPtr = otherPtr->parentPtr;  
         }  
         TkWmRestackToplevel(winPtr, aboveBelow, otherPtr);  
         return TCL_OK;  
     }  
   
     /*  
      * Find an ancestor of otherPtr that is a sibling of winPtr.  
      */  
   
     if (winPtr->parentPtr == NULL) {  
         /*  
          * Window is going to be deleted shortly;  don't do anything.  
          */  
   
         return TCL_OK;  
     }  
     if (otherPtr == NULL) {  
         if (aboveBelow == Above) {  
             otherPtr = winPtr->parentPtr->lastChildPtr;  
         } else {  
             otherPtr = winPtr->parentPtr->childList;  
         }  
     } else {  
         while (winPtr->parentPtr != otherPtr->parentPtr) {  
             if ((otherPtr == NULL) || (otherPtr->flags & TK_TOP_LEVEL)) {  
                 return TCL_ERROR;  
             }  
             otherPtr = otherPtr->parentPtr;  
         }  
     }  
     if (otherPtr == winPtr) {  
         return TCL_OK;  
     }  
   
     /*  
      * Reposition winPtr in the stacking order.  
      */  
   
     UnlinkWindow(winPtr);  
     if (aboveBelow == Above) {  
         winPtr->nextPtr = otherPtr->nextPtr;  
         if (winPtr->nextPtr == NULL) {  
             winPtr->parentPtr->lastChildPtr = winPtr;  
         }  
         otherPtr->nextPtr = winPtr;  
     } else {  
         TkWindow *prevPtr;  
   
         prevPtr = winPtr->parentPtr->childList;  
         if (prevPtr == otherPtr) {  
             winPtr->parentPtr->childList = winPtr;  
         } else {  
             while (prevPtr->nextPtr != otherPtr) {  
                 prevPtr = prevPtr->nextPtr;  
             }  
             prevPtr->nextPtr = winPtr;  
         }  
         winPtr->nextPtr = otherPtr;  
     }  
   
     /*  
      * Notify the X server of the change.  If winPtr hasn't yet been  
      * created then there's no need to tell the X server now, since  
      * the stacking order will be handled properly when the window  
      * is finally created.  
      */  
   
     if (winPtr->window != None) {  
         XWindowChanges changes;  
         unsigned int mask;  
   
         mask = CWStackMode;  
         changes.stack_mode = Above;  
         for (otherPtr = winPtr->nextPtr; otherPtr != NULL;  
                 otherPtr = otherPtr->nextPtr) {  
             if ((otherPtr->window != None)  
                     && !(otherPtr->flags & (TK_TOP_LEVEL|TK_REPARENTED))){  
                 changes.sibling = otherPtr->window;  
                 changes.stack_mode = Below;  
                 mask = CWStackMode|CWSibling;  
                 break;  
             }  
         }  
         XConfigureWindow(winPtr->display, winPtr->window, mask, &changes);  
     }  
     return TCL_OK;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_MainWindow --  
  *  
  *      Returns the main window for an application.  
  *  
  * Results:  
  *      If interp has a Tk application associated with it, the main  
  *      window for the application is returned.  Otherwise NULL is  
  *      returned and an error message is left in the interp's result.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tk_Window  
 Tk_MainWindow(interp)  
     Tcl_Interp *interp;                 /* Interpreter that embodies the  
                                          * application.  Used for error  
                                          * reporting also. */  
 {  
     TkMainInfo *mainPtr;  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
   
     for (mainPtr = tsdPtr->mainWindowList; mainPtr != NULL;  
             mainPtr = mainPtr->nextPtr) {  
         if (mainPtr->interp == interp) {  
             return (Tk_Window) mainPtr->winPtr;  
         }  
     }  
     Tcl_SetResult(interp, "this isn't a Tk application", TCL_STATIC);  
     return NULL;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_StrictMotif --  
  *  
  *      Indicates whether strict Motif compliance has been specified  
  *      for the given window.  
  *  
  * Results:  
  *      The return value is 1 if strict Motif compliance has been  
  *      requested for tkwin's application by setting the tk_strictMotif  
  *      variable in its interpreter to a true value.  0 is returned  
  *      if tk_strictMotif has a false value.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tk_StrictMotif(tkwin)  
     Tk_Window tkwin;                    /* Window whose application is  
                                          * to be checked. */  
 {  
     return ((TkWindow *) tkwin)->mainPtr->strictMotif;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * OpenIM --  
  *  
  *      Tries to open an X input method, associated with the  
  *      given display.  Right now we can only deal with a bare-bones  
  *      input style:  no preedit, and no status.  
  *  
  * Results:  
  *      Stores the input method in dispPtr->inputMethod;  if there isn't  
  *      a suitable input method, then NULL is stored in dispPtr->inputMethod.  
  *  
  * Side effects:  
  *      An input method gets opened.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 OpenIM(dispPtr)  
     TkDisplay *dispPtr;         /* Tk's structure for the display. */  
 {  
 #ifndef TK_USE_INPUT_METHODS  
     return;  
 #else  
     unsigned short i;  
     XIMStyles *stylePtr;  
   
     dispPtr->inputMethod = XOpenIM(dispPtr->display, NULL, NULL, NULL);  
     if (dispPtr->inputMethod == NULL) {  
         return;  
     }  
   
     if ((XGetIMValues(dispPtr->inputMethod, XNQueryInputStyle, &stylePtr,  
             NULL) != NULL) || (stylePtr == NULL)) {  
         goto error;  
     }  
     for (i = 0; i < stylePtr->count_styles; i++) {  
         if (stylePtr->supported_styles[i]  
                 == (XIMPreeditNothing|XIMStatusNothing)) {  
             XFree(stylePtr);  
             return;  
         }  
     }  
     XFree(stylePtr);  
   
     error:  
   
     /*  
      * Should close the input method, but this causes core dumps on some  
      * systems (e.g. Solaris 2.3 as of 1/6/95).  
      * XCloseIM(dispPtr->inputMethod);  
      */  
     dispPtr->inputMethod = NULL;  
     return;  
 #endif /* TK_USE_INPUT_METHODS */  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_GetNumMainWindows --  
  *  
  *      This procedure returns the number of main windows currently  
  *      open in this process.  
  *  
  * Results:  
  *      The number of main windows open in this process.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tk_GetNumMainWindows()  
 {  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
   
     return tsdPtr->numMainWindows;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * DeleteWindowsExitProc --  
  *  
  *      This procedure is invoked as an exit handler.  It deletes all  
  *      of the main windows in the process.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 DeleteWindowsExitProc(clientData)  
     ClientData clientData;              /* Not used. */  
 {  
     TkDisplay *displayPtr, *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,  
          * because of <Destroy> bindings which could destroy the interpreter  
          * while the window is being deleted. This would leave frames on  
          * the call stack pointing at deleted memory, causing core dumps.  
          */  
           
         interp = tsdPtr->mainWindowList->winPtr->mainPtr->interp;  
         Tcl_Preserve((ClientData) interp);  
         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) {  
   
         /*  
          * 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  
          * any new displays got created during deletion of the current set.  
          * We must also do this to ensure that Tk_IdToWindow does not find  
          * 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);  
         }  
     }  
       
     tsdPtr->numMainWindows = 0;  
     tsdPtr->mainWindowList = NULL;  
     tsdPtr->initialized = 0;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_Init --  
  *  
  *      This procedure is invoked to add Tk to an interpreter.  It  
  *      incorporates all of Tk's commands into the interpreter and  
  *      creates the main window for a new Tk application.  If the  
  *      interpreter contains a variable "argv", this procedure  
  *      extracts several arguments from that variable, uses them  
  *      to configure the main window, and modifies argv to exclude  
  *      the arguments (see the "wish" documentation for a list of  
  *      the arguments that are extracted).  
  *  
  * Results:  
  *      Returns a standard Tcl completion code and sets the interp's result  
  *      if there is an error.  
  *  
  * Side effects:  
  *      Depends on various initialization scripts that get invoked.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tk_Init(interp)  
     Tcl_Interp *interp;         /* Interpreter to initialize. */  
 {  
     return Initialize(interp);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_SafeInit --  
  *  
  *      This procedure is invoked to add Tk to a safe interpreter. It  
  *      invokes the internal procedure that does the real work.  
  *  
  * Results:  
  *      Returns a standard Tcl completion code and sets the interp's result  
  *      if there is an error.  
  *  
  * Side effects:  
  *      Depends on various initialization scripts that are invoked.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 Tk_SafeInit(interp)  
     Tcl_Interp *interp;         /* Interpreter to initialize. */  
 {  
     /*  
      * Initialize the interpreter with Tk, safely. This removes  
      * all the Tk commands that are unsafe.  
      *  
      * Rationale:  
      *  
      * - Toplevel and menu are unsafe because they can be used to cover  
      *   the entire screen and to steal input from the user.  
      * - Continuous ringing of the bell is a nuisance.  
      * - Cannot allow access to the clipboard because a malicious script  
      *   can replace the contents with the string "rm -r *" and lead to  
      *   surprises when the contents of the clipboard are pasted. We do  
      *   not currently hide the selection command.. Should we?  
      * - Cannot allow send because it can be used to cause unsafe  
      *   interpreters to execute commands. The tk command recreates the  
      *   send command, so that too must be hidden.  
      * - Focus can be used to grab the focus away from another window,  
      *   in effect stealing user input. Cannot allow that.  
      *   NOTE: We currently do *not* hide focus as it would make it  
      *   impossible to provide keyboard input to Tk in a safe interpreter.  
      * - Grab can be used to block the user from using any other apps  
      *   on the screen.  
      * - Tkwait can block the containing process forever. Use bindings,  
      *   fileevents and split the protocol into before-the-wait and  
      *   after-the-wait parts. More work but necessary.  
      * - Wm is unsafe because (if toplevels are allowed, in the future)  
      *   it can be used to remove decorations, move windows around, cover  
      *   the entire screen etc etc.  
      *  
      * Current risks:  
      *  
      * - No CPU time limit, no memory allocation limits, no color limits.  
      *  
      *  The actual code called is the same as Tk_Init but Tcl_IsSafe()  
      *  is checked at several places to differentiate the two initialisations.  
      */  
   
     return Initialize(interp);  
 }  
   
   
 extern TkStubs tkStubs;  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Initialize --  
  *  
  *  
  * Results:  
  *      A standard Tcl result. Also leaves an error message in the interp's  
  *      result if there was an error.  
  *  
  * Side effects:  
  *      Depends on the initialization scripts that are invoked.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 Initialize(interp)  
     Tcl_Interp *interp;         /* Interpreter to initialize. */  
 {  
     char *p;  
     int argc, code;  
     char **argv, *args[20];  
     Tcl_DString class;  
     ThreadSpecificData *tsdPtr;  
       
     /*  
      * Ensure that we are getting the matching version of Tcl.  This is  
      * really only an issue when Tk is loaded dynamically.  
      */  
   
     if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) {  
         return TCL_ERROR;  
     }  
   
     tsdPtr = (ThreadSpecificData *)  
         Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
   
     /*  
      * Start by initializing all the static variables to default acceptable  
      * values so that no information is leaked from a previous run of this  
      * code.  
      */  
   
     Tcl_MutexLock(&windowMutex);  
     synchronize = 0;  
     name = NULL;  
     display = NULL;  
     geometry = NULL;  
     colormap = NULL;  
     use = NULL;  
     visual = NULL;  
     rest = 0;  
   
     /*  
      * We start by resetting the result because it might not be clean  
      */  
     Tcl_ResetResult(interp);  
   
     if (Tcl_IsSafe(interp)) {  
         /*  
          * Get the clearance to start Tk and the "argv" parameters  
          * from the master.  
          */  
         Tcl_DString ds;  
           
         /*  
          * Step 1 : find the master and construct the interp name  
          * (could be a function if new APIs were ok).  
          * We could also construct the path while walking, but there  
          * is no API to get the name of an interp either.  
          */  
         Tcl_Interp *master = interp;  
   
         while (1) {  
             master = Tcl_GetMaster(master);  
             if (master == NULL) {  
                 Tcl_DStringFree(&ds);  
                 Tcl_AppendResult(interp, "NULL master", (char *) NULL);  
                 Tcl_MutexUnlock(&windowMutex);  
                 return TCL_ERROR;  
             }  
             if (!Tcl_IsSafe(master)) {  
                 /* Found the trusted master. */  
                 break;  
             }  
         }  
         /*  
          * Construct the name (rewalk...)  
          */  
         if (Tcl_GetInterpPath(master, interp) != TCL_OK) {  
             Tcl_AppendResult(interp, "error in Tcl_GetInterpPath",  
                     (char *) NULL);  
             Tcl_MutexUnlock(&windowMutex);  
             return TCL_ERROR;  
         }  
         /*  
          * Build the string to eval.  
          */  
         Tcl_DStringInit(&ds);  
         Tcl_DStringAppendElement(&ds, "::safe::TkInit");  
         Tcl_DStringAppendElement(&ds, Tcl_GetStringResult(master));  
           
         /*  
          * Step 2 : Eval in the master. The argument is the *reversed*  
          * interp path of the slave.  
          */  
           
         if (Tcl_Eval(master, Tcl_DStringValue(&ds)) != TCL_OK) {  
             /*  
              * We might want to transfer the error message or not.  
              * We don't. (no API to do it and maybe security reasons).  
              */  
             Tcl_DStringFree(&ds);  
             Tcl_AppendResult(interp,  
                     "not allowed to start Tk by master's safe::TkInit",  
                     (char *) NULL);  
             Tcl_MutexUnlock(&windowMutex);  
             return TCL_ERROR;  
         }  
         Tcl_DStringFree(&ds);  
         /*  
          * Use the master's result as argv.  
          * Note: We don't use the Obj interfaces to avoid dealing with  
          * cross interp refcounting and changing the code below.  
          */  
   
         p = Tcl_GetStringResult(master);  
     } else {  
         /*  
          * If there is an "argv" variable, get its value, extract out  
          * relevant arguments from it, and rewrite the variable without  
          * the arguments that we used.  
          */  
   
         p = Tcl_GetVar2(interp, "argv", (char *) NULL, TCL_GLOBAL_ONLY);  
     }  
     argv = NULL;  
     if (p != NULL) {  
         char buffer[TCL_INTEGER_SPACE];  
   
         if (Tcl_SplitList(interp, p, &argc, &argv) != TCL_OK) {  
             argError:  
             Tcl_AddErrorInfo(interp,  
                     "\n    (processing arguments in argv variable)");  
             Tcl_MutexUnlock(&windowMutex);  
             return TCL_ERROR;  
         }  
         if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv,  
                 argTable, TK_ARGV_DONT_SKIP_FIRST_ARG|TK_ARGV_NO_DEFAULTS)  
                 != TCL_OK) {  
             ckfree((char *) argv);  
             goto argError;  
         }  
         p = Tcl_Merge(argc, argv);  
         Tcl_SetVar2(interp, "argv", (char *) NULL, p, TCL_GLOBAL_ONLY);  
         sprintf(buffer, "%d", argc);  
         Tcl_SetVar2(interp, "argc", (char *) NULL, buffer, TCL_GLOBAL_ONLY);  
         ckfree(p);  
     }  
   
     /*  
      * Figure out the application's name and class.  
      */  
   
     Tcl_DStringInit(&class);  
     if (name == NULL) {  
         int offset;  
         TkpGetAppName(interp, &class);  
         offset = Tcl_DStringLength(&class)+1;  
         Tcl_DStringSetLength(&class, offset);  
         Tcl_DStringAppend(&class, Tcl_DStringValue(&class), offset-1);  
         name = Tcl_DStringValue(&class) + offset;  
     } else {  
         Tcl_DStringAppend(&class, name, -1);  
     }  
   
     p = Tcl_DStringValue(&class);  
     if (*p) {  
         Tcl_UtfToTitle(p);  
     }  
   
     /*  
      * Create an argument list for creating the top-level window,  
      * using the information parsed from argv, if any.  
      */  
   
     args[0] = "toplevel";  
     args[1] = ".";  
     args[2] = "-class";  
     args[3] = Tcl_DStringValue(&class);  
     argc = 4;  
     if (display != NULL) {  
         args[argc] = "-screen";  
         args[argc+1] = display;  
         argc += 2;  
   
         /*  
          * If this is the first application for this process, save  
          * the display name in the DISPLAY environment variable so  
          * that it will be available to subprocesses created by us.  
          */  
   
         if (tsdPtr->numMainWindows == 0) {  
             Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY);  
         }  
     }  
     if (colormap != NULL) {  
         args[argc] = "-colormap";  
         args[argc+1] = colormap;  
         argc += 2;  
         colormap = NULL;  
     }  
     if (use != NULL) {  
         args[argc] = "-use";  
         args[argc+1] = use;  
         argc += 2;  
         use = NULL;  
     }  
     if (visual != NULL) {  
         args[argc] = "-visual";  
         args[argc+1] = visual;  
         argc += 2;  
         visual = NULL;  
     }  
     args[argc] = NULL;  
     code = TkCreateFrame((ClientData) NULL, interp, argc, args, 1, name);  
   
     Tcl_DStringFree(&class);  
     if (code != TCL_OK) {  
         goto done;  
     }  
     Tcl_ResetResult(interp);  
     if (synchronize) {  
         XSynchronize(Tk_Display(Tk_MainWindow(interp)), True);  
     }  
   
     /*  
      * Set the geometry of the main window, if requested.  Put the  
      * requested geometry into the "geometry" variable.  
      */  
   
     if (geometry != NULL) {  
         Tcl_SetVar(interp, "geometry", geometry, TCL_GLOBAL_ONLY);  
         code = Tcl_VarEval(interp, "wm geometry . ", geometry, (char *) NULL);  
         if (code != TCL_OK) {  
             goto done;  
         }  
         geometry = NULL;  
     }  
     Tcl_MutexUnlock(&windowMutex);  
   
     if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {  
         code = TCL_ERROR;  
         goto done;  
     }  
   
     /*  
      * Provide Tk and its stub table.  
      */  
   
     code = Tcl_PkgProvideEx(interp, "Tk", TK_VERSION, (ClientData) &tkStubs);  
     if (code != TCL_OK) {  
         goto done;  
     }  
   
 #ifdef Tk_InitStubs  
 #undef Tk_InitStubs  
 #endif  
   
     Tk_InitStubs(interp, TK_VERSION, 1);  
   
     /*  
      * Invoke platform-specific initialization.  
      */  
   
     code = TkpInit(interp);  
   
     done:  
     if (argv != NULL) {  
         ckfree((char *) argv);  
     }  
     return code;  
 }  
   
   
 /* $History: tkWindow.c $  
  *  
  * *****************  Version 1  *****************  
  * User: Dtashley     Date: 1/02/01    Time: 3:16a  
  * Created in $/IjuScripter, IjuConsole/Source/Tk Base  
  * Initial check-in.  
  */  
   
 /* End of TKWINDOW.C */  
1    /* $Header$ */
2    
3    /*
4     * tkWindow.c --
5     *
6     *      This file provides basic window-manipulation procedures,
7     *      which are equivalent to procedures in Xlib (and even
8     *      invoke them) but also maintain the local Tk_Window
9     *      structure.
10     *
11     * Copyright (c) 1989-1994 The Regents of the University of California.
12     * Copyright (c) 1994-1997 Sun Microsystems, Inc.
13     *
14     * See the file "license.terms" for information on usage and redistribution
15     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16     *
17     * RCS: @(#) $Id: tkwindow.c,v 1.1.1.1 2001/06/13 05:12:54 dtashley Exp $
18     */
19    
20    #include "tkPort.h"
21    #include "tkInt.h"
22    
23    #if !defined(__WIN32__) && !defined(MAC_TCL)
24    #include "tkUnixInt.h"
25    #endif
26    
27    
28    typedef struct ThreadSpecificData {
29        int numMainWindows;    /* Count of numver of main windows currently
30                                * open in this thread. */
31        TkMainInfo *mainWindowList;
32                               /* First in list of all main windows managed
33                                * by this thread. */
34        TkDisplay *displayList;
35                               /* List of all displays currently in use by
36                                * the current thread. */
37        int initialized;       /* 0 means the structures above need
38                                * initializing. */
39    } ThreadSpecificData;
40    static Tcl_ThreadDataKey dataKey;
41    
42    /*
43     * The Mutex below is used to lock access to the Tk_Uid structs above.
44     */
45    
46    TCL_DECLARE_MUTEX(windowMutex)
47    
48    /*
49     * Default values for "changes" and "atts" fields of TkWindows.  Note
50     * that Tk always requests all events for all windows, except StructureNotify
51     * events on internal windows:  these events are generated internally.
52     */
53    
54    static XWindowChanges defChanges = {
55        0, 0, 1, 1, 0, 0, Above
56    };
57    #define ALL_EVENTS_MASK \
58        KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
59        EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
60        VisibilityChangeMask|PropertyChangeMask|ColormapChangeMask
61    static XSetWindowAttributes defAtts= {
62        None,                       /* background_pixmap */
63        0,                          /* background_pixel */
64        CopyFromParent,             /* border_pixmap */
65        0,                          /* border_pixel */
66        NorthWestGravity,           /* bit_gravity */
67        NorthWestGravity,           /* win_gravity */
68        NotUseful,                  /* backing_store */
69        (unsigned) ~0,              /* backing_planes */
70        0,                          /* backing_pixel */
71        False,                      /* save_under */
72        ALL_EVENTS_MASK,            /* event_mask */
73        0,                          /* do_not_propagate_mask */
74        False,                      /* override_redirect */
75        CopyFromParent,             /* colormap */
76        None                        /* cursor */
77    };
78    
79    /*
80     * The following structure defines all of the commands supported by
81     * Tk, and the C procedures that execute them.
82     */
83    
84    typedef struct {
85        char *name;                 /* Name of command. */
86        Tcl_CmdProc *cmdProc;       /* Command's string-based procedure. */
87        Tcl_ObjCmdProc *objProc;    /* Command's object-based procedure. */
88        int isSafe;                 /* If !0, this command will be exposed in
89                                     * a safe interpreter. Otherwise it will be
90                                     * hidden in a safe interpreter. */
91        int passMainWindow;         /* 0 means provide NULL clientData to
92                                     * command procedure; 1 means pass main
93                                     * window as clientData to command
94                                     * procedure. */
95    } TkCmd;
96    
97    static TkCmd commands[] = {
98        /*
99         * Commands that are part of the intrinsics:
100         */
101    
102        {"bell",            NULL,                   Tk_BellObjCmd,          0, 1},
103        {"bind",            Tk_BindCmd,             NULL,                   1, 1},
104        {"bindtags",        Tk_BindtagsCmd,         NULL,                   1, 1},
105        {"clipboard",       Tk_ClipboardCmd,        NULL,                   0, 1},
106        {"destroy",         NULL,                   Tk_DestroyObjCmd,       1, 1},
107        {"event",           NULL,                   Tk_EventObjCmd,         1, 1},
108        {"focus",           NULL,                   Tk_FocusObjCmd,         1, 1},
109        {"font",            NULL,                   Tk_FontObjCmd,          1, 1},
110        {"grab",            Tk_GrabCmd,             NULL,                   0, 1},
111        {"grid",            Tk_GridCmd,             NULL,                   1, 1},
112        {"image",           NULL,                   Tk_ImageObjCmd,         1, 1},
113        {"lower",           NULL,                   Tk_LowerObjCmd,         1, 1},
114        {"option",          NULL,                   Tk_OptionObjCmd,        1, 1},
115        {"pack",            Tk_PackCmd,             NULL,                   1, 1},
116        {"place",           Tk_PlaceCmd,            NULL,                   1, 1},
117        {"raise",           NULL,                   Tk_RaiseObjCmd,         1, 1},
118        {"selection",       Tk_SelectionCmd,        NULL,                   0, 1},
119        {"tk",              NULL,                   Tk_TkObjCmd,            0, 1},
120        {"tkwait",          Tk_TkwaitCmd,           NULL,                   1, 1},
121    #if defined(__WIN32__) || defined(MAC_TCL)
122        {"tk_chooseColor",  NULL,                   Tk_ChooseColorObjCmd,   0, 1},
123        {"tk_chooseDirectory", NULL,                Tk_ChooseDirectoryObjCmd, 0, 1},
124        {"tk_getOpenFile",  NULL,                   Tk_GetOpenFileObjCmd,   0, 1},
125        {"tk_getSaveFile",  NULL,                   Tk_GetSaveFileObjCmd,   0, 1},
126    #endif
127    #ifdef __WIN32__
128        {"tk_messageBox",   NULL,                   Tk_MessageBoxObjCmd,    0, 1},
129    #endif
130        {"update",          NULL,                   Tk_UpdateObjCmd,        1, 1},
131        {"winfo",           NULL,                   Tk_WinfoObjCmd,         1, 1},
132        {"wm",              Tk_WmCmd,               NULL,                   0, 1},
133    
134        /*
135         * Widget class commands.
136         */
137    
138        {"button",          NULL,                   Tk_ButtonObjCmd,        1, 0},
139        {"canvas",          NULL,                   Tk_CanvasObjCmd,        1, 1},
140        {"checkbutton",     NULL,                   Tk_CheckbuttonObjCmd,   1, 0},
141        {"entry",           NULL,                   Tk_EntryObjCmd,         1, 0},
142        {"frame",           NULL,                   Tk_FrameObjCmd,         1, 1},
143        {"label",           NULL,                   Tk_LabelObjCmd,         1, 0},
144        {"listbox",         NULL,                   Tk_ListboxObjCmd,       1, 0},
145        {"menubutton",      NULL,                   Tk_MenubuttonObjCmd,    1, 0},
146        {"message",         Tk_MessageCmd,          NULL,                   1, 1},
147        {"radiobutton",     NULL,                   Tk_RadiobuttonObjCmd,   1, 0},
148        {"scale",           NULL,                   Tk_ScaleObjCmd,         1, 0},
149        {"scrollbar",       Tk_ScrollbarCmd,        NULL,                   1, 1},
150        {"text",            Tk_TextCmd,             NULL,                   1, 1},
151        {"toplevel",        NULL,                   Tk_ToplevelObjCmd,      0, 1},
152    
153        /*
154         * Misc.
155         */
156    
157    #ifdef MAC_TCL
158        {"unsupported1",    TkUnsupported1Cmd,      NULL,                   1, 1},
159    #endif
160        {(char *) NULL,     (int (*) _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **))) NULL, NULL, 0}
161    };
162    
163    /*
164     * The variables and table below are used to parse arguments from
165     * the "argv" variable in Tk_Init.
166     */
167    
168    static int synchronize = 0;
169    static char *name = NULL;
170    static char *display = NULL;
171    static char *geometry = NULL;
172    static char *colormap = NULL;
173    static char *use = NULL;
174    static char *visual = NULL;
175    static int rest = 0;
176    
177    static Tk_ArgvInfo argTable[] = {
178        {"-colormap", TK_ARGV_STRING, (char *) NULL, (char *) &colormap,
179            "Colormap for main window"},
180        {"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,
181            "Display to use"},
182        {"-geometry", TK_ARGV_STRING, (char *) NULL, (char *) &geometry,
183            "Initial geometry for window"},
184        {"-name", TK_ARGV_STRING, (char *) NULL, (char *) &name,
185            "Name to use for application"},
186        {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,
187            "Use synchronous mode for display server"},
188        {"-visual", TK_ARGV_STRING, (char *) NULL, (char *) &visual,
189            "Visual for main window"},
190        {"-use", TK_ARGV_STRING, (char *) NULL, (char *) &use,
191            "Id of window in which to embed application"},
192        {"--", TK_ARGV_REST, (char *) 1, (char *) &rest,
193            "Pass all remaining arguments through to script"},
194        {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
195            (char *) NULL}
196    };
197    
198    /*
199     * Forward declarations to procedures defined later in this file:
200     */
201    
202    static Tk_Window        CreateTopLevelWindow _ANSI_ARGS_((Tcl_Interp *interp,
203                                Tk_Window parent, char *name, char *screenName));
204    static void             DeleteWindowsExitProc _ANSI_ARGS_((
205                                ClientData clientData));
206    static TkDisplay *      GetScreen _ANSI_ARGS_((Tcl_Interp *interp,
207                                char *screenName, int *screenPtr));
208    static int              Initialize _ANSI_ARGS_((Tcl_Interp *interp));
209    static int              NameWindow _ANSI_ARGS_((Tcl_Interp *interp,
210                                TkWindow *winPtr, TkWindow *parentPtr,
211                                char *name));
212    static void             OpenIM _ANSI_ARGS_((TkDisplay *dispPtr));
213    static void             UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr));
214    
215    /*
216     *----------------------------------------------------------------------
217     *
218     * CreateTopLevelWindow --
219     *
220     *      Make a new window that will be at top-level (its parent will
221     *      be the root window of a screen).
222     *
223     * Results:
224     *      The return value is a token for the new window, or NULL if
225     *      an error prevented the new window from being created.  If
226     *      NULL is returned, an error message will be left in
227     *      the interp's result.
228     *
229     * Side effects:
230     *      A new window structure is allocated locally.  An X
231     *      window is NOT initially created, but will be created
232     *      the first time the window is mapped.
233     *
234     *----------------------------------------------------------------------
235     */
236    
237    static Tk_Window
238    CreateTopLevelWindow(interp, parent, name, screenName)
239        Tcl_Interp *interp;         /* Interpreter to use for error reporting. */
240        Tk_Window parent;           /* Token for logical parent of new window
241                                     * (used for naming, options, etc.).  May
242                                     * be NULL. */
243        char *name;                 /* Name for new window;  if parent is
244                                     * non-NULL, must be unique among parent's
245                                     * children. */
246        char *screenName;           /* Name of screen on which to create
247                                     * window.  NULL means use DISPLAY environment
248                                     * variable to determine.  Empty string means
249                                     * use parent's screen, or DISPLAY if no
250                                     * parent. */
251    {
252        register TkWindow *winPtr;
253        register TkDisplay *dispPtr;
254        int screenId;
255        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
256                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
257    
258        if (!tsdPtr->initialized) {
259            tsdPtr->initialized = 1;
260    
261            /*
262             * Create built-in image types.
263             */
264        
265            Tk_CreateImageType(&tkBitmapImageType);
266            Tk_CreateImageType(&tkPhotoImageType);
267        
268            /*
269             * Create built-in photo image formats.
270             */
271        
272            Tk_CreatePhotoImageFormat(&tkImgFmtGIF);
273            Tk_CreateOldPhotoImageFormat(&tkImgFmtPPM);
274    
275            /*
276             * Create exit handler to delete all windows when the application
277             * exits.
278             */
279    
280            Tcl_CreateExitHandler(DeleteWindowsExitProc, (ClientData) NULL);
281        }
282    
283        if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
284            dispPtr = ((TkWindow *) parent)->dispPtr;
285            screenId = Tk_ScreenNumber(parent);
286        } else {
287            dispPtr = GetScreen(interp, screenName, &screenId);
288            if (dispPtr == NULL) {
289                return (Tk_Window) NULL;
290            }
291        }
292    
293        winPtr = TkAllocWindow(dispPtr, screenId, (TkWindow *) parent);
294    
295        /*
296         * Force the window to use a border pixel instead of border pixmap.
297         * This is needed for the case where the window doesn't use the
298         * default visual.  In this case, the default border is a pixmap
299         * inherited from the root window, which won't work because it will
300         * have the wrong visual.
301         */
302    
303        winPtr->dirtyAtts |= CWBorderPixel;
304    
305        /*
306         * (Need to set the TK_TOP_LEVEL flag immediately here;  otherwise
307         * Tk_DestroyWindow will core dump if it is called before the flag
308         * has been set.)
309         */
310    
311        winPtr->flags |= TK_TOP_LEVEL;
312    
313        if (parent != NULL) {
314            if (NameWindow(interp, winPtr, (TkWindow *) parent, name) != TCL_OK) {
315                Tk_DestroyWindow((Tk_Window) winPtr);
316                return (Tk_Window) NULL;
317            }
318        }
319        TkWmNewWindow(winPtr);
320    
321        return (Tk_Window) winPtr;
322    }
323    
324    /*
325     *----------------------------------------------------------------------
326     *
327     * GetScreen --
328     *
329     *      Given a string name for a display-plus-screen, find the
330     *      TkDisplay structure for the display and return the screen
331     *      number too.
332     *
333     * Results:
334     *      The return value is a pointer to information about the display,
335     *      or NULL if the display couldn't be opened.  In this case, an
336     *      error message is left in the interp's result.  The location at
337     *      *screenPtr is overwritten with the screen number parsed from
338     *      screenName.
339     *
340     * Side effects:
341     *      A new connection is opened to the display if there is no
342     *      connection already.  A new TkDisplay data structure is also
343     *      setup, if necessary.
344     *
345     *----------------------------------------------------------------------
346     */
347    
348    static TkDisplay *
349    GetScreen(interp, screenName, screenPtr)
350        Tcl_Interp *interp;         /* Place to leave error message. */
351        char *screenName;           /* Name for screen.  NULL or empty means
352                                     * use DISPLAY envariable. */
353        int *screenPtr;             /* Where to store screen number. */
354    {
355        register TkDisplay *dispPtr;
356        char *p;
357        int screenId;
358        size_t length;
359        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
360                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
361    
362        /*
363         * Separate the screen number from the rest of the display
364         * name.  ScreenName is assumed to have the syntax
365         * <display>.<screen> with the dot and the screen being
366         * optional.
367         */
368    
369        screenName = TkGetDefaultScreenName(interp, screenName);
370        if (screenName == NULL) {
371            Tcl_SetResult(interp,
372                    "no display name and no $DISPLAY environment variable",
373                    TCL_STATIC);
374            return (TkDisplay *) NULL;
375        }
376        length = strlen(screenName);
377        screenId = 0;
378        p = screenName+length-1;
379        while (isdigit(UCHAR(*p)) && (p != screenName)) {
380            p--;
381        }
382        if ((*p == '.') && (p[1] != '\0')) {
383            length = p - screenName;
384            screenId = strtoul(p+1, (char **) NULL, 10);
385        }
386    
387        /*
388         * See if we already have a connection to this display.  If not,
389         * then open a new connection.
390         */
391    
392        for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) {
393            if (dispPtr == NULL) {
394                dispPtr = TkpOpenDisplay(screenName);
395                if (dispPtr == NULL) {
396                    Tcl_AppendResult(interp, "couldn't connect to display \"",
397                            screenName, "\"", (char *) NULL);
398                    return (TkDisplay *) NULL;
399                }
400                dispPtr->nextPtr = TkGetDisplayList();
401                dispPtr->name = (char *) ckalloc((unsigned) (length+1));
402                dispPtr->lastEventTime = CurrentTime;
403                dispPtr->borderInit = 0;
404                dispPtr->atomInit = 0;
405                dispPtr->bindInfoStale = 1;
406                dispPtr->modeModMask = 0;
407                dispPtr->metaModMask = 0;
408                dispPtr->altModMask = 0;
409                dispPtr->numModKeyCodes = 0;
410                dispPtr->modKeyCodes = NULL;
411                dispPtr->bitmapInit = 0;
412                dispPtr->bitmapAutoNumber = 0;
413                dispPtr->numIdSearches = 0;
414                dispPtr->numSlowSearches = 0;
415                dispPtr->colorInit = 0;
416                dispPtr->stressPtr = NULL;
417                dispPtr->cursorInit = 0;
418                dispPtr->cursorString[0] = '\0';
419                dispPtr->cursorFont = None;
420                dispPtr->errorPtr = NULL;
421                dispPtr->deleteCount = 0;
422                dispPtr->delayedMotionPtr = NULL;
423                dispPtr->focusDebug = 0;
424                dispPtr->implicitWinPtr = NULL;
425                dispPtr->focusPtr = NULL;
426                dispPtr->gcInit = 0;
427                dispPtr->geomInit = 0;
428                dispPtr->uidInit = 0;
429                dispPtr->grabWinPtr = NULL;
430                dispPtr->eventualGrabWinPtr = NULL;
431                dispPtr->buttonWinPtr = NULL;
432                dispPtr->serverWinPtr = NULL;
433                dispPtr->firstGrabEventPtr = NULL;
434                dispPtr->lastGrabEventPtr = NULL;
435                dispPtr->grabFlags = 0;
436                dispPtr->mouseButtonState = 0;
437                dispPtr->warpInProgress = 0;
438                dispPtr->warpWindow = None;
439                dispPtr->warpX = 0;
440                dispPtr->warpY = 0;
441                dispPtr->gridInit = 0;
442                dispPtr->imageId = 0;
443                dispPtr->packInit = 0;
444                dispPtr->placeInit = 0;
445                dispPtr->selectionInfoPtr = NULL;
446                dispPtr->multipleAtom = None;
447                dispPtr->clipWindow = NULL;
448                dispPtr->clipboardActive = 0;
449                dispPtr->clipboardAppPtr = NULL;
450                dispPtr->clipTargetPtr = NULL;
451                dispPtr->commTkwin = NULL;
452                dispPtr->wmTracing = 0;
453                dispPtr->firstWmPtr = NULL;
454                dispPtr->foregroundWmPtr = NULL;
455                dispPtr->destroyCount = 0;
456                dispPtr->lastDestroyRequest = 0;
457                dispPtr->cmapPtr = NULL;
458                Tcl_InitHashTable(&dispPtr->winTable, TCL_ONE_WORD_KEYS);
459    
460                dispPtr->refCount = 0;
461                strncpy(dispPtr->name, screenName, length);
462                dispPtr->name[length] = '\0';
463                dispPtr->useInputMethods = 0;
464                OpenIM(dispPtr);
465                TkInitXId(dispPtr);
466    
467                tsdPtr->displayList = dispPtr;
468                break;
469            }
470            if ((strncmp(dispPtr->name, screenName, length) == 0)
471                    && (dispPtr->name[length] == '\0')) {
472                break;
473            }
474        }
475        if (screenId >= ScreenCount(dispPtr->display)) {
476            char buf[32 + TCL_INTEGER_SPACE];
477            
478            sprintf(buf, "bad screen number \"%d\"", screenId);
479            Tcl_SetResult(interp, buf, TCL_VOLATILE);
480            return (TkDisplay *) NULL;
481        }
482        *screenPtr = screenId;
483        return dispPtr;
484    }
485    
486    /*
487     *----------------------------------------------------------------------
488     *
489     * TkGetDisplay --
490     *
491     *      Given an X display, TkGetDisplay returns the TkDisplay
492     *      structure for the display.
493     *
494     * Results:
495     *      The return value is a pointer to information about the display,
496     *      or NULL if the display did not have a TkDisplay structure.
497     *
498     * Side effects:
499     *      None.
500     *
501     *----------------------------------------------------------------------
502     */
503    
504    TkDisplay *
505    TkGetDisplay(display)
506         Display *display;          /* X's display pointer */
507    {
508        TkDisplay *dispPtr;
509        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
510                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
511    
512        for (dispPtr = tsdPtr->displayList; dispPtr != NULL;
513                dispPtr = dispPtr->nextPtr) {
514            if (dispPtr->display == display) {
515                break;
516            }
517        }
518        return dispPtr;
519    }
520    
521    /*
522     *--------------------------------------------------------------
523     *
524     * TkGetDisplayList --
525     *
526     *      This procedure returns a pointer to the thread-local
527     *      list of TkDisplays corresponding to the open displays.
528     *
529     * Results:
530     *      The return value is a pointer to the first TkDisplay
531     *      structure in thread-local-storage.
532     *
533     * Side effects:
534     *      None.
535     *
536     *--------------------------------------------------------------
537     */
538    TkDisplay *
539    TkGetDisplayList()
540    {
541        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
542                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
543        
544        return tsdPtr->displayList;
545    }
546    
547    /*
548     *--------------------------------------------------------------
549     *
550     * TkGetMainInfoList --
551     *
552     *      This procedure returns a pointer to the list of structures
553     *      containing information about all main windows for the
554     *      current thread.
555     *
556     * Results:
557     *      The return value is a pointer to the first TkMainInfo
558     *      structure in thread local storage.
559     *
560     * Side effects:
561     *      None.
562     *
563     *--------------------------------------------------------------
564     */
565    TkMainInfo *
566    TkGetMainInfoList()
567    {
568        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
569                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
570        
571        return tsdPtr->mainWindowList;
572    }
573    /*
574     *--------------------------------------------------------------
575     *
576     * TkAllocWindow --
577     *
578     *      This procedure creates and initializes a TkWindow structure.
579     *
580     * Results:
581     *      The return value is a pointer to the new window.
582     *
583     * Side effects:
584     *      A new window structure is allocated and all its fields are
585     *      initialized.
586     *
587     *--------------------------------------------------------------
588     */
589    
590    TkWindow *
591    TkAllocWindow(dispPtr, screenNum, parentPtr)
592        TkDisplay *dispPtr;         /* Display associated with new window. */
593        int screenNum;              /* Index of screen for new window. */
594        TkWindow *parentPtr;        /* Parent from which this window should
595                                     * inherit visual information.  NULL means
596                                     * use screen defaults instead of
597                                     * inheriting. */
598    {
599        register TkWindow *winPtr;
600    
601        winPtr = (TkWindow *) ckalloc(sizeof(TkWindow));
602        winPtr->display = dispPtr->display;
603        winPtr->dispPtr = dispPtr;
604        winPtr->screenNum = screenNum;
605        if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
606                && (parentPtr->screenNum == winPtr->screenNum)) {
607            winPtr->visual = parentPtr->visual;
608            winPtr->depth = parentPtr->depth;
609        } else {
610            winPtr->visual = DefaultVisual(dispPtr->display, screenNum);
611            winPtr->depth = DefaultDepth(dispPtr->display, screenNum);
612        }
613        winPtr->window = None;
614        winPtr->childList = NULL;
615        winPtr->lastChildPtr = NULL;
616        winPtr->parentPtr = NULL;
617        winPtr->nextPtr = NULL;
618        winPtr->mainPtr = NULL;
619        winPtr->pathName = NULL;
620        winPtr->nameUid = NULL;
621        winPtr->classUid = NULL;
622        winPtr->changes = defChanges;
623        winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
624        winPtr->atts = defAtts;
625        if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
626                && (parentPtr->screenNum == winPtr->screenNum)) {
627            winPtr->atts.colormap = parentPtr->atts.colormap;
628        } else {
629            winPtr->atts.colormap = DefaultColormap(dispPtr->display, screenNum);
630        }
631        winPtr->dirtyAtts = CWEventMask|CWColormap|CWBitGravity;
632        winPtr->flags = 0;
633        winPtr->handlerList = NULL;
634    #ifdef TK_USE_INPUT_METHODS
635        winPtr->inputContext = NULL;
636    #endif /* TK_USE_INPUT_METHODS */
637        winPtr->tagPtr = NULL;
638        winPtr->numTags = 0;
639        winPtr->optionLevel = -1;
640        winPtr->selHandlerList = NULL;
641        winPtr->geomMgrPtr = NULL;
642        winPtr->geomData = NULL;
643        winPtr->reqWidth = winPtr->reqHeight = 1;
644        winPtr->internalBorderWidth = 0;
645        winPtr->wmInfoPtr = NULL;
646        winPtr->classProcsPtr = NULL;
647        winPtr->instanceData = NULL;
648        winPtr->privatePtr = NULL;
649    
650        return winPtr;
651    }
652    
653    /*
654     *----------------------------------------------------------------------
655     *
656     * NameWindow --
657     *
658     *      This procedure is invoked to give a window a name and insert
659     *      the window into the hierarchy associated with a particular
660     *      application.
661     *
662     * Results:
663     *      A standard Tcl return value.
664     *
665     * Side effects:
666     *      See above.
667     *
668     *----------------------------------------------------------------------
669     */
670    
671    static int
672    NameWindow(interp, winPtr, parentPtr, name)
673        Tcl_Interp *interp;         /* Interpreter to use for error reporting. */
674        register TkWindow *winPtr;  /* Window that is to be named and inserted. */
675        TkWindow *parentPtr;        /* Pointer to logical parent for winPtr
676                                     * (used for naming, options, etc.). */
677        char *name;                 /* Name for winPtr;   must be unique among
678                                     * parentPtr's children. */
679    {
680    #define FIXED_SIZE 200
681        char staticSpace[FIXED_SIZE];
682        char *pathName;
683        int new;
684        Tcl_HashEntry *hPtr;
685        int length1, length2;
686    
687        /*
688         * Setup all the stuff except name right away, then do the name stuff
689         * last.  This is so that if the name stuff fails, everything else
690         * will be properly initialized (needed to destroy the window cleanly
691         * after the naming failure).
692         */
693        winPtr->parentPtr = parentPtr;
694        winPtr->nextPtr = NULL;
695        if (parentPtr->childList == NULL) {
696            parentPtr->childList = winPtr;
697        } else {
698            parentPtr->lastChildPtr->nextPtr = winPtr;
699        }
700        parentPtr->lastChildPtr = winPtr;
701        winPtr->mainPtr = parentPtr->mainPtr;
702        winPtr->mainPtr->refCount++;
703        winPtr->nameUid = Tk_GetUid(name);
704    
705        /*
706         * Don't permit names that start with an upper-case letter:  this
707         * will just cause confusion with class names in the option database.
708         */
709    
710        if (isupper(UCHAR(name[0]))) {
711            Tcl_AppendResult(interp,
712                    "window name starts with an upper-case letter: \"",
713                    name, "\"", (char *) NULL);
714            return TCL_ERROR;
715        }
716    
717        /*
718         * To permit names of arbitrary length, must be prepared to malloc
719         * a buffer to hold the new path name.  To run fast in the common
720         * case where names are short, use a fixed-size buffer on the
721         * stack.
722         */
723    
724        length1 = strlen(parentPtr->pathName);
725        length2 = strlen(name);
726        if ((length1+length2+2) <= FIXED_SIZE) {
727            pathName = staticSpace;
728        } else {
729            pathName = (char *) ckalloc((unsigned) (length1+length2+2));
730        }
731        if (length1 == 1) {
732            pathName[0] = '.';
733            strcpy(pathName+1, name);
734        } else {
735            strcpy(pathName, parentPtr->pathName);
736            pathName[length1] = '.';
737            strcpy(pathName+length1+1, name);
738        }
739        hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new);
740        if (pathName != staticSpace) {
741            ckfree(pathName);
742        }
743        if (!new) {
744            Tcl_AppendResult(interp, "window name \"", name,
745                    "\" already exists in parent", (char *) NULL);
746            return TCL_ERROR;
747        }
748        Tcl_SetHashValue(hPtr, winPtr);
749        winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr);
750        return TCL_OK;
751    }
752    
753    /*
754     *----------------------------------------------------------------------
755     *
756     * TkCreateMainWindow --
757     *
758     *      Make a new main window.  A main window is a special kind of
759     *      top-level window used as the outermost window in an
760     *      application.
761     *
762     * Results:
763     *      The return value is a token for the new window, or NULL if
764     *      an error prevented the new window from being created.  If
765     *      NULL is returned, an error message will be left in
766     *      the interp's result.
767     *
768     * Side effects:
769     *      A new window structure is allocated locally;  "interp" is
770     *      associated with the window and registered for "send" commands
771     *      under "baseName".  BaseName may be extended with an instance
772     *      number in the form "#2" if necessary to make it globally
773     *      unique.  Tk-related commands are bound into interp.
774     *
775     *----------------------------------------------------------------------
776     */
777    
778    Tk_Window
779    TkCreateMainWindow(interp, screenName, baseName)
780        Tcl_Interp *interp;         /* Interpreter to use for error reporting. */
781        char *screenName;           /* Name of screen on which to create
782                                     * window.  Empty or NULL string means
783                                     * use DISPLAY environment variable. */
784        char *baseName;             /* Base name for application;  usually of the
785                                     * form "prog instance". */
786    {
787        Tk_Window tkwin;
788        int dummy;
789        int isSafe;
790        Tcl_HashEntry *hPtr;
791        register TkMainInfo *mainPtr;
792        register TkWindow *winPtr;
793        register TkCmd *cmdPtr;
794        ClientData clientData;
795        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
796                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
797        
798        /*
799         * Panic if someone updated the TkWindow structure without
800         * also updating the Tk_FakeWin structure (or vice versa).
801         */
802    
803        if (sizeof(TkWindow) != sizeof(Tk_FakeWin)) {
804            panic("TkWindow and Tk_FakeWin are not the same size");
805        }
806    
807        /*
808         * Create the basic TkWindow structure.
809         */
810    
811        tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName,
812                screenName);
813        if (tkwin == NULL) {
814            return NULL;
815        }
816        
817        /*
818         * Create the TkMainInfo structure for this application, and set
819         * up name-related information for the new window.
820         */
821    
822        winPtr = (TkWindow *) tkwin;
823        mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo));
824        mainPtr->winPtr = winPtr;
825        mainPtr->refCount = 1;
826        mainPtr->interp = interp;
827        Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS);
828        TkEventInit();
829        TkBindInit(mainPtr);
830        TkFontPkgInit(mainPtr);
831        mainPtr->tlFocusPtr = NULL;
832        mainPtr->displayFocusPtr = NULL;
833        mainPtr->optionRootPtr = NULL;
834        Tcl_InitHashTable(&mainPtr->imageTable, TCL_STRING_KEYS);
835        mainPtr->strictMotif = 0;
836        if (Tcl_LinkVar(interp, "tk_strictMotif", (char *) &mainPtr->strictMotif,
837                TCL_LINK_BOOLEAN) != TCL_OK) {
838            Tcl_ResetResult(interp);
839        }
840        mainPtr->nextPtr = tsdPtr->mainWindowList;
841        tsdPtr->mainWindowList = mainPtr;
842        winPtr->mainPtr = mainPtr;
843        hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy);
844        Tcl_SetHashValue(hPtr, winPtr);
845        winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr);
846    
847        /*
848         * We have just created another Tk application; increment the refcount
849         * on the display pointer.
850         */
851    
852        winPtr->dispPtr->refCount++;
853    
854        /*
855         * Register the interpreter for "send" purposes.
856         */
857    
858        winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, baseName));
859    
860        /*
861         * Bind in Tk's commands.
862         */
863    
864        isSafe = Tcl_IsSafe(interp);
865        for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
866            if ((cmdPtr->cmdProc == NULL) && (cmdPtr->objProc == NULL)) {
867                panic("TkCreateMainWindow: builtin command with NULL string and object procs");
868            }
869            if (cmdPtr->passMainWindow) {
870                clientData = (ClientData) tkwin;
871            } else {
872                clientData = (ClientData) NULL;
873            }
874            if (cmdPtr->cmdProc != NULL) {
875                Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc,
876                        clientData, (void (*) _ANSI_ARGS_((ClientData))) NULL);
877            } else {
878                Tcl_CreateObjCommand(interp, cmdPtr->name, cmdPtr->objProc,
879                        clientData, NULL);
880            }
881            if (isSafe) {
882                if (!(cmdPtr->isSafe)) {
883                    Tcl_HideCommand(interp, cmdPtr->name, cmdPtr->name);
884                }
885            }
886        }
887    
888        TkCreateMenuCmd(interp);
889    
890        /*
891         * Set variables for the intepreter.
892         */
893    
894        Tcl_SetVar(interp, "tk_patchLevel", TK_PATCH_LEVEL, TCL_GLOBAL_ONLY);
895        Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY);
896    
897        tsdPtr->numMainWindows++;
898        return tkwin;
899    }
900    
901    /*
902     *--------------------------------------------------------------
903     *
904     * Tk_CreateWindow --
905     *
906     *      Create a new internal or top-level window as a child of an
907     *      existing window.
908     *
909     * Results:
910     *      The return value is a token for the new window.  This
911     *      is not the same as X's token for the window.  If an error
912     *      occurred in creating the window (e.g. no such display or
913     *      screen), then an error message is left in the interp's result and
914     *      NULL is returned.
915     *
916     * Side effects:
917     *      A new window structure is allocated locally.  An X
918     *      window is not initially created, but will be created
919     *      the first time the window is mapped.
920     *
921     *--------------------------------------------------------------
922     */
923    
924    Tk_Window
925    Tk_CreateWindow(interp, parent, name, screenName)
926        Tcl_Interp *interp;         /* Interpreter to use for error reporting.
927                                     * the interp's result is assumed to be
928                                     * initialized by the caller. */
929        Tk_Window parent;           /* Token for parent of new window. */
930        char *name;                 /* Name for new window.  Must be unique
931                                     * among parent's children. */
932        char *screenName;           /* If NULL, new window will be internal on
933                                     * same screen as its parent.  If non-NULL,
934                                     * gives name of screen on which to create
935                                     * new window;  window will be a top-level
936                                     * window. */
937    {
938        TkWindow *parentPtr = (TkWindow *) parent;
939        TkWindow *winPtr;
940    
941        if ((parentPtr != NULL) && (parentPtr->flags & TK_ALREADY_DEAD)) {
942            Tcl_AppendResult(interp,
943                    "can't create window: parent has been destroyed",
944                    (char *) NULL);
945            return NULL;
946        } else if ((parentPtr != NULL) &&
947                (parentPtr->flags & TK_CONTAINER)) {
948            Tcl_AppendResult(interp,
949                    "can't create window: its parent has -container = yes",
950                    (char *) NULL);
951            return NULL;
952        }
953        if (screenName == NULL) {
954            winPtr = TkAllocWindow(parentPtr->dispPtr, parentPtr->screenNum,
955                    parentPtr);
956            if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) {
957                Tk_DestroyWindow((Tk_Window) winPtr);
958                return NULL;
959            } else {
960                return (Tk_Window) winPtr;
961            }
962        } else {
963            return CreateTopLevelWindow(interp, parent, name, screenName);
964        }
965    }
966    
967    /*
968     *----------------------------------------------------------------------
969     *
970     * Tk_CreateWindowFromPath --
971     *
972     *      This procedure is similar to Tk_CreateWindow except that
973     *      it uses a path name to create the window, rather than a
974     *      parent and a child name.
975     *
976     * Results:
977     *      The return value is a token for the new window.  This
978     *      is not the same as X's token for the window.  If an error
979     *      occurred in creating the window (e.g. no such display or
980     *      screen), then an error message is left in the interp's result and
981     *      NULL is returned.
982     *
983     * Side effects:
984     *      A new window structure is allocated locally.  An X
985     *      window is not initially created, but will be created
986     *      the first time the window is mapped.
987     *
988     *----------------------------------------------------------------------
989     */
990    
991    Tk_Window
992    Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName)
993        Tcl_Interp *interp;         /* Interpreter to use for error reporting.
994                                     * the interp's result is assumed to be
995                                     * initialized by the caller. */
996        Tk_Window tkwin;            /* Token for any window in application
997                                     * that is to contain new window. */
998        char *pathName;             /* Path name for new window within the
999                                     * application of tkwin.  The parent of
1000                                     * this window must already exist, but
1001                                     * the window itself must not exist. */
1002        char *screenName;           /* If NULL, new window will be on same
1003                                     * screen as its parent.  If non-NULL,
1004                                     * gives name of screen on which to create
1005                                     * new window;  window will be a top-level
1006                                     * window. */
1007    {
1008    #define FIXED_SPACE 5
1009        char fixedSpace[FIXED_SPACE+1];
1010        char *p;
1011        Tk_Window parent;
1012        int numChars;
1013    
1014        /*
1015         * Strip the parent's name out of pathName (it's everything up
1016         * to the last dot).  There are two tricky parts: (a) must
1017         * copy the parent's name somewhere else to avoid modifying
1018         * the pathName string (for large names, space for the copy
1019         * will have to be malloc'ed);  (b) must special-case the
1020         * situation where the parent is ".".
1021         */
1022    
1023        p = strrchr(pathName, '.');
1024        if (p == NULL) {
1025            Tcl_AppendResult(interp, "bad window path name \"", pathName,
1026                    "\"", (char *) NULL);
1027            return NULL;
1028        }
1029        numChars = p-pathName;
1030        if (numChars > FIXED_SPACE) {
1031            p = (char *) ckalloc((unsigned) (numChars+1));
1032        } else {
1033            p = fixedSpace;
1034        }
1035        if (numChars == 0) {
1036            *p = '.';
1037            p[1] = '\0';
1038        } else {
1039            strncpy(p, pathName, (size_t) numChars);
1040            p[numChars] = '\0';
1041        }
1042    
1043        /*
1044         * Find the parent window.
1045         */
1046    
1047        parent = Tk_NameToWindow(interp, p, tkwin);
1048        if (p != fixedSpace) {
1049            ckfree(p);
1050        }
1051        if (parent == NULL) {
1052            return NULL;
1053        }
1054        if (((TkWindow *) parent)->flags & TK_ALREADY_DEAD) {
1055            Tcl_AppendResult(interp,
1056                "can't create window: parent has been destroyed", (char *) NULL);
1057            return NULL;
1058        } else if (((TkWindow *) parent)->flags & TK_CONTAINER) {
1059            Tcl_AppendResult(interp,
1060                "can't create window: its parent has -container = yes",
1061                    (char *) NULL);
1062            return NULL;
1063        }
1064    
1065        /*
1066         * Create the window.
1067         */
1068    
1069        if (screenName == NULL) {
1070            TkWindow *parentPtr = (TkWindow *) parent;
1071            TkWindow *winPtr;
1072    
1073            winPtr = TkAllocWindow(parentPtr->dispPtr, parentPtr->screenNum,
1074                    parentPtr);
1075            if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1)
1076                    != TCL_OK) {
1077                Tk_DestroyWindow((Tk_Window) winPtr);
1078                return NULL;
1079            } else {
1080                return (Tk_Window) winPtr;
1081            }
1082        } else {
1083            return CreateTopLevelWindow(interp, parent, pathName+numChars+1,
1084                    screenName);
1085        }
1086    }
1087    
1088    /*
1089     *--------------------------------------------------------------
1090     *
1091     * Tk_DestroyWindow --
1092     *
1093     *      Destroy an existing window.  After this call, the caller
1094     *      should never again use the token.
1095     *
1096     * Results:
1097     *      None.
1098     *
1099     * Side effects:
1100     *      The window is deleted, along with all of its children.
1101     *      Relevant callback procedures are invoked.
1102     *
1103     *--------------------------------------------------------------
1104     */
1105    
1106    void
1107    Tk_DestroyWindow(tkwin)
1108        Tk_Window tkwin;            /* Window to destroy. */
1109    {
1110        TkWindow *winPtr = (TkWindow *) tkwin;
1111        TkDisplay *dispPtr = winPtr->dispPtr;
1112        XEvent event;
1113        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1114                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1115    
1116        if (winPtr->flags & TK_ALREADY_DEAD) {
1117            /*
1118             * A destroy event binding caused the window to be destroyed
1119             * again.  Ignore the request.
1120             */
1121    
1122            return;
1123        }
1124        winPtr->flags |= TK_ALREADY_DEAD;
1125    
1126        /*
1127         * Some cleanup needs to be done immediately, rather than later,
1128         * because it needs information that will be destoyed before we
1129         * get to the main cleanup point.  For example, TkFocusDeadWindow
1130         * needs to access the parentPtr field from a window, but if
1131         * a Destroy event handler deletes the window's parent this
1132         * field will be NULL before the main cleanup point is reached.
1133         */
1134    
1135        TkFocusDeadWindow(winPtr);
1136    
1137        /*
1138         * If this is a main window, remove it from the list of main
1139         * windows.  This needs to be done now (rather than later with
1140         * all the other main window cleanup) to handle situations where
1141         * a destroy binding for a window calls "exit".  In this case
1142         * the child window cleanup isn't complete when exit is called,
1143         * so the reference count of its application doesn't go to zero
1144         * when exit calls Tk_DestroyWindow on ".", so the main window
1145         * doesn't get removed from the list and exit loops infinitely.
1146         * Even worse, if "destroy ." is called by the destroy binding
1147         * before calling "exit", "exit" will attempt to destroy
1148         * mainPtr->winPtr, which no longer exists, and there may be a
1149         * core dump.
1150         *
1151         * Also decrement the display refcount so that if this is the
1152         * last Tk application in this process on this display, the display
1153         * can be closed and its data structures deleted.
1154         */
1155    
1156        if (winPtr->mainPtr->winPtr == winPtr) {
1157            dispPtr->refCount--;
1158            if (tsdPtr->mainWindowList == winPtr->mainPtr) {
1159                tsdPtr->mainWindowList = winPtr->mainPtr->nextPtr;
1160            } else {
1161                TkMainInfo *prevPtr;
1162    
1163                for (prevPtr = tsdPtr->mainWindowList;
1164                        prevPtr->nextPtr != winPtr->mainPtr;
1165                        prevPtr = prevPtr->nextPtr) {
1166                    /* Empty loop body. */
1167                }
1168                prevPtr->nextPtr = winPtr->mainPtr->nextPtr;
1169            }
1170            tsdPtr->numMainWindows--;
1171        }
1172    
1173        /*
1174         * Recursively destroy children.
1175         */
1176    
1177        dispPtr->destroyCount++;
1178        while (winPtr->childList != NULL) {
1179            TkWindow *childPtr;
1180            childPtr = winPtr->childList;
1181            childPtr->flags |= TK_DONT_DESTROY_WINDOW;
1182            Tk_DestroyWindow((Tk_Window) childPtr);
1183            if (winPtr->childList == childPtr) {
1184                /*
1185                 * The child didn't remove itself from the child list, so
1186                 * let's remove it here.  This can happen in some strange
1187                 * conditions, such as when a Delete event handler for a
1188                 * window deletes the window's parent.
1189                 */
1190    
1191                winPtr->childList = childPtr->nextPtr;
1192                childPtr->parentPtr = NULL;
1193            }
1194        }
1195        if ((winPtr->flags & (TK_CONTAINER|TK_BOTH_HALVES))
1196                == (TK_CONTAINER|TK_BOTH_HALVES)) {
1197            /*
1198             * This is the container for an embedded application, and
1199             * the embedded application is also in this process.  Delete
1200             * the embedded window in-line here, for the same reasons we
1201             * delete children in-line (otherwise, for example, the Tk
1202             * window may appear to exist even though its X window is
1203             * gone; this could cause errors).  Special note: it's possible
1204             * that the embedded window has already been deleted, in which
1205             * case TkpGetOtherWindow will return NULL.
1206             */
1207    
1208            TkWindow *childPtr;
1209            childPtr = TkpGetOtherWindow(winPtr);
1210            if (childPtr != NULL) {
1211                childPtr->flags |= TK_DONT_DESTROY_WINDOW;
1212                Tk_DestroyWindow((Tk_Window) childPtr);
1213            }
1214        }
1215    
1216        /*
1217         * Generate a DestroyNotify event.  In order for the DestroyNotify
1218         * event to be processed correctly, need to make sure the window
1219         * exists.  This is a bit of a kludge, and may be unnecessarily
1220         * expensive, but without it no event handlers will get called for
1221         * windows that don't exist yet.
1222         *
1223         * Note: if the window's pathName is NULL it means that the window
1224         * was not successfully initialized in the first place, so we should
1225         * not make the window exist or generate the event.
1226         */
1227    
1228        if (winPtr->pathName != NULL) {
1229            if (winPtr->window == None) {
1230                Tk_MakeWindowExist(tkwin);
1231            }
1232            event.type = DestroyNotify;
1233            event.xdestroywindow.serial =
1234                    LastKnownRequestProcessed(winPtr->display);
1235            event.xdestroywindow.send_event = False;
1236            event.xdestroywindow.display = winPtr->display;
1237            event.xdestroywindow.event = winPtr->window;
1238            event.xdestroywindow.window = winPtr->window;
1239            Tk_HandleEvent(&event);
1240        }
1241    
1242        /*
1243         * Cleanup the data structures associated with this window.
1244         */
1245    
1246        if (winPtr->flags & TK_TOP_LEVEL) {
1247            TkWmDeadWindow(winPtr);
1248        } else if (winPtr->flags & TK_WM_COLORMAP_WINDOW) {
1249            TkWmRemoveFromColormapWindows(winPtr);
1250        }
1251        if (winPtr->window != None) {
1252    #if defined(MAC_TCL) || defined(__WIN32__)
1253            XDestroyWindow(winPtr->display, winPtr->window);
1254    #else
1255            if ((winPtr->flags & TK_TOP_LEVEL)
1256                    || !(winPtr->flags & TK_DONT_DESTROY_WINDOW)) {
1257                /*
1258                 * The parent has already been destroyed and this isn't
1259                 * a top-level window, so this window will be destroyed
1260                 * implicitly when the parent's X window is destroyed;
1261                 * it's much faster not to do an explicit destroy of this
1262                 * X window.
1263                 */
1264    
1265                dispPtr->lastDestroyRequest = NextRequest(winPtr->display);
1266                XDestroyWindow(winPtr->display, winPtr->window);
1267            }
1268    #endif
1269            TkFreeWindowId(dispPtr, winPtr->window);
1270            Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->winTable,
1271                    (char *) winPtr->window));
1272            winPtr->window = None;
1273        }
1274        dispPtr->destroyCount--;
1275        UnlinkWindow(winPtr);
1276        TkEventDeadWindow(winPtr);
1277        TkBindDeadWindow(winPtr);
1278    #ifdef TK_USE_INPUT_METHODS
1279        if (winPtr->inputContext != NULL) {
1280            XDestroyIC(winPtr->inputContext);
1281        }
1282    #endif /* TK_USE_INPUT_METHODS */
1283        if (winPtr->tagPtr != NULL) {
1284            TkFreeBindingTags(winPtr);
1285        }
1286        TkOptionDeadWindow(winPtr);
1287        TkSelDeadWindow(winPtr);
1288        TkGrabDeadWindow(winPtr);
1289        if (winPtr->mainPtr != NULL) {
1290            if (winPtr->pathName != NULL) {
1291                Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable,
1292                        (ClientData) winPtr->pathName);
1293                Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable,
1294                        winPtr->pathName));
1295            }
1296            winPtr->mainPtr->refCount--;
1297            if (winPtr->mainPtr->refCount == 0) {
1298                register TkCmd *cmdPtr;
1299    
1300                /*
1301                 * We just deleted the last window in the application.  Delete
1302                 * the TkMainInfo structure too and replace all of Tk's commands
1303                 * with dummy commands that return errors.  Also delete the
1304                 * "send" command to unregister the interpreter.
1305                 *
1306                 * NOTE: Only replace the commands it if the interpreter is
1307                 * not being deleted. If it *is*, the interpreter cleanup will
1308                 * do all the needed work.
1309                 */
1310    
1311                if ((winPtr->mainPtr->interp != NULL) &&
1312                        (!Tcl_InterpDeleted(winPtr->mainPtr->interp))) {
1313                    for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
1314                        Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name,
1315                                TkDeadAppCmd, (ClientData) NULL,
1316                                (void (*) _ANSI_ARGS_((ClientData))) NULL);
1317                    }
1318                    Tcl_CreateCommand(winPtr->mainPtr->interp, "send",
1319                            TkDeadAppCmd, (ClientData) NULL,
1320                            (void (*) _ANSI_ARGS_((ClientData))) NULL);
1321                    Tcl_UnlinkVar(winPtr->mainPtr->interp, "tk_strictMotif");
1322                }
1323                    
1324                Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable);
1325                TkBindFree(winPtr->mainPtr);
1326                TkDeleteAllImages(winPtr->mainPtr);
1327                TkFontPkgFree(winPtr->mainPtr);
1328    
1329                /*
1330                 * When embedding Tk into other applications, make sure
1331                 * that all destroy events reach the server. Otherwise
1332                 * the embedding application may also attempt to destroy
1333                 * the windows, resulting in an X error
1334                 */
1335    
1336                if (winPtr->flags & TK_EMBEDDED) {
1337                    XSync(winPtr->display,False) ;
1338                }
1339                ckfree((char *) winPtr->mainPtr);
1340    
1341                /*
1342                 * If no other applications are using the display, close the
1343                 * display now and relinquish its data structures.
1344                 */
1345                
1346                if (dispPtr->refCount <= 0) {
1347    #ifdef  NOT_YET
1348                    /*
1349                     * I have disabled this code because on Windows there are
1350                     * still order dependencies in close-down. All displays
1351                     * and resources will get closed down properly anyway at
1352                     * exit, through the exit handler.
1353                     */
1354                    
1355                    TkDisplay *theDispPtr, *backDispPtr;
1356                    
1357                    /*
1358                     * Splice this display out of the list of displays.
1359                     */
1360                    
1361                    for (theDispPtr = displayList, backDispPtr = NULL;
1362                             (theDispPtr != winPtr->dispPtr) &&
1363                                 (theDispPtr != NULL);
1364                             theDispPtr = theDispPtr->nextPtr) {
1365                        backDispPtr = theDispPtr;
1366                    }
1367                    if (theDispPtr == NULL) {
1368                        panic("could not find display to close!");
1369                    }
1370                    if (backDispPtr == NULL) {
1371                        displayList = theDispPtr->nextPtr;
1372                    } else {
1373                        backDispPtr->nextPtr = theDispPtr->nextPtr;
1374                    }
1375                    
1376                    /*
1377                     * Found and spliced it out, now actually do the cleanup.
1378                     */
1379                    
1380                    if (dispPtr->name != NULL) {
1381                        ckfree(dispPtr->name);
1382                    }
1383                    
1384                    Tcl_DeleteHashTable(&(dispPtr->winTable));
1385    
1386                    /*
1387                     * Cannot yet close the display because we still have
1388                     * order of deletion problems. Defer until exit handling
1389                     * instead. At that time, the display will cleanly shut
1390                     * down (hopefully..). (JYL)
1391                     */
1392    
1393                    TkpCloseDisplay(dispPtr);
1394    
1395                    /*
1396                     * There is lots more to clean up, we leave it at this for
1397                     * the time being.
1398                     */
1399    #endif
1400                }
1401            }
1402        }
1403        ckfree((char *) winPtr);
1404    }
1405    
1406    /*
1407     *--------------------------------------------------------------
1408     *
1409     * Tk_MapWindow --
1410     *
1411     *      Map a window within its parent.  This may require the
1412     *      window and/or its parents to actually be created.
1413     *
1414     * Results:
1415     *      None.
1416     *
1417     * Side effects:
1418     *      The given window will be mapped.  Windows may also
1419     *      be created.
1420     *
1421     *--------------------------------------------------------------
1422     */
1423    
1424    void
1425    Tk_MapWindow(tkwin)
1426        Tk_Window tkwin;            /* Token for window to map. */
1427    {
1428        register TkWindow *winPtr = (TkWindow *) tkwin;
1429        XEvent event;
1430    
1431        if (winPtr->flags & TK_MAPPED) {
1432            return;
1433        }
1434        if (winPtr->window == None) {
1435            Tk_MakeWindowExist(tkwin);
1436        }
1437        if (winPtr->flags & TK_TOP_LEVEL) {
1438            /*
1439             * Lots of special processing has to be done for top-level
1440             * windows.  Let tkWm.c handle everything itself.
1441             */
1442    
1443            TkWmMapWindow(winPtr);
1444            return;
1445        }
1446        winPtr->flags |= TK_MAPPED;
1447        XMapWindow(winPtr->display, winPtr->window);
1448        event.type = MapNotify;
1449        event.xmap.serial = LastKnownRequestProcessed(winPtr->display);
1450        event.xmap.send_event = False;
1451        event.xmap.display = winPtr->display;
1452        event.xmap.event = winPtr->window;
1453        event.xmap.window = winPtr->window;
1454        event.xmap.override_redirect = winPtr->atts.override_redirect;
1455        Tk_HandleEvent(&event);
1456    }
1457    
1458    /*
1459     *--------------------------------------------------------------
1460     *
1461     * Tk_MakeWindowExist --
1462     *
1463     *      Ensure that a particular window actually exists.  This
1464     *      procedure shouldn't normally need to be invoked from
1465     *      outside the Tk package, but may be needed if someone
1466     *      wants to manipulate a window before mapping it.
1467     *
1468     * Results:
1469     *      None.
1470     *
1471     * Side effects:
1472     *      When the procedure returns, the X window associated with
1473     *      tkwin is guaranteed to exist.  This may require the
1474     *      window's ancestors to be created also.
1475     *
1476     *--------------------------------------------------------------
1477     */
1478    
1479    void
1480    Tk_MakeWindowExist(tkwin)
1481        Tk_Window tkwin;            /* Token for window. */
1482    {
1483        register TkWindow *winPtr = (TkWindow *) tkwin;
1484        TkWindow *winPtr2;
1485        Window parent;
1486        Tcl_HashEntry *hPtr;
1487        int new;
1488    
1489        if (winPtr->window != None) {
1490            return;
1491        }
1492    
1493        if ((winPtr->parentPtr == NULL) || (winPtr->flags & TK_TOP_LEVEL)) {
1494            parent = XRootWindow(winPtr->display, winPtr->screenNum);
1495        } else {
1496            if (winPtr->parentPtr->window == None) {
1497                Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr);
1498            }
1499            parent = winPtr->parentPtr->window;
1500        }
1501    
1502        if (winPtr->classProcsPtr != NULL
1503                && winPtr->classProcsPtr->createProc != NULL) {
1504            winPtr->window = (*winPtr->classProcsPtr->createProc)(tkwin, parent,
1505                    winPtr->instanceData);
1506        } else {
1507            winPtr->window = TkpMakeWindow(winPtr, parent);
1508        }
1509    
1510        hPtr = Tcl_CreateHashEntry(&winPtr->dispPtr->winTable,
1511                (char *) winPtr->window, &new);
1512        Tcl_SetHashValue(hPtr, winPtr);
1513        winPtr->dirtyAtts = 0;
1514        winPtr->dirtyChanges = 0;
1515    #ifdef TK_USE_INPUT_METHODS
1516        winPtr->inputContext = NULL;
1517    #endif /* TK_USE_INPUT_METHODS */
1518    
1519        if (!(winPtr->flags & TK_TOP_LEVEL)) {
1520            /*
1521             * If any siblings higher up in the stacking order have already
1522             * been created then move this window to its rightful position
1523             * in the stacking order.
1524             *
1525             * NOTE: this code ignores any changes anyone might have made
1526             * to the sibling and stack_mode field of the window's attributes,
1527             * so it really isn't safe for these to be manipulated except
1528             * by calling Tk_RestackWindow.
1529             */
1530    
1531            for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL;
1532                    winPtr2 = winPtr2->nextPtr) {
1533                if ((winPtr2->window != None)
1534                        && !(winPtr2->flags & (TK_TOP_LEVEL|TK_REPARENTED))) {
1535                    XWindowChanges changes;
1536                    changes.sibling = winPtr2->window;
1537                    changes.stack_mode = Below;
1538                    XConfigureWindow(winPtr->display, winPtr->window,
1539                            CWSibling|CWStackMode, &changes);
1540                    break;
1541                }
1542            }
1543    
1544            /*
1545             * If this window has a different colormap than its parent, add
1546             * the window to the WM_COLORMAP_WINDOWS property for its top-level.
1547             */
1548    
1549            if ((winPtr->parentPtr != NULL) &&
1550                    (winPtr->atts.colormap != winPtr->parentPtr->atts.colormap)) {
1551                TkWmAddToColormapWindows(winPtr);
1552                winPtr->flags |= TK_WM_COLORMAP_WINDOW;
1553            }
1554        }
1555    
1556        /*
1557         * Issue a ConfigureNotify event if there were deferred configuration
1558         * changes (but skip it if the window is being deleted;  the
1559         * ConfigureNotify event could cause problems if we're being called
1560         * from Tk_DestroyWindow under some conditions).
1561         */
1562    
1563        if ((winPtr->flags & TK_NEED_CONFIG_NOTIFY)
1564                && !(winPtr->flags & TK_ALREADY_DEAD)){
1565            winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY;
1566            TkDoConfigureNotify(winPtr);
1567        }
1568    }
1569    
1570    /*
1571     *--------------------------------------------------------------
1572     *
1573     * Tk_UnmapWindow, etc. --
1574     *
1575     *      There are several procedures under here, each of which
1576     *      mirrors an existing X procedure.  In addition to performing
1577     *      the functions of the corresponding procedure, each
1578     *      procedure also updates the local window structure and
1579     *      synthesizes an X event (if the window's structure is being
1580     *      managed internally).
1581     *
1582     * Results:
1583     *      See the manual entries.
1584     *
1585     * Side effects:
1586     *      See the manual entries.
1587     *
1588     *--------------------------------------------------------------
1589     */
1590    
1591    void
1592    Tk_UnmapWindow(tkwin)
1593        Tk_Window tkwin;            /* Token for window to unmap. */
1594    {
1595        register TkWindow *winPtr = (TkWindow *) tkwin;
1596    
1597        if (!(winPtr->flags & TK_MAPPED) || (winPtr->flags & TK_ALREADY_DEAD)) {
1598            return;
1599        }
1600        if (winPtr->flags & TK_TOP_LEVEL) {
1601            /*
1602             * Special processing has to be done for top-level windows.  Let
1603             * tkWm.c handle everything itself.
1604             */
1605    
1606            TkWmUnmapWindow(winPtr);
1607            return;
1608        }
1609        winPtr->flags &= ~TK_MAPPED;
1610        XUnmapWindow(winPtr->display, winPtr->window);
1611        if (!(winPtr->flags & TK_TOP_LEVEL)) {
1612            XEvent event;
1613    
1614            event.type = UnmapNotify;
1615            event.xunmap.serial = LastKnownRequestProcessed(winPtr->display);
1616            event.xunmap.send_event = False;
1617            event.xunmap.display = winPtr->display;
1618            event.xunmap.event = winPtr->window;
1619            event.xunmap.window = winPtr->window;
1620            event.xunmap.from_configure = False;
1621            Tk_HandleEvent(&event);
1622        }
1623    }
1624    
1625    void
1626    Tk_ConfigureWindow(tkwin, valueMask, valuePtr)
1627        Tk_Window tkwin;            /* Window to re-configure. */
1628        unsigned int valueMask;     /* Mask indicating which parts of
1629                                     * *valuePtr are to be used. */
1630        XWindowChanges *valuePtr;   /* New values. */
1631    {
1632        register TkWindow *winPtr = (TkWindow *) tkwin;
1633    
1634        if (valueMask & CWX) {
1635            winPtr->changes.x = valuePtr->x;
1636        }
1637        if (valueMask & CWY) {
1638            winPtr->changes.y = valuePtr->y;
1639        }
1640        if (valueMask & CWWidth) {
1641            winPtr->changes.width = valuePtr->width;
1642        }
1643        if (valueMask & CWHeight) {
1644            winPtr->changes.height = valuePtr->height;
1645        }
1646        if (valueMask & CWBorderWidth) {
1647            winPtr->changes.border_width = valuePtr->border_width;
1648        }
1649        if (valueMask & (CWSibling|CWStackMode)) {
1650            panic("Can't set sibling or stack mode from Tk_ConfigureWindow.");
1651        }
1652    
1653        if (winPtr->window != None) {
1654            XConfigureWindow(winPtr->display, winPtr->window,
1655                    valueMask, valuePtr);
1656            TkDoConfigureNotify(winPtr);
1657        } else {
1658            winPtr->dirtyChanges |= valueMask;
1659            winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1660        }
1661    }
1662    
1663    void
1664    Tk_MoveWindow(tkwin, x, y)
1665        Tk_Window tkwin;            /* Window to move. */
1666        int x, y;                   /* New location for window (within
1667                                     * parent). */
1668    {
1669        register TkWindow *winPtr = (TkWindow *) tkwin;
1670    
1671        winPtr->changes.x = x;
1672        winPtr->changes.y = y;
1673        if (winPtr->window != None) {
1674            XMoveWindow(winPtr->display, winPtr->window, x, y);
1675            TkDoConfigureNotify(winPtr);
1676        } else {
1677            winPtr->dirtyChanges |= CWX|CWY;
1678            winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1679        }
1680    }
1681    
1682    void
1683    Tk_ResizeWindow(tkwin, width, height)
1684        Tk_Window tkwin;            /* Window to resize. */
1685        int width, height;          /* New dimensions for window. */
1686    {
1687        register TkWindow *winPtr = (TkWindow *) tkwin;
1688    
1689        winPtr->changes.width = (unsigned) width;
1690        winPtr->changes.height = (unsigned) height;
1691        if (winPtr->window != None) {
1692            XResizeWindow(winPtr->display, winPtr->window, (unsigned) width,
1693                    (unsigned) height);
1694            TkDoConfigureNotify(winPtr);
1695        } else {
1696            winPtr->dirtyChanges |= CWWidth|CWHeight;
1697            winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1698        }
1699    }
1700    
1701    void
1702    Tk_MoveResizeWindow(tkwin, x, y, width, height)
1703        Tk_Window tkwin;            /* Window to move and resize. */
1704        int x, y;                   /* New location for window (within
1705                                     * parent). */
1706        int width, height;          /* New dimensions for window. */
1707    {
1708        register TkWindow *winPtr = (TkWindow *) tkwin;
1709    
1710        winPtr->changes.x = x;
1711        winPtr->changes.y = y;
1712        winPtr->changes.width = (unsigned) width;
1713        winPtr->changes.height = (unsigned) height;
1714        if (winPtr->window != None) {
1715            XMoveResizeWindow(winPtr->display, winPtr->window, x, y,
1716                    (unsigned) width, (unsigned) height);
1717            TkDoConfigureNotify(winPtr);
1718        } else {
1719            winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight;
1720            winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1721        }
1722    }
1723    
1724    void
1725    Tk_SetWindowBorderWidth(tkwin, width)
1726        Tk_Window tkwin;            /* Window to modify. */
1727        int width;                  /* New border width for window. */
1728    {
1729        register TkWindow *winPtr = (TkWindow *) tkwin;
1730    
1731        winPtr->changes.border_width = width;
1732        if (winPtr->window != None) {
1733            XSetWindowBorderWidth(winPtr->display, winPtr->window,
1734                    (unsigned) width);
1735            TkDoConfigureNotify(winPtr);
1736        } else {
1737            winPtr->dirtyChanges |= CWBorderWidth;
1738            winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1739        }
1740    }
1741    
1742    void
1743    Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr)
1744        Tk_Window tkwin;            /* Window to manipulate. */
1745        unsigned long valueMask;    /* OR'ed combination of bits,
1746                                     * indicating which fields of
1747                                     * *attsPtr are to be used. */
1748        register XSetWindowAttributes *attsPtr;
1749                                    /* New values for some attributes. */
1750    {
1751        register TkWindow *winPtr = (TkWindow *) tkwin;
1752    
1753        if (valueMask & CWBackPixmap) {
1754            winPtr->atts.background_pixmap = attsPtr->background_pixmap;
1755        }
1756        if (valueMask & CWBackPixel) {
1757            winPtr->atts.background_pixel = attsPtr->background_pixel;
1758        }
1759        if (valueMask & CWBorderPixmap) {
1760            winPtr->atts.border_pixmap = attsPtr->border_pixmap;
1761        }
1762        if (valueMask & CWBorderPixel) {
1763            winPtr->atts.border_pixel = attsPtr->border_pixel;
1764        }
1765        if (valueMask & CWBitGravity) {
1766            winPtr->atts.bit_gravity = attsPtr->bit_gravity;
1767        }
1768        if (valueMask & CWWinGravity) {
1769            winPtr->atts.win_gravity = attsPtr->win_gravity;
1770        }
1771        if (valueMask & CWBackingStore) {
1772            winPtr->atts.backing_store = attsPtr->backing_store;
1773        }
1774        if (valueMask & CWBackingPlanes) {
1775            winPtr->atts.backing_planes = attsPtr->backing_planes;
1776        }
1777        if (valueMask & CWBackingPixel) {
1778            winPtr->atts.backing_pixel = attsPtr->backing_pixel;
1779        }
1780        if (valueMask & CWOverrideRedirect) {
1781            winPtr->atts.override_redirect = attsPtr->override_redirect;
1782        }
1783        if (valueMask & CWSaveUnder) {
1784            winPtr->atts.save_under = attsPtr->save_under;
1785        }
1786        if (valueMask & CWEventMask) {
1787            winPtr->atts.event_mask = attsPtr->event_mask;
1788        }
1789        if (valueMask & CWDontPropagate) {
1790            winPtr->atts.do_not_propagate_mask
1791                    = attsPtr->do_not_propagate_mask;
1792        }
1793        if (valueMask & CWColormap) {
1794            winPtr->atts.colormap = attsPtr->colormap;
1795        }
1796        if (valueMask & CWCursor) {
1797            winPtr->atts.cursor = attsPtr->cursor;
1798        }
1799    
1800        if (winPtr->window != None) {
1801            XChangeWindowAttributes(winPtr->display, winPtr->window,
1802                    valueMask, attsPtr);
1803        } else {
1804            winPtr->dirtyAtts |= valueMask;
1805        }
1806    }
1807    
1808    void
1809    Tk_SetWindowBackground(tkwin, pixel)
1810        Tk_Window tkwin;            /* Window to manipulate. */
1811        unsigned long pixel;        /* Pixel value to use for
1812                                     * window's background. */
1813    {
1814        register TkWindow *winPtr = (TkWindow *) tkwin;
1815    
1816        winPtr->atts.background_pixel = pixel;
1817    
1818        if (winPtr->window != None) {
1819            XSetWindowBackground(winPtr->display, winPtr->window, pixel);
1820        } else {
1821            winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixmap)
1822                    | CWBackPixel;
1823        }
1824    }
1825    
1826    void
1827    Tk_SetWindowBackgroundPixmap(tkwin, pixmap)
1828        Tk_Window tkwin;            /* Window to manipulate. */
1829        Pixmap pixmap;              /* Pixmap to use for window's
1830                                     * background. */
1831    {
1832        register TkWindow *winPtr = (TkWindow *) tkwin;
1833    
1834        winPtr->atts.background_pixmap = pixmap;
1835    
1836        if (winPtr->window != None) {
1837            XSetWindowBackgroundPixmap(winPtr->display,
1838                    winPtr->window, pixmap);
1839        } else {
1840            winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixel)
1841                    | CWBackPixmap;
1842        }
1843    }
1844    
1845    void
1846    Tk_SetWindowBorder(tkwin, pixel)
1847        Tk_Window tkwin;            /* Window to manipulate. */
1848        unsigned long pixel;        /* Pixel value to use for
1849                                     * window's border. */
1850    {
1851        register TkWindow *winPtr = (TkWindow *) tkwin;
1852    
1853        winPtr->atts.border_pixel = pixel;
1854    
1855        if (winPtr->window != None) {
1856            XSetWindowBorder(winPtr->display, winPtr->window, pixel);
1857        } else {
1858            winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixmap)
1859                    | CWBorderPixel;
1860        }
1861    }
1862    
1863    void
1864    Tk_SetWindowBorderPixmap(tkwin, pixmap)
1865        Tk_Window tkwin;            /* Window to manipulate. */
1866        Pixmap pixmap;              /* Pixmap to use for window's
1867                                     * border. */
1868    {
1869        register TkWindow *winPtr = (TkWindow *) tkwin;
1870    
1871        winPtr->atts.border_pixmap = pixmap;
1872    
1873        if (winPtr->window != None) {
1874            XSetWindowBorderPixmap(winPtr->display,
1875                    winPtr->window, pixmap);
1876        } else {
1877            winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixel)
1878                    | CWBorderPixmap;
1879        }
1880    }
1881    
1882    void
1883    Tk_DefineCursor(tkwin, cursor)
1884        Tk_Window tkwin;            /* Window to manipulate. */
1885        Tk_Cursor cursor;           /* Cursor to use for window (may be None). */
1886    {
1887        register TkWindow *winPtr = (TkWindow *) tkwin;
1888    
1889    #ifdef MAC_TCL
1890        winPtr->atts.cursor = (XCursor) cursor;
1891    #else
1892        winPtr->atts.cursor = (Cursor) cursor;
1893    #endif
1894        
1895        if (winPtr->window != None) {
1896            XDefineCursor(winPtr->display, winPtr->window, winPtr->atts.cursor);
1897        } else {
1898            winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor;
1899        }
1900    }
1901    
1902    void
1903    Tk_UndefineCursor(tkwin)
1904        Tk_Window tkwin;            /* Window to manipulate. */
1905    {
1906        Tk_DefineCursor(tkwin, None);
1907    }
1908    
1909    void
1910    Tk_SetWindowColormap(tkwin, colormap)
1911        Tk_Window tkwin;            /* Window to manipulate. */
1912        Colormap colormap;          /* Colormap to use for window. */
1913    {
1914        register TkWindow *winPtr = (TkWindow *) tkwin;
1915    
1916        winPtr->atts.colormap = colormap;
1917    
1918        if (winPtr->window != None) {
1919            XSetWindowColormap(winPtr->display, winPtr->window, colormap);
1920            if (!(winPtr->flags & TK_TOP_LEVEL)) {
1921                TkWmAddToColormapWindows(winPtr);
1922                winPtr->flags |= TK_WM_COLORMAP_WINDOW;
1923            }
1924        } else {
1925            winPtr->dirtyAtts |= CWColormap;
1926        }
1927    }
1928    
1929    /*
1930     *----------------------------------------------------------------------
1931     *
1932     * Tk_SetWindowVisual --
1933     *
1934     *      This procedure is called to specify a visual to be used
1935     *      for a Tk window when it is created.  This procedure, if
1936     *      called at all, must be called before the X window is created
1937     *      (i.e. before Tk_MakeWindowExist is called).
1938     *
1939     * Results:
1940     *      The return value is 1 if successful, or 0 if the X window has
1941     *      been already created.
1942     *
1943     * Side effects:
1944     *      The information given is stored for when the window is created.
1945     *
1946     *----------------------------------------------------------------------
1947     */
1948    
1949    int
1950    Tk_SetWindowVisual(tkwin, visual, depth, colormap)
1951        Tk_Window tkwin;            /* Window to manipulate. */
1952        Visual *visual;             /* New visual for window. */
1953        int depth;                  /* New depth for window. */
1954        Colormap colormap;          /* An appropriate colormap for the visual. */
1955    {
1956        register TkWindow *winPtr = (TkWindow *) tkwin;
1957    
1958        if( winPtr->window != None ){
1959            /* Too late! */
1960            return 0;
1961        }
1962    
1963        winPtr->visual = visual;
1964        winPtr->depth = depth;
1965        winPtr->atts.colormap = colormap;
1966        winPtr->dirtyAtts |= CWColormap;
1967    
1968        /*
1969         * The following code is needed to make sure that the window doesn't
1970         * inherit the parent's border pixmap, which would result in a BadMatch
1971         * error.
1972         */
1973    
1974        if (!(winPtr->dirtyAtts & CWBorderPixmap)) {
1975            winPtr->dirtyAtts |= CWBorderPixel;
1976        }
1977        return 1;
1978    }
1979    
1980    /*
1981     *----------------------------------------------------------------------
1982     *
1983     * TkDoConfigureNotify --
1984     *
1985     *      Generate a ConfigureNotify event describing the current
1986     *      configuration of a window.
1987     *
1988     * Results:
1989     *      None.
1990     *
1991     * Side effects:
1992     *      An event is generated and processed by Tk_HandleEvent.
1993     *
1994     *----------------------------------------------------------------------
1995     */
1996    
1997    void
1998    TkDoConfigureNotify(winPtr)
1999        register TkWindow *winPtr;          /* Window whose configuration
2000                                             * was just changed. */
2001    {
2002        XEvent event;
2003    
2004        event.type = ConfigureNotify;
2005        event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display);
2006        event.xconfigure.send_event = False;
2007        event.xconfigure.display = winPtr->display;
2008        event.xconfigure.event = winPtr->window;
2009        event.xconfigure.window = winPtr->window;
2010        event.xconfigure.x = winPtr->changes.x;
2011        event.xconfigure.y = winPtr->changes.y;
2012        event.xconfigure.width = winPtr->changes.width;
2013        event.xconfigure.height = winPtr->changes.height;
2014        event.xconfigure.border_width = winPtr->changes.border_width;
2015        if (winPtr->changes.stack_mode == Above) {
2016            event.xconfigure.above = winPtr->changes.sibling;
2017        } else {
2018            event.xconfigure.above = None;
2019        }
2020        event.xconfigure.override_redirect = winPtr->atts.override_redirect;
2021        Tk_HandleEvent(&event);
2022    }
2023    
2024    /*
2025     *----------------------------------------------------------------------
2026     *
2027     * Tk_SetClass --
2028     *
2029     *      This procedure is used to give a window a class.
2030     *
2031     * Results:
2032     *      None.
2033     *
2034     * Side effects:
2035     *      A new class is stored for tkwin, replacing any existing
2036     *      class for it.
2037     *
2038     *----------------------------------------------------------------------
2039     */
2040    
2041    void
2042    Tk_SetClass(tkwin, className)
2043        Tk_Window tkwin;            /* Token for window to assign class. */
2044        char *className;            /* New class for tkwin. */
2045    {
2046        register TkWindow *winPtr = (TkWindow *) tkwin;
2047    
2048        winPtr->classUid = Tk_GetUid(className);
2049        if (winPtr->flags & TK_TOP_LEVEL) {
2050            TkWmSetClass(winPtr);
2051        }
2052        TkOptionClassChanged(winPtr);
2053    }
2054    
2055    /*
2056     *----------------------------------------------------------------------
2057     *
2058     * TkSetClassProcs --
2059     *
2060     *      This procedure is used to set the class procedures and
2061     *      instance data for a window.
2062     *
2063     * Results:
2064     *      None.
2065     *
2066     * Side effects:
2067     *      A new set of class procedures and instance data is stored
2068     *      for tkwin, replacing any existing values.
2069     *
2070     *----------------------------------------------------------------------
2071     */
2072    
2073    void
2074    TkSetClassProcs(tkwin, procs, instanceData)
2075        Tk_Window tkwin;            /* Token for window to modify. */
2076        TkClassProcs *procs;        /* Class procs structure. */
2077        ClientData instanceData;    /* Data to be passed to class procedures. */
2078    {
2079        register TkWindow *winPtr = (TkWindow *) tkwin;
2080    
2081        winPtr->classProcsPtr = procs;
2082        winPtr->instanceData = instanceData;
2083    }
2084    
2085    /*
2086     *----------------------------------------------------------------------
2087     *
2088     * Tk_NameToWindow --
2089     *
2090     *      Given a string name for a window, this procedure
2091     *      returns the token for the window, if there exists a
2092     *      window corresponding to the given name.
2093     *
2094     * Results:
2095     *      The return result is either a token for the window corresponding
2096     *      to "name", or else NULL to indicate that there is no such
2097     *      window.  In this case, an error message is left in the interp's result.
2098     *
2099     * Side effects:
2100     *      None.
2101     *
2102     *----------------------------------------------------------------------
2103     */
2104    
2105    Tk_Window
2106    Tk_NameToWindow(interp, pathName, tkwin)
2107        Tcl_Interp *interp;         /* Where to report errors. */
2108        char *pathName;             /* Path name of window. */
2109        Tk_Window tkwin;            /* Token for window:  name is assumed to
2110                                     * belong to the same main window as tkwin. */
2111    {
2112        Tcl_HashEntry *hPtr;
2113    
2114        if (tkwin == NULL) {
2115            /*
2116             * Either we're not really in Tk, or the main window was destroyed and
2117             * we're on our way out of the application
2118             */
2119            Tcl_AppendResult(interp, "NULL main window", (char *)NULL);
2120            return NULL;
2121        }
2122        
2123        hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable,
2124                pathName);
2125        if (hPtr == NULL) {
2126            Tcl_AppendResult(interp, "bad window path name \"",
2127                    pathName, "\"", (char *) NULL);
2128            return NULL;
2129        }
2130        return (Tk_Window) Tcl_GetHashValue(hPtr);
2131    }
2132    
2133    /*
2134     *----------------------------------------------------------------------
2135     *
2136     * Tk_IdToWindow --
2137     *
2138     *      Given an X display and window ID, this procedure returns the
2139     *      Tk token for the window, if there exists a Tk window corresponding
2140     *      to the given ID.
2141     *
2142     * Results:
2143     *      The return result is either a token for the window corresponding
2144     *      to the given X id, or else NULL to indicate that there is no such
2145     *      window.
2146     *
2147     * Side effects:
2148     *      None.
2149     *
2150     *----------------------------------------------------------------------
2151     */
2152    
2153    Tk_Window
2154    Tk_IdToWindow(display, window)
2155        Display *display;           /* X display containing the window. */
2156        Window window;              /* X window window id. */
2157    {
2158        TkDisplay *dispPtr;
2159        Tcl_HashEntry *hPtr;
2160    
2161        for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) {
2162            if (dispPtr == NULL) {
2163                return NULL;
2164            }
2165            if (dispPtr->display == display) {
2166                break;
2167            }
2168        }
2169    
2170        hPtr = Tcl_FindHashEntry(&dispPtr->winTable, (char *) window);
2171        if (hPtr == NULL) {
2172            return NULL;
2173        }
2174        return (Tk_Window) Tcl_GetHashValue(hPtr);
2175    }
2176    
2177    /*
2178     *----------------------------------------------------------------------
2179     *
2180     * Tk_DisplayName --
2181     *
2182     *      Return the textual name of a window's display.
2183     *
2184     * Results:
2185     *      The return value is the string name of the display associated
2186     *      with tkwin.
2187     *
2188     * Side effects:
2189     *      None.
2190     *
2191     *----------------------------------------------------------------------
2192     */
2193    
2194    char *
2195    Tk_DisplayName(tkwin)
2196        Tk_Window tkwin;            /* Window whose display name is desired. */
2197    {
2198        return ((TkWindow *) tkwin)->dispPtr->name;
2199    }
2200    
2201    /*
2202     *----------------------------------------------------------------------
2203     *
2204     * UnlinkWindow --
2205     *
2206     *      This procedure removes a window from the childList of its
2207     *      parent.
2208     *
2209     * Results:
2210     *      None.
2211     *
2212     * Side effects:
2213     *      The window is unlinked from its childList.
2214     *
2215     *----------------------------------------------------------------------
2216     */
2217    
2218    static void
2219    UnlinkWindow(winPtr)
2220        TkWindow *winPtr;                   /* Child window to be unlinked. */
2221    {
2222        TkWindow *prevPtr;
2223    
2224        if (winPtr->parentPtr == NULL) {
2225            return;
2226        }
2227        prevPtr = winPtr->parentPtr->childList;
2228        if (prevPtr == winPtr) {
2229            winPtr->parentPtr->childList = winPtr->nextPtr;
2230            if (winPtr->nextPtr == NULL) {
2231                winPtr->parentPtr->lastChildPtr = NULL;
2232            }
2233        } else {
2234            while (prevPtr->nextPtr != winPtr) {
2235                prevPtr = prevPtr->nextPtr;
2236                if (prevPtr == NULL) {
2237                    panic("UnlinkWindow couldn't find child in parent");
2238                }
2239            }
2240            prevPtr->nextPtr = winPtr->nextPtr;
2241            if (winPtr->nextPtr == NULL) {
2242                winPtr->parentPtr->lastChildPtr = prevPtr;
2243            }
2244        }
2245    }
2246    
2247    /*
2248     *----------------------------------------------------------------------
2249     *
2250     * Tk_RestackWindow --
2251     *
2252     *      Change a window's position in the stacking order.
2253     *
2254     * Results:
2255     *      TCL_OK is normally returned.  If other is not a descendant
2256     *      of tkwin's parent then TCL_ERROR is returned and tkwin is
2257     *      not repositioned.
2258     *
2259     * Side effects:
2260     *      Tkwin is repositioned in the stacking order.
2261     *
2262     *----------------------------------------------------------------------
2263     */
2264    
2265    int
2266    Tk_RestackWindow(tkwin, aboveBelow, other)
2267        Tk_Window tkwin;            /* Token for window whose position in
2268                                     * the stacking order is to change. */
2269        int aboveBelow;             /* Indicates new position of tkwin relative
2270                                     * to other;  must be Above or Below. */
2271        Tk_Window other;            /* Tkwin will be moved to a position that
2272                                     * puts it just above or below this window.
2273                                     * If NULL then tkwin goes above or below
2274                                     * all windows in the same parent. */
2275    {
2276        TkWindow *winPtr = (TkWindow *) tkwin;
2277        TkWindow *otherPtr = (TkWindow *) other;
2278    
2279        /*
2280         * Special case:  if winPtr is a top-level window then just find
2281         * the top-level ancestor of otherPtr and restack winPtr above
2282         * otherPtr without changing any of Tk's childLists.
2283         */
2284    
2285        if (winPtr->flags & TK_TOP_LEVEL) {
2286            while ((otherPtr != NULL) && !(otherPtr->flags & TK_TOP_LEVEL)) {
2287                otherPtr = otherPtr->parentPtr;
2288            }
2289            TkWmRestackToplevel(winPtr, aboveBelow, otherPtr);
2290            return TCL_OK;
2291        }
2292    
2293        /*
2294         * Find an ancestor of otherPtr that is a sibling of winPtr.
2295         */
2296    
2297        if (winPtr->parentPtr == NULL) {
2298            /*
2299             * Window is going to be deleted shortly;  don't do anything.
2300             */
2301    
2302            return TCL_OK;
2303        }
2304        if (otherPtr == NULL) {
2305            if (aboveBelow == Above) {
2306                otherPtr = winPtr->parentPtr->lastChildPtr;
2307            } else {
2308                otherPtr = winPtr->parentPtr->childList;
2309            }
2310        } else {
2311            while (winPtr->parentPtr != otherPtr->parentPtr) {
2312                if ((otherPtr == NULL) || (otherPtr->flags & TK_TOP_LEVEL)) {
2313                    return TCL_ERROR;
2314                }
2315                otherPtr = otherPtr->parentPtr;
2316            }
2317        }
2318        if (otherPtr == winPtr) {
2319            return TCL_OK;
2320        }
2321    
2322        /*
2323         * Reposition winPtr in the stacking order.
2324         */
2325    
2326        UnlinkWindow(winPtr);
2327        if (aboveBelow == Above) {
2328            winPtr->nextPtr = otherPtr->nextPtr;
2329            if (winPtr->nextPtr == NULL) {
2330                winPtr->parentPtr->lastChildPtr = winPtr;
2331            }
2332            otherPtr->nextPtr = winPtr;
2333        } else {
2334            TkWindow *prevPtr;
2335    
2336            prevPtr = winPtr->parentPtr->childList;
2337            if (prevPtr == otherPtr) {
2338                winPtr->parentPtr->childList = winPtr;
2339            } else {
2340                while (prevPtr->nextPtr != otherPtr) {
2341                    prevPtr = prevPtr->nextPtr;
2342                }
2343                prevPtr->nextPtr = winPtr;
2344            }
2345            winPtr->nextPtr = otherPtr;
2346        }
2347    
2348        /*
2349         * Notify the X server of the change.  If winPtr hasn't yet been
2350         * created then there's no need to tell the X server now, since
2351         * the stacking order will be handled properly when the window
2352         * is finally created.
2353         */
2354    
2355        if (winPtr->window != None) {
2356            XWindowChanges changes;
2357            unsigned int mask;
2358    
2359            mask = CWStackMode;
2360            changes.stack_mode = Above;
2361            for (otherPtr = winPtr->nextPtr; otherPtr != NULL;
2362                    otherPtr = otherPtr->nextPtr) {
2363                if ((otherPtr->window != None)
2364                        && !(otherPtr->flags & (TK_TOP_LEVEL|TK_REPARENTED))){
2365                    changes.sibling = otherPtr->window;
2366                    changes.stack_mode = Below;
2367                    mask = CWStackMode|CWSibling;
2368                    break;
2369                }
2370            }
2371            XConfigureWindow(winPtr->display, winPtr->window, mask, &changes);
2372        }
2373        return TCL_OK;
2374    }
2375    
2376    /*
2377     *----------------------------------------------------------------------
2378     *
2379     * Tk_MainWindow --
2380     *
2381     *      Returns the main window for an application.
2382     *
2383     * Results:
2384     *      If interp has a Tk application associated with it, the main
2385     *      window for the application is returned.  Otherwise NULL is
2386     *      returned and an error message is left in the interp's result.
2387     *
2388     * Side effects:
2389     *      None.
2390     *
2391     *----------------------------------------------------------------------
2392     */
2393    
2394    Tk_Window
2395    Tk_MainWindow(interp)
2396        Tcl_Interp *interp;                 /* Interpreter that embodies the
2397                                             * application.  Used for error
2398                                             * reporting also. */
2399    {
2400        TkMainInfo *mainPtr;
2401        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
2402                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2403    
2404        for (mainPtr = tsdPtr->mainWindowList; mainPtr != NULL;
2405                mainPtr = mainPtr->nextPtr) {
2406            if (mainPtr->interp == interp) {
2407                return (Tk_Window) mainPtr->winPtr;
2408            }
2409        }
2410        Tcl_SetResult(interp, "this isn't a Tk application", TCL_STATIC);
2411        return NULL;
2412    }
2413    
2414    /*
2415     *----------------------------------------------------------------------
2416     *
2417     * Tk_StrictMotif --
2418     *
2419     *      Indicates whether strict Motif compliance has been specified
2420     *      for the given window.
2421     *
2422     * Results:
2423     *      The return value is 1 if strict Motif compliance has been
2424     *      requested for tkwin's application by setting the tk_strictMotif
2425     *      variable in its interpreter to a true value.  0 is returned
2426     *      if tk_strictMotif has a false value.
2427     *
2428     * Side effects:
2429     *      None.
2430     *
2431     *----------------------------------------------------------------------
2432     */
2433    
2434    int
2435    Tk_StrictMotif(tkwin)
2436        Tk_Window tkwin;                    /* Window whose application is
2437                                             * to be checked. */
2438    {
2439        return ((TkWindow *) tkwin)->mainPtr->strictMotif;
2440    }
2441    
2442    /*
2443     *--------------------------------------------------------------
2444     *
2445     * OpenIM --
2446     *
2447     *      Tries to open an X input method, associated with the
2448     *      given display.  Right now we can only deal with a bare-bones
2449     *      input style:  no preedit, and no status.
2450     *
2451     * Results:
2452     *      Stores the input method in dispPtr->inputMethod;  if there isn't
2453     *      a suitable input method, then NULL is stored in dispPtr->inputMethod.
2454     *
2455     * Side effects:
2456     *      An input method gets opened.
2457     *
2458     *--------------------------------------------------------------
2459     */
2460    
2461    static void
2462    OpenIM(dispPtr)
2463        TkDisplay *dispPtr;         /* Tk's structure for the display. */
2464    {
2465    #ifndef TK_USE_INPUT_METHODS
2466        return;
2467    #else
2468        unsigned short i;
2469        XIMStyles *stylePtr;
2470    
2471        dispPtr->inputMethod = XOpenIM(dispPtr->display, NULL, NULL, NULL);
2472        if (dispPtr->inputMethod == NULL) {
2473            return;
2474        }
2475    
2476        if ((XGetIMValues(dispPtr->inputMethod, XNQueryInputStyle, &stylePtr,
2477                NULL) != NULL) || (stylePtr == NULL)) {
2478            goto error;
2479        }
2480        for (i = 0; i < stylePtr->count_styles; i++) {
2481            if (stylePtr->supported_styles[i]
2482                    == (XIMPreeditNothing|XIMStatusNothing)) {
2483                XFree(stylePtr);
2484                return;
2485            }
2486        }
2487        XFree(stylePtr);
2488    
2489        error:
2490    
2491        /*
2492         * Should close the input method, but this causes core dumps on some
2493         * systems (e.g. Solaris 2.3 as of 1/6/95).
2494         * XCloseIM(dispPtr->inputMethod);
2495         */
2496        dispPtr->inputMethod = NULL;
2497        return;
2498    #endif /* TK_USE_INPUT_METHODS */
2499    }
2500    
2501    /*
2502     *----------------------------------------------------------------------
2503     *
2504     * Tk_GetNumMainWindows --
2505     *
2506     *      This procedure returns the number of main windows currently
2507     *      open in this process.
2508     *
2509     * Results:
2510     *      The number of main windows open in this process.
2511     *
2512     * Side effects:
2513     *      None.
2514     *
2515     *----------------------------------------------------------------------
2516     */
2517    
2518    int
2519    Tk_GetNumMainWindows()
2520    {
2521        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
2522                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2523    
2524        return tsdPtr->numMainWindows;
2525    }
2526    
2527    /*
2528     *----------------------------------------------------------------------
2529     *
2530     * DeleteWindowsExitProc --
2531     *
2532     *      This procedure is invoked as an exit handler.  It deletes all
2533     *      of the main windows in the process.
2534     *
2535     * Results:
2536     *      None.
2537     *
2538     * Side effects:
2539     *      None.
2540     *
2541     *----------------------------------------------------------------------
2542     */
2543    
2544    static void
2545    DeleteWindowsExitProc(clientData)
2546        ClientData clientData;              /* Not used. */
2547    {
2548        TkDisplay *displayPtr, *nextPtr;
2549        Tcl_Interp *interp;
2550        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
2551                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2552        
2553        while (tsdPtr->mainWindowList != NULL) {
2554            /*
2555             * We must protect the interpreter while deleting the window,
2556             * because of <Destroy> bindings which could destroy the interpreter
2557             * while the window is being deleted. This would leave frames on
2558             * the call stack pointing at deleted memory, causing core dumps.
2559             */
2560            
2561            interp = tsdPtr->mainWindowList->winPtr->mainPtr->interp;
2562            Tcl_Preserve((ClientData) interp);
2563            Tk_DestroyWindow((Tk_Window) tsdPtr->mainWindowList->winPtr);
2564            Tcl_Release((ClientData) interp);
2565        }
2566        
2567        displayPtr = tsdPtr->displayList;
2568        tsdPtr->displayList = NULL;
2569        
2570        /*
2571         * Iterate destroying the displays until no more displays remain.
2572         * It is possible for displays to get recreated during exit by any
2573         * code that calls GetScreen, so we must destroy these new displays
2574         * as well as the old ones.
2575         */
2576        
2577        for (displayPtr = tsdPtr->displayList;
2578             displayPtr != NULL;
2579             displayPtr = tsdPtr->displayList) {
2580    
2581            /*
2582             * Now iterate over the current list of open displays, and first
2583             * set the global pointer to NULL so we will be able to notice if
2584             * any new displays got created during deletion of the current set.
2585             * We must also do this to ensure that Tk_IdToWindow does not find
2586             * the old display as it is being destroyed, when it wants to see
2587             * if it needs to dispatch a message.
2588             */
2589            
2590            for (tsdPtr->displayList = NULL; displayPtr != NULL;
2591                    displayPtr = nextPtr) {
2592                nextPtr = displayPtr->nextPtr;
2593                if (displayPtr->name != (char *) NULL) {
2594                    ckfree(displayPtr->name);
2595                }
2596                Tcl_DeleteHashTable(&(displayPtr->winTable));
2597                TkpCloseDisplay(displayPtr);
2598            }
2599        }
2600        
2601        tsdPtr->numMainWindows = 0;
2602        tsdPtr->mainWindowList = NULL;
2603        tsdPtr->initialized = 0;
2604    }
2605    
2606    /*
2607     *----------------------------------------------------------------------
2608     *
2609     * Tk_Init --
2610     *
2611     *      This procedure is invoked to add Tk to an interpreter.  It
2612     *      incorporates all of Tk's commands into the interpreter and
2613     *      creates the main window for a new Tk application.  If the
2614     *      interpreter contains a variable "argv", this procedure
2615     *      extracts several arguments from that variable, uses them
2616     *      to configure the main window, and modifies argv to exclude
2617     *      the arguments (see the "wish" documentation for a list of
2618     *      the arguments that are extracted).
2619     *
2620     * Results:
2621     *      Returns a standard Tcl completion code and sets the interp's result
2622     *      if there is an error.
2623     *
2624     * Side effects:
2625     *      Depends on various initialization scripts that get invoked.
2626     *
2627     *----------------------------------------------------------------------
2628     */
2629    
2630    int
2631    Tk_Init(interp)
2632        Tcl_Interp *interp;         /* Interpreter to initialize. */
2633    {
2634        return Initialize(interp);
2635    }
2636    
2637    /*
2638     *----------------------------------------------------------------------
2639     *
2640     * Tk_SafeInit --
2641     *
2642     *      This procedure is invoked to add Tk to a safe interpreter. It
2643     *      invokes the internal procedure that does the real work.
2644     *
2645     * Results:
2646     *      Returns a standard Tcl completion code and sets the interp's result
2647     *      if there is an error.
2648     *
2649     * Side effects:
2650     *      Depends on various initialization scripts that are invoked.
2651     *
2652     *----------------------------------------------------------------------
2653     */
2654    
2655    int
2656    Tk_SafeInit(interp)
2657        Tcl_Interp *interp;         /* Interpreter to initialize. */
2658    {
2659        /*
2660         * Initialize the interpreter with Tk, safely. This removes
2661         * all the Tk commands that are unsafe.
2662         *
2663         * Rationale:
2664         *
2665         * - Toplevel and menu are unsafe because they can be used to cover
2666         *   the entire screen and to steal input from the user.
2667         * - Continuous ringing of the bell is a nuisance.
2668         * - Cannot allow access to the clipboard because a malicious script
2669         *   can replace the contents with the string "rm -r *" and lead to
2670         *   surprises when the contents of the clipboard are pasted. We do
2671         *   not currently hide the selection command.. Should we?
2672         * - Cannot allow send because it can be used to cause unsafe
2673         *   interpreters to execute commands. The tk command recreates the
2674         *   send command, so that too must be hidden.
2675         * - Focus can be used to grab the focus away from another window,
2676         *   in effect stealing user input. Cannot allow that.
2677         *   NOTE: We currently do *not* hide focus as it would make it
2678         *   impossible to provide keyboard input to Tk in a safe interpreter.
2679         * - Grab can be used to block the user from using any other apps
2680         *   on the screen.
2681         * - Tkwait can block the containing process forever. Use bindings,
2682         *   fileevents and split the protocol into before-the-wait and
2683         *   after-the-wait parts. More work but necessary.
2684         * - Wm is unsafe because (if toplevels are allowed, in the future)
2685         *   it can be used to remove decorations, move windows around, cover
2686         *   the entire screen etc etc.
2687         *
2688         * Current risks:
2689         *
2690         * - No CPU time limit, no memory allocation limits, no color limits.
2691         *
2692         *  The actual code called is the same as Tk_Init but Tcl_IsSafe()
2693         *  is checked at several places to differentiate the two initialisations.
2694         */
2695    
2696        return Initialize(interp);
2697    }
2698    
2699    
2700    extern TkStubs tkStubs;
2701    
2702    /*
2703     *----------------------------------------------------------------------
2704     *
2705     * Initialize --
2706     *
2707     *
2708     * Results:
2709     *      A standard Tcl result. Also leaves an error message in the interp's
2710     *      result if there was an error.
2711     *
2712     * Side effects:
2713     *      Depends on the initialization scripts that are invoked.
2714     *
2715     *----------------------------------------------------------------------
2716     */
2717    
2718    static int
2719    Initialize(interp)
2720        Tcl_Interp *interp;         /* Interpreter to initialize. */
2721    {
2722        char *p;
2723        int argc, code;
2724        char **argv, *args[20];
2725        Tcl_DString class;
2726        ThreadSpecificData *tsdPtr;
2727        
2728        /*
2729         * Ensure that we are getting the matching version of Tcl.  This is
2730         * really only an issue when Tk is loaded dynamically.
2731         */
2732    
2733        if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) {
2734            return TCL_ERROR;
2735        }
2736    
2737        tsdPtr = (ThreadSpecificData *)
2738            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2739    
2740        /*
2741         * Start by initializing all the static variables to default acceptable
2742         * values so that no information is leaked from a previous run of this
2743         * code.
2744         */
2745    
2746        Tcl_MutexLock(&windowMutex);
2747        synchronize = 0;
2748        name = NULL;
2749        display = NULL;
2750        geometry = NULL;
2751        colormap = NULL;
2752        use = NULL;
2753        visual = NULL;
2754        rest = 0;
2755    
2756        /*
2757         * We start by resetting the result because it might not be clean
2758         */
2759        Tcl_ResetResult(interp);
2760    
2761        if (Tcl_IsSafe(interp)) {
2762            /*
2763             * Get the clearance to start Tk and the "argv" parameters
2764             * from the master.
2765             */
2766            Tcl_DString ds;
2767            
2768            /*
2769             * Step 1 : find the master and construct the interp name
2770             * (could be a function if new APIs were ok).
2771             * We could also construct the path while walking, but there
2772             * is no API to get the name of an interp either.
2773             */
2774            Tcl_Interp *master = interp;
2775    
2776            while (1) {
2777                master = Tcl_GetMaster(master);
2778                if (master == NULL) {
2779                    Tcl_DStringFree(&ds);
2780                    Tcl_AppendResult(interp, "NULL master", (char *) NULL);
2781                    Tcl_MutexUnlock(&windowMutex);
2782                    return TCL_ERROR;
2783                }
2784                if (!Tcl_IsSafe(master)) {
2785                    /* Found the trusted master. */
2786                    break;
2787                }
2788            }
2789            /*
2790             * Construct the name (rewalk...)
2791             */
2792            if (Tcl_GetInterpPath(master, interp) != TCL_OK) {
2793                Tcl_AppendResult(interp, "error in Tcl_GetInterpPath",
2794                        (char *) NULL);
2795                Tcl_MutexUnlock(&windowMutex);
2796                return TCL_ERROR;
2797            }
2798            /*
2799             * Build the string to eval.
2800             */
2801            Tcl_DStringInit(&ds);
2802            Tcl_DStringAppendElement(&ds, "::safe::TkInit");
2803            Tcl_DStringAppendElement(&ds, Tcl_GetStringResult(master));
2804            
2805            /*
2806             * Step 2 : Eval in the master. The argument is the *reversed*
2807             * interp path of the slave.
2808             */
2809            
2810            if (Tcl_Eval(master, Tcl_DStringValue(&ds)) != TCL_OK) {
2811                /*
2812                 * We might want to transfer the error message or not.
2813                 * We don't. (no API to do it and maybe security reasons).
2814                 */
2815                Tcl_DStringFree(&ds);
2816                Tcl_AppendResult(interp,
2817                        "not allowed to start Tk by master's safe::TkInit",
2818                        (char *) NULL);
2819                Tcl_MutexUnlock(&windowMutex);
2820                return TCL_ERROR;
2821            }
2822            Tcl_DStringFree(&ds);
2823            /*
2824             * Use the master's result as argv.
2825             * Note: We don't use the Obj interfaces to avoid dealing with
2826             * cross interp refcounting and changing the code below.
2827             */
2828    
2829            p = Tcl_GetStringResult(master);
2830        } else {
2831            /*
2832             * If there is an "argv" variable, get its value, extract out
2833             * relevant arguments from it, and rewrite the variable without
2834             * the arguments that we used.
2835             */
2836    
2837            p = Tcl_GetVar2(interp, "argv", (char *) NULL, TCL_GLOBAL_ONLY);
2838        }
2839        argv = NULL;
2840        if (p != NULL) {
2841            char buffer[TCL_INTEGER_SPACE];
2842    
2843            if (Tcl_SplitList(interp, p, &argc, &argv) != TCL_OK) {
2844                argError:
2845                Tcl_AddErrorInfo(interp,
2846                        "\n    (processing arguments in argv variable)");
2847                Tcl_MutexUnlock(&windowMutex);
2848                return TCL_ERROR;
2849            }
2850            if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv,
2851                    argTable, TK_ARGV_DONT_SKIP_FIRST_ARG|TK_ARGV_NO_DEFAULTS)
2852                    != TCL_OK) {
2853                ckfree((char *) argv);
2854                goto argError;
2855            }
2856            p = Tcl_Merge(argc, argv);
2857            Tcl_SetVar2(interp, "argv", (char *) NULL, p, TCL_GLOBAL_ONLY);
2858            sprintf(buffer, "%d", argc);
2859            Tcl_SetVar2(interp, "argc", (char *) NULL, buffer, TCL_GLOBAL_ONLY);
2860            ckfree(p);
2861        }
2862    
2863        /*
2864         * Figure out the application's name and class.
2865         */
2866    
2867        Tcl_DStringInit(&class);
2868        if (name == NULL) {
2869            int offset;
2870            TkpGetAppName(interp, &class);
2871            offset = Tcl_DStringLength(&class)+1;
2872            Tcl_DStringSetLength(&class, offset);
2873            Tcl_DStringAppend(&class, Tcl_DStringValue(&class), offset-1);
2874            name = Tcl_DStringValue(&class) + offset;
2875        } else {
2876            Tcl_DStringAppend(&class, name, -1);
2877        }
2878    
2879        p = Tcl_DStringValue(&class);
2880        if (*p) {
2881            Tcl_UtfToTitle(p);
2882        }
2883    
2884        /*
2885         * Create an argument list for creating the top-level window,
2886         * using the information parsed from argv, if any.
2887         */
2888    
2889        args[0] = "toplevel";
2890        args[1] = ".";
2891        args[2] = "-class";
2892        args[3] = Tcl_DStringValue(&class);
2893        argc = 4;
2894        if (display != NULL) {
2895            args[argc] = "-screen";
2896            args[argc+1] = display;
2897            argc += 2;
2898    
2899            /*
2900             * If this is the first application for this process, save
2901             * the display name in the DISPLAY environment variable so
2902             * that it will be available to subprocesses created by us.
2903             */
2904    
2905            if (tsdPtr->numMainWindows == 0) {
2906                Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY);
2907            }
2908        }
2909        if (colormap != NULL) {
2910            args[argc] = "-colormap";
2911            args[argc+1] = colormap;
2912            argc += 2;
2913            colormap = NULL;
2914        }
2915        if (use != NULL) {
2916            args[argc] = "-use";
2917            args[argc+1] = use;
2918            argc += 2;
2919            use = NULL;
2920        }
2921        if (visual != NULL) {
2922            args[argc] = "-visual";
2923            args[argc+1] = visual;
2924            argc += 2;
2925            visual = NULL;
2926        }
2927        args[argc] = NULL;
2928        code = TkCreateFrame((ClientData) NULL, interp, argc, args, 1, name);
2929    
2930        Tcl_DStringFree(&class);
2931        if (code != TCL_OK) {
2932            goto done;
2933        }
2934        Tcl_ResetResult(interp);
2935        if (synchronize) {
2936            XSynchronize(Tk_Display(Tk_MainWindow(interp)), True);
2937        }
2938    
2939        /*
2940         * Set the geometry of the main window, if requested.  Put the
2941         * requested geometry into the "geometry" variable.
2942         */
2943    
2944        if (geometry != NULL) {
2945            Tcl_SetVar(interp, "geometry", geometry, TCL_GLOBAL_ONLY);
2946            code = Tcl_VarEval(interp, "wm geometry . ", geometry, (char *) NULL);
2947            if (code != TCL_OK) {
2948                goto done;
2949            }
2950            geometry = NULL;
2951        }
2952        Tcl_MutexUnlock(&windowMutex);
2953    
2954        if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {
2955            code = TCL_ERROR;
2956            goto done;
2957        }
2958    
2959        /*
2960         * Provide Tk and its stub table.
2961         */
2962    
2963        code = Tcl_PkgProvideEx(interp, "Tk", TK_VERSION, (ClientData) &tkStubs);
2964        if (code != TCL_OK) {
2965            goto done;
2966        }
2967    
2968    #ifdef Tk_InitStubs
2969    #undef Tk_InitStubs
2970    #endif
2971    
2972        Tk_InitStubs(interp, TK_VERSION, 1);
2973    
2974        /*
2975         * Invoke platform-specific initialization.
2976         */
2977    
2978        code = TkpInit(interp);
2979    
2980        done:
2981        if (argv != NULL) {
2982            ckfree((char *) argv);
2983        }
2984        return code;
2985    }
2986    
2987    /* End of tkwindow.c */

Legend:
Removed from v.29  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25