home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / mac / tkMacWm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  114.9 KB  |  4,097 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkMacWm.c --
  3.  *
  4.  *    This module takes care of the interactions between a Tk-based
  5.  *    application and the window manager.  Among other things, it
  6.  *    implements the "wm" command and passes geometry information
  7.  *    to the window manager.
  8.  *
  9.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * SCCS: @(#) tkMacWm.c 1.69 97/08/08 14:34:48
  15.  */
  16.  
  17. #include <QDOffscreen.h>
  18. #include <Windows.h>
  19. #include <ToolUtils.h>
  20.  
  21. #include "tkPort.h"
  22. #include "tkInt.h"
  23. #include "tkMacInt.h"
  24. #include <errno.h>
  25. #include "tkScrollbar.h"
  26.  
  27. /*
  28.  * A data structure of the following type holds information for
  29.  * each window manager protocol (such as WM_DELETE_WINDOW) for
  30.  * which a handler (i.e. a Tcl command) has been defined for a
  31.  * particular top-level window.
  32.  */
  33.  
  34. typedef struct ProtocolHandler {
  35.     Atom protocol;        /* Identifies the protocol. */
  36.     struct ProtocolHandler *nextPtr;
  37.                 /* Next in list of protocol handlers for
  38.                  * the same top-level window, or NULL for
  39.                  * end of list. */
  40.     Tcl_Interp *interp;        /* Interpreter in which to invoke command. */
  41.     char command[4];        /* Tcl command to invoke when a client
  42.                  * message for this protocol arrives. 
  43.                  * The actual size of the structure varies
  44.                  * to accommodate the needs of the actual
  45.                  * command. THIS MUST BE THE LAST FIELD OF
  46.                  * THE STRUCTURE. */
  47. } ProtocolHandler;
  48.  
  49. #define HANDLER_SIZE(cmdLength) \
  50. ((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
  51.  
  52. /*
  53.  * A data structure of the following type holds window-manager-related
  54.  * information for each top-level window in an application.
  55.  */
  56.  
  57. typedef struct TkWmInfo {
  58.     TkWindow *winPtr;        /* Pointer to main Tk information for
  59.                  * this window. */
  60.     Window reparent;        /* If the window has been reparented, this
  61.                  * gives the ID of the ancestor of the window
  62.                  * that is a child of the root window (may
  63.                  * not be window's immediate parent).  If
  64.                  * the window isn't reparented, this has the
  65.                  * value None. */
  66.     Tk_Uid titleUid;        /* Title to display in window caption.  If
  67.                  * NULL, use name of widget. */
  68.     Tk_Uid iconName;        /* Name to display in icon. */
  69.     Window master;        /* Master window for TRANSIENT_FOR property,
  70.                  * or None. */
  71.     XWMHints hints;        /* Various pieces of information for
  72.                  * window manager. */
  73.     char *leaderName;        /* Path name of leader of window group
  74.                  * (corresponds to hints.window_group).
  75.                  * Malloc-ed.  Note:  this field doesn't
  76.                  * get updated if leader is destroyed. */
  77.     char *masterWindowName;    /* Path name of window specified as master
  78.                  * in "wm transient" command, or NULL.
  79.                  * Malloc-ed. Note:  this field doesn't
  80.                  * get updated if masterWindowName is
  81.                  * destroyed. */
  82.     Tk_Window icon;        /* Window to use as icon for this window,
  83.                  * or NULL. */
  84.     Tk_Window iconFor;        /* Window for which this window is icon, or
  85.                  * NULL if this isn't an icon for anyone. */
  86.     int withdrawn;        /* Non-zero means window has been withdrawn. */
  87.  
  88.     /*
  89.      * Information used to construct an XSizeHints structure for
  90.      * the window manager:
  91.      */
  92.  
  93.     int sizeHintsFlags;        /* Flags word for XSizeHints structure.
  94.                  * If the PBaseSize flag is set then the
  95.                  * window is gridded;  otherwise it isn't
  96.                  * gridded. */
  97.     int minWidth, minHeight;    /* Minimum dimensions of window, in
  98.                  * grid units, not pixels. */
  99.     int maxWidth, maxHeight;    /* Maximum dimensions of window, in
  100.                  * grid units, not pixels. */
  101.     Tk_Window gridWin;        /* Identifies the window that controls
  102.                  * gridding for this top-level, or NULL if
  103.                  * the top-level isn't currently gridded. */
  104.     int widthInc, heightInc;    /* Increments for size changes (# pixels
  105.                  * per step). */
  106.     struct {
  107.     int x;    /* numerator */
  108.     int y;  /* denominator */
  109.     } minAspect, maxAspect;    /* Min/max aspect ratios for window. */
  110.     int reqGridWidth, reqGridHeight;
  111.                 /* The dimensions of the window (in
  112.                  * grid units) requested through
  113.                  * the geometry manager. */
  114.     int gravity;        /* Desired window gravity. */
  115.  
  116.     /*
  117.      * Information used to manage the size and location of a window.
  118.      */
  119.  
  120.     int width, height;        /* Desired dimensions of window, specified
  121.                  * in grid units.  These values are
  122.                  * set by the "wm geometry" command and by
  123.                  * ConfigureNotify events (for when wm
  124.                  * resizes window).  -1 means user hasn't
  125.                  * requested dimensions. */
  126.     int x, y;            /* Desired X and Y coordinates for window.
  127.                  * These values are set by "wm geometry",
  128.                  * plus by ConfigureNotify events (when wm
  129.                  * moves window).  These numbers are
  130.                  * different than the numbers stored in
  131.                  * winPtr->changes because (a) they could be
  132.                  * measured from the right or bottom edge
  133.                  * of the screen (see WM_NEGATIVE_X and
  134.                  * WM_NEGATIVE_Y flags) and (b) if the window
  135.                  * has been reparented then they refer to the
  136.                  * parent rather than the window itself. */
  137.     int parentWidth, parentHeight;
  138.                 /* Width and height of reparent, in pixels
  139.                  * *including border*.  If window hasn't been
  140.                  * reparented then these will be the outer
  141.                  * dimensions of the window, including
  142.                  * border. */
  143.     int xInParent, yInParent;    /* Offset of window within reparent,  measured
  144.                  * from upper-left outer corner of parent's
  145.                  * border to upper-left outer corner of child's
  146.                  * border.  If not reparented then these are
  147.                  * zero. */
  148.     int configWidth, configHeight;
  149.                 /* Dimensions passed to last request that we
  150.                  * issued to change geometry of window.  Used
  151.                  * to eliminate redundant resize operations. */
  152.  
  153.     /*
  154.      * Information about the virtual root window for this top-level,
  155.      * if there is one.
  156.      */
  157.  
  158.     Window vRoot;        /* Virtual root window for this top-level,
  159.                  * or None if there is no virtual root
  160.                  * window (i.e. just use the screen's root). */
  161.     int vRootX, vRootY;        /* Position of the virtual root inside the
  162.                  * root window.  If the WM_VROOT_OFFSET_STALE
  163.                  * flag is set then this information may be
  164.                  * incorrect and needs to be refreshed from
  165.                  * the X server.  If vRoot is None then these
  166.                  * values are both 0. */
  167.     unsigned int vRootWidth, vRootHeight;
  168.                 /* Dimensions of the virtual root window.
  169.                  * If vRoot is None, gives the dimensions
  170.                  * of the containing screen.  This information
  171.                  * is never stale, even though vRootX and
  172.                  * vRootY can be. */
  173.  
  174.     /*
  175.      * List of children of the toplevel which have private colormaps.
  176.      */
  177.  
  178.     TkWindow **cmapList;    /* Array of window with private colormaps. */
  179.     int cmapCount;        /* Number of windows in array. */
  180.  
  181.     /*
  182.      * Miscellaneous information.
  183.      */
  184.  
  185.     ProtocolHandler *protPtr;    /* First in list of protocol handlers for
  186.                  * this window (NULL means none). */
  187.     int cmdArgc;        /* Number of elements in cmdArgv below. */
  188.     char **cmdArgv;        /* Array of strings to store in the
  189.                  * WM_COMMAND property.  NULL means nothing
  190.                  * available. */
  191.     char *clientMachine;    /* String to store in WM_CLIENT_MACHINE
  192.                  * property, or NULL. */
  193.     int flags;            /* Miscellaneous flags, defined below. */
  194.  
  195.     /*
  196.      * Macintosh information.
  197.      */
  198.     int style;            /* Native window style. */
  199.     TkWindow *scrollWinPtr;    /* Ptr to scrollbar handling grow widget. */
  200. } WmInfo;
  201.  
  202.  
  203. /*
  204.  * Flag values for WmInfo structures:
  205.  *
  206.  * WM_NEVER_MAPPED -        non-zero means window has never been
  207.  *                mapped;  need to update all info when
  208.  *                window is first mapped.
  209.  * WM_UPDATE_PENDING -        non-zero means a call to UpdateGeometryInfo
  210.  *                has already been scheduled for this
  211.  *                window;  no need to schedule another one.
  212.  * WM_NEGATIVE_X -        non-zero means x-coordinate is measured in
  213.  *                pixels from right edge of screen, rather
  214.  *                than from left edge.
  215.  * WM_NEGATIVE_Y -        non-zero means y-coordinate is measured in
  216.  *                pixels up from bottom of screen, rather than
  217.  *                down from top.
  218.  * WM_UPDATE_SIZE_HINTS -    non-zero means that new size hints need to be
  219.  *                propagated to window manager.
  220.  * WM_SYNC_PENDING -        set to non-zero while waiting for the window
  221.  *                manager to respond to some state change.
  222.  * WM_VROOT_OFFSET_STALE -    non-zero means that (x,y) offset information
  223.  *                about the virtual root window is stale and
  224.  *                needs to be fetched fresh from the X server.
  225.  * WM_ABOUT_TO_MAP -        non-zero means that the window is about to
  226.  *                be mapped by TkWmMapWindow.  This is used
  227.  *                by UpdateGeometryInfo to modify its behavior.
  228.  * WM_MOVE_PENDING -        non-zero means the application has requested
  229.  *                a new position for the window, but it hasn't
  230.  *                been reflected through the window manager
  231.  *                yet.
  232.  * WM_COLORMAPS_EXPLICIT -    non-zero means the colormap windows were
  233.  *                set explicitly via "wm colormapwindows".
  234.  * WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows"
  235.  *                was called the top-level itself wasn't
  236.  *                specified, so we added it implicitly at
  237.  *                the end of the list.
  238.  * WM_WIDTH_NOT_RESIZABLE -    non-zero means that we're not supposed to
  239.  *                allow the user to change the width of the
  240.  *                window (controlled by "wm resizable"
  241.  *                command).
  242.  * WM_HEIGHT_NOT_RESIZABLE -    non-zero means that we're not supposed to
  243.  *                allow the user to change the height of the
  244.  *                window (controlled by "wm resizable"
  245.  *                command).
  246.  */
  247.  
  248. #define WM_NEVER_MAPPED            1
  249. #define WM_UPDATE_PENDING        2
  250. #define WM_NEGATIVE_X            4
  251. #define WM_NEGATIVE_Y            8
  252. #define WM_UPDATE_SIZE_HINTS        0x10
  253. #define WM_SYNC_PENDING            0x20
  254. #define WM_VROOT_OFFSET_STALE        0x40
  255. #define WM_ABOUT_TO_MAP            0x100
  256. #define WM_MOVE_PENDING            0x200
  257. #define WM_COLORMAPS_EXPLICIT        0x400
  258. #define WM_ADDED_TOPLEVEL_COLORMAP    0x800
  259. #define WM_WIDTH_NOT_RESIZABLE        0x1000
  260. #define WM_HEIGHT_NOT_RESIZABLE        0x2000
  261.  
  262. /*
  263.  * This is a list of all of the toplevels that have been mapped so far. It is
  264.  * used by the menu code to inval windows that were damaged by menus, and will
  265.  * eventually also be used to keep track of floating windows.
  266.  */
  267.  
  268. TkMacWindowList *tkMacWindowListPtr = NULL;
  269.  
  270. /*
  271.  * The variable below is used to enable or disable tracing in this
  272.  * module.  If tracing is enabled, then information is printed on
  273.  * standard output about interesting interactions with the window
  274.  * manager.
  275.  */
  276.  
  277. static int wmTracing = 0;
  278.  
  279. /*
  280.  * The following structure is the official type record for geometry
  281.  * management of top-level windows.
  282.  */
  283.  
  284. static void        TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
  285.     Tk_Window tkwin));
  286.  
  287. static Tk_GeomMgr wmMgrType = {
  288.     "wm",                /* name */
  289.     TopLevelReqProc,            /* requestProc */
  290.     (Tk_GeomLostSlaveProc *) NULL,    /* lostSlaveProc */
  291. };
  292.  
  293. /*
  294.  * Hash table for Mac Window -> TkWindow mapping.
  295.  */
  296.  
  297. static Tcl_HashTable windowTable;
  298. static int windowHashInit = false;
  299.  
  300. void MacMoveWindow(WindowRef window, int x, int y);
  301.  
  302. /*
  303.  * Forward declarations for procedures defined in this file:
  304.  */
  305.  
  306. static void        InitialWindowBounds _ANSI_ARGS_((TkWindow *winPtr, 
  307.                 Rect *geometry));
  308. static int        ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
  309.                 char *string, TkWindow *winPtr));
  310. static void        TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
  311.                 XEvent *eventPtr));
  312. static void        TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
  313.                 Tk_Window tkwin));
  314. static void        UpdateGeometryInfo _ANSI_ARGS_((
  315.                 ClientData clientData));
  316. static void        UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr));
  317. static void        UpdateVRootGeometry _ANSI_ARGS_((WmInfo *wmPtr));
  318.  
  319. /*
  320.  *--------------------------------------------------------------
  321.  *
  322.  * TkWmNewWindow --
  323.  *
  324.  *    This procedure is invoked whenever a new top-level
  325.  *    window is created.  Its job is to initialize the WmInfo
  326.  *    structure for the window.
  327.  *
  328.  * Results:
  329.  *    None.
  330.  *
  331.  * Side effects:
  332.  *    A WmInfo structure gets allocated and initialized.
  333.  *
  334.  *--------------------------------------------------------------
  335.  */
  336.  
  337. void
  338. TkWmNewWindow(
  339.     TkWindow *winPtr)        /* Newly-created top-level window. */
  340. {
  341.     register WmInfo *wmPtr;
  342.     
  343.     wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
  344.     wmPtr->winPtr = winPtr;
  345.     wmPtr->reparent = None;
  346.     wmPtr->titleUid = NULL;
  347.     wmPtr->iconName = NULL;
  348.     wmPtr->master = None;
  349.     wmPtr->hints.flags = InputHint | StateHint;
  350.     wmPtr->hints.input = True;
  351.     wmPtr->hints.initial_state = NormalState;
  352.     wmPtr->hints.icon_pixmap = None;
  353.     wmPtr->hints.icon_window = None;
  354.     wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
  355.     wmPtr->hints.icon_mask = None;
  356.     wmPtr->hints.window_group = None;
  357.     wmPtr->leaderName = NULL;
  358.     wmPtr->masterWindowName = NULL;
  359.     wmPtr->icon = NULL;
  360.     wmPtr->iconFor = NULL;
  361.     wmPtr->withdrawn = 0;
  362.     wmPtr->sizeHintsFlags = 0;
  363.     wmPtr->minWidth = wmPtr->minHeight = 1;
  364.  
  365.     /*
  366.      * Default the maximum dimensions to the size of the display, minus
  367.      * a guess about how space is needed for window manager decorations.
  368.      */
  369.  
  370.     wmPtr->maxWidth = DisplayWidth(winPtr->display, winPtr->screenNum) - 15;
  371.     wmPtr->maxHeight = DisplayHeight(winPtr->display, winPtr->screenNum) - 30;
  372.     wmPtr->gridWin = NULL;
  373.     wmPtr->widthInc = wmPtr->heightInc = 1;
  374.     wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
  375.     wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
  376.     wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
  377.     wmPtr->gravity = NorthWestGravity;
  378.     wmPtr->width = -1;
  379.     wmPtr->height = -1;
  380.     wmPtr->x = winPtr->changes.x;
  381.     wmPtr->y = winPtr->changes.y;
  382.     wmPtr->parentWidth = winPtr->changes.width
  383.     + 2*winPtr->changes.border_width;
  384.     wmPtr->parentHeight = winPtr->changes.height
  385.     + 2*winPtr->changes.border_width;
  386.     wmPtr->xInParent = 0;
  387.     wmPtr->yInParent = 0;
  388.     wmPtr->cmapList = NULL;
  389.     wmPtr->cmapCount = 0;
  390.     wmPtr->configWidth = -1;
  391.     wmPtr->configHeight = -1;
  392.     wmPtr->vRoot = None;
  393.     wmPtr->protPtr = NULL;
  394.     wmPtr->cmdArgv = NULL;
  395.     wmPtr->clientMachine = NULL;
  396.     wmPtr->flags = WM_NEVER_MAPPED;
  397.     wmPtr->style = zoomDocProc;
  398.     wmPtr->scrollWinPtr = NULL;
  399.     winPtr->wmInfoPtr = wmPtr;
  400.  
  401.     UpdateVRootGeometry(wmPtr);
  402.  
  403.     /*
  404.      * Tk must monitor structure events for top-level windows, in order
  405.      * to detect size and position changes caused by window managers.
  406.      */
  407.  
  408.     Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
  409.         TopLevelEventProc, (ClientData) winPtr);
  410.  
  411.     /*
  412.      * Arrange for geometry requests to be reflected from the window
  413.      * to the window manager.
  414.      */
  415.  
  416.     Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
  417. }
  418.  
  419. /*
  420.  *--------------------------------------------------------------
  421.  *
  422.  * TkWmMapWindow --
  423.  *
  424.  *    This procedure is invoked to map a top-level window.  This
  425.  *    module gets a chance to update all window-manager-related
  426.  *    information in properties before the window manager sees
  427.  *    the map event and checks the properties.  It also gets to
  428.  *    decide whether or not to even map the window after all.
  429.  *
  430.  * Results:
  431.  *    None.
  432.  *
  433.  * Side effects:
  434.  *    Properties of winPtr may get updated to provide up-to-date
  435.  *    information to the window manager.  The window may also get
  436.  *    mapped, but it may not be if this procedure decides that
  437.  *    isn't appropriate (e.g. because the window is withdrawn).
  438.  *
  439.  *--------------------------------------------------------------
  440.  */
  441.  
  442. void
  443. TkWmMapWindow(
  444.     TkWindow *winPtr)        /* Top-level window that's about to
  445.                  * be mapped. */
  446. {
  447.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  448.     Point where = {0, 0};
  449.     int xOffset, yOffset;        
  450.     int firstMap = false;
  451.     MacDrawable *macWin;
  452.  
  453.     if (wmPtr->flags & WM_NEVER_MAPPED) {
  454.     wmPtr->flags &= ~WM_NEVER_MAPPED;
  455.     firstMap = true;
  456.  
  457.     /*
  458.      * Create the underlying Mac window for this Tk window.
  459.      */
  460.     macWin = (MacDrawable *) winPtr->window;
  461.     if (!TkMacHostToplevelExists(winPtr)) {
  462.         TkMacMakeRealWindowExist(winPtr);
  463.     }
  464.     
  465.     /*
  466.      * Generate configure event when we first map the window.
  467.      */
  468.     LocalToGlobal(&where);
  469.     TkMacWindowOffset((WindowRef) TkMacGetDrawablePort((Drawable) macWin),
  470.         &xOffset, &yOffset);
  471.     where.h -= xOffset;
  472.     where.v -= yOffset;
  473.     TkGenWMConfigureEvent((Tk_Window) winPtr, 
  474.         where.h, where.v, -1, -1, TK_LOCATION_CHANGED);
  475.     
  476.     /*
  477.      * This is the first time this window has ever been mapped.
  478.      * Store all the window-manager-related information for the
  479.      * window.
  480.      */
  481.  
  482.     if (wmPtr->titleUid == NULL) {
  483.         wmPtr->titleUid = winPtr->nameUid;
  484.     }
  485.     
  486.     if (!Tk_IsEmbedded(winPtr)) {
  487.         TkSetWMName(winPtr, wmPtr->titleUid);
  488.     }
  489.  
  490.     TkWmSetClass(winPtr);
  491.     
  492.     if (wmPtr->iconName != NULL) {
  493.         XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
  494.     }
  495.     
  496.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  497.     }
  498.     if ((wmPtr->hints.initial_state == WithdrawnState) ||
  499.     (wmPtr->hints.initial_state == IconicState)) {
  500.     return;
  501.     }
  502.  
  503.     /*
  504.      * Update geometry information.
  505.      */
  506.     wmPtr->flags |= WM_ABOUT_TO_MAP;
  507.     if (wmPtr->flags & WM_UPDATE_PENDING) {
  508.     Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
  509.     }
  510.     UpdateGeometryInfo((ClientData) winPtr);
  511.     wmPtr->flags &= ~WM_ABOUT_TO_MAP;
  512.  
  513.     /*
  514.      * Map the window.
  515.      */
  516.  
  517.     XMapWindow(winPtr->display, winPtr->window);
  518.     
  519.     /*
  520.      * Now that the window is visable we can determine the offset
  521.      * from the window's content orgin to the window's decorative
  522.      * orgin (structure orgin).
  523.      */
  524.     TkMacWindowOffset((WindowRef) TkMacGetDrawablePort(Tk_WindowId(winPtr)), 
  525.     &wmPtr->xInParent, &wmPtr->yInParent);
  526. }
  527.  
  528. /*
  529.  *--------------------------------------------------------------
  530.  *
  531.  * TkWmUnmapWindow --
  532.  *
  533.  *    This procedure is invoked to unmap a top-level window.
  534.  *    On the Macintosh all we do is call XUnmapWindow.
  535.  *
  536.  * Results:
  537.  *    None.
  538.  *
  539.  * Side effects:
  540.  *    Unmaps the window.
  541.  *
  542.  *--------------------------------------------------------------
  543.  */
  544.  
  545. void
  546. TkWmUnmapWindow(
  547.     TkWindow *winPtr)        /* Top-level window that's about to
  548.                  * be mapped. */
  549. {
  550.     XUnmapWindow(winPtr->display, winPtr->window);
  551. }
  552.  
  553. /*
  554.  *--------------------------------------------------------------
  555.  *
  556.  * TkWmDeadWindow --
  557.  *
  558.  *    This procedure is invoked when a top-level window is
  559.  *    about to be deleted.  It cleans up the wm-related data
  560.  *    structures for the window.
  561.  *
  562.  * Results:
  563.  *    None.
  564.  *
  565.  * Side effects:
  566.  *    The WmInfo structure for winPtr gets freed up.
  567.  *
  568.  *--------------------------------------------------------------
  569.  */
  570.  
  571. void
  572. TkWmDeadWindow(winPtr)
  573.     TkWindow *winPtr;        /* Top-level window that's being deleted. */
  574. {
  575.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  576.     WmInfo *wmPtr2;
  577.  
  578.     if (wmPtr == NULL) {
  579.     return;
  580.     }
  581.     if (wmPtr->hints.flags & IconPixmapHint) {
  582.     Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
  583.     }
  584.     if (wmPtr->hints.flags & IconMaskHint) {
  585.     Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
  586.     }
  587.     if (wmPtr->leaderName != NULL) {
  588.     ckfree(wmPtr->leaderName);
  589.     }
  590.     if (wmPtr->masterWindowName != NULL) {
  591.     ckfree(wmPtr->masterWindowName);
  592.     }
  593.     if (wmPtr->icon != NULL) {
  594.     wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  595.     wmPtr2->iconFor = NULL;
  596.     wmPtr2->withdrawn = 1;
  597.     }
  598.     if (wmPtr->iconFor != NULL) {
  599.     wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
  600.     wmPtr2->icon = NULL;
  601.     wmPtr2->hints.flags &= ~IconWindowHint;
  602.     }
  603.     while (wmPtr->protPtr != NULL) {
  604.     ProtocolHandler *protPtr;
  605.  
  606.     protPtr = wmPtr->protPtr;
  607.     wmPtr->protPtr = protPtr->nextPtr;
  608.     Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
  609.     }
  610.     if (wmPtr->cmdArgv != NULL) {
  611.     ckfree((char *) wmPtr->cmdArgv);
  612.     }
  613.     if (wmPtr->clientMachine != NULL) {
  614.     ckfree((char *) wmPtr->clientMachine);
  615.     }
  616.     if (wmPtr->flags & WM_UPDATE_PENDING) {
  617.     Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
  618.     }
  619.     ckfree((char *) wmPtr);
  620.     winPtr->wmInfoPtr = NULL;
  621. }
  622.  
  623. /*
  624.  *--------------------------------------------------------------
  625.  *
  626.  * TkWmSetClass --
  627.  *
  628.  *    This procedure is invoked whenever a top-level window's
  629.  *    class is changed.  If the window has been mapped then this
  630.  *    procedure updates the window manager property for the
  631.  *    class.  If the window hasn't been mapped, the update is
  632.  *    deferred until just before the first mapping.
  633.  *
  634.  * Results:
  635.  *    None.
  636.  *
  637.  * Side effects:
  638.  *    A window property may get updated.
  639.  *
  640.  *--------------------------------------------------------------
  641.  */
  642.  
  643. void
  644. TkWmSetClass(
  645.     TkWindow *winPtr)        /* Newly-created top-level window. */
  646. {
  647.     return;
  648. }
  649.  
  650. /*
  651.  *----------------------------------------------------------------------
  652.  *
  653.  * Tk_WmCmd --
  654.  *
  655.  *    This procedure is invoked to process the "wm" Tcl command.
  656.  *    See the user documentation for details on what it does.
  657.  *
  658.  * Results:
  659.  *    A standard Tcl result.
  660.  *
  661.  * Side effects:
  662.  *    See the user documentation.
  663.  *
  664.  *----------------------------------------------------------------------
  665.  */
  666.  
  667.     /* ARGSUSED */
  668. int
  669. Tk_WmCmd(
  670.     ClientData clientData,    /* Main window associated with
  671.                  * interpreter. */
  672.     Tcl_Interp *interp,        /* Current interpreter. */
  673.     int argc,            /* Number of arguments. */
  674.     char **argv)        /* Argument strings. */
  675. {
  676.     Tk_Window tkwin = (Tk_Window) clientData;
  677.     TkWindow *winPtr;
  678.     register WmInfo *wmPtr;
  679.     int c;
  680.     size_t length;
  681.  
  682.     if (argc < 2) {
  683.     wrongNumArgs:
  684.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  685.         argv[0], " option window ?arg ...?\"", (char *) NULL);
  686.     return TCL_ERROR;
  687.     }
  688.     c = argv[1][0];
  689.     length = strlen(argv[1]);
  690.     if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0)
  691.         && (length >= 3)) {
  692.     if ((argc != 2) && (argc != 3)) {
  693.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  694.             argv[0], " tracing ?boolean?\"", (char *) NULL);
  695.         return TCL_ERROR;
  696.     }
  697.     if (argc == 2) {
  698.         interp->result = (wmTracing) ? "on" : "off";
  699.         return TCL_OK;
  700.     }
  701.     return Tcl_GetBoolean(interp, argv[2], &wmTracing);
  702.     }
  703.  
  704.     if (argc < 3) {
  705.     goto wrongNumArgs;
  706.     }
  707.     winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
  708.     if (winPtr == NULL) {
  709.     return TCL_ERROR;
  710.     }
  711.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  712.     Tcl_AppendResult(interp, "window \"", winPtr->pathName,
  713.         "\" isn't a top-level window", (char *) NULL);
  714.     return TCL_ERROR;
  715.     }
  716.     wmPtr = winPtr->wmInfoPtr;
  717.     if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
  718.     int numer1, denom1, numer2, denom2;
  719.  
  720.     if ((argc != 3) && (argc != 7)) {
  721.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  722.             argv[0], " aspect window ?minNumer minDenom ",
  723.             "maxNumer maxDenom?\"", (char *) NULL);
  724.         return TCL_ERROR;
  725.     }
  726.     if (argc == 3) {
  727.         if (wmPtr->sizeHintsFlags & PAspect) {
  728.         sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
  729.             wmPtr->minAspect.y, wmPtr->maxAspect.x,
  730.             wmPtr->maxAspect.y);
  731.         }
  732.         return TCL_OK;
  733.     }
  734.     if (*argv[3] == '\0') {
  735.         wmPtr->sizeHintsFlags &= ~PAspect;
  736.     } else {
  737.         if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
  738.             || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
  739.             || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
  740.             || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
  741.         return TCL_ERROR;
  742.         }
  743.         if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
  744.             (denom2 <= 0)) {
  745.         interp->result = "aspect number can't be <= 0";
  746.         return TCL_ERROR;
  747.         }
  748.         wmPtr->minAspect.x = numer1;
  749.         wmPtr->minAspect.y = denom1;
  750.         wmPtr->maxAspect.x = numer2;
  751.         wmPtr->maxAspect.y = denom2;
  752.         wmPtr->sizeHintsFlags |= PAspect;
  753.     }
  754.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  755.     goto updateGeom;
  756.     } else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0)
  757.         && (length >= 2)) {
  758.     if ((argc != 3) && (argc != 4)) {
  759.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  760.             argv[0], " client window ?name?\"",
  761.             (char *) NULL);
  762.         return TCL_ERROR;
  763.     }
  764.     if (argc == 3) {
  765.         if (wmPtr->clientMachine != NULL) {
  766.         interp->result = wmPtr->clientMachine;
  767.         }
  768.         return TCL_OK;
  769.     }
  770.     if (argv[3][0] == 0) {
  771.         if (wmPtr->clientMachine != NULL) {
  772.         ckfree((char *) wmPtr->clientMachine);
  773.         wmPtr->clientMachine = NULL;
  774.         }
  775.         return TCL_OK;
  776.     }
  777.     if (wmPtr->clientMachine != NULL) {
  778.         ckfree((char *) wmPtr->clientMachine);
  779.     }
  780.     wmPtr->clientMachine = (char *)
  781.         ckalloc((unsigned) (strlen(argv[3]) + 1));
  782.     strcpy(wmPtr->clientMachine, argv[3]);
  783.     } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0)
  784.         && (length >= 3)) {
  785.     TkWindow **cmapList;
  786.     TkWindow *winPtr2;
  787.     int i, windowArgc, gotToplevel;
  788.     char **windowArgv;
  789.  
  790.     if ((argc != 3) && (argc != 4)) {
  791.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  792.             argv[0], " colormapwindows window ?windowList?\"",
  793.             (char *) NULL);
  794.         return TCL_ERROR;
  795.     }
  796.     if (argc == 3) {
  797.         Tk_MakeWindowExist((Tk_Window) winPtr);
  798.         for (i = 0; i < wmPtr->cmapCount; i++) {
  799.         if ((i == (wmPtr->cmapCount-1))
  800.             && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
  801.             break;
  802.         }
  803.         Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
  804.         }
  805.         return TCL_OK;
  806.     }
  807.     if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv)
  808.         != TCL_OK) {
  809.         return TCL_ERROR;
  810.     }
  811.     cmapList = (TkWindow **) ckalloc((unsigned)
  812.         ((windowArgc+1)*sizeof(TkWindow*)));
  813.     for (i = 0; i < windowArgc; i++) {
  814.         winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i],
  815.             tkwin);
  816.         if (winPtr2 == NULL) {
  817.         ckfree((char *) cmapList);
  818.         ckfree((char *) windowArgv);
  819.         return TCL_ERROR;
  820.         }
  821.         if (winPtr2 == winPtr) {
  822.         gotToplevel = 1;
  823.         }
  824.         if (winPtr2->window == None) {
  825.         Tk_MakeWindowExist((Tk_Window) winPtr2);
  826.         }
  827.         cmapList[i] = winPtr2;
  828.     }
  829.     if (!gotToplevel) {
  830.         wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
  831.         cmapList[windowArgc] = winPtr;
  832.         windowArgc++;
  833.     } else {
  834.         wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
  835.     }
  836.     wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
  837.     if (wmPtr->cmapList != NULL) {
  838.         ckfree((char *)wmPtr->cmapList);
  839.     }
  840.     wmPtr->cmapList = cmapList;
  841.     wmPtr->cmapCount = windowArgc;
  842.     ckfree((char *) windowArgv);
  843.  
  844.     /*
  845.      * On the Macintosh all of this is just an excercise
  846.      * in compatability as we don't support colormaps.  If 
  847.      * we did they would be installed here.
  848.      */
  849.  
  850.     return TCL_OK;
  851.     } else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0)
  852.         && (length >= 3)) {
  853.     int cmdArgc;
  854.     char **cmdArgv;
  855.  
  856.     if ((argc != 3) && (argc != 4)) {
  857.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  858.             argv[0], " command window ?value?\"",
  859.             (char *) NULL);
  860.         return TCL_ERROR;
  861.     }
  862.     if (argc == 3) {
  863.         if (wmPtr->cmdArgv != NULL) {
  864.         interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
  865.         interp->freeProc = (Tcl_FreeProc *) free;
  866.         }
  867.         return TCL_OK;
  868.     }
  869.     if (argv[3][0] == 0) {
  870.         if (wmPtr->cmdArgv != NULL) {
  871.         ckfree((char *) wmPtr->cmdArgv);
  872.         wmPtr->cmdArgv = NULL;
  873.         }
  874.         return TCL_OK;
  875.     }
  876.     if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) {
  877.         return TCL_ERROR;
  878.     }
  879.     if (wmPtr->cmdArgv != NULL) {
  880.         ckfree((char *) wmPtr->cmdArgv);
  881.     }
  882.     wmPtr->cmdArgc = cmdArgc;
  883.     wmPtr->cmdArgv = cmdArgv;
  884.     } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
  885.     if (argc != 3) {
  886.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  887.             argv[0], " deiconify window\"", (char *) NULL);
  888.         return TCL_ERROR;
  889.     }
  890.     if (wmPtr->iconFor != NULL) {
  891.         Tcl_AppendResult(interp, "can't deiconify ", argv[2],
  892.             ": it is an icon for ", winPtr->pathName, (char *) NULL);
  893.         return TCL_ERROR;
  894.     }
  895.     wmPtr->hints.initial_state = NormalState;
  896.     wmPtr->withdrawn = 0;
  897.     if (wmPtr->flags & WM_NEVER_MAPPED) {
  898.         return TCL_OK;
  899.     }
  900.     Tk_MapWindow((Tk_Window) winPtr);
  901.     } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
  902.         && (length >= 2)) {
  903.     if ((argc != 3) && (argc != 4)) {
  904.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  905.             argv[0], " focusmodel window ?active|passive?\"",
  906.             (char *) NULL);
  907.         return TCL_ERROR;
  908.     }
  909.     if (argc == 3) {
  910.         interp->result = wmPtr->hints.input ? "passive" : "active";
  911.         return TCL_OK;
  912.     }
  913.     c = argv[3][0];
  914.     length = strlen(argv[3]);
  915.     if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
  916.         wmPtr->hints.input = False;
  917.     } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
  918.         wmPtr->hints.input = True;
  919.     } else {
  920.         Tcl_AppendResult(interp, "bad argument \"", argv[3],
  921.             "\": must be active or passive", (char *) NULL);
  922.         return TCL_ERROR;
  923.     }
  924.     } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
  925.         && (length >= 2)) {
  926.     Window window;
  927.  
  928.     if (argc != 3) {
  929.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  930.             argv[0], " frame window\"", (char *) NULL);
  931.         return TCL_ERROR;
  932.     }
  933.     window = wmPtr->reparent;
  934.     if (window == None) {
  935.         window = Tk_WindowId((Tk_Window) winPtr);
  936.     }
  937.     sprintf(interp->result, "0x%x", (unsigned int) window);
  938.     } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
  939.         && (length >= 2)) {
  940.     char xSign, ySign;
  941.     int width, height;
  942.  
  943.     if ((argc != 3) && (argc != 4)) {
  944.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  945.             argv[0], " geometry window ?newGeometry?\"",
  946.             (char *) NULL);
  947.         return TCL_ERROR;
  948.     }
  949.     if (argc == 3) {
  950.         xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
  951.         ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
  952.         if (wmPtr->gridWin != NULL) {
  953.         width = wmPtr->reqGridWidth + (winPtr->changes.width
  954.             - winPtr->reqWidth)/wmPtr->widthInc;
  955.         height = wmPtr->reqGridHeight + (winPtr->changes.height
  956.             - winPtr->reqHeight)/wmPtr->heightInc;
  957.         } else {
  958.         width = winPtr->changes.width;
  959.         height = winPtr->changes.height;
  960.         }
  961.         sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
  962.             xSign, wmPtr->x, ySign, wmPtr->y);
  963.         return TCL_OK;
  964.     }
  965.     if (*argv[3] == '\0') {
  966.         wmPtr->width = -1;
  967.         wmPtr->height = -1;
  968.         goto updateGeom;
  969.     }
  970.     return ParseGeometry(interp, argv[3], winPtr);
  971.     } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
  972.         && (length >= 3)) {
  973.     int reqWidth, reqHeight, widthInc, heightInc;
  974.  
  975.     if ((argc != 3) && (argc != 7)) {
  976.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  977.             argv[0], " grid window ?baseWidth baseHeight ",
  978.             "widthInc heightInc?\"", (char *) NULL);
  979.         return TCL_ERROR;
  980.     }
  981.     if (argc == 3) {
  982.         if (wmPtr->sizeHintsFlags & PBaseSize) {
  983.         sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
  984.             wmPtr->reqGridHeight, wmPtr->widthInc,
  985.             wmPtr->heightInc);
  986.         }
  987.         return TCL_OK;
  988.     }
  989.     if (*argv[3] == '\0') {
  990.         /*
  991.          * Turn off gridding and reset the width and height
  992.          * to make sense as ungridded numbers.
  993.          */
  994.  
  995.         wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
  996.         if (wmPtr->width != -1) {
  997.         wmPtr->width = winPtr->reqWidth + (wmPtr->width
  998.             - wmPtr->reqGridWidth)*wmPtr->widthInc;
  999.         wmPtr->height = winPtr->reqHeight + (wmPtr->height
  1000.             - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1001.         }
  1002.         wmPtr->widthInc = 1;
  1003.         wmPtr->heightInc = 1;
  1004.     } else {
  1005.         if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
  1006.             || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
  1007.             || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
  1008.             || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
  1009.         return TCL_ERROR;
  1010.         }
  1011.         if (reqWidth < 0) {
  1012.         interp->result = "baseWidth can't be < 0";
  1013.         return TCL_ERROR;
  1014.         }
  1015.         if (reqHeight < 0) {
  1016.         interp->result = "baseHeight can't be < 0";
  1017.         return TCL_ERROR;
  1018.         }
  1019.         if (widthInc < 0) {
  1020.         interp->result = "widthInc can't be < 0";
  1021.         return TCL_ERROR;
  1022.         }
  1023.         if (heightInc < 0) {
  1024.         interp->result = "heightInc can't be < 0";
  1025.         return TCL_ERROR;
  1026.         }
  1027.         Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
  1028.             heightInc);
  1029.     }
  1030.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1031.     goto updateGeom;
  1032.     } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
  1033.         && (length >= 3)) {
  1034.     Tk_Window tkwin2;
  1035.  
  1036.     if ((argc != 3) && (argc != 4)) {
  1037.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1038.             argv[0], " group window ?pathName?\"",
  1039.             (char *) NULL);
  1040.         return TCL_ERROR;
  1041.     }
  1042.     if (argc == 3) {
  1043.         if (wmPtr->hints.flags & WindowGroupHint) {
  1044.         interp->result = wmPtr->leaderName;
  1045.         }
  1046.         return TCL_OK;
  1047.     }
  1048.     if (*argv[3] == '\0') {
  1049.         wmPtr->hints.flags &= ~WindowGroupHint;
  1050.         if (wmPtr->leaderName != NULL) {
  1051.         ckfree(wmPtr->leaderName);
  1052.         }
  1053.         wmPtr->leaderName = NULL;
  1054.     } else {
  1055.         tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
  1056.         if (tkwin2 == NULL) {
  1057.         return TCL_ERROR;
  1058.         }
  1059.         Tk_MakeWindowExist(tkwin2);
  1060.         wmPtr->hints.window_group = Tk_WindowId(tkwin2);
  1061.         wmPtr->hints.flags |= WindowGroupHint;
  1062.         wmPtr->leaderName = ckalloc((unsigned) (strlen(argv[3])+1));
  1063.         strcpy(wmPtr->leaderName, argv[3]);
  1064.     }
  1065.     } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
  1066.         && (length >= 5)) {
  1067.     Pixmap pixmap;
  1068.  
  1069.     if ((argc != 3) && (argc != 4)) {
  1070.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1071.             argv[0], " iconbitmap window ?bitmap?\"",
  1072.             (char *) NULL);
  1073.         return TCL_ERROR;
  1074.     }
  1075.     if (argc == 3) {
  1076.         if (wmPtr->hints.flags & IconPixmapHint) {
  1077.         interp->result = Tk_NameOfBitmap(winPtr->display,
  1078.             wmPtr->hints.icon_pixmap);
  1079.         }
  1080.         return TCL_OK;
  1081.     }
  1082.     if (*argv[3] == '\0') {
  1083.         if (wmPtr->hints.icon_pixmap != None) {
  1084.         Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
  1085.         }
  1086.         wmPtr->hints.flags &= ~IconPixmapHint;
  1087.     } else {
  1088.         pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
  1089.             Tk_GetUid(argv[3]));
  1090.         if (pixmap == None) {
  1091.         return TCL_ERROR;
  1092.         }
  1093.         wmPtr->hints.icon_pixmap = pixmap;
  1094.         wmPtr->hints.flags |= IconPixmapHint;
  1095.     }
  1096.     } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
  1097.         && (length >= 5)) {
  1098.     if (argc != 3) {
  1099.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1100.             argv[0], " iconify window\"", (char *) NULL);
  1101.         return TCL_ERROR;
  1102.     }
  1103.     if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
  1104.         Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
  1105.             "\": override-redirect flag is set", (char *) NULL);
  1106.         return TCL_ERROR;
  1107.     }
  1108.     if (wmPtr->master != None) {
  1109.         Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
  1110.             "\": it is a transient", (char *) NULL);
  1111.         return TCL_ERROR;
  1112.     }
  1113.     if (wmPtr->iconFor != NULL) {
  1114.         Tcl_AppendResult(interp, "can't iconify ", argv[2],
  1115.             ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
  1116.            (char *) NULL);
  1117.         return TCL_ERROR;
  1118.     }
  1119.     wmPtr->hints.initial_state = IconicState;
  1120.     wmPtr->withdrawn = 1;
  1121.     if (wmPtr->flags & WM_NEVER_MAPPED) {
  1122.         return TCL_OK;
  1123.     }
  1124.     
  1125.     /*
  1126.      * To iconify a window we just unmap it.
  1127.      */
  1128.     
  1129.     XUnmapWindow(winPtr->display, winPtr->window);
  1130.     } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
  1131.         && (length >= 5)) {
  1132.     Pixmap pixmap;
  1133.  
  1134.     if ((argc != 3) && (argc != 4)) {
  1135.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1136.             argv[0], " iconmask window ?bitmap?\"",
  1137.             (char *) NULL);
  1138.         return TCL_ERROR;
  1139.     }
  1140.     if (argc == 3) {
  1141.         if (wmPtr->hints.flags & IconMaskHint) {
  1142.         interp->result = Tk_NameOfBitmap(winPtr->display,
  1143.             wmPtr->hints.icon_mask);
  1144.         }
  1145.         return TCL_OK;
  1146.     }
  1147.     if (*argv[3] == '\0') {
  1148.         if (wmPtr->hints.icon_mask != None) {
  1149.         Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
  1150.         }
  1151.         wmPtr->hints.flags &= ~IconMaskHint;
  1152.     } else {
  1153.         pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
  1154.         if (pixmap == None) {
  1155.         return TCL_ERROR;
  1156.         }
  1157.         wmPtr->hints.icon_mask = pixmap;
  1158.         wmPtr->hints.flags |= IconMaskHint;
  1159.     }
  1160.     } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
  1161.         && (length >= 5)) {
  1162.     if (argc > 4) {
  1163.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1164.             argv[0], " iconname window ?newName?\"", (char *) NULL);
  1165.         return TCL_ERROR;
  1166.     }
  1167.     if (argc == 3) {
  1168.         interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
  1169.         return TCL_OK;
  1170.     } else {
  1171.         wmPtr->iconName = Tk_GetUid(argv[3]);
  1172.         if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1173.         XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
  1174.         }
  1175.     }
  1176.     } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
  1177.         && (length >= 5)) {
  1178.     int x, y;
  1179.  
  1180.     if ((argc != 3) && (argc != 5)) {
  1181.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1182.             argv[0], " iconposition window ?x y?\"",
  1183.             (char *) NULL);
  1184.         return TCL_ERROR;
  1185.     }
  1186.     if (argc == 3) {
  1187.         if (wmPtr->hints.flags & IconPositionHint) {
  1188.         sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
  1189.             wmPtr->hints.icon_y);
  1190.         }
  1191.         return TCL_OK;
  1192.     }
  1193.     if (*argv[3] == '\0') {
  1194.         wmPtr->hints.flags &= ~IconPositionHint;
  1195.     } else {
  1196.         if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
  1197.             || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
  1198.         return TCL_ERROR;
  1199.         }
  1200.         wmPtr->hints.icon_x = x;
  1201.         wmPtr->hints.icon_y = y;
  1202.         wmPtr->hints.flags |= IconPositionHint;
  1203.     }
  1204.     } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
  1205.         && (length >= 5)) {
  1206.     Tk_Window tkwin2;
  1207.     WmInfo *wmPtr2;
  1208.  
  1209.     if ((argc != 3) && (argc != 4)) {
  1210.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1211.             argv[0], " iconwindow window ?pathName?\"",
  1212.             (char *) NULL);
  1213.         return TCL_ERROR;
  1214.     }
  1215.     if (argc == 3) {
  1216.         if (wmPtr->icon != NULL) {
  1217.         interp->result = Tk_PathName(wmPtr->icon);
  1218.         }
  1219.         return TCL_OK;
  1220.     }
  1221.     if (*argv[3] == '\0') {
  1222.         wmPtr->hints.flags &= ~IconWindowHint;
  1223.         if (wmPtr->icon != NULL) {
  1224.         wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  1225.         wmPtr2->iconFor = NULL;
  1226.         wmPtr2->withdrawn = 1;
  1227.         wmPtr2->hints.initial_state = WithdrawnState;
  1228.         }
  1229.         wmPtr->icon = NULL;
  1230.     } else {
  1231.         tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
  1232.         if (tkwin2 == NULL) {
  1233.         return TCL_ERROR;
  1234.         }
  1235.         if (!Tk_IsTopLevel(tkwin2)) {
  1236.         Tcl_AppendResult(interp, "can't use ", argv[3],
  1237.             " as icon window: not at top level", (char *) NULL);
  1238.         return TCL_ERROR;
  1239.         }
  1240.         wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
  1241.         if (wmPtr2->iconFor != NULL) {
  1242.         Tcl_AppendResult(interp, argv[3], " is already an icon for ",
  1243.             Tk_PathName(wmPtr2->iconFor), (char *) NULL);
  1244.         return TCL_ERROR;
  1245.         }
  1246.         if (wmPtr->icon != NULL) {
  1247.         WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  1248.         wmPtr3->iconFor = NULL;
  1249.         wmPtr3->withdrawn = 1;
  1250.         }
  1251.         Tk_MakeWindowExist(tkwin2);
  1252.         wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
  1253.         wmPtr->hints.flags |= IconWindowHint;
  1254.         wmPtr->icon = tkwin2;
  1255.         wmPtr2->iconFor = (Tk_Window) winPtr;
  1256.         if (!wmPtr2->withdrawn && !(wmPtr2->flags & WM_NEVER_MAPPED)) {
  1257.         wmPtr2->withdrawn = 1;
  1258.         /*
  1259.          * Don't have iconwindows on the Mac.  We just withdraw.
  1260.          */
  1261.         XUnmapWindow(Tk_Display(tkwin2), Tk_WindowId(tkwin2));
  1262.         }
  1263.     }
  1264.     } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
  1265.         && (length >= 2)) {
  1266.     int width, height;
  1267.     if ((argc != 3) && (argc != 5)) {
  1268.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1269.             argv[0], " maxsize window ?width height?\"", (char *) NULL);
  1270.         return TCL_ERROR;
  1271.     }
  1272.     if (argc == 3) {
  1273.         sprintf(interp->result, "%d %d", wmPtr->maxWidth,
  1274.             wmPtr->maxHeight);
  1275.         return TCL_OK;
  1276.     }
  1277.     if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
  1278.         || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
  1279.         return TCL_ERROR;
  1280.     }
  1281.     wmPtr->maxWidth = width;
  1282.     wmPtr->maxHeight = height;
  1283.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1284.     goto updateGeom;
  1285.     } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
  1286.         && (length >= 2)) {
  1287.     int width, height;
  1288.     if ((argc != 3) && (argc != 5)) {
  1289.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1290.            argv[0], " minsize window ?width height?\"", (char *) NULL);
  1291.         return TCL_ERROR;
  1292.     }
  1293.     if (argc == 3) {
  1294.         sprintf(interp->result, "%d %d", wmPtr->minWidth,
  1295.             wmPtr->minHeight);
  1296.         return TCL_OK;
  1297.     }
  1298.     if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
  1299.         || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
  1300.         return TCL_ERROR;
  1301.     }
  1302.     wmPtr->minWidth = width;
  1303.     wmPtr->minHeight = height;
  1304.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1305.     goto updateGeom;
  1306.     } else if ((c == 'o')
  1307.         && (strncmp(argv[1], "overrideredirect", length) == 0)) {
  1308.     int boolean;
  1309.     XSetWindowAttributes atts;
  1310.  
  1311.     if ((argc != 3) && (argc != 4)) {
  1312.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1313.             argv[0], " overrideredirect window ?boolean?\"",
  1314.             (char *) NULL);
  1315.         return TCL_ERROR;
  1316.     }
  1317.     if (argc == 3) {
  1318.         if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
  1319.         interp->result = "1";
  1320.         } else {
  1321.         interp->result = "0";
  1322.         }
  1323.         return TCL_OK;
  1324.     }
  1325.     if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) {
  1326.         return TCL_ERROR;
  1327.     }
  1328.     atts.override_redirect = (boolean) ? True : False;
  1329.     Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
  1330.         &atts);
  1331.     wmPtr->style = (boolean) ? plainDBox : documentProc;
  1332.     } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
  1333.         && (length >= 2)) {
  1334.     if ((argc != 3) && (argc != 4)) {
  1335.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1336.             argv[0], " positionfrom window ?user/program?\"",
  1337.             (char *) NULL);
  1338.         return TCL_ERROR;
  1339.     }
  1340.     if (argc == 3) {
  1341.         if (wmPtr->sizeHintsFlags & USPosition) {
  1342.         interp->result = "user";
  1343.         } else if (wmPtr->sizeHintsFlags & PPosition) {
  1344.         interp->result = "program";
  1345.         }
  1346.         return TCL_OK;
  1347.     }
  1348.     if (*argv[3] == '\0') {
  1349.         wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
  1350.     } else {
  1351.         c = argv[3][0];
  1352.         length = strlen(argv[3]);
  1353.         if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
  1354.         wmPtr->sizeHintsFlags &= ~PPosition;
  1355.         wmPtr->sizeHintsFlags |= USPosition;
  1356.         } else if ((c == 'p') &&
  1357.             (strncmp(argv[3], "program", length) == 0)) {
  1358.         wmPtr->sizeHintsFlags &= ~USPosition;
  1359.         wmPtr->sizeHintsFlags |= PPosition;
  1360.         } else {
  1361.         Tcl_AppendResult(interp, "bad argument \"", argv[3],
  1362.             "\": must be program or user", (char *) NULL);
  1363.         return TCL_ERROR;
  1364.         }
  1365.     }
  1366.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1367.     goto updateGeom;
  1368.     } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)
  1369.         && (length >= 2)) {
  1370.     register ProtocolHandler *protPtr, *prevPtr;
  1371.     Atom protocol;
  1372.     int cmdLength;
  1373.  
  1374.     if ((argc < 3) || (argc > 5)) {
  1375.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1376.             argv[0], " protocol window ?name? ?command?\"",
  1377.             (char *) NULL);
  1378.         return TCL_ERROR;
  1379.     }
  1380.     if (argc == 3) {
  1381.         /*
  1382.          * Return a list of all defined protocols for the window.
  1383.          */
  1384.         for (protPtr = wmPtr->protPtr; protPtr != NULL;
  1385.                        protPtr = protPtr->nextPtr) {
  1386.         Tcl_AppendElement(interp,
  1387.             Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
  1388.         }
  1389.         return TCL_OK;
  1390.     }
  1391.     protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
  1392.     if (argc == 4) {
  1393.         /*
  1394.          * Return the command to handle a given protocol.
  1395.          */
  1396.         for (protPtr = wmPtr->protPtr; protPtr != NULL;
  1397.                        protPtr = protPtr->nextPtr) {
  1398.         if (protPtr->protocol == protocol) {
  1399.             interp->result = protPtr->command;
  1400.             return TCL_OK;
  1401.         }
  1402.         }
  1403.         return TCL_OK;
  1404.     }
  1405.  
  1406.     /*
  1407.      * Delete any current protocol handler, then create a new
  1408.      * one with the specified command, unless the command is
  1409.      * empty.
  1410.      */
  1411.  
  1412.     for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
  1413.            prevPtr = protPtr, protPtr = protPtr->nextPtr) {
  1414.         if (protPtr->protocol == protocol) {
  1415.         if (prevPtr == NULL) {
  1416.             wmPtr->protPtr = protPtr->nextPtr;
  1417.         } else {
  1418.             prevPtr->nextPtr = protPtr->nextPtr;
  1419.         }
  1420.         Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
  1421.         break;
  1422.         }
  1423.     }
  1424.     cmdLength = strlen(argv[4]);
  1425.     if (cmdLength > 0) {
  1426.         protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
  1427.         protPtr->protocol = protocol;
  1428.         protPtr->nextPtr = wmPtr->protPtr;
  1429.         wmPtr->protPtr = protPtr;
  1430.         protPtr->interp = interp;
  1431.         strcpy(protPtr->command, argv[4]);
  1432.     }
  1433.     } else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) {
  1434.     int width, height;
  1435.  
  1436.     if ((argc != 3) && (argc != 5)) {
  1437.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1438.             argv[0], " resizable window ?width height?\"",
  1439.             (char *) NULL);
  1440.         return TCL_ERROR;
  1441.     }
  1442.     if (argc == 3) {
  1443.         sprintf(interp->result, "%d %d",
  1444.             (wmPtr->flags  & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
  1445.             (wmPtr->flags  & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
  1446.         return TCL_OK;
  1447.     }
  1448.     if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
  1449.         || (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) {
  1450.         return TCL_ERROR;
  1451.     }
  1452.     if (width) {
  1453.         wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
  1454.     } else {
  1455.         wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
  1456.     }
  1457.     if (height) {
  1458.         wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
  1459.     } else {
  1460.         wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
  1461.     }
  1462.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1463.     if (wmPtr->scrollWinPtr != NULL) {
  1464.         TkScrollbarEventuallyRedraw(
  1465.         (TkScrollbar *) wmPtr->scrollWinPtr->instanceData);
  1466.     }
  1467.     goto updateGeom;
  1468.     } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
  1469.         && (length >= 2)) {
  1470.     if ((argc != 3) && (argc != 4)) {
  1471.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1472.             argv[0], " sizefrom window ?user|program?\"",
  1473.             (char *) NULL);
  1474.         return TCL_ERROR;
  1475.     }
  1476.     if (argc == 3) {
  1477.         if (wmPtr->sizeHintsFlags & USSize) {
  1478.         interp->result = "user";
  1479.         } else if (wmPtr->sizeHintsFlags & PSize) {
  1480.         interp->result = "program";
  1481.         }
  1482.         return TCL_OK;
  1483.     }
  1484.     if (*argv[3] == '\0') {
  1485.         wmPtr->sizeHintsFlags &= ~(USSize|PSize);
  1486.     } else {
  1487.         c = argv[3][0];
  1488.         length = strlen(argv[3]);
  1489.         if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
  1490.         wmPtr->sizeHintsFlags &= ~PSize;
  1491.         wmPtr->sizeHintsFlags |= USSize;
  1492.         } else if ((c == 'p')
  1493.             && (strncmp(argv[3], "program", length) == 0)) {
  1494.         wmPtr->sizeHintsFlags &= ~USSize;
  1495.         wmPtr->sizeHintsFlags |= PSize;
  1496.         } else {
  1497.         Tcl_AppendResult(interp, "bad argument \"", argv[3],
  1498.             "\": must be program or user", (char *) NULL);
  1499.         return TCL_ERROR;
  1500.         }
  1501.     }
  1502.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1503.     goto updateGeom;
  1504.     } else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
  1505.         && (length >= 2)) {
  1506.     if (argc != 3) {
  1507.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1508.             argv[0], " state window\"", (char *) NULL);
  1509.         return TCL_ERROR;
  1510.     }
  1511.     if (wmPtr->iconFor != NULL) {
  1512.         interp->result = "icon";
  1513.     } else if (wmPtr->withdrawn) {
  1514.         interp->result = "withdrawn";
  1515.     } else if (Tk_IsMapped((Tk_Window) winPtr)
  1516.         || ((wmPtr->flags & WM_NEVER_MAPPED)
  1517.             && (wmPtr->hints.initial_state == NormalState))) {
  1518.         interp->result = "normal";
  1519.     } else {
  1520.         interp->result = "iconic";
  1521.     }
  1522.     } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
  1523.         && (length >= 2)) {
  1524.     if (argc > 4) {
  1525.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1526.             argv[0], " title window ?newTitle?\"", (char *) NULL);
  1527.         return TCL_ERROR;
  1528.     }
  1529.     if (argc == 3) {
  1530.         interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
  1531.         : winPtr->nameUid;
  1532.         return TCL_OK;
  1533.     } else {
  1534.         wmPtr->titleUid = Tk_GetUid(argv[3]);
  1535.         if (!(wmPtr->flags & WM_NEVER_MAPPED) && !Tk_IsEmbedded(winPtr)) {
  1536.         TkSetWMName(winPtr, wmPtr->titleUid);
  1537.         }
  1538.     }
  1539.     } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
  1540.         && (length >= 3)) {
  1541.     Tk_Window master;
  1542.  
  1543.     if ((argc != 3) && (argc != 4)) {
  1544.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1545.             argv[0], " transient window ?master?\"", (char *) NULL);
  1546.         return TCL_ERROR;
  1547.     }
  1548.     if (argc == 3) {
  1549.         if (wmPtr->master != None) {
  1550.         interp->result = wmPtr->masterWindowName;
  1551.         }
  1552.         return TCL_OK;
  1553.     }
  1554.     if (argv[3][0] == '\0') {
  1555.         wmPtr->master = None;
  1556.         if (wmPtr->masterWindowName != NULL) {
  1557.         ckfree(wmPtr->masterWindowName);
  1558.         }
  1559.         wmPtr->masterWindowName = NULL;
  1560.         wmPtr->style = documentProc;
  1561.     } else {
  1562.         master = Tk_NameToWindow(interp, argv[3], tkwin);
  1563.         if (master == NULL) {
  1564.         return TCL_ERROR;
  1565.         }
  1566.         Tk_MakeWindowExist(master);
  1567.         wmPtr->master = Tk_WindowId(master);
  1568.         wmPtr->masterWindowName = ckalloc((unsigned) (strlen(argv[3])+1));
  1569.         strcpy(wmPtr->masterWindowName, argv[3]);
  1570.         wmPtr->style = plainDBox;
  1571.     }
  1572.     } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
  1573.     if (argc != 3) {
  1574.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1575.             argv[0], " withdraw window\"", (char *) NULL);
  1576.         return TCL_ERROR;
  1577.     }
  1578.     if (wmPtr->iconFor != NULL) {
  1579.         Tcl_AppendResult(interp, "can't withdraw ", argv[2],
  1580.             ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
  1581.             (char *) NULL);
  1582.         return TCL_ERROR;
  1583.     }
  1584.     wmPtr->hints.initial_state = WithdrawnState;
  1585.     wmPtr->withdrawn = 1;
  1586.     if (wmPtr->flags & WM_NEVER_MAPPED) {
  1587.         return TCL_OK;
  1588.     }
  1589.     /*
  1590.      * To withdraw a window we just unmap it.
  1591.      */
  1592.     XUnmapWindow(winPtr->display, winPtr->window);
  1593.     } else {
  1594.     Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
  1595.         "\": must be aspect, client, command, deiconify, ",
  1596.         "focusmodel, frame, geometry, grid, group, iconbitmap, ",
  1597.         "iconify, iconmask, iconname, iconposition, ",
  1598.         "iconwindow, maxsize, minsize, overrideredirect, ",
  1599.         "positionfrom, protocol, resizable, sizefrom, state, title, ",
  1600.         "transient, or withdraw",
  1601.         (char *) NULL);
  1602.     return TCL_ERROR;
  1603.     }
  1604.     return TCL_OK;
  1605.  
  1606.     updateGeom:
  1607.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1608.     Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1609.     wmPtr->flags |= WM_UPDATE_PENDING;
  1610.     }
  1611.     return TCL_OK;
  1612. }
  1613.  
  1614. /*
  1615.  *----------------------------------------------------------------------
  1616.  *
  1617.  * Tk_SetGrid --
  1618.  *
  1619.  *    This procedure is invoked by a widget when it wishes to set a grid
  1620.  *    coordinate system that controls the size of a top-level window.
  1621.  *    It provides a C interface equivalent to the "wm grid" command and
  1622.  *    is usually asscoiated with the -setgrid option.
  1623.  *
  1624.  * Results:
  1625.  *    None.
  1626.  *
  1627.  * Side effects:
  1628.  *    Grid-related information will be passed to the window manager, so
  1629.  *    that the top-level window associated with tkwin will resize on
  1630.  *    even grid units.  If some other window already controls gridding
  1631.  *    for the top-level window then this procedure call has no effect.
  1632.  *
  1633.  *----------------------------------------------------------------------
  1634.  */
  1635.  
  1636. void
  1637. Tk_SetGrid(
  1638.     Tk_Window tkwin,        /* Token for window.  New window mgr info
  1639.                  * will be posted for the top-level window
  1640.                  * associated with this window. */
  1641.     int reqWidth,        /* Width (in grid units) corresponding to
  1642.                  * the requested geometry for tkwin. */
  1643.     int reqHeight,        /* Height (in grid units) corresponding to
  1644.                  * the requested geometry for tkwin. */
  1645.     int widthInc, int heightInc)/* Pixel increments corresponding to a
  1646.                  * change of one grid unit. */
  1647. {
  1648.     TkWindow *winPtr = (TkWindow *) tkwin;
  1649.     register WmInfo *wmPtr;
  1650.  
  1651.     /*
  1652.      * Find the top-level window for tkwin, plus the window manager
  1653.      * information.
  1654.      */
  1655.  
  1656.     while (!(winPtr->flags & TK_TOP_LEVEL)) {
  1657.     winPtr = winPtr->parentPtr;
  1658.     }
  1659.     wmPtr = winPtr->wmInfoPtr;
  1660.  
  1661.     if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
  1662.     return;
  1663.     }
  1664.  
  1665.     if ((wmPtr->reqGridWidth == reqWidth)
  1666.         && (wmPtr->reqGridHeight == reqHeight)
  1667.         && (wmPtr->widthInc == widthInc)
  1668.         && (wmPtr->heightInc == heightInc)
  1669.         && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
  1670.             == PBaseSize|PResizeInc)) {
  1671.     return;
  1672.     }
  1673.  
  1674.     /*
  1675.      * If gridding was previously off, then forget about any window
  1676.      * size requests made by the user or via "wm geometry":  these are
  1677.      * in pixel units and there's no easy way to translate them to
  1678.      * grid units since the new requested size of the top-level window in
  1679.      * pixels may not yet have been registered yet (it may filter up
  1680.      * the hierarchy in DoWhenIdle handlers).  However, if the window
  1681.      * has never been mapped yet then just leave the window size alone:
  1682.      * assume that it is intended to be in grid units but just happened
  1683.      * to have been specified before this procedure was called.
  1684.      */
  1685.  
  1686.     if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
  1687.     wmPtr->width = -1;
  1688.     wmPtr->height = -1;
  1689.     }
  1690.  
  1691.     /* 
  1692.      * Set the new gridding information, and start the process of passing
  1693.      * all of this information to the window manager.
  1694.      */
  1695.  
  1696.     wmPtr->gridWin = tkwin;
  1697.     wmPtr->reqGridWidth = reqWidth;
  1698.     wmPtr->reqGridHeight = reqHeight;
  1699.     wmPtr->widthInc = widthInc;
  1700.     wmPtr->heightInc = heightInc;
  1701.     wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
  1702.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1703.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1704.     Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1705.     wmPtr->flags |= WM_UPDATE_PENDING;
  1706.     }
  1707. }
  1708.  
  1709. /*
  1710.  *----------------------------------------------------------------------
  1711.  *
  1712.  * Tk_UnsetGrid --
  1713.  *
  1714.  *    This procedure cancels the effect of a previous call
  1715.  *    to Tk_SetGrid.
  1716.  *
  1717.  * Results:
  1718.  *    None.
  1719.  *
  1720.  * Side effects:
  1721.  *    If tkwin currently controls gridding for its top-level window,
  1722.  *    gridding is cancelled for that top-level window;  if some other
  1723.  *    window controls gridding then this procedure has no effect.
  1724.  *
  1725.  *----------------------------------------------------------------------
  1726.  */
  1727.  
  1728. void
  1729. Tk_UnsetGrid(
  1730.     Tk_Window tkwin)        /* Token for window that is currently
  1731.                  * controlling gridding. */
  1732. {
  1733.     TkWindow *winPtr = (TkWindow *) tkwin;
  1734.     register WmInfo *wmPtr;
  1735.  
  1736.     /*
  1737.      * Find the top-level window for tkwin, plus the window manager
  1738.      * information.
  1739.      */
  1740.  
  1741.     while (!(winPtr->flags & TK_TOP_LEVEL)) {
  1742.     winPtr = winPtr->parentPtr;
  1743.     }
  1744.     wmPtr = winPtr->wmInfoPtr;
  1745.     if (tkwin != wmPtr->gridWin) {
  1746.     return;
  1747.     }
  1748.  
  1749.     wmPtr->gridWin = NULL;
  1750.     wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
  1751.     if (wmPtr->width != -1) {
  1752.     wmPtr->width = winPtr->reqWidth + (wmPtr->width
  1753.         - wmPtr->reqGridWidth)*wmPtr->widthInc;
  1754.     wmPtr->height = winPtr->reqHeight + (wmPtr->height
  1755.         - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1756.     }
  1757.     wmPtr->widthInc = 1;
  1758.     wmPtr->heightInc = 1;
  1759.  
  1760.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1761.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1762.     Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1763.     wmPtr->flags |= WM_UPDATE_PENDING;
  1764.     }
  1765. }
  1766.  
  1767. /*
  1768.  *----------------------------------------------------------------------
  1769.  *
  1770.  * TopLevelEventProc --
  1771.  *
  1772.  *    This procedure is invoked when a top-level (or other externally-
  1773.  *    managed window) is restructured in any way.
  1774.  *
  1775.  * Results:
  1776.  *    None.
  1777.  *
  1778.  * Side effects:
  1779.  *    Tk's internal data structures for the window get modified to
  1780.  *    reflect the structural change.
  1781.  *
  1782.  *----------------------------------------------------------------------
  1783.  */
  1784.  
  1785. static void
  1786. TopLevelEventProc(
  1787.     ClientData clientData,        /* Window for which event occurred. */
  1788.     XEvent *eventPtr)            /* Event that just happened. */
  1789. {
  1790.     register TkWindow *winPtr = (TkWindow *) clientData;
  1791.  
  1792.     winPtr->wmInfoPtr->flags |= WM_VROOT_OFFSET_STALE;
  1793.     if (eventPtr->type == DestroyNotify) {
  1794.     Tk_ErrorHandler handler;
  1795.  
  1796.     if (!(winPtr->flags & TK_ALREADY_DEAD)) {
  1797.         /*
  1798.          * A top-level window was deleted externally (e.g., by the window
  1799.          * manager).  This is probably not a good thing, but cleanup as
  1800.          * best we can.  The error handler is needed because
  1801.          * Tk_DestroyWindow will try to destroy the window, but of course
  1802.          * it's already gone.
  1803.          */
  1804.     
  1805.         handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
  1806.             (Tk_ErrorProc *) NULL, (ClientData) NULL);
  1807.         Tk_DestroyWindow((Tk_Window) winPtr);
  1808.         Tk_DeleteErrorHandler(handler);
  1809.     }
  1810.     if (wmTracing) {
  1811.         printf("TopLevelEventProc: %s deleted\n", winPtr->pathName);
  1812.     }
  1813.     } else if (eventPtr->type == ReparentNotify) {
  1814.     panic("recieved unwanted reparent event");
  1815.     }
  1816. }
  1817.  
  1818. /*
  1819.  *----------------------------------------------------------------------
  1820.  *
  1821.  * TopLevelReqProc --
  1822.  *
  1823.  *    This procedure is invoked by the geometry manager whenever
  1824.  *    the requested size for a top-level window is changed.
  1825.  *
  1826.  * Results:
  1827.  *    None.
  1828.  *
  1829.  * Side effects:
  1830.  *    Arrange for the window to be resized to satisfy the request
  1831.  *    (this happens as a when-idle action).
  1832.  *
  1833.  *----------------------------------------------------------------------
  1834.  */
  1835.  
  1836.     /* ARGSUSED */
  1837. static void
  1838. TopLevelReqProc(
  1839.     ClientData dummy,            /* Not used. */
  1840.     Tk_Window tkwin)            /* Information about window. */
  1841. {
  1842.     TkWindow *winPtr = (TkWindow *) tkwin;
  1843.     WmInfo *wmPtr;
  1844.  
  1845.     wmPtr = winPtr->wmInfoPtr;
  1846.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1847.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1848.     Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1849.     wmPtr->flags |= WM_UPDATE_PENDING;
  1850.     }
  1851. }
  1852.  
  1853. /*
  1854.  *----------------------------------------------------------------------
  1855.  *
  1856.  * UpdateGeometryInfo --
  1857.  *
  1858.  *    This procedure is invoked when a top-level window is first
  1859.  *    mapped, and also as a when-idle procedure, to bring the
  1860.  *    geometry and/or position of a top-level window back into
  1861.  *    line with what has been requested by the user and/or widgets.
  1862.  *    This procedure doesn't return until the window manager has
  1863.  *    responded to the geometry change.
  1864.  *
  1865.  * Results:
  1866.  *    None.
  1867.  *
  1868.  * Side effects:
  1869.  *    The window's size and location may change, unless the WM prevents
  1870.  *    that from happening.
  1871.  *
  1872.  *----------------------------------------------------------------------
  1873.  */
  1874.  
  1875. static void
  1876. UpdateGeometryInfo(
  1877.     ClientData clientData)        /* Pointer to the window's record. */
  1878. {
  1879.     register TkWindow *winPtr = (TkWindow *) clientData;
  1880.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  1881.     int x, y, width, height;
  1882.     unsigned long serial;
  1883.  
  1884.     wmPtr->flags &= ~WM_UPDATE_PENDING;
  1885.  
  1886.     /*
  1887.      * Compute the new size for the top-level window.  See the
  1888.      * user documentation for details on this, but the size
  1889.      * requested depends on (a) the size requested internally
  1890.      * by the window's widgets, (b) the size requested by the
  1891.      * user in a "wm geometry" command or via wm-based interactive
  1892.      * resizing (if any), and (c) whether or not the window is
  1893.      * gridded.  Don't permit sizes <= 0 because this upsets
  1894.      * the X server.
  1895.      */
  1896.  
  1897.     if (wmPtr->width == -1) {
  1898.     width = winPtr->reqWidth;
  1899.     } else if (wmPtr->gridWin != NULL) {
  1900.     width = winPtr->reqWidth
  1901.         + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
  1902.     } else {
  1903.     width = wmPtr->width;
  1904.     }
  1905.     if (width <= 0) {
  1906.     width = 1;
  1907.     }
  1908.     if (wmPtr->height == -1) {
  1909.     height = winPtr->reqHeight;
  1910.     } else if (wmPtr->gridWin != NULL) {
  1911.     height = winPtr->reqHeight
  1912.         + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1913.     } else {
  1914.     height = wmPtr->height;
  1915.     }
  1916.     if (height <= 0) {
  1917.     height = 1;
  1918.     }
  1919.  
  1920.     /*
  1921.      * Compute the new position for the upper-left pixel of the window's
  1922.      * decorative frame.  This is tricky, because we need to include the
  1923.      * border widths supplied by a reparented parent in this calculation,
  1924.      * but can't use the parent's current overall size since that may
  1925.      * change as a result of this code.
  1926.      */
  1927.  
  1928.     if (wmPtr->flags & WM_NEGATIVE_X) {
  1929.     x = wmPtr->vRootWidth - wmPtr->x
  1930.         - (width + (wmPtr->parentWidth - winPtr->changes.width));
  1931.     } else {
  1932.     x =  wmPtr->x;
  1933.     }
  1934.     if (wmPtr->flags & WM_NEGATIVE_Y) {
  1935.     y = wmPtr->vRootHeight - wmPtr->y
  1936.         - (height + (wmPtr->parentHeight - winPtr->changes.height));
  1937.     } else {
  1938.     y =  wmPtr->y;
  1939.     }
  1940.  
  1941.     /*
  1942.      * If the window's size is going to change and the window is
  1943.      * supposed to not be resizable by the user, then we have to
  1944.      * update the size hints.  There may also be a size-hint-update
  1945.      * request pending from somewhere else, too.
  1946.      */
  1947.  
  1948.     if (((width != winPtr->changes.width)
  1949.         || (height != winPtr->changes.height))
  1950.         && (wmPtr->gridWin == NULL)
  1951.         && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
  1952.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1953.     }
  1954.     if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) {
  1955.     UpdateSizeHints(winPtr);
  1956.     }
  1957.  
  1958.     /*
  1959.      * Reconfigure the window if it isn't already configured correctly.
  1960.      * A few tricky points:
  1961.      *
  1962.      * 1. If the window is embedded and the container is also in this
  1963.      *    process, don't actually reconfigure the window; just pass the
  1964.      *    desired size on to the container.  Also, zero out any position
  1965.      *    information, since embedded windows are not allowed to move.
  1966.      * 2. Sometimes the window manager will give us a different size
  1967.      *    than we asked for (e.g. mwm has a minimum size for windows), so
  1968.      *    base the size check on what we *asked for* last time, not what we
  1969.      *    got.
  1970.      * 3. Don't move window unless a new position has been requested for
  1971.      *      it.  This is because of "features" in some window managers (e.g.
  1972.      *    twm, as of 4/24/91) where they don't interpret coordinates
  1973.      *    according to ICCCM.  Moving a window to its current location may
  1974.      *    cause it to shift position on the screen.
  1975.      */
  1976.  
  1977.     if (Tk_IsEmbedded(winPtr)) {
  1978.         TkWindow *contWinPtr;
  1979.  
  1980.     contWinPtr = TkpGetOtherWindow(winPtr);
  1981.     
  1982.     /*
  1983.      * NOTE: Here we should handle out of process embedding.
  1984.      */
  1985.  
  1986.     if (contWinPtr != NULL) {        
  1987.         /*
  1988.          * This window is embedded and the container is also in this
  1989.          * process, so we don't need to do anything special about the
  1990.          * geometry, except to make sure that the desired size is known
  1991.          * by the container.  Also, zero out any position information,
  1992.          * since embedded windows are not allowed to move.
  1993.          */
  1994.  
  1995.         wmPtr->x = wmPtr->y = 0;
  1996.         wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
  1997.         Tk_GeometryRequest((Tk_Window) contWinPtr, width, height);
  1998.         }
  1999.     return;
  2000.     }
  2001.     serial = NextRequest(winPtr->display);
  2002.     if (wmPtr->flags & WM_MOVE_PENDING) {
  2003.     wmPtr->configWidth = width;
  2004.     wmPtr->configHeight = height;
  2005.     if (wmTracing) {
  2006.         printf(
  2007.         "UpdateGeometryInfo moving to %d %d, resizing to %d x %d,\n",
  2008.             x, y, width, height);
  2009.     }
  2010.     Tk_MoveResizeWindow((Tk_Window) winPtr, x, y, (unsigned) width,
  2011.         (unsigned) height);
  2012.     } else if ((width != wmPtr->configWidth)
  2013.         || (height != wmPtr->configHeight)) {
  2014.     wmPtr->configWidth = width;
  2015.     wmPtr->configHeight = height;
  2016.     if (wmTracing) {
  2017.         printf("UpdateGeometryInfo resizing to %d x %d\n", width, height);
  2018.     }
  2019.     Tk_ResizeWindow((Tk_Window) winPtr, (unsigned) width,
  2020.         (unsigned) height);
  2021.     } else {
  2022.     return;
  2023.     }
  2024. }
  2025.  
  2026. /*
  2027.  *--------------------------------------------------------------
  2028.  *
  2029.  * UpdateSizeHints --
  2030.  *
  2031.  *    This procedure is called to update the window manager's
  2032.  *    size hints information from the information in a WmInfo
  2033.  *    structure.
  2034.  *
  2035.  * Results:
  2036.  *    None.
  2037.  *
  2038.  * Side effects:
  2039.  *    Properties get changed for winPtr.
  2040.  *
  2041.  *--------------------------------------------------------------
  2042.  */
  2043.  
  2044. static void
  2045. UpdateSizeHints(
  2046.     TkWindow *winPtr)
  2047. {
  2048.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  2049.     XSizeHints *hintsPtr;
  2050.  
  2051.     wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS;
  2052.  
  2053.     hintsPtr = XAllocSizeHints();
  2054.     if (hintsPtr == NULL) {
  2055.     return;
  2056.     }
  2057.  
  2058.     /*
  2059.      * Compute the pixel-based sizes for the various fields in the
  2060.      * size hints structure, based on the grid-based sizes in
  2061.      * our structure.
  2062.      */
  2063.  
  2064.     if (wmPtr->gridWin != NULL) {
  2065.     hintsPtr->base_width = winPtr->reqWidth
  2066.         - (wmPtr->reqGridWidth * wmPtr->widthInc);
  2067.     if (hintsPtr->base_width < 0) {
  2068.         hintsPtr->base_width = 0;
  2069.     }
  2070.     hintsPtr->base_height = winPtr->reqHeight
  2071.         - (wmPtr->reqGridHeight * wmPtr->heightInc);
  2072.     if (hintsPtr->base_height < 0) {
  2073.         hintsPtr->base_height = 0;
  2074.     }
  2075.     hintsPtr->min_width = hintsPtr->base_width
  2076.         + (wmPtr->minWidth * wmPtr->widthInc);
  2077.     hintsPtr->min_height = hintsPtr->base_height
  2078.         + (wmPtr->minHeight * wmPtr->heightInc);
  2079.     hintsPtr->max_width = hintsPtr->base_width
  2080.         + (wmPtr->maxWidth * wmPtr->widthInc);
  2081.     hintsPtr->max_height = hintsPtr->base_height
  2082.         + (wmPtr->maxHeight * wmPtr->heightInc);
  2083.     } else {
  2084.     hintsPtr->min_width = wmPtr->minWidth;
  2085.     hintsPtr->min_height = wmPtr->minHeight;
  2086.     hintsPtr->max_width = wmPtr->maxWidth;
  2087.     hintsPtr->max_height = wmPtr->maxHeight;
  2088.     hintsPtr->base_width = 0;
  2089.     hintsPtr->base_height = 0;
  2090.     }
  2091.     hintsPtr->width_inc = wmPtr->widthInc;
  2092.     hintsPtr->height_inc = wmPtr->heightInc;
  2093.     hintsPtr->min_aspect.x = wmPtr->minAspect.x;
  2094.     hintsPtr->min_aspect.y = wmPtr->minAspect.y;
  2095.     hintsPtr->max_aspect.x = wmPtr->maxAspect.x;
  2096.     hintsPtr->max_aspect.y = wmPtr->maxAspect.y;
  2097.     hintsPtr->win_gravity = wmPtr->gravity;
  2098.     hintsPtr->flags = wmPtr->sizeHintsFlags | PMinSize | PMaxSize;
  2099.  
  2100.     /*
  2101.      * If the window isn't supposed to be resizable, then set the
  2102.      * minimum and maximum dimensions to be the same.
  2103.      */
  2104.  
  2105.     if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
  2106.     if (wmPtr->width >= 0) {
  2107.         hintsPtr->min_width = wmPtr->width;
  2108.     } else {
  2109.         hintsPtr->min_width = winPtr->reqWidth;
  2110.     }
  2111.     hintsPtr->max_width = hintsPtr->min_width;
  2112.     }
  2113.     if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
  2114.     if (wmPtr->height >= 0) {
  2115.         hintsPtr->min_height = wmPtr->height;
  2116.     } else {
  2117.         hintsPtr->min_height = winPtr->reqHeight;
  2118.     }
  2119.     hintsPtr->max_height = hintsPtr->min_height;
  2120.     }
  2121.  
  2122.     XSetWMNormalHints(winPtr->display, winPtr->window, hintsPtr);
  2123.  
  2124.     XFree((char *) hintsPtr);
  2125. }
  2126.  
  2127. /*
  2128.  *--------------------------------------------------------------
  2129.  *
  2130.  * ParseGeometry --
  2131.  *
  2132.  *    This procedure parses a geometry string and updates
  2133.  *    information used to control the geometry of a top-level
  2134.  *    window.
  2135.  *
  2136.  * Results:
  2137.  *    A standard Tcl return value, plus an error message in
  2138.  *    interp->result if an error occurs.
  2139.  *
  2140.  * Side effects:
  2141.  *    The size and/or location of winPtr may change.
  2142.  *
  2143.  *--------------------------------------------------------------
  2144.  */
  2145.  
  2146. static int
  2147. ParseGeometry(
  2148.     Tcl_Interp *interp,        /* Used for error reporting. */
  2149.     char *string,        /* String containing new geometry.  Has the
  2150.                  * standard form "=wxh+x+y". */
  2151.     TkWindow *winPtr)        /* Pointer to top-level window whose
  2152.                  * geometry is to be changed. */
  2153. {
  2154.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  2155.     int x, y, width, height, flags;
  2156.     char *end;
  2157.     register char *p = string;
  2158.  
  2159.     /*
  2160.      * The leading "=" is optional.
  2161.      */
  2162.  
  2163.     if (*p == '=') {
  2164.     p++;
  2165.     }
  2166.  
  2167.     /*
  2168.      * Parse the width and height, if they are present.  Don't
  2169.      * actually update any of the fields of wmPtr until we've
  2170.      * successfully parsed the entire geometry string.
  2171.      */
  2172.  
  2173.     width = wmPtr->width;
  2174.     height = wmPtr->height;
  2175.     x = wmPtr->x;
  2176.     y = wmPtr->y;
  2177.     flags = wmPtr->flags;
  2178.     if (isdigit(UCHAR(*p))) {
  2179.     width = strtoul(p, &end, 10);
  2180.     p = end;
  2181.     if (*p != 'x') {
  2182.         goto error;
  2183.     }
  2184.     p++;
  2185.     if (!isdigit(UCHAR(*p))) {
  2186.         goto error;
  2187.     }
  2188.     height = strtoul(p, &end, 10);
  2189.     p = end;
  2190.     }
  2191.  
  2192.     /*
  2193.      * Parse the X and Y coordinates, if they are present.
  2194.      */
  2195.  
  2196.     if (*p != '\0') {
  2197.     flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
  2198.     if (*p == '-') {
  2199.         flags |= WM_NEGATIVE_X;
  2200.     } else if (*p != '+') {
  2201.         goto error;
  2202.     }
  2203.     x = strtol(p+1, &end, 10);
  2204.     p = end;
  2205.     if (*p == '-') {
  2206.         flags |= WM_NEGATIVE_Y;
  2207.     } else if (*p != '+') {
  2208.         goto error;
  2209.     }
  2210.     y = strtol(p+1, &end, 10);
  2211.     if (*end != '\0') {
  2212.         goto error;
  2213.     }
  2214.  
  2215.     /*
  2216.      * Assume that the geometry information came from the user,
  2217.      * unless an explicit source has been specified.  Otherwise
  2218.      * most window managers assume that the size hints were
  2219.      * program-specified and they ignore them.
  2220.      */
  2221.  
  2222.     if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
  2223.         wmPtr->sizeHintsFlags |= USPosition;
  2224.         flags |= WM_UPDATE_SIZE_HINTS;
  2225.     }
  2226.     }
  2227.  
  2228.     /*
  2229.      * Everything was parsed OK.  Update the fields of *wmPtr and
  2230.      * arrange for the appropriate information to be percolated out
  2231.      * to the window manager at the next idle moment.
  2232.      */
  2233.  
  2234.     wmPtr->width = width;
  2235.     wmPtr->height = height;
  2236.     if ((x != wmPtr->x) || (y != wmPtr->y)
  2237.         || ((flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y))
  2238.             != (wmPtr->flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y)))) {
  2239.     wmPtr->x = x;
  2240.     wmPtr->y = y;
  2241.     flags |= WM_MOVE_PENDING;
  2242.     }
  2243.     wmPtr->flags = flags;
  2244.  
  2245.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  2246.     Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  2247.     wmPtr->flags |= WM_UPDATE_PENDING;
  2248.     }
  2249.     return TCL_OK;
  2250.  
  2251.     error:
  2252.     Tcl_AppendResult(interp, "bad geometry specifier \"",
  2253.         string, "\"", (char *) NULL);
  2254.     return TCL_ERROR;
  2255. }
  2256.  
  2257. /*
  2258.  *----------------------------------------------------------------------
  2259.  *
  2260.  * Tk_GetRootCoords --
  2261.  *
  2262.  *    Given a token for a window, this procedure traces through the
  2263.  *    window's lineage to find the (virtual) root-window coordinates
  2264.  *    corresponding to point (0,0) in the window.
  2265.  *
  2266.  * Results:
  2267.  *    The locations pointed to by xPtr and yPtr are filled in with
  2268.  *    the root coordinates of the (0,0) point in tkwin.  If a virtual
  2269.  *    root window is in effect for the window, then the coordinates
  2270.  *    in the virtual root are returned.
  2271.  *
  2272.  * Side effects:
  2273.  *    None.
  2274.  *
  2275.  *----------------------------------------------------------------------
  2276.  */
  2277.  
  2278. void
  2279. Tk_GetRootCoords(
  2280.     Tk_Window tkwin,        /* Token for window. */
  2281.     int *xPtr,            /* Where to store x-displacement of (0,0). */
  2282.     int *yPtr)            /* Where to store y-displacement of (0,0). */
  2283. {
  2284.     int x, y;
  2285.     register TkWindow *winPtr = (TkWindow *) tkwin;
  2286.  
  2287.     /*
  2288.      * Search back through this window's parents all the way to a
  2289.      * top-level window, combining the offsets of each window within
  2290.      * its parent.
  2291.      */
  2292.  
  2293.     x = y = 0;
  2294.     while (1) {
  2295.     x += winPtr->changes.x + winPtr->changes.border_width;
  2296.     y += winPtr->changes.y + winPtr->changes.border_width;
  2297.     if (winPtr->flags & TK_TOP_LEVEL) {
  2298.         if (!(Tk_IsEmbedded(winPtr))) {
  2299.             x += winPtr->wmInfoPtr->xInParent;
  2300.             y += winPtr->wmInfoPtr->yInParent;
  2301.             break;            
  2302.         } else {
  2303.             TkWindow *otherPtr;
  2304.         
  2305.         otherPtr = TkpGetOtherWindow(winPtr);
  2306.         if (otherPtr != NULL) {
  2307.             /*
  2308.              * The container window is in the same application.
  2309.              * Query its coordinates.
  2310.              */
  2311.             winPtr = otherPtr;
  2312.             
  2313.             /*
  2314.              * Remember to offset by the container window here,
  2315.              * since at the end of this if branch, we will
  2316.              * pop out to the container's parent...
  2317.              */
  2318.              
  2319.                 x += winPtr->changes.x + winPtr->changes.border_width;
  2320.                 y += winPtr->changes.y + winPtr->changes.border_width;
  2321.             
  2322.         } else {
  2323.             
  2324.             /*
  2325.              * NOTE: Here we should handle
  2326.              * out of process embedding.
  2327.              */
  2328.             
  2329.             break;
  2330.         }
  2331.         }
  2332.     }
  2333.     winPtr = winPtr->parentPtr;
  2334.     }
  2335.     *xPtr = x;
  2336.     *yPtr = y;
  2337. }
  2338.  
  2339. /*
  2340.  *----------------------------------------------------------------------
  2341.  *
  2342.  * Tk_CoordsToWindow --
  2343.  *
  2344.  *    This is a Macintosh specific implementation of this function.
  2345.  *    Given the root coordinates of a point, this procedure returns
  2346.  *    the token for the top-most window covering that point, if
  2347.  *    there exists such a window in this application.
  2348.  *
  2349.  * Results:
  2350.  *    The return result is either a token for the window corresponding
  2351.  *    to rootX and rootY, or else NULL to indicate that there is no such
  2352.  *    window.
  2353.  *
  2354.  * Side effects:
  2355.  *    None.
  2356.  *
  2357.  *----------------------------------------------------------------------
  2358.  */
  2359.  
  2360. Tk_Window
  2361. Tk_CoordsToWindow(
  2362.     int rootX, int rootY,    /* Coordinates of point in root window.  If
  2363.                  * a virtual-root window manager is in use,
  2364.                  * these coordinates refer to the virtual
  2365.                  * root, not the real root. */
  2366.     Tk_Window tkwin)        /* Token for any window in application;
  2367.                  * used to identify the display. */
  2368. {
  2369.     WindowPtr whichWin;
  2370.     Point where;
  2371.     Window rootChild;
  2372.     register TkWindow *winPtr, *childPtr;
  2373.     TkWindow *nextPtr;        /* Coordinates of highest child found so
  2374.                  * far that contains point. */
  2375.     int x, y;            /* Coordinates in winPtr. */
  2376.     int tmpx, tmpy, bd;
  2377.  
  2378.     /*
  2379.      * Step 1: find the top-level window that contains the desired point.
  2380.      */
  2381.      
  2382.     where.h = rootX;
  2383.     where.v = rootY;
  2384.     FindWindow(where, &whichWin);
  2385.     if (whichWin == NULL) {
  2386.     return NULL;
  2387.     }
  2388.     rootChild = TkMacGetXWindow(whichWin);
  2389.     winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, rootChild);
  2390.     if (winPtr == NULL) {
  2391.         return NULL;
  2392.     }
  2393.  
  2394.     /*
  2395.      * Step 2: work down through the hierarchy underneath this window.
  2396.      * At each level, scan through all the children to find the highest
  2397.      * one in the stacking order that contains the point.  Then repeat
  2398.      * the whole process on that child.
  2399.      */
  2400.  
  2401.     x = rootX - winPtr->wmInfoPtr->xInParent;
  2402.     y = rootY - winPtr->wmInfoPtr->yInParent;
  2403.     while (1) {
  2404.     x -= winPtr->changes.x;
  2405.     y -= winPtr->changes.y;
  2406.     nextPtr = NULL;
  2407.     
  2408.     /*
  2409.      * Container windows cannot have children.  So if it is a container,
  2410.      * look there, otherwise inspect the children.
  2411.      */
  2412.      
  2413.     if (Tk_IsContainer(winPtr)) {
  2414.         childPtr = TkpGetOtherWindow(winPtr);
  2415.         if (childPtr != NULL) {
  2416.         if (Tk_IsMapped(childPtr)) {
  2417.                 tmpx = x - childPtr->changes.x;
  2418.                 tmpy = y - childPtr->changes.y;
  2419.                 bd = childPtr->changes.border_width;
  2420.                       
  2421.                 if ((tmpx >= -bd) && (tmpy >= -bd)
  2422.                 && (tmpx < (childPtr->changes.width + bd))
  2423.                 && (tmpy < (childPtr->changes.height + bd))) {
  2424.                 nextPtr = childPtr;
  2425.                 }
  2426.             }
  2427.         }
  2428.         
  2429.  
  2430.         /*
  2431.          * NOTE: Here we should handle out of process embedding.
  2432.          */
  2433.     
  2434.     } else {
  2435.         for (childPtr = winPtr->childList; childPtr != NULL;
  2436.             childPtr = childPtr->nextPtr) {
  2437.             if (!Tk_IsMapped(childPtr) ||
  2438.             (childPtr->flags & TK_TOP_LEVEL)) {
  2439.             continue;
  2440.             }
  2441.             tmpx = x - childPtr->changes.x;
  2442.             tmpy = y - childPtr->changes.y;
  2443.             bd = childPtr->changes.border_width;
  2444.             if ((tmpx >= -bd) && (tmpy >= -bd)
  2445.                 && (tmpx < (childPtr->changes.width + bd))
  2446.                 && (tmpy < (childPtr->changes.height + bd))) {
  2447.             nextPtr = childPtr;
  2448.             }
  2449.         }
  2450.     }
  2451.     if (nextPtr == NULL) {
  2452.         break;
  2453.     }
  2454.     winPtr = nextPtr;
  2455.     }
  2456.     return (Tk_Window) winPtr;
  2457. }
  2458.  
  2459. /*
  2460.  *----------------------------------------------------------------------
  2461.  *
  2462.  * Tk_TopCoordsToWindow --
  2463.  *
  2464.  *    Given a Tk Window, and coordinates of a point relative to that window
  2465.  *      this procedure returns the top-most child of the window (excluding
  2466.  *      toplevels) covering that point, if there exists such a window in this
  2467.  *    application.
  2468.  *    It also sets newX, and newY to the coords of the point relative to the
  2469.  *      window returned.
  2470.  *
  2471.  * Results:
  2472.  *    The return result is either a token for the window corresponding
  2473.  *    to rootX and rootY, or else NULL to indicate that there is no such
  2474.  *    window.  newX and newY are also set to the coords of the point relative
  2475.  *      to the returned window.
  2476.  *
  2477.  * Side effects:
  2478.  *    None.
  2479.  *
  2480.  *----------------------------------------------------------------------
  2481.  */
  2482.  
  2483. Tk_Window
  2484. Tk_TopCoordsToWindow(
  2485.     Tk_Window tkwin,        /* Token for a Tk Window which defines the;
  2486.                  * coordinates for rootX & rootY */
  2487.     int rootX, int rootY,    /* Coordinates of a point in tkWin. */
  2488.     int *newX, int *newY)    /* Coordinates of point in the upperMost child of
  2489.                                  * tkWin containing (rootX,rootY) */
  2490. {
  2491.     register TkWindow *winPtr, *childPtr;
  2492.     TkWindow *nextPtr;        /* Coordinates of highest child found so
  2493.                  * far that contains point. */
  2494.     int x, y;            /* Coordinates in winPtr. */
  2495.     Window *children;        /* Children of winPtr, or NULL. */
  2496.  
  2497.     winPtr = (TkWindow *) tkwin;
  2498.     x = rootX;
  2499.     y = rootY;
  2500.     while (1) {
  2501.     nextPtr = NULL;
  2502.     children = NULL;
  2503.  
  2504.     /*
  2505.      * Container windows cannot have children.  So if it is a container,
  2506.      * look there, otherwise inspect the children.
  2507.      */
  2508.      
  2509.     if (Tk_IsContainer(winPtr)) {
  2510.         childPtr = TkpGetOtherWindow(winPtr);
  2511.         if (childPtr != NULL) {
  2512.         if (Tk_IsMapped(childPtr) && 
  2513.                      (x > childPtr->changes.x && 
  2514.                          x < childPtr->changes.x +
  2515.                  childPtr->changes.width) &&
  2516.                      (y > childPtr->changes.y &&
  2517.                          y < childPtr->changes.y +
  2518.                  childPtr->changes.height)) {        
  2519.                 nextPtr = childPtr;
  2520.             }
  2521.         }
  2522.  
  2523.         /*
  2524.          * NOTE: Here we should handle out of process embedding.
  2525.          */
  2526.     
  2527.     } else {
  2528.     
  2529.         for (childPtr = winPtr->childList; childPtr != NULL;
  2530.                        childPtr = childPtr->nextPtr) {
  2531.             if (!Tk_IsMapped(childPtr) ||
  2532.             (childPtr->flags & TK_TOP_LEVEL)) {
  2533.             continue;
  2534.             }
  2535.             if (x < childPtr->changes.x || y < childPtr->changes.y) {
  2536.             continue;
  2537.             }
  2538.             if (x > childPtr->changes.x + childPtr->changes.width ||
  2539.                 y > childPtr->changes.y + childPtr->changes.height) {
  2540.             continue;
  2541.             }
  2542.             nextPtr = childPtr;
  2543.         }
  2544.     }
  2545.     if (nextPtr == NULL) {
  2546.         break;
  2547.     }
  2548.     winPtr = nextPtr;
  2549.     x -= winPtr->changes.x;
  2550.     y -= winPtr->changes.y;
  2551.     }
  2552.     *newX = x;
  2553.     *newY = y;
  2554.     return (Tk_Window) winPtr;
  2555. }
  2556.  
  2557. /*
  2558.  *----------------------------------------------------------------------
  2559.  *
  2560.  * UpdateVRootGeometry --
  2561.  *
  2562.  *    This procedure is called to update all the virtual root
  2563.  *    geometry information in wmPtr.
  2564.  *
  2565.  * Results:
  2566.  *    None.
  2567.  *
  2568.  * Side effects:
  2569.  *    The vRootX, vRootY, vRootWidth, and vRootHeight fields in
  2570.  *    wmPtr are filled with the most up-to-date information.
  2571.  *
  2572.  *----------------------------------------------------------------------
  2573.  */
  2574.  
  2575. static void
  2576. UpdateVRootGeometry(
  2577.     WmInfo *wmPtr)        /* Window manager information to be
  2578.                  * updated.  The wmPtr->vRoot field must
  2579.                  * be valid. */
  2580. {
  2581.     TkWindow *winPtr = wmPtr->winPtr;
  2582.     unsigned int bd, dummy;
  2583.     Window dummy2;
  2584.     Status status;
  2585.     Tk_ErrorHandler handler;
  2586.  
  2587.     /*
  2588.      * If this isn't a virtual-root window manager, just return information
  2589.      * about the screen.
  2590.      */
  2591.  
  2592.     wmPtr->flags &= ~WM_VROOT_OFFSET_STALE;
  2593.     if (wmPtr->vRoot == None) {
  2594.     noVRoot:
  2595.     wmPtr->vRootX = wmPtr->vRootY = 0;
  2596.     wmPtr->vRootWidth = DisplayWidth(winPtr->display, winPtr->screenNum);
  2597.     wmPtr->vRootHeight = DisplayHeight(winPtr->display, winPtr->screenNum);
  2598.     return;
  2599.     }
  2600.  
  2601.     /*
  2602.      * Refresh the virtual root information if it's out of date.
  2603.      */
  2604.  
  2605.     handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
  2606.         (Tk_ErrorProc *) NULL, (ClientData) NULL);
  2607.     status = XGetGeometry(winPtr->display, wmPtr->vRoot,
  2608.         &dummy2, &wmPtr->vRootX, &wmPtr->vRootY,
  2609.         &wmPtr->vRootWidth, &wmPtr->vRootHeight, &bd, &dummy);
  2610.     if (wmTracing) {
  2611.     printf("UpdateVRootGeometry: x = %d, y = %d, width = %d, ",
  2612.         wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth);
  2613.     printf("height = %d, status = %d\n", wmPtr->vRootHeight, status);
  2614.     }
  2615.     Tk_DeleteErrorHandler(handler);
  2616.     if (status == 0) {
  2617.     /*
  2618.      * The virtual root is gone!  Pretend that it never existed.
  2619.      */
  2620.  
  2621.     wmPtr->vRoot = None;
  2622.     goto noVRoot;
  2623.     }
  2624. }
  2625.  
  2626. /*
  2627.  *----------------------------------------------------------------------
  2628.  *
  2629.  * Tk_GetVRootGeometry --
  2630.  *
  2631.  *    This procedure returns information about the virtual root
  2632.  *    window corresponding to a particular Tk window.
  2633.  *
  2634.  * Results:
  2635.  *    The values at xPtr, yPtr, widthPtr, and heightPtr are set
  2636.  *    with the offset and dimensions of the root window corresponding
  2637.  *    to tkwin.  If tkwin is being managed by a virtual root window
  2638.  *    manager these values correspond to the virtual root window being
  2639.  *    used for tkwin;  otherwise the offsets will be 0 and the
  2640.  *    dimensions will be those of the screen.
  2641.  *
  2642.  * Side effects:
  2643.  *    Vroot window information is refreshed if it is out of date.
  2644.  *
  2645.  *----------------------------------------------------------------------
  2646.  */
  2647.  
  2648. void
  2649. Tk_GetVRootGeometry(
  2650.     Tk_Window tkwin,        /* Window whose virtual root is to be
  2651.                  * queried. */
  2652.     int *xPtr, int *yPtr,    /* Store x and y offsets of virtual root
  2653.                  * here. */
  2654.     int *widthPtr,        /* Store dimensions of virtual root here. */
  2655.     int *heightPtr)
  2656. {
  2657.     WmInfo *wmPtr;
  2658.     TkWindow *winPtr = (TkWindow *) tkwin;
  2659.  
  2660.     /*
  2661.      * Find the top-level window for tkwin, and locate the window manager
  2662.      * information for that window.
  2663.      */
  2664.  
  2665.     while (!(winPtr->flags & TK_TOP_LEVEL)) {
  2666.     winPtr = winPtr->parentPtr;
  2667.     }
  2668.     wmPtr = winPtr->wmInfoPtr;
  2669.  
  2670.     /*
  2671.      * Make sure that the geometry information is up-to-date, then copy
  2672.      * it out to the caller.
  2673.      */
  2674.  
  2675.     if (wmPtr->flags & WM_VROOT_OFFSET_STALE) {
  2676.     UpdateVRootGeometry(wmPtr);
  2677.     }
  2678.     *xPtr = wmPtr->vRootX;
  2679.     *yPtr = wmPtr->vRootY;
  2680.     *widthPtr = wmPtr->vRootWidth;
  2681.     *heightPtr = wmPtr->vRootHeight;
  2682. }
  2683.  
  2684. /*
  2685.  *----------------------------------------------------------------------
  2686.  *
  2687.  * Tk_MoveToplevelWindow --
  2688.  *
  2689.  *    This procedure is called instead of Tk_MoveWindow to adjust
  2690.  *    the x-y location of a top-level window.  It delays the actual
  2691.  *    move to a later time and keeps window-manager information
  2692.  *    up-to-date with the move
  2693.  *
  2694.  * Results:
  2695.  *    None.
  2696.  *
  2697.  * Side effects:
  2698.  *    The window is eventually moved so that its upper-left corner
  2699.  *    (actually, the upper-left corner of the window's decorative
  2700.  *    frame, if there is one) is at (x,y).
  2701.  *
  2702.  *----------------------------------------------------------------------
  2703.  */
  2704.  
  2705. void
  2706. Tk_MoveToplevelWindow(
  2707.     Tk_Window tkwin,        /* Window to move. */
  2708.     int x, int y)        /* New location for window (within
  2709.                  * parent). */
  2710. {
  2711.     TkWindow *winPtr = (TkWindow *) tkwin;
  2712.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  2713.  
  2714.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  2715.     panic("Tk_MoveToplevelWindow called with non-toplevel window");
  2716.     }
  2717.     wmPtr->x = x;
  2718.     wmPtr->y = y;
  2719.     wmPtr->flags |= WM_MOVE_PENDING;
  2720.     wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
  2721.     if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
  2722.     wmPtr->sizeHintsFlags |= USPosition;
  2723.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  2724.     }
  2725.  
  2726.     /*
  2727.      * If the window has already been mapped, must bring its geometry
  2728.      * up-to-date immediately, otherwise an event might arrive from the
  2729.      * server that would overwrite wmPtr->x and wmPtr->y and lose the
  2730.      * new position.
  2731.      */
  2732.  
  2733.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  2734.     if (wmPtr->flags & WM_UPDATE_PENDING) {
  2735.         Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
  2736.     }
  2737.     UpdateGeometryInfo((ClientData) winPtr);
  2738.     }
  2739. }
  2740.  
  2741. /*
  2742.  *----------------------------------------------------------------------
  2743.  *
  2744.  * TkWmProtocolEventProc --
  2745.  *
  2746.  *    This procedure is called by the Tk_HandleEvent whenever a
  2747.  *    ClientMessage event arrives whose type is "WM_PROTOCOLS".
  2748.  *    This procedure handles the message from the window manager
  2749.  *    in an appropriate fashion.
  2750.  *
  2751.  * Results:
  2752.  *    None.
  2753.  *
  2754.  * Side effects:
  2755.  *    Depends on what sort of handler, if any, was set up for the
  2756.  *    protocol.
  2757.  *
  2758.  *----------------------------------------------------------------------
  2759.  */
  2760.  
  2761. void
  2762. TkWmProtocolEventProc(
  2763.     TkWindow *winPtr,        /* Window to which the event was sent. */
  2764.     XEvent *eventPtr)        /* X event. */
  2765. {
  2766.     WmInfo *wmPtr;
  2767.     register ProtocolHandler *protPtr;
  2768.     Tcl_Interp *interp;
  2769.     Atom protocol;
  2770.     int result;
  2771.  
  2772.     wmPtr = winPtr->wmInfoPtr;
  2773.     if (wmPtr == NULL) {
  2774.     return;
  2775.     }
  2776.     protocol = (Atom) eventPtr->xclient.data.l[0];
  2777.     for (protPtr = wmPtr->protPtr; protPtr != NULL;
  2778.                    protPtr = protPtr->nextPtr) {
  2779.     if (protocol == protPtr->protocol) {
  2780.         Tcl_Preserve((ClientData) protPtr);
  2781.             interp = protPtr->interp;
  2782.             Tcl_Preserve((ClientData) interp);
  2783.         result = Tcl_GlobalEval(interp, protPtr->command);
  2784.         if (result != TCL_OK) {
  2785.         Tcl_AddErrorInfo(interp, "\n    (command for \"");
  2786.         Tcl_AddErrorInfo(interp,
  2787.             Tk_GetAtomName((Tk_Window) winPtr, protocol));
  2788.         Tcl_AddErrorInfo(interp, "\" window manager protocol)");
  2789.         Tk_BackgroundError(interp);
  2790.         }
  2791.             Tcl_Release((ClientData) interp);
  2792.         Tcl_Release((ClientData) protPtr);
  2793.         return;
  2794.     }
  2795.     }
  2796.  
  2797.     /*
  2798.      * No handler was present for this protocol.  If this is a
  2799.      * WM_DELETE_WINDOW message then just destroy the window.
  2800.      */
  2801.  
  2802.     if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
  2803.     Tk_DestroyWindow((Tk_Window) winPtr);
  2804.     }
  2805. }
  2806.  
  2807. /*
  2808.  *----------------------------------------------------------------------
  2809.  *
  2810.  * TkWmRestackToplevel --
  2811.  *
  2812.  *    This procedure restacks a top-level window.
  2813.  *
  2814.  * Results:
  2815.  *    None.
  2816.  *
  2817.  * Side effects:
  2818.  *    WinPtr gets restacked  as specified by aboveBelow and otherPtr.
  2819.  *    This procedure doesn't return until the restack has taken
  2820.  *    effect and the ConfigureNotify event for it has been received.
  2821.  *
  2822.  *----------------------------------------------------------------------
  2823.  */
  2824.  
  2825. void
  2826. TkWmRestackToplevel(
  2827.     TkWindow *winPtr,        /* Window to restack. */
  2828.     int aboveBelow,        /* Gives relative position for restacking;
  2829.                  * must be Above or Below. */
  2830.     TkWindow *otherPtr)        /* Window relative to which to restack;
  2831.                  * if NULL, then winPtr gets restacked
  2832.                  * above or below *all* siblings. */
  2833. {
  2834.     WmInfo *wmPtr;
  2835.     WindowPeek macWindow, otherMacWindow, frontWindow;
  2836.  
  2837.     wmPtr = winPtr->wmInfoPtr;
  2838.     
  2839.     /*
  2840.      * Get the mac window.  Make sure it exists & is mapped.
  2841.      */
  2842.     
  2843.     if (winPtr->window == None) {
  2844.     Tk_MakeWindowExist((Tk_Window) winPtr);
  2845.     }
  2846.     if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
  2847.  
  2848.     /*
  2849.      * Can't set stacking order properly until the window is on the
  2850.      * screen (mapping it may give it a reparent window), so make sure
  2851.      * it's on the screen.
  2852.      */
  2853.  
  2854.     TkWmMapWindow(winPtr);
  2855.     }
  2856.     macWindow = (WindowPeek) TkMacGetDrawablePort(winPtr->window);
  2857.     
  2858.     /*
  2859.      * Get the window in which a raise or lower is in relation to.
  2860.      */
  2861.     if (otherPtr != NULL) {
  2862.     if (otherPtr->window == None) {
  2863.         Tk_MakeWindowExist((Tk_Window) otherPtr);
  2864.     }
  2865.     if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
  2866.         TkWmMapWindow(otherPtr);
  2867.     }
  2868.     otherMacWindow = (WindowPeek) TkMacGetDrawablePort(otherPtr->window);
  2869.     } else {
  2870.     otherMacWindow = NULL;
  2871.     }
  2872.     
  2873.     frontWindow = (WindowPeek) FrontWindow();
  2874.     if (aboveBelow == Above) {
  2875.     if (macWindow == frontWindow) {
  2876.         /* 
  2877.          * Do nothing - it's already at the top.
  2878.          */
  2879.     } else if (otherMacWindow == frontWindow || otherMacWindow == NULL) {
  2880.         /*
  2881.          * Raise the window to the top.  If the window is visable then
  2882.          * we also make it the active window.
  2883.          */
  2884.         if (wmPtr->withdrawn) {
  2885.         BringToFront((WindowPtr) macWindow);
  2886.         } else {
  2887.         SelectWindow((WindowPtr)  macWindow);
  2888.         }
  2889.     } else {
  2890.         /*
  2891.          * Find the window to be above.  (Front window will actually be the
  2892.          * window to be behind.)  Front window is NULL if no other windows.
  2893.          */
  2894.         while (frontWindow != NULL &&
  2895.             frontWindow->nextWindow != otherMacWindow) {
  2896.         frontWindow = frontWindow->nextWindow;
  2897.         }
  2898.         if (frontWindow != NULL) {
  2899.         SendBehind((WindowPtr) macWindow, (WindowPtr) frontWindow);
  2900.         }
  2901.     }
  2902.     } else {
  2903.     /*
  2904.      * Send behind.  If it was in front find another window to make active.
  2905.      */
  2906.     if (macWindow == frontWindow) {
  2907.         if (macWindow->nextWindow != NULL) {
  2908.         SelectWindow((WindowPtr)  macWindow->nextWindow);
  2909.         }
  2910.     }
  2911.     SendBehind((WindowPtr) macWindow, (WindowPtr) otherMacWindow);
  2912.     }
  2913. }
  2914.  
  2915. /*
  2916.  *----------------------------------------------------------------------
  2917.  *
  2918.  * TkWmAddToColormapWindows --
  2919.  *
  2920.  *    This procedure is called to add a given window to the
  2921.  *    WM_COLORMAP_WINDOWS property for its top-level, if it
  2922.  *    isn't already there.  It is invoked by the Tk code that
  2923.  *    creates a new colormap, in order to make sure that colormap
  2924.  *    information is propagated to the window manager by default.
  2925.  *
  2926.  * Results:
  2927.  *    None.
  2928.  *
  2929.  * Side effects:
  2930.  *    WinPtr's window gets added to the WM_COLORMAP_WINDOWS
  2931.  *    property of its nearest top-level ancestor, unless the
  2932.  *    colormaps have been set explicitly with the
  2933.  *    "wm colormapwindows" command.
  2934.  *
  2935.  *----------------------------------------------------------------------
  2936.  */
  2937.  
  2938. void
  2939. TkWmAddToColormapWindows(
  2940.     TkWindow *winPtr)        /* Window with a non-default colormap.
  2941.                  * Should not be a top-level window. */
  2942. {
  2943.     TkWindow *topPtr;
  2944.     TkWindow **oldPtr, **newPtr;
  2945.     int count, i;
  2946.  
  2947.     if (winPtr->window == None) {
  2948.     return;
  2949.     }
  2950.  
  2951.     for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
  2952.     if (topPtr == NULL) {
  2953.         /*
  2954.          * Window is being deleted.  Skip the whole operation.
  2955.          */
  2956.  
  2957.         return;
  2958.     }
  2959.     if (topPtr->flags & TK_TOP_LEVEL) {
  2960.         break;
  2961.     }
  2962.     }
  2963.     if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
  2964.     return;
  2965.     }
  2966.  
  2967.     /*
  2968.      * Make sure that the window isn't already in the list.
  2969.      */
  2970.  
  2971.     count = topPtr->wmInfoPtr->cmapCount;
  2972.     oldPtr = topPtr->wmInfoPtr->cmapList;
  2973.  
  2974.     for (i = 0; i < count; i++) {
  2975.     if (oldPtr[i] == winPtr) {
  2976.         return;
  2977.     }
  2978.     }
  2979.  
  2980.     /*
  2981.      * Make a new bigger array and use it to reset the property.
  2982.      * Automatically add the toplevel itself as the last element
  2983.      * of the list.
  2984.      */
  2985.  
  2986.     newPtr = (TkWindow **) ckalloc((unsigned) ((count+2)*sizeof(TkWindow*)));
  2987.     if (count > 0) {
  2988.     memcpy(newPtr, oldPtr, count * sizeof(TkWindow*));
  2989.     }
  2990.     if (count == 0) {
  2991.     count++;
  2992.     }
  2993.     newPtr[count-1] = winPtr;
  2994.     newPtr[count] = topPtr;
  2995.     if (oldPtr != NULL) {
  2996.     ckfree((char *) oldPtr);
  2997.     }
  2998.  
  2999.     topPtr->wmInfoPtr->cmapList = newPtr;
  3000.     topPtr->wmInfoPtr->cmapCount = count+1;
  3001.  
  3002.     /*
  3003.      * On the Macintosh all of this is just an excercise
  3004.      * in compatability as we don't support colormaps.  If 
  3005.      * we did they would be installed here.
  3006.      */
  3007. }
  3008.  
  3009. /*
  3010.  *----------------------------------------------------------------------
  3011.  *
  3012.  * TkWmRemoveFromColormapWindows --
  3013.  *
  3014.  *    This procedure is called to remove a given window from the
  3015.  *    WM_COLORMAP_WINDOWS property for its top-level.  It is invoked
  3016.  *    when windows are deleted.
  3017.  *
  3018.  * Results:
  3019.  *    None.
  3020.  *
  3021.  * Side effects:
  3022.  *    WinPtr's window gets removed from the WM_COLORMAP_WINDOWS
  3023.  *    property of its nearest top-level ancestor, unless the
  3024.  *    top-level itself is being deleted too.
  3025.  *
  3026.  *----------------------------------------------------------------------
  3027.  */
  3028.  
  3029. void
  3030. TkWmRemoveFromColormapWindows(
  3031.     TkWindow *winPtr)        /* Window that may be present in
  3032.                  * WM_COLORMAP_WINDOWS property for its
  3033.                  * top-level.  Should not be a top-level
  3034.                  * window. */
  3035. {
  3036.     TkWindow *topPtr;
  3037.     TkWindow **oldPtr;
  3038.     int count, i, j;
  3039.  
  3040.     for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
  3041.     if (topPtr == NULL) {
  3042.         /*
  3043.          * Ancestors have been deleted, so skip the whole operation.
  3044.          * Seems like this can't ever happen?
  3045.          */
  3046.  
  3047.         return;
  3048.     }
  3049.     if (topPtr->flags & TK_TOP_LEVEL) {
  3050.         break;
  3051.     }
  3052.     }
  3053.     if (topPtr->flags & TK_ALREADY_DEAD) {
  3054.     /*
  3055.      * Top-level is being deleted, so there's no need to cleanup
  3056.      * the WM_COLORMAP_WINDOWS property.
  3057.      */
  3058.  
  3059.     return;
  3060.     }
  3061.  
  3062.     /*
  3063.      * Find the window and slide the following ones down to cover
  3064.      * it up.
  3065.      */
  3066.  
  3067.     count = topPtr->wmInfoPtr->cmapCount;
  3068.     oldPtr = topPtr->wmInfoPtr->cmapList;
  3069.     for (i = 0; i < count; i++) {
  3070.     if (oldPtr[i] == winPtr) {
  3071.         for (j = i ; j < count-1; j++) {
  3072.         oldPtr[j] = oldPtr[j+1];
  3073.         }
  3074.         topPtr->wmInfoPtr->cmapCount = count - 1;
  3075.         break;
  3076.     }
  3077.     }
  3078. }
  3079.  
  3080. /*
  3081.  *----------------------------------------------------------------------
  3082.  *
  3083.  * TkGetPointerCoords --
  3084.  *
  3085.  *    Fetch the position of the mouse pointer.
  3086.  *
  3087.  * Results:
  3088.  *    *xPtr and *yPtr are filled in with the (virtual) root coordinates
  3089.  *    of the mouse pointer for tkwin's display.  If the pointer isn't
  3090.  *    on tkwin's screen, then -1 values are returned for both
  3091.  *    coordinates.  The argument tkwin must be a toplevel window.
  3092.  *
  3093.  * Side effects:
  3094.  *    None.
  3095.  *
  3096.  *----------------------------------------------------------------------
  3097.  */
  3098.  
  3099. void
  3100. TkGetPointerCoords(
  3101.     Tk_Window tkwin,        /* Toplevel window that identifies screen
  3102.                  * on which lookup is to be done. */
  3103.     int *xPtr, int *yPtr)    /* Store pointer coordinates here. */
  3104. {
  3105.     Point where;
  3106.  
  3107.     GetMouse(&where);
  3108.     LocalToGlobal(&where);
  3109.     *xPtr = where.h;
  3110.     *yPtr = where.v;
  3111. }
  3112.  
  3113. /*
  3114.  *----------------------------------------------------------------------
  3115.  *
  3116.  * InitialWindowBounds --
  3117.  *
  3118.  *    This function calculates the initial bounds for a new Mac
  3119.  *    toplevel window.  Unless the geometry is specified by the user
  3120.  *    this code will auto place the windows in a cascade diagonially
  3121.  *    across the main monitor of the Mac.
  3122.  *
  3123.  * Results:
  3124.  *    The bounds are returned in geometry.
  3125.  *
  3126.  * Side effects:
  3127.  *    None.
  3128.  *
  3129.  *----------------------------------------------------------------------
  3130.  */
  3131.  
  3132. static void
  3133. InitialWindowBounds(
  3134.     TkWindow *winPtr,        /* Window to get initial bounds for. */
  3135.     Rect *geometry)        /* On return the initial bounds. */
  3136. {
  3137.     int x, y;
  3138.     static int defaultX = 5;
  3139.     static int defaultY = 45;
  3140.     
  3141.     if (!(winPtr->wmInfoPtr->sizeHintsFlags & (USPosition | PPosition))) {
  3142.     /* 
  3143.      * We will override the program & hopefully place the
  3144.      * window in a "better" location.
  3145.      */
  3146.         
  3147.     if (((tcl_macQdPtr->screenBits.bounds.right - defaultX) < 30) ||
  3148.         ((tcl_macQdPtr->screenBits.bounds.bottom - defaultY) < 30)) {
  3149.         defaultX = 5;
  3150.         defaultY = 45;
  3151.     }
  3152.     x = defaultX;
  3153.     y = defaultY;
  3154.     defaultX += 20;
  3155.     defaultY += 20;
  3156.     } else {
  3157.     x = winPtr->wmInfoPtr->x;
  3158.     y = winPtr->wmInfoPtr->y;
  3159.     }
  3160.     
  3161.     geometry->left = x;
  3162.     geometry->top = y;
  3163.     geometry->right = x + winPtr->changes.width;
  3164.     geometry->bottom = y + winPtr->changes.height;
  3165. }
  3166.  
  3167. /*
  3168.  *----------------------------------------------------------------------
  3169.  *
  3170.  * TkMacResizable --
  3171.  *
  3172.  *    This function determines if the passed in window is part of
  3173.  *    a toplevel window that is resizable.  If the window is 
  3174.  *    resizable in the x, y or both directions, true is returned.
  3175.  *
  3176.  * Results:
  3177.  *    True if resizable, false otherwise.
  3178.  *
  3179.  * Side effects:
  3180.  *    None.
  3181.  *
  3182.  *----------------------------------------------------------------------
  3183.  */
  3184.  
  3185. int
  3186. TkMacResizable(
  3187.     TkWindow *winPtr)        /* Tk window or NULL. */
  3188. {
  3189.     WmInfo *wmPtr;
  3190.  
  3191.     if (winPtr == NULL) {
  3192.     return false;
  3193.     }
  3194.     while (winPtr->wmInfoPtr == NULL) {
  3195.     winPtr = winPtr->parentPtr;
  3196.     }
  3197.     
  3198.     wmPtr = winPtr->wmInfoPtr;
  3199.     if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
  3200.         (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
  3201.     return false;
  3202.     } else {
  3203.     return true;
  3204.     }
  3205. }
  3206.  
  3207. /*
  3208.  *----------------------------------------------------------------------
  3209.  *
  3210.  * TkMacGrowToplevel --
  3211.  *
  3212.  *    The function is invoked when the user clicks in the grow region
  3213.  *    of a Tk window.  The function will handle the dragging
  3214.  *    procedure and not return until completed.  Finally, the function
  3215.  *    may place information Tk's event queue is the window was resized.
  3216.  *
  3217.  * Results:
  3218.  *    True if events were placed on event queue, false otherwise.
  3219.  *
  3220.  * Side effects:
  3221.  *    None.
  3222.  *
  3223.  *----------------------------------------------------------------------
  3224.  */
  3225.  
  3226. int
  3227. TkMacGrowToplevel(
  3228.     WindowPtr whichWindow,
  3229.     Point start)
  3230. {
  3231.     Point where = start;
  3232.  
  3233.     GlobalToLocal(&where);
  3234.     if (where.h > (whichWindow->portRect.right - 16) &&
  3235.         where.v > (whichWindow->portRect.bottom - 16)) {
  3236.         
  3237.     Window window;
  3238.     TkWindow *winPtr;
  3239.     WmInfo *wmPtr;
  3240.     Rect bounds;
  3241.     long growResult;
  3242.  
  3243.     window = TkMacGetXWindow(whichWindow);
  3244.     winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window);
  3245.     wmPtr = winPtr->wmInfoPtr;
  3246.     
  3247.     /* TODO: handle grid size options. */
  3248.     if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
  3249.         (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
  3250.         return false;
  3251.     }
  3252.     if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
  3253.         bounds.left = bounds.right = winPtr->changes.width;
  3254.     } else {
  3255.         bounds.left = (wmPtr->minWidth < 64) ? 64 : wmPtr->minWidth;
  3256.         bounds.right = (wmPtr->maxWidth < 64) ? 64 : wmPtr->maxWidth;
  3257.     }
  3258.     if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
  3259.         bounds.top = bounds.bottom = winPtr->changes.height;
  3260.     } else {
  3261.         bounds.top = (wmPtr->minHeight < 64) ? 64 : wmPtr->minHeight;
  3262.         bounds.bottom = (wmPtr->maxHeight < 64) ? 64 : wmPtr->maxHeight;
  3263.     }
  3264.     
  3265.     growResult = GrowWindow(whichWindow, start, &bounds);
  3266.  
  3267.     if (growResult != 0) {
  3268.         SizeWindow(whichWindow,
  3269.             LoWord(growResult), HiWord(growResult), true);
  3270.         SetPort(whichWindow);
  3271.         InvalRect(&whichWindow->portRect);    /* TODO: may not be needed */
  3272.         TkMacInvalClipRgns(winPtr);
  3273.         TkGenWMConfigureEvent((Tk_Window) winPtr, -1, -1, 
  3274.             (int) LoWord(growResult), (int) HiWord(growResult),
  3275.             TK_SIZE_CHANGED);
  3276.         return true;
  3277.     }
  3278.     return false;
  3279.     }
  3280.     return false;
  3281. }
  3282.  
  3283. /*
  3284.  *----------------------------------------------------------------------
  3285.  *
  3286.  * TkSetWMName --
  3287.  *
  3288.  *    Set the title for a toplevel window.  If the window is embedded, 
  3289.  *    do not change the window title.
  3290.  *
  3291.  * Results:
  3292.  *    None.
  3293.  *
  3294.  * Side effects:
  3295.  *    The title of the window is changed.
  3296.  *
  3297.  *----------------------------------------------------------------------
  3298.  */
  3299.  
  3300. void
  3301. TkSetWMName(
  3302.     TkWindow *winPtr,
  3303.     Tk_Uid titleUid)
  3304. {
  3305.     Str255  pTitle;
  3306.     GWorldPtr macWin;
  3307.     
  3308.     if (Tk_IsEmbedded(winPtr)) {
  3309.         return;
  3310.     }
  3311.     
  3312.      macWin = TkMacGetDrawablePort(winPtr->window);
  3313.     
  3314.     strcpy((char *) pTitle + 1, titleUid);
  3315.     pTitle[0] = strlen(titleUid);
  3316.     SetWTitle((WindowPtr) macWin, pTitle);
  3317. }
  3318.  
  3319. void
  3320. TkGenWMDestroyEvent(
  3321.     Tk_Window tkwin)
  3322. {
  3323.     XEvent event;
  3324.     
  3325.     event.xany.serial = Tk_Display(tkwin)->request;
  3326.     event.xany.send_event = False;
  3327.     event.xany.display = Tk_Display(tkwin);
  3328.     
  3329.     event.xclient.window = Tk_WindowId(tkwin);
  3330.     event.xclient.type = ClientMessage;
  3331.     event.xclient.message_type = Tk_InternAtom(tkwin, "WM_PROTOCOLS");
  3332.     event.xclient.format = 32;
  3333.     event.xclient.data.l[0] = Tk_InternAtom(tkwin, "WM_DELETE_WINDOW");
  3334.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  3335. }
  3336.  
  3337. /*
  3338.  *----------------------------------------------------------------------
  3339.  *
  3340.  * TkGenWMConfigureEvent --
  3341.  *
  3342.  *    Generate a ConfigureNotify event for Tk.  Depending on the 
  3343.  *    value of flag the values of width/height, x/y, or both may
  3344.  *    be changed.
  3345.  *
  3346.  * Results:
  3347.  *    None.
  3348.  *
  3349.  * Side effects:
  3350.  *    A ConfigureNotify event is sent to Tk.
  3351.  *
  3352.  *----------------------------------------------------------------------
  3353.  */
  3354.  
  3355. void
  3356. TkGenWMConfigureEvent(
  3357.     Tk_Window tkwin,
  3358.     int x,
  3359.     int y,
  3360.     int width,
  3361.     int height,
  3362.     int flags)
  3363. {
  3364.     XEvent event;
  3365.     WmInfo *wmPtr;
  3366.     TkWindow *winPtr = (TkWindow *) tkwin;
  3367.     
  3368.     if (tkwin == NULL) {
  3369.     return;
  3370.     }
  3371.     
  3372.     event.type = ConfigureNotify;
  3373.     event.xconfigure.serial = Tk_Display(tkwin)->request;
  3374.     event.xconfigure.send_event = False;
  3375.     event.xconfigure.display = Tk_Display(tkwin);
  3376.     event.xconfigure.event = Tk_WindowId(tkwin);
  3377.     event.xconfigure.window = Tk_WindowId(tkwin);
  3378.     event.xconfigure.border_width = winPtr->changes.border_width;
  3379.     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  3380.     if (winPtr->changes.stack_mode == Above) {
  3381.     event.xconfigure.above = winPtr->changes.sibling;
  3382.     } else {
  3383.     event.xconfigure.above = None;
  3384.     }
  3385.  
  3386.     if (flags & TK_LOCATION_CHANGED) {
  3387.     event.xconfigure.x = x;
  3388.     event.xconfigure.y = y;
  3389.     } else {
  3390.     event.xconfigure.x = Tk_X(tkwin);
  3391.     event.xconfigure.y = Tk_Y(tkwin);
  3392.     x = Tk_X(tkwin);
  3393.     y = Tk_Y(tkwin);
  3394.     }
  3395.     if (flags & TK_SIZE_CHANGED) {
  3396.     event.xconfigure.width = width;
  3397.     event.xconfigure.height = height;
  3398.     } else {
  3399.     event.xconfigure.width = Tk_Width(tkwin);
  3400.     event.xconfigure.height = Tk_Height(tkwin);
  3401.     width = Tk_Width(tkwin);
  3402.     height = Tk_Height(tkwin);
  3403.     }
  3404.     
  3405.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  3406.     
  3407.     /*
  3408.      * Update window manager information.
  3409.      */
  3410.     if (Tk_IsTopLevel(winPtr)) {
  3411.     wmPtr = winPtr->wmInfoPtr;
  3412.     if (flags & TK_LOCATION_CHANGED) {
  3413.         wmPtr->x = x;
  3414.         wmPtr->y = y;
  3415.         wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
  3416.     }
  3417.     if ((flags & TK_SIZE_CHANGED) && 
  3418.         ((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) {
  3419.         if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) {
  3420.         /*
  3421.          * Don't set external width, since the user didn't change it
  3422.          * from what the widgets asked for.
  3423.          */
  3424.         } else {
  3425.         if (wmPtr->gridWin != NULL) {
  3426.             wmPtr->width = wmPtr->reqGridWidth
  3427.             + (width - winPtr->reqWidth)/wmPtr->widthInc;
  3428.             if (wmPtr->width < 0) {
  3429.             wmPtr->width = 0;
  3430.             }
  3431.         } else {
  3432.             wmPtr->width = width;
  3433.         }
  3434.         }
  3435.         if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) {
  3436.         /*
  3437.          * Don't set external height, since the user didn't change it
  3438.          * from what the widgets asked for.
  3439.          */
  3440.         } else {
  3441.         if (wmPtr->gridWin != NULL) {
  3442.             wmPtr->height = wmPtr->reqGridHeight
  3443.             + (height - winPtr->reqHeight)/wmPtr->heightInc;
  3444.             if (wmPtr->height < 0) {
  3445.             wmPtr->height = 0;
  3446.             }
  3447.         } else {
  3448.             wmPtr->height = height;
  3449.         }
  3450.         }
  3451.         wmPtr->configWidth = width;
  3452.         wmPtr->configHeight = height;
  3453.     }
  3454.     }
  3455.     
  3456.     /*
  3457.      * Now set up the changes structure.  Under X we wait for the
  3458.      * ConfigureNotify to set these values.  On the Mac we know imediatly that
  3459.      * this is what we want - so we just set them.  However, we need to
  3460.      * make sure the windows clipping region is marked invalid so the
  3461.      * change is visable to the subwindow.
  3462.      */
  3463.     winPtr->changes.x = x;
  3464.     winPtr->changes.y = y;
  3465.     winPtr->changes.width = width;
  3466.     winPtr->changes.height = height;
  3467.     TkMacInvalClipRgns(winPtr);
  3468. }
  3469.  
  3470. /*
  3471.  *----------------------------------------------------------------------
  3472.  *
  3473.  * TkGetTransientMaster --
  3474.  *
  3475.  *    If the passed window has the TRANSIENT_FOR property set this
  3476.  *    will return the master window.  Otherwise it will return None.
  3477.  *
  3478.  * Results:
  3479.  *      The master window or None.
  3480.  *
  3481.  * Side effects:
  3482.  *    None.
  3483.  *
  3484.  *----------------------------------------------------------------------
  3485.  */
  3486.  
  3487. Window
  3488. TkGetTransientMaster(
  3489.     TkWindow *winPtr)
  3490. {
  3491.     if (winPtr->wmInfoPtr != NULL) {
  3492.     return winPtr->wmInfoPtr->master;
  3493.     }
  3494.     return None;
  3495. }
  3496.  
  3497. /*
  3498.  *----------------------------------------------------------------------
  3499.  *
  3500.  * TkMacGetXWindow --
  3501.  *
  3502.  *    Returns the X window Id associated with the given WindowRef.
  3503.  *
  3504.  * Results:
  3505.  *    The window id is returned.  None is returned if not a Tk window.
  3506.  *
  3507.  * Side effects:
  3508.  *    None.
  3509.  *
  3510.  *----------------------------------------------------------------------
  3511.  */
  3512.  
  3513. Window
  3514. TkMacGetXWindow(
  3515.     WindowRef macWinPtr)
  3516. {
  3517.     register Tcl_HashEntry *hPtr;
  3518.  
  3519.     if ((macWinPtr == NULL) || !windowHashInit) {
  3520.     return None;
  3521.     }
  3522.     hPtr = Tcl_FindHashEntry(&windowTable, (char *) macWinPtr);
  3523.     if (hPtr == NULL) {
  3524.     return None;
  3525.     }
  3526.     return (Window) Tcl_GetHashValue(hPtr);
  3527. }
  3528.  
  3529. /*
  3530.  *----------------------------------------------------------------------
  3531.  *
  3532.  * TkMacZoomToplevel --
  3533.  *
  3534.  *    The function is invoked when the user clicks in the zoom region
  3535.  *    of a Tk window.  The function will handle the mouse tracking
  3536.  *    for the interaction.  If the window is to be zoomed the window
  3537.  *    size is changed and events are generated to let Tk know what
  3538.  *    happened.
  3539.  *
  3540.  * Results:
  3541.  *    True if events were placed on event queue, false otherwise.
  3542.  *
  3543.  * Side effects:
  3544.  *    The window may be resized & events placed on Tk's queue.
  3545.  *
  3546.  *----------------------------------------------------------------------
  3547.  */
  3548.  
  3549. int
  3550. TkMacZoomToplevel(
  3551.     WindowPtr whichWindow,    /* The Macintosh window to zoom. */
  3552.     Point where,        /* The current mouse position. */
  3553.     short zoomPart)        /* Either inZoomIn or inZoomOut */
  3554. {
  3555.     Window window;
  3556.     Tk_Window tkwin;
  3557.     Point location = {0, 0};
  3558.     int xOffset, yOffset;
  3559.     WmInfo *wmPtr;
  3560.  
  3561.     SetPort(whichWindow);
  3562.     if (!TrackBox(whichWindow, where, zoomPart)) {
  3563.     return false;
  3564.     }
  3565.  
  3566.     /*
  3567.      * We should now zoom the window (as long as it's one of ours).  We 
  3568.      * also need to generate an event to let Tk know that the window size 
  3569.      * has changed.
  3570.      */
  3571.     window = TkMacGetXWindow(whichWindow);
  3572.     tkwin = Tk_IdToWindow(tkDisplayList->display, window);
  3573.     if (tkwin == NULL) {
  3574.     return false;
  3575.     }
  3576.  
  3577.     /*
  3578.      * The following block of code works around a bug in the window
  3579.      * definition for Apple's floating windows.  The zoom behavior is
  3580.      * broken - we must manually set the standard state (by default
  3581.      * it's something like 1x1) and we must swap the zoomPart manually
  3582.      * otherwise we always get the same zoomPart and nothing happens.
  3583.      */
  3584.     wmPtr = ((TkWindow *) tkwin)->wmInfoPtr;
  3585.     if (wmPtr->style >= floatProc && wmPtr->style <= floatSideZoomGrowProc) {
  3586.     if (zoomPart == inZoomIn) {
  3587.         Rect zoomRect = tcl_macQdPtr->screenBits.bounds;
  3588.         InsetRect(&zoomRect, 60, 60);
  3589.         SetWindowStandardState(whichWindow, &zoomRect);
  3590.         zoomPart = inZoomOut;
  3591.     } else {
  3592.         zoomPart = inZoomIn;
  3593.     }
  3594.     }
  3595.     
  3596.     ZoomWindow(whichWindow, zoomPart, false);
  3597.     InvalRect(&whichWindow->portRect);
  3598.     TkMacInvalClipRgns((TkWindow *) tkwin);
  3599.  
  3600.     LocalToGlobal(&location);
  3601.     TkMacWindowOffset(whichWindow, &xOffset, &yOffset);
  3602.     location.h -= xOffset;
  3603.     location.v -= yOffset;
  3604.     TkGenWMConfigureEvent(tkwin, location.h, location.v, 
  3605.         whichWindow->portRect.right - whichWindow->portRect.left,
  3606.         whichWindow->portRect.bottom - whichWindow->portRect.top,
  3607.         TK_BOTH_CHANGED);
  3608.     return true;
  3609. }
  3610.  
  3611. /*
  3612.  *----------------------------------------------------------------------
  3613.  *
  3614.  * TkUnsupported1Cmd --
  3615.  *
  3616.  *    This procedure is invoked to process the "unsupported1" Tcl 
  3617.  *    command.  This command allows you to set the style of decoration
  3618.  *    for a Macintosh window.
  3619.  *
  3620.  * Results:
  3621.  *    A standard Tcl result.
  3622.  *
  3623.  * Side effects:
  3624.  *    Changes the style of a new Mac window.
  3625.  *
  3626.  *----------------------------------------------------------------------
  3627.  */
  3628.  
  3629.     /* ARGSUSED */
  3630. int
  3631. TkUnsupported1Cmd(
  3632.     ClientData clientData,    /* Main window associated with
  3633.                  * interpreter. */
  3634.     Tcl_Interp *interp,        /* Current interpreter. */
  3635.     int argc,            /* Number of arguments. */
  3636.     char **argv)        /* Argument strings. */
  3637. {
  3638.     Tk_Window tkwin = (Tk_Window) clientData;
  3639.     TkWindow *winPtr;
  3640.     register WmInfo *wmPtr;
  3641.     int c;
  3642.     size_t length;
  3643.  
  3644.     if (argc < 3) {
  3645.     wrongNumArgs:
  3646.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  3647.         argv[0], " option window ?arg ...?\"", (char *) NULL);
  3648.     return TCL_ERROR;
  3649.     }
  3650.  
  3651.     winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
  3652.     if (winPtr == NULL) {
  3653.     return TCL_ERROR;
  3654.     }
  3655.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  3656.     Tcl_AppendResult(interp, "window \"", winPtr->pathName,
  3657.         "\" isn't a top-level window", (char *) NULL);
  3658.     return TCL_ERROR;
  3659.     }
  3660.     wmPtr = winPtr->wmInfoPtr;
  3661.     c = argv[1][0];
  3662.     length = strlen(argv[1]);
  3663.     if ((c == 's')  && (strncmp(argv[1], "style", length) == 0)) {
  3664.     if ((argc != 3) && (argc != 4)) {
  3665.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  3666.             argv[0], " style window ?windowStyle?\"",
  3667.             (char *) NULL);
  3668.         return TCL_ERROR;
  3669.     }
  3670.     if (argc == 3) {
  3671.         switch (wmPtr->style) {
  3672.         case noGrowDocProc:
  3673.         case documentProc:
  3674.             interp->result = "documentProc";
  3675.             break;
  3676.         case dBoxProc:
  3677.             interp->result = "dBoxProc";
  3678.             break;
  3679.         case plainDBox:
  3680.             interp->result = "plainDBox";
  3681.             break;
  3682.         case altDBoxProc:
  3683.             interp->result = "altDBoxProc";
  3684.             break;
  3685.         case movableDBoxProc:
  3686.             interp->result = "movableDBoxProc";
  3687.             break;
  3688.         case zoomDocProc:
  3689.         case zoomNoGrow:
  3690.             interp->result = "zoomDocProc";
  3691.             break;
  3692.         case rDocProc:
  3693.             interp->result = "rDocProc";
  3694.             break;
  3695.         case floatProc:
  3696.         case floatGrowProc:
  3697.             interp->result = "floatProc";
  3698.             break;
  3699.         case floatZoomProc:
  3700.         case floatZoomGrowProc:
  3701.             interp->result = "floatZoomProc";
  3702.             break;
  3703.         case floatSideProc:
  3704.         case floatSideGrowProc:
  3705.             interp->result = "floatSideProc";
  3706.             break;
  3707.         case floatSideZoomProc:
  3708.         case floatSideZoomGrowProc:
  3709.             interp->result = "floatSideZoomProc";
  3710.             break;
  3711.         default:
  3712.            panic("invalid style");
  3713.         }
  3714.         return TCL_OK;
  3715.     }
  3716.     if (strcmp(argv[3], "documentProc") == 0) {
  3717.         wmPtr->style = documentProc;
  3718.     } else if (strcmp(argv[3], "noGrowDocProc") == 0) {
  3719.         wmPtr->style = documentProc;
  3720.     } else if (strcmp(argv[3], "dBoxProc") == 0) {
  3721.         wmPtr->style = dBoxProc;
  3722.     } else if (strcmp(argv[3], "plainDBox") == 0) {
  3723.         wmPtr->style = plainDBox;
  3724.     } else if (strcmp(argv[3], "altDBoxProc") == 0) {
  3725.         wmPtr->style = altDBoxProc;
  3726.     } else if (strcmp(argv[3], "movableDBoxProc") == 0) {
  3727.         wmPtr->style = movableDBoxProc;
  3728.     } else if (strcmp(argv[3], "zoomDocProc") == 0) {
  3729.         wmPtr->style = zoomDocProc;
  3730.     } else if (strcmp(argv[3], "zoomNoGrow") == 0) {
  3731.         wmPtr->style = zoomNoGrow;
  3732.     } else if (strcmp(argv[3], "rDocProc") == 0) {
  3733.         wmPtr->style = rDocProc;
  3734.     } else if (strcmp(argv[3], "floatProc") == 0) {
  3735.         wmPtr->style = floatGrowProc;
  3736.     } else if (strcmp(argv[3], "floatGrowProc") == 0) {
  3737.         wmPtr->style = floatGrowProc;
  3738.     } else if (strcmp(argv[3], "floatZoomProc") == 0) {
  3739.         wmPtr->style = floatZoomGrowProc;
  3740.     } else if (strcmp(argv[3], "floatZoomGrowProc") == 0) {
  3741.         wmPtr->style = floatZoomGrowProc;
  3742.     } else if (strcmp(argv[3], "floatSideProc") == 0) {
  3743.         wmPtr->style = floatSideGrowProc;
  3744.     } else if (strcmp(argv[3], "floatSideGrowProc") == 0) {
  3745.         wmPtr->style = floatSideGrowProc;
  3746.     } else if (strcmp(argv[3], "floatSideZoomProc") == 0) {
  3747.         wmPtr->style = floatSideZoomGrowProc;
  3748.     } else if (strcmp(argv[3], "floatSideZoomGrowProc") == 0) {
  3749.         wmPtr->style = floatSideZoomGrowProc;
  3750.     } else {
  3751.         Tcl_AppendResult(interp, "bad style: should be documentProc, ",
  3752.                 "dBoxProc, plainDBox, altDBoxProc, movableDBoxProc, ",
  3753.                 "zoomDocProc, rDocProc, floatProc, floatZoomProc, ",
  3754.             "floatSideProc, or floatSideZoomProc",
  3755.             (char *) NULL);
  3756.         return TCL_ERROR;
  3757.     }
  3758.     } else {
  3759.     Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
  3760.         "\": must be style",
  3761.         (char *) NULL);
  3762.     return TCL_ERROR;
  3763.     }
  3764.     
  3765.     return TCL_OK;
  3766. }
  3767.  
  3768. /*
  3769.  *----------------------------------------------------------------------
  3770.  *
  3771.  * TkMakeMenuWindow --
  3772.  *
  3773.  *    Configure the window to be either a undecorated pull-down 
  3774.  *    (or pop-up) menu, or as a toplevel floating menu (palette).
  3775.  *
  3776.  * Results:
  3777.  *    None.
  3778.  *
  3779.  * Side effects:
  3780.  *    Changes the style bit used to create a new Mac toplevel.
  3781.  *
  3782.  *----------------------------------------------------------------------
  3783.  */
  3784.  
  3785. void
  3786. TkMakeMenuWindow(
  3787.     Tk_Window tkwin,        /* New window. */
  3788.     int transient)        /* 1 means menu is only posted briefly as
  3789.                  * a popup or pulldown or cascade.  0 means
  3790.                  * menu is always visible, e.g. as a 
  3791.                  * floating menu. */
  3792. {
  3793.     if (transient) {
  3794.     ((TkWindow *) tkwin)->wmInfoPtr->style = plainDBox;
  3795.     } else {
  3796.     ((TkWindow *) tkwin)->wmInfoPtr->style = floatGrowProc;
  3797.     }
  3798. }
  3799.  
  3800. /*
  3801.  *----------------------------------------------------------------------
  3802.  *
  3803.  * TkMacMakeRealWindowExist --
  3804.  *
  3805.  *    This function finally creates the real Macintosh window that
  3806.  *    the Mac actually understands.  
  3807.  *
  3808.  * Results:
  3809.  *    None.
  3810.  *
  3811.  * Side effects:
  3812.  *    A new Macintosh toplevel is created.
  3813.  *
  3814.  *----------------------------------------------------------------------
  3815.  */
  3816.  
  3817. void 
  3818. TkMacMakeRealWindowExist(
  3819.     TkWindow *winPtr)    /* Tk window. */
  3820. {
  3821.     WmInfo *wmPtr = winPtr->wmInfoPtr;
  3822.     WindowRef newWindow = NULL;
  3823.     MacDrawable *macWin;
  3824.     Rect geometry;
  3825.     Tcl_HashEntry *valueHashPtr;
  3826.     int new;
  3827.     TkMacWindowList *listPtr;
  3828.  
  3829.     if (TkMacHostToplevelExists(winPtr)) {
  3830.         return;
  3831.     }
  3832.     
  3833.     macWin = (MacDrawable *) winPtr->window;
  3834.  
  3835.     /*
  3836.      * If this is embedded, make sure its container's toplevel exists,
  3837.      * then return... 
  3838.      */
  3839.     
  3840.     if (Tk_IsEmbedded(winPtr)) {
  3841.     TkWindow *contWinPtr;
  3842.  
  3843.     contWinPtr = TkpGetOtherWindow(winPtr);
  3844.     if (contWinPtr != NULL) {
  3845.         TkMacMakeRealWindowExist(contWinPtr->privatePtr->toplevel->winPtr);
  3846.         macWin->flags |= TK_HOST_EXISTS;
  3847.         return;
  3848.     } else {
  3849.         panic("TkMacMakeRealWindowExist could not find container");
  3850.     }
  3851.  
  3852.     /*
  3853.      * NOTE: Here we should handle out of process embedding.
  3854.      */
  3855.     
  3856.     }
  3857.     
  3858.     InitialWindowBounds(winPtr, &geometry);
  3859.     
  3860.     newWindow = NewCWindow(NULL, &geometry, "\ptemp", false, 
  3861.         (short) wmPtr->style, (WindowRef) -1, true, 0);
  3862.     if (newWindow == NULL) {
  3863.     panic("couldn't allocate new Mac window");
  3864.     }
  3865.     
  3866.     /*
  3867.      * Add this window to the list of toplevel windows.
  3868.      */
  3869.     
  3870.     listPtr = (TkMacWindowList *) ckalloc(sizeof(TkMacWindowList));
  3871.     listPtr->nextPtr = tkMacWindowListPtr;
  3872.     listPtr->winPtr = winPtr;
  3873.     tkMacWindowListPtr = listPtr;
  3874.     
  3875.     macWin->portPtr = (GWorldPtr) newWindow;
  3876.     MacMoveWindow(newWindow, (int) geometry.left, (int) geometry.top);
  3877.     SetPort((GrafPtr) newWindow);
  3878.     
  3879.     if (!windowHashInit) {
  3880.     Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
  3881.     windowHashInit = true;
  3882.     }
  3883.     valueHashPtr = Tcl_CreateHashEntry(&windowTable,
  3884.         (char *) newWindow, &new);
  3885.     if (!new) {
  3886.     panic("same macintosh window allocated twice!");
  3887.     }
  3888.     Tcl_SetHashValue(valueHashPtr, macWin);
  3889.     
  3890.     macWin->flags |= TK_HOST_EXISTS;
  3891. }
  3892.  
  3893. /*
  3894.  *----------------------------------------------------------------------
  3895.  *
  3896.  * TkMacRegisterOffScreenWindow --
  3897.  *
  3898.  *    This function adds the passed in Off Screen Port to the
  3899.  *    hash table that maps Mac windows to root X windows.  
  3900.  *
  3901.  * Results:
  3902.  *    None.
  3903.  *
  3904.  * Side effects:
  3905.  *    An entry is added to the windowTable hash table.
  3906.  *
  3907.  *----------------------------------------------------------------------
  3908.  */
  3909.  
  3910. void 
  3911. TkMacRegisterOffScreenWindow(
  3912.     Window window,    /* Window structure. */
  3913.     GWorldPtr portPtr)    /* Pointer to a Mac GWorld. */
  3914. {
  3915.     WindowRef newWindow = NULL;
  3916.     MacDrawable *macWin;
  3917.     Tcl_HashEntry *valueHashPtr;
  3918.     int new;
  3919.  
  3920.     macWin = (MacDrawable *) window;
  3921.     if (!windowHashInit) {
  3922.     Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
  3923.     windowHashInit = true;
  3924.     }
  3925.     valueHashPtr = Tcl_CreateHashEntry(&windowTable,
  3926.         (char *) portPtr, &new);
  3927.     if (!new) {
  3928.     panic("same macintosh window allocated twice!");
  3929.     }
  3930.     Tcl_SetHashValue(valueHashPtr, macWin);
  3931. }
  3932.  
  3933. /*
  3934.  *----------------------------------------------------------------------
  3935.  *
  3936.  * TkMacUnregisterMacWindow --
  3937.  *
  3938.  *    Given a macintosh port window, this function removes the 
  3939.  *    association between this window and the root X window that
  3940.  *    Tk cares about.  
  3941.  *
  3942.  * Results:
  3943.  *    None.
  3944.  *
  3945.  * Side effects:
  3946.  *    An entry is removed from the windowTable hash table.
  3947.  *
  3948.  *----------------------------------------------------------------------
  3949.  */
  3950.  
  3951. void 
  3952. TkMacUnregisterMacWindow(
  3953.     GWorldPtr portPtr)    /* Pointer to a Mac GWorld. */
  3954. {
  3955.     if (!windowHashInit) {
  3956.     panic("TkMacUnregisterMacWindow: unmapping before inited");;
  3957.     }
  3958.     Tcl_DeleteHashEntry(Tcl_FindHashEntry(&windowTable,
  3959.     (char *) portPtr));
  3960. }
  3961.  
  3962. /*
  3963.  *----------------------------------------------------------------------
  3964.  *
  3965.  * TkMacSetScrollbarGrow --
  3966.  *
  3967.  *    Sets a flag for a toplevel window indicating that the passed
  3968.  *    Tk scrollbar window will display the grow region for the 
  3969.  *    toplevel window.
  3970.  *
  3971.  * Results:
  3972.  *    None.
  3973.  *
  3974.  * Side effects:
  3975.  *    A flag is set int windows toplevel parent.
  3976.  *
  3977.  *----------------------------------------------------------------------
  3978.  */
  3979.  
  3980. void 
  3981. TkMacSetScrollbarGrow(
  3982.     TkWindow *winPtr,        /* Tk scrollbar window. */
  3983.     int flag)            /* Boolean value true or false. */
  3984. {
  3985.     if (flag) {
  3986.     winPtr->privatePtr->toplevel->flags |= TK_SCROLLBAR_GROW;
  3987.     winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = winPtr;
  3988.     } else if (winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr
  3989.         == winPtr) {
  3990.     winPtr->privatePtr->toplevel->flags &= ~TK_SCROLLBAR_GROW;
  3991.     winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = NULL;
  3992.     }
  3993. }
  3994.  
  3995. /*
  3996.  *----------------------------------------------------------------------
  3997.  *
  3998.  * TkMacGetScrollbarGrowWindow --
  3999.  *
  4000.  *    Tests to see if a given window's toplevel window contains a
  4001.  *    scrollbar that will draw the GrowIcon for the window.
  4002.  *
  4003.  * Results:
  4004.  *    Boolean value.
  4005.  *
  4006.  * Side effects:
  4007.  *    None.
  4008.  *
  4009.  *----------------------------------------------------------------------
  4010.  */
  4011.  
  4012. TkWindow * 
  4013. TkMacGetScrollbarGrowWindow(
  4014.     TkWindow *winPtr)    /* Tk window. */
  4015. {
  4016.     TkWindow *scrollWinPtr;
  4017.     
  4018.     if (winPtr == NULL) {
  4019.     return NULL;
  4020.     }
  4021.     scrollWinPtr =
  4022.     winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr;
  4023.     if (winPtr != NULL) {
  4024.     /*
  4025.      * We need to confirm the window exists.
  4026.      */
  4027.     if ((Tk_Window) scrollWinPtr !=
  4028.         Tk_IdToWindow(winPtr->display, winPtr->window)) {
  4029.         scrollWinPtr = NULL;
  4030.     }
  4031.     }
  4032.     return scrollWinPtr;
  4033. }
  4034.  
  4035. /*
  4036.  *----------------------------------------------------------------------
  4037.  *
  4038.  * TkWmFocusToplevel --
  4039.  *
  4040.  *    This is a utility procedure invoked by focus-management code. It
  4041.  *    exists because of the extra wrapper windows that exist under
  4042.  *    Unix; its job is to map from wrapper windows to the
  4043.  *    corresponding toplevel windows.  On PCs and Macs there are no
  4044.  *    wrapper windows so no mapping is necessary;  this procedure just
  4045.  *    determines whether a window is a toplevel or not.
  4046.  *
  4047.  * Results:
  4048.  *    If winPtr is a toplevel window, returns the pointer to the
  4049.  *    window; otherwise returns NULL.
  4050.  *
  4051.  * Side effects:
  4052.  *    None.
  4053.  *
  4054.  *----------------------------------------------------------------------
  4055.  */
  4056.  
  4057. TkWindow *
  4058. TkWmFocusToplevel(
  4059.     TkWindow *winPtr)        /* Window that received a focus-related
  4060.                  * event. */
  4061. {
  4062.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  4063.     return NULL;
  4064.     }
  4065.     return winPtr;
  4066. }
  4067.  
  4068. /*
  4069.  *----------------------------------------------------------------------
  4070.  *
  4071.  * TkpGetWrapperWindow --
  4072.  *
  4073.  *    This is a utility procedure invoked by focus-management code. It
  4074.  *    maps to the wrapper for a top-level, which is just the same
  4075.  *    as the top-level on Macs and PCs.
  4076.  *
  4077.  * Results:
  4078.  *    If winPtr is a toplevel window, returns the pointer to the
  4079.  *    window; otherwise returns NULL.
  4080.  *
  4081.  * Side effects:
  4082.  *    None.
  4083.  *
  4084.  *----------------------------------------------------------------------
  4085.  */
  4086.  
  4087. TkWindow *
  4088. TkpGetWrapperWindow(
  4089.     TkWindow *winPtr)        /* Window that received a focus-related
  4090.                  * event. */
  4091. {
  4092.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  4093.     return NULL;
  4094.     }
  4095.     return winPtr;
  4096. }
  4097.