OSDN Git Service

Updated to tk 8.4.1
[pf3gnuchains/pf3gnuchains3x.git] / tk / win / tkWinWm.c
index 9ee8076..db1e540 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * tkWinWm.c --
  *
  *     This module takes care of the interactions between a Tk-based
@@ -16,6 +16,7 @@
  */
 
 #include "tkWinInt.h"
+#include <shellapi.h>
 
 /*
  * Event structure for synthetic activation events.  These events are
@@ -43,7 +44,7 @@ typedef struct ProtocolHandler {
                                 * end of list. */
     Tcl_Interp *interp;                /* Interpreter in which to invoke command. */
     char command[4];           /* Tcl command to invoke when a client
-                                * message for this protocol arrives. 
+                                * message for this protocol arrives.
                                 * The actual size of the structure varies
                                 * to accommodate the needs of the actual
                                 * command. THIS MUST BE THE LAST FIELD OF
@@ -54,6 +55,88 @@ typedef struct ProtocolHandler {
     ((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
 
 /*
+ * Helper type passed via lParam to TkWmStackorderToplevelEnumProc
+ */
+typedef struct TkWmStackorderToplevelPair {
+    Tcl_HashTable *table;
+    TkWindow **window_ptr;
+} TkWmStackorderToplevelPair;
+
+/*
+ * This structure represents the contents of a icon, in terms of its
+ * image.  The HICON is an internal Windows format.  Most of these
+ * icon-specific-structures originated with the Winico extension.
+ * We stripped out unused parts of that code, and integrated the
+ * code more naturally with Tcl.
+ */
+typedef struct {
+       UINT                    Width, Height, Colors; /*  Width, Height and bpp */
+       LPBYTE                  lpBits;                /*  ptr to DIB bits */
+       DWORD                   dwNumBytes;            /*  how many bytes? */
+       LPBITMAPINFO    lpbi;                          /*  ptr to header */
+       LPBYTE                  lpXOR;                 /*  ptr to XOR image bits */
+       LPBYTE                  lpAND;                 /*  ptr to AND image bits */
+       HICON                   hIcon;                 /*  DAS ICON */
+} ICONIMAGE, *LPICONIMAGE;
+/*
+ * This structure is how we represent a block of the above
+ * items.  We will reallocate these structures according to
+ * how many images they need to contain.
+ */
+typedef struct {
+       int             nNumImages;                      /*  How many images? */
+       ICONIMAGE       IconImages[1];                   /*  Image entries */
+} BlockOfIconImages, *BlockOfIconImagesPtr;
+/*
+ * These two structures are used to read in icons from an
+ * 'icon directory' (i.e. the contents of a .icr file, say).
+ * We only use these structures temporarily, since we copy
+ * the information we want into a BlockOfIconImages.
+ */
+typedef struct {
+       BYTE    bWidth;               /*  Width of the image */
+       BYTE    bHeight;              /*  Height of the image (times 2) */
+       BYTE    bColorCount;          /*  Number of colors in image (0 if >=8bpp) */
+       BYTE    bReserved;            /*  Reserved */
+       WORD    wPlanes;              /*  Color Planes */
+       WORD    wBitCount;            /*  Bits per pixel */
+       DWORD   dwBytesInRes;         /*  how many bytes in this resource? */
+       DWORD   dwImageOffset;        /*  where in the file is this image */
+} ICONDIRENTRY, *LPICONDIRENTRY;
+typedef struct {
+       WORD            idReserved;   /*  Reserved */
+       WORD            idType;       /*  resource type (1 for icons) */
+       WORD            idCount;      /*  how many images? */
+       ICONDIRENTRY    idEntries[1]; /*  the entries for each image */
+} ICONDIR, *LPICONDIR;
+
+/*
+ * A pointer to one of these strucutures is associated with each
+ * toplevel.  This allows us to free up all memory associated with icon
+ * resources when a window is deleted or if the window's icon is
+ * changed.  They are simply reference counted according to:
+ *
+ * (i) how many WmInfo structures point to this object
+ * (ii) whether the ThreadSpecificData defined in this file contains
+ * a pointer to this object.
+ *
+ * The former count is for windows whose icons are individually
+ * set, and the latter is for the global default icon choice.
+ *
+ * Icons loaded from .icr/.icr use the iconBlock field, icons
+ * loaded from .exe/.dll use the hIcon field.
+ */
+typedef struct WinIconInstance {
+    int refCount;               /* Number of instances that share this
+                                 * data structure. */
+    BlockOfIconImagesPtr iconBlock;
+                                 /* Pointer to icon resource data for
+                                  * image. */
+} WinIconInstance;
+
+typedef struct WinIconInstance *WinIconPtr;
+
+/*
  * A data structure of the following type holds window-manager-related
  * information for each top-level window in an application.
  */
@@ -65,17 +148,17 @@ typedef struct TkWmInfo {
                                 * created by the window manager to wrap
                                 * a toplevel window.  This window is
                                 * a direct child of the root window. */
-    Tk_Uid titleUid;           /* Title to display in window caption.  If
-                                * NULL, use name of widget. */
-    Tk_Uid iconName;           /* Name to display in icon. */
-    TkWindow *masterPtr;       /* Master window for TRANSIENT_FOR property,
-                                * or NULL. */
+    char *title;               /* Title to display in window caption.  If
+                                * NULL, use name of widget.  Malloced. */
+    char *iconName;            /* Name to display in icon.  Malloced. */
     XWMHints hints;            /* Various pieces of information for
                                 * window manager. */
     char *leaderName;          /* Path name of leader of window group
                                 * (corresponds to hints.window_group).
-                                * Malloc-ed. Note:  this field doesn't
+                                * Malloc-ed.  Note:  this field doesn't
                                 * get updated if leader is destroyed. */
+    TkWindow *masterPtr;       /* Master window for TRANSIENT_FOR property,
+                                * or NULL. */
     Tk_Window icon;            /* Window to use as icon for this window,
                                 * or NULL. */
     Tk_Window iconFor;         /* Window for which this window is icon, or
@@ -143,6 +226,8 @@ typedef struct TkWmInfo {
                                 * to eliminate redundant resize operations. */
     HMENU hMenu;               /* the hMenu associated with this menu */
     DWORD style, exStyle;      /* Style flags for the wrapper window. */
+    LONG styleConfig;          /* Extra user requested style bits */
+    LONG exStyleConfig;                /* Extra user requested extended style bits */
 
     /*
      * List of children of the toplevel which have private colormaps.
@@ -158,13 +243,15 @@ typedef struct TkWmInfo {
     ProtocolHandler *protPtr;  /* First in list of protocol handlers for
                                 * this window (NULL means none). */
     int cmdArgc;               /* Number of elements in cmdArgv below. */
-    char **cmdArgv;            /* Array of strings to store in the
+    CONST char **cmdArgv;      /* Array of strings to store in the
                                 * WM_COMMAND property.  NULL means nothing
                                 * available. */
     char *clientMachine;       /* String to store in WM_CLIENT_MACHINE
                                 * property, or NULL. */
     int flags;                 /* Miscellaneous flags, defined below. */
     int numTransients;         /* number of transients on this window */
+    WinIconPtr iconPtr;         /* pointer to titlebar icon structure for
+                                 * this window, or NULL. */
     struct TkWmInfo *nextPtr;  /* Next in list of all top-level windows. */
 } WmInfo;
 
