home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkWindow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-07  |  53.6 KB  |  1,918 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-1993 The Regents of the University of California.
  10.  * All rights reserved.
  11.  *
  12.  * Permission is hereby granted, without written agreement and without
  13.  * license or royalty fees, to use, copy, modify, and distribute this
  14.  * software and its documentation for any purpose, provided that the
  15.  * above copyright notice and the following two paragraphs appear in
  16.  * all copies of this software.
  17.  * 
  18.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  19.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  20.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  21.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22.  *
  23.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  24.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  25.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  26.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  27.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  28.  */
  29.  
  30. #ifndef lint
  31. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkWindow.c,v 1.119 93/07/07 13:22:05 ouster Exp $ SPRITE (Berkeley)";
  32. #endif
  33.  
  34. #include "tkConfig.h"
  35. #include "tkInt.h"
  36. #include "patchlevel.h"
  37.  
  38. /*
  39.  * Count of number of main windows currently open in this process.
  40.  */
  41.  
  42. int tk_NumMainWindows;
  43.  
  44. /*
  45.  * First in list of all main windows managed by this process.
  46.  */
  47.  
  48. TkMainInfo *tkMainWindowList = NULL;
  49.  
  50. /*
  51.  * List of all displays currently in use.
  52.  */
  53.  
  54. TkDisplay *tkDisplayList = NULL;
  55.  
  56. /*
  57.  * Have statics in this module been initialized?
  58.  */
  59.  
  60. static initialized = 0;
  61.  
  62. /*
  63.  * Context information used to map from X window id's to
  64.  * TkWindow structures (during event handling, for example):
  65.  */
  66.  
  67. XContext tkWindowContext;
  68.  
  69. /*
  70.  * The variables below hold several uid's that are used in many places
  71.  * in the toolkit.
  72.  */
  73.  
  74. Tk_Uid tkDisabledUid = NULL;
  75. Tk_Uid tkActiveUid = NULL;
  76. Tk_Uid tkNormalUid = NULL;
  77.  
  78. /*
  79.  * Default values for "changes" and "atts" fields of TkWindows.  Note
  80.  * that Tk always requests all events for all windows, except StructureNotify
  81.  * events on internal windows:  these events are generated internally.
  82.  */
  83.  
  84. static XWindowChanges defChanges = {
  85.     0, 0, 1, 1, 0, 0, Above
  86. };
  87. #define ALL_EVENTS_MASK \
  88.     KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
  89.     EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
  90.     VisibilityChangeMask|SubstructureNotifyMask| \
  91.     FocusChangeMask|PropertyChangeMask|ColormapChangeMask
  92. static XSetWindowAttributes defAtts= {
  93.     None,            /* background_pixmap */
  94.     0,                /* background_pixel */
  95.     CopyFromParent,        /* border_pixmap */
  96.     0,                /* border_pixel */
  97.     ForgetGravity,        /* bit_gravity */
  98.     NorthWestGravity,        /* win_gravity */
  99.     NotUseful,            /* backing_store */
  100.     ~0,                /* backing_planes */
  101.     0,                /* backing_pixel */
  102.     False,            /* save_under */
  103.     ALL_EVENTS_MASK,        /* event_mask */
  104.     0,                /* do_not_propagate_mask */
  105.     False,            /* override_redirect */
  106.     CopyFromParent,        /* colormap */
  107.     None            /* cursor */
  108. };
  109.  
  110. /*
  111.  * The following structure defines all of the commands supported by
  112.  * Tk, and the C procedures that execute them.
  113.  */
  114.  
  115. typedef struct {
  116.     char *name;            /* Name of command. */
  117.     int (*cmdProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
  118.         int argc, char **argv));
  119.                 /* Command procedure. */
  120. } TkCmd;
  121.  
  122. TkCmd commands[] = {
  123.     /*
  124.      * Commands that are part of the intrinsics:
  125.      */
  126.  
  127.     {"after",        Tk_AfterCmd},
  128.     {"bind",        Tk_BindCmd},
  129.     {"destroy",        Tk_DestroyCmd},
  130.     {"exit",        Tk_ExitCmd},
  131.     {"focus",        Tk_FocusCmd},
  132.     {"grab",        Tk_GrabCmd},
  133.     {"lower",        Tk_LowerCmd},
  134.     {"option",        Tk_OptionCmd},
  135.     {"pack",        Tk_PackCmd},
  136.     {"place",        Tk_PlaceCmd},
  137.     {"raise",        Tk_RaiseCmd},
  138.     {"selection",    Tk_SelectionCmd},
  139.     {"tk",        Tk_TkCmd},
  140.     {"tkwait",        Tk_TkwaitCmd},
  141.     {"update",        Tk_UpdateCmd},
  142.     {"winfo",        Tk_WinfoCmd},
  143.     {"wm",        Tk_WmCmd},
  144.  
  145.     /*
  146.      * Widget-creation commands.
  147.      */
  148.     {"button",        Tk_ButtonCmd},
  149.     {"canvas",        Tk_CanvasCmd},
  150.     {"checkbutton",    Tk_ButtonCmd},
  151.     {"entry",        Tk_EntryCmd},
  152.     {"frame",        Tk_FrameCmd},
  153.     {"label",        Tk_ButtonCmd},
  154.     {"listbox",        Tk_ListboxCmd},
  155.     {"menu",        Tk_MenuCmd},
  156.     {"menubutton",    Tk_MenubuttonCmd},
  157.     {"message",        Tk_MessageCmd},
  158.     {"radiobutton",    Tk_ButtonCmd},
  159.     {"scale",        Tk_ScaleCmd},
  160.     {"scrollbar",    Tk_ScrollbarCmd},
  161.     {"text",        Tk_TextCmd},
  162.     {"toplevel",    Tk_FrameCmd},
  163.     {(char *) NULL,    (int (*)()) NULL}
  164. };
  165.  
  166. /*
  167.  * Forward declarations to procedures defined later in this file:
  168.  */
  169.  
  170. static Tk_Window    CreateTopLevelWindow _ANSI_ARGS_((Tcl_Interp *interp,
  171.                 Tk_Window parent, char *name, char *screenName));
  172. static void        DoConfigureNotify _ANSI_ARGS_((TkWindow *winPtr));
  173. static TkDisplay *    GetScreen _ANSI_ARGS_((Tcl_Interp *interp,
  174.                 char *screenName, int *screenPtr));
  175. static int        NameWindow _ANSI_ARGS_((Tcl_Interp *interp,
  176.                 TkWindow *winPtr, TkWindow *parentPtr,
  177.                 char *name));
  178. static TkWindow    *    NewWindow _ANSI_ARGS_((TkDisplay *dispPtr,
  179.                 int screenNum, TkWindow *parentPtr));
  180. static void        UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr));
  181.  
  182. /*
  183.  *----------------------------------------------------------------------
  184.  *
  185.  * CreateTopLevelWindow --
  186.  *
  187.  *    Make a new window that will be at top-level (its parent will
  188.  *    be the root window of a screen).
  189.  *
  190.  * Results:
  191.  *    The return value is a token for the new window, or NULL if
  192.  *    an error prevented the new window from being created.  If
  193.  *    NULL is returned, an error message will be left in
  194.  *    interp->result.
  195.  *
  196.  * Side effects:
  197.  *    A new window structure is allocated locally.  An X
  198.  *    window is NOT initially created, but will be created
  199.  *    the first time the window is mapped.
  200.  *
  201.  *----------------------------------------------------------------------
  202.  */
  203.  
  204. static Tk_Window
  205. CreateTopLevelWindow(interp, parent, name, screenName)
  206.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  207.     Tk_Window parent;        /* Token for logical parent of new window
  208.                  * (used for naming, options, etc.).  May
  209.                  * be NULL. */
  210.     char *name;            /* Name for new window;  if parent is
  211.                  * non-NULL, must be unique among parent's
  212.                  * children. */
  213.     char *screenName;        /* Name of screen on which to create
  214.                  * window.  NULL means use DISPLAY environment
  215.                  * variable to determine.  Empty string means
  216.                  * use parent's screen, or DISPLAY if no
  217.                  * parent. */
  218. {
  219.     register TkWindow *winPtr;
  220.     register TkDisplay *dispPtr;
  221.     int screenId;
  222.  
  223.     if (!initialized) {
  224.     initialized = 1;
  225.     tkWindowContext = XUniqueContext();
  226.     tkActiveUid = Tk_GetUid("active");
  227.     tkDisabledUid = Tk_GetUid("disabled");
  228.     tkNormalUid = Tk_GetUid("normal");
  229.     }
  230.  
  231.     if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
  232.     dispPtr = ((TkWindow *) parent)->dispPtr;
  233.     screenId = Tk_ScreenNumber(parent);
  234.     } else {
  235.     dispPtr = GetScreen(interp, screenName, &screenId);
  236.     if (dispPtr == NULL) {
  237.         return (Tk_Window) NULL;
  238.     }
  239.     }
  240.  
  241.     winPtr = NewWindow(dispPtr, screenId, (TkWindow *) parent);
  242.  
  243.     /*
  244.      * Internal windows don't normally ask for StructureNotify events,
  245.      * since we can generate them internally.  However, for top-level
  246.      * windows we need to as for the events because the window could
  247.      * be manipulated externally.
  248.      */
  249.  
  250.     winPtr->atts.event_mask |= StructureNotifyMask;
  251.  
  252.     /*
  253.      * (Need to set the TK_TOP_LEVEL flag immediately here;  otherwise
  254.      * Tk_DestroyWindow will core dump if it is called before the flag
  255.      * has been set.)
  256.      */
  257.  
  258.     winPtr->flags |= TK_TOP_LEVEL;
  259.     if (parent != NULL) {
  260.     if (NameWindow(interp, winPtr, (TkWindow *) parent, name) != TCL_OK) {
  261.         Tk_DestroyWindow((Tk_Window) winPtr);
  262.         return (Tk_Window) NULL;
  263.     }
  264.     }
  265.     TkWmNewWindow(winPtr);
  266.     return (Tk_Window) winPtr;
  267. }
  268.  
  269. /*
  270.  *----------------------------------------------------------------------
  271.  *
  272.  * GetScreen --
  273.  *
  274.  *    Given a string name for a display-plus-screen, find the
  275.  *    TkDisplay structure for the display and return the screen
  276.  *    number too.
  277.  *
  278.  * Results:
  279.  *    The return value is a pointer to information about the display,
  280.  *    or NULL if the display couldn't be opened.  In this case, an
  281.  *    error message is left in interp->result.  The location at
  282.  *    *screenPtr is overwritten with the screen number parsed from
  283.  *    screenName.
  284.  *
  285.  * Side effects:
  286.  *    A new connection is opened to the display if there is no
  287.  *    connection already.  A new TkDisplay data structure is also
  288.  *    setup, if necessary.
  289.  *
  290.  *----------------------------------------------------------------------
  291.  */
  292.  
  293. static TkDisplay *
  294. GetScreen(interp, screenName, screenPtr)
  295.     Tcl_Interp *interp;        /* Place to leave error message. */
  296.     char *screenName;        /* Name for screen.  NULL or empty means
  297.                  * use DISPLAY envariable. */
  298.     int *screenPtr;        /* Where to store screen number. */
  299. {
  300.     register TkDisplay *dispPtr;
  301.     char *p;
  302.     int length, screenId, i;
  303.  
  304.     /*
  305.      * Separate the screen number from the rest of the display
  306.      * name.  ScreenName is assumed to have the syntax
  307.      * <display>.<screen> with the dot and the screen being
  308.      * optional.
  309.      */
  310.  
  311.     if ((screenName == NULL) || (screenName[0] == '\0')) {
  312.     screenName = getenv("DISPLAY");
  313.     if (screenName == NULL) {
  314.         interp->result =
  315.             "no display name and no $DISPLAY environment variable";
  316.         return (TkDisplay *) NULL;
  317.     }
  318.     }
  319.     length = strlen(screenName);
  320.     screenId = 0;
  321.     p = screenName+length-1;
  322.     while (isdigit(*p) && (p != screenName)) {
  323.     p--;
  324.     }
  325.     if ((*p == '.') && (p[1] != '\0')) {
  326.     length = p - screenName;
  327.     screenId = strtoul(p+1, (char **) NULL, 10);
  328.     }
  329.  
  330.     /*
  331.      * See if we already have a connection to this display.  If not,
  332.      * then open a new connection.
  333.      */
  334.  
  335.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  336.     if (dispPtr == NULL) {
  337.         Display *display;
  338.  
  339.         display = XOpenDisplay(screenName);
  340.         if (display == NULL) {
  341.         Tcl_AppendResult(interp, "couldn't connect to display \"",
  342.             screenName, "\"", (char *) NULL);
  343.         return (TkDisplay *) NULL;
  344.         }
  345.         dispPtr = (TkDisplay *) ckalloc(sizeof(TkDisplay));
  346.         dispPtr->display = display;
  347.         dispPtr->nextPtr = tkDisplayList;
  348.         dispPtr->name = (char *) ckalloc((unsigned) (length+1));
  349.         dispPtr->lastEventTime = CurrentTime;
  350.         strncpy(dispPtr->name, screenName, length);
  351.         dispPtr->focusTopLevelPtr = NULL;
  352.         dispPtr->focussedOnEnter = 0;
  353.         dispPtr->name[length] = '\0';
  354.         dispPtr->bindInfoStale = 1;
  355.         dispPtr->errorPtr = NULL;
  356.         dispPtr->deleteCount = 0;
  357.         dispPtr->defaultHandler = NULL;
  358.         dispPtr->commWindow = NULL;
  359.         dispPtr->serverSecure = 0;
  360.         dispPtr->selectionOwner = NULL;
  361.         dispPtr->selectionSerial = 0;
  362.         dispPtr->multipleAtom = None;
  363.         dispPtr->atomInit = 0;
  364.         dispPtr->cursorFont = None;
  365.         dispPtr->grabWinPtr = NULL;
  366.         dispPtr->eventualGrabWinPtr = NULL;
  367.         dispPtr->buttonWinPtr = NULL;
  368.         dispPtr->serverWinPtr = NULL;
  369.         dispPtr->firstGrabEventPtr = NULL;
  370.         dispPtr->lastGrabEventPtr = NULL;
  371.         dispPtr->grabFlags = 0;
  372.         dispPtr->colorModels = (Tk_ColorModel *) ckalloc((unsigned)
  373.             (ScreenCount(display)*sizeof(Tk_ColorModel)));
  374.         for (i = ScreenCount(display)-1; i >= 0; i--) {
  375.         if (DisplayPlanes(display, i) <= 4) {
  376.             dispPtr->colorModels[i] = TK_MONO;
  377.         } else {
  378.             dispPtr->colorModels[i] = TK_COLOR;
  379.         }
  380.         }
  381.         tkDisplayList = dispPtr;
  382.         Tk_CreateFileHandler(ConnectionNumber(display),
  383.             TK_READABLE, (void (*)()) NULL,
  384.             (ClientData) display);
  385.         break;
  386.     }
  387.     if ((strncmp(dispPtr->name, screenName, length) == 0)
  388.         && (dispPtr->name[length] == '\0')) {
  389.         break;
  390.     }
  391.     }
  392.     if (screenId >= ScreenCount(dispPtr->display)) {
  393.     sprintf(interp->result, "bad screen number \"%d\"", screenId);
  394.     return (TkDisplay *) NULL;
  395.     }
  396.     *screenPtr = screenId;
  397.     return dispPtr;
  398. }
  399.  
  400. /*
  401.  *--------------------------------------------------------------
  402.  *
  403.  * NewWindow --
  404.  *
  405.  *    This procedure creates and initializes a TkWindow structure.
  406.  *
  407.  * Results:
  408.  *    The return value is a pointer to the new window.
  409.  *
  410.  * Side effects:
  411.  *    A new window structure is allocated and all its fields are
  412.  *    initialized.
  413.  *
  414.  *--------------------------------------------------------------
  415.  */
  416.  
  417. static TkWindow *
  418. NewWindow(dispPtr, screenNum, parentPtr)
  419.     TkDisplay *dispPtr;        /* Display associated with new window. */
  420.     int screenNum;        /* Index of screen for new window. */
  421.     TkWindow *parentPtr;    /* Parent from which this window should
  422.                  * inherit visual information.  NULL means
  423.                  * use screen defaults instead of
  424.                  * inheriting. */
  425. {
  426.     register TkWindow *winPtr;
  427.  
  428.     winPtr = (TkWindow *) ckalloc(sizeof(TkWindow));
  429.     winPtr->display = dispPtr->display;
  430.     winPtr->dispPtr = dispPtr;
  431.     winPtr->screenNum = screenNum;
  432.     if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
  433.         && (parentPtr->screenNum == winPtr->screenNum)) {
  434.     winPtr->visual = parentPtr->visual;
  435.     winPtr->depth = parentPtr->depth;
  436.     } else {
  437.     winPtr->visual = DefaultVisual(dispPtr->display, screenNum);
  438.     winPtr->depth = DefaultDepth(dispPtr->display, screenNum);
  439.     }
  440.     winPtr->window = None;
  441.     winPtr->childList = NULL;
  442.     winPtr->lastChildPtr = NULL;
  443.     winPtr->parentPtr = NULL;
  444.     winPtr->nextPtr = NULL;
  445.     winPtr->mainPtr = NULL;
  446.     winPtr->pathName = NULL;
  447.     winPtr->nameUid = NULL;
  448.     winPtr->classUid = NULL;
  449.     winPtr->changes = defChanges;
  450.     winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
  451.     winPtr->atts = defAtts;
  452.     if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
  453.         && (parentPtr->screenNum == winPtr->screenNum)) {
  454.     winPtr->atts.colormap = parentPtr->atts.colormap;
  455.     } else {
  456.     winPtr->atts.colormap = DefaultColormap(dispPtr->display, screenNum);
  457.     }
  458.     winPtr->dirtyAtts = CWEventMask|CWColormap;
  459.     winPtr->flags = 0;
  460.     winPtr->handlerList = NULL;
  461.     winPtr->focusProc = NULL;
  462.     winPtr->focusData = NULL;
  463.     winPtr->optionLevel = -1;
  464.     winPtr->selHandlerList = NULL;
  465.     winPtr->selClearProc = NULL;
  466.     winPtr->selClearData = NULL;
  467.     winPtr->geomProc = NULL;
  468.     winPtr->geomData = NULL;
  469.     winPtr->reqWidth = winPtr->reqHeight = 1;
  470.     winPtr->internalBorderWidth = 0;
  471.     winPtr->wmInfoPtr = NULL;
  472.  
  473.     return winPtr;
  474. }
  475.  
  476. /*
  477.  *----------------------------------------------------------------------
  478.  *
  479.  * NameWindow --
  480.  *
  481.  *    This procedure is invoked to give a window a name and insert
  482.  *    the window into the hierarchy associated with a particular
  483.  *    application.
  484.  *
  485.  * Results:
  486.  *    A standard Tcl return value.
  487.  *
  488.  * Side effects:
  489.  *      See above.
  490.  *
  491.  *----------------------------------------------------------------------
  492.  */
  493.  
  494. static int
  495. NameWindow(interp, winPtr, parentPtr, name)
  496.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  497.     register TkWindow *winPtr;    /* Window that is to be named and inserted. */
  498.     TkWindow *parentPtr;    /* Pointer to logical parent for winPtr
  499.                  * (used for naming, options, etc.). */
  500.     char *name;            /* Name for winPtr;   must be unique among
  501.                  * parentPtr's children. */
  502. {
  503. #define FIXED_SIZE 200
  504.     char staticSpace[FIXED_SIZE];
  505.     char *pathName;
  506.     int new;
  507.     Tcl_HashEntry *hPtr;
  508.     int length1, length2;
  509.  
  510.     /*
  511.      * Setup all the stuff except name right away, then do the name stuff
  512.      * last.  This is so that if the name stuff fails, everything else
  513.      * will be properly initialized (needed to destroy the window cleanly
  514.      * after the naming failure).
  515.      */
  516.     winPtr->parentPtr = parentPtr;
  517.     winPtr->nextPtr = NULL;
  518.     if (parentPtr->childList == NULL) {
  519.     parentPtr->childList = winPtr;
  520.     } else {
  521.     parentPtr->lastChildPtr->nextPtr = winPtr;
  522.     }
  523.     parentPtr->lastChildPtr = winPtr;
  524.     winPtr->mainPtr = parentPtr->mainPtr;
  525.     winPtr->nameUid = Tk_GetUid(name);
  526.  
  527.     /*
  528.      * Don't permit names that start with an upper-case letter:  this
  529.      * will just cause confusion with class names in the option database.
  530.      */
  531.  
  532.     if (isupper(name[0])) {
  533.     Tcl_AppendResult(interp,
  534.         "window name starts with an upper-case letter: \"",
  535.         name, "\"", (char *) NULL);
  536.     return TCL_ERROR;
  537.     }
  538.  
  539.     /*
  540.      * To permit names of arbitrary length, must be prepared to malloc
  541.      * a buffer to hold the new path name.  To run fast in the common
  542.      * case where names are short, use a fixed-size buffer on the
  543.      * stack.
  544.      */
  545.  
  546.     length1 = strlen(parentPtr->pathName);
  547.     length2 = strlen(name);
  548.     if ((length1+length2+2) <= FIXED_SIZE) {
  549.     pathName = staticSpace;
  550.     } else {
  551.     pathName = (char *) ckalloc((unsigned) (length1+length2+2));
  552.     }
  553.     if (length1 == 1) {
  554.     pathName[0] = '.';
  555.     strcpy(pathName+1, name);
  556.     } else {
  557.     strcpy(pathName, parentPtr->pathName);
  558.     pathName[length1] = '.';
  559.     strcpy(pathName+length1+1, name);
  560.     }
  561.     hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new);
  562.     if (pathName != staticSpace) {
  563.     ckfree(pathName);
  564.     }
  565.     if (!new) {
  566.     Tcl_AppendResult(interp, "window name \"", name,
  567.         "\" already exists in parent", (char *) NULL);
  568.     return TCL_ERROR;
  569.     }
  570.     Tcl_SetHashValue(hPtr, winPtr);
  571.     winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr);
  572.     return TCL_OK;
  573. }
  574.  
  575. /*
  576.  *----------------------------------------------------------------------
  577.  *
  578.  * Tk_CreateMainWindow --
  579.  *
  580.  *    Make a new main window.  A main window is a special kind of
  581.  *    top-level window used as the outermost window in an
  582.  *    application.
  583.  *
  584.  * Results:
  585.  *    The return value is a token for the new window, or NULL if
  586.  *    an error prevented the new window from being created.  If
  587.  *    NULL is returned, an error message will be left in
  588.  *    interp->result.
  589.  *
  590.  * Side effects:
  591.  *    A new window structure is allocated locally;  "interp" is
  592.  *    associated with the window and registered for "send" commands
  593.  *    under "baseName".  BaseName may be extended with an instance
  594.  *    number in the form "#2" if necessary to make it globally
  595.  *    unique.  Tk-related commands are bound into interp.  An X
  596.  *    window is NOT initially created, but will be created the
  597.  *    first time the window is mapped.
  598.  *
  599.  *----------------------------------------------------------------------
  600.  */
  601.  
  602. Tk_Window
  603. Tk_CreateMainWindow(interp, screenName, baseName)
  604.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  605.     char *screenName;        /* Name of screen on which to create
  606.                  * window.  Empty or NULL string means
  607.                  * use DISPLAY environment variable. */
  608.     char *baseName;        /* Base name for application;  usually of the
  609.                  * form "prog instance". */
  610. {
  611.     Tk_Window tkwin;
  612.     int result, dummy;
  613.     Tcl_HashEntry *hPtr;
  614.     register TkMainInfo *mainPtr;
  615.     register TkWindow *winPtr;
  616.     register TkCmd *cmdPtr;
  617.     char *libDir;
  618.     char buffer[30];
  619.  
  620.     /*
  621.      * Create the basic TkWindow structure.
  622.      */
  623.  
  624.     tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName,
  625.         screenName);
  626.     if (tkwin == NULL) {
  627.     return NULL;
  628.     }
  629.  
  630.     /*
  631.      * Create the TkMainInfo structure for this application, and set
  632.      * up name-related information for the new window.
  633.      */
  634.  
  635.     winPtr = (TkWindow *) tkwin;
  636.     mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo));
  637.     mainPtr->winPtr = winPtr;
  638.     mainPtr->interp = interp;
  639.     Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS);
  640.     mainPtr->bindingTable = Tk_CreateBindingTable(interp);
  641.     mainPtr->focusPtr = winPtr;
  642.     mainPtr->focusDefaultPtr = NULL;
  643.     mainPtr->optionRootPtr = NULL;
  644.     mainPtr->nextPtr = tkMainWindowList;
  645.     tkMainWindowList = mainPtr;
  646.     winPtr->mainPtr = mainPtr;
  647.     hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy);
  648.     Tcl_SetHashValue(hPtr, winPtr);
  649.     winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr);
  650.  
  651.     /*
  652.      * Register the interpreter for "send" purposes.  If baseName isn't
  653.      * already unique, find a unique suffix to add to it to make it
  654.      * unique.  Change the window's name to contain the suffix.
  655.      */
  656.  
  657.     result = Tk_RegisterInterp(interp, baseName, tkwin);
  658.     if (result == TCL_OK) {
  659.     winPtr->nameUid = Tk_GetUid(baseName);
  660.     } else {
  661.     char newName[110];
  662.     int i;
  663.  
  664.     for (i = 2; ; i++) {
  665.         sprintf(newName, "%.100s #%d", baseName, i);
  666.         Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
  667.         result = Tk_RegisterInterp(interp, newName, tkwin);
  668.         if (result == TCL_OK) {
  669.         break;
  670.         }
  671.         if (i >= 100) {
  672.         Tcl_SetResult(interp,
  673.             "couldn't generate unique name to register application",
  674.             TCL_STATIC);
  675.         Tk_DestroyWindow(tkwin);
  676.         }
  677.     }
  678.     winPtr->nameUid = Tk_GetUid(newName);
  679.     }
  680.  
  681.     /*
  682.      * Bind in Tk's commands.
  683.      */
  684.  
  685.     for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
  686.     Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc,
  687.         (ClientData) tkwin, (void (*)()) NULL);
  688.     }
  689.  
  690.     /*
  691.      * Set variables for the intepreter.
  692.      */
  693.  
  694.     libDir = getenv("TK_LIBRARY");
  695.     if (libDir == NULL) {
  696.     libDir = TK_LIBRARY;
  697.     }
  698.     Tcl_SetVar(interp, "tk_library", libDir, TCL_GLOBAL_ONLY);
  699.     sprintf(buffer, "%d", TK_PATCH_LEVEL);
  700.     Tcl_SetVar(interp, "tk_patchLevel", buffer, TCL_GLOBAL_ONLY);
  701.     Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY);
  702.     Tcl_SetVar(interp, "tkVersion", TK_VERSION, TCL_GLOBAL_ONLY);
  703.  
  704.     tk_NumMainWindows++;
  705.     return tkwin;
  706. }
  707.  
  708. /*
  709.  *--------------------------------------------------------------
  710.  *
  711.  * Tk_CreateWindow --
  712.  *
  713.  *    Create a new internal or top-level window as a child of an
  714.  *    existing window.
  715.  *
  716.  * Results:
  717.  *    The return value is a token for the new window.  This
  718.  *    is not the same as X's token for the window.  If an error
  719.  *    occurred in creating the window (e.g. no such display or
  720.  *    screen), then an error message is left in interp->result and
  721.  *    NULL is returned.
  722.  *
  723.  * Side effects:
  724.  *    A new window structure is allocated locally.  An X
  725.  *    window is not initially created, but will be created
  726.  *    the first time the window is mapped.
  727.  *
  728.  *--------------------------------------------------------------
  729.  */
  730.  
  731. Tk_Window
  732. Tk_CreateWindow(interp, parent, name, screenName)
  733.     Tcl_Interp *interp;        /* Interpreter to use for error reporting.
  734.                  * Interp->result is assumed to be
  735.                  * initialized by the caller. */
  736.     Tk_Window parent;        /* Token for parent of new window. */
  737.     char *name;            /* Name for new window.  Must be unique
  738.                  * among parent's children. */
  739.     char *screenName;        /* If NULL, new window will be internal on
  740.                  * same screen as its parent.  If non-NULL,
  741.                  * gives name of screen on which to create
  742.                  * new window;  window will be a top-level
  743.                  * window. */
  744. {
  745.     TkWindow *parentPtr = (TkWindow *) parent;
  746.     TkWindow *winPtr;
  747.  
  748.     if (screenName == NULL) {
  749.     winPtr = NewWindow(parentPtr->dispPtr, parentPtr->screenNum,
  750.         parentPtr);
  751.     if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) {
  752.         Tk_DestroyWindow((Tk_Window) winPtr);
  753.         return NULL;
  754.     } else {
  755.       return (Tk_Window) winPtr;
  756.     }
  757.     } else {
  758.     return CreateTopLevelWindow(interp, parent, name, screenName);
  759.     }
  760. }
  761.  
  762. /*
  763.  *----------------------------------------------------------------------
  764.  *
  765.  * Tk_CreateWindowFromPath --
  766.  *
  767.  *    This procedure is similar to Tk_CreateWindow except that
  768.  *    it uses a path name to create the window, rather than a
  769.  *    parent and a child name.
  770.  *
  771.  * Results:
  772.  *    The return value is a token for the new window.  This
  773.  *    is not the same as X's token for the window.  If an error
  774.  *    occurred in creating the window (e.g. no such display or
  775.  *    screen), then an error message is left in interp->result and
  776.  *    NULL is returned.
  777.  *
  778.  * Side effects:
  779.  *    A new window structure is allocated locally.  An X
  780.  *    window is not initially created, but will be created
  781.  *    the first time the window is mapped.
  782.  *
  783.  *----------------------------------------------------------------------
  784.  */
  785.  
  786. Tk_Window
  787. Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName)
  788.     Tcl_Interp *interp;        /* Interpreter to use for error reporting.
  789.                  * Interp->result is assumed to be
  790.                  * initialized by the caller. */
  791.     Tk_Window tkwin;        /* Token for any window in application
  792.                  * that is to contain new window. */
  793.     char *pathName;        /* Path name for new window within the
  794.                  * application of tkwin.  The parent of
  795.                  * this window must already exist, but
  796.                  * the window itself must not exist. */
  797.     char *screenName;        /* If NULL, new window will be on same
  798.                  * screen as its parent.  If non-NULL,
  799.                  * gives name of screen on which to create
  800.                  * new window;  window will be a top-level
  801.                  * window. */
  802. {
  803. #define FIXED_SPACE 5
  804.     char fixedSpace[FIXED_SPACE+1];
  805.     char *p;
  806.     Tk_Window parent;
  807.     int numChars;
  808.  
  809.     /*
  810.      * Strip the parent's name out of pathName (it's everything up
  811.      * to the last dot).  There are two tricky parts: (a) must
  812.      * copy the parent's name somewhere else to avoid modifying
  813.      * the pathName string (for large names, space for the copy
  814.      * will have to be malloc'ed);  (b) must special-case the
  815.      * situation where the parent is ".".
  816.      */
  817.  
  818.     p = strrchr(pathName, '.');
  819.     if (p == NULL) {
  820.     Tcl_AppendResult(interp, "bad window path name \"", pathName,
  821.         "\"", (char *) NULL);
  822.     return NULL;
  823.     }
  824.     numChars = p-pathName;
  825.     if (numChars > FIXED_SPACE) {
  826.     p = (char *) ckalloc((unsigned) (numChars+1));
  827.     } else {
  828.     p = fixedSpace;
  829.     }
  830.     if (numChars == 0) {
  831.     *p = '.';
  832.     p[1] = '\0';
  833.     } else {
  834.     strncpy(p, pathName, numChars);
  835.     p[numChars] = '\0';
  836.     }
  837.  
  838.     /*
  839.      * Find the parent window.
  840.      */
  841.  
  842.     parent = Tk_NameToWindow(interp, p, tkwin);
  843.     if (p != fixedSpace) {
  844.     ckfree(p);
  845.     }
  846.     if (parent == NULL) {
  847.     return NULL;
  848.     }
  849.  
  850.     /*
  851.      * Create the window.
  852.      */
  853.  
  854.     if (screenName == NULL) {
  855.     TkWindow *parentPtr = (TkWindow *) parent;
  856.     TkWindow *winPtr;
  857.  
  858.     winPtr = NewWindow(parentPtr->dispPtr, parentPtr->screenNum,
  859.         parentPtr);
  860.     if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1)
  861.         != 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, pathName+numChars+1,
  869.         screenName);
  870.     }
  871. }
  872.  
  873. /*
  874.  *--------------------------------------------------------------
  875.  *
  876.  * Tk_DestroyWindow --
  877.  *
  878.  *    Destroy an existing window.  After this call, the caller
  879.  *    should never again use the token.
  880.  *
  881.  * Results:
  882.  *    None.
  883.  *
  884.  * Side effects:
  885.  *    The window is deleted, along with all of its children.
  886.  *    Relevant callback procedures are invoked.
  887.  *
  888.  *--------------------------------------------------------------
  889.  */
  890.  
  891. void
  892. Tk_DestroyWindow(tkwin)
  893.     Tk_Window tkwin;        /* Window to destroy. */
  894. {
  895.     register TkWindow *winPtr = (TkWindow *) tkwin;
  896.     XEvent event;
  897.  
  898.     if (winPtr->flags & TK_ALREADY_DEAD) {
  899.     /*
  900.      * An destroy event binding caused the window to be destroyed
  901.      * again.  Ignore the request.
  902.      */
  903.  
  904.     return;
  905.     }
  906.     winPtr->flags |= TK_ALREADY_DEAD;
  907.  
  908.     /*
  909.      * Recursively destroy children.  The TK_RECURSIVE_DESTROY
  910.      * flags means that the child's window needn't be explicitly
  911.      * destroyed (the destroy of the parent already did it), nor
  912.      * does it need to be removed from its parent's child list,
  913.      * since the parent is being destroyed too.
  914.      */
  915.  
  916.     while (winPtr->childList != NULL) {
  917.     winPtr->childList->flags |= TK_RECURSIVE_DESTROY;
  918.     Tk_DestroyWindow((Tk_Window) winPtr->childList);
  919.     }
  920.  
  921.     /*
  922.      * Generate a DestroyNotify event.  In order for the DestroyNotify
  923.      * event to be processed correctly, need to make sure the window
  924.      * exists.  This is a bit of a kludge, and may be unnecessarily
  925.      * expensive, but without it no event handlers will get called for
  926.      * windows that don't exist yet.
  927.      */
  928.  
  929.     if (winPtr->window == None) {
  930.     Tk_MakeWindowExist(tkwin);
  931.     }
  932.     event.type = DestroyNotify;
  933.     event.xdestroywindow.serial =
  934.         LastKnownRequestProcessed(winPtr->display);
  935.     event.xdestroywindow.send_event = False;
  936.     event.xdestroywindow.display = winPtr->display;
  937.     event.xdestroywindow.event = winPtr->window;
  938.     event.xdestroywindow.window = winPtr->window;
  939.     Tk_HandleEvent(&event);
  940.  
  941.     /*
  942.      * Cleanup the data structures associated with this window.
  943.      * No need to destroy windows during recursive destroys, since
  944.      * that will happen automatically when the parent window is
  945.      * destroyed (not true for top-level windows:  must destroy
  946.      * them explicitly).
  947.      */
  948.  
  949.     if (winPtr->window != None) {
  950.     if (!(winPtr->flags & TK_RECURSIVE_DESTROY)
  951.         || (winPtr->flags & TK_TOP_LEVEL)) {
  952.         XDestroyWindow(winPtr->display, winPtr->window);
  953.     }
  954.     XDeleteContext(winPtr->display, winPtr->window, tkWindowContext);
  955.     winPtr->window = None;
  956.     }
  957.     UnlinkWindow(winPtr);
  958.     TkEventDeadWindow(winPtr);
  959.     TkFocusDeadWindow(winPtr);
  960.     TkOptionDeadWindow(winPtr);
  961.     TkSelDeadWindow(winPtr);
  962.     if (winPtr->flags & TK_TOP_LEVEL) {
  963.     TkWmDeadWindow(winPtr);
  964.     }
  965.     TkGrabDeadWindow(winPtr);
  966.     if (winPtr->mainPtr != NULL) {
  967.     Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable,
  968.         (ClientData) winPtr->pathName);
  969.     if (winPtr->pathName != NULL) {
  970.         Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable,
  971.             winPtr->pathName));
  972.     }
  973.     if (winPtr->mainPtr->winPtr == winPtr) {
  974.         register TkCmd *cmdPtr;
  975.  
  976.         /*
  977.          * Deleting a main window.  Delete the TkMainInfo structure too
  978.          * and replace all of Tk's commands with dummy commands that
  979.          * return errors.  Also delete the "send" command to unregister
  980.          * the interpreter.
  981.          */
  982.  
  983.         for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
  984.         Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name,
  985.             TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL);
  986.         }
  987.         Tcl_CreateCommand(winPtr->mainPtr->interp, "send",
  988.             TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL);
  989.         Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable);
  990.         Tk_DeleteBindingTable(winPtr->mainPtr->bindingTable);
  991.         if (tkMainWindowList == winPtr->mainPtr) {
  992.         tkMainWindowList = winPtr->mainPtr->nextPtr;
  993.         } else {
  994.         TkMainInfo *prevPtr;
  995.  
  996.         for (prevPtr = tkMainWindowList;
  997.             prevPtr->nextPtr != winPtr->mainPtr;
  998.             prevPtr = prevPtr->nextPtr) {
  999.             /* Empty loop body. */
  1000.         }
  1001.         prevPtr->nextPtr = winPtr->mainPtr->nextPtr;
  1002.         }
  1003.         ckfree((char *) winPtr->mainPtr);
  1004.         tk_NumMainWindows--;
  1005.     }
  1006.     }
  1007.     ckfree((char *) winPtr);
  1008. }
  1009.  
  1010. /*
  1011.  *--------------------------------------------------------------
  1012.  *
  1013.  * Tk_MapWindow --
  1014.  *
  1015.  *    Map a window within its parent.  This may require the
  1016.  *    window and/or its parents to actually be created.
  1017.  *
  1018.  * Results:
  1019.  *    None.
  1020.  *
  1021.  * Side effects:
  1022.  *    The given window will be mapped.  Windows may also
  1023.  *    be created.
  1024.  *
  1025.  *--------------------------------------------------------------
  1026.  */
  1027.  
  1028. void
  1029. Tk_MapWindow(tkwin)
  1030.     Tk_Window tkwin;        /* Token for window to map. */
  1031. {
  1032.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1033.     XEvent event;
  1034.  
  1035.     if (winPtr->flags & TK_MAPPED) {
  1036.     return;
  1037.     }
  1038.     if (winPtr->window == None) {
  1039.     Tk_MakeWindowExist(tkwin);
  1040.     }
  1041.     if (winPtr->flags & TK_TOP_LEVEL) {
  1042.     /*
  1043.      * Lots of special processing has to be done for top-level
  1044.      * windows.  Let tkWm.c handle everything itself.
  1045.      */
  1046.  
  1047.     TkWmMapWindow(winPtr);
  1048.     return;
  1049.     }
  1050.     winPtr->flags |= TK_MAPPED;
  1051.     XMapWindow(winPtr->display, winPtr->window);
  1052.     event.type = MapNotify;
  1053.     event.xmap.serial = LastKnownRequestProcessed(winPtr->display);
  1054.     event.xmap.send_event = False;
  1055.     event.xmap.display = winPtr->display;
  1056.     event.xmap.event = winPtr->window;
  1057.     event.xmap.window = winPtr->window;
  1058.     event.xmap.override_redirect = winPtr->atts.override_redirect;
  1059.     Tk_HandleEvent(&event);
  1060. }
  1061.  
  1062. /*
  1063.  *--------------------------------------------------------------
  1064.  *
  1065.  * Tk_MakeWindowExist --
  1066.  *
  1067.  *    Ensure that a particular window actually exists.  This
  1068.  *    procedure shouldn't normally need to be invoked from
  1069.  *    outside the Tk package, but may be needed if someone
  1070.  *    wants to manipulate a window before mapping it.
  1071.  *
  1072.  * Results:
  1073.  *    None.
  1074.  *
  1075.  * Side effects:
  1076.  *    When the procedure returns, the X window associated with
  1077.  *    tkwin is guaranteed to exist.  This may require the
  1078.  *    window's ancestors to be created also.
  1079.  *
  1080.  *--------------------------------------------------------------
  1081.  */
  1082.  
  1083. void
  1084. Tk_MakeWindowExist(tkwin)
  1085.     Tk_Window tkwin;        /* Token for window. */
  1086. {
  1087.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1088.     TkWindow *winPtr2;
  1089.     Window parent;
  1090.  
  1091.     if (winPtr->window != None) {
  1092.     return;
  1093.     }
  1094.  
  1095.     if (winPtr->flags & TK_TOP_LEVEL) {
  1096.     parent = XRootWindow(winPtr->display, winPtr->screenNum);
  1097.     } else {
  1098.     if (winPtr->parentPtr->window == None) {
  1099.         Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr);
  1100.     }
  1101.     parent = winPtr->parentPtr->window;
  1102.     }
  1103.  
  1104.     winPtr->window = XCreateWindow(winPtr->display, parent,
  1105.         winPtr->changes.x, winPtr->changes.y,
  1106.         winPtr->changes.width, winPtr->changes.height,
  1107.         winPtr->changes.border_width, winPtr->depth,
  1108.         InputOutput, winPtr->visual, winPtr->dirtyAtts,
  1109.         &winPtr->atts);
  1110.     XSaveContext(winPtr->display, winPtr->window, tkWindowContext,
  1111.         (caddr_t) winPtr);
  1112.     winPtr->dirtyAtts = 0;
  1113.     winPtr->dirtyChanges = 0;
  1114.  
  1115.     /*
  1116.      * If any siblings higher up in the stacking order have already
  1117.      * been created then move this window to its rightful position
  1118.      * in the stacking order.
  1119.      *
  1120.      * NOTE: this code ignores any changes anyone might have made
  1121.      * to the sibling and stack_mode field of the window's attributes,
  1122.      * so it really isn't safe for these to be manipulated except
  1123.      * by calling Tk_RestackWindow.
  1124.      */
  1125.  
  1126.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1127.     for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL;
  1128.         winPtr2 = winPtr2->nextPtr) {
  1129.         if (winPtr2->window != None) {
  1130.         XWindowChanges changes;
  1131.         changes.sibling = winPtr2->window;
  1132.         changes.stack_mode = Below;
  1133.         XConfigureWindow(winPtr->display, winPtr->window,
  1134.             CWSibling|CWStackMode, &changes);
  1135.         break;
  1136.         }
  1137.     }
  1138.     }
  1139.  
  1140.     /*
  1141.      * Issue a ConfigureNotify event if there were deferred configuration
  1142.      * changes.
  1143.      */
  1144.  
  1145.     if (winPtr->flags & TK_NEED_CONFIG_NOTIFY) {
  1146.     winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY;
  1147.     DoConfigureNotify(winPtr);
  1148.     }
  1149. }
  1150.  
  1151. /*
  1152.  *--------------------------------------------------------------
  1153.  *
  1154.  * Tk_UnmapWindow, etc. --
  1155.  *
  1156.  *    There are several procedures under here, each of which
  1157.  *    mirrors an existing X procedure.  In addition to performing
  1158.  *    the functions of the corresponding procedure, each
  1159.  *    procedure also updates the local window structure and
  1160.  *    synthesizes an X event (if the window's structure is being
  1161.  *    managed internally).
  1162.  *
  1163.  * Results:
  1164.  *    See the manual entries.
  1165.  *
  1166.  * Side effects:
  1167.  *    See the manual entries.
  1168.  *
  1169.  *--------------------------------------------------------------
  1170.  */
  1171.  
  1172. void
  1173. Tk_UnmapWindow(tkwin)
  1174.     Tk_Window tkwin;        /* Token for window to unmap. */
  1175. {
  1176.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1177.  
  1178.     if (!(winPtr->flags & TK_MAPPED)) {
  1179.     return;
  1180.     }
  1181.     if (winPtr->flags & TK_TOP_LEVEL) {
  1182.     /*
  1183.      * Special processing has to be done for top-level windows.  Let
  1184.      * tkWm.c handle everything itself.
  1185.      */
  1186.  
  1187.     TkWmUnmapWindow(winPtr);
  1188.     return;
  1189.     }
  1190.     winPtr->flags &= ~TK_MAPPED;
  1191.     XUnmapWindow(winPtr->display, winPtr->window);
  1192.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1193.     XEvent event;
  1194.  
  1195.     event.type = UnmapNotify;
  1196.     event.xunmap.serial = LastKnownRequestProcessed(winPtr->display);
  1197.     event.xunmap.send_event = False;
  1198.     event.xunmap.display = winPtr->display;
  1199.     event.xunmap.event = winPtr->window;
  1200.     event.xunmap.window = winPtr->window;
  1201.     event.xunmap.from_configure = False;
  1202.     Tk_HandleEvent(&event);
  1203.     }
  1204. }
  1205.  
  1206. void
  1207. Tk_ConfigureWindow(tkwin, valueMask, valuePtr)
  1208.     Tk_Window tkwin;        /* Window to re-configure. */
  1209.     unsigned int valueMask;    /* Mask indicating which parts of
  1210.                  * *valuePtr are to be used. */
  1211.     XWindowChanges *valuePtr;    /* New values. */
  1212. {
  1213.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1214.  
  1215.     if (valueMask & CWX) {
  1216.     winPtr->changes.x = valuePtr->x;
  1217.     }
  1218.     if (valueMask & CWY) {
  1219.     winPtr->changes.y = valuePtr->y;
  1220.     }
  1221.     if (valueMask & CWWidth) {
  1222.     winPtr->changes.width = valuePtr->width;
  1223.     }
  1224.     if (valueMask & CWHeight) {
  1225.     winPtr->changes.height = valuePtr->height;
  1226.     }
  1227.     if (valueMask & CWBorderWidth) {
  1228.     winPtr->changes.border_width = valuePtr->border_width;
  1229.     }
  1230.     if (valueMask & CWSibling|CWStackMode) {
  1231.     panic("Can't set sibling or stack mode from Tk_ConfigureWindow.");
  1232.     }
  1233.  
  1234.     if (winPtr->window != None) {
  1235.     XConfigureWindow(winPtr->display, winPtr->window,
  1236.         valueMask, valuePtr);
  1237.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1238.         DoConfigureNotify(winPtr);
  1239.     }
  1240.     } else {
  1241.     winPtr->dirtyChanges |= valueMask;
  1242.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1243.     }
  1244. }
  1245.  
  1246. void
  1247. Tk_MoveWindow(tkwin, x, y)
  1248.     Tk_Window tkwin;        /* Window to move. */
  1249.     int x, y;            /* New location for window (within
  1250.                  * parent). */
  1251. {
  1252.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1253.  
  1254.     winPtr->changes.x = x;
  1255.     winPtr->changes.y = y;
  1256.     if (winPtr->window != None) {
  1257.     XMoveWindow(winPtr->display, winPtr->window, x, y);
  1258.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1259.         DoConfigureNotify(winPtr);
  1260.     }
  1261.     } else {
  1262.     winPtr->dirtyChanges |= CWX|CWY;
  1263.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1264.     }
  1265. }
  1266.  
  1267. void
  1268. Tk_ResizeWindow(tkwin, width, height)
  1269.     Tk_Window tkwin;        /* Window to resize. */
  1270.     unsigned int width, height;    /* New dimensions for window. */
  1271. {
  1272.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1273.  
  1274.     winPtr->changes.width = width;
  1275.     winPtr->changes.height = height;
  1276.     if (winPtr->window != None) {
  1277.     XResizeWindow(winPtr->display, winPtr->window, width, height);
  1278.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1279.         DoConfigureNotify(winPtr);
  1280.     }
  1281.     } else {
  1282.     winPtr->dirtyChanges |= CWWidth|CWHeight;
  1283.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1284.     }
  1285. }
  1286.  
  1287. void
  1288. Tk_MoveResizeWindow(tkwin, x, y, width, height)
  1289.     Tk_Window tkwin;        /* Window to move and resize. */
  1290.     int x, y;            /* New location for window (within
  1291.                  * parent). */
  1292.     unsigned int width, height;    /* New dimensions for window. */
  1293. {
  1294.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1295.  
  1296.     winPtr->changes.x = x;
  1297.     winPtr->changes.y = y;
  1298.     winPtr->changes.width = width;
  1299.     winPtr->changes.height = height;
  1300.     if (winPtr->window != None) {
  1301.     XMoveResizeWindow(winPtr->display, winPtr->window,
  1302.         x, y, width, height);
  1303.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1304.         DoConfigureNotify(winPtr);
  1305.     }
  1306.     } else {
  1307.     winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight;
  1308.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1309.     }
  1310. }
  1311.  
  1312. void
  1313. Tk_SetWindowBorderWidth(tkwin, width)
  1314.     Tk_Window tkwin;        /* Window to modify. */
  1315.     int width;            /* New border width for window. */
  1316. {
  1317.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1318.  
  1319.     winPtr->changes.border_width = width;
  1320.     if (winPtr->window != None) {
  1321.     XSetWindowBorderWidth(winPtr->display, winPtr->window, width);
  1322.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1323.         DoConfigureNotify(winPtr);
  1324.     }
  1325.     } else {
  1326.     winPtr->dirtyChanges |= CWBorderWidth;
  1327.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1328.     }
  1329. }
  1330.  
  1331. void
  1332. Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr)
  1333.     Tk_Window tkwin;        /* Window to manipulate. */
  1334.     unsigned long valueMask;    /* OR'ed combination of bits,
  1335.                  * indicating which fields of
  1336.                  * *attsPtr are to be used. */
  1337.     register XSetWindowAttributes *attsPtr;
  1338.                 /* New values for some attributes. */
  1339. {
  1340.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1341.  
  1342.     if (valueMask & CWBackPixmap) {
  1343.     winPtr->atts.background_pixmap = attsPtr->background_pixmap;
  1344.     }
  1345.     if (valueMask & CWBackPixel) {
  1346.     winPtr->atts.background_pixel = attsPtr->background_pixel;
  1347.     }
  1348.     if (valueMask & CWBorderPixmap) {
  1349.     winPtr->atts.border_pixmap = attsPtr->border_pixmap;
  1350.     }
  1351.     if (valueMask & CWBorderPixel) {
  1352.     winPtr->atts.border_pixel = attsPtr->border_pixel;
  1353.     }
  1354.     if (valueMask & CWBitGravity) {
  1355.     winPtr->atts.bit_gravity = attsPtr->bit_gravity;
  1356.     }
  1357.     if (valueMask & CWWinGravity) {
  1358.     winPtr->atts.win_gravity = attsPtr->win_gravity;
  1359.     }
  1360.     if (valueMask & CWBackingStore) {
  1361.     winPtr->atts.backing_store = attsPtr->backing_store;
  1362.     }
  1363.     if (valueMask & CWBackingPlanes) {
  1364.     winPtr->atts.backing_planes = attsPtr->backing_planes;
  1365.     }
  1366.     if (valueMask & CWBackingPixel) {
  1367.     winPtr->atts.backing_pixel = attsPtr->backing_pixel;
  1368.     }
  1369.     if (valueMask & CWOverrideRedirect) {
  1370.     winPtr->atts.override_redirect = attsPtr->override_redirect;
  1371.     }
  1372.     if (valueMask & CWSaveUnder) {
  1373.     winPtr->atts.save_under = attsPtr->save_under;
  1374.     }
  1375.     if (valueMask & CWEventMask) {
  1376.     winPtr->atts.event_mask = attsPtr->event_mask;
  1377.     }
  1378.     if (valueMask & CWDontPropagate) {
  1379.     winPtr->atts.do_not_propagate_mask
  1380.         = attsPtr->do_not_propagate_mask;
  1381.     }
  1382.     if (valueMask & CWColormap) {
  1383.     winPtr->atts.colormap = attsPtr->colormap;
  1384.     }
  1385.     if (valueMask & CWCursor) {
  1386.     winPtr->atts.cursor = attsPtr->cursor;
  1387.     }
  1388.  
  1389.     if (winPtr->window != None) {
  1390.     XChangeWindowAttributes(winPtr->display, winPtr->window,
  1391.         valueMask, attsPtr);
  1392.     } else {
  1393.     winPtr->dirtyAtts |= valueMask;
  1394.     }
  1395. }
  1396.  
  1397. void
  1398. Tk_SetWindowBackground(tkwin, pixel)
  1399.     Tk_Window tkwin;        /* Window to manipulate. */
  1400.     unsigned long pixel;    /* Pixel value to use for
  1401.                  * window's background. */
  1402. {
  1403.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1404.  
  1405.     winPtr->atts.background_pixel = pixel;
  1406.  
  1407.     if (winPtr->window != None) {
  1408.     XSetWindowBackground(winPtr->display, winPtr->window, pixel);
  1409.     } else {
  1410.     winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBackPixmap)
  1411.         | CWBackPixel;
  1412.     }
  1413. }
  1414.  
  1415. void
  1416. Tk_SetWindowBackgroundPixmap(tkwin, pixmap)
  1417.     Tk_Window tkwin;        /* Window to manipulate. */
  1418.     Pixmap pixmap;        /* Pixmap to use for window's
  1419.                  * background. */
  1420. {
  1421.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1422.  
  1423.     winPtr->atts.background_pixmap = pixmap;
  1424.  
  1425.     if (winPtr->window != None) {
  1426.     XSetWindowBackgroundPixmap(winPtr->display,
  1427.         winPtr->window, pixmap);
  1428.     } else {
  1429.     winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBackPixel)
  1430.         | CWBackPixmap;
  1431.     }
  1432. }
  1433.  
  1434. void
  1435. Tk_SetWindowBorder(tkwin, pixel)
  1436.     Tk_Window tkwin;        /* Window to manipulate. */
  1437.     unsigned long pixel;    /* Pixel value to use for
  1438.                  * window's border. */
  1439. {
  1440.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1441.  
  1442.     winPtr->atts.border_pixel = pixel;
  1443.  
  1444.     if (winPtr->window != None) {
  1445.     XSetWindowBorder(winPtr->display, winPtr->window, pixel);
  1446.     } else {
  1447.     winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBorderPixmap)
  1448.         | CWBorderPixel;
  1449.     }
  1450. }
  1451.  
  1452. void
  1453. Tk_SetWindowBorderPixmap(tkwin, pixmap)
  1454.     Tk_Window tkwin;        /* Window to manipulate. */
  1455.     Pixmap pixmap;        /* Pixmap to use for window's
  1456.                  * border. */
  1457. {
  1458.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1459.  
  1460.     winPtr->atts.border_pixmap = pixmap;
  1461.  
  1462.     if (winPtr->window != None) {
  1463.     XSetWindowBorderPixmap(winPtr->display,
  1464.         winPtr->window, pixmap);
  1465.     } else {
  1466.     winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBorderPixel)
  1467.         | CWBorderPixmap;
  1468.     }
  1469. }
  1470.  
  1471. void
  1472. Tk_DefineCursor(tkwin, cursor)
  1473.     Tk_Window tkwin;        /* Window to manipulate. */
  1474.     Cursor cursor;        /* Cursor to use for window (may be None). */
  1475. {
  1476.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1477.  
  1478.     winPtr->atts.cursor = cursor;
  1479.  
  1480.     if (winPtr->window != None) {
  1481.     XDefineCursor(winPtr->display, winPtr->window, cursor);
  1482.     } else {
  1483.     winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor;
  1484.     }
  1485. }
  1486.  
  1487. void
  1488. Tk_UndefineCursor(tkwin)
  1489.     Tk_Window tkwin;        /* Window to manipulate. */
  1490. {
  1491.     Tk_DefineCursor(tkwin, None);
  1492. }
  1493.  
  1494. void
  1495. Tk_SetWindowColormap(tkwin, colormap)
  1496.     Tk_Window tkwin;        /* Window to manipulate. */
  1497.     Colormap colormap;        /* Colormap to use for window. */
  1498. {
  1499.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1500.  
  1501.     winPtr->atts.colormap = colormap;
  1502.  
  1503.     if (winPtr->window != None) {
  1504.     XSetWindowColormap(winPtr->display, winPtr->window, colormap);
  1505.     } else {
  1506.     winPtr->dirtyAtts |= CWColormap;
  1507.     }
  1508. }
  1509.  
  1510. /*
  1511.  *----------------------------------------------------------------------
  1512.  *
  1513.  * Tk_SetWindowVisual --
  1514.  *
  1515.  *    This procedure is called to specify a visual to be used
  1516.  *    for a Tk window when it is created.  This procedure, if
  1517.  *    called at all, must be called before the X window is created
  1518.  *    (i.e. before Tk_MakeWindowExist is called).
  1519.  *
  1520.  * Results:
  1521.  *    The return value is 1 if successful, or 0 if the X window has
  1522.  *    been already created.
  1523.  *
  1524.  * Side effects:
  1525.  *    The information given is stored for when the window is created.
  1526.  *
  1527.  *----------------------------------------------------------------------
  1528.  */
  1529.  
  1530. int
  1531. Tk_SetWindowVisual(tkwin, visual, depth, colormap)
  1532.     Tk_Window tkwin;        /* Window to manipulate. */
  1533.     Visual *visual;        /* New visual for window. */
  1534.     unsigned int depth;        /* New depth for window. */
  1535.     Colormap colormap;        /* An appropriate colormap for the visual. */
  1536. {
  1537.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1538.  
  1539.     if( winPtr->window != None ){
  1540.     /* Too late! */
  1541.     return 0;
  1542.     }
  1543.  
  1544.     winPtr->visual = visual;
  1545.     winPtr->depth = depth;
  1546.     winPtr->atts.colormap = colormap;
  1547.  
  1548.     /*
  1549.      * The following code is needed to make sure that the window doesn't
  1550.      * inherit the parent's border pixmap, which would result in a BadMatch
  1551.      * error.
  1552.      */
  1553.  
  1554.     if (!(winPtr->dirtyAtts & CWBorderPixmap)) {
  1555.     winPtr->dirtyAtts |= CWBorderPixel;
  1556.     }
  1557.     return 1;
  1558. }
  1559.  
  1560. /*
  1561.  *----------------------------------------------------------------------
  1562.  *
  1563.  * DoConfigureNotify --
  1564.  *
  1565.  *    Generate a ConfigureNotify event describing the current
  1566.  *    configuration of a window.
  1567.  *
  1568.  * Results:
  1569.  *    None.
  1570.  *
  1571.  * Side effects:
  1572.  *    An event is generated and processed by Tk_HandleEvent.
  1573.  *
  1574.  *----------------------------------------------------------------------
  1575.  */
  1576.  
  1577. static void
  1578. DoConfigureNotify(winPtr)
  1579.     register TkWindow *winPtr;        /* Window whose configuration
  1580.                      * was just changed. */
  1581. {
  1582.     XEvent event;
  1583.  
  1584.     event.type = ConfigureNotify;
  1585.     event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display);
  1586.     event.xconfigure.send_event = False;
  1587.     event.xconfigure.display = winPtr->display;
  1588.     event.xconfigure.event = winPtr->window;
  1589.     event.xconfigure.window = winPtr->window;
  1590.     event.xconfigure.x = winPtr->changes.x;
  1591.     event.xconfigure.y = winPtr->changes.y;
  1592.     event.xconfigure.width = winPtr->changes.width;
  1593.     event.xconfigure.height = winPtr->changes.height;
  1594.     event.xconfigure.border_width = winPtr->changes.border_width;
  1595.     if (winPtr->changes.stack_mode == Above) {
  1596.     event.xconfigure.above = winPtr->changes.sibling;
  1597.     } else {
  1598.     event.xconfigure.above = None;
  1599.     }
  1600.     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  1601.     Tk_HandleEvent(&event);
  1602. }
  1603.  
  1604. /*
  1605.  *----------------------------------------------------------------------
  1606.  *
  1607.  * Tk_SetClass --
  1608.  *
  1609.  *    This procedure is used to give a window a class.
  1610.  *
  1611.  * Results:
  1612.  *    None.
  1613.  *
  1614.  * Side effects:
  1615.  *    A new class is stored for tkwin, replacing any existing
  1616.  *    class for it.
  1617.  *
  1618.  *----------------------------------------------------------------------
  1619.  */
  1620.  
  1621. void
  1622. Tk_SetClass(tkwin, className)
  1623.     Tk_Window tkwin;        /* Token for window to assign class. */
  1624.     char *className;        /* New class for tkwin. */
  1625. {
  1626.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1627.  
  1628.     winPtr->classUid = Tk_GetUid(className);
  1629.     if (winPtr->flags & TK_TOP_LEVEL) {
  1630.     TkWmSetClass(winPtr);
  1631.     }
  1632. }
  1633.  
  1634. /*
  1635.  *----------------------------------------------------------------------
  1636.  *
  1637.  * Tk_NameToWindow --
  1638.  *
  1639.  *    Given a string name for a window, this procedure
  1640.  *    returns the token for the window, if there exists a
  1641.  *    window corresponding to the given name.
  1642.  *
  1643.  * Results:
  1644.  *    The return result is either a token for the window corresponding
  1645.  *    to "name", or else NULL to indicate that there is no such
  1646.  *    window.  In this case, an error message is left in interp->result.
  1647.  *
  1648.  * Side effects:
  1649.  *    None.
  1650.  *
  1651.  *----------------------------------------------------------------------
  1652.  */
  1653.  
  1654. Tk_Window
  1655. Tk_NameToWindow(interp, pathName, tkwin)
  1656.     Tcl_Interp *interp;        /* Where to report errors. */
  1657.     char *pathName;        /* Path name of window. */
  1658.     Tk_Window tkwin;        /* Token for window:  name is assumed to
  1659.                  * belong to the same main window as tkwin. */
  1660. {
  1661.     Tcl_HashEntry *hPtr;
  1662.  
  1663.     hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable,
  1664.         pathName);
  1665.     if (hPtr == NULL) {
  1666.     Tcl_AppendResult(interp, "bad window path name \"",
  1667.         pathName, "\"", (char *) NULL);
  1668.     return NULL;
  1669.     }
  1670.     return (Tk_Window) Tcl_GetHashValue(hPtr);
  1671. }
  1672.  
  1673. /*
  1674.  *----------------------------------------------------------------------
  1675.  *
  1676.  * Tk_DisplayName --
  1677.  *
  1678.  *    Return the textual name of a window's display.
  1679.  *
  1680.  * Results:
  1681.  *    The return value is the string name of the display associated
  1682.  *    with tkwin.
  1683.  *
  1684.  * Side effects:
  1685.  *    None.
  1686.  *
  1687.  *----------------------------------------------------------------------
  1688.  */
  1689.  
  1690. char *
  1691. Tk_DisplayName(tkwin)
  1692.     Tk_Window tkwin;        /* Window whose display name is desired. */
  1693. {
  1694.     return ((TkWindow *) tkwin)->dispPtr->name;
  1695. }
  1696.  
  1697. /*
  1698.  *----------------------------------------------------------------------
  1699.  *
  1700.  * Tk_SetColorModel --
  1701.  *
  1702.  *    This procedure changes the current color model for a window
  1703.  *    (actually, for the window's screen).
  1704.  *
  1705.  * Results:
  1706.  *    None.
  1707.  *
  1708.  * Side effects:
  1709.  *    The color model for tkwin's screen is set to "model".
  1710.  *
  1711.  *----------------------------------------------------------------------
  1712.  */
  1713.  
  1714. void
  1715. Tk_SetColorModel(tkwin, model)
  1716.     Tk_Window tkwin;        /* Token for window;  this selects a screen
  1717.                  * whose color model is to be modified. */
  1718.     Tk_ColorModel model;    /* New model for tkwin's screen. */
  1719. {
  1720.     TkWindow *winPtr = (TkWindow *) tkwin;
  1721.     winPtr->dispPtr->colorModels[winPtr->screenNum] = model;
  1722. }
  1723.  
  1724. /*
  1725.  *----------------------------------------------------------------------
  1726.  *
  1727.  * Tk_GetColorModel --
  1728.  *
  1729.  *    This procedure returns the current color model for a window
  1730.  *    (actually, for the window's screen).
  1731.  *
  1732.  * Results:
  1733.  *    A color model.
  1734.  *
  1735.  * Side effects:
  1736.  *    None.
  1737.  *
  1738.  *----------------------------------------------------------------------
  1739.  */
  1740.  
  1741. Tk_ColorModel
  1742. Tk_GetColorModel(tkwin)
  1743.     Tk_Window tkwin;        /* Token for window;  this selects a screen
  1744.                  * whose color model is returned. */
  1745. {
  1746.     TkWindow *winPtr = (TkWindow *) tkwin;
  1747.     return winPtr->dispPtr->colorModels[winPtr->screenNum];
  1748. }
  1749.  
  1750. /*
  1751.  *----------------------------------------------------------------------
  1752.  *
  1753.  * UnlinkWindow --
  1754.  *
  1755.  *    This procedure removes a window from the childList of its
  1756.  *    parent.
  1757.  *
  1758.  * Results:
  1759.  *    None.
  1760.  *
  1761.  * Side effects:
  1762.  *    The window is unlinked from its childList.
  1763.  *
  1764.  *----------------------------------------------------------------------
  1765.  */
  1766.  
  1767. static void
  1768. UnlinkWindow(winPtr)
  1769.     TkWindow *winPtr;            /* Child window to be unlinked. */
  1770. {
  1771.     TkWindow *prevPtr;
  1772.  
  1773.     if (winPtr->parentPtr == NULL) {
  1774.     return;
  1775.     }
  1776.     prevPtr = winPtr->parentPtr->childList;
  1777.     if (prevPtr == winPtr) {
  1778.     winPtr->parentPtr->childList = winPtr->nextPtr;
  1779.     if (winPtr->nextPtr == NULL) {
  1780.         winPtr->parentPtr->lastChildPtr = NULL;
  1781.     }
  1782.     } else {
  1783.     while (prevPtr->nextPtr != winPtr) {
  1784.         prevPtr = prevPtr->nextPtr;
  1785.         if (prevPtr == NULL) {
  1786.         panic("UnlinkWindow couldn't find child in parent");
  1787.         }
  1788.     }
  1789.     prevPtr->nextPtr = winPtr->nextPtr;
  1790.     if (winPtr->nextPtr == NULL) {
  1791.         winPtr->parentPtr->lastChildPtr = prevPtr;
  1792.     }
  1793.     }
  1794. }
  1795.  
  1796. /*
  1797.  *----------------------------------------------------------------------
  1798.  *
  1799.  * Tk_RestackWindow --
  1800.  *
  1801.  *    Change a window's position in the stacking order.
  1802.  *
  1803.  * Results:
  1804.  *    TCL_OK is normally returned.  If other is not a descendant
  1805.  *    of tkwin's parent then TCL_ERROR is returned and tkwin is
  1806.  *    not repositioned.
  1807.  *
  1808.  * Side effects:
  1809.  *    Tkwin is repositioned in the stacking order.
  1810.  *
  1811.  *----------------------------------------------------------------------
  1812.  */
  1813.  
  1814. int
  1815. Tk_RestackWindow(tkwin, aboveBelow, other)
  1816.     Tk_Window tkwin;        /* Token for window whose position in
  1817.                  * the stacking order is to change. */
  1818.     int aboveBelow;        /* Indicates new position of tkwin relative
  1819.                  * to other;  must be Above or Below. */
  1820.     Tk_Window other;        /* Tkwin will be moved to a position that
  1821.                  * puts it just above or below this window.
  1822.                  * If NULL then tkwin goes above or below
  1823.                  * all windows in the same parent. */
  1824. {
  1825.     TkWindow *winPtr = (TkWindow *) tkwin;
  1826.     TkWindow *otherPtr = (TkWindow *) other;
  1827.     XWindowChanges changes;
  1828.     unsigned int mask;
  1829.  
  1830.     /*
  1831.      * Special case:  if winPtr is a top-level window then just find
  1832.      * the top-level ancestor of otherPtr and restack winPtr above
  1833.      * otherPtr without changing any of Tk's childLists.
  1834.      */
  1835.  
  1836.     changes.stack_mode = aboveBelow;
  1837.     mask = CWStackMode;
  1838.     if (winPtr->flags & TK_TOP_LEVEL) {
  1839.     if (otherPtr != NULL) {
  1840.         while (!(otherPtr->flags & TK_TOP_LEVEL)) {
  1841.         otherPtr = otherPtr->parentPtr;
  1842.         }
  1843.     }
  1844.     TkWmRestackToplevel(winPtr, aboveBelow, otherPtr);
  1845.     return TCL_OK;
  1846.     }
  1847.  
  1848.     /*
  1849.      * Find an ancestor of otherPtr that is a sibling of winPtr.
  1850.      */
  1851.  
  1852.     if (otherPtr == NULL) {
  1853.     if (aboveBelow == Above) {
  1854.         otherPtr = winPtr->parentPtr->lastChildPtr;
  1855.     } else {
  1856.         otherPtr = winPtr->parentPtr->childList;
  1857.     }
  1858.     } else {
  1859.     while (winPtr->parentPtr != otherPtr->parentPtr) {
  1860.         if (otherPtr->flags & TK_TOP_LEVEL) {
  1861.         return TCL_ERROR;
  1862.         }
  1863.         otherPtr = otherPtr->parentPtr;
  1864.     }
  1865.     }
  1866.     if (otherPtr == winPtr) {
  1867.     return TCL_OK;
  1868.     }
  1869.  
  1870.     /*
  1871.      * Reposition winPtr in the stacking order.
  1872.      */
  1873.  
  1874.     UnlinkWindow(winPtr);
  1875.     if (aboveBelow == Above) {
  1876.     winPtr->nextPtr = otherPtr->nextPtr;
  1877.     if (winPtr->nextPtr == NULL) {
  1878.         winPtr->parentPtr->lastChildPtr = winPtr;
  1879.     }
  1880.     otherPtr->nextPtr = winPtr;
  1881.     } else {
  1882.     TkWindow *prevPtr;
  1883.  
  1884.     prevPtr = winPtr->parentPtr->childList;
  1885.     if (prevPtr == otherPtr) {
  1886.         winPtr->parentPtr->childList = winPtr;
  1887.     } else {
  1888.         while (prevPtr->nextPtr != otherPtr) {
  1889.         prevPtr = prevPtr->nextPtr;
  1890.         }
  1891.         prevPtr->nextPtr = winPtr;
  1892.     }
  1893.     winPtr->nextPtr = otherPtr;
  1894.     }
  1895.  
  1896.     /*
  1897.      * Notify the X server of the change.  If winPtr hasn't yet been
  1898.      * created then there's no need to tell the X server now, since
  1899.      * the stacking order will be handled properly when the window
  1900.      * is finally created.
  1901.      */
  1902.  
  1903.     if (winPtr->window != None) {
  1904.     changes.stack_mode = Above;
  1905.     for (otherPtr = winPtr->nextPtr; otherPtr != NULL;
  1906.         otherPtr = otherPtr->nextPtr) {
  1907.         if (otherPtr->window != None) {
  1908.         changes.sibling = otherPtr->window;
  1909.         changes.stack_mode = Below;
  1910.         mask = CWStackMode|CWSibling;
  1911.         break;
  1912.         }
  1913.     }
  1914.     XConfigureWindow(winPtr->display, winPtr->window, mask, &changes);
  1915.     }
  1916.     return TCL_OK;
  1917. }
  1918.