home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / generic / tkWindow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  67.1 KB  |  2,438 lines

  1. /* 
  2.  * tkWindow.c --
  3.  *
  4.  *    This file provides basic window-manipulation procedures,
  5.  *    which are equivalent to procedures in Xlib (and even
  6.  *    invoke them) but also maintain the local Tk_Window
  7.  *    structure.
  8.  *
  9.  * Copyright (c) 1989-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994-1996 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * SCCS: @(#) tkWindow.c 1.209 96/04/05 15:16:54
  16.  */
  17.  
  18. #include "tkPort.h"
  19. #include "tkInt.h"
  20. #include "patchlevel.h"
  21.  
  22. /*
  23.  * Count of number of main windows currently open in this process.
  24.  */
  25.  
  26. static int numMainWindows;
  27.  
  28. /*
  29.  * First in list of all main windows managed by this process.
  30.  */
  31.  
  32. TkMainInfo *tkMainWindowList = NULL;
  33.  
  34. /*
  35.  * List of all displays currently in use.
  36.  */
  37.  
  38. TkDisplay *tkDisplayList = NULL;
  39.  
  40. /*
  41.  * Have statics in this module been initialized?
  42.  */
  43.  
  44. static int initialized = 0;
  45.  
  46. /*
  47.  * The variables below hold several uid's that are used in many places
  48.  * in the toolkit.
  49.  */
  50.  
  51. Tk_Uid tkDisabledUid = NULL;
  52. Tk_Uid tkActiveUid = NULL;
  53. Tk_Uid tkNormalUid = NULL;
  54.  
  55. /*
  56.  * Default values for "changes" and "atts" fields of TkWindows.  Note
  57.  * that Tk always requests all events for all windows, except StructureNotify
  58.  * events on internal windows:  these events are generated internally.
  59.  */
  60.  
  61. static XWindowChanges defChanges = {
  62.     0, 0, 1, 1, 0, 0, Above
  63. };
  64. #define ALL_EVENTS_MASK \
  65.     KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
  66.     EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
  67.     VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|ColormapChangeMask
  68. static XSetWindowAttributes defAtts= {
  69.     None,            /* background_pixmap */
  70.     0,                /* background_pixel */
  71.     CopyFromParent,        /* border_pixmap */
  72.     0,                /* border_pixel */
  73.     NorthWestGravity,        /* bit_gravity */
  74.     NorthWestGravity,        /* win_gravity */
  75.     NotUseful,            /* backing_store */
  76.     (unsigned) ~0,        /* backing_planes */
  77.     0,                /* backing_pixel */
  78.     False,            /* save_under */
  79.     ALL_EVENTS_MASK,        /* event_mask */
  80.     0,                /* do_not_propagate_mask */
  81.     False,            /* override_redirect */
  82.     CopyFromParent,        /* colormap */
  83.     None            /* cursor */
  84. };
  85.  
  86. /*
  87.  * The following structure defines all of the commands supported by
  88.  * Tk, and the C procedures that execute them.
  89.  */
  90.  
  91. typedef struct {
  92.     char *name;            /* Name of command. */
  93.     int (*cmdProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
  94.         int argc, char **argv));
  95.                 /* Command procedure. */
  96. } TkCmd;
  97.  
  98. static TkCmd commands[] = {
  99.     /*
  100.      * Commands that are part of the intrinsics:
  101.      */
  102.  
  103.     {"bell",        Tk_BellCmd},
  104.     {"bind",        Tk_BindCmd},
  105.     {"bindtags",    Tk_BindtagsCmd},
  106.     {"clipboard",    Tk_ClipboardCmd},
  107.     {"destroy",        Tk_DestroyCmd},
  108.     {"focus",        Tk_FocusCmd},
  109.     {"grab",        Tk_GrabCmd},
  110.     {"grid",        Tk_GridCmd},
  111.     {"image",        Tk_ImageCmd},
  112.     {"lower",        Tk_LowerCmd},
  113.     {"option",        Tk_OptionCmd},
  114.     {"pack",        Tk_PackCmd},
  115.     {"place",        Tk_PlaceCmd},
  116.     {"raise",        Tk_RaiseCmd},
  117.     {"selection",    Tk_SelectionCmd},
  118.     {"tk",        Tk_TkCmd},
  119.     {"tkwait",        Tk_TkwaitCmd},
  120.     {"update",        Tk_UpdateCmd},
  121.     {"winfo",        Tk_WinfoCmd},
  122.     {"wm",        Tk_WmCmd},
  123.  
  124.     /*
  125.      * Widget class commands.
  126.      */
  127.     {"button",        Tk_ButtonCmd},
  128.     {"canvas",        Tk_CanvasCmd},
  129.     {"checkbutton",    Tk_CheckbuttonCmd},
  130.     {"entry",        Tk_EntryCmd},
  131.     {"frame",        Tk_FrameCmd},
  132.     {"label",        Tk_LabelCmd},
  133.     {"listbox",        Tk_ListboxCmd},
  134.     {"menu",        Tk_MenuCmd},
  135.     {"menubutton",    Tk_MenubuttonCmd},
  136.     {"message",        Tk_MessageCmd},
  137.     {"radiobutton",    Tk_RadiobuttonCmd},
  138.     {"scale",        Tk_ScaleCmd},
  139.     {"scrollbar",    Tk_ScrollbarCmd},
  140.     {"text",        Tk_TextCmd},
  141.     {"toplevel",    Tk_ToplevelCmd},
  142.     /*
  143.      * Native widget class commands.
  144.      */
  145. #ifdef MAC_TCL
  146.     {"macscrollbar",    Tk_MacScrollbarCmd},
  147. #endif
  148.     {(char *) NULL,    (int (*)()) NULL}
  149. };
  150.  
  151. /*
  152.  * The variables and table below are used to parse arguments from
  153.  * the "argv" variable in Tk_Init.
  154.  */
  155.  
  156. static int synchronize;
  157. static char *name;
  158. static char *display;
  159. static char *geometry;
  160. static char *colormap;
  161. static char *visual;
  162. static int rest = 0;
  163.  
  164. static Tk_ArgvInfo argTable[] = {
  165.     {"-colormap", TK_ARGV_STRING, (char *) NULL, (char *) &colormap,
  166.     "Colormap for main window"},
  167.     {"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,
  168.     "Display to use"},
  169.     {"-geometry", TK_ARGV_STRING, (char *) NULL, (char *) &geometry,
  170.     "Initial geometry for window"},
  171.     {"-name", TK_ARGV_STRING, (char *) NULL, (char *) &name,
  172.     "Name to use for application"},
  173.     {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,
  174.     "Use synchronous mode for display server"},
  175.     {"-visual", TK_ARGV_STRING, (char *) NULL, (char *) &visual,
  176.     "Visual for main window"},
  177.     {"--", TK_ARGV_REST, (char *) 1, (char *) &rest,
  178.     "Pass all remaining arguments through to script"},
  179.     {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
  180.     (char *) NULL}
  181. };
  182.  
  183. /*
  184.  * Forward declarations to procedures defined later in this file:
  185.  */
  186.  
  187. static TkWindow    *    AllocWindow _ANSI_ARGS_((TkDisplay *dispPtr,
  188.                 int screenNum, TkWindow *parentPtr));
  189. static Tk_Window    CreateTopLevelWindow _ANSI_ARGS_((Tcl_Interp *interp,
  190.                 Tk_Window parent, char *name, char *screenName));
  191. static void        DeleteWindowsExitProc _ANSI_ARGS_((
  192.                 ClientData clientData));
  193. static void        DoConfigureNotify _ANSI_ARGS_((TkWindow *winPtr));
  194. static TkDisplay *    GetScreen _ANSI_ARGS_((Tcl_Interp *interp,
  195.                 char *screenName, int *screenPtr));
  196. static int        NameWindow _ANSI_ARGS_((Tcl_Interp *interp,
  197.                 TkWindow *winPtr, TkWindow *parentPtr,
  198.                 char *name));
  199. static void        OpenIM _ANSI_ARGS_((TkDisplay *dispPtr));
  200. static void        UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr));
  201.  
  202. /*
  203.  *----------------------------------------------------------------------
  204.  *
  205.  * CreateTopLevelWindow --
  206.  *
  207.  *    Make a new window that will be at top-level (its parent will
  208.  *    be the root window of a screen).
  209.  *
  210.  * Results:
  211.  *    The return value is a token for the new window, or NULL if
  212.  *    an error prevented the new window from being created.  If
  213.  *    NULL is returned, an error message will be left in
  214.  *    interp->result.
  215.  *
  216.  * Side effects:
  217.  *    A new window structure is allocated locally.  An X
  218.  *    window is NOT initially created, but will be created
  219.  *    the first time the window is mapped.
  220.  *
  221.  *----------------------------------------------------------------------
  222.  */
  223.  
  224. static Tk_Window
  225. CreateTopLevelWindow(interp, parent, name, screenName)
  226.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  227.     Tk_Window parent;        /* Token for logical parent of new window
  228.                  * (used for naming, options, etc.).  May
  229.                  * be NULL. */
  230.     char *name;            /* Name for new window;  if parent is
  231.                  * non-NULL, must be unique among parent's
  232.                  * children. */
  233.     char *screenName;        /* Name of screen on which to create
  234.                  * window.  NULL means use DISPLAY environment
  235.                  * variable to determine.  Empty string means
  236.                  * use parent's screen, or DISPLAY if no
  237.                  * parent. */
  238. {
  239.     register TkWindow *winPtr;
  240.     register TkDisplay *dispPtr;
  241.     int screenId;
  242.  
  243.     if (!initialized) {
  244.     initialized = 1;
  245.     tkActiveUid = Tk_GetUid("active");
  246.     tkDisabledUid = Tk_GetUid("disabled");
  247.     tkNormalUid = Tk_GetUid("normal");
  248.  
  249.     /*
  250.      * Create built-in image types.
  251.      */
  252.     
  253.     Tk_CreateImageType(&tkBitmapImageType);
  254.     Tk_CreateImageType(&tkPhotoImageType);
  255.     
  256.     /*
  257.      * Create built-in photo image formats.
  258.      */
  259.     
  260.     Tk_CreatePhotoImageFormat(&tkImgFmtGIF);
  261.     Tk_CreatePhotoImageFormat(&tkImgFmtPPM);
  262.  
  263.     /*
  264.      * Create exit handler to delete all windows when the application
  265.      * exits.
  266.      */
  267.  
  268.     Tcl_CreateExitHandler(DeleteWindowsExitProc, (ClientData) NULL);
  269.     }
  270.  
  271.     if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
  272.     dispPtr = ((TkWindow *) parent)->dispPtr;
  273.     screenId = Tk_ScreenNumber(parent);
  274.     } else {
  275.     dispPtr = GetScreen(interp, screenName, &screenId);
  276.     if (dispPtr == NULL) {
  277.         return (Tk_Window) NULL;
  278.     }
  279.     }
  280.  
  281.     winPtr = AllocWindow(dispPtr, screenId, (TkWindow *) parent);
  282.  
  283.     /*
  284.      * Force the window to use a the border pixel instead of border
  285.      * pixmap.  This is needed for the case where the window doesn't
  286.      * use the default visual.  In this case, the default border is
  287.      * a pixmap inherited from the root window, which won't work because
  288.      * it will have the wrong visual.
  289.      */
  290.  
  291.     winPtr->dirtyAtts |= CWBorderPixel;
  292.  
  293.     /*
  294.      * Internal windows don't normally ask for StructureNotify events,
  295.      * since we can generate them internally.  However, for top-level
  296.      * windows we need to ask for the events because the window could
  297.      * be manipulated externally.
  298.      */
  299.  
  300.     winPtr->atts.event_mask |= StructureNotifyMask;
  301.  
  302.     /*
  303.      * (Need to set the TK_TOP_LEVEL flag immediately here;  otherwise
  304.      * Tk_DestroyWindow will core dump if it is called before the flag
  305.      * has been set.)
  306.      */
  307.  
  308.     winPtr->flags |= TK_TOP_LEVEL;
  309.     if (parent != NULL) {
  310.     if (NameWindow(interp, winPtr, (TkWindow *) parent, name) != TCL_OK) {
  311.         Tk_DestroyWindow((Tk_Window) winPtr);
  312.         return (Tk_Window) NULL;
  313.     }
  314.     }
  315.     TkWmNewWindow(winPtr);
  316.     return (Tk_Window) winPtr;
  317. }
  318.  
  319. /*
  320.  *----------------------------------------------------------------------
  321.  *
  322.  * GetScreen --
  323.  *
  324.  *    Given a string name for a display-plus-screen, find the
  325.  *    TkDisplay structure for the display and return the screen
  326.  *    number too.
  327.  *
  328.  * Results:
  329.  *    The return value is a pointer to information about the display,
  330.  *    or NULL if the display couldn't be opened.  In this case, an
  331.  *    error message is left in interp->result.  The location at
  332.  *    *screenPtr is overwritten with the screen number parsed from
  333.  *    screenName.
  334.  *
  335.  * Side effects:
  336.  *    A new connection is opened to the display if there is no
  337.  *    connection already.  A new TkDisplay data structure is also
  338.  *    setup, if necessary.
  339.  *
  340.  *----------------------------------------------------------------------
  341.  */
  342.  
  343. static TkDisplay *
  344. GetScreen(interp, screenName, screenPtr)
  345.     Tcl_Interp *interp;        /* Place to leave error message. */
  346.     char *screenName;        /* Name for screen.  NULL or empty means
  347.                  * use DISPLAY envariable. */
  348.     int *screenPtr;        /* Where to store screen number. */
  349. {
  350.     register TkDisplay *dispPtr;
  351.     char *p;
  352.     int screenId;
  353.     size_t length;
  354.  
  355.     /*
  356.      * Separate the screen number from the rest of the display
  357.      * name.  ScreenName is assumed to have the syntax
  358.      * <display>.<screen> with the dot and the screen being
  359.      * optional.
  360.      */
  361.  
  362.     screenName = TkGetDefaultScreenName(interp, screenName);
  363.     if (screenName == NULL) {
  364.     interp->result =
  365.         "no display name and no $DISPLAY environment variable";
  366.     return (TkDisplay *) NULL;
  367.     }
  368.     length = strlen(screenName);
  369.     screenId = 0;
  370.     p = screenName+length-1;
  371.     while (isdigit(UCHAR(*p)) && (p != screenName)) {
  372.     p--;
  373.     }
  374.     if ((*p == '.') && (p[1] != '\0')) {
  375.     length = p - screenName;
  376.     screenId = strtoul(p+1, (char **) NULL, 10);
  377.     }
  378.  
  379.     /*
  380.      * See if we already have a connection to this display.  If not,
  381.      * then open a new connection.
  382.      */
  383.  
  384.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  385.     if (dispPtr == NULL) {
  386.         Display *display;
  387.  
  388.         display = XOpenDisplay(screenName);
  389.         if (display == NULL) {
  390.         Tcl_AppendResult(interp, "couldn't connect to display \"",
  391.             screenName, "\"", (char *) NULL);
  392.         return (TkDisplay *) NULL;
  393.         }
  394.         dispPtr = (TkDisplay *) ckalloc(sizeof(TkDisplay));
  395.         dispPtr->display = display;
  396.         dispPtr->nextPtr = tkDisplayList;
  397.         dispPtr->name = (char *) ckalloc((unsigned) (length+1));
  398.         dispPtr->lastEventTime = CurrentTime;
  399.         strncpy(dispPtr->name, screenName, length);
  400.         dispPtr->name[length] = '\0';
  401.         dispPtr->bindInfoStale = 1;
  402.         dispPtr->numModKeyCodes = 0;
  403.         dispPtr->modKeyCodes = NULL;
  404.         OpenIM(dispPtr);
  405.         dispPtr->errorPtr = NULL;
  406.         dispPtr->deleteCount = 0;
  407.         dispPtr->commTkwin = NULL;
  408.         dispPtr->selectionInfoPtr = NULL;
  409.         dispPtr->multipleAtom = None;
  410.         dispPtr->clipWindow = NULL;
  411.         dispPtr->clipboardActive = 0;
  412.         dispPtr->clipboardAppPtr = NULL;
  413.         dispPtr->atomInit = 0;
  414.         dispPtr->cursorFont = None;
  415.         dispPtr->grabWinPtr = NULL;
  416.         dispPtr->eventualGrabWinPtr = NULL;
  417.         dispPtr->buttonWinPtr = NULL;
  418.         dispPtr->serverWinPtr = NULL;
  419.         dispPtr->firstGrabEventPtr = NULL;
  420.         dispPtr->lastGrabEventPtr = NULL;
  421.         dispPtr->grabFlags = 0;
  422.         TkInitXId(dispPtr);
  423.         dispPtr->destroyCount = 0;
  424.         dispPtr->lastDestroyRequest = 0;
  425.         dispPtr->cmapPtr = NULL;
  426.         dispPtr->focusWinPtr = NULL;
  427.         dispPtr->implicitWinPtr = NULL;
  428.         dispPtr->focusOnMapPtr = NULL;
  429.         dispPtr->forceFocus = 0;
  430.         dispPtr->stressPtr = NULL;
  431.         dispPtr->delayedMotionPtr = NULL;
  432.         Tcl_InitHashTable(&dispPtr->winTable, TCL_ONE_WORD_KEYS);
  433.         tkDisplayList = dispPtr;
  434.         break;
  435.     }
  436.     if ((strncmp(dispPtr->name, screenName, length) == 0)
  437.         && (dispPtr->name[length] == '\0')) {
  438.         break;
  439.     }
  440.     }
  441.     if (screenId >= ScreenCount(dispPtr->display)) {
  442.     sprintf(interp->result, "bad screen number \"%d\"", screenId);
  443.     return (TkDisplay *) NULL;
  444.     }
  445.     *screenPtr = screenId;
  446.     return dispPtr;
  447. }
  448.  
  449. /*
  450.  *----------------------------------------------------------------------
  451.  *
  452.  * TkGetDisplay --
  453.  *
  454.  *    Given an X display, TkGetDisplay returns the TkDisplay 
  455.  *      structure for the display.
  456.  *
  457.  * Results:
  458.  *    The return value is a pointer to information about the display,
  459.  *    or NULL if the display did not have a TkDisplay structure.
  460.  *
  461.  * Side effects:
  462.  *      None.
  463.  *
  464.  *----------------------------------------------------------------------
  465.  */
  466.  
  467. TkDisplay *
  468. TkGetDisplay(display)
  469.      Display *display;          /* X's display pointer */
  470. {
  471.     TkDisplay *dispPtr;
  472.  
  473.     for (dispPtr = tkDisplayList; dispPtr != NULL;
  474.         dispPtr = dispPtr->nextPtr) {
  475.     if (dispPtr->display == display) {
  476.         break;
  477.     }
  478.     }
  479.     return dispPtr;
  480. }
  481.  
  482. /*
  483.  *--------------------------------------------------------------
  484.  *
  485.  * AllocWindow --
  486.  *
  487.  *    This procedure creates and initializes a TkWindow structure.
  488.  *
  489.  * Results:
  490.  *    The return value is a pointer to the new window.
  491.  *
  492.  * Side effects:
  493.  *    A new window structure is allocated and all its fields are
  494.  *    initialized.
  495.  *
  496.  *--------------------------------------------------------------
  497.  */
  498.  
  499. static TkWindow *
  500. AllocWindow(dispPtr, screenNum, parentPtr)
  501.     TkDisplay *dispPtr;        /* Display associated with new window. */
  502.     int screenNum;        /* Index of screen for new window. */
  503.     TkWindow *parentPtr;    /* Parent from which this window should
  504.                  * inherit visual information.  NULL means
  505.                  * use screen defaults instead of
  506.                  * inheriting. */
  507. {
  508.     register TkWindow *winPtr;
  509.  
  510.     winPtr = (TkWindow *) ckalloc(sizeof(TkWindow));
  511.     winPtr->display = dispPtr->display;
  512.     winPtr->dispPtr = dispPtr;
  513.     winPtr->screenNum = screenNum;
  514.     if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
  515.         && (parentPtr->screenNum == winPtr->screenNum)) {
  516.     winPtr->visual = parentPtr->visual;
  517.     winPtr->depth = parentPtr->depth;
  518.     } else {
  519.     winPtr->visual = DefaultVisual(dispPtr->display, screenNum);
  520.     winPtr->depth = DefaultDepth(dispPtr->display, screenNum);
  521.     }
  522.     winPtr->window = None;
  523.     winPtr->childList = NULL;
  524.     winPtr->lastChildPtr = NULL;
  525.     winPtr->parentPtr = NULL;
  526.     winPtr->nextPtr = NULL;
  527.     winPtr->mainPtr = NULL;
  528.     winPtr->pathName = NULL;
  529.     winPtr->nameUid = NULL;
  530.     winPtr->classUid = NULL;
  531.     winPtr->changes = defChanges;
  532.     winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
  533.     winPtr->atts = defAtts;
  534.     if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
  535.         && (parentPtr->screenNum == winPtr->screenNum)) {
  536.     winPtr->atts.colormap = parentPtr->atts.colormap;
  537.     } else {
  538.     winPtr->atts.colormap = DefaultColormap(dispPtr->display, screenNum);
  539.     }
  540.     winPtr->dirtyAtts = CWEventMask|CWColormap|CWBitGravity;
  541.     winPtr->flags = 0;
  542.     winPtr->handlerList = NULL;
  543. #ifdef TK_USE_INPUT_METHODS
  544.     winPtr->inputContext = NULL;
  545. #endif /* TK_USE_INPUT_METHODS */
  546.     winPtr->tagPtr = NULL;
  547.     winPtr->numTags = 0;
  548.     winPtr->optionLevel = -1;
  549.     winPtr->selHandlerList = NULL;
  550.     winPtr->geomMgrPtr = NULL;
  551.     winPtr->geomData = NULL;
  552.     winPtr->reqWidth = winPtr->reqHeight = 1;
  553.     winPtr->internalBorderWidth = 0;
  554.     winPtr->wmInfoPtr = NULL;
  555.     winPtr->privatePtr = NULL;
  556.  
  557.     return winPtr;
  558. }
  559.  
  560. /*
  561.  *----------------------------------------------------------------------
  562.  *
  563.  * NameWindow --
  564.  *
  565.  *    This procedure is invoked to give a window a name and insert
  566.  *    the window into the hierarchy associated with a particular
  567.  *    application.
  568.  *
  569.  * Results:
  570.  *    A standard Tcl return value.
  571.  *
  572.  * Side effects:
  573.  *      See above.
  574.  *
  575.  *----------------------------------------------------------------------
  576.  */
  577.  
  578. static int
  579. NameWindow(interp, winPtr, parentPtr, name)
  580.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  581.     register TkWindow *winPtr;    /* Window that is to be named and inserted. */
  582.     TkWindow *parentPtr;    /* Pointer to logical parent for winPtr
  583.                  * (used for naming, options, etc.). */
  584.     char *name;            /* Name for winPtr;   must be unique among
  585.                  * parentPtr's children. */
  586. {
  587. #define FIXED_SIZE 200
  588.     char staticSpace[FIXED_SIZE];
  589.     char *pathName;
  590.     int new;
  591.     Tcl_HashEntry *hPtr;
  592.     int length1, length2;
  593.  
  594.     /*
  595.      * Setup all the stuff except name right away, then do the name stuff
  596.      * last.  This is so that if the name stuff fails, everything else
  597.      * will be properly initialized (needed to destroy the window cleanly
  598.      * after the naming failure).
  599.      */
  600.     winPtr->parentPtr = parentPtr;
  601.     winPtr->nextPtr = NULL;
  602.     if (parentPtr->childList == NULL) {
  603.     parentPtr->childList = winPtr;
  604.     } else {
  605.     parentPtr->lastChildPtr->nextPtr = winPtr;
  606.     }
  607.     parentPtr->lastChildPtr = winPtr;
  608.     winPtr->mainPtr = parentPtr->mainPtr;
  609.     winPtr->mainPtr->refCount++;
  610.     winPtr->nameUid = Tk_GetUid(name);
  611.  
  612.     /*
  613.      * Don't permit names that start with an upper-case letter:  this
  614.      * will just cause confusion with class names in the option database.
  615.      */
  616.  
  617.     if (isupper(UCHAR(name[0]))) {
  618.     Tcl_AppendResult(interp,
  619.         "window name starts with an upper-case letter: \"",
  620.         name, "\"", (char *) NULL);
  621.     return TCL_ERROR;
  622.     }
  623.  
  624.     /*
  625.      * To permit names of arbitrary length, must be prepared to malloc
  626.      * a buffer to hold the new path name.  To run fast in the common
  627.      * case where names are short, use a fixed-size buffer on the
  628.      * stack.
  629.      */
  630.  
  631.     length1 = strlen(parentPtr->pathName);
  632.     length2 = strlen(name);
  633.     if ((length1+length2+2) <= FIXED_SIZE) {
  634.     pathName = staticSpace;
  635.     } else {
  636.     pathName = (char *) ckalloc((unsigned) (length1+length2+2));
  637.     }
  638.     if (length1 == 1) {
  639.     pathName[0] = '.';
  640.     strcpy(pathName+1, name);
  641.     } else {
  642.     strcpy(pathName, parentPtr->pathName);
  643.     pathName[length1] = '.';
  644.     strcpy(pathName+length1+1, name);
  645.     }
  646.     hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new);
  647.     if (pathName != staticSpace) {
  648.     ckfree(pathName);
  649.     }
  650.     if (!new) {
  651.     Tcl_AppendResult(interp, "window name \"", name,
  652.         "\" already exists in parent", (char *) NULL);
  653.     return TCL_ERROR;
  654.     }
  655.     Tcl_SetHashValue(hPtr, winPtr);
  656.     winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr);
  657.     return TCL_OK;
  658. }
  659.  
  660. /*
  661.  *----------------------------------------------------------------------
  662.  *
  663.  * TkCreateMainWindow --
  664.  *
  665.  *    Make a new main window.  A main window is a special kind of
  666.  *    top-level window used as the outermost window in an
  667.  *    application.
  668.  *
  669.  * Results:
  670.  *    The return value is a token for the new window, or NULL if
  671.  *    an error prevented the new window from being created.  If
  672.  *    NULL is returned, an error message will be left in
  673.  *    interp->result.
  674.  *
  675.  * Side effects:
  676.  *    A new window structure is allocated locally;  "interp" is
  677.  *    associated with the window and registered for "send" commands
  678.  *    under "baseName".  BaseName may be extended with an instance
  679.  *    number in the form "#2" if necessary to make it globally
  680.  *    unique.  Tk-related commands are bound into interp.
  681.  *
  682.  *----------------------------------------------------------------------
  683.  */
  684.  
  685. Tk_Window
  686. TkCreateMainWindow(interp, screenName, baseName)
  687.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  688.     char *screenName;        /* Name of screen on which to create
  689.                  * window.  Empty or NULL string means
  690.                  * use DISPLAY environment variable. */
  691.     char *baseName;        /* Base name for application;  usually of the
  692.                  * form "prog instance". */
  693. {
  694.     Tk_Window tkwin;
  695.     int dummy;
  696.     Tcl_HashEntry *hPtr;
  697.     register TkMainInfo *mainPtr;
  698.     register TkWindow *winPtr;
  699.     register TkCmd *cmdPtr;
  700.  
  701.     /*
  702.      * Panic if someone updated the TkWindow structure without
  703.      * also updating the Tk_FakeWin structure (or vice versa).
  704.      */
  705.  
  706.     if (sizeof(TkWindow) != sizeof(Tk_FakeWin)) {
  707.     panic("TkWindow and Tk_FakeWin are not the same size");
  708.     }
  709.  
  710.     /*
  711.      * Create the basic TkWindow structure.
  712.      */
  713.  
  714.     tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName,
  715.         screenName);
  716.     if (tkwin == NULL) {
  717.     return NULL;
  718.     }
  719.  
  720.     /*
  721.      * Create the TkMainInfo structure for this application, and set
  722.      * up name-related information for the new window.
  723.      */
  724.  
  725.     winPtr = (TkWindow *) tkwin;
  726.     mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo));
  727.     mainPtr->winPtr = winPtr;
  728.     mainPtr->refCount = 1;
  729.     mainPtr->interp = interp;
  730.     Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS);
  731.     mainPtr->bindingTable = Tk_CreateBindingTable(interp);
  732.     mainPtr->focusPtr = NULL;
  733.     mainPtr->focusSerial = 0;
  734.     mainPtr->lastFocusPtr = NULL;
  735.     mainPtr->optionRootPtr = NULL;
  736.     Tcl_InitHashTable(&mainPtr->imageTable, TCL_STRING_KEYS);
  737.     mainPtr->strictMotif = 0;
  738. #ifndef STk_CODE
  739.     if (Tcl_LinkVar(interp, "tk_strictMotif", (char *) &mainPtr->strictMotif,
  740.         TCL_LINK_BOOLEAN) != TCL_OK) {
  741.     Tcl_ResetResult(interp);
  742.     }
  743. #endif
  744.     mainPtr->nextPtr = tkMainWindowList;
  745.     tkMainWindowList = mainPtr;
  746.     winPtr->mainPtr = mainPtr;
  747.     hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy);
  748.     Tcl_SetHashValue(hPtr, winPtr);
  749.     winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr);
  750.  
  751.     /*
  752.      * Register the interpreter for "send" purposes.
  753.      */
  754.  
  755.     winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, baseName));
  756.  
  757.     /*
  758.      * Bind in Tk's commands.
  759.      */
  760.  
  761.     for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
  762.     Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc,
  763.         (ClientData) tkwin, (void (*)()) NULL);
  764.     }
  765.  
  766.     /*
  767.      * Set variables for the intepreter.
  768.      */
  769.  
  770. #ifdef STk_CODE
  771.      Tcl_SetVar(interp, "*tk-patch-level*", TK_PATCH_LEVEL,
  772.         STk_STRINGIFY | TCL_GLOBAL_ONLY);
  773.      Tcl_SetVar(interp, "*tk-version*", TK_VERSION,
  774.         STk_STRINGIFY | TCL_GLOBAL_ONLY);
  775. #else
  776.     Tcl_SetVar(interp, "tk_patchLevel", TK_PATCH_LEVEL, TCL_GLOBAL_ONLY);
  777.     Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY);
  778. #endif
  779.  
  780.     numMainWindows++;
  781.     return tkwin;
  782. }
  783.  
  784. /*
  785.  *--------------------------------------------------------------
  786.  *
  787.  * Tk_CreateWindow --
  788.  *
  789.  *    Create a new internal or top-level window as a child of an
  790.  *    existing window.
  791.  *
  792.  * Results:
  793.  *    The return value is a token for the new window.  This
  794.  *    is not the same as X's token for the window.  If an error
  795.  *    occurred in creating the window (e.g. no such display or
  796.  *    screen), then an error message is left in interp->result and
  797.  *    NULL is returned.
  798.  *
  799.  * Side effects:
  800.  *    A new window structure is allocated locally.  An X
  801.  *    window is not initially created, but will be created
  802.  *    the first time the window is mapped.
  803.  *
  804.  *--------------------------------------------------------------
  805.  */
  806.  
  807. Tk_Window
  808. Tk_CreateWindow(interp, parent, name, screenName)
  809.     Tcl_Interp *interp;        /* Interpreter to use for error reporting.
  810.                  * Interp->result is assumed to be
  811.                  * initialized by the caller. */
  812.     Tk_Window parent;        /* Token for parent of new window. */
  813.     char *name;            /* Name for new window.  Must be unique
  814.                  * among parent's children. */
  815.     char *screenName;        /* If NULL, new window will be internal on
  816.                  * same screen as its parent.  If non-NULL,
  817.                  * gives name of screen on which to create
  818.                  * new window;  window will be a top-level
  819.                  * window. */
  820. {
  821.     TkWindow *parentPtr = (TkWindow *) parent;
  822.     TkWindow *winPtr;
  823.  
  824.     if (screenName == NULL) {
  825.     winPtr = AllocWindow(parentPtr->dispPtr, parentPtr->screenNum,
  826.         parentPtr);
  827.     if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) {
  828.         Tk_DestroyWindow((Tk_Window) winPtr);
  829.         return NULL;
  830.     } else {
  831.       return (Tk_Window) winPtr;
  832.     }
  833.     } else {
  834.     return CreateTopLevelWindow(interp, parent, name, screenName);
  835.     }
  836. }
  837.  
  838. /*
  839.  *----------------------------------------------------------------------
  840.  *
  841.  * Tk_CreateWindowFromPath --
  842.  *
  843.  *    This procedure is similar to Tk_CreateWindow except that
  844.  *    it uses a path name to create the window, rather than a
  845.  *    parent and a child name.
  846.  *
  847.  * Results:
  848.  *    The return value is a token for the new window.  This
  849.  *    is not the same as X's token for the window.  If an error
  850.  *    occurred in creating the window (e.g. no such display or
  851.  *    screen), then an error message is left in interp->result and
  852.  *    NULL is returned.
  853.  *
  854.  * Side effects:
  855.  *    A new window structure is allocated locally.  An X
  856.  *    window is not initially created, but will be created
  857.  *    the first time the window is mapped.
  858.  *
  859.  *----------------------------------------------------------------------
  860.  */
  861.  
  862. Tk_Window
  863. Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName)
  864.     Tcl_Interp *interp;        /* Interpreter to use for error reporting.
  865.                  * Interp->result is assumed to be
  866.                  * initialized by the caller. */
  867.     Tk_Window tkwin;        /* Token for any window in application
  868.                  * that is to contain new window. */
  869.     char *pathName;        /* Path name for new window within the
  870.                  * application of tkwin.  The parent of
  871.                  * this window must already exist, but
  872.                  * the window itself must not exist. */
  873.     char *screenName;        /* If NULL, new window will be on same
  874.                  * screen as its parent.  If non-NULL,
  875.                  * gives name of screen on which to create
  876.                  * new window;  window will be a top-level
  877.                  * window. */
  878. {
  879. #define FIXED_SPACE 5
  880.     char fixedSpace[FIXED_SPACE+1];
  881.     char *p;
  882.     Tk_Window parent;
  883.     int numChars;
  884.  
  885.     /*
  886.      * Strip the parent's name out of pathName (it's everything up
  887.      * to the last dot).  There are two tricky parts: (a) must
  888.      * copy the parent's name somewhere else to avoid modifying
  889.      * the pathName string (for large names, space for the copy
  890.      * will have to be malloc'ed);  (b) must special-case the
  891.      * situation where the parent is ".".
  892.      */
  893.  
  894.     p = strrchr(pathName, '.');
  895.     if (p == NULL) {
  896.     Tcl_AppendResult(interp, "bad window path name \"", pathName,
  897.         "\"", (char *) NULL);
  898.     return NULL;
  899.     }
  900.     numChars = p-pathName;
  901.     if (numChars > FIXED_SPACE) {
  902.     p = (char *) ckalloc((unsigned) (numChars+1));
  903.     } else {
  904.     p = fixedSpace;
  905.     }
  906.     if (numChars == 0) {
  907.     *p = '.';
  908.     p[1] = '\0';
  909.     } else {
  910.     strncpy(p, pathName, (size_t) numChars);
  911.     p[numChars] = '\0';
  912.     }
  913.  
  914.     /*
  915.      * Find the parent window.
  916.      */
  917.  
  918.     parent = Tk_NameToWindow(interp, p, tkwin);
  919.     if (p != fixedSpace) {
  920.     ckfree(p);
  921.     }
  922.     if (parent == NULL) {
  923.     return NULL;
  924.     }
  925.  
  926.     /*
  927.      * Create the window.
  928.      */
  929.  
  930.     if (screenName == NULL) {
  931.     TkWindow *parentPtr = (TkWindow *) parent;
  932.     TkWindow *winPtr;
  933.  
  934.     winPtr = AllocWindow(parentPtr->dispPtr, parentPtr->screenNum,
  935.         parentPtr);
  936.     if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1)
  937.         != TCL_OK) {
  938.         Tk_DestroyWindow((Tk_Window) winPtr);
  939.         return NULL;
  940.     } else {
  941.         return (Tk_Window) winPtr;
  942.     }
  943.     } else {
  944.     return CreateTopLevelWindow(interp, parent, pathName+numChars+1,
  945.         screenName);
  946.     }
  947. }
  948.  
  949. /*
  950.  *--------------------------------------------------------------
  951.  *
  952.  * Tk_DestroyWindow --
  953.  *
  954.  *    Destroy an existing window.  After this call, the caller
  955.  *    should never again use the token.
  956.  *
  957.  * Results:
  958.  *    None.
  959.  *
  960.  * Side effects:
  961.  *    The window is deleted, along with all of its children.
  962.  *    Relevant callback procedures are invoked.
  963.  *
  964.  *--------------------------------------------------------------
  965.  */
  966.  
  967. void
  968. Tk_DestroyWindow(tkwin)
  969.     Tk_Window tkwin;        /* Window to destroy. */
  970. {
  971.     TkWindow *winPtr = (TkWindow *) tkwin;
  972.     TkDisplay *dispPtr = winPtr->dispPtr;
  973.     XEvent event;
  974.  
  975.     if (winPtr->flags & TK_ALREADY_DEAD) {
  976.     /*
  977.      * A destroy event binding caused the window to be destroyed
  978.      * again.  Ignore the request.
  979.      */
  980.  
  981.     return;
  982.     }
  983.     winPtr->flags |= TK_ALREADY_DEAD;
  984.  
  985.     /*
  986.      * Some cleanup needs to be done immediately, rather than later,
  987.      * because it needs information that will be destoyed before we
  988.      * get to the main cleanup point.  For example, TkFocusDeadWindow
  989.      * needs to access the parentPtr field from a window, but if
  990.      * a Destroy event handler deletes the window's parent this
  991.      * field will be NULL before the main cleanup point is reached.
  992.      */
  993.  
  994.     TkFocusDeadWindow(winPtr);
  995.  
  996.     /*
  997.      * If this is a main window, remove it from the list of main
  998.      * windows.  This needs to be done now (rather than later with
  999.      * all the other main window cleanup) to handle situations where
  1000.      * a destroy binding for a window calls "exit".  In this case
  1001.      * the child window cleanup isn't complete when exit is called,
  1002.      * so the reference count of its application doesn't go to zero
  1003.      * when exit calls Tk_DestroyWindow on ".", so the main window
  1004.      * doesn't get removed from the list and exit loops infinitely.
  1005.      * Even worse, if "destroy ." is called by the destroy binding
  1006.      * before calling "exit", "exit" will attempt to destroy
  1007.      * mainPtr->winPtr, which no longer exists, and there may be a
  1008.      * core dump.
  1009.      */
  1010.  
  1011.     if (winPtr->mainPtr->winPtr == winPtr) {
  1012.     if (tkMainWindowList == winPtr->mainPtr) {
  1013.         tkMainWindowList = winPtr->mainPtr->nextPtr;
  1014.     } else {
  1015.         TkMainInfo *prevPtr;
  1016.  
  1017.         for (prevPtr = tkMainWindowList;
  1018.             prevPtr->nextPtr != winPtr->mainPtr;
  1019.             prevPtr = prevPtr->nextPtr) {
  1020.         /* Empty loop body. */
  1021.         }
  1022.         prevPtr->nextPtr = winPtr->mainPtr->nextPtr;
  1023.     }
  1024.     numMainWindows--;
  1025.     }
  1026.  
  1027.     /*
  1028.      * Recursively destroy children.
  1029.      */
  1030.  
  1031.     dispPtr->destroyCount++;
  1032.     while (winPtr->childList != NULL) {
  1033.     TkWindow *childPtr;
  1034.  
  1035.     childPtr = winPtr->childList;
  1036.     childPtr->flags |= TK_PARENT_DESTROYED;
  1037.     Tk_DestroyWindow((Tk_Window) childPtr);
  1038.     if (winPtr->childList == childPtr) {
  1039.         /*
  1040.          * The child didn't remove itself from the child list, so
  1041.          * let's remove it here.  This can happen in some strange
  1042.          * conditions, such as when a Delete event handler for a
  1043.          * window deletes the window's parent.
  1044.          */
  1045.  
  1046.         winPtr->childList = childPtr->nextPtr;
  1047.         childPtr->parentPtr = NULL;
  1048.     }
  1049.     }
  1050.  
  1051.     /*
  1052.      * Generate a DestroyNotify event.  In order for the DestroyNotify
  1053.      * event to be processed correctly, need to make sure the window
  1054.      * exists.  This is a bit of a kludge, and may be unnecessarily
  1055.      * expensive, but without it no event handlers will get called for
  1056.      * windows that don't exist yet.
  1057.      *
  1058.      * Note: if the window's pathName is NULL it means that the window
  1059.      * was not successfully initialized in the first place, so we should
  1060.      * not make the window exist or generate the event.
  1061.      */
  1062.  
  1063.     if (winPtr->pathName != NULL) {
  1064.     if (winPtr->window == None) {
  1065.         Tk_MakeWindowExist(tkwin);
  1066.     }
  1067.     event.type = DestroyNotify;
  1068.     event.xdestroywindow.serial =
  1069.         LastKnownRequestProcessed(winPtr->display);
  1070.     event.xdestroywindow.send_event = False;
  1071.     event.xdestroywindow.display = winPtr->display;
  1072.     event.xdestroywindow.event = winPtr->window;
  1073.     event.xdestroywindow.window = winPtr->window;
  1074.     Tk_HandleEvent(&event);
  1075.     }
  1076.  
  1077.     /*
  1078.      * Cleanup the data structures associated with this window.
  1079.      */
  1080.  
  1081.     if (winPtr->flags & TK_TOP_LEVEL) {
  1082.     TkWmDeadWindow(winPtr);
  1083.     } else if (winPtr->flags & TK_WM_COLORMAP_WINDOW) {
  1084.     TkWmRemoveFromColormapWindows(winPtr);
  1085.     }
  1086.     if (winPtr->window != None) {
  1087. #if defined(MAC_TCL) || defined(__WIN32__)
  1088.     XDestroyWindow(winPtr->display, winPtr->window);
  1089. #else
  1090.     if ((winPtr->flags & TK_TOP_LEVEL)
  1091.         || !(winPtr->flags & TK_PARENT_DESTROYED)) {
  1092.         /*
  1093.          * The parent has already been destroyed and this isn't
  1094.          * a top-level window, so this window will be destroyed
  1095.          * implicitly when the parent's X window is destroyed;
  1096.          * it's much faster not to do an explicit destroy of this
  1097.          * X window.
  1098.          */
  1099.  
  1100.         dispPtr->lastDestroyRequest = NextRequest(winPtr->display);
  1101.         XDestroyWindow(winPtr->display, winPtr->window);
  1102.     }
  1103. #endif
  1104.     TkFreeWindowId(dispPtr, winPtr->window);
  1105.     Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->winTable,
  1106.         (char *) winPtr->window));
  1107.     winPtr->window = None;
  1108.     }
  1109.     dispPtr->destroyCount--;
  1110.     UnlinkWindow(winPtr);
  1111.     TkEventDeadWindow(winPtr);
  1112. #ifdef TK_USE_INPUT_METHODS
  1113.     if (winPtr->inputContext != NULL) {
  1114.     XDestroyIC(winPtr->inputContext);
  1115.     }
  1116. #endif /* TK_USE_INPUT_METHODS */
  1117.     if (winPtr->tagPtr != NULL) {
  1118.     TkFreeBindingTags(winPtr);
  1119.     }
  1120.     TkOptionDeadWindow(winPtr);
  1121.     TkSelDeadWindow(winPtr);
  1122.     TkGrabDeadWindow(winPtr);
  1123.     if (winPtr->mainPtr != NULL) {
  1124.     if (winPtr->pathName != NULL) {
  1125.         Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable,
  1126.             (ClientData) winPtr->pathName);
  1127.         Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable,
  1128.             winPtr->pathName));
  1129.     }
  1130.     winPtr->mainPtr->refCount--;
  1131.     if (winPtr->mainPtr->refCount == 0) {
  1132.         register TkCmd *cmdPtr;
  1133.  
  1134.         /*
  1135.          * We just deleted the last window in the application.  Delete
  1136.          * the TkMainInfo structure too and replace all of Tk's commands
  1137.          * with dummy commands that return errors.  Also delete the
  1138.          * "send" command to unregister the interpreter.
  1139.              *
  1140.              * NOTE: Only replace the commands it if the interpreter is
  1141.              * not being deleted. If it *is*, the interpreter cleanup will
  1142.              * do all the needed work.
  1143.          */
  1144.  
  1145.             if ((winPtr->mainPtr->interp != NULL) &&
  1146.                     (!Tcl_InterpDeleted(winPtr->mainPtr->interp))) {
  1147.                 for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
  1148.                     Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name,
  1149.                             TkDeadAppCmd, (ClientData) NULL,
  1150.                             (void (*)()) NULL);
  1151.                 }
  1152.                 Tcl_CreateCommand(winPtr->mainPtr->interp, "send",
  1153.                         TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL);
  1154. #ifndef STk_CODE
  1155.                 Tcl_UnlinkVar(winPtr->mainPtr->interp, "tk_strictMotif");
  1156. #endif
  1157.             }
  1158.         Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable);
  1159.         Tk_DeleteBindingTable(winPtr->mainPtr->bindingTable);
  1160.         TkDeleteAllImages(winPtr->mainPtr);
  1161.         ckfree((char *) winPtr->mainPtr);
  1162.     }
  1163.     }
  1164.     ckfree((char *) winPtr);
  1165. }
  1166.  
  1167. /*
  1168.  *--------------------------------------------------------------
  1169.  *
  1170.  * Tk_MapWindow --
  1171.  *
  1172.  *    Map a window within its parent.  This may require the
  1173.  *    window and/or its parents to actually be created.
  1174.  *
  1175.  * Results:
  1176.  *    None.
  1177.  *
  1178.  * Side effects:
  1179.  *    The given window will be mapped.  Windows may also
  1180.  *    be created.
  1181.  *
  1182.  *--------------------------------------------------------------
  1183.  */
  1184.  
  1185. void
  1186. Tk_MapWindow(tkwin)
  1187.     Tk_Window tkwin;        /* Token for window to map. */
  1188. {
  1189.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1190.     XEvent event;
  1191.  
  1192.     if (winPtr->flags & TK_MAPPED) {
  1193.     return;
  1194.     }
  1195.     if (winPtr->window == None) {
  1196.     Tk_MakeWindowExist(tkwin);
  1197.     }
  1198.     if (winPtr->flags & TK_TOP_LEVEL) {
  1199.     /*
  1200.      * Lots of special processing has to be done for top-level
  1201.      * windows.  Let tkWm.c handle everything itself.
  1202.      */
  1203.  
  1204.     TkWmMapWindow(winPtr);
  1205.     return;
  1206.     }
  1207.     winPtr->flags |= TK_MAPPED;
  1208.     XMapWindow(winPtr->display, winPtr->window);
  1209.     event.type = MapNotify;
  1210.     event.xmap.serial = LastKnownRequestProcessed(winPtr->display);
  1211.     event.xmap.send_event = False;
  1212.     event.xmap.display = winPtr->display;
  1213.     event.xmap.event = winPtr->window;
  1214.     event.xmap.window = winPtr->window;
  1215.     event.xmap.override_redirect = winPtr->atts.override_redirect;
  1216.     Tk_HandleEvent(&event);
  1217. }
  1218.  
  1219. /*
  1220.  *--------------------------------------------------------------
  1221.  *
  1222.  * Tk_MakeWindowExist --
  1223.  *
  1224.  *    Ensure that a particular window actually exists.  This
  1225.  *    procedure shouldn't normally need to be invoked from
  1226.  *    outside the Tk package, but may be needed if someone
  1227.  *    wants to manipulate a window before mapping it.
  1228.  *
  1229.  * Results:
  1230.  *    None.
  1231.  *
  1232.  * Side effects:
  1233.  *    When the procedure returns, the X window associated with
  1234.  *    tkwin is guaranteed to exist.  This may require the
  1235.  *    window's ancestors to be created also.
  1236.  *
  1237.  *--------------------------------------------------------------
  1238.  */
  1239.  
  1240. void
  1241. Tk_MakeWindowExist(tkwin)
  1242.     Tk_Window tkwin;        /* Token for window. */
  1243. {
  1244.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1245.     TkWindow *winPtr2;
  1246.     Window parent;
  1247.     Tcl_HashEntry *hPtr;
  1248.     int new;
  1249.  
  1250.     if (winPtr->window != None) {
  1251.     return;
  1252.     }
  1253.  
  1254.     if ((winPtr->parentPtr == NULL) || (winPtr->flags & TK_TOP_LEVEL)) {
  1255.     parent = XRootWindow(winPtr->display, winPtr->screenNum);
  1256.     } else {
  1257.     if (winPtr->parentPtr->window == None) {
  1258.         Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr);
  1259.     }
  1260.     parent = winPtr->parentPtr->window;
  1261.     }
  1262.  
  1263.     winPtr->window = TkMakeWindow(winPtr, parent);
  1264.     hPtr = Tcl_CreateHashEntry(&winPtr->dispPtr->winTable,
  1265.         (char *) winPtr->window, &new);
  1266.     Tcl_SetHashValue(hPtr, winPtr);
  1267.     winPtr->dirtyAtts = 0;
  1268.     winPtr->dirtyChanges = 0;
  1269. #ifdef TK_USE_INPUT_METHODS
  1270.     winPtr->inputContext = NULL;
  1271. #endif /* TK_USE_INPUT_METHODS */
  1272.  
  1273.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1274.     /*
  1275.      * If any siblings higher up in the stacking order have already
  1276.      * been created then move this window to its rightful position
  1277.      * in the stacking order.
  1278.      *
  1279.      * NOTE: this code ignores any changes anyone might have made
  1280.      * to the sibling and stack_mode field of the window's attributes,
  1281.      * so it really isn't safe for these to be manipulated except
  1282.      * by calling Tk_RestackWindow.
  1283.      */
  1284.  
  1285.     for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL;
  1286.         winPtr2 = winPtr2->nextPtr) {
  1287.         if ((winPtr2->window != None) && !(winPtr2->flags & TK_TOP_LEVEL)) {
  1288.         XWindowChanges changes;
  1289.         changes.sibling = winPtr2->window;
  1290.         changes.stack_mode = Below;
  1291.         XConfigureWindow(winPtr->display, winPtr->window,
  1292.             CWSibling|CWStackMode, &changes);
  1293.         break;
  1294.         }
  1295.     }
  1296.  
  1297.     /*
  1298.      * If this window has a different colormap than its parent, add
  1299.      * the window to the WM_COLORMAP_WINDOWS property for its top-level.
  1300.      */
  1301.  
  1302.     if ((winPtr->parentPtr != NULL) &&
  1303.         (winPtr->atts.colormap != winPtr->parentPtr->atts.colormap)) {
  1304.         TkWmAddToColormapWindows(winPtr);
  1305.         winPtr->flags |= TK_WM_COLORMAP_WINDOW;
  1306.     }
  1307.     }
  1308.  
  1309.     /*
  1310.      * Issue a ConfigureNotify event if there were deferred configuration
  1311.      * changes (but skip it if the window is being deleted;  the
  1312.      * ConfigureNotify event could cause problems if we're being called
  1313.      * from Tk_DestroyWindow under some conditions).
  1314.      */
  1315.  
  1316.     if ((winPtr->flags & TK_NEED_CONFIG_NOTIFY)
  1317.         && !(winPtr->flags & TK_ALREADY_DEAD)){
  1318.     winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY;
  1319.     DoConfigureNotify(winPtr);
  1320.     }
  1321. }
  1322.  
  1323. /*
  1324.  *--------------------------------------------------------------
  1325.  *
  1326.  * Tk_UnmapWindow, etc. --
  1327.  *
  1328.  *    There are several procedures under here, each of which
  1329.  *    mirrors an existing X procedure.  In addition to performing
  1330.  *    the functions of the corresponding procedure, each
  1331.  *    procedure also updates the local window structure and
  1332.  *    synthesizes an X event (if the window's structure is being
  1333.  *    managed internally).
  1334.  *
  1335.  * Results:
  1336.  *    See the manual entries.
  1337.  *
  1338.  * Side effects:
  1339.  *    See the manual entries.
  1340.  *
  1341.  *--------------------------------------------------------------
  1342.  */
  1343.  
  1344. void
  1345. Tk_UnmapWindow(tkwin)
  1346.     Tk_Window tkwin;        /* Token for window to unmap. */
  1347. {
  1348.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1349.  
  1350.     if (!(winPtr->flags & TK_MAPPED) || (winPtr->flags & TK_ALREADY_DEAD)) {
  1351.     return;
  1352.     }
  1353.     if (winPtr->flags & TK_TOP_LEVEL) {
  1354.     /*
  1355.      * Special processing has to be done for top-level windows.  Let
  1356.      * tkWm.c handle everything itself.
  1357.      */
  1358.  
  1359.     TkWmUnmapWindow(winPtr);
  1360.     return;
  1361.     }
  1362.     winPtr->flags &= ~TK_MAPPED;
  1363.     XUnmapWindow(winPtr->display, winPtr->window);
  1364.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1365.     XEvent event;
  1366.  
  1367.     event.type = UnmapNotify;
  1368.     event.xunmap.serial = LastKnownRequestProcessed(winPtr->display);
  1369.     event.xunmap.send_event = False;
  1370.     event.xunmap.display = winPtr->display;
  1371.     event.xunmap.event = winPtr->window;
  1372.     event.xunmap.window = winPtr->window;
  1373.     event.xunmap.from_configure = False;
  1374.     Tk_HandleEvent(&event);
  1375.     }
  1376. }
  1377.  
  1378. void
  1379. Tk_ConfigureWindow(tkwin, valueMask, valuePtr)
  1380.     Tk_Window tkwin;        /* Window to re-configure. */
  1381.     unsigned int valueMask;    /* Mask indicating which parts of
  1382.                  * *valuePtr are to be used. */
  1383.     XWindowChanges *valuePtr;    /* New values. */
  1384. {
  1385.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1386.  
  1387.     if (valueMask & CWX) {
  1388.     winPtr->changes.x = valuePtr->x;
  1389.     }
  1390.     if (valueMask & CWY) {
  1391.     winPtr->changes.y = valuePtr->y;
  1392.     }
  1393.     if (valueMask & CWWidth) {
  1394.     winPtr->changes.width = valuePtr->width;
  1395.     }
  1396.     if (valueMask & CWHeight) {
  1397.     winPtr->changes.height = valuePtr->height;
  1398.     }
  1399.     if (valueMask & CWBorderWidth) {
  1400.     winPtr->changes.border_width = valuePtr->border_width;
  1401.     }
  1402.     if (valueMask & (CWSibling|CWStackMode)) {
  1403.     panic("Can't set sibling or stack mode from Tk_ConfigureWindow.");
  1404.     }
  1405.  
  1406.     if (winPtr->window != None) {
  1407.     XConfigureWindow(winPtr->display, winPtr->window,
  1408.         valueMask, valuePtr);
  1409.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1410.         DoConfigureNotify(winPtr);
  1411.     }
  1412.     } else {
  1413.     winPtr->dirtyChanges |= valueMask;
  1414.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1415.     }
  1416. }
  1417.  
  1418. void
  1419. Tk_MoveWindow(tkwin, x, y)
  1420.     Tk_Window tkwin;        /* Window to move. */
  1421.     int x, y;            /* New location for window (within
  1422.                  * parent). */
  1423. {
  1424.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1425.  
  1426.     winPtr->changes.x = x;
  1427.     winPtr->changes.y = y;
  1428.     if (winPtr->window != None) {
  1429.     XMoveWindow(winPtr->display, winPtr->window, x, y);
  1430.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1431.         DoConfigureNotify(winPtr);
  1432.     }
  1433.     } else {
  1434.     winPtr->dirtyChanges |= CWX|CWY;
  1435.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1436.     }
  1437. }
  1438.  
  1439. void
  1440. Tk_ResizeWindow(tkwin, width, height)
  1441.     Tk_Window tkwin;        /* Window to resize. */
  1442.     int width, height;        /* New dimensions for window. */
  1443. {
  1444.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1445.  
  1446.     winPtr->changes.width = (unsigned) width;
  1447.     winPtr->changes.height = (unsigned) height;
  1448.     if (winPtr->window != None) {
  1449.     XResizeWindow(winPtr->display, winPtr->window, (unsigned) width,
  1450.         (unsigned) height);
  1451.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1452.         DoConfigureNotify(winPtr);
  1453.     }
  1454.     } else {
  1455.     winPtr->dirtyChanges |= CWWidth|CWHeight;
  1456.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1457.     }
  1458. }
  1459.  
  1460. void
  1461. Tk_MoveResizeWindow(tkwin, x, y, width, height)
  1462.     Tk_Window tkwin;        /* Window to move and resize. */
  1463.     int x, y;            /* New location for window (within
  1464.                  * parent). */
  1465.     int width, height;        /* New dimensions for window. */
  1466. {
  1467.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1468.  
  1469.     winPtr->changes.x = x;
  1470.     winPtr->changes.y = y;
  1471.     winPtr->changes.width = (unsigned) width;
  1472.     winPtr->changes.height = (unsigned) height;
  1473.     if (winPtr->window != None) {
  1474.     XMoveResizeWindow(winPtr->display, winPtr->window, x, y,
  1475.         (unsigned) width, (unsigned) height);
  1476.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1477.         DoConfigureNotify(winPtr);
  1478.     }
  1479.     } else {
  1480.     winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight;
  1481.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1482.     }
  1483. }
  1484.  
  1485. void
  1486. Tk_SetWindowBorderWidth(tkwin, width)
  1487.     Tk_Window tkwin;        /* Window to modify. */
  1488.     int width;            /* New border width for window. */
  1489. {
  1490.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1491.  
  1492.     winPtr->changes.border_width = width;
  1493.     if (winPtr->window != None) {
  1494.     XSetWindowBorderWidth(winPtr->display, winPtr->window,
  1495.         (unsigned) width);
  1496.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1497.         DoConfigureNotify(winPtr);
  1498.     }
  1499.     } else {
  1500.     winPtr->dirtyChanges |= CWBorderWidth;
  1501.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1502.     }
  1503. }
  1504.  
  1505. void
  1506. Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr)
  1507.     Tk_Window tkwin;        /* Window to manipulate. */
  1508.     unsigned long valueMask;    /* OR'ed combination of bits,
  1509.                  * indicating which fields of
  1510.                  * *attsPtr are to be used. */
  1511.     register XSetWindowAttributes *attsPtr;
  1512.                 /* New values for some attributes. */
  1513. {
  1514.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1515.  
  1516.     if (valueMask & CWBackPixmap) {
  1517.     winPtr->atts.background_pixmap = attsPtr->background_pixmap;
  1518.     }
  1519.     if (valueMask & CWBackPixel) {
  1520.     winPtr->atts.background_pixel = attsPtr->background_pixel;
  1521.     }
  1522.     if (valueMask & CWBorderPixmap) {
  1523.     winPtr->atts.border_pixmap = attsPtr->border_pixmap;
  1524.     }
  1525.     if (valueMask & CWBorderPixel) {
  1526.     winPtr->atts.border_pixel = attsPtr->border_pixel;
  1527.     }
  1528.     if (valueMask & CWBitGravity) {
  1529.     winPtr->atts.bit_gravity = attsPtr->bit_gravity;
  1530.     }
  1531.     if (valueMask & CWWinGravity) {
  1532.     winPtr->atts.win_gravity = attsPtr->win_gravity;
  1533.     }
  1534.     if (valueMask & CWBackingStore) {
  1535.     winPtr->atts.backing_store = attsPtr->backing_store;
  1536.     }
  1537.     if (valueMask & CWBackingPlanes) {
  1538.     winPtr->atts.backing_planes = attsPtr->backing_planes;
  1539.     }
  1540.     if (valueMask & CWBackingPixel) {
  1541.     winPtr->atts.backing_pixel = attsPtr->backing_pixel;
  1542.     }
  1543.     if (valueMask & CWOverrideRedirect) {
  1544.     winPtr->atts.override_redirect = attsPtr->override_redirect;
  1545.     }
  1546.     if (valueMask & CWSaveUnder) {
  1547.     winPtr->atts.save_under = attsPtr->save_under;
  1548.     }
  1549.     if (valueMask & CWEventMask) {
  1550.     winPtr->atts.event_mask = attsPtr->event_mask;
  1551.     }
  1552.     if (valueMask & CWDontPropagate) {
  1553.     winPtr->atts.do_not_propagate_mask
  1554.         = attsPtr->do_not_propagate_mask;
  1555.     }
  1556.     if (valueMask & CWColormap) {
  1557.     winPtr->atts.colormap = attsPtr->colormap;
  1558.     }
  1559.     if (valueMask & CWCursor) {
  1560.     winPtr->atts.cursor = attsPtr->cursor;
  1561.     }
  1562.  
  1563.     if (winPtr->window != None) {
  1564.     XChangeWindowAttributes(winPtr->display, winPtr->window,
  1565.         valueMask, attsPtr);
  1566.     } else {
  1567.     winPtr->dirtyAtts |= valueMask;
  1568.     }
  1569. }
  1570.  
  1571. void
  1572. Tk_SetWindowBackground(tkwin, pixel)
  1573.     Tk_Window tkwin;        /* Window to manipulate. */
  1574.     unsigned long pixel;    /* Pixel value to use for
  1575.                  * window's background. */
  1576. {
  1577.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1578.  
  1579.     winPtr->atts.background_pixel = pixel;
  1580.  
  1581.     if (winPtr->window != None) {
  1582.     XSetWindowBackground(winPtr->display, winPtr->window, pixel);
  1583.     } else {
  1584.     winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixmap)
  1585.         | CWBackPixel;
  1586.     }
  1587. }
  1588.  
  1589. void
  1590. Tk_SetWindowBackgroundPixmap(tkwin, pixmap)
  1591.     Tk_Window tkwin;        /* Window to manipulate. */
  1592.     Pixmap pixmap;        /* Pixmap to use for window's
  1593.                  * background. */
  1594. {
  1595.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1596.  
  1597.     winPtr->atts.background_pixmap = pixmap;
  1598.  
  1599.     if (winPtr->window != None) {
  1600.     XSetWindowBackgroundPixmap(winPtr->display,
  1601.         winPtr->window, pixmap);
  1602.     } else {
  1603.     winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixel)
  1604.         | CWBackPixmap;
  1605.     }
  1606. }
  1607.  
  1608. void
  1609. Tk_SetWindowBorder(tkwin, pixel)
  1610.     Tk_Window tkwin;        /* Window to manipulate. */
  1611.     unsigned long pixel;    /* Pixel value to use for
  1612.                  * window's border. */
  1613. {
  1614.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1615.  
  1616.     winPtr->atts.border_pixel = pixel;
  1617.  
  1618.     if (winPtr->window != None) {
  1619.     XSetWindowBorder(winPtr->display, winPtr->window, pixel);
  1620.     } else {
  1621.     winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixmap)
  1622.         | CWBorderPixel;
  1623.     }
  1624. }
  1625.  
  1626. void
  1627. Tk_SetWindowBorderPixmap(tkwin, pixmap)
  1628.     Tk_Window tkwin;        /* Window to manipulate. */
  1629.     Pixmap pixmap;        /* Pixmap to use for window's
  1630.                  * border. */
  1631. {
  1632.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1633.  
  1634.     winPtr->atts.border_pixmap = pixmap;
  1635.  
  1636.     if (winPtr->window != None) {
  1637.     XSetWindowBorderPixmap(winPtr->display,
  1638.         winPtr->window, pixmap);
  1639.     } else {
  1640.     winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixel)
  1641.         | CWBorderPixmap;
  1642.     }
  1643. }
  1644.  
  1645. void
  1646. Tk_DefineCursor(tkwin, cursor)
  1647.     Tk_Window tkwin;        /* Window to manipulate. */
  1648.     Tk_Cursor cursor;        /* Cursor to use for window (may be None). */
  1649. {
  1650.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1651.  
  1652. #ifdef MAC_TCL
  1653.     winPtr->atts.cursor = (XCursor) cursor;
  1654. #else
  1655.     winPtr->atts.cursor = (Cursor) cursor;
  1656. #endif
  1657.     
  1658.     if (winPtr->window != None) {
  1659.     XDefineCursor(winPtr->display, winPtr->window, winPtr->atts.cursor);
  1660.     } else {
  1661.     winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor;
  1662.     }
  1663. }
  1664.  
  1665. void
  1666. Tk_UndefineCursor(tkwin)
  1667.     Tk_Window tkwin;        /* Window to manipulate. */
  1668. {
  1669.     Tk_DefineCursor(tkwin, None);
  1670. }
  1671.  
  1672. void
  1673. Tk_SetWindowColormap(tkwin, colormap)
  1674.     Tk_Window tkwin;        /* Window to manipulate. */
  1675.     Colormap colormap;        /* Colormap to use for window. */
  1676. {
  1677.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1678.  
  1679.     winPtr->atts.colormap = colormap;
  1680.  
  1681.     if (winPtr->window != None) {
  1682.     XSetWindowColormap(winPtr->display, winPtr->window, colormap);
  1683.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1684.         TkWmAddToColormapWindows(winPtr);
  1685.         winPtr->flags |= TK_WM_COLORMAP_WINDOW;
  1686.     }
  1687.     } else {
  1688.     winPtr->dirtyAtts |= CWColormap;
  1689.     }
  1690. }
  1691.  
  1692. /*
  1693.  *----------------------------------------------------------------------
  1694.  *
  1695.  * Tk_SetWindowVisual --
  1696.  *
  1697.  *    This procedure is called to specify a visual to be used
  1698.  *    for a Tk window when it is created.  This procedure, if
  1699.  *    called at all, must be called before the X window is created
  1700.  *    (i.e. before Tk_MakeWindowExist is called).
  1701.  *
  1702.  * Results:
  1703.  *    The return value is 1 if successful, or 0 if the X window has
  1704.  *    been already created.
  1705.  *
  1706.  * Side effects:
  1707.  *    The information given is stored for when the window is created.
  1708.  *
  1709.  *----------------------------------------------------------------------
  1710.  */
  1711.  
  1712. int
  1713. Tk_SetWindowVisual(tkwin, visual, depth, colormap)
  1714.     Tk_Window tkwin;        /* Window to manipulate. */
  1715.     Visual *visual;        /* New visual for window. */
  1716.     int depth;            /* New depth for window. */
  1717.     Colormap colormap;        /* An appropriate colormap for the visual. */
  1718. {
  1719.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1720.  
  1721.     if( winPtr->window != None ){
  1722.     /* Too late! */
  1723.     return 0;
  1724.     }
  1725.  
  1726.     winPtr->visual = visual;
  1727.     winPtr->depth = depth;
  1728.     winPtr->atts.colormap = colormap;
  1729.  
  1730.     /*
  1731.      * The following code is needed to make sure that the window doesn't
  1732.      * inherit the parent's border pixmap, which would result in a BadMatch
  1733.      * error.
  1734.      */
  1735.  
  1736.     if (!(winPtr->dirtyAtts & CWBorderPixmap)) {
  1737.     winPtr->dirtyAtts |= CWBorderPixel;
  1738.     }
  1739.     return 1;
  1740. }
  1741.  
  1742. /*
  1743.  *----------------------------------------------------------------------
  1744.  *
  1745.  * DoConfigureNotify --
  1746.  *
  1747.  *    Generate a ConfigureNotify event describing the current
  1748.  *    configuration of a window.
  1749.  *
  1750.  * Results:
  1751.  *    None.
  1752.  *
  1753.  * Side effects:
  1754.  *    An event is generated and processed by Tk_HandleEvent.
  1755.  *
  1756.  *----------------------------------------------------------------------
  1757.  */
  1758.  
  1759. static void
  1760. DoConfigureNotify(winPtr)
  1761.     register TkWindow *winPtr;        /* Window whose configuration
  1762.                      * was just changed. */
  1763. {
  1764.     XEvent event;
  1765.  
  1766.     event.type = ConfigureNotify;
  1767.     event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display);
  1768.     event.xconfigure.send_event = False;
  1769.     event.xconfigure.display = winPtr->display;
  1770.     event.xconfigure.event = winPtr->window;
  1771.     event.xconfigure.window = winPtr->window;
  1772.     event.xconfigure.x = winPtr->changes.x;
  1773.     event.xconfigure.y = winPtr->changes.y;
  1774.     event.xconfigure.width = winPtr->changes.width;
  1775.     event.xconfigure.height = winPtr->changes.height;
  1776.     event.xconfigure.border_width = winPtr->changes.border_width;
  1777.     if (winPtr->changes.stack_mode == Above) {
  1778.     event.xconfigure.above = winPtr->changes.sibling;
  1779.     } else {
  1780.     event.xconfigure.above = None;
  1781.     }
  1782.     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  1783.     Tk_HandleEvent(&event);
  1784. }
  1785.  
  1786. /*
  1787.  *----------------------------------------------------------------------
  1788.  *
  1789.  * Tk_SetClass --
  1790.  *
  1791.  *    This procedure is used to give a window a class.
  1792.  *
  1793.  * Results:
  1794.  *    None.
  1795.  *
  1796.  * Side effects:
  1797.  *    A new class is stored for tkwin, replacing any existing
  1798.  *    class for it.
  1799.  *
  1800.  *----------------------------------------------------------------------
  1801.  */
  1802.  
  1803. void
  1804. Tk_SetClass(tkwin, className)
  1805.     Tk_Window tkwin;        /* Token for window to assign class. */
  1806.     char *className;        /* New class for tkwin. */
  1807. {
  1808.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1809.  
  1810.     winPtr->classUid = Tk_GetUid(className);
  1811.     if (winPtr->flags & TK_TOP_LEVEL) {
  1812.     TkWmSetClass(winPtr);
  1813.     }
  1814.     TkOptionClassChanged(winPtr);
  1815. }
  1816.  
  1817. /*
  1818.  *----------------------------------------------------------------------
  1819.  *
  1820.  * Tk_NameToWindow --
  1821.  *
  1822.  *    Given a string name for a window, this procedure
  1823.  *    returns the token for the window, if there exists a
  1824.  *    window corresponding to the given name.
  1825.  *
  1826.  * Results:
  1827.  *    The return result is either a token for the window corresponding
  1828.  *    to "name", or else NULL to indicate that there is no such
  1829.  *    window.  In this case, an error message is left in interp->result.
  1830.  *
  1831.  * Side effects:
  1832.  *    None.
  1833.  *
  1834.  *----------------------------------------------------------------------
  1835.  */
  1836.  
  1837. Tk_Window
  1838. Tk_NameToWindow(interp, pathName, tkwin)
  1839.     Tcl_Interp *interp;        /* Where to report errors. */
  1840.     char *pathName;        /* Path name of window. */
  1841.     Tk_Window tkwin;        /* Token for window:  name is assumed to
  1842.                  * belong to the same main window as tkwin. */
  1843. {
  1844.     Tcl_HashEntry *hPtr;
  1845.  
  1846.     hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable,
  1847.         pathName);
  1848.     if (hPtr == NULL) {
  1849.     Tcl_AppendResult(interp, "bad window path name \"",
  1850.         pathName, "\"", (char *) NULL);
  1851.     return NULL;
  1852.     }
  1853.     return (Tk_Window) Tcl_GetHashValue(hPtr);
  1854. }
  1855.  
  1856. /*
  1857.  *----------------------------------------------------------------------
  1858.  *
  1859.  * Tk_IdToWindow --
  1860.  *
  1861.  *    Given an X display and window ID, this procedure returns the
  1862.  *    Tk token for the window, if there exists a Tk window corresponding
  1863.  *    to the given ID.
  1864.  *
  1865.  * Results:
  1866.  *    The return result is either a token for the window corresponding
  1867.  *    to the given X id, or else NULL to indicate that there is no such
  1868.  *    window.
  1869.  *
  1870.  * Side effects:
  1871.  *    None.
  1872.  *
  1873.  *----------------------------------------------------------------------
  1874.  */
  1875.  
  1876. Tk_Window
  1877. Tk_IdToWindow(display, window)
  1878.     Display *display;        /* X display containing the window. */
  1879.     Window window;        /* X window window id. */
  1880. {
  1881.     TkDisplay *dispPtr;
  1882.     Tcl_HashEntry *hPtr;
  1883.  
  1884.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  1885.     if (dispPtr == NULL) {
  1886.         return NULL;
  1887.     }
  1888.     if (dispPtr->display == display) {
  1889.         break;
  1890.     }
  1891.     }
  1892.  
  1893.     hPtr = Tcl_FindHashEntry(&dispPtr->winTable, (char *) window);
  1894.     if (hPtr == NULL) {
  1895.     return NULL;
  1896.     }
  1897.     return (Tk_Window) Tcl_GetHashValue(hPtr);
  1898. }
  1899.  
  1900. /*
  1901.  *----------------------------------------------------------------------
  1902.  *
  1903.  * Tk_DisplayName --
  1904.  *
  1905.  *    Return the textual name of a window's display.
  1906.  *
  1907.  * Results:
  1908.  *    The return value is the string name of the display associated
  1909.  *    with tkwin.
  1910.  *
  1911.  * Side effects:
  1912.  *    None.
  1913.  *
  1914.  *----------------------------------------------------------------------
  1915.  */
  1916.  
  1917. char *
  1918. Tk_DisplayName(tkwin)
  1919.     Tk_Window tkwin;        /* Window whose display name is desired. */
  1920. {
  1921.     return ((TkWindow *) tkwin)->dispPtr->name;
  1922. }
  1923.  
  1924. /*
  1925.  *----------------------------------------------------------------------
  1926.  *
  1927.  * UnlinkWindow --
  1928.  *
  1929.  *    This procedure removes a window from the childList of its
  1930.  *    parent.
  1931.  *
  1932.  * Results:
  1933.  *    None.
  1934.  *
  1935.  * Side effects:
  1936.  *    The window is unlinked from its childList.
  1937.  *
  1938.  *----------------------------------------------------------------------
  1939.  */
  1940.  
  1941. static void
  1942. UnlinkWindow(winPtr)
  1943.     TkWindow *winPtr;            /* Child window to be unlinked. */
  1944. {
  1945.     TkWindow *prevPtr;
  1946.  
  1947.     if (winPtr->parentPtr == NULL) {
  1948.     return;
  1949.     }
  1950.     prevPtr = winPtr->parentPtr->childList;
  1951.     if (prevPtr == winPtr) {
  1952.     winPtr->parentPtr->childList = winPtr->nextPtr;
  1953.     if (winPtr->nextPtr == NULL) {
  1954.         winPtr->parentPtr->lastChildPtr = NULL;
  1955.     }
  1956.     } else {
  1957.     while (prevPtr->nextPtr != winPtr) {
  1958.         prevPtr = prevPtr->nextPtr;
  1959.         if (prevPtr == NULL) {
  1960.         panic("UnlinkWindow couldn't find child in parent");
  1961.         }
  1962.     }
  1963.     prevPtr->nextPtr = winPtr->nextPtr;
  1964.     if (winPtr->nextPtr == NULL) {
  1965.         winPtr->parentPtr->lastChildPtr = prevPtr;
  1966.     }
  1967.     }
  1968. }
  1969.  
  1970. /*
  1971.  *----------------------------------------------------------------------
  1972.  *
  1973.  * Tk_RestackWindow --
  1974.  *
  1975.  *    Change a window's position in the stacking order.
  1976.  *
  1977.  * Results:
  1978.  *    TCL_OK is normally returned.  If other is not a descendant
  1979.  *    of tkwin's parent then TCL_ERROR is returned and tkwin is
  1980.  *    not repositioned.
  1981.  *
  1982.  * Side effects:
  1983.  *    Tkwin is repositioned in the stacking order.
  1984.  *
  1985.  *----------------------------------------------------------------------
  1986.  */
  1987.  
  1988. int
  1989. Tk_RestackWindow(tkwin, aboveBelow, other)
  1990.     Tk_Window tkwin;        /* Token for window whose position in
  1991.                  * the stacking order is to change. */
  1992.     int aboveBelow;        /* Indicates new position of tkwin relative
  1993.                  * to other;  must be Above or Below. */
  1994.     Tk_Window other;        /* Tkwin will be moved to a position that
  1995.                  * puts it just above or below this window.
  1996.                  * If NULL then tkwin goes above or below
  1997.                  * all windows in the same parent. */
  1998. {
  1999.     TkWindow *winPtr = (TkWindow *) tkwin;
  2000.     TkWindow *otherPtr = (TkWindow *) other;
  2001.     XWindowChanges changes;
  2002.     unsigned int mask;
  2003.  
  2004.  
  2005.     /*
  2006.      * Special case:  if winPtr is a top-level window then just find
  2007.      * the top-level ancestor of otherPtr and restack winPtr above
  2008.      * otherPtr without changing any of Tk's childLists.
  2009.      */
  2010.  
  2011.     changes.stack_mode = aboveBelow;
  2012.     mask = CWStackMode;
  2013.     if (winPtr->flags & TK_TOP_LEVEL) {
  2014.     while ((otherPtr != NULL) && !(otherPtr->flags & TK_TOP_LEVEL)) {
  2015.         otherPtr = otherPtr->parentPtr;
  2016.     }
  2017.     TkWmRestackToplevel(winPtr, aboveBelow, otherPtr);
  2018.     return TCL_OK;
  2019.     }
  2020.  
  2021.     /*
  2022.      * Find an ancestor of otherPtr that is a sibling of winPtr.
  2023.      */
  2024.  
  2025.     if (winPtr->parentPtr == NULL) {
  2026.     /*
  2027.      * Window is going to be deleted shortly;  don't do anything.
  2028.      */
  2029.  
  2030.     return TCL_OK;
  2031.     }
  2032.     if (otherPtr == NULL) {
  2033.     if (aboveBelow == Above) {
  2034.         otherPtr = winPtr->parentPtr->lastChildPtr;
  2035.     } else {
  2036.         otherPtr = winPtr->parentPtr->childList;
  2037.     }
  2038.     } else {
  2039.     while (winPtr->parentPtr != otherPtr->parentPtr) {
  2040.         if ((otherPtr == NULL) || (otherPtr->flags & TK_TOP_LEVEL)) {
  2041.         return TCL_ERROR;
  2042.         }
  2043.         otherPtr = otherPtr->parentPtr;
  2044.     }
  2045.     }
  2046.     if (otherPtr == winPtr) {
  2047.     return TCL_OK;
  2048.     }
  2049.  
  2050.     /*
  2051.      * Reposition winPtr in the stacking order.
  2052.      */
  2053.  
  2054.     UnlinkWindow(winPtr);
  2055.     if (aboveBelow == Above) {
  2056.     winPtr->nextPtr = otherPtr->nextPtr;
  2057.     if (winPtr->nextPtr == NULL) {
  2058.         winPtr->parentPtr->lastChildPtr = winPtr;
  2059.     }
  2060.     otherPtr->nextPtr = winPtr;
  2061.     } else {
  2062.     TkWindow *prevPtr;
  2063.  
  2064.     prevPtr = winPtr->parentPtr->childList;
  2065.     if (prevPtr == otherPtr) {
  2066.         winPtr->parentPtr->childList = winPtr;
  2067.     } else {
  2068.         while (prevPtr->nextPtr != otherPtr) {
  2069.         prevPtr = prevPtr->nextPtr;
  2070.         }
  2071.         prevPtr->nextPtr = winPtr;
  2072.     }
  2073.     winPtr->nextPtr = otherPtr;
  2074.     }
  2075.  
  2076.     /*
  2077.      * Notify the X server of the change.  If winPtr hasn't yet been
  2078.      * created then there's no need to tell the X server now, since
  2079.      * the stacking order will be handled properly when the window
  2080.      * is finally created.
  2081.      */
  2082.  
  2083.     if (winPtr->window != None) {
  2084.     changes.stack_mode = Above;
  2085.     for (otherPtr = winPtr->nextPtr; otherPtr != NULL;
  2086.         otherPtr = otherPtr->nextPtr) {
  2087.         if ((otherPtr->window != None)
  2088.             && !(otherPtr->flags & TK_TOP_LEVEL)){
  2089.         changes.sibling = otherPtr->window;
  2090.         changes.stack_mode = Below;
  2091.         mask = CWStackMode|CWSibling;
  2092.         break;
  2093.         }
  2094.     }
  2095.     XConfigureWindow(winPtr->display, winPtr->window, mask, &changes);
  2096.     }
  2097.     return TCL_OK;
  2098. }
  2099.  
  2100. /*
  2101.  *----------------------------------------------------------------------
  2102.  *
  2103.  * Tk_MainWindow --
  2104.  *
  2105.  *    Returns the main window for an application.
  2106.  *
  2107.  * Results:
  2108.  *    If interp has a Tk application associated with it, the main
  2109.  *    window for the application is returned.  Otherwise NULL is
  2110.  *    returned and an error message is left in interp->result.
  2111.  *
  2112.  * Side effects:
  2113.  *    None.
  2114.  *
  2115.  *----------------------------------------------------------------------
  2116.  */
  2117.  
  2118. Tk_Window
  2119. Tk_MainWindow(interp)
  2120.     Tcl_Interp *interp;            /* Interpreter that embodies the
  2121.                      * application.  Used for error
  2122.                      * reporting also. */
  2123. {
  2124.     TkMainInfo *mainPtr;
  2125.  
  2126.     for (mainPtr = tkMainWindowList; mainPtr != NULL;
  2127.         mainPtr = mainPtr->nextPtr) {
  2128.     if (mainPtr->interp == interp) {
  2129.         return (Tk_Window) mainPtr->winPtr;
  2130.     }
  2131.     }
  2132.     interp->result = "this isn't a Tk application";
  2133.     return NULL;
  2134. }
  2135.  
  2136. /*
  2137.  *----------------------------------------------------------------------
  2138.  *
  2139.  * Tk_StrictMotif --
  2140.  *
  2141.  *    Indicates whether strict Motif compliance has been specified
  2142.  *    for the given window.
  2143.  *
  2144.  * Results:
  2145.  *    The return value is 1 if strict Motif compliance has been
  2146.  *    requested for tkwin's application by setting the tk_strictMotif
  2147.  *    variable in its interpreter to a true value.  0 is returned
  2148.  *    if tk_strictMotif has a false value.
  2149.  *
  2150.  * Side effects:
  2151.  *    None.
  2152.  *
  2153.  *----------------------------------------------------------------------
  2154.  */
  2155.  
  2156. int
  2157. Tk_StrictMotif(tkwin)
  2158.     Tk_Window tkwin;            /* Window whose application is
  2159.                      * to be checked. */
  2160. {
  2161.     return ((TkWindow *) tkwin)->mainPtr->strictMotif;
  2162. }
  2163.  
  2164. /* 
  2165.  *--------------------------------------------------------------
  2166.  *
  2167.  * OpenIM --
  2168.  *
  2169.  *    Tries to open an X input method, associated with the
  2170.  *    given display.  Right now we can only deal with a bare-bones
  2171.  *    input style:  no preedit, and no status.
  2172.  *
  2173.  * Results:
  2174.  *    Stores the input method in dispPtr->inputMethod;  if there isn't
  2175.  *    a suitable input method, then NULL is stored in dispPtr->inputMethod.
  2176.  *
  2177.  * Side effects:
  2178.  *    An input method gets opened.
  2179.  *
  2180.  *--------------------------------------------------------------
  2181.  */
  2182.  
  2183. static void
  2184. OpenIM(dispPtr)
  2185.     TkDisplay *dispPtr;        /* Tk's structure for the display. */
  2186. {
  2187. #ifndef TK_USE_INPUT_METHODS
  2188.     return;
  2189. #else
  2190.     unsigned short i;
  2191.     XIMStyles *stylePtr;
  2192.  
  2193.     dispPtr->inputMethod = XOpenIM(dispPtr->display, NULL, NULL, NULL);
  2194.     if (dispPtr->inputMethod == NULL) {
  2195.     return;
  2196.     }
  2197.  
  2198.     if ((XGetIMValues(dispPtr->inputMethod, XNQueryInputStyle, &stylePtr,
  2199.         NULL) != NULL) || (stylePtr == NULL)) {
  2200.     goto error;
  2201.     }
  2202.     for (i = 0; i < stylePtr->count_styles; i++) {
  2203.     if (stylePtr->supported_styles[i]
  2204.         == (XIMPreeditNothing|XIMStatusNothing)) {
  2205.         XFree(stylePtr);
  2206.         return;
  2207.     }
  2208.     }
  2209.     XFree(stylePtr);
  2210.  
  2211.     error:
  2212.  
  2213.     /*
  2214.      * Should close the input method, but this causes core dumps on some
  2215.      * systems (e.g. Solaris 2.3 as of 1/6/95).
  2216.      * XCloseIM(dispPtr->inputMethod);
  2217.      */
  2218.     dispPtr->inputMethod = NULL;
  2219.     return;
  2220. #endif /* TK_USE_INPUT_METHODS */
  2221. }
  2222.  
  2223. /*
  2224.  *----------------------------------------------------------------------
  2225.  *
  2226.  * Tk_GetNumMainWindows --
  2227.  *
  2228.  *    This procedure returns the number of main windows currently
  2229.  *    open in this process.
  2230.  *
  2231.  * Results:
  2232.  *    The number of main windows open in this process.
  2233.  *
  2234.  * Side effects:
  2235.  *    None.
  2236.  *
  2237.  *----------------------------------------------------------------------
  2238.  */
  2239.  
  2240. int
  2241. Tk_GetNumMainWindows()
  2242. {
  2243.     return numMainWindows;
  2244. }
  2245.  
  2246. /*
  2247.  *----------------------------------------------------------------------
  2248.  *
  2249.  * DeleteWindowsExitProc --
  2250.  *
  2251.  *    This procedure is invoked as an exit handler.  It deletes all
  2252.  *    of the main windows in the process.
  2253.  *
  2254.  * Results:
  2255.  *    None.
  2256.  *
  2257.  * Side effects:
  2258.  *    None.
  2259.  *
  2260.  *----------------------------------------------------------------------
  2261.  */
  2262.  
  2263. static void
  2264. DeleteWindowsExitProc(clientData)
  2265.     ClientData clientData;        /* Not used. */
  2266. {
  2267.     while (tkMainWindowList != NULL) {
  2268.     Tk_DestroyWindow((Tk_Window) tkMainWindowList->winPtr);
  2269.     }
  2270. }
  2271.  
  2272. /*
  2273.  *----------------------------------------------------------------------
  2274.  *
  2275.  * Tk_Init --
  2276.  *
  2277.  *    This procedure is invoked to add Tk to an interpreter.  It
  2278.  *    incorporates all of Tk's commands into the interpreter and
  2279.  *    creates the main window for a new Tk application.  If the
  2280.  *    interpreter contains a variable "argv", this procedure
  2281.  *    extracts several arguments from that variable, uses them
  2282.  *    to configure the main window, and modifies argv to exclude
  2283.  *    the arguments (see the "wish" documentation for a list of
  2284.  *    the arguments that are extracted).
  2285.  *
  2286.  * Results:
  2287.  *    Returns a standard Tcl completion code and sets interp->result
  2288.  *    if there is an error.
  2289.  *
  2290.  * Side effects:
  2291.  *    Depends on various initialization scripts that get invoked.
  2292.  *
  2293.  *----------------------------------------------------------------------
  2294.  */
  2295. #ifndef STk_CODE
  2296. int
  2297. Tk_Init(interp)
  2298.     Tcl_Interp *interp;        /* Interpreter to initialize. */
  2299. {
  2300.     char *p;
  2301.     int argc, code;
  2302.     char **argv, *args[20];
  2303.     Tcl_DString class;
  2304.     char buffer[30];
  2305.  
  2306.     /*
  2307.      * If there is an "argv" variable, get its value, extract out
  2308.      * relevant arguments from it, and rewrite the variable without
  2309.      * the arguments that we used.
  2310.      */
  2311.  
  2312.     synchronize = 0;
  2313.     name = display = geometry = colormap = visual = NULL; 
  2314.     p = Tcl_GetVar2(interp, "argv", (char *) NULL, TCL_GLOBAL_ONLY);
  2315.     argv = NULL;
  2316.     if (p != NULL) {
  2317.     if (Tcl_SplitList(interp, p, &argc, &argv) != TCL_OK) {
  2318.         argError:
  2319.         Tcl_AddErrorInfo(interp,
  2320.             "\n    (processing arguments in argv variable)");
  2321.         return TCL_ERROR;
  2322.     }
  2323.     if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv,
  2324.         argTable, TK_ARGV_DONT_SKIP_FIRST_ARG|TK_ARGV_NO_DEFAULTS)
  2325.         != TCL_OK) {
  2326.         ckfree((char *) argv);
  2327.         goto argError;
  2328.     }
  2329.     p = Tcl_Merge(argc, argv);
  2330.     Tcl_SetVar2(interp, "argv", (char *) NULL, p, TCL_GLOBAL_ONLY);
  2331.     sprintf(buffer, "%d", argc);
  2332.     Tcl_SetVar2(interp, "argc", (char *) NULL, buffer, TCL_GLOBAL_ONLY);
  2333.     ckfree(p);
  2334.     }
  2335.  
  2336.     /*
  2337.      * Figure out the application's name and class.
  2338.      */
  2339.  
  2340.     if (name == NULL) {
  2341.     name = Tcl_GetVar(interp, "argv0", TCL_GLOBAL_ONLY);
  2342.     if ((name == NULL) || (*name == 0)) {
  2343.         name = "tk";
  2344.     } else {
  2345.         p = strrchr(name, '/');
  2346.         if (p != NULL) {
  2347.         name = p+1;
  2348.         }
  2349.     }
  2350.     }
  2351.     Tcl_DStringInit(&class);
  2352.     Tcl_DStringAppend(&class, name, -1);
  2353.     p = Tcl_DStringValue(&class);
  2354.     if (islower(*p)) {
  2355.     *p = toupper((unsigned char) *p);
  2356.     }
  2357.  
  2358.     /*
  2359.      * Create an argument list for creating the top-level window,
  2360.      * using the information parsed from argv, if any.
  2361.      */
  2362.  
  2363.     args[0] = "toplevel";
  2364.     args[1] = ".";
  2365.     args[2] = "-class";
  2366.     args[3] = Tcl_DStringValue(&class);
  2367.     argc = 4;
  2368.     if (display != NULL) {
  2369.     args[argc] = "-screen";
  2370.     args[argc+1] = display;
  2371.     argc += 2;
  2372.  
  2373.     /*
  2374.      * If this is the first application for this process, save
  2375.      * the display name in the DISPLAY environment variable so
  2376.      * that it will be available to subprocesses created by us.
  2377.      */
  2378.  
  2379.     if (numMainWindows == 0) {
  2380.         Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY);
  2381.     }
  2382.     }
  2383.     if (colormap != NULL) {
  2384.     args[argc] = "-colormap";
  2385.     args[argc+1] = colormap;
  2386.     argc += 2;
  2387.     }
  2388.     if (visual != NULL) {
  2389.     args[argc] = "-visual";
  2390.     args[argc+1] = visual;
  2391.     argc += 2;
  2392.     }
  2393.     args[argc] = NULL;
  2394.     code = TkCreateFrame((ClientData) NULL, interp, argc, args, 1, name);
  2395.     Tcl_DStringFree(&class);
  2396.     if (code != TCL_OK) {
  2397.     goto done;
  2398.     }
  2399.     Tcl_ResetResult(interp);
  2400.     if (synchronize) {
  2401.     XSynchronize(Tk_Display(Tk_MainWindow(interp)), True);
  2402.     }
  2403.  
  2404.     /*
  2405.      * Set the geometry of the main window, if requested.  Put the
  2406.      * requested geometry into the "geometry" variable.
  2407.      */
  2408.  
  2409.     if (geometry != NULL) {
  2410.     Tcl_SetVar(interp, "geometry", geometry, TCL_GLOBAL_ONLY);
  2411.     code = Tcl_VarEval(interp, "wm geometry . ", geometry, (char *) NULL);
  2412.     if (code != TCL_OK) {
  2413.         goto done;
  2414.     }
  2415.     }
  2416.     if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {
  2417.     code = TCL_ERROR;
  2418.     goto done;
  2419.     }
  2420.     code = Tcl_PkgProvide(interp, "Tk", TK_VERSION);
  2421.     if (code != TCL_OK) {
  2422.     goto done;
  2423.     }
  2424.  
  2425.     /*
  2426.      * Invoke platform-specific initialization.
  2427.      */
  2428.  
  2429.     code = TkPlatformInit(interp);
  2430.  
  2431.     done:
  2432.     if (argv != NULL) {
  2433.     ckfree((char *) argv);
  2434.     }
  2435.     return code;
  2436. }
  2437. #endif
  2438.