@@ -191,12 +278,23 @@ typedef struct TkWmInfo {
  *                             a new position for the window, but it hasn't
  *                             been reflected through the window manager
  *                             yet.
- * WM_COLORAMPS_EXPLICIT -     non-zero means the colormap windows were
+ * WM_COLORMAPS_EXPLICIT -     non-zero means the colormap windows were
  *                             set explicitly via "wm colormapwindows".
  * WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows"
  *                             was called the top-level itself wasn't
  *                             specified, so we added it implicitly at
  *                             the end of the list.
+ * WM_WIDTH_NOT_RESIZABLE -    non-zero means that we're not supposed to
+ *                             allow the user to change the width of the
+ *                             window (controlled by "wm resizable"
+ *                             command).
+ * WM_HEIGHT_NOT_RESIZABLE -   non-zero means that we're not supposed to
+ *                             allow the user to change the height of the
+ *                             window (controlled by "wm resizable"
+ *                             command).
+ * WM_TRANSIENT_WITHDRAWN -    non-zero means that this is a transient window
+ *                             that has explicitly been withdrawn. It should
+ *                             not mirror state changes in the master.
  */
 
 #define WM_NEVER_MAPPED                        (1<<0)
@@ -211,6 +309,7 @@ typedef struct TkWmInfo {
 #define WM_ADDED_TOPLEVEL_COLORMAP     (1<<9)
 #define WM_WIDTH_NOT_RESIZABLE         (1<<10)
 #define WM_HEIGHT_NOT_RESIZABLE                (1<<11)
+#define WM_TRANSIENT_WITHDRAWN         (1<<12)
 
 /*
  * Window styles for various types of toplevel windows.
@@ -224,8 +323,7 @@ typedef struct TkWmInfo {
 
 #define WM_TRANSIENT_STYLE \
                (WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_CLIPSIBLINGS|CS_DBLCLKS)
-#define EX_TRANSIENT_STYLE \
-               (WS_EX_TOOLWINDOW|WS_EX_DLGMODALFRAME)
+#define EX_TRANSIENT_STYLE (WS_EX_DLGMODALFRAME)
 
 /*
  * The following structure is the official type record for geometry
@@ -241,7 +339,7 @@ static Tk_GeomMgr wmMgrType = {
 };
 
 typedef struct ThreadSpecificData {
-    HPALETTE systemPalette;      /* System palette; refers to the 
+    HPALETTE systemPalette;      /* System palette; refers to the
                                  * currently installed foreground logical
                                  * palette. */
     TkWindow *createWindow;      /* Window that is being constructed.  This
@@ -253,10 +351,12 @@ typedef struct ThreadSpecificData {
                                  * WM_GETMINMAXINFO message before the
                                  * WM_CREATE window. */
     int initialized;             /* Flag indicating whether thread-
-                                 * specific elements of module have 
+                                 * specific elements of module have
                                  * been initialized. */
     int firstWindow;             /* Flag, cleared when the first window
                                  * is mapped in a non-iconic state. */
+    WinIconPtr iconPtr;          /* IconPtr being used as default for all
+                                  * toplevels, or NULL. */
 } ThreadSpecificData;
 static Tcl_ThreadDataKey dataKey;
 
@@ -265,11 +365,18 @@ static Tcl_ThreadDataKey dataKey;
  * because they must be shared across threads.
  */
 
-static WNDCLASS toplevelClass; /* Class for toplevel windows. */
 static int initialized;        /* Flag indicating whether module has
                                * been initialized. */
-TCL_DECLARE_MUTEX(winWmMutex)
 
+/* 
+ * A pointer to a shell proc which allows us to extract icons from
+ * any file.  We just initialize this when we start up (if we can)
+ * and then it never changes
+ */
+DWORD* (WINAPI *shgetfileinfoProc) (LPCTSTR pszPath, DWORD dwFileAttributes,
+    SHFILEINFO* psfi, UINT cbFileInfo, UINT uFlags) = NULL;
+
+TCL_DECLARE_MUTEX(winWmMutex)
 
 /*
  * Forward declarations for procedures defined in this file:
@@ -277,8 +384,6 @@ TCL_DECLARE_MUTEX(winWmMutex)
 
 static int             ActivateWindow _ANSI_ARGS_((Tcl_Event *evPtr,
                            int flags));
-static void            ConfigureEvent _ANSI_ARGS_((TkWindow *winPtr,
-                           XConfigureEvent *eventPtr));
 static void            ConfigureTopLevel _ANSI_ARGS_((WINDOWPOS *pos));
 static void            GenerateConfigureNotify _ANSI_ARGS_((
                            TkWindow *winPtr));
@@ -297,6 +402,9 @@ static int          ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
 static void            RefreshColormap _ANSI_ARGS_((Colormap colormap,
                            TkDisplay *dispPtr));
 static void            SetLimits _ANSI_ARGS_((HWND hwnd, MINMAXINFO *info));
+static void            TkWmStackorderToplevelWrapperMap _ANSI_ARGS_((
+                           TkWindow *winPtr,
+                           Tcl_HashTable *table));
 static LRESULT CALLBACK        TopLevelProc _ANSI_ARGS_((HWND hwnd, UINT message,
                            WPARAM wParam, LPARAM lParam));
 static void            TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
@@ -308,2046 +416,4321 @@ static void           UpdateGeometryInfo _ANSI_ARGS_((
 static void            UpdateWrapper _ANSI_ARGS_((TkWindow *winPtr));
 static LRESULT CALLBACK        WmProc _ANSI_ARGS_((HWND hwnd, UINT message,
                            WPARAM wParam, LPARAM lParam));
-static void            WmWaitVisibilityProc _ANSI_ARGS_((
+static void            WmWaitVisibilityOrMapProc _ANSI_ARGS_((
                            ClientData clientData, XEvent *eventPtr));
-\f
+static BlockOfIconImagesPtr   ReadIconOrCursorFromFile _ANSI_ARGS_((
+                           Tcl_Interp *interp, Tcl_Obj* fileName, BOOL isIcon));
+static WinIconPtr       ReadIconFromFile _ANSI_ARGS_((
+                           Tcl_Interp *interp, Tcl_Obj *fileName));
+static WinIconPtr       GetIconFromPixmap _ANSI_ARGS_((Display *dsPtr,
+                                                      Pixmap pixmap));
+static int                     ReadICOHeader _ANSI_ARGS_((Tcl_Channel channel));
+static BOOL            AdjustIconImagePointers _ANSI_ARGS_((LPICONIMAGE lpImage));
+static HICON           MakeIconOrCursorFromResource 
+                            _ANSI_ARGS_((LPICONIMAGE lpIcon, BOOL isIcon));
+static HICON           GetIcon _ANSI_ARGS_((WinIconPtr titlebaricon, 
+                           int icon_size));
+static int             WinSetIcon _ANSI_ARGS_((Tcl_Interp *interp,
+                           WinIconPtr titlebaricon, Tk_Window tkw));
+static void            FreeIconBlock _ANSI_ARGS_((BlockOfIconImagesPtr lpIR));
+static void            DecrIconRefCount _ANSI_ARGS_((WinIconPtr titlebaricon));
+
+static int             WmAspectCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmAttributesCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmClientCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmColormapwindowsCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmCommandCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmDeiconifyCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmFocusmodelCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmFrameCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmGeometryCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmGridCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmGroupCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmIconbitmapCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmIconifyCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmIconmaskCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmIconnameCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmIconpositionCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmIconwindowCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmMaxsizeCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmMinsizeCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmOverrideredirectCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmPositionfromCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmProtocolCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmResizableCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmSizefromCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmStackorderCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmStateCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmTitleCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmTransientCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static int             WmWithdrawCmd _ANSI_ARGS_((Tk_Window tkwin,
+                           TkWindow *winPtr, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *CONST objv[]));
+static void            WmUpdateGeom _ANSI_ARGS_((WmInfo *wmPtr,
+                           TkWindow *winPtr));
+
+/* Used in BytesPerLine */
+#define WIDTHBYTES(bits)      ((((bits) + 31)>>5)<<2)
+
 /*
  *----------------------------------------------------------------------
  *
- * InitWm --
+ * DIBNumColors --
  *
- *     This routine creates the Wm toplevel decorative frame class.
+ *     Calculates the number of entries in the color table, given by
+ *     LPSTR lpbi - pointer to the CF_DIB memory block.  Used by
+ *     titlebar icon code.
  *
  * Results:
- *     None.
  *
- * Side effects:
- *     Registers a new window class.
+ *      WORD - Number of entries in the color table.
+ *
+ * Side effects: None.
+ *
  *
  *----------------------------------------------------------------------
  */
-
-static void
-InitWm(void)
+static WORD 
+DIBNumColors( LPSTR lpbi )
 {
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
-            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-    WNDCLASS * classPtr;
+    WORD wBitCount;
+    DWORD dwClrUsed;
 
-    if (! tsdPtr->initialized) {
-       tsdPtr->initialized = 1;
-       tsdPtr->firstWindow = 1;
-    }
-    if (! initialized) {
-       Tcl_MutexLock(&winWmMutex);
-       if (! initialized) {
-           initialized = 1;
-           classPtr = &toplevelClass;
+    dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed;
 
-    /*
-     * When threads are enabled, we cannot use CLASSDC because
-     * threads will then write into the same device context.
-     * 
-     * This is a hack; we should add a subsystem that manages
-     * device context on a per-thread basis.  See also tkWinX.c,
-     * which also initializes a WNDCLASS structure.
-     */
+    if (dwClrUsed)
+       return (WORD) dwClrUsed;
 
-#ifdef TCL_THREADS
-           classPtr->style = CS_HREDRAW | CS_VREDRAW;
-#else
-           classPtr->style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
-#endif
-           classPtr->cbClsExtra = 0;
-           classPtr->cbWndExtra = 0;
-           classPtr->hInstance = Tk_GetHINSTANCE();
-           classPtr->hbrBackground = NULL;
-           classPtr->lpszMenuName = NULL;
-           classPtr->lpszClassName = TK_WIN_TOPLEVEL_CLASS_NAME;
-           classPtr->lpfnWndProc = WmProc;
-           classPtr->hIcon = LoadIcon(Tk_GetHINSTANCE(), "tk");
-           classPtr->hCursor = LoadCursor(NULL, IDC_ARROW);
-
-           if (!RegisterClass(classPtr)) {
-               panic("Unable to register TkTopLevel class");
-           }
-       }
-       Tcl_MutexUnlock(&winWmMutex);
+    wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount;
+
+    switch (wBitCount)
+    {
+       case 1: return 2;
+       case 4: return 16;
+       case 8: return 256;
+       default:return 0;
     }
 }
 \f
 /*
  *----------------------------------------------------------------------
  *
- * GetTopLevel --
+ * PaletteSize --
  *
- *     This function retrieves the TkWindow associated with the
- *     given HWND.
+ *     Calculates the number of bytes in the color table, as given by
+ *     LPSTR lpbi - pointer to the CF_DIB memory block.  Used by
+ *     titlebar icon code.
  *
  * Results:
- *     Returns the matching TkWindow.
+ *     number of bytes in the color table
+ *
+ * Side effects: None.
  *
- * Side effects:
- *     None.
  *
  *----------------------------------------------------------------------
  */
-
-static TkWindow *
-GetTopLevel(hwnd)
-    HWND hwnd;
+static WORD 
+PaletteSize( LPSTR lpbi )
 {
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
-            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-
-    /*
-     * If this function is called before the CreateWindowEx call
-     * has completed, then the user data slot will not have been
-     * set yet, so we use the global createWindow variable.
-     */
-
-    if (tsdPtr->createWindow) {
-       return tsdPtr->createWindow;
-    }
-    return (TkWindow *) GetWindowLong(hwnd, GWL_USERDATA);
+    return ((WORD)( DIBNumColors( lpbi ) * sizeof( RGBQUAD )) );
 }
 \f
 /*
  *----------------------------------------------------------------------
  *
- * SetLimits --
+ * FindDIBits --
  *
- *     Updates the minimum and maximum window size constraints.
+ *     Locate the image bits in a CF_DIB format DIB, as given by
+ *     LPSTR lpbi - pointer to the CF_DIB memory block.  Used by
+ *     titlebar icon code.
  *
  * Results:
- *     None.
+ *     pointer to the image bits
+ *
+ * Side effects: None
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+static LPSTR 
+FindDIBBits( LPSTR lpbi )
+{
+   return ( lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ) );
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * BytesPerLine --
+ *
+ *     Calculates the number of bytes in one scan line, as given by
+ *     LPBITMAPINFOHEADER lpBMIH - pointer to the BITMAPINFOHEADER
+ *     that begins the CF_DIB block.  Used by titlebar icon code.
+ *
+ * Results:
+ *     number of bytes in one scan line (DWORD aligned)
+ *
+ * Side effects: None
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+static DWORD 
+BytesPerLine( LPBITMAPINFOHEADER lpBMIH )
+{
+    return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * AdjustIconImagePointers --
+ *
+ *     Adjusts internal pointers in icon resource struct, as given
+ *     by LPICONIMAGE lpImage - the resource to handle.  Used by
+ *     titlebar icon code.
+ *
+ * Results:
+ *     BOOL - TRUE for success, FALSE for failure
  *
  * Side effects:
- *     Changes the values of the info pointer to reflect the current
- *     minimum and maximum size values.
+ *
  *
  *----------------------------------------------------------------------
  */
-
-static void
-SetLimits(hwnd, info)
-    HWND hwnd;
-    MINMAXINFO *info;
+static BOOL 
+AdjustIconImagePointers( LPICONIMAGE lpImage )
 {
-    register WmInfo *wmPtr;
-    int maxWidth, maxHeight;
-    int minWidth, minHeight;
-    int base;
-    TkWindow *winPtr = GetTopLevel(hwnd);
-
-    if (winPtr == NULL) {
-       return;
-    }
-
-    wmPtr = winPtr->wmInfoPtr;
-    
-    /*
-     * Copy latest constraint info.
+    /*  Sanity check */
+    if (lpImage==NULL)
+       return FALSE;
+    /*  BITMAPINFO is at beginning of bits */
+    lpImage->lpbi = (LPBITMAPINFO)lpImage->lpBits;
+    /*  Width - simple enough */
+    lpImage->Width = lpImage->lpbi->bmiHeader.biWidth;
+    /* 
+     * Icons are stored in funky format where height is doubled 
+     * so account for that 
      */
-
-    wmPtr->defMinWidth = info->ptMinTrackSize.x;
-    wmPtr->defMinHeight = info->ptMinTrackSize.y;
-    wmPtr->defMaxWidth = info->ptMaxTrackSize.x;
-    wmPtr->defMaxHeight = info->ptMaxTrackSize.y;
-    
-    GetMaxSize(wmPtr, &maxWidth, &maxHeight);
-    GetMinSize(wmPtr, &minWidth, &minHeight);
-
-    if (wmPtr->gridWin != NULL) {
-       base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
-       if (base < 0) {
-           base = 0;
-       }
-       base += wmPtr->borderWidth;
-       info->ptMinTrackSize.x = base + (minWidth * wmPtr->widthInc);
-       info->ptMaxTrackSize.x = base + (maxWidth * wmPtr->widthInc);
-
-       base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
-       if (base < 0) {
-           base = 0;
+    lpImage->Height = (lpImage->lpbi->bmiHeader.biHeight)/2;
+    /*  How many colors? */
+    lpImage->Colors = lpImage->lpbi->bmiHeader.biPlanes * 
+                            lpImage->lpbi->bmiHeader.biBitCount;
+    /*  XOR bits follow the header and color table */
+    lpImage->lpXOR = (LPBYTE)FindDIBBits(((LPSTR)lpImage->lpbi));
+    /*  AND bits follow the XOR bits */
+    lpImage->lpAND = lpImage->lpXOR + (lpImage->Height*
+               BytesPerLine((LPBITMAPINFOHEADER)(lpImage->lpbi)));
+    return TRUE;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * MakeIconOrCursorFromResource --
+ *
+ *     Construct an actual HICON structure from the information
+ *     in a resource.
+ *
+ * Results:
+ *
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+static HICON 
+MakeIconOrCursorFromResource(LPICONIMAGE lpIcon, BOOL isIcon) {
+    HICON hIcon ;
+    static FARPROC pfnCreateIconFromResourceEx=NULL;
+    static int initinfo=0;
+    /*  Sanity Check */
+    if (lpIcon == NULL)
+       return NULL;
+    if (lpIcon->lpBits == NULL)
+       return NULL;
+    if (!initinfo) {
+       HMODULE hMod = GetModuleHandleA("USER32.DLL");
+       initinfo=1;
+       if (hMod){
+           pfnCreateIconFromResourceEx = 
+             GetProcAddress(hMod, "CreateIconFromResourceEx");
        }
-       base += wmPtr->borderHeight;
-       info->ptMinTrackSize.y = base + (minHeight * wmPtr->heightInc);
-       info->ptMaxTrackSize.y = base + (maxHeight * wmPtr->heightInc);
+    }
+    /*  Let the OS do the real work :) */
+    if (pfnCreateIconFromResourceEx!=NULL) {
+       hIcon = (HICON) (pfnCreateIconFromResourceEx)
+       (lpIcon->lpBits, lpIcon->dwNumBytes, isIcon, 0x00030000,
+        (*(LPBITMAPINFOHEADER)(lpIcon->lpBits)).biWidth,
+        (*(LPBITMAPINFOHEADER)(lpIcon->lpBits)).biHeight/2, 0);
     } else {
-       info->ptMaxTrackSize.x = maxWidth + wmPtr->borderWidth;
-       info->ptMaxTrackSize.y = maxHeight + wmPtr->borderHeight;
-       info->ptMinTrackSize.x = minWidth + wmPtr->borderWidth;
-       info->ptMinTrackSize.y = minHeight + wmPtr->borderHeight;
+        hIcon = NULL;
     }
-
-    /*
-     * If the window isn't supposed to be resizable, then set the
-     * minimum and maximum dimensions to be the same as the current size.
-     */
-
-    if (!(wmPtr->flags & WM_SYNC_PENDING)) {
-       if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
-           info->ptMinTrackSize.x = winPtr->changes.width
-               + wmPtr->borderWidth;
-           info->ptMaxTrackSize.x = info->ptMinTrackSize.x;
-       }
-       if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
-           info->ptMinTrackSize.y = winPtr->changes.height 
-               + wmPtr->borderHeight;
-           info->ptMaxTrackSize.y = info->ptMinTrackSize.y;
+    /*  It failed, odds are good we're on NT so try the non-Ex way */
+    if (hIcon == NULL)    {
+       /*  We would break on NT if we try with a 16bpp image */
+       if (lpIcon->lpbi->bmiHeader.biBitCount != 16) {
+           hIcon = CreateIconFromResource(lpIcon->lpBits, lpIcon->dwNumBytes, 
+                                          isIcon, 0x00030000);
        }
     }
+    return hIcon;
 }
 \f
 /*
  *----------------------------------------------------------------------
  *
- * TkWinWmCleanup --
+ * ReadICOHeader --
  *
- *     Unregisters classes registered by the window manager. This is
- *     called from the DLL main entry point when the DLL is unloaded.
+ *     Reads the header from an ICO file, as specfied by channel.
  *
  * Results:
- *     None.
+ *     UINT - Number of images in file, -1 for failure.
+ *     If this succeeds, there is a decent chance this is a
+ *     valid icon file.
  *
  * Side effects:
- *     The window classes are discarded.
+ *
  *
  *----------------------------------------------------------------------
  */
-
-void
-TkWinWmCleanup(hInstance)
-    HINSTANCE hInstance;
+static int 
+ReadICOHeader( Tcl_Channel channel )
 {
-    ThreadSpecificData *tsdPtr;
-
-    /*
-     * If we're using stubs to access the Tcl library, and they
-     * haven't been initialized, we can't call Tcl_GetThreadData.
-     */
-
-#ifdef USE_TCL_STUBS
-    if (tclStubsPtr == NULL) {
-        return;
-    }
-#endif
-
-    tsdPtr = (ThreadSpecificData *) 
-            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-
-    if (!tsdPtr->initialized) {
-        return;
-    }
-    tsdPtr->initialized = 0;
-    
-    UnregisterClass(TK_WIN_TOPLEVEL_CLASS_NAME, hInstance);
+    WORD    Input;
+    DWORD      dwBytesRead;
+
+    /*  Read the 'reserved' WORD */
+    dwBytesRead = Tcl_Read( channel, (char*)&Input, sizeof( WORD ));
+    /*  Did we get a WORD? */
+    if (dwBytesRead != sizeof( WORD ))
+       return -1;
+    /*  Was it 'reserved' ?   (ie 0) */
+    if (Input != 0)
+       return -1;
+    /*  Read the type WORD */
+    dwBytesRead = Tcl_Read( channel, (char*)&Input, sizeof( WORD ));
+    /*  Did we get a WORD? */
+    if (dwBytesRead != sizeof( WORD ))
+       return -1;
+    /*  Was it type 1? */
+    if (Input != 1)
+       return -1;
+    /*  Get the count of images */
+    dwBytesRead = Tcl_Read( channel, (char*)&Input, sizeof( WORD ));
+    /*  Did we get a WORD? */
+    if (dwBytesRead != sizeof( WORD ))
+       return -1;
+    /*  Return the count */
+    return (int)Input;
 }
 \f
 /*
- *--------------------------------------------------------------
+ *----------------------------------------------------------------------
  *
- * TkWmNewWindow --
+ * InitWindowClass --
  *
- *     This procedure is invoked whenever a new top-level
- *     window is created.  Its job is to initialize the WmInfo
- *     structure for the window.
+ *     This routine creates the Wm toplevel decorative frame class.
  *
  * Results:
  *     None.
  *
  * Side effects:
- *     A WmInfo structure gets allocated and initialized.
+ *     Registers a new window class.
  *
- *--------------------------------------------------------------
+ *----------------------------------------------------------------------
  */
+static int 
+InitWindowClass(WinIconPtr titlebaricon) {
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
+           Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
 
-void
-TkWmNewWindow(winPtr)
-    TkWindow *winPtr;          /* Newly-created top-level window. */
-{
-    register WmInfo *wmPtr;
-
-    wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
-    winPtr->wmInfoPtr = wmPtr;
-    wmPtr->winPtr = winPtr;
-    wmPtr->wrapper = NULL;
-    wmPtr->titleUid = NULL;
-    wmPtr->iconName = NULL;
-    wmPtr->masterPtr = NULL;
-    wmPtr->hints.flags = InputHint | StateHint;
-    wmPtr->hints.input = True;
-    wmPtr->hints.initial_state = NormalState;
-    wmPtr->hints.icon_pixmap = None;
-    wmPtr->hints.icon_window = None;
-    wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
-    wmPtr->hints.icon_mask = None;
-    wmPtr->hints.window_group = None;
-    wmPtr->leaderName = NULL;
-    wmPtr->icon = NULL;
-    wmPtr->iconFor = NULL;
-    wmPtr->sizeHintsFlags = 0;
-
-    /*
-     * Default the maximum dimensions to the size of the display.
-     */
-
-    wmPtr->defMinWidth = wmPtr->defMinHeight = 0;
-    wmPtr->defMaxWidth = DisplayWidth(winPtr->display,
-           winPtr->screenNum);
-    wmPtr->defMaxHeight = DisplayHeight(winPtr->display,
-           winPtr->screenNum);
-    wmPtr->minWidth = wmPtr->minHeight = 1;
-    wmPtr->maxWidth = wmPtr->maxHeight = 0;
-    wmPtr->gridWin = NULL;
-    wmPtr->widthInc = wmPtr->heightInc = 1;
-    wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
-    wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
-    wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
-    wmPtr->gravity = NorthWestGravity;
-    wmPtr->width = -1;
-    wmPtr->height = -1;
-    wmPtr->hMenu = NULL;
-    wmPtr->x = winPtr->changes.x;
-    wmPtr->y = winPtr->changes.y;
-    wmPtr->borderWidth = 0;
-    wmPtr->borderHeight = 0;
-    
-    wmPtr->cmapList = NULL;
-    wmPtr->cmapCount = 0;
-    wmPtr->numTransients = 0;
-
-    wmPtr->configWidth = -1;
-    wmPtr->configHeight = -1;
-    wmPtr->protPtr = NULL;
-    wmPtr->cmdArgv = NULL;
-    wmPtr->clientMachine = NULL;
-    wmPtr->flags = WM_NEVER_MAPPED;
-    wmPtr->nextPtr = winPtr->dispPtr->firstWmPtr;
-    winPtr->dispPtr->firstWmPtr = wmPtr;
+    if (! tsdPtr->initialized) {
+       tsdPtr->initialized = 1;
+       tsdPtr->firstWindow = 1;
+       tsdPtr->iconPtr = NULL;
+    }
+    if (! initialized) {
+       Tcl_MutexLock(&winWmMutex);
+       if (! initialized) {
+           Tcl_DString classString;
+           WNDCLASS class;
+           initialized = 1;
 
-    /*
-     * Tk must monitor structure events for top-level windows, in order
-     * to detect size and position changes caused by window managers.
-     */
+           if (shgetfileinfoProc == NULL) {
+               HINSTANCE hInstance = LoadLibraryA("shell32");
+               if (hInstance != NULL) {
+                   shgetfileinfoProc = 
+                   (DWORD* (WINAPI *) (LPCTSTR pszPath, DWORD dwFileAttributes,
+    SHFILEINFO* psfi, UINT cbFileInfo, UINT uFlags)) GetProcAddress(hInstance, 
+                     "SHGetFileInfo");
+                   FreeLibrary(hInstance);
+               }
+           }
+           /*
+            * The only difference between WNDCLASSW and WNDCLASSA are
+            * in pointers, so we can use the generic structure WNDCLASS.
+            */
+           ZeroMemory(&class, sizeof(WNDCLASS));
 
-    Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
-           TopLevelEventProc, (ClientData) winPtr);
+           /*
+            * When threads are enabled, we cannot use CLASSDC because
+            * threads will then write into the same device context.
+            *
+            * This is a hack; we should add a subsystem that manages
+            * device context on a per-thread basis.  See also tkWinX.c,
+            * which also initializes a WNDCLASS structure.
+            */
 
-    /*
-     * Arrange for geometry requests to be reflected from the window
-     * to the window manager.
-     */
+#ifdef TCL_THREADS
+           class.style = CS_HREDRAW | CS_VREDRAW;
+#else
+           class.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
+#endif
+           class.hInstance = Tk_GetHINSTANCE();
+           Tcl_WinUtfToTChar(TK_WIN_TOPLEVEL_CLASS_NAME, -1, &classString);
+           class.lpszClassName = (LPCTSTR) Tcl_DStringValue(&classString);
+           class.lpfnWndProc = WmProc;
+           if (titlebaricon == NULL) {
+               class.hIcon = LoadIcon(Tk_GetHINSTANCE(), "tk");
+           } else {
+               class.hIcon = GetIcon(titlebaricon, ICON_BIG);
+               if (class.hIcon == NULL) {
+                   return TCL_ERROR;
+               }
+               /*
+                * Store pointer to default icon so we know when
+                * we need to free that information
+                */
+               tsdPtr->iconPtr = titlebaricon;
+           }
+           class.hCursor = LoadCursor(NULL, IDC_ARROW);
 
-    Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
+           if (!(*tkWinProcs->registerClass)(&class)) {
+               panic("Unable to register TkTopLevel class");
+           }
+           Tcl_DStringFree(&classString);
+       }
+       Tcl_MutexUnlock(&winWmMutex);
+    }
+    return TCL_OK;
 }
 \f
 /*
  *----------------------------------------------------------------------
  *
- * UpdateWrapper --
+ * InitWm --
  *
- *     This function creates the wrapper window that contains the
- *     window decorations and menus for a toplevel.  This function
- *     may be called after a window is mapped to change the window
- *     style.
+ *     This initialises the window manager
  *
  * Results:
  *     None.
  *
  * Side effects:
- *     Destroys any old wrapper window and replaces it with a newly
- *     created wrapper.
+ *     Registers a new window class.
  *
  *----------------------------------------------------------------------
  */
-
 static void
-UpdateWrapper(winPtr)
-    TkWindow *winPtr;          /* Top-level window to redecorate. */
+InitWm(void)
 {
-    register WmInfo *wmPtr = winPtr->wmInfoPtr;
-    HWND parentHWND = NULL, oldWrapper;
-    HWND child = TkWinGetHWND(winPtr->window);
-    int x, y, width, height, state;
-    WINDOWPLACEMENT place;
-    Tcl_DString titleString;
-    int *childStateInfo = NULL;
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
-            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+    /* Ignore return result */
+    (void) InitWindowClass(NULL);
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WinSetIcon --
+ *
+ *     Sets either the default toplevel titlebar icon, or the icon
+ *     for a specific toplevel (if tkw is given, then only that
+ *     window is used).
+ *
+ *     The ref-count of the titlebaricon is NOT changed.  If this
+ *     function returns successfully, the caller should assume
+ *     the icon was used (and therefore the ref-count should
+ *     be adjusted to reflect that fact).  If the function returned
+ *     an error, the caller should assume the icon was not used
+ *     (and may wish to free the memory associated with it).
+ *
+ * Results:
+ *     A standard Tcl return code.
+ *
+ * Side effects:
+ *     One or all windows may have their icon changed.
+ *     The Tcl result may be modified.
+ *     The window-manager will be initialised if it wasn't already.
+ *     The given window will be forced into existence.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+WinSetIcon(interp, titlebaricon, tkw)
+    Tcl_Interp *interp;
+    WinIconPtr titlebaricon;
+    Tk_Window tkw;
+{
+    WmInfo *wmPtr;
+    HWND hwnd;
+    int application = 0;
 
-    parentHWND = NULL;
-    child = TkWinGetHWND(winPtr->window);
+    if (tkw == NULL) {
+        tkw = Tk_MainWindow(interp);
+       application = 1;
+    }
 
-    if (winPtr->flags & TK_EMBEDDED) {
-       wmPtr->wrapper = (HWND) winPtr->privatePtr;
-       if (wmPtr->wrapper == NULL) {
-           panic("TkWmMapWindow: Cannot find container window");
-       }
-       if (!IsWindow(wmPtr->wrapper)) {
-           panic("TkWmMapWindow: Container was destroyed");
-       }
+    if (!(Tk_IsTopLevel(tkw))) {
+       Tcl_AppendResult(interp, "window \"", Tk_PathName(tkw),
+               "\" isn't a top-level window", (char *) NULL);
+       return TCL_ERROR;
+    }
+    if (Tk_WindowId(tkw) == None) {
+       Tk_MakeWindowExist(tkw);
+    }
+    /* We must get the window's wrapper, not the window itself */
+    wmPtr = ((TkWindow*)tkw)->wmInfoPtr;
+    hwnd = wmPtr->wrapper;
 
-    } else {
+    if (application) {
+       if (hwnd == NULL) {
+           /*
+            * I don't actually think this is ever the correct thing, unless
+            * perhaps the window doesn't have a wrapper.  But I believe all
+            * windows have wrappers.
+            */
+           hwnd = Tk_GetHWND(Tk_WindowId(tkw));
+       }
        /*
-        * Pick the decorative frame style.  Override redirect windows get
-        * created as undecorated popups.  Transient windows get a modal
-        * dialog frame.  Neither override, nor transient windows appear in
-        * the Windows taskbar.  Note that a transient window does not resize
-        * by default, so we need to explicitly add the WS_THICKFRAME style
-        * if we want it to be resizeable.
+        * If we aren't initialised, then just initialise with the user's
+        * icon.  Otherwise our icon choice will be ignored moments later
+        * when Tk finishes initialising.
         */
-
-       if (winPtr->atts.override_redirect) {
-           wmPtr->style = WM_OVERRIDE_STYLE;
-           wmPtr->exStyle = EX_OVERRIDE_STYLE;
-       } else if (wmPtr->masterPtr) {
-           wmPtr->style = WM_TRANSIENT_STYLE;
-           wmPtr->exStyle = EX_TRANSIENT_STYLE;
-           parentHWND = Tk_GetHWND(Tk_WindowId(wmPtr->masterPtr));
-           if (! ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) && 
-                   (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE))) {
-               wmPtr->style |= WS_THICKFRAME;
+       if (!initialized) {
+           if (InitWindowClass(titlebaricon) != TCL_OK) {
+               Tcl_AppendResult(interp,"Unable to set icon", (char*)NULL);
+               return TCL_ERROR;
            }
        } else {
-           wmPtr->style = WM_TOPLEVEL_STYLE;
-           wmPtr->exStyle = EX_TOPLEVEL_STYLE;
-       }
+           ThreadSpecificData *tsdPtr;
+           if (
+#ifdef _WIN64
+               !SetClassLongPtr(hwnd, GCLP_HICONSM,
+                       (LPARAM)GetIcon(titlebaricon, ICON_SMALL))
+#else
+               !SetClassLong(hwnd, GCL_HICONSM,
+                       (LPARAM)GetIcon(titlebaricon, ICON_SMALL))
+#endif
+               ) {
+               /*
+                * For some reason this triggers, even though it seems
+                * to be successful This is probably related to the
+                * WNDCLASS vs WNDCLASSEX difference.  Anyway it seems
+                * we have to ignore errors returned here.
+                */
 
-       if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE)
-               && (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
-           wmPtr->style &= ~ (WS_MAXIMIZEBOX | WS_SIZEBOX);
+               /*
+                * Tcl_AppendResult(interp,"Unable to set new small icon", (char*)NULL);
+                * return TCL_ERROR;
+                */
+           }
+           if (
+#ifdef _WIN64
+               !SetClassLongPtr(hwnd, GCLP_HICON,
+                       (LPARAM)GetIcon(titlebaricon, ICON_BIG))
+#else
+               !SetClassLong(hwnd, GCL_HICON,
+                       (LPARAM)GetIcon(titlebaricon, ICON_BIG))
+#endif
+               ) {
+               Tcl_AppendResult(interp,"Unable to set new icon", (char*)NULL);
+               return TCL_ERROR;
+           }
+           tsdPtr = (ThreadSpecificData *)
+                   Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+           if (tsdPtr->iconPtr != NULL) {
+               DecrIconRefCount(tsdPtr->iconPtr);
+           }
+           tsdPtr->iconPtr = titlebaricon;
        }
-
-       /*
-        * Compute the geometry of the parent and child windows.
-        */
-
-       wmPtr->flags |= WM_CREATE_PENDING|WM_MOVE_PENDING;
-       UpdateGeometryInfo((ClientData)winPtr);
-       wmPtr->flags &= ~(WM_CREATE_PENDING|WM_MOVE_PENDING);
-
-       width = wmPtr->borderWidth + winPtr->changes.width;
-       height = wmPtr->borderHeight + winPtr->changes.height;
-
-       /*
-        * Set the initial position from the user or program specified
-        * location.  If nothing has been specified, then let the system
-        * pick a location.
-        */
-
-       if (!(wmPtr->sizeHintsFlags & (USPosition | PPosition))
-               && (wmPtr->flags & WM_NEVER_MAPPED)) {
-           x = CW_USEDEFAULT;
-           y = CW_USEDEFAULT;
-       } else {
-           x = winPtr->changes.x;
-           y = winPtr->changes.y;
+    } else {
+       if (!initialized) {
+           /*
+            * Need to initialise the wm otherwise we will fail on
+            * code which tries to set a toplevel's icon before that
+            * happens.  Ignore return result.
+            */
+           (void)InitWindowClass(NULL);
        }
-
        /*
-        * Create the containing window, and set the user data to point
-        * to the TkWindow.
+        * The following code is exercised if you do
+        *
+        *   toplevel .t ; wm titlebaricon .t foo.icr
+        *
+        * i.e. the wm hasn't had time to properly create
+        * the '.t' window before you set the icon.
         */
-
-       tsdPtr->createWindow = winPtr;
-       Tcl_UtfToExternalDString(NULL, wmPtr->titleUid, -1, &titleString);
-       wmPtr->wrapper = CreateWindowEx(wmPtr->exStyle,
-               TK_WIN_TOPLEVEL_CLASS_NAME,
-               Tcl_DStringValue(&titleString), wmPtr->style, x, y, width, 
-               height, parentHWND, NULL, Tk_GetHINSTANCE(), NULL);
-       Tcl_DStringFree(&titleString);
-       SetWindowLong(wmPtr->wrapper, GWL_USERDATA, (LONG) winPtr);
-       tsdPtr->createWindow = NULL;
-
-       place.length = sizeof(WINDOWPLACEMENT);
-       GetWindowPlacement(wmPtr->wrapper, &place);
-       wmPtr->x = place.rcNormalPosition.left;
-       wmPtr->y = place.rcNormalPosition.top;
-
-       TkInstallFrameMenu((Tk_Window) winPtr);
-    }
-
-    /*
-     * Now we need to reparent the contained window and set its
-     * style appropriately.  Be sure to update the style first so that
-     * Windows doesn't try to set the focus to the child window.
-     */
-
-    SetWindowLong(child, GWL_STYLE,
-           WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
-    if (winPtr->flags & TK_EMBEDDED) {
-       SetWindowLong(child, GWL_WNDPROC, (LONG) TopLevelProc);
-    }
-    oldWrapper = SetParent(child, wmPtr->wrapper);
-    if (oldWrapper && (oldWrapper != wmPtr->wrapper) 
-           && (oldWrapper != GetDesktopWindow())) {
-       SetWindowLong(oldWrapper, GWL_USERDATA, (LONG) NULL);
-
-       if (wmPtr->numTransients > 0) {
+       if (hwnd == NULL) {
            /*
-            * Unset the current wrapper as the parent for all transient
-            * children for whom this is the master
+            * This little snippet is copied from the 'Map' function,
+            * and should probably be placed in one proper location
             */
-           WmInfo *wmPtr2;
-
-           childStateInfo = (int *)ckalloc((unsigned) wmPtr->numTransients
-               * sizeof(int));
-           state = 0;
-           for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
-                wmPtr2 = wmPtr2->nextPtr) {
-               if (wmPtr2->masterPtr == winPtr) {
-                   if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
-                       childStateInfo[state++] = wmPtr2->hints.initial_state;
-                       SetParent(TkWinGetHWND(wmPtr2->winPtr->window), NULL);
-                   }
-               }
+           UpdateWrapper(wmPtr->winPtr);
+           wmPtr = ((TkWindow*)tkw)->wmInfoPtr;
+           hwnd = wmPtr->wrapper;
+           if (hwnd == NULL) {
+               Tcl_AppendResult(interp,
+                       "Can't set icon; window has no wrapper.", (char*)NULL);
+               return TCL_ERROR;
            }
        }
+       SendMessage(hwnd, WM_SETICON, ICON_SMALL,
+               (LPARAM) GetIcon(titlebaricon, ICON_SMALL));
+       SendMessage(hwnd, WM_SETICON, ICON_BIG,
+               (LPARAM) GetIcon(titlebaricon, ICON_BIG));
+
+       /* Update the iconPtr we keep for each WmInfo structure. */
+       if (wmPtr->iconPtr != NULL) {
+           /* Free any old icon ptr which is associated with this window. */
+           DecrIconRefCount(wmPtr->iconPtr);
+       }
        /*
-        * Remove the menubar before destroying the window so the menubar
-        * isn't destroyed.
+        * We do not need to increment the ref count for the
+        * titlebaricon, because it was already incremented when we
+        * retrieved it.
         */
-
-       SetMenu(oldWrapper, NULL);
-       DestroyWindow(oldWrapper);
+       wmPtr->iconPtr = titlebaricon;
     }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * ReadIconFromFile --
+ *
+ *     Read the contents of a file (usually .ico, .icr) and extract an
+ *     icon resource, if possible, otherwise check if the shell has an
+ *     icon assigned to the given file and use that.  If both of those
+ *     fail, then NULL is returned, and an error message will already be
+ *     in the interpreter.
+ *     
+ * Results:
+ *     A WinIconPtr structure containing the icons in the file, with
+ *     its ref count already incremented. The calling procedure should
+ *     either place this structure inside a WmInfo structure, or it should
+ *     pass it on to DecrIconRefCount() to ensure no memory leaks occur.
+ *
+ *     If the given fileName did not contain a valid icon structure,
+ *     return NULL.
+ *
+ * Side effects:
+ *     Memory is allocated for the returned structure and the icons
+ *     it contains.  If the structure is not wanted, it should be
+ *     passed to DecrIconRefCount, and in any case a valid ref count
+ *     should be ensured to avoid memory leaks.
+ *
+ *     Currently icon resources are not shared, so the ref count of
+ *     one of these structures will always be 0 or 1.  However all we
+ *     need do is implement some sort of lookup function between
+ *     filenames and WinIconPtr structures and no other code will need
+ *     to be changed.  The pseudo-code for this is implemented below
+ *     in the 'if (0)' branch.  It did not seem necessary to implement
+ *     this optimisation here, since moving to icon<->image
+ *     conversions will probably make it obsolete.
+ *
+ *----------------------------------------------------------------------
+ */
+static WinIconPtr
+ReadIconFromFile(interp, fileName)
+    Tcl_Interp *interp;
+    Tcl_Obj *fileName;
+{
+    WinIconPtr titlebaricon = NULL;
 
-    wmPtr->flags &= ~WM_NEVER_MAPPED;
-    SendMessage(wmPtr->wrapper, TK_ATTACHWINDOW, (WPARAM) child, 0);
-
-    /*
-     * Force an initial transition from withdrawn to the real
-     * initial state.   
-     */
-
-    state = wmPtr->hints.initial_state;
-    wmPtr->hints.initial_state = WithdrawnState;
-    TkpWmSetState(winPtr, state);
-
-    /*
-     * If we are embedded then force a mapping of the window now,
-     * because we do not necessarily own the wrapper and may not
-     * get another opportunity to map ourselves. We should not be
-     * in either iconified or zoomed states when we get here, so
-     * it is safe to just check for TK_EMBEDDED without checking
-     * what state we are supposed to be in (default to NormalState).
-     */
-
-    if (winPtr->flags & TK_EMBEDDED) {
-       XMapWindow(winPtr->display, winPtr->window);
-    }
-
-    /*
-     * Set up menus on the wrapper if required.
-     */
-        
-    if (wmPtr->hMenu != NULL) {
-       wmPtr->flags = WM_SYNC_PENDING;
-       SetMenu(wmPtr->wrapper, wmPtr->hMenu);
-       wmPtr->flags &= ~WM_SYNC_PENDING;
-    }
-
-    if (childStateInfo) {
-       if (wmPtr->numTransients > 0) {
-           /*
-            * Reset all transient children for whom this is the master
-            */
-           WmInfo *wmPtr2;
-
-           state = 0;
-           for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
-                wmPtr2 = wmPtr2->nextPtr) {
-               if (wmPtr2->masterPtr == winPtr) {
-                   if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
-                       UpdateWrapper(wmPtr2->winPtr);
-                       TkpWmSetState(wmPtr2->winPtr, childStateInfo[state++]);
-                   }
+    if (0 /* If we already have an icon for this filename */) {
+       titlebaricon = NULL; /* Get the real value from a lookup */
+       titlebaricon->refCount++;
+       return titlebaricon;
+    } else {
+       /* First check if it is a .ico file */
+       BlockOfIconImagesPtr lpIR;
+       lpIR = ReadIconOrCursorFromFile(interp, fileName, TRUE);
+       
+       /* Then see if we can ask the shell for the icon for this file */
+       if (lpIR == NULL && shgetfileinfoProc != NULL) {
+           SHFILEINFO sfi;
+           Tcl_DString ds, ds2;
+           DWORD *res;
+           CONST char *file;
+           
+           file = Tcl_TranslateFileName(interp, Tcl_GetString(fileName), &ds);
+           if (file == NULL) { return NULL; }
+           Tcl_UtfToExternalDString(NULL, file, -1, &ds2);
+           Tcl_DStringFree(&ds);
+           
+           res = (*shgetfileinfoProc)(Tcl_DStringValue(&ds2), 0, &sfi, 
+                         sizeof(SHFILEINFO), SHGFI_SMALLICON|SHGFI_ICON);
+          
+           Tcl_DStringFree(&ds2);
+           
+           if (res != 0) {
+               Tcl_ResetResult(interp);
+                             
+               lpIR = (BlockOfIconImagesPtr) ckalloc(sizeof(BlockOfIconImages));
+               if (lpIR == NULL) {
+                   DestroyIcon(sfi.hIcon);
+                   return NULL;
                }
+           
+               lpIR->nNumImages = 1;
+               lpIR->IconImages[0].Width = 16;
+               lpIR->IconImages[0].Height = 16;
+               lpIR->IconImages[0].Colors = 4;
+               lpIR->IconImages[0].hIcon = sfi.hIcon;
+               /* These fields are ignored */
+               lpIR->IconImages[0].lpBits = 0;
+               lpIR->IconImages[0].dwNumBytes = 0;
+               lpIR->IconImages[0].lpXOR = 0;
+               lpIR->IconImages[0].lpAND = 0;
            }
        }
-
-       ckfree((char *) childStateInfo);
-    }
-
-    /*
-     * If this is the first window created by the application, then
-     * we should activate the initial window.
-     */
-
-    if (tsdPtr->firstWindow) {
-       tsdPtr->firstWindow = 0;
-       SetActiveWindow(wmPtr->wrapper);
+       if (lpIR != NULL) {
+           titlebaricon = (WinIconPtr) ckalloc(sizeof(WinIconInstance));
+           titlebaricon->iconBlock = lpIR;
+           titlebaricon->refCount = 1;
+       }
+       return titlebaricon;
     }
 }
 \f
 /*
- *--------------------------------------------------------------
+ *----------------------------------------------------------------------
  *
- * TkWmMapWindow --
+ * GetIconFromPixmap --
  *
- *     This procedure is invoked to map a top-level window.  This
- *     module gets a chance to update all window-manager-related
- *     information in properties before the window manager sees
- *     the map event and checks the properties.  It also gets to
- *     decide whether or not to even map the window after all.
+ *     Turn a Tk Pixmap (i.e. a bitmap) into an icon resource, if
+ *     possible, otherwise NULL is returned.
  *
  * Results:
- *     None.
+ *     A WinIconPtr structure containing a conversion of the given
+ *     bitmap into an icon, with its ref count already incremented.  The
+ *     calling procedure should either place this structure inside a
+ *     WmInfo structure, or it should pass it on to DecrIconRefCount()
+ *     to ensure no memory leaks occur.
+ *     
+ *     If the given pixmap did not contain a valid icon structure,
+ *     return NULL.
  *
  * Side effects:
- *     Properties of winPtr may get updated to provide up-to-date
- *     information to the window manager.  The window may also get
- *     mapped, but it may not be if this procedure decides that
- *     isn't appropriate (e.g. because the window is withdrawn).
+ *     Memory is allocated for the returned structure and the icons
+ *     it contains.  If the structure is not wanted, it should be
+ *     passed to DecrIconRefCount, and in any case a valid ref count
+ *     should be ensured to avoid memory leaks.
+ *     
+ *     Currently icon resources are not shared, so the ref count of
+ *     one of these structures will always be 0 or 1.  However all we
+ *     need do is implement some sort of lookup function between
+ *     pixmaps and WinIconPtr structures and no other code will need
+ *     to be changed.
  *
- *--------------------------------------------------------------
+ *----------------------------------------------------------------------
  */
-
-void
-TkWmMapWindow(winPtr)
-    TkWindow *winPtr;          /* Top-level window that's about to
-                                * be mapped. */
+static WinIconPtr       
+GetIconFromPixmap(dsPtr, pixmap)
+    Display *dsPtr;
+    Pixmap pixmap;
 {
-    register WmInfo *wmPtr = winPtr->wmInfoPtr;
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
-            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-
-    if (!tsdPtr->initialized) {
-       InitWm();
+    WinIconPtr titlebaricon = NULL;
+    TkWinDrawable* twdPtr = (TkWinDrawable*) pixmap;
+    
+    if (twdPtr == NULL) {
+        return NULL;
     }
+    
+    if (0 /* If we already have an icon for this pixmap */) {
+       titlebaricon = NULL; /* Get the real value from a lookup */
+       titlebaricon->refCount++;
+       return titlebaricon;
+    } else {
+       BlockOfIconImagesPtr lpIR;
+       ICONINFO icon;
+       HICON hIcon;
+       int width, height;
 
-    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
-       if (wmPtr->hints.initial_state == WithdrawnState) {
-           return;
-       }
-
-       /*
-        * Map the window in either the iconified or normal state.  Note that
-        * we only send a map event if the window is in the normal state.
-        */
-
-       TkpWmSetState(winPtr, wmPtr->hints.initial_state);
-    }
+       Tk_SizeOfBitmap(dsPtr, pixmap, &width, &height);
+    
+       icon.fIcon = TRUE;
+       icon.xHotspot = 0;
+       icon.yHotspot = 0;
+       icon.hbmMask = twdPtr->bitmap.handle;
+       icon.hbmColor = twdPtr->bitmap.handle;
 
-    /*
-     * This is the first time this window has ever been mapped.
-     * Store all the window-manager-related information for the
-     * window.
-     */
+       hIcon = CreateIconIndirect(&icon);
+       if (hIcon == NULL) {
+           return NULL;
+       }
 
-    if (wmPtr->titleUid == NULL) {
-       wmPtr->titleUid = winPtr->nameUid;
+       lpIR = (BlockOfIconImagesPtr) ckalloc(sizeof(BlockOfIconImages));
+       if (lpIR == NULL) {
+           DestroyIcon(hIcon);
+           return NULL;
+       }
+       
+       lpIR->nNumImages = 1;
+       lpIR->IconImages[0].Width = width;
+       lpIR->IconImages[0].Height = height;
+       lpIR->IconImages[0].Colors = 1 << twdPtr->bitmap.depth;
+       lpIR->IconImages[0].hIcon = hIcon;
+       /* These fields are ignored */
+       lpIR->IconImages[0].lpBits = 0;
+       lpIR->IconImages[0].dwNumBytes = 0;
+       lpIR->IconImages[0].lpXOR = 0;
+       lpIR->IconImages[0].lpAND = 0;
+       
+       titlebaricon = (WinIconPtr) ckalloc(sizeof(WinIconInstance));
+       titlebaricon->iconBlock = lpIR;
+       titlebaricon->refCount = 1;
+       return titlebaricon;
     }
-    UpdateWrapper(winPtr);
 }
 \f
 /*
- *--------------------------------------------------------------
+ *----------------------------------------------------------------------
  *
- * TkWmUnmapWindow --
+ * DecrIconRefCount --
  *
- *     This procedure is invoked to unmap a top-level window.  The
- *     only thing it does special is unmap the decorative frame before
- *     unmapping the toplevel window.
+ *     Reduces the reference count.
  *
  * Results:
  *     None.
  *
  * Side effects:
- *     Unmaps the decorative frame and the window.
+ *     If the ref count falls to zero, free the memory associated
+ *     with the icon resource structures.  In this case the pointer
+ *     passed into this function is no longer valid.
  *
- *--------------------------------------------------------------
+ *----------------------------------------------------------------------
  */
+static void 
+DecrIconRefCount(WinIconPtr titlebaricon) {
+    titlebaricon->refCount--;
 
-void
-TkWmUnmapWindow(winPtr)
-    TkWindow *winPtr;          /* Top-level window that's about to
-                                * be unmapped. */
-{
-    TkpWmSetState(winPtr, WithdrawnState);
+    if (titlebaricon->refCount <= 0) {
+       if (titlebaricon->iconBlock != NULL) {
+           FreeIconBlock(titlebaricon->iconBlock);
+       }
+       titlebaricon->iconBlock = NULL;
+
+       ckfree((char*)titlebaricon);
+    }
 }
 \f
 /*
  *----------------------------------------------------------------------
  *
- * TkpWmSetState --
+ * FreeIconBlock --
  *
- *     Sets the window manager state for the wrapper window of a
- *     given toplevel window.
+ *     Frees all memory associated with a previously loaded
+ *     titlebaricon.  The icon block pointer is no longer
+ *     valid once this function returns.
  *
  * Results:
  *     None.
  *
  * Side effects:
- *     May maximize, minimize, restore, or withdraw a window.
+ *
  *
  *----------------------------------------------------------------------
  */
+static void 
+FreeIconBlock(BlockOfIconImagesPtr lpIR) {
+    int i;
 
-void
-TkpWmSetState(winPtr, state)
-     TkWindow *winPtr;         /* Toplevel window to operate on. */
-     int state;                        /* One of IconicState, ZoomState, NormalState,
-                                * or WithdrawnState. */
-{
-    WmInfo *wmPtr = winPtr->wmInfoPtr;
-    int cmd;
-
-    if ((wmPtr->flags & WM_NEVER_MAPPED) ||
-           (wmPtr->masterPtr && !Tk_IsMapped(wmPtr->masterPtr))) {
-       wmPtr->hints.initial_state = state;
-       return;
-    }
-
-    wmPtr->flags |= WM_SYNC_PENDING;
-    if (state == WithdrawnState) {
-       cmd = SW_HIDE;
-    } else if (state == IconicState) {
-       cmd = SW_SHOWMINNOACTIVE;
-    } else if (state == NormalState) {
-       cmd = SW_SHOWNOACTIVATE;
-    } else if (state == ZoomState) {
-       cmd = SW_SHOWMAXIMIZED;
+    /* Free all the bits */
+    for (i=0; i< lpIR->nNumImages; i++) {
+       if (lpIR->IconImages[i].lpBits != NULL) {
+           ckfree((char*)lpIR->IconImages[i].lpBits);
+       }
+       if (lpIR->IconImages[i].hIcon != NULL) {
+           DestroyIcon(lpIR->IconImages[i].hIcon);
+       }
     }
-
-    ShowWindow(wmPtr->wrapper, cmd);
-    wmPtr->flags &= ~WM_SYNC_PENDING;
+    ckfree ((char*)lpIR);
 }
 \f
 /*
- *--------------------------------------------------------------
+ *----------------------------------------------------------------------
  *
- * TkWmDeadWindow --
+ * GetIcon --
  *
- *     This procedure is invoked when a top-level window is
- *     about to be deleted.  It cleans up the wm-related data
- *     structures for the window.
+ *     Extracts an icon of a given size from an icon resource
  *
  * Results:
- *     None.
+ *     Returns the icon, if found, else NULL.
  *
  * Side effects:
- *     The WmInfo structure for winPtr gets freed up.
  *
- *--------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------
  */
-
-void
-TkWmDeadWindow(winPtr)
-    TkWindow *winPtr;          /* Top-level window that's being deleted. */
-{
-    register WmInfo *wmPtr = winPtr->wmInfoPtr;
-    WmInfo *wmPtr2;
-
-    if (wmPtr == NULL) {
-       return;
+static HICON 
+GetIcon(WinIconPtr titlebaricon, int icon_size) {
+    BlockOfIconImagesPtr lpIR;
+    
+    if (titlebaricon == NULL) {
+        return NULL;
     }
 
-    /*
-     * Clean up event related window info.
-     */
-
-    if (winPtr->dispPtr->firstWmPtr == wmPtr) {
-       winPtr->dispPtr->firstWmPtr = wmPtr->nextPtr;
+    lpIR = titlebaricon->iconBlock;
+    if (lpIR == NULL) {
+       return NULL;
     } else {
-       register WmInfo *prevPtr;
-       for (prevPtr = winPtr->dispPtr->firstWmPtr; ;
-            prevPtr = prevPtr->nextPtr) {
-           if (prevPtr == NULL) {
-               panic("couldn't unlink window in TkWmDeadWindow");
-           }
-           if (prevPtr->nextPtr == wmPtr) {
-               prevPtr->nextPtr = wmPtr->nextPtr;
-               break;
+       unsigned int size = (icon_size == 0 ? 16 : 32);
+       int i;
+
+       for (i = 0; i < lpIR->nNumImages; i++) {
+           /* Take the first or a 32x32 16 color icon*/
+           if ((lpIR->IconImages[i].Height == size)
+              && (lpIR->IconImages[i].Width == size)
+              && (lpIR->IconImages[i].Colors >= 4)) {
+               return lpIR->IconImages[i].hIcon;
            }
        }
-    }
-
-    /*
-     * Reset all transient windows whose master is the dead window.
-     */
 
-    for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
-        wmPtr2 = wmPtr2->nextPtr) {
-       if (wmPtr2->masterPtr == winPtr) {
-           wmPtr2->masterPtr = NULL;
-           if ((wmPtr2->wrapper != None)
-                   && !(wmPtr2->flags & (WM_NEVER_MAPPED))) {
-               UpdateWrapper(wmPtr2->winPtr);
-           }
+       /* 
+        * If we get here, then just return the first one, 
+        * it will have to do!
+        */
+       if (lpIR->nNumImages >= 1) {
+           return lpIR->IconImages[0].hIcon;
        }
     }
+    return NULL;
+}
+\f
+static HCURSOR 
+TclWinReadCursorFromFile(Tcl_Interp* interp, Tcl_Obj* fileName) {
+    BlockOfIconImagesPtr lpIR;
+    HICON res = NULL;
     
-    if (wmPtr->hints.flags & IconPixmapHint) {
-       Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
+    lpIR = ReadIconOrCursorFromFile(interp, fileName, FALSE);
+    if (lpIR == NULL) {
+        return NULL;
     }
-    if (wmPtr->hints.flags & IconMaskHint) {
-       Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
+    if (lpIR->nNumImages >= 1) {
+       res = CopyImage(lpIR->IconImages[0].hIcon, IMAGE_CURSOR,0,0,0);
     }
-    if (wmPtr->leaderName != NULL) {
-       ckfree(wmPtr->leaderName);
+    FreeIconBlock(lpIR);
+    return res;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * ReadIconOrCursorFromFile --
+ *
+ *     Reads an Icon Resource from an ICO file, as given by
+ *     char* fileName - Name of the ICO file. This name should
+ *     be in Utf format.
+ *
+ * Results:
+ *     Returns an icon resource, if found, else NULL.
+ *
+ * Side effects:
+ *      May leave error messages in the Tcl interpreter.
+ *
+ *----------------------------------------------------------------------
+ */
+static BlockOfIconImagesPtr 
+ReadIconOrCursorFromFile(Tcl_Interp* interp, Tcl_Obj* fileName, BOOL isIcon) {
+    BlockOfIconImagesPtr lpIR, lpNew;
+    Tcl_Channel          channel;
+    int                  i;
+    DWORD               dwBytesRead;
+    LPICONDIRENTRY      lpIDE;
+
+    /*  Open the file */
+    channel = Tcl_FSOpenFileChannel(interp, fileName, "r", 0);
+    if (channel == NULL) {
+       Tcl_AppendResult(interp,"Error opening file \"", 
+                        Tcl_GetString(fileName), 
+                        "\" for reading",(char*)NULL);
+       return NULL;
     }
-    if (wmPtr->icon != NULL) {
-       wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
-       wmPtr2->iconFor = NULL;
+    if (Tcl_SetChannelOption(interp, channel, "-translation", "binary")
+           != TCL_OK) {
+       Tcl_Close(NULL, channel);
+       return NULL;
     }
-    if (wmPtr->iconFor != NULL) {
-       wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
-       wmPtr2->icon = NULL;
-       wmPtr2->hints.flags &= ~IconWindowHint;
+    if (Tcl_SetChannelOption(interp, channel, "-encoding", "binary")
+           != TCL_OK) {
+       Tcl_Close(NULL, channel);
+       return NULL;
     }
-    while (wmPtr->protPtr != NULL) {
-       ProtocolHandler *protPtr;
-
-       protPtr = wmPtr->protPtr;
-       wmPtr->protPtr = protPtr->nextPtr;
-       Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
+    /*  Allocate memory for the resource structure */
+    lpIR = (BlockOfIconImagesPtr) ckalloc(sizeof(BlockOfIconImages));
+    if (lpIR == NULL)    {
+       Tcl_AppendResult(interp,"Error allocating memory",(char*)NULL);
+       Tcl_Close(NULL, channel);
+       return NULL;
     }
-    if (wmPtr->cmdArgv != NULL) {
-       ckfree((char *) wmPtr->cmdArgv);
+    /*  Read in the header */
+    if ((lpIR->nNumImages = ReadICOHeader( channel )) == -1)    {
+       Tcl_AppendResult(interp,"Invalid file header",(char*)NULL);
+       Tcl_Close(NULL, channel);
+       ckfree((char*) lpIR );
+       return NULL;
     }
-    if (wmPtr->clientMachine != NULL) {
-       ckfree((char *) wmPtr->clientMachine);
+    /*  Adjust the size of the struct to account for the images */
+    lpNew = (BlockOfIconImagesPtr) ckrealloc((char*)lpIR, 
+       sizeof(BlockOfIconImages) + ((lpIR->nNumImages-1) * sizeof(ICONIMAGE)));
+    if (lpNew == NULL) {
+       Tcl_AppendResult(interp,"Error allocating memory",(char*)NULL);
+       Tcl_Close(NULL, channel);
+       ckfree( (char*)lpIR );
+       return NULL;
     }
-    if (wmPtr->flags & WM_UPDATE_PENDING) {
-       Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
+    lpIR = lpNew;
+    /*  Allocate enough memory for the icon directory entries */
+    lpIDE = (LPICONDIRENTRY) ckalloc(lpIR->nNumImages * sizeof(ICONDIRENTRY));
+    if (lpIDE == NULL) {
+       Tcl_AppendResult(interp,"Error allocating memory",(char*)NULL);
+       Tcl_Close(NULL, channel);
+       ckfree( (char*)lpIR );
+       return NULL;
     }
-    if (wmPtr->masterPtr != NULL) {
-       wmPtr2 = wmPtr->masterPtr->wmInfoPtr;
-       /*
-        * If we had a master, tell them that we aren't tied
-        * to them anymore
-        */
-       if (wmPtr2 != NULL) {
-           wmPtr2->numTransients--;
-       }
-       Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
-               VisibilityChangeMask,
-               WmWaitVisibilityProc, (ClientData) winPtr);
-       wmPtr->masterPtr = NULL;
+    /*  Read in the icon directory entries */
+    dwBytesRead = Tcl_Read(channel, (char*)lpIDE, 
+                          lpIR->nNumImages * sizeof( ICONDIRENTRY ));
+    if (dwBytesRead != lpIR->nNumImages * sizeof( ICONDIRENTRY ))    {
+       Tcl_AppendResult(interp,"Error reading file",(char*)NULL);
+       Tcl_Close(NULL, channel);
+       ckfree( (char*)lpIR );
+       return NULL;
     }
-
-    /*
-     * Destroy the decorative frame window.
-     */
-
-    if (!(winPtr->flags & TK_EMBEDDED)) {
-       if (wmPtr->wrapper != NULL) {
-           DestroyWindow(wmPtr->wrapper);
-       } else {
-           DestroyWindow(Tk_GetHWND(winPtr->window));
-       }
+    /*  Loop through and read in each image */
+    for( i = 0; i < lpIR->nNumImages; i++ )    {
+       /*  Allocate memory for the resource */
+       lpIR->IconImages[i].lpBits = (LPBYTE) ckalloc(lpIDE[i].dwBytesInRes);
+       if (lpIR->IconImages[i].lpBits == NULL) {
+           Tcl_AppendResult(interp,"Error allocating memory",(char*)NULL);
+           Tcl_Close(NULL, channel);
+           ckfree( (char*)lpIR );
+           ckfree( (char*)lpIDE );
+           return NULL;
+       }
+       lpIR->IconImages[i].dwNumBytes = lpIDE[i].dwBytesInRes;
+       /*  Seek to beginning of this image */
+       if (Tcl_Seek(channel, lpIDE[i].dwImageOffset, FILE_BEGIN) == -1) {
+           Tcl_AppendResult(interp,"Error seeking in file",(char*)NULL);
+           Tcl_Close(NULL, channel);
+           ckfree( (char*)lpIR );
+           ckfree( (char*)lpIDE );
+           return NULL;
+       }
+       /*  Read it in */
+       dwBytesRead = Tcl_Read( channel, lpIR->IconImages[i].lpBits, 
+                              lpIDE[i].dwBytesInRes);
+       if (dwBytesRead != lpIDE[i].dwBytesInRes) {
+           Tcl_AppendResult(interp,"Error reading file",(char*)NULL);
+           Tcl_Close(NULL, channel);
+           ckfree( (char*)lpIDE );
+           ckfree( (char*)lpIR );
+           return NULL;
+       }
+       /*  Set the internal pointers appropriately */
+       if (!AdjustIconImagePointers( &(lpIR->IconImages[i]))) {
+           Tcl_AppendResult(interp,"Error converting to internal format",
+                            (char*)NULL);
+           Tcl_Close(NULL, channel);
+           ckfree( (char*)lpIDE );
+           ckfree( (char*)lpIR );
+           return NULL;
+       }
+       lpIR->IconImages[i].hIcon =
+           MakeIconOrCursorFromResource(&(lpIR->IconImages[i]), isIcon);
     }
-    ckfree((char *) wmPtr);
-    winPtr->wmInfoPtr = NULL;
+    /*  Clean up */
+    ckfree((char*)lpIDE);
+    Tcl_Close(NULL, channel);
+    if (lpIR == NULL){
+       Tcl_AppendResult(interp,"Reading of ", Tcl_GetString(fileName),
+       " failed!",(char*)NULL);
+       return NULL;
+    }
+    return lpIR;
 }
 \f
 /*
- *--------------------------------------------------------------
+ *----------------------------------------------------------------------
  *
- * TkWmSetClass --
+ * GetTopLevel --
  *
- *     This procedure is invoked whenever a top-level window's
- *     class is changed.  If the window has been mapped then this
- *     procedure updates the window manager property for the
- *     class.  If the window hasn't been mapped, the update is
- *     deferred until just before the first mapping.
+ *     This function retrieves the TkWindow associated with the
+ *     given HWND.
  *
  * Results:
- *     None.
+ *     Returns the matching TkWindow.
  *
  * Side effects:
- *     A window property may get updated.
+ *     None.
  *
- *--------------------------------------------------------------
+ *----------------------------------------------------------------------
  */
-
-void
-TkWmSetClass(winPtr)
-    TkWindow *winPtr;          /* Newly-created top-level window. */
+static TkWindow *
+GetTopLevel(hwnd)
+    HWND hwnd;
 {
-    return;
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+    /*
+     * If this function is called before the CreateWindowEx call
+     * has completed, then the user data slot will not have been
+     * set yet, so we use the global createWindow variable.
+     */
+
+    if (tsdPtr->createWindow) {
+       return tsdPtr->createWindow;
+    }
+#ifdef _WIN64
+    return (TkWindow *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
+#else
+    return (TkWindow *) GetWindowLong(hwnd, GWL_USERDATA);
+#endif
 }
 \f
 /*
  *----------------------------------------------------------------------
  *
- * Tk_WmCmd --
+ * SetLimits --
  *
- *     This procedure is invoked to process the "wm" Tcl command.
- *     See the user documentation for details on what it does.
+ *     Updates the minimum and maximum window size constraints.
  *
  * Results:
- *     A standard Tcl result.
+ *     None.
  *
  * Side effects:
- *     See the user documentation.
+ *     Changes the values of the info pointer to reflect the current
+ *     minimum and maximum size values.
  *
  *----------------------------------------------------------------------
  */
 
-       /* ARGSUSED */
-int
-Tk_WmCmd(clientData, interp, argc, argv)
-    ClientData clientData;     /* Main window associated with
-                                * interpreter. */
-    Tcl_Interp *interp;                /* Current interpreter. */
-    int argc;                  /* Number of arguments. */
-    char **argv;               /* Argument strings. */
+static void
+SetLimits(hwnd, info)
+    HWND hwnd;
+    MINMAXINFO *info;
 {
-    Tk_Window tkwin = (Tk_Window) clientData;
-    TkWindow *winPtr = NULL;
     register WmInfo *wmPtr;
-    int c;
-    size_t length;
-    TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
-
-    if (argc < 2) {
-       wrongNumArgs:
-       Tcl_AppendResult(interp, "wrong # args: should be \"",
-               argv[0], " option window ?arg ...?\"", (char *) NULL);
-       return TCL_ERROR;
-    }
-    c = argv[1][0];
-    length = strlen(argv[1]);
-    if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0)
-           && (length >= 3)) {
-       if ((argc != 2) && (argc != 3)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " tracing ?boolean?\"", (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (argc == 2) {
-           Tcl_SetResult(interp, ((dispPtr->wmTracing) ? "on" : "off"),
-                   TCL_STATIC);
-           return TCL_OK;
-       }
-       return Tcl_GetBoolean(interp, argv[2], &dispPtr->wmTracing);
-    }
+    int maxWidth, maxHeight;
+    int minWidth, minHeight;
+    int base;
+    TkWindow *winPtr = GetTopLevel(hwnd);
 
-    if (argc < 3) {
-       goto wrongNumArgs;
-    }
-    winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
     if (winPtr == NULL) {
-       return TCL_ERROR;
-    }
-    if (!(winPtr->flags & TK_TOP_LEVEL)) {
-       Tcl_AppendResult(interp, "window \"", winPtr->pathName,
-               "\" isn't a top-level window", (char *) NULL);
-       return TCL_ERROR;
+       return;
     }
+
     wmPtr = winPtr->wmInfoPtr;
-    if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
-       int numer1, denom1, numer2, denom2;
 
-       if ((argc != 3) && (argc != 7)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " aspect window ?minNumer minDenom ",
-                   "maxNumer maxDenom?\"", (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (argc == 3) {
-           if (wmPtr->sizeHintsFlags & PAspect) {
-               char buf[TCL_INTEGER_SPACE * 4];
-               
-               sprintf(buf, "%d %d %d %d", wmPtr->minAspect.x,
-                       wmPtr->minAspect.y, wmPtr->maxAspect.x,
-                       wmPtr->maxAspect.y);
-               Tcl_SetResult(interp, buf, TCL_VOLATILE);
-           }
-           return TCL_OK;
-       }
-       if (*argv[3] == '\0') {
-           wmPtr->sizeHintsFlags &= ~PAspect;
-       } else {
-           if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
-                   || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
-                   || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
-                   || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
-               return TCL_ERROR;
-           }
-           if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
-                   (denom2 <= 0)) {
-               Tcl_SetResult(interp, "aspect number can't be <= 0",
-                       TCL_STATIC);
-               return TCL_ERROR;
-           }
-           wmPtr->minAspect.x = numer1;
-           wmPtr->minAspect.y = denom1;
-           wmPtr->maxAspect.x = numer2;
-           wmPtr->maxAspect.y = denom2;
-           wmPtr->sizeHintsFlags |= PAspect;
-       }
-       goto updateGeom;
-    } else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0)
-           && (length >= 2)) {
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " client window ?name?\"",
-                   (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (argc == 3) {
-           if (wmPtr->clientMachine != NULL) {
-               Tcl_SetResult(interp, wmPtr->clientMachine, TCL_STATIC);
-           }
-           return TCL_OK;
-       }
-       if (argv[3][0] == 0) {
-           if (wmPtr->clientMachine != NULL) {
-               ckfree((char *) wmPtr->clientMachine);
-               wmPtr->clientMachine = NULL;
-               if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
-                   XDeleteProperty(winPtr->display, winPtr->window,
-                           Tk_InternAtom((Tk_Window) winPtr,
-                           "WM_CLIENT_MACHINE"));
-               }
-           }
-           return TCL_OK;
-       }
-       if (wmPtr->clientMachine != NULL) {
-           ckfree((char *) wmPtr->clientMachine);
-       }
-       wmPtr->clientMachine = (char *)
-               ckalloc((unsigned) (strlen(argv[3]) + 1));
-       strcpy(wmPtr->clientMachine, argv[3]);
-       if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
-           XTextProperty textProp;
-           if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
-                   != 0) {
-               XSetWMClientMachine(winPtr->display, winPtr->window,
-                       &textProp);
-               XFree((char *) textProp.value);
-           }
-       }
-    } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0)
-           && (length >= 3)) {
-       TkWindow **cmapList;
-       TkWindow *winPtr2;
-       int i, windowArgc, gotToplevel;
-       char **windowArgv;
+    /*
+     * Copy latest constraint info.
+     */
 
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " colormapwindows window ?windowList?\"",
-                   (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (argc == 3) {
-           Tk_MakeWindowExist((Tk_Window) winPtr);
-           for (i = 0; i < wmPtr->cmapCount; i++) {
-               if ((i == (wmPtr->cmapCount-1))
-                       && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
-                   break;
-               }
-               Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
-           }
-           return TCL_OK;
-       }
-       if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv)
-               != TCL_OK) {
-           return TCL_ERROR;
-       }
-       cmapList = (TkWindow **) ckalloc((unsigned)
-               ((windowArgc+1)*sizeof(TkWindow*)));
-       for (i = 0; i < windowArgc; i++) {
-           winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i],
-                   tkwin);
-           if (winPtr2 == NULL) {
-               ckfree((char *) cmapList);
-               ckfree((char *) windowArgv);
-               return TCL_ERROR;
-           }
-           if (winPtr2 == winPtr) {
-               gotToplevel = 1;
-           }
-           if (winPtr2->window == None) {
-               Tk_MakeWindowExist((Tk_Window) winPtr2);
-           }
-           cmapList[i] = winPtr2;
-       }
-       if (!gotToplevel) {
-           wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
-           cmapList[windowArgc] = winPtr;
-           windowArgc++;
-       } else {
-           wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
-       }
-       wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
-       if (wmPtr->cmapList != NULL) {
-           ckfree((char *)wmPtr->cmapList);
-       }
-       wmPtr->cmapList = cmapList;
-       wmPtr->cmapCount = windowArgc;
-       ckfree((char *) windowArgv);
+    wmPtr->defMinWidth = info->ptMinTrackSize.x;
+    wmPtr->defMinHeight = info->ptMinTrackSize.y;
+    wmPtr->defMaxWidth = info->ptMaxTrackSize.x;
+    wmPtr->defMaxHeight = info->ptMaxTrackSize.y;
 
-       /*
-        * Now we need to force the updated colormaps to be installed.
-        */
+    GetMaxSize(wmPtr, &maxWidth, &maxHeight);
+    GetMinSize(wmPtr, &minWidth, &minHeight);
 
-       if (wmPtr == winPtr->dispPtr->foregroundWmPtr) {
-           InstallColormaps(wmPtr->wrapper, WM_QUERYNEWPALETTE, 1);
-       } else {
-           InstallColormaps(wmPtr->wrapper, WM_PALETTECHANGED, 0);
+    if (wmPtr->gridWin != NULL) {
+       base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
+       if (base < 0) {
+           base = 0;
        }
-       return TCL_OK;
-    } else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0)
-           && (length >= 3)) {
-       int cmdArgc;
-       char **cmdArgv;
+       base += wmPtr->borderWidth;
+       info->ptMinTrackSize.x = base + (minWidth * wmPtr->widthInc);
+       info->ptMaxTrackSize.x = base + (maxWidth * wmPtr->widthInc);
 
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " command window ?value?\"",
-                   (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (argc == 3) {
-           if (wmPtr->cmdArgv != NULL) {
-               Tcl_SetResult(interp,
-                       Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv),
-                       TCL_DYNAMIC);
-           }
-           return TCL_OK;
-       }
-       if (argv[3][0] == 0) {
-           if (wmPtr->cmdArgv != NULL) {
-               ckfree((char *) wmPtr->cmdArgv);
-               wmPtr->cmdArgv = NULL;
-               if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
-                   XDeleteProperty(winPtr->display, winPtr->window,
-                           Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND"));
-               }
-           }
-           return TCL_OK;
-       }
-       if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       if (wmPtr->cmdArgv != NULL) {
-           ckfree((char *) wmPtr->cmdArgv);
-       }
-       wmPtr->cmdArgc = cmdArgc;
-       wmPtr->cmdArgv = cmdArgv;
-       if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
-           XSetCommand(winPtr->display, winPtr->window, cmdArgv, cmdArgc);
-       }
-    } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
-       if (argc != 3) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " deiconify window\"", (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (wmPtr->iconFor != NULL) {
-           Tcl_AppendResult(interp, "can't deiconify ", argv[2],
-                   ": it is an icon for ", winPtr->pathName, (char *) NULL);
-           return TCL_ERROR;
-       }
-        if (winPtr->flags & TK_EMBEDDED) {
-            Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName,
-                    ": it is an embedded window", (char *) NULL);
-            return TCL_ERROR;
-        }
-       /*
-        * If WM_UPDATE_PENDING is true, a pending UpdateGeometryInfo may
-        * need to be called first to update a withdrawn toplevel's geometry
-        * before it is deiconified by TkpWmSetState.
-        * Don't bother if we've never been mapped.
-        */
-       if ((wmPtr->flags & WM_UPDATE_PENDING) &&
-               !(wmPtr->flags & WM_NEVER_MAPPED)) {
-           Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
-           UpdateGeometryInfo((ClientData) winPtr);
+       base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
+       if (base < 0) {
+           base = 0;
        }
+       base += wmPtr->borderHeight;
+       info->ptMinTrackSize.y = base + (minHeight * wmPtr->heightInc);
+       info->ptMaxTrackSize.y = base + (maxHeight * wmPtr->heightInc);
+    } else {
+       info->ptMaxTrackSize.x = maxWidth + wmPtr->borderWidth;
+       info->ptMaxTrackSize.y = maxHeight + wmPtr->borderHeight;
+       info->ptMinTrackSize.x = minWidth + wmPtr->borderWidth;
+       info->ptMinTrackSize.y = minHeight + wmPtr->borderHeight;
+    }
 
-       /*
-        * If we were in the ZoomState (maximized), 'wm deiconify'
-        * should not cause the window to shrink
-        */
-       if (wmPtr->hints.initial_state == ZoomState) {
-           TkpWmSetState(winPtr, ZoomState);
-       } else {
-           TkpWmSetState(winPtr, NormalState);
-       }
+    /*
+     * If the window isn't supposed to be resizable, then set the
+     * minimum and maximum dimensions to be the same as the current size.
+     */
 
-       /*
-        * An unmapped window will be mapped at idle time
-        * by a call to MapFrame. That calls CreateWrapper
-        * which sets the focus and raises the window.
+    if (!(wmPtr->flags & WM_SYNC_PENDING)) {
+       if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
+           info->ptMinTrackSize.x = winPtr->changes.width
+               + wmPtr->borderWidth;
+           info->ptMaxTrackSize.x = info->ptMinTrackSize.x;
+       }
+       if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
+           info->ptMinTrackSize.y = winPtr->changes.height
+               + wmPtr->borderHeight;
+           info->ptMaxTrackSize.y = info->ptMinTrackSize.y;
+       }
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkWinWmCleanup --
+ *
+ *     Unregisters classes registered by the window manager. This is
+ *     called from the DLL main entry point when the DLL is unloaded.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     The window classes are discarded.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkWinWmCleanup(hInstance)
+    HINSTANCE hInstance;
+{
+    ThreadSpecificData *tsdPtr;
+
+    /*
+     * If we're using stubs to access the Tcl library, and they
+     * haven't been initialized, we can't call Tcl_GetThreadData.
+     */
+
+#ifdef USE_TCL_STUBS
+    if (tclStubsPtr == NULL) {
+        return;
+    }
+#endif
+
+    tsdPtr = (ThreadSpecificData *)
+            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+    if (!tsdPtr->initialized) {
+        return;
+    }
+    tsdPtr->initialized = 0;
+
+    UnregisterClass(TK_WIN_TOPLEVEL_CLASS_NAME, hInstance);
+}
+\f
+/*
+ *--------------------------------------------------------------
+ *
+ * TkWmNewWindow --
+ *
+ *     This procedure is invoked whenever a new top-level
+ *     window is created.  Its job is to initialize the WmInfo
+ *     structure for the window.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     A WmInfo structure gets allocated and initialized.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkWmNewWindow(winPtr)
+    TkWindow *winPtr;          /* Newly-created top-level window. */
+{
+    register WmInfo *wmPtr;
+
+    wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
+
+    /*
+     * Initialize full structure, then set what isn't NULL
+     */
+    ZeroMemory(wmPtr, sizeof(WmInfo));
+    winPtr->wmInfoPtr = wmPtr;
+    wmPtr->winPtr = winPtr;
+    wmPtr->hints.flags = InputHint | StateHint;
+    wmPtr->hints.input = True;
+    wmPtr->hints.initial_state = NormalState;
+    wmPtr->hints.icon_pixmap = None;
+    wmPtr->hints.icon_window = None;
+    wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
+    wmPtr->hints.icon_mask = None;
+    wmPtr->hints.window_group = None;
+
+    /*
+     * Default the maximum dimensions to the size of the display.
+     */
+
+    wmPtr->defMinWidth = wmPtr->defMinHeight = 0;
+    wmPtr->defMaxWidth = DisplayWidth(winPtr->display, winPtr->screenNum);
+    wmPtr->defMaxHeight = DisplayHeight(winPtr->display, winPtr->screenNum);
+    wmPtr->minWidth = wmPtr->minHeight = 1;
+    wmPtr->maxWidth = wmPtr->maxHeight = 0;
+    wmPtr->widthInc = wmPtr->heightInc = 1;
+    wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
+    wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
+    wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
+    wmPtr->gravity = NorthWestGravity;
+    wmPtr->width = -1;
+    wmPtr->height = -1;
+    wmPtr->x = winPtr->changes.x;
+    wmPtr->y = winPtr->changes.y;
+
+    wmPtr->configWidth = -1;
+    wmPtr->configHeight = -1;
+    wmPtr->flags = WM_NEVER_MAPPED;
+    wmPtr->nextPtr = winPtr->dispPtr->firstWmPtr;
+    winPtr->dispPtr->firstWmPtr = wmPtr;
+
+    /*
+     * Tk must monitor structure events for top-level windows, in order
+     * to detect size and position changes caused by window managers.
+     */
+
+    Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
+           TopLevelEventProc, (ClientData) winPtr);
+
+    /*
+     * Arrange for geometry requests to be reflected from the window
+     * to the window manager.
+     */
+
+    Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * UpdateWrapper --
+ *
+ *     This function creates the wrapper window that contains the
+ *     window decorations and menus for a toplevel.  This function
+ *     may be called after a window is mapped to change the window
+ *     style.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Destroys any old wrapper window and replaces it with a newly
+ *     created wrapper.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+UpdateWrapper(winPtr)
+    TkWindow *winPtr;          /* Top-level window to redecorate. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    HWND parentHWND, oldWrapper;
+    HWND child;
+    int x, y, width, height, state;
+    WINDOWPLACEMENT place;
+    HICON hSmallIcon = NULL;
+    HICON hBigIcon = NULL;
+    Tcl_DString titleString, classString;
+    int *childStateInfo = NULL;
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+    if (winPtr->window == None) {
+       /*
+        * Ensure existence of the window to update the wrapper for.
+        */
+       Tk_MakeWindowExist((Tk_Window) winPtr);
+    }
+
+    child = TkWinGetHWND(winPtr->window);
+    parentHWND = NULL;
+
+    if (winPtr->flags & TK_EMBEDDED) {
+       wmPtr->wrapper = (HWND) winPtr->privatePtr;
+       if (wmPtr->wrapper == NULL) {
+           panic("UpdateWrapper: Cannot find container window");
+       }
+       if (!IsWindow(wmPtr->wrapper)) {
+           panic("UpdateWrapper: Container was destroyed");
+       }
+
+    } else {
+       /*
+        * Pick the decorative frame style.  Override redirect windows get
+        * created as undecorated popups.  Transient windows get a modal
+        * dialog frame.  Neither override, nor transient windows appear in
+        * the Windows taskbar.  Note that a transient window does not resize
+        * by default, so we need to explicitly add the WS_THICKFRAME style
+        * if we want it to be resizeable.
+        */
+
+       if (winPtr->atts.override_redirect) {
+           wmPtr->style = WM_OVERRIDE_STYLE;
+           wmPtr->exStyle = EX_OVERRIDE_STYLE;
+       } else if (wmPtr->masterPtr) {
+           wmPtr->style = WM_TRANSIENT_STYLE;
+           wmPtr->exStyle = EX_TRANSIENT_STYLE;
+           parentHWND = Tk_GetHWND(Tk_WindowId(wmPtr->masterPtr));
+           if (! ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
+                   (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE))) {
+               wmPtr->style |= WS_THICKFRAME;
+           }
+       } else {
+           wmPtr->style = WM_TOPLEVEL_STYLE;
+           wmPtr->exStyle = EX_TOPLEVEL_STYLE;
+       }
+
+       wmPtr->style   |= wmPtr->styleConfig;
+       wmPtr->exStyle |= wmPtr->exStyleConfig;
+
+       if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE)
+               && (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
+           wmPtr->style &= ~ (WS_MAXIMIZEBOX | WS_SIZEBOX);
+       }
+
+       /*
+        * Compute the geometry of the parent and child windows.
+        */
+
+       wmPtr->flags |= WM_CREATE_PENDING|WM_MOVE_PENDING;
+       UpdateGeometryInfo((ClientData)winPtr);
+       wmPtr->flags &= ~(WM_CREATE_PENDING|WM_MOVE_PENDING);
+
+       width = wmPtr->borderWidth + winPtr->changes.width;
+       height = wmPtr->borderHeight + winPtr->changes.height;
+
+       /*
+        * Set the initial position from the user or program specified
+        * location.  If nothing has been specified, then let the system
+        * pick a location.
+        */
+
+       if (!(wmPtr->sizeHintsFlags & (USPosition | PPosition))
+               && (wmPtr->flags & WM_NEVER_MAPPED)) {
+           x = CW_USEDEFAULT;
+           y = CW_USEDEFAULT;
+       } else {
+           x = winPtr->changes.x;
+           y = winPtr->changes.y;
+       }
+
+       /*
+        * Create the containing window, and set the user data to point
+        * to the TkWindow.
+        */
+
+       tsdPtr->createWindow = winPtr;
+       Tcl_WinUtfToTChar(((wmPtr->title != NULL) ?
+                           wmPtr->title : winPtr->nameUid), -1, &titleString);
+       Tcl_WinUtfToTChar(TK_WIN_TOPLEVEL_CLASS_NAME, -1, &classString);
+       wmPtr->wrapper = (*tkWinProcs->createWindowEx)(wmPtr->exStyle,
+               (LPCTSTR) Tcl_DStringValue(&classString),
+               (LPCTSTR) Tcl_DStringValue(&titleString),
+               wmPtr->style, x, y, width, height,
+               parentHWND, NULL, Tk_GetHINSTANCE(), NULL);
+       Tcl_DStringFree(&classString);
+       Tcl_DStringFree(&titleString);
+#ifdef _WIN64
+       SetWindowLongPtr(wmPtr->wrapper, GWLP_USERDATA, (LONG_PTR) winPtr);
+#else
+       SetWindowLong(wmPtr->wrapper, GWL_USERDATA, (LONG) winPtr);
+#endif
+       tsdPtr->createWindow = NULL;
+
+       place.length = sizeof(WINDOWPLACEMENT);
+       GetWindowPlacement(wmPtr->wrapper, &place);
+       wmPtr->x = place.rcNormalPosition.left;
+       wmPtr->y = place.rcNormalPosition.top;
+
+       TkInstallFrameMenu((Tk_Window) winPtr);
+    }
+
+    /*
+     * Now we need to reparent the contained window and set its
+     * style appropriately.  Be sure to update the style first so that
+     * Windows doesn't try to set the focus to the child window.
+     */
+
+#ifdef _WIN64
+    SetWindowLongPtr(child, GWL_STYLE,
+           WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+#else
+    SetWindowLong(child, GWL_STYLE,
+           WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+#endif
+    if (winPtr->flags & TK_EMBEDDED) {
+#ifdef _WIN64
+       SetWindowLongPtr(child, GWLP_WNDPROC, (LONG_PTR) TopLevelProc);
+#else
+       SetWindowLong(child, GWL_WNDPROC, (LONG) TopLevelProc);
+#endif
+    }
+    oldWrapper = SetParent(child, wmPtr->wrapper);
+    if (oldWrapper) {
+       hSmallIcon = (HICON) SendMessage(oldWrapper, WM_GETICON, ICON_SMALL,
+               (LPARAM) NULL);
+       hBigIcon = (HICON) SendMessage(oldWrapper, WM_GETICON, ICON_BIG,
+               (LPARAM) NULL);
+    }
+
+    if (oldWrapper && (oldWrapper != wmPtr->wrapper)
+           && (oldWrapper != GetDesktopWindow())) {
+#ifdef _WIN64
+       SetWindowLongPtr(oldWrapper, GWLP_USERDATA, (LONG) NULL);
+#else
+       SetWindowLong(oldWrapper, GWL_USERDATA, (LONG) NULL);
+#endif
+
+       if (wmPtr->numTransients > 0) {
+           /*
+            * Unset the current wrapper as the parent for all transient
+            * children for whom this is the master
+            */
+           WmInfo *wmPtr2;
+
+           childStateInfo = (int *)ckalloc((unsigned) wmPtr->numTransients
+               * sizeof(int));
+           state = 0;
+           for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
+                wmPtr2 = wmPtr2->nextPtr) {
+               if (wmPtr2->masterPtr == winPtr) {
+                   if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
+                       childStateInfo[state++] = wmPtr2->hints.initial_state;
+                       SetParent(TkWinGetHWND(wmPtr2->winPtr->window), NULL);
+                   }
+               }
+           }
+       }
+       /*
+        * Remove the menubar before destroying the window so the menubar
+        * isn't destroyed.
+        */
+
+       SetMenu(oldWrapper, NULL);
+       DestroyWindow(oldWrapper);
+    }
+
+    wmPtr->flags &= ~WM_NEVER_MAPPED;
+    SendMessage(wmPtr->wrapper, TK_ATTACHWINDOW, (WPARAM) child, 0);
+
+    /*
+     * Force an initial transition from withdrawn to the real
+     * initial state.
+     */
+
+    state = wmPtr->hints.initial_state;
+    wmPtr->hints.initial_state = WithdrawnState;
+    TkpWmSetState(winPtr, state);
+
+    if (hSmallIcon != NULL) {
+       SendMessage(wmPtr->wrapper,WM_SETICON,ICON_SMALL,(LPARAM)hSmallIcon);
+    }
+    if (hBigIcon != NULL) {
+       SendMessage(wmPtr->wrapper,WM_SETICON,ICON_BIG,(LPARAM)hBigIcon);
+    }
+
+    /*
+     * If we are embedded then force a mapping of the window now,
+     * because we do not necessarily own the wrapper and may not
+     * get another opportunity to map ourselves. We should not be
+     * in either iconified or zoomed states when we get here, so
+     * it is safe to just check for TK_EMBEDDED without checking
+     * what state we are supposed to be in (default to NormalState).
+     */
+
+    if (winPtr->flags & TK_EMBEDDED) {
+       XMapWindow(winPtr->display, winPtr->window);
+    }
+
+    /*
+     * Set up menus on the wrapper if required.
+     */
+
+    if (wmPtr->hMenu != NULL) {
+       wmPtr->flags = WM_SYNC_PENDING;
+       SetMenu(wmPtr->wrapper, wmPtr->hMenu);
+       wmPtr->flags &= ~WM_SYNC_PENDING;
+    }
+
+    if (childStateInfo) {
+       if (wmPtr->numTransients > 0) {
+           /*
+            * Reset all transient children for whom this is the master
+            */
+           WmInfo *wmPtr2;
+
+           state = 0;
+           for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
+                wmPtr2 = wmPtr2->nextPtr) {
+               if (wmPtr2->masterPtr == winPtr) {
+                   if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
+                       UpdateWrapper(wmPtr2->winPtr);
+                       TkpWmSetState(wmPtr2->winPtr, childStateInfo[state++]);
+                   }
+               }
+           }
+       }
+
+       ckfree((char *) childStateInfo);
+    }
+
+    /*
+     * If this is the first window created by the application, then
+     * we should activate the initial window.
+     */
+
+    if (tsdPtr->firstWindow) {
+       tsdPtr->firstWindow = 0;
+       SetActiveWindow(wmPtr->wrapper);
+    }
+}
+\f
+/*
+ *--------------------------------------------------------------
+ *
+ * TkWmMapWindow --
+ *
+ *     This procedure is invoked to map a top-level window.  This
+ *     module gets a chance to update all window-manager-related
+ *     information in properties before the window manager sees
+ *     the map event and checks the properties.  It also gets to
+ *     decide whether or not to even map the window after all.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Properties of winPtr may get updated to provide up-to-date
+ *     information to the window manager.  The window may also get
+ *     mapped, but it may not be if this procedure decides that
+ *     isn't appropriate (e.g. because the window is withdrawn).
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkWmMapWindow(winPtr)
+    TkWindow *winPtr;          /* Top-level window that's about to
+                                * be mapped. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+    if (!tsdPtr->initialized) {
+       InitWm();
+    }
+
+    if (wmPtr->flags & WM_NEVER_MAPPED) {
+       /*
+        * Don't map a transient if the master is not mapped.
+        */
+
+       if (wmPtr->masterPtr != NULL &&
+               !Tk_IsMapped(wmPtr->masterPtr)) {
+           wmPtr->hints.initial_state = WithdrawnState;
+           return;
+       }
+    } else {
+       if (wmPtr->hints.initial_state == WithdrawnState) {
+           return;
+       }
+
+       /*
+        * Map the window in either the iconified or normal state.  Note that
+        * we only send a map event if the window is in the normal state.
+        */
+
+       TkpWmSetState(winPtr, wmPtr->hints.initial_state);
+    }
+
+    /*
+     * This is the first time this window has ever been mapped.
+     * Store all the window-manager-related information for the
+     * window.
+     */
+
+    UpdateWrapper(winPtr);
+}
+\f
+/*
+ *--------------------------------------------------------------
+ *
+ * TkWmUnmapWindow --
+ *
+ *     This procedure is invoked to unmap a top-level window.  The
+ *     only thing it does special is unmap the decorative frame before
+ *     unmapping the toplevel window.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Unmaps the decorative frame and the window.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkWmUnmapWindow(winPtr)
+    TkWindow *winPtr;          /* Top-level window that's about to
+                                * be unmapped. */
+{
+    TkpWmSetState(winPtr, WithdrawnState);
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpWmSetState --
+ *
+ *     Sets the window manager state for the wrapper window of a
+ *     given toplevel window.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     May maximize, minimize, restore, or withdraw a window.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpWmSetState(winPtr, state)
+     TkWindow *winPtr;         /* Toplevel window to operate on. */
+     int state;                        /* One of IconicState, ZoomState, NormalState,
+                                * or WithdrawnState. */
+{
+    WmInfo *wmPtr = winPtr->wmInfoPtr;
+    int cmd;
+
+    if (wmPtr->flags & WM_NEVER_MAPPED) {
+       wmPtr->hints.initial_state = state;
+       return;
+    }
+
+    wmPtr->flags |= WM_SYNC_PENDING;
+    if (state == WithdrawnState) {
+       cmd = SW_HIDE;
+    } else if (state == IconicState) {
+       cmd = SW_SHOWMINNOACTIVE;
+    } else if (state == NormalState) {
+       cmd = SW_SHOWNOACTIVATE;
+    } else if (state == ZoomState) {
+       cmd = SW_SHOWMAXIMIZED;
+    }
+
+    ShowWindow(wmPtr->wrapper, cmd);
+    wmPtr->flags &= ~WM_SYNC_PENDING;
+}
+\f
+/*
+ *--------------------------------------------------------------
+ *
+ * TkWmDeadWindow --
+ *
+ *     This procedure is invoked when a top-level window is
+ *     about to be deleted.  It cleans up the wm-related data
+ *     structures for the window.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     The WmInfo structure for winPtr gets freed up.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkWmDeadWindow(winPtr)
+    TkWindow *winPtr;          /* Top-level window that's being deleted. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    WmInfo *wmPtr2;
+
+    if (wmPtr == NULL) {
+       return;
+    }
+
+    /*
+     * Clean up event related window info.
+     */
+
+    if (winPtr->dispPtr->firstWmPtr == wmPtr) {
+       winPtr->dispPtr->firstWmPtr = wmPtr->nextPtr;
+    } else {
+       register WmInfo *prevPtr;
+       for (prevPtr = winPtr->dispPtr->firstWmPtr; ;
+            prevPtr = prevPtr->nextPtr) {
+           if (prevPtr == NULL) {
+               panic("couldn't unlink window in TkWmDeadWindow");
+           }
+           if (prevPtr->nextPtr == wmPtr) {
+               prevPtr->nextPtr = wmPtr->nextPtr;
+               break;
+           }
+       }
+    }
+
+    /*
+     * Reset all transient windows whose master is the dead window.
+     */
+
+    for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
+        wmPtr2 = wmPtr2->nextPtr) {
+       if (wmPtr2->masterPtr == winPtr) {
+           wmPtr->numTransients--;
+           Tk_DeleteEventHandler((Tk_Window) wmPtr2->masterPtr,
+                   VisibilityChangeMask|StructureNotifyMask,
+                   WmWaitVisibilityOrMapProc, (ClientData) wmPtr2->winPtr);
+           wmPtr2->masterPtr = NULL;
+           if ((wmPtr2->wrapper != None)
+                   && !(wmPtr2->flags & (WM_NEVER_MAPPED))) {
+               UpdateWrapper(wmPtr2->winPtr);
+           }
+       }
+    }
+    if (wmPtr->numTransients != 0)
+        panic("numTransients should be 0");
+
+    if (wmPtr->title != NULL) {
+       ckfree(wmPtr->title);
+    }
+    if (wmPtr->iconName != NULL) {
+       ckfree(wmPtr->iconName);
+    }
+    if (wmPtr->hints.flags & IconPixmapHint) {
+       Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
+    }
+    if (wmPtr->hints.flags & IconMaskHint) {
+       Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
+    }
+    if (wmPtr->leaderName != NULL) {
+       ckfree(wmPtr->leaderName);
+    }
+    if (wmPtr->icon != NULL) {
+       wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
+       wmPtr2->iconFor = NULL;
+    }
+    if (wmPtr->iconFor != NULL) {
+       wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
+       wmPtr2->icon = NULL;
+       wmPtr2->hints.flags &= ~IconWindowHint;
+    }
+    while (wmPtr->protPtr != NULL) {
+       ProtocolHandler *protPtr;
+
+       protPtr = wmPtr->protPtr;
+       wmPtr->protPtr = protPtr->nextPtr;
+       Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
+    }
+    if (wmPtr->cmdArgv != NULL) {
+       ckfree((char *) wmPtr->cmdArgv);
+    }
+    if (wmPtr->clientMachine != NULL) {
+       ckfree((char *) wmPtr->clientMachine);
+    }
+    if (wmPtr->flags & WM_UPDATE_PENDING) {
+       Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
+    }
+    if (wmPtr->masterPtr != NULL) {
+       wmPtr2 = wmPtr->masterPtr->wmInfoPtr;
+       /*
+        * If we had a master, tell them that we aren't tied
+        * to them anymore
+        */
+       if (wmPtr2 != NULL) {
+           wmPtr2->numTransients--;
+       }
+       Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
+               VisibilityChangeMask|StructureNotifyMask,
+               WmWaitVisibilityOrMapProc, (ClientData) winPtr);
+       wmPtr->masterPtr = NULL;
+    }
+
+    /*
+     * Destroy the decorative frame window.
+     */
+
+    if (!(winPtr->flags & TK_EMBEDDED)) {
+       if (wmPtr->wrapper != NULL) {
+           DestroyWindow(wmPtr->wrapper);
+       } else {
+           DestroyWindow(Tk_GetHWND(winPtr->window));
+       }
+    }
+    if (wmPtr->iconPtr != NULL) {
+       /*
+        * This may delete the icon resource data.  I believe we
+        * should do this after destroying the decorative frame,
+        * because the decorative frame is using this icon.
+        */
+        DecrIconRefCount(wmPtr->iconPtr);
+    }
+
+    ckfree((char *) wmPtr);
+    winPtr->wmInfoPtr = NULL;
+}
+\f
+/*
+ *--------------------------------------------------------------
+ *
+ * TkWmSetClass --
+ *
+ *     This procedure is invoked whenever a top-level window's
+ *     class is changed.  If the window has been mapped then this
+ *     procedure updates the window manager property for the
+ *     class.  If the window hasn't been mapped, the update is
+ *     deferred until just before the first mapping.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     A window property may get updated.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkWmSetClass(winPtr)
+    TkWindow *winPtr;          /* Newly-created top-level window. */
+{
+    return;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_WmObjCmd --
+ *
+ *     This procedure is invoked to process the "wm" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+       /* ARGSUSED */
+int
+Tk_WmObjCmd(clientData, interp, objc, objv)
+    ClientData clientData;     /* Main window associated with
+                                * interpreter. */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    Tk_Window tkwin = (Tk_Window) clientData;
+    static CONST char *optionStrings[] = {
+       "aspect", "attributes", "client", "colormapwindows",
+       "command", "deiconify", "focusmodel", "frame",
+       "geometry", "grid", "group", "iconbitmap",
+       "iconify", "iconmask", "iconname", "iconposition",
+       "iconwindow", "maxsize", "minsize", "overrideredirect",
+        "positionfrom", "protocol", "resizable", "sizefrom",
+        "stackorder", "state", "title", "transient",
+       "withdraw", (char *) NULL };
+    enum options {
+        WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS,
+       WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FRAME,
+       WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP, WMOPT_ICONBITMAP,
+       WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME, WMOPT_ICONPOSITION,
+       WMOPT_ICONWINDOW, WMOPT_MAXSIZE, WMOPT_MINSIZE, WMOPT_OVERRIDEREDIRECT,
+        WMOPT_POSITIONFROM, WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM,
+        WMOPT_STACKORDER, WMOPT_STATE, WMOPT_TITLE, WMOPT_TRANSIENT,
+       WMOPT_WITHDRAW };
+    int index, length;
+    char *argv1;
+    TkWindow *winPtr;
+    TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
+
+    if (objc < 2) {
+       wrongNumArgs:
+       Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg ...?");
+       return TCL_ERROR;
+    }
+
+    argv1 = Tcl_GetStringFromObj(objv[1], &length);
+    if ((argv1[0] == 't') && (strncmp(argv1, "tracing", length) == 0)
+           && (length >= 3)) {
+       int wmTracing;
+       if ((objc != 2) && (objc != 3)) {
+           Tcl_WrongNumArgs(interp, 2, objv, "?boolean?");
+           return TCL_ERROR;
+       }
+       if (objc == 2) {
+           Tcl_SetResult(interp,
+                   ((dispPtr->flags & TK_DISPLAY_WM_TRACING) ? "on" : "off"),
+                   TCL_STATIC);
+           return TCL_OK;
+       }
+       if (Tcl_GetBooleanFromObj(interp, objv[2], &wmTracing) != TCL_OK) {
+           return TCL_ERROR;
+       }
+       if (wmTracing) {
+           dispPtr->flags |= TK_DISPLAY_WM_TRACING;
+       } else {
+           dispPtr->flags &= ~TK_DISPLAY_WM_TRACING;
+       }
+       return TCL_OK;
+    }
+
+    if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
+           &index) != TCL_OK) {
+       return TCL_ERROR;
+    }
+
+    if (objc < 3) {
+       goto wrongNumArgs;
+    }
+
+    if (TkGetWindowFromObj(interp, tkwin, objv[2], (Tk_Window *) &winPtr)
+           != TCL_OK) {
+       return TCL_ERROR;
+    }
+    if (!Tk_IsTopLevel(winPtr)) {
+       Tcl_AppendResult(interp, "window \"", winPtr->pathName,
+               "\" isn't a top-level window", (char *) NULL);
+       return TCL_ERROR;
+    }
+
+    switch ((enum options) index) {
+      case WMOPT_ASPECT:
+       return WmAspectCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_ATTRIBUTES:
+       return WmAttributesCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_CLIENT:
+       return WmClientCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_COLORMAPWINDOWS:
+       return WmColormapwindowsCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_COMMAND:
+       return WmCommandCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_DEICONIFY:
+       return WmDeiconifyCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_FOCUSMODEL:
+       return WmFocusmodelCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_FRAME:
+       return WmFrameCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_GEOMETRY:
+       return WmGeometryCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_GRID:
+       return WmGridCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_GROUP:
+       return WmGroupCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_ICONBITMAP:
+       return WmIconbitmapCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_ICONIFY:
+       return WmIconifyCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_ICONMASK:
+       return WmIconmaskCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_ICONNAME:
+       return WmIconnameCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_ICONPOSITION:
+       return WmIconpositionCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_ICONWINDOW:
+       return WmIconwindowCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_MAXSIZE:
+       return WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_MINSIZE:
+       return WmMinsizeCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_OVERRIDEREDIRECT:
+       return WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_POSITIONFROM:
+       return WmPositionfromCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_PROTOCOL:
+       return WmProtocolCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_RESIZABLE:
+       return WmResizableCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_SIZEFROM:
+       return WmSizefromCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_STACKORDER:
+       return WmStackorderCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_STATE:
+       return WmStateCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_TITLE:
+       return WmTitleCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_TRANSIENT:
+       return WmTransientCmd(tkwin, winPtr, interp, objc, objv);
+      case WMOPT_WITHDRAW:
+       return WmWithdrawCmd(tkwin, winPtr, interp, objc, objv);
+    }
+
+    /* This should not happen */
+    return TCL_ERROR;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmAspectCmd --
+ *
+ *     This procedure is invoked to process the "wm aspect" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmAspectCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    int numer1, denom1, numer2, denom2;
+
+    if ((objc != 3) && (objc != 7)) {
+       Tcl_WrongNumArgs(interp, 2, objv,
+               "window ?minNumer minDenom maxNumer maxDenom?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->sizeHintsFlags & PAspect) {
+           char buf[TCL_INTEGER_SPACE * 4];
+
+           sprintf(buf, "%d %d %d %d", wmPtr->minAspect.x,
+                   wmPtr->minAspect.y, wmPtr->maxAspect.x,
+                   wmPtr->maxAspect.y);
+           Tcl_SetResult(interp, buf, TCL_VOLATILE);
+       }
+       return TCL_OK;
+    }
+    if (*Tcl_GetString(objv[3]) == '\0') {
+       wmPtr->sizeHintsFlags &= ~PAspect;
+    } else {
+       if ((Tcl_GetIntFromObj(interp, objv[3], &numer1) != TCL_OK)
+               || (Tcl_GetIntFromObj(interp, objv[4], &denom1) != TCL_OK)
+               || (Tcl_GetIntFromObj(interp, objv[5], &numer2) != TCL_OK)
+               || (Tcl_GetIntFromObj(interp, objv[6], &denom2) != TCL_OK)) {
+           return TCL_ERROR;
+       }
+       if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
+               (denom2 <= 0)) {
+           Tcl_SetResult(interp, "aspect number can't be <= 0",
+                   TCL_STATIC);
+           return TCL_ERROR;
+       }
+       wmPtr->minAspect.x = numer1;
+       wmPtr->minAspect.y = denom1;
+       wmPtr->maxAspect.x = numer2;
+       wmPtr->maxAspect.y = denom2;
+       wmPtr->sizeHintsFlags |= PAspect;
+    }
+    WmUpdateGeom(wmPtr, winPtr);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmAttributesCmd --
+ *
+ *     This procedure is invoked to process the "wm attributes" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmAttributesCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    LONG style, exStyle, styleBit, *stylePtr;
+    char buf[TCL_INTEGER_SPACE], *string;
+    int i, boolean, length;
+
+    if (objc < 3) {
+        configArgs:
+       Tcl_WrongNumArgs(interp, 2, objv,
+               "window"
+               " ?-disabled ?bool??"
+               " ?-toolwindow ?bool??"
+               " ?-topmost ?bool??");
+       return TCL_ERROR;
+    }
+    exStyle = wmPtr->exStyleConfig;
+    style   = wmPtr->styleConfig;
+    if (objc == 3) {
+       sprintf(buf, "%d", ((style & WS_DISABLED) != 0));
+       Tcl_AppendResult(interp, "-disabled ", buf, (char *) NULL);
+       sprintf(buf, "%d", ((exStyle & WS_EX_TOOLWINDOW) != 0));
+       Tcl_AppendResult(interp, " -toolwindow ", buf, (char *) NULL);
+       sprintf(buf, "%d", ((exStyle & WS_EX_TOPMOST) != 0));
+       Tcl_AppendResult(interp, " -topmost ", buf, (char *) NULL);
+       return TCL_OK;
+    }
+    for (i = 3; i < objc; i += 2) {
+       string = Tcl_GetStringFromObj(objv[i], &length);
+       if ((length < 2) || (string[0] != '-')) {
+           goto configArgs;
+       }
+       if ((i < objc-1) &&
+               (Tcl_GetBooleanFromObj(interp, objv[i+1], &boolean) != TCL_OK)) {
+           return TCL_ERROR;
+       }
+       if (strncmp(string, "-disabled", length) == 0) {
+           stylePtr = &style;
+           styleBit = WS_DISABLED;
+       } else if ((strncmp(string, "-toolwindow", length) == 0)
+                  && (length >= 3)) {
+           stylePtr = &exStyle;
+           styleBit = WS_EX_TOOLWINDOW;
+       } else if ((strncmp(string, "-topmost", length) == 0)
+                  && (length >= 3)) {
+           stylePtr = &exStyle;
+           styleBit = WS_EX_TOPMOST;
+           if ((i < objc-1) && (winPtr->flags & TK_EMBEDDED)) {
+               Tcl_AppendResult(interp, "can't set topmost flag on ",
+                       winPtr->pathName, ": it is an embedded window",
+                       (char *) NULL);
+               return TCL_ERROR;
+           }
+       } else {
+           goto configArgs;
+       }
+       if (i == objc-1) {
+           Tcl_SetIntObj(Tcl_GetObjResult(interp),
+                   ((*stylePtr & styleBit) != 0));
+       } else if (boolean) {
+           *stylePtr |= styleBit;
+       } else {
+           *stylePtr &= ~styleBit;
+       }
+    }
+    if ((wmPtr->styleConfig != style) ||
+           (wmPtr->exStyleConfig != exStyle)) {
+       wmPtr->styleConfig = style;
+       wmPtr->exStyleConfig = exStyle;
+       UpdateWrapper(winPtr);
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmClientCmd --
+ *
+ *     This procedure is invoked to process the "wm client" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmClientCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    char *argv3;
+    int length;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?name?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->clientMachine != NULL) {
+           Tcl_SetResult(interp, wmPtr->clientMachine, TCL_STATIC);
+       }
+       return TCL_OK;
+    }
+    argv3 = Tcl_GetStringFromObj(objv[3], &length);
+    if (argv3[0] == 0) {
+       if (wmPtr->clientMachine != NULL) {
+           ckfree((char *) wmPtr->clientMachine);
+           wmPtr->clientMachine = NULL;
+           if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
+               XDeleteProperty(winPtr->display, winPtr->window,
+                       Tk_InternAtom((Tk_Window) winPtr,
+                               "WM_CLIENT_MACHINE"));
+           }
+       }
+       return TCL_OK;
+    }
+    if (wmPtr->clientMachine != NULL) {
+       ckfree((char *) wmPtr->clientMachine);
+    }
+    wmPtr->clientMachine = (char *)
+           ckalloc((unsigned) (length + 1));
+    strcpy(wmPtr->clientMachine, argv3);
+    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
+       XTextProperty textProp;
+       if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
+               != 0) {
+           XSetWMClientMachine(winPtr->display, winPtr->window,
+                   &textProp);
+           XFree((char *) textProp.value);
+       }
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmColormapwindowsCmd --
+ *
+ *     This procedure is invoked to process the "wm colormapwindows"
+ *     Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmColormapwindowsCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    TkWindow **cmapList;
+    TkWindow *winPtr2;
+    int i, windowObjc, gotToplevel;
+    Tcl_Obj **windowObjv;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?windowList?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       Tk_MakeWindowExist((Tk_Window) winPtr);
+       for (i = 0; i < wmPtr->cmapCount; i++) {
+           if ((i == (wmPtr->cmapCount-1))
+                   && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
+               break;
+           }
+           Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
+       }
+       return TCL_OK;
+    }
+    if (Tcl_ListObjGetElements(interp, objv[3], &windowObjc, &windowObjv)
+           != TCL_OK) {
+       return TCL_ERROR;
+    }
+    cmapList = (TkWindow **) ckalloc((unsigned)
+           ((windowObjc+1)*sizeof(TkWindow*)));
+    gotToplevel = 0;
+    for (i = 0; i < windowObjc; i++) {
+       if (TkGetWindowFromObj(interp, tkwin, windowObjv[i],
+               (Tk_Window *) &winPtr2) != TCL_OK)
+       {
+           ckfree((char *) cmapList);
+           return TCL_ERROR;
+       }
+       if (winPtr2 == winPtr) {
+           gotToplevel = 1;
+       }
+       if (winPtr2->window == None) {
+           Tk_MakeWindowExist((Tk_Window) winPtr2);
+       }
+       cmapList[i] = winPtr2;
+    }
+    if (!gotToplevel) {
+       wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
+       cmapList[windowObjc] = winPtr;
+       windowObjc++;
+    } else {
+       wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
+    }
+    wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
+    if (wmPtr->cmapList != NULL) {
+       ckfree((char *)wmPtr->cmapList);
+    }
+    wmPtr->cmapList = cmapList;
+    wmPtr->cmapCount = windowObjc;
+
+    /*
+     * Now we need to force the updated colormaps to be installed.
+     */
+
+    if (wmPtr == winPtr->dispPtr->foregroundWmPtr) {
+       InstallColormaps(wmPtr->wrapper, WM_QUERYNEWPALETTE, 1);
+    } else {
+       InstallColormaps(wmPtr->wrapper, WM_PALETTECHANGED, 0);
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmCommandCmd --
+ *
+ *     This procedure is invoked to process the "wm command" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmCommandCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    char *argv3;
+    int cmdArgc;
+    CONST char **cmdArgv;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?value?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->cmdArgv != NULL) {
+           Tcl_SetResult(interp,
+                   Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv),
+                   TCL_DYNAMIC);
+       }
+       return TCL_OK;
+    }
+    argv3 = Tcl_GetString(objv[3]);
+    if (argv3[0] == 0) {
+       if (wmPtr->cmdArgv != NULL) {
+           ckfree((char *) wmPtr->cmdArgv);
+           wmPtr->cmdArgv = NULL;
+           if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
+               XDeleteProperty(winPtr->display, winPtr->window,
+                       Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND"));
+           }
+       }
+       return TCL_OK;
+    }
+    if (Tcl_SplitList(interp, argv3, &cmdArgc, &cmdArgv) != TCL_OK) {
+       return TCL_ERROR;
+    }
+    if (wmPtr->cmdArgv != NULL) {
+       ckfree((char *) wmPtr->cmdArgv);
+    }
+    wmPtr->cmdArgc = cmdArgc;
+    wmPtr->cmdArgv = cmdArgv;
+    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
+       XSetCommand(winPtr->display, winPtr->window, cmdArgv, cmdArgc);
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmDeiconifyCmd --
+ *
+ *     This procedure is invoked to process the "wm deiconify" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmDeiconifyCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+
+    if (objc != 3) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window");
+       return TCL_ERROR;
+    }
+    if (wmPtr->iconFor != NULL) {
+       Tcl_AppendResult(interp, "can't deiconify ", Tcl_GetString(objv[2]),
+               ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
+               (char *) NULL);
+       return TCL_ERROR;
+    }
+    if (winPtr->flags & TK_EMBEDDED) {
+       Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName,
+               ": it is an embedded window", (char *) NULL);
+       return TCL_ERROR;
+    }
+
+    if (wmPtr->flags & WM_TRANSIENT_WITHDRAWN) {
+       wmPtr->flags &= ~WM_TRANSIENT_WITHDRAWN;
+    }
+
+    /*
+     * If WM_UPDATE_PENDING is true, a pending UpdateGeometryInfo may
+     * need to be called first to update a withdrawn toplevel's geometry
+     * before it is deiconified by TkpWmSetState.
+     * Don't bother if we've never been mapped.
+     */
+    if ((wmPtr->flags & WM_UPDATE_PENDING) &&
+           !(wmPtr->flags & WM_NEVER_MAPPED)) {
+       Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
+       UpdateGeometryInfo((ClientData) winPtr);
+    }
+
+    /*
+     * If we were in the ZoomState (maximized), 'wm deiconify'
+     * should not cause the window to shrink
+     */
+    if (wmPtr->hints.initial_state == ZoomState) {
+       TkpWmSetState(winPtr, ZoomState);
+    } else {
+       TkpWmSetState(winPtr, NormalState);
+    }
+
+    /*
+     * An unmapped window will be mapped at idle time
+     * by a call to MapFrame. That calls CreateWrapper
+     * which sets the focus and raises the window.
+     */
+    if (wmPtr->flags & WM_NEVER_MAPPED) {
+       return TCL_OK;
+    }
+
+    /*
+     * Follow Windows-like style here, raising the window to the top.
+     */
+    TkWmRestackToplevel(winPtr, Above, NULL);
+    if (!(Tk_Attributes((Tk_Window) winPtr)->override_redirect)) {
+       TkSetFocusWin(winPtr, 1);
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmFocusmodelCmd --
+ *
+ *     This procedure is invoked to process the "wm focusmodel" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmFocusmodelCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    static CONST char *optionStrings[] = {
+       "active", "passive", (char *) NULL };
+    enum options {
+       OPT_ACTIVE, OPT_PASSIVE };
+    int index;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?active|passive?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"),
+               TCL_STATIC);
+       return TCL_OK;
+    }
+
+    if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
+           &index) != TCL_OK) {
+       return TCL_ERROR;
+    }
+    if (index == OPT_ACTIVE) {
+       wmPtr->hints.input = False;
+    } else { /* OPT_PASSIVE */
+       wmPtr->hints.input = True;
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmFrameCmd --
+ *
+ *     This procedure is invoked to process the "wm frame" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmFrameCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    HWND hwnd;
+    char buf[TCL_INTEGER_SPACE];
+
+    if (objc != 3) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window");
+       return TCL_ERROR;
+    }
+    if (Tk_WindowId((Tk_Window) winPtr) == None) {
+       Tk_MakeWindowExist((Tk_Window) winPtr);
+    }
+    hwnd = wmPtr->wrapper;
+    if (hwnd == NULL) {
+       hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) winPtr));
+    }
+    sprintf(buf, "0x%x", (unsigned int) hwnd);
+    Tcl_SetResult(interp, buf, TCL_VOLATILE);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmGeometryCmd --
+ *
+ *     This procedure is invoked to process the "wm geometry" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmGeometryCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    char xSign, ySign;
+    int width, height;
+    char *argv3;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?newGeometry?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       char buf[16 + TCL_INTEGER_SPACE * 4];
+
+       xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
+       ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
+       if (wmPtr->gridWin != NULL) {
+           width = wmPtr->reqGridWidth + (winPtr->changes.width
+                   - winPtr->reqWidth)/wmPtr->widthInc;
+           height = wmPtr->reqGridHeight + (winPtr->changes.height
+                   - winPtr->reqHeight)/wmPtr->heightInc;
+       } else {
+           width = winPtr->changes.width;
+           height = winPtr->changes.height;
+       }
+       sprintf(buf, "%dx%d%c%d%c%d", width, height, xSign, wmPtr->x,
+               ySign, wmPtr->y);
+       Tcl_SetResult(interp, buf, TCL_VOLATILE);
+       return TCL_OK;
+    }
+    argv3 = Tcl_GetString(objv[3]);
+    if (*argv3 == '\0') {
+       wmPtr->width = -1;
+       wmPtr->height = -1;
+       WmUpdateGeom(wmPtr, winPtr);
+       return TCL_OK;
+    }
+    return ParseGeometry(interp, argv3, winPtr);
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmGridCmd --
+ *
+ *     This procedure is invoked to process the "wm grid" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmGridCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    int reqWidth, reqHeight, widthInc, heightInc;
+
+    if ((objc != 3) && (objc != 7)) {
+       Tcl_WrongNumArgs(interp, 2, objv,
+               "window ?baseWidth baseHeight widthInc heightInc?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->sizeHintsFlags & PBaseSize) {
+           char buf[TCL_INTEGER_SPACE * 4];
+
+           sprintf(buf, "%d %d %d %d", wmPtr->reqGridWidth,
+                   wmPtr->reqGridHeight, wmPtr->widthInc,
+                   wmPtr->heightInc);
+           Tcl_SetResult(interp, buf, TCL_VOLATILE);
+       }
+       return TCL_OK;
+    }
+    if (*Tcl_GetString(objv[3]) == '\0') {
+       /*
+        * Turn off gridding and reset the width and height
+        * to make sense as ungridded numbers.
         */
-       if (wmPtr->flags & WM_NEVER_MAPPED) {
-           return TCL_OK;
+
+       wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
+       if (wmPtr->width != -1) {
+           wmPtr->width = winPtr->reqWidth + (wmPtr->width
+                   - wmPtr->reqGridWidth)*wmPtr->widthInc;
+           wmPtr->height = winPtr->reqHeight + (wmPtr->height
+                   - wmPtr->reqGridHeight)*wmPtr->heightInc;
+       }
+       wmPtr->widthInc = 1;
+       wmPtr->heightInc = 1;
+    } else {
+       if ((Tcl_GetIntFromObj(interp, objv[3], &reqWidth) != TCL_OK)
+               || (Tcl_GetIntFromObj(interp, objv[4], &reqHeight) != TCL_OK)
+               || (Tcl_GetIntFromObj(interp, objv[5], &widthInc) != TCL_OK)
+               || (Tcl_GetIntFromObj(interp, objv[6], &heightInc) != TCL_OK)) {
+           return TCL_ERROR;
+       }
+       if (reqWidth < 0) {
+           Tcl_SetResult(interp, "baseWidth can't be < 0", TCL_STATIC);
+           return TCL_ERROR;
+       }
+       if (reqHeight < 0) {
+           Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC);
+           return TCL_ERROR;
+       }
+       if (widthInc < 0) {
+           Tcl_SetResult(interp, "widthInc can't be < 0", TCL_STATIC);
+           return TCL_ERROR;
+       }
+       if (heightInc < 0) {
+           Tcl_SetResult(interp, "heightInc can't be < 0", TCL_STATIC);
+           return TCL_ERROR;
        }
+       Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
+               heightInc);
+    }
+    WmUpdateGeom(wmPtr, winPtr);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmGroupCmd --
+ *
+ *     This procedure is invoked to process the "wm group" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
 
