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