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