-       /*
-        * Follow Windows-like style here, raising the window to the top.
-        */
-       TkWmRestackToplevel(winPtr, Above, NULL);
-       if (!(Tk_Attributes((Tk_Window) winPtr)->override_redirect)) {
-           TkSetFocusWin(winPtr, 1);
-       }
-    } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
-           && (length >= 2)) {
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " focusmodel window ?active|passive?\"",
-                   (char *) NULL);
+static int
+WmGroupCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    Tk_Window tkwin2;
+    char *argv3;
+    int length;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->hints.flags & WindowGroupHint) {
+           Tcl_SetResult(interp, wmPtr->leaderName, TCL_STATIC);
+       }
+       return TCL_OK;
+    }
+    argv3 = Tcl_GetStringFromObj(objv[3], &length);
+    if (*argv3 == '\0') {
+       wmPtr->hints.flags &= ~WindowGroupHint;
+       if (wmPtr->leaderName != NULL) {
+           ckfree(wmPtr->leaderName);
+       }
+       wmPtr->leaderName = NULL;
+    } else {
+       if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) {
            return TCL_ERROR;
        }
-       if (argc == 3) {
-           Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"),
-                   TCL_STATIC);
-           return TCL_OK;
+       Tk_MakeWindowExist(tkwin2);
+       if (wmPtr->leaderName != NULL) {
+           ckfree(wmPtr->leaderName);
        }
-       c = argv[3][0];
-       length = strlen(argv[3]);
-       if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
-           wmPtr->hints.input = False;
-       } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
-           wmPtr->hints.input = True;
-       } else {
-           Tcl_AppendResult(interp, "bad argument \"", argv[3],
-                   "\": must be active or passive", (char *) NULL);
+       wmPtr->hints.window_group = Tk_WindowId(tkwin2);
+       wmPtr->hints.flags |= WindowGroupHint;
+       wmPtr->leaderName = ckalloc((unsigned) (length + 1));
+       strcpy(wmPtr->leaderName, argv3);
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmIconbitmapCmd --
+ *
+ *     This procedure is invoked to process the "wm iconbitmap" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmIconbitmapCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    /* If true, then set for all windows. */
+    int isDefault = 0;
+    char *string;
+
+    if ((objc < 3) || (objc > 5)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?-default? ?image?");
+       return TCL_ERROR;
+    } else if (objc == 5) {
+       /* If we have 5 arguments, we must have a '-default' flag */
+       char *argv3 = Tcl_GetString(objv[3]);
+       if (strcmp(argv3, "-default")) {
+           Tcl_AppendResult(interp, "illegal option \"",
+                   argv3, "\" must be \"-default\"",
+                   (char *) NULL);
            return TCL_ERROR;
        }
-    } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
-           && (length >= 2)) {
-       HWND hwnd;
-       char buf[TCL_INTEGER_SPACE];
+       isDefault = 1;
+    } else if (objc == 3) {
+       /* No arguments were given */
+       if (wmPtr->hints.flags & IconPixmapHint) {
+           Tcl_SetResult(interp, (char *)
+                   Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_pixmap),
+                   TCL_STATIC);
+       }
+       return TCL_OK;
+    }
 
-       if (argc != 3) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " frame window\"", (char *) NULL);
+    string = Tcl_GetString(objv[objc-1]);
+    if (*string == '\0') {
+       if (wmPtr->hints.icon_pixmap != None) {
+           Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
+           wmPtr->hints.icon_pixmap = None;
+       }
+       wmPtr->hints.flags &= ~IconPixmapHint;
+       if (WinSetIcon(interp, NULL, 
+                      (isDefault ? NULL : (Tk_Window) winPtr)) != TCL_OK) {
            return TCL_ERROR;
        }
-       if (Tk_WindowId((Tk_Window) winPtr) == None) {
-           Tk_MakeWindowExist((Tk_Window) winPtr);
+    } else {
+       /*
+        * In the future this block of code will use Tk's 'image'
+        * functionality to allow all supported image formats.
+        * However, this will require a change to the way icons are
+        * handled.  We will need to add icon<->image conversions
+        * routines.
+        *
+        * Until that happens we simply try to find an icon in the
+        * given argument, and if that fails, we use the older
+        * bitmap code.  We do things this way round (icon then
+        * bitmap), because the bitmap code actually seems to have
+        * no visible effect, so we want to give the icon code the
+        * first try at doing something.
+        */
+
+       /*
+        * Either return NULL, or return a valid titlebaricon with its
+        * ref count already incremented.
+        */
+       WinIconPtr titlebaricon = ReadIconFromFile(interp, objv[objc-1]);
+       if (titlebaricon != NULL) {
+           /*
+            * Try to set the icon for the window.  If it is a '-default'
+            * icon, we must pass in NULL
+            */
+           if (WinSetIcon(interp, titlebaricon,
+                   (isDefault ? NULL : (Tk_Window) winPtr)) != TCL_OK) {
+               /* We didn't use the titlebaricon after all */
+               DecrIconRefCount(titlebaricon);
+               titlebaricon = NULL;
+           }
        }
-       hwnd = wmPtr->wrapper;
-       if (hwnd == NULL) {
-           hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) winPtr));
+       if (titlebaricon == NULL) {
+           /*
+            * We didn't manage to handle the argument as a valid
+            * icon.  Try as a bitmap.  First we must clear the
+            * error message which was placed in the interpreter
+            */
+           Pixmap pixmap;
+           Tcl_ResetResult(interp);
+           pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr, string);
+           if (pixmap == None) {
+               return TCL_ERROR;
+           }
+           wmPtr->hints.icon_pixmap = pixmap;
+           wmPtr->hints.flags |= IconPixmapHint;
+           titlebaricon = GetIconFromPixmap(Tk_Display(winPtr), pixmap);
+           if (titlebaricon != NULL) {
+               if (WinSetIcon(interp, titlebaricon, 
+                       (isDefault ? NULL : (Tk_Window) winPtr)) != TCL_OK) {
+                   /* We didn't use the titlebaricon after all */
+                   DecrIconRefCount(titlebaricon);
+                   titlebaricon = NULL;
+               }
+           }
        }
-       sprintf(buf, "0x%x", (unsigned int) hwnd);
-       Tcl_SetResult(interp, buf, TCL_VOLATILE);
-    } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
-           && (length >= 2)) {
-       char xSign, ySign;
-       int width, height;
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmIconifyCmd --
+ *
+ *     This procedure is invoked to process the "wm iconify" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
 
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " geometry window ?newGeometry?\"",
-                   (char *) NULL);
+static int
+WmIconifyCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    if (objc != 3) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window");
+       return TCL_ERROR;
+    }
+    if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
+       Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
+               "\": override-redirect flag is set", (char *) NULL);
+       return TCL_ERROR;
+    }
+    if (wmPtr->masterPtr != NULL) {
+       Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
+               "\": it is a transient", (char *) NULL);
+       return TCL_ERROR;
+    }
+    if (wmPtr->iconFor != NULL) {
+       Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
+               ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
+               (char *) NULL);
+       return TCL_ERROR;
+    }
+    if (winPtr->flags & TK_EMBEDDED) {
+       Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
+               ": it is an embedded window", (char *) NULL);
+       return TCL_ERROR;
+    }
+    TkpWmSetState(winPtr, IconicState);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmIconmaskCmd --
+ *
+ *     This procedure is invoked to process the "wm iconmask" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmIconmaskCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    Pixmap pixmap;
+    char *argv3;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?bitmap?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->hints.flags & IconMaskHint) {
+           Tcl_SetResult(interp, (char *)
+                   Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask),
+                   TCL_STATIC);
+       }
+       return TCL_OK;
+    }
+    argv3 = Tcl_GetString(objv[3]);
+    if (*argv3 == '\0') {
+       if (wmPtr->hints.icon_mask != None) {
+           Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
+       }
+       wmPtr->hints.flags &= ~IconMaskHint;
+    } else {
+       pixmap = Tk_GetBitmap(interp, tkwin, argv3);
+       if (pixmap == None) {
            return TCL_ERROR;
        }
-       if (argc == 3) {
-           char buf[16 + TCL_INTEGER_SPACE * 4];
-           
-           xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
-           ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
-           if (wmPtr->gridWin != NULL) {
-               width = wmPtr->reqGridWidth + (winPtr->changes.width
-                       - winPtr->reqWidth)/wmPtr->widthInc;
-               height = wmPtr->reqGridHeight + (winPtr->changes.height
-                       - winPtr->reqHeight)/wmPtr->heightInc;
-           } else {
-               width = winPtr->changes.width;
-               height = winPtr->changes.height;
-           }
-           sprintf(buf, "%dx%d%c%d%c%d", width, height, xSign, wmPtr->x,
-                   ySign, wmPtr->y);
-           Tcl_SetResult(interp, buf, TCL_VOLATILE);
-           return TCL_OK;
+       wmPtr->hints.icon_mask = pixmap;
+       wmPtr->hints.flags |= IconMaskHint;
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmIconnameCmd --
+ *
+ *     This procedure is invoked to process the "wm iconname" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmIconnameCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    char *argv3;
+    int length;
+
+    if (objc > 4) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?newName?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       Tcl_SetResult(interp,
+               ((wmPtr->iconName != NULL) ? wmPtr->iconName : ""),
+               TCL_STATIC);
+       return TCL_OK;
+    } else {
+       if (wmPtr->iconName != NULL) {
+           ckfree((char *) wmPtr->iconName);
        }
-       if (*argv[3] == '\0') {
-           wmPtr->width = -1;
-           wmPtr->height = -1;
-           goto updateGeom;
+       argv3 = Tcl_GetStringFromObj(objv[3], &length);
+       wmPtr->iconName = ckalloc((unsigned) (length + 1));
+       strcpy(wmPtr->iconName, argv3);
+       if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
+           XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
        }
-       return ParseGeometry(interp, argv[3], winPtr);
-    } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
-           && (length >= 3)) {
-       int reqWidth, reqHeight, widthInc, heightInc;
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmIconpositionCmd --
+ *
+ *     This procedure is invoked to process the "wm iconposition"
+ *     Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmIconpositionCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    int x, y;
+
+    if ((objc != 3) && (objc != 5)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?x y?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->hints.flags & IconPositionHint) {
+           char buf[TCL_INTEGER_SPACE * 2];
 
-       if ((argc != 3) && (argc != 7)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " grid window ?baseWidth baseHeight ",
-                   "widthInc heightInc?\"", (char *) NULL);
+           sprintf(buf, "%d %d", wmPtr->hints.icon_x,
+                   wmPtr->hints.icon_y);
+           Tcl_SetResult(interp, buf, TCL_VOLATILE);
+       }
+       return TCL_OK;
+    }
+    if (*Tcl_GetString(objv[3]) == '\0') {
+       wmPtr->hints.flags &= ~IconPositionHint;
+    } else {
+       if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
+               || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)){
            return TCL_ERROR;
        }
-       if (argc == 3) {
-           if (wmPtr->sizeHintsFlags & PBaseSize) {
-               char buf[TCL_INTEGER_SPACE * 4];
-               
-               sprintf(buf, "%d %d %d %d", wmPtr->reqGridWidth,
-                       wmPtr->reqGridHeight, wmPtr->widthInc,
-                       wmPtr->heightInc);
-               Tcl_SetResult(interp, buf, TCL_VOLATILE);
-           }
-           return TCL_OK;
+       wmPtr->hints.icon_x = x;
+       wmPtr->hints.icon_y = y;
+       wmPtr->hints.flags |= IconPositionHint;
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmIconwindowCmd --
+ *
+ *     This procedure is invoked to process the "wm iconwindow" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmIconwindowCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    Tk_Window tkwin2;
+    WmInfo *wmPtr2;
+    XSetWindowAttributes atts;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->icon != NULL) {
+           Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC);
        }
-       if (*argv[3] == '\0') {
+       return TCL_OK;
+    }
+    if (*Tcl_GetString(objv[3]) == '\0') {
+       wmPtr->hints.flags &= ~IconWindowHint;
+       if (wmPtr->icon != NULL) {
            /*
-            * Turn off gridding and reset the width and height
-            * to make sense as ungridded numbers.
+            * Let the window use button events again, then remove
+            * it as icon window.
             */
 
-           wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
-           if (wmPtr->width != -1) {
-               wmPtr->width = winPtr->reqWidth + (wmPtr->width
-                       - wmPtr->reqGridWidth)*wmPtr->widthInc;
-               wmPtr->height = winPtr->reqHeight + (wmPtr->height
-                       - wmPtr->reqGridHeight)*wmPtr->heightInc;
-           }
-           wmPtr->widthInc = 1;
-           wmPtr->heightInc = 1;
-       } else {
-           if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
-                   || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
-                   || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
-                   || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
-               return TCL_ERROR;
-           }
-           if (reqWidth < 0) {
-               Tcl_SetResult(interp, "baseWidth can't be < 0", TCL_STATIC);
-               return TCL_ERROR;
-           }
-           if (reqHeight < 0) {
-               Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC);
-               return TCL_ERROR;
-           }
-           if (widthInc < 0) {
-               Tcl_SetResult(interp, "widthInc can't be < 0", TCL_STATIC);
-               return TCL_ERROR;
-           }
-           if (heightInc < 0) {
-               Tcl_SetResult(interp, "heightInc can't be < 0", TCL_STATIC);
-               return TCL_ERROR;
-           }
-           Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
-                   heightInc);
-       }
-       goto updateGeom;
-    } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
-           && (length >= 3)) {
-       Tk_Window tkwin2;
-
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " group window ?pathName?\"",
-                   (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (argc == 3) {
-           if (wmPtr->hints.flags & WindowGroupHint) {
-               Tcl_SetResult(interp, wmPtr->leaderName, TCL_STATIC);
-           }
-           return TCL_OK;
-       }
-       if (*argv[3] == '\0') {
-           wmPtr->hints.flags &= ~WindowGroupHint;
-           if (wmPtr->leaderName != NULL) {
-               ckfree(wmPtr->leaderName);
-           }
-           wmPtr->leaderName = NULL;
-       } else {
-           tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
-           if (tkwin2 == NULL) {
-               return TCL_ERROR;
-           }
-           Tk_MakeWindowExist(tkwin2);
-           wmPtr->hints.window_group = Tk_WindowId(tkwin2);
-           wmPtr->hints.flags |= WindowGroupHint;
-           wmPtr->leaderName = ckalloc((unsigned) (strlen(argv[3])+1));
-           strcpy(wmPtr->leaderName, argv[3]);
-       }
-    } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
-           && (length >= 5)) {
-       Pixmap pixmap;
-
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " iconbitmap window ?bitmap?\"",
-                   (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (argc == 3) {
-           if (wmPtr->hints.flags & IconPixmapHint) {
-               Tcl_SetResult(interp,
-                       Tk_NameOfBitmap(winPtr->display,
-                               wmPtr->hints.icon_pixmap), TCL_STATIC);
-           }
-           return TCL_OK;
-       }
-       if (*argv[3] == '\0') {
-           if (wmPtr->hints.icon_pixmap != None) {
-               Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
-           }
-           wmPtr->hints.flags &= ~IconPixmapHint;
-       } else {
-           pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
-                   Tk_GetUid(argv[3]));
-           if (pixmap == None) {
-               return TCL_ERROR;
-           }
-           wmPtr->hints.icon_pixmap = pixmap;
-           wmPtr->hints.flags |= IconPixmapHint;
-       }
-    } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
-           && (length >= 5)) {
-       if (argc != 3) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " iconify window\"", (char *) NULL);
-           return TCL_ERROR;
+           atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
+                   | ButtonPressMask;
+           Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
+           wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
+           wmPtr2->iconFor = NULL;
+           wmPtr2->hints.initial_state = WithdrawnState;
        }
-       if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
-           Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
-                   "\": override-redirect flag is set", (char *) NULL);
+       wmPtr->icon = NULL;
+    } else {
+       if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) {
            return TCL_ERROR;
        }
-       if (wmPtr->masterPtr != NULL) {
-           Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
-                   "\": it is a transient", (char *) NULL);
+       if (!Tk_IsTopLevel(tkwin2)) {
+           Tcl_AppendResult(interp, "can't use ", Tcl_GetString(objv[3]),
+                   " as icon window: not at top level", (char *) NULL);
            return TCL_ERROR;
        }
-       if (wmPtr->iconFor != NULL) {
-           Tcl_AppendResult(interp, "can't iconify ", argv[2],
-                   ": it is an icon for ", winPtr->pathName, (char *) NULL);
+       wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
+       if (wmPtr2->iconFor != NULL) {
+           Tcl_AppendResult(interp, Tcl_GetString(objv[3]),
+                   " is already an icon for ",
+                   Tk_PathName(wmPtr2->iconFor), (char *) NULL);
            return TCL_ERROR;
        }
-        if (winPtr->flags & TK_EMBEDDED) {
-            Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
-                    ": it is an embedded window", (char *) NULL);
-            return TCL_ERROR;
-        }
-       TkpWmSetState(winPtr, IconicState);
-    } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
-           && (length >= 5)) {
-       Pixmap pixmap;
-
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " iconmask window ?bitmap?\"",
-                   (char *) NULL);
-           return TCL_ERROR;
+       if (wmPtr->icon != NULL) {
+           WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
+           wmPtr3->iconFor = NULL;
+
+           /*
+            * Let the window use button events again.
+            */
+
+           atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
+                   | ButtonPressMask;
+           Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
        }
-       if (argc == 3) {
-           if (wmPtr->hints.flags & IconMaskHint) {
+
+       /*
+        * Disable button events in the icon window:  some window
+        * managers (like olvwm) want to get the events themselves,
+        * but X only allows one application at a time to receive
+        * button events for a window.
+        */
+
+       atts.event_mask = Tk_Attributes(tkwin2)->event_mask
+               & ~ButtonPressMask;
+       Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
+       Tk_MakeWindowExist(tkwin2);
+       wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
+       wmPtr->hints.flags |= IconWindowHint;
+       wmPtr->icon = tkwin2;
+       wmPtr2->iconFor = (Tk_Window) winPtr;
+       if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
+           if (XWithdrawWindow(Tk_Display(tkwin2), Tk_WindowId(tkwin2),
+                   Tk_ScreenNumber(tkwin2)) == 0) {
                Tcl_SetResult(interp,
-                       Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask),
+                       "couldn't send withdraw message to window manager",
                        TCL_STATIC);
-           }
-           return TCL_OK;
-       }
-       if (*argv[3] == '\0') {
-           if (wmPtr->hints.icon_mask != None) {
-               Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
-           }
-           wmPtr->hints.flags &= ~IconMaskHint;
-       } else {
-           pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
-           if (pixmap == None) {
                return TCL_ERROR;
            }
-           wmPtr->hints.icon_mask = pixmap;
-           wmPtr->hints.flags |= IconMaskHint;
-       }
-    } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
-           && (length >= 5)) {
-       if (argc > 4) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " iconname window ?newName?\"", (char *) NULL);
-           return TCL_ERROR;
        }
-       if (argc == 3) {
-           Tcl_SetResult(interp,
-                   ((wmPtr->iconName != NULL) ? wmPtr->iconName : ""),
-                   TCL_STATIC);
-           return TCL_OK;
-       } else {
-           wmPtr->iconName = Tk_GetUid(argv[3]);
-           if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
-               XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
-           }
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmMaxsizeCmd --
+ *
+ *     This procedure is invoked to process the "wm maxsize" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    int width, height;
+
+    if ((objc != 3) && (objc != 5)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       char buf[TCL_INTEGER_SPACE * 2];
+
+       GetMaxSize(wmPtr, &width, &height);
+       sprintf(buf, "%d %d", width, height);
+       Tcl_SetResult(interp, buf, TCL_VOLATILE);
+       return TCL_OK;
+    }
+    if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
+           || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
+       return TCL_ERROR;
+    }
+    wmPtr->maxWidth = width;
+    wmPtr->maxHeight = height;
+    WmUpdateGeom(wmPtr, winPtr);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmMinsizeCmd --
+ *
+ *     This procedure is invoked to process the "wm minsize" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmMinsizeCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    int width, height;
+
+    if ((objc != 3) && (objc != 5)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       char buf[TCL_INTEGER_SPACE * 2];
+
+       GetMinSize(wmPtr, &width, &height);
+       sprintf(buf, "%d %d", width, height);
+       Tcl_SetResult(interp, buf, TCL_VOLATILE);
+       return TCL_OK;
+    }
+    if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
+           || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
+       return TCL_ERROR;
+    }
+    wmPtr->minWidth = width;
+    wmPtr->minHeight = height;
+    WmUpdateGeom(wmPtr, winPtr);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmOverrideredirectCmd --
+ *
+ *     This procedure is invoked to process the "wm overrideredirect"
+ *     Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    int boolean, curValue;
+    XSetWindowAttributes atts;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?boolean?");
+       return TCL_ERROR;
+    }
+    curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect;
+    if (objc == 3) {
+       Tcl_SetBooleanObj(Tcl_GetObjResult(interp), curValue);
+       return TCL_OK;
+    }
+    if (Tcl_GetBooleanFromObj(interp, objv[3], &boolean) != TCL_OK) {
+       return TCL_ERROR;
+    }
+    if (curValue != boolean) {
+       /*
+        * Only do this if we are really changing value, because it
+        * causes some funky stuff to occur
+        */
+       atts.override_redirect = (boolean) ? True : False;
+       Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
+               &atts);
+       if (!(wmPtr->flags & (WM_NEVER_MAPPED)
+               && !(winPtr->flags & TK_EMBEDDED))) {
+           UpdateWrapper(winPtr);
        }
-    } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
-           && (length >= 5)) {
-       int x, y;
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmPositionfromCmd --
+ *
+ *     This procedure is invoked to process the "wm positionfrom"
+ *     Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
 
-       if ((argc != 3) && (argc != 5)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " iconposition window ?x y?\"",
-                   (char *) NULL);
-           return TCL_ERROR;
+static int
+WmPositionfromCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    static CONST char *optionStrings[] = {
+       "program", "user", (char *) NULL };
+    enum options {
+       OPT_PROGRAM, OPT_USER };
+    int index;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?user/program?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->sizeHintsFlags & USPosition) {
+           Tcl_SetResult(interp, "user", TCL_STATIC);
+       } else if (wmPtr->sizeHintsFlags & PPosition) {
+           Tcl_SetResult(interp, "program", TCL_STATIC);
        }
-       if (argc == 3) {
-           if (wmPtr->hints.flags & IconPositionHint) {
-               char buf[TCL_INTEGER_SPACE * 2];
-               
-               sprintf(buf, "%d %d", wmPtr->hints.icon_x,
-                       wmPtr->hints.icon_y);
-               Tcl_SetResult(interp, buf, TCL_VOLATILE);
-           }
-           return TCL_OK;
+       return TCL_OK;
+    }
+    if (*Tcl_GetString(objv[3]) == '\0') {
+       wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
+    } else {
+       if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
+               &index) != TCL_OK) {
+           return TCL_ERROR;
        }
-       if (*argv[3] == '\0') {
-           wmPtr->hints.flags &= ~IconPositionHint;
+       if (index == OPT_USER) {
+           wmPtr->sizeHintsFlags &= ~PPosition;
+           wmPtr->sizeHintsFlags |= USPosition;
        } else {
-           if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
-                   || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
-               return TCL_ERROR;
-           }
-           wmPtr->hints.icon_x = x;
-           wmPtr->hints.icon_y = y;
-           wmPtr->hints.flags |= IconPositionHint;
-       }
-    } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
-           && (length >= 5)) {
-       Tk_Window tkwin2;
-       WmInfo *wmPtr2;
-       XSetWindowAttributes atts;
-
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " iconwindow window ?pathName?\"",
-                   (char *) NULL);
-           return TCL_ERROR;
+           wmPtr->sizeHintsFlags &= ~USPosition;
+           wmPtr->sizeHintsFlags |= PPosition;
+       }
+    }
+    WmUpdateGeom(wmPtr, winPtr);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmProtocolCmd --
+ *
+ *     This procedure is invoked to process the "wm protocol" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmProtocolCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    register ProtocolHandler *protPtr, *prevPtr;
+    Atom protocol;
+    char *cmd;
+    int cmdLength;
+
+    if ((objc < 3) || (objc > 5)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?name? ?command?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       /*
+        * Return a list of all defined protocols for the window.
+        */
+       for (protPtr = wmPtr->protPtr; protPtr != NULL;
+            protPtr = protPtr->nextPtr) {
+           Tcl_AppendElement(interp,
+                   Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
        }
-       if (argc == 3) {
-           if (wmPtr->icon != NULL) {
-               Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC);
+       return TCL_OK;
+    }
+    protocol = Tk_InternAtom((Tk_Window) winPtr, Tcl_GetString(objv[3]));
+    if (objc == 4) {
+       /*
+        * Return the command to handle a given protocol.
+        */
+       for (protPtr = wmPtr->protPtr; protPtr != NULL;
+            protPtr = protPtr->nextPtr) {
+           if (protPtr->protocol == protocol) {
+               Tcl_SetResult(interp, protPtr->command, TCL_STATIC);
+               return TCL_OK;
            }
-           return TCL_OK;
        }
-       if (*argv[3] == '\0') {
-           wmPtr->hints.flags &= ~IconWindowHint;
-           if (wmPtr->icon != NULL) {
-               /*
-                * Let the window use button events again, then remove
-                * it as icon window.
-                */
+       return TCL_OK;
+    }
 
-               atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
-                       | ButtonPressMask;
-               Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
-               wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
-               wmPtr2->iconFor = NULL;
-               wmPtr2->hints.initial_state = WithdrawnState;
-           }
-           wmPtr->icon = NULL;
-       } else {
-           tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
-           if (tkwin2 == NULL) {
-               return TCL_ERROR;
-           }
-           if (!Tk_IsTopLevel(tkwin2)) {
-               Tcl_AppendResult(interp, "can't use ", argv[3],
-                       " as icon window: not at top level", (char *) NULL);
-               return TCL_ERROR;
-           }
-           wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
-           if (wmPtr2->iconFor != NULL) {
-               Tcl_AppendResult(interp, argv[3], " is already an icon for ",
-                       Tk_PathName(wmPtr2->iconFor), (char *) NULL);
-               return TCL_ERROR;
+    /*
+     * Delete any current protocol handler, then create a new
+     * one with the specified command, unless the command is
+     * empty.
+     */
+
+    for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
+        prevPtr = protPtr, protPtr = protPtr->nextPtr) {
+       if (protPtr->protocol == protocol) {
+           if (prevPtr == NULL) {
+               wmPtr->protPtr = protPtr->nextPtr;
+           } else {
+               prevPtr->nextPtr = protPtr->nextPtr;
            }
-           if (wmPtr->icon != NULL) {
-               WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
-               wmPtr3->iconFor = NULL;
+           Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
+           break;
+       }
+    }
+    cmd = Tcl_GetStringFromObj(objv[4], &cmdLength);
+    if (cmdLength > 0) {
+       protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
+       protPtr->protocol = protocol;
+       protPtr->nextPtr = wmPtr->protPtr;
+       wmPtr->protPtr = protPtr;
+       protPtr->interp = interp;
+       strcpy(protPtr->command, cmd);
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmResizableCmd --
+ *
+ *     This procedure is invoked to process the "wm resizable" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
 
-               /*
-                * Let the window use button events again.
-                */
+static int
+WmResizableCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    int width, height;
 
-               atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
-                       | ButtonPressMask;
-               Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
-           }
+    if ((objc != 3) && (objc != 5)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       char buf[TCL_INTEGER_SPACE * 2];
 
-           /*
-            * Disable button events in the icon window:  some window
-            * managers (like olvwm) want to get the events themselves,
-            * but X only allows one application at a time to receive
-            * button events for a window.
-            */
+       sprintf(buf, "%d %d",
+               (wmPtr->flags  & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
+               (wmPtr->flags  & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
+       Tcl_SetResult(interp, buf, TCL_VOLATILE);
+       return TCL_OK;
+    }
+    if ((Tcl_GetBooleanFromObj(interp, objv[3], &width) != TCL_OK)
+           || (Tcl_GetBooleanFromObj(interp, objv[4], &height) != TCL_OK)) {
+       return TCL_ERROR;
+    }
+    if (width) {
+       wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
+    } else {
+       wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
+    }
+    if (height) {
+       wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
+    } else {
+       wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
+    }
+    if (!((wmPtr->flags & WM_NEVER_MAPPED)
+           && !(winPtr->flags & TK_EMBEDDED))) {
+       UpdateWrapper(winPtr);
+    }
+    WmUpdateGeom(wmPtr, winPtr);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmSizefromCmd --
+ *
+ *     This procedure is invoked to process the "wm sizefrom" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
 
-           atts.event_mask = Tk_Attributes(tkwin2)->event_mask
-                   & ~ButtonPressMask;
-           Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
-           Tk_MakeWindowExist(tkwin2);
-           wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
-           wmPtr->hints.flags |= IconWindowHint;
-           wmPtr->icon = tkwin2;
-           wmPtr2->iconFor = (Tk_Window) winPtr;
-           if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
-               if (XWithdrawWindow(Tk_Display(tkwin2), Tk_WindowId(tkwin2),
-                       Tk_ScreenNumber(tkwin2)) == 0) {
-                   Tcl_SetResult(interp,
-                           "couldn't send withdraw message to window manager",
-                           TCL_STATIC);
-                   return TCL_ERROR;
-               }
-           }
-       }
-    } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
-           && (length >= 2)) {
-       int width, height;
-       if ((argc != 3) && (argc != 5)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " maxsize window ?width height?\"",
-                    (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (argc == 3) {
-           char buf[TCL_INTEGER_SPACE * 2];
-           
-           GetMaxSize(wmPtr, &width, &height);
-           sprintf(buf, "%d %d", width, height);
-           Tcl_SetResult(interp, buf, TCL_VOLATILE);
-           return TCL_OK;
+static int
+WmSizefromCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    static CONST char *optionStrings[] = {
+       "program", "user", (char *) NULL };
+    enum options {
+       OPT_PROGRAM, OPT_USER };
+    int index;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?user|program?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (wmPtr->sizeHintsFlags & USSize) {
+           Tcl_SetResult(interp, "user", TCL_STATIC);
+       } else if (wmPtr->sizeHintsFlags & PSize) {
+           Tcl_SetResult(interp, "program", TCL_STATIC);
        }
-       if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
-               || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
+       return TCL_OK;
+    }
+
+    if (*Tcl_GetString(objv[3]) == '\0') {
+       wmPtr->sizeHintsFlags &= ~(USSize|PSize);
+    } else {
+       if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
+               &index) != TCL_OK) {
            return TCL_ERROR;
        }
-       wmPtr->maxWidth = width;
-       wmPtr->maxHeight = height;
-       goto updateGeom;
-    } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
-           && (length >= 2)) {
-       int width, height;
-       if ((argc != 3) && (argc != 5)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " minsize window ?width height?\"",
-                    (char *) NULL);
-           return TCL_ERROR;
+       if (index == OPT_USER) {
+           wmPtr->sizeHintsFlags &= ~PSize;
+           wmPtr->sizeHintsFlags |= USSize;
+       } else { /* OPT_PROGRAM */
+           wmPtr->sizeHintsFlags &= ~USSize;
+           wmPtr->sizeHintsFlags |= PSize;
        }
-       if (argc == 3) {
-           char buf[TCL_INTEGER_SPACE * 2];
-           
-           GetMinSize(wmPtr, &width, &height);
-           sprintf(buf, "%d %d", width, height);
-           Tcl_SetResult(interp, buf, TCL_VOLATILE);
+    }
+    WmUpdateGeom(wmPtr, winPtr);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmStackorderCmd --
+ *
+ *     This procedure is invoked to process the "wm stackorder" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmStackorderCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    TkWindow **windows, **window_ptr;
+    static CONST char *optionStrings[] = {
+       "isabove", "isbelow", (char *) NULL };
+    enum options {
+       OPT_ISABOVE, OPT_ISBELOW };
+    int index;
+
+    if ((objc != 3) && (objc != 5)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?isabove|isbelow window?");
+       return TCL_ERROR;
+    }
+
+    if (objc == 3) {
+       windows = TkWmStackorderToplevel(winPtr);
+       if (windows == NULL) {
+           panic("TkWmStackorderToplevel failed");
+       } else {
+           for (window_ptr = windows; *window_ptr ; window_ptr++) {
+               Tcl_AppendElement(interp, (*window_ptr)->pathName);
+           }
+           ckfree((char *) windows);
            return TCL_OK;
        }
-       if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
-               || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
-           return TCL_ERROR;
-       }
-       wmPtr->minWidth = width;
-       wmPtr->minHeight = height;
-       goto updateGeom;
-    } else if ((c == 'o')
-           && (strncmp(argv[1], "overrideredirect", length) == 0)) {
-       int boolean, curValue;
-       XSetWindowAttributes atts;
-
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " overrideredirect window ?boolean?\"",
-                   (char *) NULL);
+    } else {
+       TkWindow *winPtr2;
+       int index1=-1, index2=-1, result;
+
+       if (TkGetWindowFromObj(interp, tkwin, objv[4], (Tk_Window *) &winPtr2)
+               != TCL_OK) {
            return TCL_ERROR;
        }
-       curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect;
-       if (argc == 3) {
-           Tcl_SetBooleanObj(Tcl_GetObjResult(interp), curValue);
-           return TCL_OK;
-       }
-       if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) {
+
+       if (!Tk_IsTopLevel(winPtr2)) {
+           Tcl_AppendResult(interp, "window \"", winPtr2->pathName,
+                   "\" isn't a top-level window", (char *) NULL);
            return TCL_ERROR;
        }
-       if (curValue != boolean) {
-           /*
-            * Only do this if we are really changing value, because it
-            * causes some funky stuff to occur
-            */
-           atts.override_redirect = (boolean) ? True : False;
-           Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
-                   &atts);
-           if (!(wmPtr->flags & (WM_NEVER_MAPPED)
-                   && !(winPtr->flags & TK_EMBEDDED))) {
-               UpdateWrapper(winPtr);
-           }
-       }
-    } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
-           && (length >= 2)) {
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " positionfrom window ?user/program?\"",
-                   (char *) NULL);
+
+       if (!Tk_IsMapped(winPtr)) {
+           Tcl_AppendResult(interp, "window \"", winPtr->pathName,
+                   "\" isn't mapped", (char *) NULL);
            return TCL_ERROR;
        }
-       if (argc == 3) {
-           if (wmPtr->sizeHintsFlags & USPosition) {
-               Tcl_SetResult(interp, "user", TCL_STATIC);
-           } else if (wmPtr->sizeHintsFlags & PPosition) {
-               Tcl_SetResult(interp, "program", TCL_STATIC);
-           }
-           return TCL_OK;
-       }
-       if (*argv[3] == '\0') {
-           wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
-       } else {
-           c = argv[3][0];
-           length = strlen(argv[3]);
-           if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
-               wmPtr->sizeHintsFlags &= ~PPosition;
-               wmPtr->sizeHintsFlags |= USPosition;
-           } else if ((c == 'p')
-                    && (strncmp(argv[3], "program", length) == 0)) {
-               wmPtr->sizeHintsFlags &= ~USPosition;
-               wmPtr->sizeHintsFlags |= PPosition;
-           } else {
-               Tcl_AppendResult(interp, "bad argument \"", argv[3],
-                       "\": must be program or user", (char *) NULL);
-               return TCL_ERROR;
-           }
-       }
-       goto updateGeom;
-    } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)
-           && (length >= 2)) {
-       register ProtocolHandler *protPtr, *prevPtr;
-       Atom protocol;
-       int cmdLength;
 
-       if ((argc < 3) || (argc > 5)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " protocol window ?name? ?command?\"",
-                   (char *) NULL);
+       if (!Tk_IsMapped(winPtr2)) {
+           Tcl_AppendResult(interp, "window \"", winPtr2->pathName,
+                   "\" isn't mapped", (char *) NULL);
            return TCL_ERROR;
        }
-       if (argc == 3) {
-           /*
-            * Return a list of all defined protocols for the window.
-            */
-           for (protPtr = wmPtr->protPtr; protPtr != NULL;
-                   protPtr = protPtr->nextPtr) {
-               Tcl_AppendElement(interp,
-                       Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
-           }
-           return TCL_OK;
-       }
-       protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
-       if (argc == 4) {
-           /*
-            * Return the command to handle a given protocol.
-            */
-           for (protPtr = wmPtr->protPtr; protPtr != NULL;
-                   protPtr = protPtr->nextPtr) {
-               if (protPtr->protocol == protocol) {
-                   Tcl_SetResult(interp, protPtr->command, TCL_STATIC);
-                   return TCL_OK;
-               }
-           }
-           return TCL_OK;
-       }
 
        /*
-        * Delete any current protocol handler, then create a new
-        * one with the specified command, unless the command is
-        * empty.
+        * Lookup stacking order of all toplevels that are children
+        * of "." and find the position of winPtr and winPtr2
+        * in the stacking order.
         */
 
-       for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
-               prevPtr = protPtr, protPtr = protPtr->nextPtr) {
-           if (protPtr->protocol == protocol) {
-               if (prevPtr == NULL) {
-                   wmPtr->protPtr = protPtr->nextPtr;
-               } else {
-                   prevPtr->nextPtr = protPtr->nextPtr;
-               }
-               Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
-               break;
+       windows = TkWmStackorderToplevel(winPtr->mainPtr->winPtr);
+
+       if (windows == NULL) {
+           Tcl_AppendResult(interp, "TkWmStackorderToplevel failed",
+                    (char *) NULL);
+           return TCL_ERROR;
+       } else {
+           for (window_ptr = windows; *window_ptr ; window_ptr++) {
+               if (*window_ptr == winPtr)
+                   index1 = (window_ptr - windows);
+               if (*window_ptr == winPtr2)
+                   index2 = (window_ptr - windows);
            }
+           if (index1 == -1)
+               panic("winPtr window not found");
+           if (index2 == -1)
+               panic("winPtr2 window not found");
+
+           ckfree((char *) windows);
        }
-       cmdLength = strlen(argv[4]);
-       if (cmdLength > 0) {
-           protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
-           protPtr->protocol = protocol;
-           protPtr->nextPtr = wmPtr->protPtr;
-           wmPtr->protPtr = protPtr;
-           protPtr->interp = interp;
-           strcpy(protPtr->command, argv[4]);
-       }
-    } else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) {
-       int width, height;
 
-       if ((argc != 3) && (argc != 5)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " resizable window ?width height?\"",
-                   (char *) NULL);
+       if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
+               &index) != TCL_OK) {
            return TCL_ERROR;
        }
-       if (argc == 3) {
-           char buf[TCL_INTEGER_SPACE * 2];
-           
-           sprintf(buf, "%d %d",
-                   (wmPtr->flags  & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
-                   (wmPtr->flags  & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
-           Tcl_SetResult(interp, buf, TCL_VOLATILE);
-           return TCL_OK;
+       if (index == OPT_ISABOVE) {
+           result = index1 > index2;
+       } else { /* OPT_ISBELOW */
+           result = index1 < index2;
        }
-       if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
-               || (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) {
+       Tcl_SetIntObj(Tcl_GetObjResult(interp), result);
+       return TCL_OK;
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmStateCmd --
+ *
+ *     This procedure is invoked to process the "wm state" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmStateCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    static CONST char *optionStrings[] = {
+       "normal", "iconic", "withdrawn", "zoomed", (char *) NULL };
+    enum options {
+       OPT_NORMAL, OPT_ICONIC, OPT_WITHDRAWN, OPT_ZOOMED };
+    int index;
+
+    if ((objc < 3) || (objc > 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?state?");
+       return TCL_ERROR;
+    }
+    if (objc == 4) {
+       if (wmPtr->iconFor != NULL) {
+           Tcl_AppendResult(interp, "can't change state of ",
+                   Tcl_GetString(objv[2]),
+                   ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
+                   (char *) NULL);
            return TCL_ERROR;
        }
-       if (width) {
-           wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
-       } else {
-           wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
-       }
-       if (height) {
-           wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
-       } else {
-           wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
-       }
-       if (!((wmPtr->flags & WM_NEVER_MAPPED)
-               && !(winPtr->flags & TK_EMBEDDED))) {
-           UpdateWrapper(winPtr);
-       }
-       goto updateGeom;
-    } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
-           && (length >= 2)) {
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " sizefrom window ?user|program?\"",
+       if (winPtr->flags & TK_EMBEDDED) {
+           Tcl_AppendResult(interp, "can't change state of ",
+                   winPtr->pathName, ": it is an embedded window",
                    (char *) NULL);
            return TCL_ERROR;
        }
-       if (argc == 3) {
-           if (wmPtr->sizeHintsFlags & USSize) {
-               Tcl_SetResult(interp, "user", TCL_STATIC);
-           } else if (wmPtr->sizeHintsFlags & PSize) {
-               Tcl_SetResult(interp, "program", TCL_STATIC);
-           }
-           return TCL_OK;
-       }
-       if (*argv[3] == '\0') {
-           wmPtr->sizeHintsFlags &= ~(USSize|PSize);
-       } else {
-           c = argv[3][0];
-           length = strlen(argv[3]);
-           if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
-               wmPtr->sizeHintsFlags &= ~PSize;
-               wmPtr->sizeHintsFlags |= USSize;
-           } else if ((c == 'p')
-                   && (strncmp(argv[3], "program", length) == 0)) {
-               wmPtr->sizeHintsFlags &= ~USSize;
-               wmPtr->sizeHintsFlags |= PSize;
-           } else {
-               Tcl_AppendResult(interp, "bad argument \"", argv[3],
-                       "\": must be program or user", (char *) NULL);
-               return TCL_ERROR;
-           }
-       }
-       goto updateGeom;
-    } else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
-           && (length >= 2)) {
-       if ((argc < 3) || (argc > 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " state window ?state?\"", (char *) NULL);
+
+       if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
+               &index) != TCL_OK) {
            return TCL_ERROR;
        }
-       if (argc == 4) {
-           if (wmPtr->iconFor != NULL) {
-               Tcl_AppendResult(interp, "can't change state of ", argv[2],
-                       ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
-                       (char *) NULL);
-               return TCL_ERROR;
+
+       if (index == OPT_NORMAL) {
+           if (wmPtr->flags & WM_TRANSIENT_WITHDRAWN) {
+               wmPtr->flags &= ~WM_TRANSIENT_WITHDRAWN;
            }
-           if (winPtr->flags & TK_EMBEDDED) {
-               Tcl_AppendResult(interp, "can't change state of ",
-                       winPtr->pathName, ": it is an embedded window",
+           TkpWmSetState(winPtr, NormalState);
+           /*
+            * This varies from 'wm deiconify' because it does not
+            * force the window to be raised and receive focus
+            */
+       } else if (index == OPT_ICONIC) {
+           if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
+               Tcl_AppendResult(interp, "can't iconify \"",
+                       winPtr->pathName,
+                       "\": override-redirect flag is set",
                        (char *) NULL);
                return TCL_ERROR;
            }
-
-           c = argv[3][0];
-           length = strlen(argv[3]);
-
-           if ((c == 'n') && (strncmp(argv[3], "normal", length) == 0)) {
-               TkpWmSetState(winPtr, NormalState);
-               /*
-                * This varies from 'wm deiconify' because it does not
-                * force the window to be raised and receive focus
-                */
-           } else if ((c == 'i')
-                   && (strncmp(argv[3], "iconic", length) == 0)) {
-               if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
-                   Tcl_AppendResult(interp, "can't iconify \"",
-                           winPtr->pathName,
-                           "\": override-redirect flag is set",
-                           (char *) NULL);
-                   return TCL_ERROR;
-               }
-               if (wmPtr->masterPtr != NULL) {
-                   Tcl_AppendResult(interp, "can't iconify \"",
-                           winPtr->pathName,
-                           "\": it is a transient", (char *) NULL);
-                   return TCL_ERROR;
-               }
-               TkpWmSetState(winPtr, IconicState);
-           } else if ((c == 'w')
-                   && (strncmp(argv[3], "withdrawn", length) == 0)) {
-               TkpWmSetState(winPtr, WithdrawnState);
-           } else if ((c == 'z')
-                   && (strncmp(argv[3], "zoomed", length) == 0)) {
-               TkpWmSetState(winPtr, ZoomState);
-           } else {
-               Tcl_AppendResult(interp, "bad argument \"", argv[3],
-                       "\": must be normal, iconic, withdrawn or zoomed",
-                       (char *) NULL);
+           if (wmPtr->masterPtr != NULL) {
+               Tcl_AppendResult(interp, "can't iconify \"",
+                       winPtr->pathName,
+                       "\": it is a transient", (char *) NULL);
                return TCL_ERROR;
            }
-       } else {
-           if (wmPtr->iconFor != NULL) {
-               Tcl_SetResult(interp, "icon", TCL_STATIC);
-           } else {
-               switch (wmPtr->hints.initial_state) {
-                   case NormalState:
-                       Tcl_SetResult(interp, "normal", TCL_STATIC);
-                       break;
-                   case IconicState:
-                       Tcl_SetResult(interp, "iconic", TCL_STATIC);
-                       break;
-                   case WithdrawnState:
-                       Tcl_SetResult(interp, "withdrawn", TCL_STATIC);
-                       break;
-                   case ZoomState:
-                       Tcl_SetResult(interp, "zoomed", TCL_STATIC);
-                       break;
-               }
+           TkpWmSetState(winPtr, IconicState);
+       } else if (index == OPT_WITHDRAWN) {
+           if (wmPtr->masterPtr != NULL) {
+               wmPtr->flags |= WM_TRANSIENT_WITHDRAWN;
            }
+           TkpWmSetState(winPtr, WithdrawnState);
+       } else { /* OPT_ZOOMED */
+           TkpWmSetState(winPtr, ZoomState);
        }
-    } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
-           && (length >= 2)) {
-       if (argc > 4) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " title window ?newTitle?\"", (char *) NULL);
-           return TCL_ERROR;
-       }
-       if (argc == 3) {
-           Tcl_SetResult(interp, ((wmPtr->titleUid != NULL) ?
-                   wmPtr->titleUid : winPtr->nameUid), TCL_STATIC);
-           return TCL_OK;
+    } else {
+       if (wmPtr->iconFor != NULL) {
+           Tcl_SetResult(interp, "icon", TCL_STATIC);
        } else {
-           wmPtr->titleUid = Tk_GetUid(argv[3]);
-           if (!(wmPtr->flags & WM_NEVER_MAPPED) && wmPtr->wrapper != NULL) {
-               Tcl_DString titleString;
-               Tcl_UtfToExternalDString(NULL, wmPtr->titleUid, -1, 
-                       &titleString);
-               SetWindowText(wmPtr->wrapper, Tcl_DStringValue(&titleString));
-               Tcl_DStringFree(&titleString);
+           switch (wmPtr->hints.initial_state) {
+             case NormalState:
+               Tcl_SetResult(interp, "normal", TCL_STATIC);
+               break;
+             case IconicState:
+               Tcl_SetResult(interp, "iconic", TCL_STATIC);
+               break;
+             case WithdrawnState:
+               Tcl_SetResult(interp, "withdrawn", TCL_STATIC);
+               break;
+             case ZoomState:
+               Tcl_SetResult(interp, "zoomed", TCL_STATIC);
+               break;
            }
        }
-    } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
-           && (length >= 3)) {
-       TkWindow *masterPtr = wmPtr->masterPtr;
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmTitleCmd --
+ *
+ *     This procedure is invoked to process the "wm title" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmTitleCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    char *argv3;
+    int length;
+
+    if (objc > 4) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?newTitle?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       Tcl_SetResult(interp, (char *)
+               ((wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid),
+               TCL_STATIC);
+       return TCL_OK;
+    } else {
+       if (wmPtr->title != NULL) {
+           ckfree((char *) wmPtr->title);
+       }
+       argv3 = Tcl_GetStringFromObj(objv[3], &length);
+       wmPtr->title = ckalloc((unsigned) (length + 1));
+       strcpy(wmPtr->title, argv3);
 
-       if ((argc != 3) && (argc != 4)) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " transient window ?master?\"", (char *) NULL);
-           return TCL_ERROR;
+       if (!(wmPtr->flags & WM_NEVER_MAPPED) && wmPtr->wrapper != NULL) {
+           Tcl_DString titleString;
+           Tcl_WinUtfToTChar(wmPtr->title, -1, &titleString);
+           (*tkWinProcs->setWindowText)(wmPtr->wrapper,
+                   (LPCTSTR) Tcl_DStringValue(&titleString));
+           Tcl_DStringFree(&titleString);
        }
-       if (argc == 3) {
-           if (masterPtr != NULL) {
-               Tcl_SetResult(interp, Tk_PathName(masterPtr), TCL_STATIC);
-           }
-           return TCL_OK;
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmTransientCmd --
+ *
+ *     This procedure is invoked to process the "wm transient" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmTransientCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+    TkWindow *masterPtr = wmPtr->masterPtr;
+    WmInfo *wmPtr2;
+
+    if ((objc != 3) && (objc != 4)) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window ?master?");
+       return TCL_ERROR;
+    }
+    if (objc == 3) {
+       if (masterPtr != NULL) {
+           Tcl_SetResult(interp, Tk_PathName(masterPtr), TCL_STATIC);
        }
+       return TCL_OK;
+    }
+    if (Tcl_GetString(objv[3])[0] == '\0') {
        if (masterPtr != NULL) {
            /*
             * If we had a master, tell them that we aren't tied
             * to them anymore
             */
+
            masterPtr->wmInfoPtr->numTransients--;
            Tk_DeleteEventHandler((Tk_Window) masterPtr,
-                   VisibilityChangeMask,
-                   WmWaitVisibilityProc, (ClientData) winPtr);
+                   VisibilityChangeMask|StructureNotifyMask,
+                   WmWaitVisibilityOrMapProc, (ClientData) winPtr);
        }
-       if (argv[3][0] == '\0') {
-           wmPtr->masterPtr = NULL;
-       } else {
-           masterPtr = (TkWindow*) Tk_NameToWindow(interp, argv[3], tkwin);
-           if (masterPtr == NULL) {
-               return TCL_ERROR;
-           }
-           if (masterPtr == winPtr) {
-               wmPtr->masterPtr = NULL;
-           } else if (masterPtr != wmPtr->masterPtr) {
-               Tk_MakeWindowExist((Tk_Window)masterPtr);
-
-               /*
-                * Ensure that the master window is actually a Tk toplevel.
-                */
-
-               while (!(masterPtr->flags & TK_TOP_LEVEL)) {
-                   masterPtr = masterPtr->parentPtr;
-               }
-               wmPtr->masterPtr = masterPtr;
-               masterPtr->wmInfoPtr->numTransients++;
 
-               /*
-                * Bind a visibility event handler to the master window,
-                * to ensure that when it is mapped, the children will
-                * have their state set properly.
-                */
+       wmPtr->masterPtr = NULL;
+    } else {
+       if (TkGetWindowFromObj(interp, tkwin, objv[3],
+               (Tk_Window *) &masterPtr) != TCL_OK) {
+           return TCL_ERROR;
+       }
+       while (!Tk_TopWinHierarchy(masterPtr)) {
+           /*
+            * Ensure that the master window is actually a Tk toplevel.
+            */
 
-               Tk_CreateEventHandler((Tk_Window) masterPtr,
-                       VisibilityChangeMask,
-                       WmWaitVisibilityProc, (ClientData) winPtr);
-           }
+           masterPtr = masterPtr->parentPtr;
        }
-       if (!((wmPtr->flags & WM_NEVER_MAPPED)
-               && !(winPtr->flags & TK_EMBEDDED))) {
-           UpdateWrapper(winPtr);
+       Tk_MakeWindowExist((Tk_Window) masterPtr);
+
+       if (wmPtr->iconFor != NULL) {
+           Tcl_AppendResult(interp, "can't make \"",
+                   Tcl_GetString(objv[2]),
+                   "\" a transient: it is an icon for ",
+                   Tk_PathName(wmPtr->iconFor),
+                   (char *) NULL);
+           return TCL_ERROR;
        }
-    } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
-       if (argc != 3) {
-           Tcl_AppendResult(interp, "wrong # arguments: must be \"",
-                   argv[0], " withdraw window\"", (char *) NULL);
+
+       wmPtr2 = masterPtr->wmInfoPtr;
+
+       if (wmPtr2->iconFor != NULL) {
+           Tcl_AppendResult(interp, "can't make \"",
+                   Tcl_GetString(objv[3]),
+                   "\" a master: it is an icon for ",
+                   Tk_PathName(wmPtr2->iconFor),
+                   (char *) NULL);
            return TCL_ERROR;
        }
-       if (wmPtr->iconFor != NULL) {
-           Tcl_AppendResult(interp, "can't withdraw ", argv[2],
-                   ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
+
+       if (masterPtr == winPtr) {
+           Tcl_AppendResult(interp, "can't make \"", Tk_PathName(winPtr),
+                   "\" its own master",
                    (char *) NULL);
            return TCL_ERROR;
+       } else if (masterPtr != wmPtr->masterPtr) {
+           /*
+            * Remove old master map/unmap binding before setting
+            * the new master. The event handler will ensure that
+            * transient states reflect the state of the master.
+            */
+
+           if (wmPtr->masterPtr != NULL) {
+               wmPtr->masterPtr->wmInfoPtr->numTransients--;
+               Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
+                       VisibilityChangeMask|StructureNotifyMask,
+                       WmWaitVisibilityOrMapProc, (ClientData) winPtr);
+           }
+
+           masterPtr->wmInfoPtr->numTransients++;
+           Tk_CreateEventHandler((Tk_Window) masterPtr,
+                   VisibilityChangeMask|StructureNotifyMask,
+                   WmWaitVisibilityOrMapProc, (ClientData) winPtr);
+
+           wmPtr->masterPtr = masterPtr;
        }
-       TkpWmSetState(winPtr, WithdrawnState);
-    } else {
-       Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
-               "\": must be aspect, client, command, deiconify, ",
-               "focusmodel, frame, geometry, grid, group, iconbitmap, ",
-               "iconify, iconmask, iconname, iconposition, ",
-               "iconwindow, maxsize, minsize, overrideredirect, ",
-               "positionfrom, protocol, resizable, sizefrom, state, title, ",
-               "transient, or withdraw",
+    }
+    if (!((wmPtr->flags & WM_NEVER_MAPPED)
+           && !(winPtr->flags & TK_EMBEDDED))) {
+       if (wmPtr->masterPtr != NULL &&
+               !Tk_IsMapped(wmPtr->masterPtr)) {
+           TkpWmSetState(winPtr, WithdrawnState);
+       } else {
+           UpdateWrapper(winPtr);
+       }
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * WmWithdrawCmd --
+ *
+ *     This procedure is invoked to process the "wm withdraw" Tcl command.
+ *     See the user documentation for details on what it does.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+WmWithdrawCmd(tkwin, winPtr, interp, objc, objv)
+    Tk_Window tkwin;           /* Main window of the application. */
+    TkWindow *winPtr;           /* Toplevel to work with */
+    Tcl_Interp *interp;                /* Current interpreter. */
+    int objc;                  /* Number of arguments. */
+    Tcl_Obj *CONST objv[];     /* Argument objects. */
+{
+    register WmInfo *wmPtr = winPtr->wmInfoPtr;
+
+    if (objc != 3) {
+       Tcl_WrongNumArgs(interp, 2, objv, "window");
+       return TCL_ERROR;
+    }
+    if (wmPtr->iconFor != NULL) {
+       Tcl_AppendResult(interp, "can't withdraw ", Tcl_GetString(objv[2]),
+               ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
                (char *) NULL);
        return TCL_ERROR;
     }
+    if (wmPtr->masterPtr != NULL) {
+       wmPtr->flags |= WM_TRANSIENT_WITHDRAWN;
+    }
+    TkpWmSetState(winPtr, WithdrawnState);
     return TCL_OK;
+}
 
-    updateGeom:
+/*
+ * Invoked by those wm subcommands that affect geometry.
+ * Schedules a geometry update.
+ */
+static void
+WmUpdateGeom(wmPtr, winPtr)
+    WmInfo *wmPtr;
+    TkWindow *winPtr;
+{
     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
        Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
        wmPtr->flags |= WM_UPDATE_PENDING;
     }
-    return TCL_OK;
 }
+
        /*ARGSUSED*/
 static void
-WmWaitVisibilityProc(clientData, eventPtr)
+WmWaitVisibilityOrMapProc(clientData, eventPtr)
     ClientData clientData;     /* Pointer to window. */
     XEvent *eventPtr;          /* Information about event. */
 {
     TkWindow *winPtr = (TkWindow *) clientData;
     TkWindow *masterPtr = winPtr->wmInfoPtr->masterPtr;
 
-    if ((eventPtr->type == VisibilityNotify) && (masterPtr != NULL)) {
+    if (masterPtr == NULL)
+       return;
+
+    if (eventPtr->type == MapNotify) {
+       if (!(winPtr->wmInfoPtr->flags & WM_TRANSIENT_WITHDRAWN))
+           TkpWmSetState(winPtr, NormalState);
+    } else if (eventPtr->type == UnmapNotify) {
+       TkpWmSetState(winPtr, WithdrawnState);
+    }
+
+    if (eventPtr->type == VisibilityNotify) {
        int state = masterPtr->wmInfoPtr->hints.initial_state;
 
        if ((state == NormalState) || (state == ZoomState)) {
@@ -2401,10 +4784,13 @@ Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
      * information.
      */
 
-    while (!(winPtr->flags & TK_TOP_LEVEL)) {
+    while (!(winPtr->flags & TK_TOP_HIERARCHY)) {
        winPtr = winPtr->parentPtr;
     }
     wmPtr = winPtr->wmInfoPtr;
+    if (wmPtr == NULL) {
+       return;
+    }
 
     if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
        return;
@@ -2436,7 +4822,7 @@ Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
        wmPtr->height = -1;
     }
 
-    /* 
+    /*
      * Set the new gridding information, and start the process of passing
      * all of this information to the window manager.
      */
@@ -2485,10 +4871,14 @@ Tk_UnsetGrid(tkwin)
      * information.
      */
 
-    while (!(winPtr->flags & TK_TOP_LEVEL)) {
+    while (!(winPtr->flags & TK_TOP_HIERARCHY)) {
        winPtr = winPtr->parentPtr;
     }
     wmPtr = winPtr->wmInfoPtr;
+    if (wmPtr == NULL) {
+       return;
+    }
+
     if (tkwin != wmPtr->gridWin) {
        return;
     }
@@ -2546,7 +4936,7 @@ TopLevelEventProc(clientData, eventPtr)
             * Tk_DestroyWindow will try to destroy the window, but of course
             * it's already gone.
             */
-    
+
            handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
                    (Tk_ErrorProc *) NULL, (ClientData) NULL);
            Tk_DestroyWindow((Tk_Window) winPtr);
@@ -2593,7 +4983,7 @@ TopLevelReqProc(dummy, tkwin)
     WmInfo *wmPtr;
 
     wmPtr = winPtr->wmInfoPtr;
-    if (winPtr->flags & TK_EMBEDDED) {
+    if ((winPtr->flags & TK_EMBEDDED) && (wmPtr->wrapper != NULL)) {
        SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ, Tk_ReqWidth(tkwin),
            Tk_ReqHeight(tkwin));
     }
@@ -2751,7 +5141,7 @@ UpdateGeometryInfo(clientData)
 
     wmPtr->configWidth = width;
     wmPtr->configHeight = height;
-           
+
     /*
      * Don't bother moving the window if we are in the process of
      * creating it.  Just update the geometry info based on what
@@ -2818,7 +5208,7 @@ UpdateGeometryInfo(clientData)
 
            GetClientRect(wmPtr->wrapper, &windowRect);
            newHeight = windowRect.bottom - windowRect.top;
-           
+
            if (newHeight == height) {
                /*
                 * We're done.
@@ -3219,7 +5609,7 @@ TkWmProtocolEventProc(winPtr, eventPtr)
             * Cache atom name, as we might destroy the window as a
             * result of the eval.
             */
-           char *name = Tk_GetAtomName((Tk_Window) winPtr, protocol);
+           CONST char *name = Tk_GetAtomName((Tk_Window) winPtr, protocol);
 
            Tcl_Preserve((ClientData) protPtr);
             interp = protPtr->interp;
@@ -3250,6 +5640,173 @@ TkWmProtocolEventProc(winPtr, eventPtr)
 /*
  *----------------------------------------------------------------------
  *
+ * TkWmStackorderToplevelEnumProc --
+ *
+ *     This procedure is invoked once for each HWND Window on the
+ *     display as a result of calling EnumWindows from
+ *     TkWmStackorderToplevel.
+ *
+ * Results:
+ *     TRUE to request further iteration.
+ *
+ * Side effects:
+ *     Adds entries to the passed array of TkWindows.
+ *
+ *----------------------------------------------------------------------
+ */
+
+BOOL CALLBACK TkWmStackorderToplevelEnumProc(hwnd, lParam)
+    HWND hwnd;     /* handle to parent window */
+    LPARAM lParam; /* application-defined value */
+{
+    Tcl_HashEntry *hPtr;
+    TkWindow *childWinPtr;
+
+    TkWmStackorderToplevelPair *pair =
+        (TkWmStackorderToplevelPair *) lParam;
+
+    /*fprintf(stderr, "Looking up HWND %d\n", hwnd);*/
+
+    hPtr = Tcl_FindHashEntry(pair->table, (char *) hwnd);
+    if (hPtr != NULL) {
+        childWinPtr = (TkWindow *) Tcl_GetHashValue(hPtr);
+        /* Double check that same HWND does not get passed twice */
+        if (childWinPtr == NULL) {
+            panic("duplicate HWND in TkWmStackorderToplevelEnumProc");
+        } else {
+            Tcl_SetHashValue(hPtr, NULL);
+        }
+        /*fprintf(stderr, "Found mapped HWND %d -> %x (%s)\n", hwnd,
+         childWinPtr, childWinPtr->pathName);*/
+        *(pair->window_ptr)-- = childWinPtr;
+    }
+    return TRUE;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkWmStackorderToplevelWrapperMap --
+ *
+ *     This procedure will create a table that maps the wrapper
+ *     HWND id for a toplevel to the TkWindow structure that is wraps.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Adds entries to the passed hashtable.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+TkWmStackorderToplevelWrapperMap(winPtr, table)
+    TkWindow *winPtr;                          /* TkWindow to recurse on */
+    Tcl_HashTable *table;              /* Table to maps HWND to TkWindow */
+{
+    TkWindow *childPtr;
+    Tcl_HashEntry *hPtr;
+    HWND wrapper;
+    int newEntry;
+
+    if (Tk_IsMapped(winPtr) && Tk_IsTopLevel(winPtr) &&
+            !Tk_IsEmbedded(winPtr)) {
+        wrapper = TkWinGetWrapperWindow((Tk_Window) winPtr);
+
+        /*fprintf(stderr, "Mapped HWND %d to %x (%s)\n", wrapper,
+         winPtr, winPtr->pathName);*/
+
+        hPtr = Tcl_CreateHashEntry(table,
+            (char *) wrapper, &newEntry);
+        Tcl_SetHashValue(hPtr, winPtr);
+    }
+
+    for (childPtr = winPtr->childList; childPtr != NULL;
+            childPtr = childPtr->nextPtr) {
+        TkWmStackorderToplevelWrapperMap(childPtr, table);
+    }
+}
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkWmStackorderToplevel --
+ *
+ *     This procedure returns the stack order of toplevel windows.
+ *
+ * Results:
+ *     An array of pointers to tk window objects in stacking order
+ *     or else NULL if there was an error.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+TkWindow **
+TkWmStackorderToplevel(parentPtr)
+    TkWindow *parentPtr;               /* Parent toplevel window. */
+{
+    TkWmStackorderToplevelPair pair;
+    TkWindow **windows;
+    Tcl_HashTable table;
+    Tcl_HashEntry *hPtr;
+    Tcl_HashSearch search;
+
+    /*
+     * Map HWND ids to a TkWindow of the wrapped toplevel.
+     */
+
+    Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS);
+    TkWmStackorderToplevelWrapperMap(parentPtr, &table);
+
+    windows = (TkWindow **) ckalloc((table.numEntries+1)
+        * sizeof(TkWindow *));
+
+    /*
+     * Special cases: If zero or one toplevels were mapped
+     * there is no need to call EnumWindows.
+     */
+
+    switch (table.numEntries) {
+    case 0:
+        windows[0] = NULL;
+        goto done;
+    case 1:
+        hPtr = Tcl_FirstHashEntry(&table, &search);
+        windows[0] = (TkWindow *) Tcl_GetHashValue(hPtr);
+        windows[1] = NULL;
+        goto done;
+    }
+
+    /*
+     * We will be inserting into the array starting at the end
+     * and working our way to the beginning since EnumWindows
+     * returns windows in highest to lowest order.
+     */
+
+    pair.table = &table;
+    pair.window_ptr = windows + table.numEntries;
+    *pair.window_ptr-- = NULL;
+
+    if (EnumWindows((WNDENUMPROC) TkWmStackorderToplevelEnumProc,
+           (LPARAM) &pair) == 0) {
+        ckfree((char *) windows);
+        windows = NULL;
+    } else {
+        if (pair.window_ptr != (windows-1))
+            panic("num matched toplevel windows does not equal num children");
+    }
+
+    done:
+    Tcl_DeleteHashTable(&table);
+    return windows;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
  * TkWmRestackToplevel --
  *
  *     This procedure restacks a top-level window.
@@ -3350,10 +5907,14 @@ TkWmAddToColormapWindows(winPtr)
 
            return;
        }
-       if (topPtr->flags & TK_TOP_LEVEL) {
+       if (topPtr->flags & TK_TOP_HIERARCHY) {
            break;
        }
     }
+    if (topPtr->wmInfoPtr == NULL) {
+       return;
+    }
+
     if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
        return;
     }
@@ -3457,6 +6018,10 @@ TkWmRemoveFromColormapWindows(winPtr)
        return;
     }
 
+    if (topPtr->wmInfoPtr == NULL) {
+       return;
+    }
+
     /*
      * Find the window and slide the following ones down to cover
      * it up.
@@ -3545,7 +6110,7 @@ ConfigureTopLevel(pos)
     int state;                 /* Current window state. */
     RECT rect;
     WINDOWPLACEMENT windowPos;
-    
+
     if (winPtr == NULL) {
        return;
     }
@@ -3636,7 +6201,7 @@ ConfigureTopLevel(pos)
 
     if (state == NormalState) {
 
-       /* 
+       /*
         * Update size information from the event.  There are a couple of
         * tricky points here:
         *
@@ -3699,9 +6264,9 @@ ConfigureTopLevel(pos)
                wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
            }
        }
-   
+
        /*
-        * Update the wrapper window location information. 
+        * Update the wrapper window location information.
         */
 
        if (wmPtr->flags & WM_NEGATIVE_X) {
@@ -3794,9 +6359,9 @@ InstallColormaps(hwnd, message, isForemost)
     HPALETTE oldPalette;
     TkWindow *winPtr = GetTopLevel(hwnd);
     WmInfo *wmPtr;
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-           
+
     if (winPtr == NULL) {
        return 0;
     }
@@ -3956,10 +6521,10 @@ InvalidateSubTree(winPtr, colormap)
            childPtr = childPtr->nextPtr) {
        /*
         * We can stop the descent when we hit an unmapped or
-        * toplevel window.  
+        * toplevel window.
         */
 
-       if (!Tk_IsTopLevel(childPtr) && Tk_IsMapped(childPtr)) {
+       if (!Tk_TopWinHierarchy(childPtr) && Tk_IsMapped(childPtr)) {
            InvalidateSubTree(childPtr, colormap);
        }
     }
@@ -3985,7 +6550,7 @@ InvalidateSubTree(winPtr, colormap)
 HPALETTE
 TkWinGetSystemPalette()
 {
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
 
     return tsdPtr->systemPalette;
@@ -4160,7 +6725,7 @@ TopLevelProc(hwnd, message, wParam, lParam)
     if (message == WM_WINDOWPOSCHANGED) {
        WINDOWPOS *pos = (WINDOWPOS *) lParam;
        TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(pos->hwnd);
-    
+
        if (winPtr == NULL) {
            return 0;
        }
@@ -4211,7 +6776,7 @@ WmProc(hwnd, message, wParam, lParam)
     LPARAM lParam;
 {
     static int inMoveSize = 0;
-    static oldMode;    /* This static is set upon entering move/size mode
+    static int oldMode;        /* This static is set upon entering move/size mode
                         * and is used to reset the service mode after
                         * leaving move/size mode.  Note that this mechanism
                         * assumes move/size is only one level deep. */
@@ -4250,7 +6815,7 @@ WmProc(hwnd, message, wParam, lParam)
            }
            break;
 
-       case WM_GETMINMAXINFO: 
+       case WM_GETMINMAXINFO:
            SetLimits(hwnd, (MINMAXINFO *) lParam);
            result = 0;
            goto done;
@@ -4263,7 +6828,7 @@ WmProc(hwnd, message, wParam, lParam)
        case WM_QUERYNEWPALETTE:
            result = InstallColormaps(hwnd, WM_QUERYNEWPALETTE, TRUE);
            goto done;
-           
+
        case WM_WINDOWPOSCHANGED:
            ConfigureTopLevel((WINDOWPOS *) lParam);
            result = 0;
@@ -4295,7 +6860,8 @@ WmProc(hwnd, message, wParam, lParam)
                 * This allows us to pass the message onto the
                 * native menus [Bug: 2272]
                 */
-               result = DefWindowProc(hwnd, message, wParam, lParam);
+               result = (*tkWinProcs->defWindowProc)(hwnd, message,
+                       wParam, lParam);
                goto done;
            }
 
@@ -4306,7 +6872,7 @@ WmProc(hwnd, message, wParam, lParam)
             * handle the mouse event.
             */
 
-           if (winPtr) { 
+           if (winPtr) {
                eventPtr = (ActivateEvent *)ckalloc(sizeof(ActivateEvent));
                eventPtr->ev.proc = ActivateWindow;
                eventPtr->winPtr = winPtr;
@@ -4328,10 +6894,11 @@ WmProc(hwnd, message, wParam, lParam)
            result = 0;
        } else if (!Tk_TranslateWinEvent(child, message, wParam, lParam,
                &result)) {
-           result = DefWindowProc(hwnd, message, wParam, lParam);
+           result = (*tkWinProcs->defWindowProc)(hwnd, message,
+                   wParam, lParam);
        }
     } else {
-       result = DefWindowProc(hwnd, message, wParam, lParam);
+       result = (*tkWinProcs->defWindowProc)(hwnd, message, wParam, lParam);
     }
 
     done:
@@ -4374,13 +6941,13 @@ TkpMakeMenuWindow(tkwin, transient)
        atts.override_redirect = False;
        atts.save_under = False;
     }
-       
+
     if ((atts.override_redirect != Tk_Attributes(tkwin)->override_redirect)
            || (atts.save_under != Tk_Attributes(tkwin)->save_under)) {
        Tk_ChangeWindowAttributes(tkwin,
                CWOverrideRedirect|CWSaveUnder, &atts);
     }
-       
+
 }
 \f
 /*
@@ -4435,7 +7002,7 @@ TkWmFocusToplevel(winPtr)
     TkWindow *winPtr;          /* Window that received a focus-related
                                 * event. */
 {
-    if (!(winPtr->flags & TK_TOP_LEVEL)) {
+    if (!(winPtr->flags & TK_TOP_HIERARCHY)) {
        return NULL;
     }
     return winPtr;
@@ -4465,7 +7032,7 @@ TkpGetWrapperWindow(
     TkWindow *winPtr)          /* Window that received a focus-related
                                 * event. */
 {
-    if (!(winPtr->flags & TK_TOP_LEVEL)) {
+    if (!(winPtr->flags & TK_TOP_HIERARCHY)) {
        return NULL;
     }
     return winPtr;
@@ -4507,7 +7074,7 @@ ActivateWindow(
     if (winPtr && (TkGrabState(winPtr) != TK_GRAB_EXCLUDED)) {
        SetFocus(Tk_GetHWND(winPtr->window));
     }
-    
+
     return 1;
 }
 
@@ -4535,7 +7102,7 @@ TkWinSetForegroundWindow(winPtr)
     TkWindow *winPtr;
 {
     register WmInfo *wmPtr = winPtr->wmInfoPtr;
-    
+
     if (wmPtr->wrapper != NULL) {
        SetForegroundWindow(wmPtr->wrapper);
     } else {