1/*
2 * tkWinWm.c --
3 *
4 *	This module takes care of the interactions between a Tk-based
5 *	application and the window manager. Among other things, it implements
6 *	the "wm" command and passes geometry information to the window
7 *	manager.
8 *
9 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
10 * Copyright (c) 1998-2000 by Scriptics Corporation.
11 *
12 * See the file "license.terms" for information on usage and redistribution of
13 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 *
15 * RCS: @(#) $Id$
16 */
17
18#include "tkWinInt.h"
19#include <shellapi.h>
20
21/*
22 * These next two defines are only valid on Win2K/XP+.
23 */
24
25#ifndef WS_EX_LAYERED
26#define WS_EX_LAYERED	0x00080000
27#endif
28#ifndef LWA_COLORKEY
29#define LWA_COLORKEY	0x00000001
30#endif
31#ifndef LWA_ALPHA
32#define LWA_ALPHA	0x00000002
33#endif
34
35/*
36 * Event structure for synthetic activation events. These events are placed on
37 * the event queue whenever a toplevel gets a WM_MOUSEACTIVATE message or
38 * a WM_ACTIVATE. If the window is being moved (*flagPtr will be true)
39 * then the handling of this event must be delayed until the operation
40 * has completed to avoid a premature WM_EXITSIZEMOVE event.
41 */
42
43typedef struct ActivateEvent {
44    Tcl_Event ev;
45    TkWindow *winPtr;
46    const int *flagPtr;
47    HWND hwnd;
48} ActivateEvent;
49
50/*
51 * A data structure of the following type holds information for each window
52 * manager protocol (such as WM_DELETE_WINDOW) for which a handler (i.e. a Tcl
53 * command) has been defined for a particular top-level window.
54 */
55
56typedef struct ProtocolHandler {
57    Atom protocol;		/* Identifies the protocol. */
58    struct ProtocolHandler *nextPtr;
59				/* Next in list of protocol handlers for the
60				 * same top-level window, or NULL for end of
61				 * list. */
62    Tcl_Interp *interp;		/* Interpreter in which to invoke command. */
63    char command[4];		/* Tcl command to invoke when a client message
64				 * for this protocol arrives. The actual size
65				 * of the structure varies to accommodate the
66				 * needs of the actual command. THIS MUST BE
67				 * THE LAST FIELD OF THE STRUCTURE. */
68} ProtocolHandler;
69
70#define HANDLER_SIZE(cmdLength) \
71    ((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
72
73/*
74 * Helper type passed via lParam to TkWmStackorderToplevelEnumProc
75 */
76
77typedef struct TkWmStackorderToplevelPair {
78    Tcl_HashTable *table;
79    TkWindow **window_ptr;
80} TkWmStackorderToplevelPair;
81
82/*
83 * This structure represents the contents of a icon, in terms of its image.
84 * The HICON is an internal Windows format. Most of these icon-specific
85 * structures originated with the Winico extension. We stripped out unused
86 * parts of that code, and integrated the code more naturally with Tcl.
87 */
88
89typedef struct {
90    UINT Width, Height, Colors;	/* Width, Height and bpp */
91    LPBYTE lpBits;		/* Ptr to DIB bits */
92    DWORD dwNumBytes;		/* How many bytes? */
93    LPBITMAPINFO lpbi;		/* Ptr to header */
94    LPBYTE lpXOR;		/* Ptr to XOR image bits */
95    LPBYTE lpAND;		/* Ptr to AND image bits */
96    HICON hIcon;		/* DAS ICON */
97} ICONIMAGE, *LPICONIMAGE;
98
99/*
100 * This structure is how we represent a block of the above items. We will
101 * reallocate these structures according to how many images they need to
102 * contain.
103 */
104
105typedef struct {
106    int nNumImages;		/* How many images? */
107    ICONIMAGE IconImages[1];	/* Image entries */
108} BlockOfIconImages, *BlockOfIconImagesPtr;
109
110/*
111 * These two structures are used to read in icons from an 'icon directory'
112 * (i.e. the contents of a .icr file, say). We only use these structures
113 * temporarily, since we copy the information we want into a
114 * BlockOfIconImages.
115 */
116
117typedef struct {
118    BYTE bWidth;		/* Width of the image */
119    BYTE bHeight;		/* Height of the image (times 2) */
120    BYTE bColorCount;		/* Number of colors in image (0 if >=8bpp) */
121    BYTE bReserved;		/* Reserved */
122    WORD wPlanes;		/* Color Planes */
123    WORD wBitCount;		/* Bits per pixel */
124    DWORD dwBytesInRes;		/* How many bytes in this resource? */
125    DWORD dwImageOffset;	/* Where in the file is this image */
126} ICONDIRENTRY, *LPICONDIRENTRY;
127
128typedef struct {
129    WORD idReserved;		/* Reserved */
130    WORD idType;		/* Resource type (1 for icons) */
131    WORD idCount;		/* How many images? */
132    ICONDIRENTRY idEntries[1];	/* The entries for each image */
133} ICONDIR, *LPICONDIR;
134
135/*
136 * A pointer to one of these strucutures is associated with each toplevel.
137 * This allows us to free up all memory associated with icon resources when a
138 * window is deleted or if the window's icon is changed. They are simply
139 * reference counted according to:
140 *
141 * (1) How many WmInfo structures point to this object
142 * (2) Whether the ThreadSpecificData defined in this file contains a pointer
143 *     to this object.
144 *
145 * The former count is for windows whose icons are individually set, and the
146 * latter is for the global default icon choice.
147 *
148 * Icons loaded from .icr/.icr use the iconBlock field, icons loaded from
149 * .exe/.dll use the hIcon field.
150 */
151
152typedef struct WinIconInstance {
153    int refCount;		/* Number of instances that share this data
154				 * structure. */
155    BlockOfIconImagesPtr iconBlock;
156				/* Pointer to icon resource data for image */
157} WinIconInstance;
158
159typedef struct WinIconInstance *WinIconPtr;
160
161/*
162 * A data structure of the following type holds window-manager-related
163 * information for each top-level window in an application.
164 */
165
166typedef struct TkWmInfo {
167    TkWindow *winPtr;		/* Pointer to main Tk information for this
168				 * window. */
169    HWND wrapper;		/* This is the decorative frame window created
170				 * by the window manager to wrap a toplevel
171				 * window. This window is a direct child of
172				 * the root window. */
173    char *title;		/* Title to display in window caption. If
174				 * NULL, use name of widget. Malloced. */
175    char *iconName;		/* Name to display in icon. Malloced. */
176    XWMHints hints;		/* Various pieces of information for window
177				 * manager. */
178    char *leaderName;		/* Path name of leader of window group
179				 * (corresponds to hints.window_group).
180				 * Malloc-ed. Note: this field doesn't get
181				 * updated if leader is destroyed. */
182    TkWindow *masterPtr;	/* Master window for TRANSIENT_FOR property,
183				 * or NULL. */
184    Tk_Window icon;		/* Window to use as icon for this window, or
185				 * NULL. */
186    Tk_Window iconFor;		/* Window for which this window is icon, or
187				 * NULL if this isn't an icon for anyone. */
188
189    /*
190     * Information used to construct an XSizeHints structure for the window
191     * manager:
192     */
193
194    int defMinWidth, defMinHeight, defMaxWidth, defMaxHeight;
195				/* Default resize limits given by system. */
196    int sizeHintsFlags;		/* Flags word for XSizeHints structure. If the
197				 * PBaseSize flag is set then the window is
198				 * gridded; otherwise it isn't gridded. */
199    int minWidth, minHeight;	/* Minimum dimensions of window, in pixels or
200				 * grid units. */
201    int maxWidth, maxHeight;	/* Maximum dimensions of window, in pixels or
202				 * grid units. 0 to default. */
203    Tk_Window gridWin;		/* Identifies the window that controls
204				 * gridding for this top-level, or NULL if the
205				 * top-level isn't currently gridded. */
206    int widthInc, heightInc;	/* Increments for size changes (# pixels per
207				 * step). */
208    struct {
209	int x;	/* numerator */
210	int y;	/* denominator */
211    } minAspect, maxAspect;	/* Min/max aspect ratios for window. */
212    int reqGridWidth, reqGridHeight;
213				/* The dimensions of the window (in grid
214				 * units) requested through the geometry
215				 * manager. */
216    int gravity;		/* Desired window gravity. */
217
218    /*
219     * Information used to manage the size and location of a window.
220     */
221
222    int width, height;		/* Desired dimensions of window, specified in
223				 * pixels or grid units. These values are set
224				 * by the "wm geometry" command and by
225				 * ConfigureNotify events (for when wm resizes
226				 * window). -1 means user hasn't requested
227				 * dimensions. */
228    int x, y;			/* Desired X and Y coordinates for window.
229				 * These values are set by "wm geometry", plus
230				 * by ConfigureNotify events (when wm moves
231				 * window). These numbers are different than
232				 * the numbers stored in winPtr->changes
233				 * because (a) they could be measured from the
234				 * right or bottom edge of the screen (see
235				 * WM_NEGATIVE_X and WM_NEGATIVE_Y flags) and
236				 * (b) if the window has been reparented then
237				 * they refer to the parent rather than the
238				 * window itself. */
239    int borderWidth, borderHeight;
240				/* Width and height of window dressing, in
241				 * pixels for the current style/exStyle. This
242				 * includes the border on both sides of the
243				 * window. */
244    int configX, configY;	/* x,y position of toplevel when window is
245				 * switched into fullscreen state, */
246    int configWidth, configHeight;
247				/* Dimensions passed to last request that we
248				 * issued to change geometry of window. Used
249				 * to eliminate redundant resize operations */
250    HMENU hMenu;		/* the hMenu associated with this menu */
251    DWORD style, exStyle;	/* Style flags for the wrapper window. */
252    LONG styleConfig;		/* Extra user requested style bits */
253    LONG exStyleConfig;		/* Extra user requested extended style bits */
254    Tcl_Obj *crefObj;		/* COLORREF object for transparent handling */
255    COLORREF colorref;		/* COLORREF for transparent handling */
256    double alpha;		/* Alpha transparency level 0.0 (fully
257				 * transparent) .. 1.0 (opaque) */
258
259    /*
260     * List of children of the toplevel which have private colormaps.
261     */
262
263    TkWindow **cmapList;	/* Array of window with private colormaps. */
264    int cmapCount;		/* Number of windows in array. */
265
266    /*
267     * Miscellaneous information.
268     */
269
270    ProtocolHandler *protPtr;	/* First in list of protocol handlers for this
271				 * window (NULL means none). */
272    int cmdArgc;		/* Number of elements in cmdArgv below. */
273    CONST char **cmdArgv;	/* Array of strings to store in the WM_COMMAND
274				 * property. NULL means nothing available. */
275    char *clientMachine;	/* String to store in WM_CLIENT_MACHINE
276				 * property, or NULL. */
277    int flags;			/* Miscellaneous flags, defined below. */
278    int numTransients;		/* Number of transients on this window */
279    WinIconPtr iconPtr;		/* Pointer to titlebar icon structure for this
280				 * window, or NULL. */
281    struct TkWmInfo *nextPtr;	/* Next in list of all top-level windows. */
282} WmInfo;
283
284/*
285 * Flag values for WmInfo structures:
286 *
287 * WM_NEVER_MAPPED -		Non-zero means window has never been mapped;
288 *				need to update all info when window is first
289 *				mapped.
290 * WM_UPDATE_PENDING -		Non-zero means a call to UpdateGeometryInfo
291 *				has already been scheduled for this window;
292 *				no need to schedule another one.
293 * WM_NEGATIVE_X -		Non-zero means x-coordinate is measured in
294 *				pixels from right edge of screen, rather than
295 *				from left edge.
296 * WM_NEGATIVE_Y -		Non-zero means y-coordinate is measured in
297 *				pixels up from bottom of screen, rather than
298 *				down from top.
299 * WM_UPDATE_SIZE_HINTS -	Non-zero means that new size hints need to be
300 *				propagated to window manager. Not used on Win.
301 * WM_SYNC_PENDING -		Set to non-zero while waiting for the window
302 *				manager to respond to some state change.
303 * WM_MOVE_PENDING -		Non-zero means the application has requested a
304 *				new position for the window, but it hasn't
305 *				been reflected through the window manager yet.
306 * WM_COLORMAPS_EXPLICIT -	Non-zero means the colormap windows were set
307 *				explicitly via "wm colormapwindows".
308 * WM_ADDED_TOPLEVEL_COLORMAP - Non-zero means that when "wm colormapwindows"
309 *				was called the top-level itself wasn't
310 *				specified, so we added it implicitly at the
311 *				end of the list.
312 * WM_WIDTH_NOT_RESIZABLE -	Non-zero means that we're not supposed to
313 *				allow the user to change the width of the
314 *				window (controlled by "wm resizable" command).
315 * WM_HEIGHT_NOT_RESIZABLE -	Non-zero means that we're not supposed to
316 *				allow the user to change the height of the
317 *				window (controlled by "wm resizable" command).
318 * WM_WITHDRAWN -		Non-zero means that this window has explicitly
319 *				been withdrawn. If it's a transient, it should
320 *				not mirror state changes in the master.
321 * WM_FULLSCREEN -		Non-zero means that this window has been placed
322 *				in the full screen mode. It should be mapped at
323 *				0,0 and be the width and height of the screen.
324 */
325
326#define WM_NEVER_MAPPED			(1<<0)
327#define WM_UPDATE_PENDING		(1<<1)
328#define WM_NEGATIVE_X			(1<<2)
329#define WM_NEGATIVE_Y			(1<<3)
330#define WM_UPDATE_SIZE_HINTS		(1<<4)
331#define WM_SYNC_PENDING			(1<<5)
332#define WM_CREATE_PENDING		(1<<6)
333#define WM_MOVE_PENDING			(1<<7)
334#define WM_COLORMAPS_EXPLICIT		(1<<8)
335#define WM_ADDED_TOPLEVEL_COLORMAP	(1<<9)
336#define WM_WIDTH_NOT_RESIZABLE		(1<<10)
337#define WM_HEIGHT_NOT_RESIZABLE		(1<<11)
338#define WM_WITHDRAWN			(1<<12)
339#define WM_FULLSCREEN			(1<<13)
340
341/*
342 * Window styles for various types of toplevel windows.
343 */
344
345#define WM_OVERRIDE_STYLE (WS_CLIPCHILDREN|WS_CLIPSIBLINGS|CS_DBLCLKS)
346#define EX_OVERRIDE_STYLE (WS_EX_TOOLWINDOW)
347
348#define WM_FULLSCREEN_STYLE (WS_POPUP|WM_OVERRIDE_STYLE)
349#define EX_FULLSCREEN_STYLE (WS_EX_APPWINDOW)
350
351#define WM_TOPLEVEL_STYLE (WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|CS_DBLCLKS)
352#define EX_TOPLEVEL_STYLE (0)
353
354#define WM_TRANSIENT_STYLE \
355		(WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_CLIPSIBLINGS|CS_DBLCLKS)
356#define EX_TRANSIENT_STYLE (WS_EX_DLGMODALFRAME)
357
358/*
359 * The following structure is the official type record for geometry management
360 * of top-level windows.
361 */
362
363static void		TopLevelReqProc(ClientData dummy, Tk_Window tkwin);
364static void		RemapWindows(TkWindow *winPtr, HWND parentHWND);
365
366static const Tk_GeomMgr wmMgrType = {
367    "wm",			/* name */
368    TopLevelReqProc,		/* requestProc */
369    NULL,			/* lostSlaveProc */
370};
371
372typedef struct ThreadSpecificData {
373    HPALETTE systemPalette;	/* System palette; refers to the currently
374				 * installed foreground logical palette. */
375    TkWindow *createWindow;	/* Window that is being constructed. This
376				 * value is set immediately before a call to
377				 * CreateWindowEx, and is used by SetLimits.
378				 * This is a gross hack needed to work around
379				 * Windows brain damage where it sends the
380				 * WM_GETMINMAXINFO message before the
381				 * WM_CREATE window. */
382    int initialized;		/* Flag indicating whether thread-specific
383				 * elements of module have been
384				 * initialized. */
385    int firstWindow;		/* Flag, cleared when the first window is
386				 * mapped in a non-iconic state. */
387    WinIconPtr iconPtr;		/* IconPtr being used as default for all
388				 * toplevels, or NULL. */
389} ThreadSpecificData;
390static Tcl_ThreadDataKey dataKey;
391
392/*
393 * The following variables cannot be placed in thread local storage because
394 * they must be shared across threads.
395 */
396
397static int initialized;		/* Flag indicating whether module has been
398				 * initialized. */
399
400/*
401 * A pointer to a shell proc which allows us to extract icons from any file.
402 * We just initialize this when we start up (if we can) and then it never
403 * changes
404 */
405
406DWORD* (WINAPI *shgetfileinfoProc) (LPCTSTR pszPath, DWORD dwFileAttributes,
407	SHFILEINFO* psfi, UINT cbFileInfo, UINT uFlags) = NULL;
408
409/*
410 * A pointer to SetLayeredWindowAttributes (user32.dll) which we retrieve
411 * dynamically because it is only valid on Win2K+.
412 */
413
414BOOL (WINAPI *setLayeredWindowAttributesProc) (HWND hwnd, COLORREF crKey,
415	BYTE bAlpha, DWORD dwFlags) = NULL;
416
417TCL_DECLARE_MUTEX(winWmMutex)
418
419/*
420 * Forward declarations for functions defined in this file:
421 */
422
423static int		ActivateWindow(Tcl_Event *evPtr, int flags);
424static void		ConfigureTopLevel(WINDOWPOS *pos);
425static void		GenerateConfigureNotify(TkWindow *winPtr);
426static void		GenerateActivateEvent(TkWindow *winPtr, const int *flagPtr);
427static void		GetMaxSize(WmInfo *wmPtr,
428			    int *maxWidthPtr, int *maxHeightPtr);
429static void		GetMinSize(WmInfo *wmPtr,
430			    int *minWidthPtr, int *minHeightPtr);
431static TkWindow *	GetTopLevel(HWND hwnd);
432static void		InitWm(void);
433static int		InstallColormaps(HWND hwnd, int message,
434			    int isForemost);
435static void		InvalidateSubTree(TkWindow *winPtr, Colormap colormap);
436static void		InvalidateSubTreeDepth(TkWindow *winPtr);
437static int		ParseGeometry(Tcl_Interp *interp, char *string,
438			    TkWindow *winPtr);
439static void		RefreshColormap(Colormap colormap, TkDisplay *dispPtr);
440static void		SetLimits(HWND hwnd, MINMAXINFO *info);
441static void		TkWmStackorderToplevelWrapperMap(TkWindow *winPtr,
442			    Display *display, Tcl_HashTable *table);
443static LRESULT CALLBACK	TopLevelProc(HWND hwnd, UINT message,
444			    WPARAM wParam, LPARAM lParam);
445static void		TopLevelEventProc(ClientData clientData,
446			    XEvent *eventPtr);
447static void		TopLevelReqProc(ClientData dummy, Tk_Window tkwin);
448static void		UpdateGeometryInfo(ClientData clientData);
449static void		UpdateWrapper(TkWindow *winPtr);
450static LRESULT CALLBACK	WmProc(HWND hwnd, UINT message,
451			    WPARAM wParam, LPARAM lParam);
452static void		WmWaitVisibilityOrMapProc(ClientData clientData,
453			    XEvent *eventPtr);
454static BlockOfIconImagesPtr ReadIconOrCursorFromFile(Tcl_Interp *interp,
455			    Tcl_Obj* fileName, BOOL isIcon);
456static WinIconPtr	ReadIconFromFile(Tcl_Interp *interp,
457			    Tcl_Obj *fileName);
458static WinIconPtr	GetIconFromPixmap(Display *dsPtr, Pixmap pixmap);
459static int		ReadICOHeader(Tcl_Channel channel);
460static BOOL		AdjustIconImagePointers(LPICONIMAGE lpImage);
461static HICON		MakeIconOrCursorFromResource(LPICONIMAGE lpIcon,
462			    BOOL isIcon);
463static HICON		GetIcon(WinIconPtr titlebaricon, int icon_size);
464static int		WinSetIcon(Tcl_Interp *interp,
465			    WinIconPtr titlebaricon, Tk_Window tkw);
466static void		FreeIconBlock(BlockOfIconImagesPtr lpIR);
467static void		DecrIconRefCount(WinIconPtr titlebaricon);
468
469static int		WmAspectCmd(Tk_Window tkwin,
470			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
471			    Tcl_Obj *CONST objv[]);
472static int		WmAttributesCmd(Tk_Window tkwin,
473			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
474			    Tcl_Obj *CONST objv[]);
475static int		WmClientCmd(Tk_Window tkwin,
476			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
477			    Tcl_Obj *CONST objv[]);
478static int		WmColormapwindowsCmd(Tk_Window tkwin,
479			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
480			    Tcl_Obj *CONST objv[]);
481static int		WmCommandCmd(Tk_Window tkwin,
482			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
483			    Tcl_Obj *CONST objv[]);
484static int		WmDeiconifyCmd(Tk_Window tkwin,
485			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
486			    Tcl_Obj *CONST objv[]);
487static int		WmFocusmodelCmd(Tk_Window tkwin,
488			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
489			    Tcl_Obj *CONST objv[]);
490static int		WmForgetCmd(Tk_Window tkwin,
491			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
492			    Tcl_Obj *CONST objv[]);
493static int		WmFrameCmd(Tk_Window tkwin,
494			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
495			    Tcl_Obj *CONST objv[]);
496static int		WmGeometryCmd(Tk_Window tkwin,
497			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
498			    Tcl_Obj *CONST objv[]);
499static int		WmGridCmd(Tk_Window tkwin,
500			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
501			    Tcl_Obj *CONST objv[]);
502static int		WmGroupCmd(Tk_Window tkwin,
503			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
504			    Tcl_Obj *CONST objv[]);
505static int		WmIconbitmapCmd(Tk_Window tkwin,
506			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
507			    Tcl_Obj *CONST objv[]);
508static int		WmIconifyCmd(Tk_Window tkwin,
509			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
510			    Tcl_Obj *CONST objv[]);
511static int		WmIconmaskCmd(Tk_Window tkwin,
512			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
513			    Tcl_Obj *CONST objv[]);
514static int		WmIconnameCmd(Tk_Window tkwin,
515			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
516			    Tcl_Obj *CONST objv[]);
517static int		WmIconphotoCmd(Tk_Window tkwin,
518			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
519			    Tcl_Obj *CONST objv[]);
520static int		WmIconpositionCmd(Tk_Window tkwin,
521			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
522			    Tcl_Obj *CONST objv[]);
523static int		WmIconwindowCmd(Tk_Window tkwin,
524			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
525			    Tcl_Obj *CONST objv[]);
526static int		WmManageCmd(Tk_Window tkwin,
527			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
528			    Tcl_Obj *CONST objv[]);
529static int		WmMaxsizeCmd(Tk_Window tkwin,
530			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
531			    Tcl_Obj *CONST objv[]);
532static int		WmMinsizeCmd(Tk_Window tkwin,
533			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
534			    Tcl_Obj *CONST objv[]);
535static int		WmOverrideredirectCmd(Tk_Window tkwin,
536			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
537			    Tcl_Obj *CONST objv[]);
538static int		WmPositionfromCmd(Tk_Window tkwin,
539			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
540			    Tcl_Obj *CONST objv[]);
541static int		WmProtocolCmd(Tk_Window tkwin,
542			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
543			    Tcl_Obj *CONST objv[]);
544static int		WmResizableCmd(Tk_Window tkwin,
545			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
546			    Tcl_Obj *CONST objv[]);
547static int		WmSizefromCmd(Tk_Window tkwin,
548			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
549			    Tcl_Obj *CONST objv[]);
550static int		WmStackorderCmd(Tk_Window tkwin,
551			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
552			    Tcl_Obj *CONST objv[]);
553static int		WmStateCmd(Tk_Window tkwin,
554			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
555			    Tcl_Obj *CONST objv[]);
556static int		WmTitleCmd(Tk_Window tkwin,
557			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
558			    Tcl_Obj *CONST objv[]);
559static int		WmTransientCmd(Tk_Window tkwin,
560			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
561			    Tcl_Obj *CONST objv[]);
562static int		WmWithdrawCmd(Tk_Window tkwin,
563			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
564			    Tcl_Obj *CONST objv[]);
565static void		WmUpdateGeom(WmInfo *wmPtr, TkWindow *winPtr);
566
567/*
568 * Used in BytesPerLine
569 */
570
571#define WIDTHBYTES(bits)	((((bits) + 31)>>5)<<2)
572
573/*
574 *----------------------------------------------------------------------
575 *
576 * DIBNumColors --
577 *
578 *	Calculates the number of entries in the color table, given by LPSTR
579 *	lpbi - pointer to the CF_DIB memory block. Used by titlebar icon code.
580 *
581 * Results:
582 *	WORD - Number of entries in the color table.
583 *
584 *----------------------------------------------------------------------
585 */
586
587static WORD
588DIBNumColors(
589    LPSTR lpbi)
590{
591    WORD wBitCount;
592    DWORD dwClrUsed;
593
594    dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed;
595
596    if (dwClrUsed) {
597	return (WORD) dwClrUsed;
598    }
599
600    wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount;
601
602    switch (wBitCount) {
603    case 1:
604	return 2;
605    case 4:
606	return 16;
607    case 8:
608	return 256;
609    default:
610	return 0;
611    }
612}
613
614/*
615 *----------------------------------------------------------------------
616 *
617 * PaletteSize --
618 *
619 *	Calculates the number of bytes in the color table, as given by LPSTR
620 *	lpbi - pointer to the CF_DIB memory block. Used by titlebar icon code.
621 *
622 * Results:
623 *	Number of bytes in the color table
624 *
625 *----------------------------------------------------------------------
626 */
627static WORD
628PaletteSize(
629    LPSTR lpbi)
630{
631    return (WORD) (DIBNumColors(lpbi) * sizeof(RGBQUAD));
632}
633
634/*
635 *----------------------------------------------------------------------
636 *
637 * FindDIBits --
638 *
639 *	Locate the image bits in a CF_DIB format DIB, as given by LPSTR lpbi -
640 *	pointer to the CF_DIB memory block. Used by titlebar icon code.
641 *
642 * Results:
643 *	pointer to the image bits
644 *
645 * Side effects: None
646 *
647 *
648 *----------------------------------------------------------------------
649 */
650
651static LPSTR
652FindDIBBits(
653    LPSTR lpbi)
654{
655    return lpbi + *(LPDWORD)lpbi + PaletteSize(lpbi);
656}
657
658/*
659 *----------------------------------------------------------------------
660 *
661 * BytesPerLine --
662 *
663 *	Calculates the number of bytes in one scan line, as given by
664 *	LPBITMAPINFOHEADER lpBMIH - pointer to the BITMAPINFOHEADER that
665 *	begins the CF_DIB block. Used by titlebar icon code.
666 *
667 * Results:
668 *	number of bytes in one scan line (DWORD aligned)
669 *
670 *----------------------------------------------------------------------
671 */
672
673static DWORD
674BytesPerLine(
675    LPBITMAPINFOHEADER lpBMIH)
676{
677    return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
678}
679
680/*
681 *----------------------------------------------------------------------
682 *
683 * AdjustIconImagePointers --
684 *
685 *	Adjusts internal pointers in icon resource struct, as given by
686 *	LPICONIMAGE lpImage - the resource to handle. Used by titlebar icon
687 *	code.
688 *
689 * Results:
690 *	BOOL - TRUE for success, FALSE for failure
691 *
692 *----------------------------------------------------------------------
693 */
694
695static BOOL
696AdjustIconImagePointers(
697    LPICONIMAGE lpImage)
698{
699    /*
700     * Sanity check.
701     */
702
703    if (lpImage == NULL) {
704	return FALSE;
705    }
706
707    /*
708     * BITMAPINFO is at beginning of bits.
709     */
710
711    lpImage->lpbi = (LPBITMAPINFO)lpImage->lpBits;
712
713    /*
714     * Width - simple enough.
715     */
716
717    lpImage->Width = lpImage->lpbi->bmiHeader.biWidth;
718
719    /*
720     * Icons are stored in funky format where height is doubled so account for
721     * that.
722     */
723
724    lpImage->Height = (lpImage->lpbi->bmiHeader.biHeight)/2;
725
726    /*
727     * How many colors?
728     */
729
730    lpImage->Colors = lpImage->lpbi->bmiHeader.biPlanes
731	    * lpImage->lpbi->bmiHeader.biBitCount;
732
733    /*
734     * XOR bits follow the header and color table.
735     */
736
737    lpImage->lpXOR = (LPBYTE)FindDIBBits(((LPSTR)lpImage->lpbi));
738
739    /*
740     * AND bits follow the XOR bits.
741     */
742
743    lpImage->lpAND = lpImage->lpXOR + (lpImage->Height*
744	    BytesPerLine((LPBITMAPINFOHEADER)(lpImage->lpbi)));
745    return TRUE;
746}
747
748/*
749 *----------------------------------------------------------------------
750 *
751 * MakeIconOrCursorFromResource --
752 *
753 *	Construct an actual HICON structure from the information in a
754 *	resource.
755 *
756 * Results:
757 *	Icon
758 *
759 *----------------------------------------------------------------------
760 */
761
762static HICON
763MakeIconOrCursorFromResource(
764    LPICONIMAGE lpIcon,
765    BOOL isIcon)
766{
767    HICON hIcon ;
768    static FARPROC pfnCreateIconFromResourceEx=NULL;
769    static int initinfo=0;
770
771    /*
772     * Sanity Check
773     */
774
775    if (lpIcon == NULL) {
776	return NULL;
777    }
778    if (lpIcon->lpBits == NULL) {
779	return NULL;
780    }
781
782    if (!initinfo) {
783	HMODULE hMod = GetModuleHandleA("USER32.DLL");
784
785	initinfo = 1;
786	if (hMod) {
787	    pfnCreateIconFromResourceEx =
788		    GetProcAddress(hMod, "CreateIconFromResourceEx");
789	}
790    }
791
792    /*
793     * Let the OS do the real work :)
794     */
795
796    if (pfnCreateIconFromResourceEx != NULL) {
797	hIcon = (HICON) (pfnCreateIconFromResourceEx) (lpIcon->lpBits,
798		lpIcon->dwNumBytes, isIcon, 0x00030000,
799		(*(LPBITMAPINFOHEADER)(lpIcon->lpBits)).biWidth,
800		(*(LPBITMAPINFOHEADER)(lpIcon->lpBits)).biHeight/2, 0);
801    } else {
802	 hIcon = NULL;
803    }
804
805    /*
806     * It failed, odds are good we're on NT so try the non-Ex way.
807     */
808
809    if (hIcon == NULL)    {
810	/*
811	 * We would break on NT if we try with a 16bpp image.
812	 */
813
814	if (lpIcon->lpbi->bmiHeader.biBitCount != 16) {
815	    hIcon = CreateIconFromResource(lpIcon->lpBits, lpIcon->dwNumBytes,
816		    isIcon, 0x00030000);
817	}
818    }
819    return hIcon;
820}
821
822/*
823 *----------------------------------------------------------------------
824 *
825 * ReadICOHeader --
826 *
827 *	Reads the header from an ICO file, as specfied by channel.
828 *
829 * Results:
830 *	UINT - Number of images in file, -1 for failure. If this succeeds,
831 *	there is a decent chance this is a valid icon file.
832 *
833 *----------------------------------------------------------------------
834 */
835
836static int
837ReadICOHeader(
838    Tcl_Channel channel)
839{
840    union {
841	WORD word;
842	char bytes[sizeof(WORD)];
843    } input;
844
845    /*
846     * Read the 'reserved' WORD, which should be a zero word.
847     */
848
849    if (Tcl_Read(channel, input.bytes, sizeof(WORD)) != sizeof(WORD)) {
850	return -1;
851    }
852    if (input.word != 0) {
853	return -1;
854    }
855
856    /*
857     * Read the type WORD, which should be of type 1.
858     */
859
860    if (Tcl_Read(channel, input.bytes, sizeof(WORD)) != sizeof(WORD)) {
861	return -1;
862    }
863    if (input.word != 1) {
864	return -1;
865    }
866
867    /*
868     * Get and return the count of images.
869     */
870
871    if (Tcl_Read(channel, input.bytes, sizeof(WORD)) != sizeof(WORD)) {
872	return -1;
873    }
874    return (int) input.word;
875}
876
877/*
878 *----------------------------------------------------------------------
879 *
880 * InitWindowClass --
881 *
882 *	This routine creates the Wm toplevel decorative frame class.
883 *
884 * Results:
885 *	None.
886 *
887 * Side effects:
888 *	Registers a new window class.
889 *
890 *----------------------------------------------------------------------
891 */
892
893static int
894InitWindowClass(
895    WinIconPtr titlebaricon)
896{
897    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
898	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
899
900    if (! tsdPtr->initialized) {
901	tsdPtr->initialized = 1;
902	tsdPtr->firstWindow = 1;
903	tsdPtr->iconPtr = NULL;
904    }
905    if (! initialized) {
906	Tcl_MutexLock(&winWmMutex);
907	if (! initialized) {
908	    Tcl_DString classString;
909	    WNDCLASS class;
910	    initialized = 1;
911
912	    if (shgetfileinfoProc == NULL) {
913		HINSTANCE hInstance = LoadLibraryA("shell32");
914		if (hInstance != NULL) {
915		    shgetfileinfoProc = (DWORD* (WINAPI *) (LPCTSTR pszPath,
916			    DWORD dwFileAttributes, SHFILEINFO* psfi,
917			    UINT cbFileInfo, UINT uFlags))
918			GetProcAddress(hInstance, "SHGetFileInfo");
919		    FreeLibrary(hInstance);
920		}
921	    }
922	    if (setLayeredWindowAttributesProc == NULL) {
923		HINSTANCE hInstance = LoadLibraryA("user32");
924		if (hInstance != NULL) {
925		    setLayeredWindowAttributesProc = (BOOL (WINAPI*)(HWND hwnd,
926			    COLORREF crKey, BYTE bAlpha, DWORD dwFlags))
927			GetProcAddress(hInstance,"SetLayeredWindowAttributes");
928		    FreeLibrary(hInstance);
929		}
930	    }
931
932	    /*
933	     * The only difference between WNDCLASSW and WNDCLASSA are in
934	     * pointers, so we can use the generic structure WNDCLASS.
935	     */
936
937	    ZeroMemory(&class, sizeof(WNDCLASS));
938
939	    class.style = CS_HREDRAW | CS_VREDRAW;
940	    class.hInstance = Tk_GetHINSTANCE();
941	    Tcl_WinUtfToTChar(TK_WIN_TOPLEVEL_CLASS_NAME, -1, &classString);
942	    class.lpszClassName = (LPCTSTR) Tcl_DStringValue(&classString);
943	    class.lpfnWndProc = WmProc;
944	    if (titlebaricon == NULL) {
945		class.hIcon = LoadIcon(Tk_GetHINSTANCE(), "tk");
946	    } else {
947		class.hIcon = GetIcon(titlebaricon, ICON_BIG);
948		if (class.hIcon == NULL) {
949		    return TCL_ERROR;
950		}
951
952		/*
953		 * Store pointer to default icon so we know when we need to
954		 * free that information
955		 */
956
957		tsdPtr->iconPtr = titlebaricon;
958	    }
959	    class.hCursor = LoadCursor(NULL, IDC_ARROW);
960
961	    if (!(*tkWinProcs->registerClass)(&class)) {
962		Tcl_Panic("Unable to register TkTopLevel class");
963	    }
964
965	    Tcl_DStringFree(&classString);
966	}
967	Tcl_MutexUnlock(&winWmMutex);
968    }
969    return TCL_OK;
970}
971
972/*
973 *----------------------------------------------------------------------
974 *
975 * InitWm --
976 *
977 *	This initialises the window manager
978 *
979 * Results:
980 *	None.
981 *
982 * Side effects:
983 *	Registers a new window class.
984 *
985 *----------------------------------------------------------------------
986 */
987
988static void
989InitWm(void)
990{
991    /* Ignore return result */
992    (void) InitWindowClass(NULL);
993}
994
995/*
996 *----------------------------------------------------------------------
997 *
998 * WinSetIcon --
999 *
1000 *	Sets either the default toplevel titlebar icon, or the icon for a
1001 *	specific toplevel (if tkw is given, then only that window is used).
1002 *
1003 *	The ref-count of the titlebaricon is NOT changed. If this function
1004 *	returns successfully, the caller should assume the icon was used (and
1005 *	therefore the ref-count should be adjusted to reflect that fact). If
1006 *	the function returned an error, the caller should assume the icon was
1007 *	not used (and may wish to free the memory associated with it).
1008 *
1009 * Results:
1010 *	A standard Tcl return code.
1011 *
1012 * Side effects:
1013 *	One or all windows may have their icon changed. The Tcl result may be
1014 *	modified. The window-manager will be initialised if it wasn't already.
1015 *	The given window will be forced into existence.
1016 *
1017 *----------------------------------------------------------------------
1018 */
1019
1020static int
1021WinSetIcon(
1022    Tcl_Interp *interp,
1023    WinIconPtr titlebaricon,
1024    Tk_Window tkw)
1025{
1026    WmInfo *wmPtr;
1027    HWND hwnd;
1028    int application = 0;
1029
1030    if (tkw == NULL) {
1031	tkw = Tk_MainWindow(interp);
1032	application = 1;
1033    }
1034
1035    if (!(Tk_IsTopLevel(tkw))) {
1036	Tcl_AppendResult(interp, "window \"", Tk_PathName(tkw),
1037		"\" isn't a top-level window", NULL);
1038	return TCL_ERROR;
1039    }
1040    if (Tk_WindowId(tkw) == None) {
1041	Tk_MakeWindowExist(tkw);
1042    }
1043
1044    /*
1045     * We must get the window's wrapper, not the window itself.
1046     */
1047
1048    wmPtr = ((TkWindow*)tkw)->wmInfoPtr;
1049    hwnd = wmPtr->wrapper;
1050
1051    if (application) {
1052	if (hwnd == NULL) {
1053	    /*
1054	     * I don't actually think this is ever the correct thing, unless
1055	     * perhaps the window doesn't have a wrapper. But I believe all
1056	     * windows have wrappers.
1057	     */
1058
1059	    hwnd = Tk_GetHWND(Tk_WindowId(tkw));
1060	}
1061
1062	/*
1063	 * If we aren't initialised, then just initialise with the user's
1064	 * icon. Otherwise our icon choice will be ignored moments later when
1065	 * Tk finishes initialising.
1066	 */
1067
1068	if (!initialized) {
1069	    if (InitWindowClass(titlebaricon) != TCL_OK) {
1070		Tcl_AppendResult(interp, "Unable to set icon", NULL);
1071		return TCL_ERROR;
1072	    }
1073	} else {
1074	    ThreadSpecificData *tsdPtr;
1075
1076	    /*
1077	     * Don't check return result of SetClassLong() or
1078	     * SetClassLongPtr() since they return the previously set value
1079	     * which is zero on the initial call or in an error case. The MSDN
1080	     * documentation does not indicate that the result needs to be
1081	     * checked.
1082	     */
1083
1084	    SetClassLongPtr(hwnd, GCLP_HICONSM,
1085		    (LPARAM) GetIcon(titlebaricon, ICON_SMALL));
1086	    SetClassLongPtr(hwnd, GCLP_HICON,
1087		    (LPARAM) GetIcon(titlebaricon, ICON_BIG));
1088	    tsdPtr = (ThreadSpecificData *)
1089		    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1090	    if (tsdPtr->iconPtr != NULL) {
1091		DecrIconRefCount(tsdPtr->iconPtr);
1092	    }
1093	    tsdPtr->iconPtr = titlebaricon;
1094	}
1095    } else {
1096	if (!initialized) {
1097	    /*
1098	     * Need to initialise the wm otherwise we will fail on code which
1099	     * tries to set a toplevel's icon before that happens. Ignore
1100	     * return result.
1101	     */
1102
1103	    (void) InitWindowClass(NULL);
1104	}
1105
1106	/*
1107	 * The following code is exercised if you do
1108	 *
1109	 *   toplevel .t ; wm titlebaricon .t foo.icr
1110	 *
1111	 * i.e. the wm hasn't had time to properly create the '.t' window
1112	 * before you set the icon.
1113	 */
1114
1115	if (hwnd == NULL) {
1116	    /*
1117	     * This little snippet is copied from the 'Map' function, and
1118	     * should probably be placed in one proper location.
1119	     */
1120
1121	    UpdateWrapper(wmPtr->winPtr);
1122	    wmPtr = ((TkWindow*)tkw)->wmInfoPtr;
1123	    hwnd = wmPtr->wrapper;
1124	    if (hwnd == NULL) {
1125		Tcl_AppendResult(interp,
1126			"Can't set icon; window has no wrapper.", NULL);
1127		return TCL_ERROR;
1128	    }
1129	}
1130	SendMessage(hwnd, WM_SETICON, ICON_SMALL,
1131		(LPARAM) GetIcon(titlebaricon, ICON_SMALL));
1132	SendMessage(hwnd, WM_SETICON, ICON_BIG,
1133		(LPARAM) GetIcon(titlebaricon, ICON_BIG));
1134
1135	/*
1136	 * Update the iconPtr we keep for each WmInfo structure.
1137	 */
1138
1139	if (wmPtr->iconPtr != NULL) {
1140	    /*
1141	     * Free any old icon ptr which is associated with this window.
1142	     */
1143
1144	    DecrIconRefCount(wmPtr->iconPtr);
1145	}
1146
1147	/*
1148	 * We do not need to increment the ref count for the titlebaricon,
1149	 * because it was already incremented when we retrieved it.
1150	 */
1151
1152	wmPtr->iconPtr = titlebaricon;
1153    }
1154    return TCL_OK;
1155}
1156
1157/*
1158 *----------------------------------------------------------------------
1159 *
1160 * TkWinGetIcon --
1161 *
1162 *	Gets either the default toplevel titlebar icon, or the icon for a
1163 *	specific toplevel (ICON_SMALL or ICON_BIG).
1164 *
1165 * Results:
1166 *	A Windows HICON.
1167 *
1168 * Side effects:
1169 *	The given window will be forced into existence.
1170 *
1171 *----------------------------------------------------------------------
1172 */
1173
1174HICON
1175TkWinGetIcon(
1176    Tk_Window tkwin,
1177    DWORD iconsize)
1178{
1179    WmInfo *wmPtr;
1180    HICON icon;
1181    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1182	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1183
1184    if (tsdPtr->iconPtr != NULL) {
1185	/*
1186	 * return default toplevel icon
1187	 */
1188
1189	return GetIcon(tsdPtr->iconPtr, (int)iconsize);
1190    }
1191
1192    /*
1193     * Ensure we operate on the toplevel, that has the icon refs.
1194     */
1195
1196    while (!Tk_IsTopLevel(tkwin)) {
1197	tkwin = Tk_Parent(tkwin);
1198	if (tkwin == NULL) {
1199	    return NULL;
1200	}
1201    }
1202
1203    if (Tk_WindowId(tkwin) == None) {
1204	Tk_MakeWindowExist(tkwin);
1205    }
1206
1207    wmPtr = ((TkWindow *) tkwin)->wmInfoPtr;
1208    if (wmPtr->iconPtr != NULL) {
1209	/*
1210	 * return window toplevel icon
1211	 */
1212
1213	return GetIcon(wmPtr->iconPtr, (int)iconsize);
1214    }
1215
1216    /*
1217     * Find the icon otherwise associated with the toplevel, or finally with
1218     * the window class.
1219     */
1220
1221    icon = (HICON) SendMessage(wmPtr->wrapper, WM_GETICON, iconsize,
1222	    (LPARAM) NULL);
1223    if (icon == (HICON) NULL) {
1224	icon = (HICON) GetClassLongPtr(wmPtr->wrapper,
1225		(iconsize == ICON_BIG) ? GCLP_HICON : GCLP_HICONSM);
1226    }
1227    return icon;
1228}
1229
1230/*
1231 *----------------------------------------------------------------------
1232 *
1233 * ReadIconFromFile --
1234 *
1235 *	Read the contents of a file (usually .ico, .icr) and extract an icon
1236 *	resource, if possible, otherwise check if the shell has an icon
1237 *	assigned to the given file and use that. If both of those fail, then
1238 *	NULL is returned, and an error message will already be in the
1239 *	interpreter.
1240 *
1241 * Results:
1242 *	A WinIconPtr structure containing the icons in the file, with its ref
1243 *	count already incremented. The calling function should either place
1244 *	this structure inside a WmInfo structure, or it should pass it on to
1245 *	DecrIconRefCount() to ensure no memory leaks occur.
1246 *
1247 *	If the given fileName did not contain a valid icon structure,
1248 *	return NULL.
1249 *
1250 * Side effects:
1251 *	Memory is allocated for the returned structure and the icons it
1252 *	contains. If the structure is not wanted, it should be passed to
1253 *	DecrIconRefCount, and in any case a valid ref count should be ensured
1254 *	to avoid memory leaks.
1255 *
1256 *	Currently icon resources are not shared, so the ref count of one of
1257 *	these structures will always be 0 or 1. However all we need do is
1258 *	implement some sort of lookup function between filenames and
1259 *	WinIconPtr structures and no other code will need to be changed. The
1260 *	pseudo-code for this is implemented below in the 'if (0)' branch. It
1261 *	did not seem necessary to implement this optimisation here, since
1262 *	moving to icon<->image conversions will probably make it obsolete.
1263 *
1264 *----------------------------------------------------------------------
1265 */
1266
1267static WinIconPtr
1268ReadIconFromFile(
1269    Tcl_Interp *interp,
1270    Tcl_Obj *fileName)
1271{
1272    WinIconPtr titlebaricon = NULL;
1273    BlockOfIconImagesPtr lpIR;
1274
1275    if (0 /* If we already have an icon for this filename */) {
1276	titlebaricon = NULL; /* Get the real value from a lookup */
1277	titlebaricon->refCount++;
1278	return titlebaricon;
1279    }
1280
1281    /*
1282     * First check if it is a .ico file.
1283     */
1284
1285    lpIR = ReadIconOrCursorFromFile(interp, fileName, TRUE);
1286
1287    /*
1288     * Then see if we can ask the shell for the icon for this file. We
1289     * want both the regular and small icons so that the Alt-Tab (task-
1290     * switching) display uses the right icon.
1291     */
1292
1293    if (lpIR == NULL && shgetfileinfoProc != NULL) {
1294	SHFILEINFO sfiSM;
1295	Tcl_DString ds, ds2;
1296	DWORD *res;
1297	CONST char *file;
1298
1299	file = Tcl_TranslateFileName(interp, Tcl_GetString(fileName), &ds);
1300	if (file == NULL) {
1301	    return NULL;
1302	}
1303	Tcl_UtfToExternalDString(NULL, file, -1, &ds2);
1304	Tcl_DStringFree(&ds);
1305	res = (*shgetfileinfoProc)(Tcl_DStringValue(&ds2), 0, &sfiSM,
1306		sizeof(SHFILEINFO), SHGFI_SMALLICON|SHGFI_ICON);
1307
1308	if (res != 0) {
1309	    SHFILEINFO sfi;
1310	    unsigned size;
1311
1312	    Tcl_ResetResult(interp);
1313	    res = (*shgetfileinfoProc)(Tcl_DStringValue(&ds2), 0, &sfi,
1314		    sizeof(SHFILEINFO), SHGFI_ICON);
1315
1316	    /*
1317	     * Account for extra icon, if necessary.
1318	     */
1319
1320	    size = sizeof(BlockOfIconImages)
1321		    + ((res != 0) ? sizeof(ICONIMAGE) : 0);
1322	    lpIR = (BlockOfIconImagesPtr) ckalloc(size);
1323	    if (lpIR == NULL) {
1324		if (res != 0) {
1325		    DestroyIcon(sfi.hIcon);
1326		}
1327		DestroyIcon(sfiSM.hIcon);
1328		Tcl_DStringFree(&ds2);
1329		return NULL;
1330	    }
1331	    ZeroMemory(lpIR, size);
1332
1333	    lpIR->nNumImages		= ((res != 0) ? 2 : 1);
1334	    lpIR->IconImages[0].Width	= 16;
1335	    lpIR->IconImages[0].Height	= 16;
1336	    lpIR->IconImages[0].Colors	= 4;
1337	    lpIR->IconImages[0].hIcon	= sfiSM.hIcon;
1338
1339	    /*
1340	     * All other IconImages fields are ignored.
1341	     */
1342
1343	    if (res != 0) {
1344		lpIR->IconImages[1].Width	= 32;
1345		lpIR->IconImages[1].Height	= 32;
1346		lpIR->IconImages[1].Colors	= 4;
1347		lpIR->IconImages[1].hIcon	= sfi.hIcon;
1348	    }
1349	}
1350	Tcl_DStringFree(&ds2);
1351    }
1352    if (lpIR != NULL) {
1353	titlebaricon = (WinIconPtr) ckalloc(sizeof(WinIconInstance));
1354	titlebaricon->iconBlock = lpIR;
1355	titlebaricon->refCount = 1;
1356    }
1357    return titlebaricon;
1358}
1359
1360/*
1361 *----------------------------------------------------------------------
1362 *
1363 * GetIconFromPixmap --
1364 *
1365 *	Turn a Tk Pixmap (i.e. a bitmap) into an icon resource, if possible,
1366 *	otherwise NULL is returned.
1367 *
1368 * Results:
1369 *	A WinIconPtr structure containing a conversion of the given bitmap
1370 *	into an icon, with its ref count already incremented. The calling
1371 *	function should either place this structure inside a WmInfo structure,
1372 *	or it should pass it on to DecrIconRefCount() to ensure no memory
1373 *	leaks occur.
1374 *
1375 *	If the given pixmap did not contain a valid icon structure, return
1376 *	NULL.
1377 *
1378 * Side effects:
1379 *	Memory is allocated for the returned structure and the icons it
1380 *	contains. If the structure is not wanted, it should be passed to
1381 *	DecrIconRefCount, and in any case a valid ref count should be ensured
1382 *	to avoid memory leaks.
1383 *
1384 *	Currently icon resources are not shared, so the ref count of one of
1385 *	these structures will always be 0 or 1. However all we need do is
1386 *	implement some sort of lookup function between pixmaps and WinIconPtr
1387 *	structures and no other code will need to be changed.
1388 *
1389 *----------------------------------------------------------------------
1390 */
1391
1392static WinIconPtr
1393GetIconFromPixmap(
1394    Display *dsPtr,
1395    Pixmap pixmap)
1396{
1397    WinIconPtr titlebaricon = NULL;
1398    TkWinDrawable *twdPtr = (TkWinDrawable*) pixmap;
1399    BlockOfIconImagesPtr lpIR;
1400    ICONINFO icon;
1401    HICON hIcon;
1402    int width, height;
1403
1404    if (twdPtr == NULL) {
1405	return NULL;
1406    }
1407
1408    if (0 /* If we already have an icon for this pixmap */) {
1409	titlebaricon = NULL; /* Get the real value from a lookup */
1410	titlebaricon->refCount++;
1411	return titlebaricon;
1412    }
1413
1414    Tk_SizeOfBitmap(dsPtr, pixmap, &width, &height);
1415
1416    icon.fIcon = TRUE;
1417    icon.xHotspot = 0;
1418    icon.yHotspot = 0;
1419    icon.hbmMask = twdPtr->bitmap.handle;
1420    icon.hbmColor = twdPtr->bitmap.handle;
1421
1422    hIcon = CreateIconIndirect(&icon);
1423    if (hIcon == NULL) {
1424	return NULL;
1425    }
1426
1427    lpIR = (BlockOfIconImagesPtr) ckalloc(sizeof(BlockOfIconImages));
1428    if (lpIR == NULL) {
1429	DestroyIcon(hIcon);
1430	return NULL;
1431    }
1432
1433    lpIR->nNumImages = 1;
1434    lpIR->IconImages[0].Width = width;
1435    lpIR->IconImages[0].Height = height;
1436    lpIR->IconImages[0].Colors = 1 << twdPtr->bitmap.depth;
1437    lpIR->IconImages[0].hIcon = hIcon;
1438
1439    /*
1440     * These fields are ignored.
1441     */
1442
1443    lpIR->IconImages[0].lpBits = 0;
1444    lpIR->IconImages[0].dwNumBytes = 0;
1445    lpIR->IconImages[0].lpXOR = 0;
1446    lpIR->IconImages[0].lpAND = 0;
1447
1448    titlebaricon = (WinIconPtr) ckalloc(sizeof(WinIconInstance));
1449    titlebaricon->iconBlock = lpIR;
1450    titlebaricon->refCount = 1;
1451    return titlebaricon;
1452}
1453
1454/*
1455 *----------------------------------------------------------------------
1456 *
1457 * DecrIconRefCount --
1458 *
1459 *	Reduces the reference count.
1460 *
1461 * Results:
1462 *	None.
1463 *
1464 * Side effects:
1465 *	If the ref count falls to zero, free the memory associated with the
1466 *	icon resource structures. In this case the pointer passed into this
1467 *	function is no longer valid.
1468 *
1469 *----------------------------------------------------------------------
1470 */
1471
1472static void
1473DecrIconRefCount(
1474    WinIconPtr titlebaricon)
1475{
1476    titlebaricon->refCount--;
1477
1478    if (titlebaricon->refCount <= 0) {
1479	if (titlebaricon->iconBlock != NULL) {
1480	    FreeIconBlock(titlebaricon->iconBlock);
1481	}
1482	titlebaricon->iconBlock = NULL;
1483
1484	ckfree((char*)titlebaricon);
1485    }
1486}
1487
1488/*
1489 *----------------------------------------------------------------------
1490 *
1491 * FreeIconBlock --
1492 *
1493 *	Frees all memory associated with a previously loaded titlebaricon.
1494 *	The icon block pointer is no longer valid once this function returns.
1495 *
1496 * Results:
1497 *	None.
1498 *
1499 * Side effects:
1500 *
1501 *
1502 *----------------------------------------------------------------------
1503 */
1504
1505static void
1506FreeIconBlock(
1507    BlockOfIconImagesPtr lpIR)
1508{
1509    int i;
1510
1511    /*
1512     * Free all the bits.
1513     */
1514
1515    for (i=0; i< lpIR->nNumImages; i++) {
1516	if (lpIR->IconImages[i].lpBits != NULL) {
1517	    ckfree((char*)lpIR->IconImages[i].lpBits);
1518	}
1519	if (lpIR->IconImages[i].hIcon != NULL) {
1520	    DestroyIcon(lpIR->IconImages[i].hIcon);
1521	}
1522    }
1523    ckfree ((char*)lpIR);
1524}
1525
1526/*
1527 *----------------------------------------------------------------------
1528 *
1529 * GetIcon --
1530 *
1531 *	Extracts an icon of a given size from an icon resource
1532 *
1533 * Results:
1534 *	Returns the icon, if found, else NULL.
1535 *
1536 *----------------------------------------------------------------------
1537 */
1538
1539static HICON
1540GetIcon(
1541    WinIconPtr titlebaricon,
1542    int icon_size)
1543{
1544    BlockOfIconImagesPtr lpIR;
1545
1546    if (titlebaricon == NULL) {
1547	return NULL;
1548    }
1549
1550    lpIR = titlebaricon->iconBlock;
1551    if (lpIR == NULL) {
1552	return NULL;
1553    } else {
1554	unsigned int size = (icon_size == 0 ? 16 : 32);
1555	int i;
1556
1557	for (i = 0; i < lpIR->nNumImages; i++) {
1558	    /*
1559	     * Take the first or a 32x32 16 color icon
1560	     */
1561
1562	    if ((lpIR->IconImages[i].Height == size)
1563		    && (lpIR->IconImages[i].Width == size)
1564		    && (lpIR->IconImages[i].Colors >= 4)) {
1565		return lpIR->IconImages[i].hIcon;
1566	    }
1567	}
1568
1569	/*
1570	 * If we get here, then just return the first one, it will have to do!
1571	 */
1572
1573	if (lpIR->nNumImages >= 1) {
1574	    return lpIR->IconImages[0].hIcon;
1575	}
1576    }
1577    return NULL;
1578}
1579
1580#if 0 /* UNUSED */
1581static HCURSOR
1582TclWinReadCursorFromFile(
1583    Tcl_Interp* interp,
1584    Tcl_Obj* fileName)
1585{
1586    BlockOfIconImagesPtr lpIR;
1587    HICON res = NULL;
1588
1589    lpIR = ReadIconOrCursorFromFile(interp, fileName, FALSE);
1590    if (lpIR == NULL) {
1591	return NULL;
1592    }
1593    if (lpIR->nNumImages >= 1) {
1594	res = CopyImage(lpIR->IconImages[0].hIcon, IMAGE_CURSOR,0,0,0);
1595    }
1596    FreeIconBlock(lpIR);
1597    return res;
1598}
1599#endif
1600
1601/*
1602 *----------------------------------------------------------------------
1603 *
1604 * ReadIconOrCursorFromFile --
1605 *
1606 *	Reads an Icon Resource from an ICO file, as given by char* fileName -
1607 *	Name of the ICO file. This name should be in Utf format.
1608 *
1609 * Results:
1610 *	Returns an icon resource, if found, else NULL.
1611 *
1612 * Side effects:
1613 *	May leave error messages in the Tcl interpreter.
1614 *
1615 *----------------------------------------------------------------------
1616 */
1617
1618static BlockOfIconImagesPtr
1619ReadIconOrCursorFromFile(
1620    Tcl_Interp *interp,
1621    Tcl_Obj *fileName,
1622    BOOL isIcon)
1623{
1624    BlockOfIconImagesPtr lpIR;
1625    Tcl_Channel channel;
1626    int i;
1627    DWORD dwBytesRead;
1628    LPICONDIRENTRY lpIDE;
1629
1630    /*
1631     * Open the file.
1632     */
1633
1634    channel = Tcl_FSOpenFileChannel(interp, fileName, "r", 0);
1635    if (channel == NULL) {
1636	Tcl_AppendResult(interp,"Error opening file \"",
1637		Tcl_GetString(fileName), "\" for reading", NULL);
1638	return NULL;
1639    }
1640    if (Tcl_SetChannelOption(interp, channel, "-translation", "binary")
1641	    != TCL_OK) {
1642	Tcl_Close(NULL, channel);
1643	return NULL;
1644    }
1645    if (Tcl_SetChannelOption(interp, channel, "-encoding", "binary")
1646	    != TCL_OK) {
1647	Tcl_Close(NULL, channel);
1648	return NULL;
1649    }
1650
1651    /*
1652     * Allocate memory for the resource structure
1653     */
1654
1655    lpIR = (BlockOfIconImagesPtr) ckalloc(sizeof(BlockOfIconImages));
1656
1657    /*
1658     * Read in the header
1659     */
1660
1661    if ((lpIR->nNumImages = ReadICOHeader(channel)) == -1) {
1662	Tcl_AppendResult(interp, "Invalid file header", NULL);
1663	Tcl_Close(NULL, channel);
1664	ckfree((char*) lpIR);
1665	return NULL;
1666    }
1667
1668    /*
1669     * Adjust the size of the struct to account for the images.
1670     */
1671
1672    lpIR = (BlockOfIconImagesPtr) ckrealloc((char*) lpIR,
1673	    sizeof(BlockOfIconImages)
1674	    + ((lpIR->nNumImages - 1) * sizeof(ICONIMAGE)));
1675
1676    /*
1677     * Allocate enough memory for the icon directory entries.
1678     */
1679
1680    lpIDE = (LPICONDIRENTRY) ckalloc(lpIR->nNumImages * sizeof(ICONDIRENTRY));
1681
1682    /*
1683     * Read in the icon directory entries.
1684     */
1685
1686    dwBytesRead = Tcl_Read(channel, (char*) lpIDE,
1687	    (int)(lpIR->nNumImages * sizeof(ICONDIRENTRY)));
1688    if (dwBytesRead != lpIR->nNumImages * sizeof(ICONDIRENTRY)) {
1689	Tcl_AppendResult(interp, "Error reading file", NULL);
1690	Tcl_Close(NULL, channel);
1691	ckfree((char *) lpIDE);
1692	ckfree((char *) lpIR);
1693	return NULL;
1694    }
1695
1696    /*
1697     * NULL-out everything to make memory management easier.
1698     */
1699
1700    for (i = 0; i < lpIR->nNumImages; i++) {
1701	lpIR->IconImages[i].lpBits = NULL;
1702    }
1703
1704    /*
1705     * Loop through and read in each image.
1706     */
1707
1708    for (i=0 ; i<lpIR->nNumImages ; i++) {
1709	/*
1710	 * Allocate memory for the resource.
1711	 */
1712
1713	lpIR->IconImages[i].lpBits = (LPBYTE) ckalloc(lpIDE[i].dwBytesInRes);
1714	lpIR->IconImages[i].dwNumBytes = lpIDE[i].dwBytesInRes;
1715
1716	/*
1717	 * Seek to beginning of this image.
1718	 */
1719
1720	if (Tcl_Seek(channel, lpIDE[i].dwImageOffset, FILE_BEGIN) == -1) {
1721	    Tcl_AppendResult(interp, "Error seeking in file", NULL);
1722	    goto readError;
1723	}
1724
1725	/*
1726	 * Read it in.
1727	 */
1728
1729	dwBytesRead = Tcl_Read(channel, lpIR->IconImages[i].lpBits,
1730		(int) lpIDE[i].dwBytesInRes);
1731	if (dwBytesRead != lpIDE[i].dwBytesInRes) {
1732	    Tcl_AppendResult(interp, "Error reading file", NULL);
1733	    goto readError;
1734	}
1735
1736	/*
1737	 * Set the internal pointers appropriately.
1738	 */
1739
1740	if (!AdjustIconImagePointers( &(lpIR->IconImages[i]))) {
1741	    Tcl_AppendResult(interp, "Error converting to internal format",
1742		    NULL);
1743	    goto readError;
1744	}
1745	lpIR->IconImages[i].hIcon =
1746		MakeIconOrCursorFromResource(&(lpIR->IconImages[i]), isIcon);
1747    }
1748
1749    /*
1750     * Clean up
1751     */
1752
1753    ckfree((char *) lpIDE);
1754    Tcl_Close(NULL, channel);
1755    if (lpIR == NULL){
1756	Tcl_AppendResult(interp, "Reading of ", Tcl_GetString(fileName),
1757		" failed!", NULL);
1758	return NULL;
1759    }
1760    return lpIR;
1761
1762  readError:
1763    Tcl_Close(NULL, channel);
1764    for (i = 0; i < lpIR->nNumImages; i++) {
1765	if (lpIR->IconImages[i].lpBits != NULL) {
1766	    ckfree((char *) lpIR->IconImages[i].lpBits);
1767	}
1768    }
1769    ckfree((char *) lpIDE);
1770    ckfree((char *) lpIR);
1771    return NULL;
1772}
1773
1774/*
1775 *----------------------------------------------------------------------
1776 *
1777 * GetTopLevel --
1778 *
1779 *	This function retrieves the TkWindow associated with the given HWND.
1780 *
1781 * Results:
1782 *	Returns the matching TkWindow.
1783 *
1784 * Side effects:
1785 *	None.
1786 *
1787 *----------------------------------------------------------------------
1788 */
1789
1790static TkWindow *
1791GetTopLevel(
1792    HWND hwnd)
1793{
1794    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1795	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1796
1797    /*
1798     * If this function is called before the CreateWindowEx call has
1799     * completed, then the user data slot will not have been set yet, so we
1800     * use the global createWindow variable.
1801     */
1802
1803    if (tsdPtr->createWindow) {
1804	return tsdPtr->createWindow;
1805    }
1806    return (TkWindow *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1807}
1808
1809/*
1810 *----------------------------------------------------------------------
1811 *
1812 * SetLimits --
1813 *
1814 *	Updates the minimum and maximum window size constraints.
1815 *
1816 * Results:
1817 *	None.
1818 *
1819 * Side effects:
1820 *	Changes the values of the info pointer to reflect the current minimum
1821 *	and maximum size values.
1822 *
1823 *----------------------------------------------------------------------
1824 */
1825
1826static void
1827SetLimits(
1828    HWND hwnd,
1829    MINMAXINFO *info)
1830{
1831    register WmInfo *wmPtr;
1832    int maxWidth, maxHeight;
1833    int minWidth, minHeight;
1834    int base;
1835    TkWindow *winPtr = GetTopLevel(hwnd);
1836
1837    if (winPtr == NULL) {
1838	return;
1839    }
1840
1841    wmPtr = winPtr->wmInfoPtr;
1842
1843    /*
1844     * Copy latest constraint info.
1845     */
1846
1847    wmPtr->defMinWidth = info->ptMinTrackSize.x;
1848    wmPtr->defMinHeight = info->ptMinTrackSize.y;
1849    wmPtr->defMaxWidth = info->ptMaxTrackSize.x;
1850    wmPtr->defMaxHeight = info->ptMaxTrackSize.y;
1851
1852    GetMaxSize(wmPtr, &maxWidth, &maxHeight);
1853    GetMinSize(wmPtr, &minWidth, &minHeight);
1854
1855    if (wmPtr->gridWin != NULL) {
1856	base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
1857	if (base < 0) {
1858	    base = 0;
1859	}
1860	base += wmPtr->borderWidth;
1861	info->ptMinTrackSize.x = base + (minWidth * wmPtr->widthInc);
1862	info->ptMaxTrackSize.x = base + (maxWidth * wmPtr->widthInc);
1863
1864	base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
1865	if (base < 0) {
1866	    base = 0;
1867	}
1868	base += wmPtr->borderHeight;
1869	info->ptMinTrackSize.y = base + (minHeight * wmPtr->heightInc);
1870	info->ptMaxTrackSize.y = base + (maxHeight * wmPtr->heightInc);
1871    } else {
1872	info->ptMaxTrackSize.x = maxWidth + wmPtr->borderWidth;
1873	info->ptMaxTrackSize.y = maxHeight + wmPtr->borderHeight;
1874	info->ptMinTrackSize.x = minWidth + wmPtr->borderWidth;
1875	info->ptMinTrackSize.y = minHeight + wmPtr->borderHeight;
1876    }
1877
1878    /*
1879     * If the window isn't supposed to be resizable, then set the minimum and
1880     * maximum dimensions to be the same as the current size.
1881     */
1882
1883    if (!(wmPtr->flags & WM_SYNC_PENDING)) {
1884	if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
1885	    info->ptMinTrackSize.x = winPtr->changes.width
1886		+ wmPtr->borderWidth;
1887	    info->ptMaxTrackSize.x = info->ptMinTrackSize.x;
1888	}
1889	if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
1890	    info->ptMinTrackSize.y = winPtr->changes.height
1891		+ wmPtr->borderHeight;
1892	    info->ptMaxTrackSize.y = info->ptMinTrackSize.y;
1893	}
1894    }
1895}
1896
1897/*
1898 *----------------------------------------------------------------------
1899 *
1900 * TkWinWmCleanup --
1901 *
1902 *	Unregisters classes registered by the window manager. This is called
1903 *	from the DLL main entry point when the DLL is unloaded.
1904 *
1905 * Results:
1906 *	None.
1907 *
1908 * Side effects:
1909 *	The window classes are discarded.
1910 *
1911 *----------------------------------------------------------------------
1912 */
1913
1914void
1915TkWinWmCleanup(
1916    HINSTANCE hInstance)
1917{
1918    ThreadSpecificData *tsdPtr;
1919
1920    /*
1921     * If we're using stubs to access the Tcl library, and they haven't been
1922     * initialized, we can't call Tcl_GetThreadData.
1923     */
1924
1925#ifdef USE_TCL_STUBS
1926    if (tclStubsPtr == NULL) {
1927	return;
1928    }
1929#endif
1930
1931    if (!initialized) {
1932	return;
1933    }
1934    initialized = 0;
1935
1936    tsdPtr = (ThreadSpecificData *)
1937	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1938
1939    if (!tsdPtr->initialized) {
1940	return;
1941    }
1942    tsdPtr->initialized = 0;
1943
1944    UnregisterClass(TK_WIN_TOPLEVEL_CLASS_NAME, hInstance);
1945}
1946
1947/*
1948 *--------------------------------------------------------------
1949 *
1950 * TkWmNewWindow --
1951 *
1952 *	This function is invoked whenever a new top-level window is created.
1953 *	Its job is to initialize the WmInfo structure for the window.
1954 *
1955 * Results:
1956 *	None.
1957 *
1958 * Side effects:
1959 *	A WmInfo structure gets allocated and initialized.
1960 *
1961 *--------------------------------------------------------------
1962 */
1963
1964void
1965TkWmNewWindow(
1966    TkWindow *winPtr)		/* Newly-created top-level window. */
1967{
1968    register WmInfo *wmPtr;
1969
1970    wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
1971
1972    /*
1973     * Initialize full structure, then set what isn't NULL
1974     */
1975
1976    ZeroMemory(wmPtr, sizeof(WmInfo));
1977    winPtr->wmInfoPtr = wmPtr;
1978    wmPtr->winPtr = winPtr;
1979    wmPtr->hints.flags = InputHint | StateHint;
1980    wmPtr->hints.input = True;
1981    wmPtr->hints.initial_state = NormalState;
1982    wmPtr->hints.icon_pixmap = None;
1983    wmPtr->hints.icon_window = None;
1984    wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
1985    wmPtr->hints.icon_mask = None;
1986    wmPtr->hints.window_group = None;
1987
1988    /*
1989     * Default the maximum dimensions to the size of the display.
1990     */
1991
1992    wmPtr->defMinWidth = wmPtr->defMinHeight = 0;
1993    wmPtr->defMaxWidth = DisplayWidth(winPtr->display, winPtr->screenNum);
1994    wmPtr->defMaxHeight = DisplayHeight(winPtr->display, winPtr->screenNum);
1995    wmPtr->minWidth = wmPtr->minHeight = 1;
1996    wmPtr->maxWidth = wmPtr->maxHeight = 0;
1997    wmPtr->widthInc = wmPtr->heightInc = 1;
1998    wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
1999    wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
2000    wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
2001    wmPtr->gravity = NorthWestGravity;
2002    wmPtr->width = -1;
2003    wmPtr->height = -1;
2004    wmPtr->x = winPtr->changes.x;
2005    wmPtr->y = winPtr->changes.y;
2006    wmPtr->crefObj = NULL;
2007    wmPtr->colorref = (COLORREF) NULL;
2008    wmPtr->alpha = 1.0;
2009
2010    wmPtr->configWidth = -1;
2011    wmPtr->configHeight = -1;
2012    wmPtr->flags = WM_NEVER_MAPPED;
2013    wmPtr->nextPtr = winPtr->dispPtr->firstWmPtr;
2014    winPtr->dispPtr->firstWmPtr = wmPtr;
2015
2016    /*
2017     * Tk must monitor structure events for top-level windows, in order to
2018     * detect size and position changes caused by window managers.
2019     */
2020
2021    Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
2022	    TopLevelEventProc, (ClientData) winPtr);
2023
2024    /*
2025     * Arrange for geometry requests to be reflected from the window to the
2026     * window manager.
2027     */
2028
2029    Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
2030}
2031
2032/*
2033 *----------------------------------------------------------------------
2034 *
2035 * UpdateWrapper --
2036 *
2037 *	This function creates the wrapper window that contains the window
2038 *	decorations and menus for a toplevel. This function may be called
2039 *	after a window is mapped to change the window style.
2040 *
2041 * Results:
2042 *	None.
2043 *
2044 * Side effects:
2045 *	Destroys any old wrapper window and replaces it with a newly created
2046 *	wrapper.
2047 *
2048 *----------------------------------------------------------------------
2049 */
2050
2051static void
2052UpdateWrapper(
2053    TkWindow *winPtr)		/* Top-level window to redecorate. */
2054{
2055    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2056    HWND parentHWND, oldWrapper = wmPtr->wrapper;
2057    HWND child, nextHWND, focusHWND;
2058    int x, y, width, height, state;
2059    WINDOWPLACEMENT place;
2060    HICON hSmallIcon = NULL;
2061    HICON hBigIcon = NULL;
2062    Tcl_DString titleString, classString;
2063    int *childStateInfo = NULL;
2064    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
2065	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2066
2067    if (winPtr->window == None) {
2068	/*
2069	 * Ensure existence of the window to update the wrapper for.
2070	 */
2071
2072	Tk_MakeWindowExist((Tk_Window) winPtr);
2073    }
2074
2075    child = TkWinGetHWND(winPtr->window);
2076    parentHWND = NULL;
2077
2078    /*
2079     * nextHWND will help us maintain Z order. focusHWND will help us maintain
2080     * focus, if we had it.
2081     */
2082
2083    nextHWND = NULL;
2084    focusHWND = GetFocus();
2085    if ((oldWrapper == NULL) || (oldWrapper != GetForegroundWindow())) {
2086	focusHWND = NULL;
2087    }
2088
2089    if (winPtr->flags & TK_EMBEDDED) {
2090	wmPtr->wrapper = (HWND) winPtr->privatePtr;
2091	if (wmPtr->wrapper == NULL) {
2092	    Tcl_Panic("UpdateWrapper: Cannot find container window");
2093	}
2094	if (!IsWindow(wmPtr->wrapper)) {
2095	    Tcl_Panic("UpdateWrapper: Container was destroyed");
2096	}
2097
2098    } else {
2099	/*
2100	 * Pick the decorative frame style. Override redirect windows get
2101	 * created as undecorated popups if they have no transient parent,
2102	 * otherwise they are children. This allows splash screens to operate
2103	 * as an independent window, while having dropdows (like for a
2104	 * combobox) not grab focus away from their parent. Transient windows
2105	 * get a modal dialog frame. Neither override, nor transient windows
2106	 * appear in the Windows taskbar. Note that a transient window does
2107	 * not resize by default, so we need to explicitly add the
2108	 * WS_THICKFRAME style if we want it to be resizeable.
2109	 */
2110
2111	if (winPtr->atts.override_redirect) {
2112	    wmPtr->style = WM_OVERRIDE_STYLE;
2113	    wmPtr->exStyle = EX_OVERRIDE_STYLE;
2114
2115	    /*
2116	     * Parent must be desktop even if we have a transient parent.
2117	     */
2118
2119	    parentHWND = GetDesktopWindow();
2120	    if (wmPtr->masterPtr) {
2121		wmPtr->style |= WS_CHILD;
2122	    } else {
2123		wmPtr->style |= WS_POPUP;
2124	    }
2125	} else if (wmPtr->flags & WM_FULLSCREEN) {
2126	    wmPtr->style = WM_FULLSCREEN_STYLE;
2127	    wmPtr->exStyle = EX_FULLSCREEN_STYLE;
2128	} else if (wmPtr->masterPtr) {
2129	    wmPtr->style = WM_TRANSIENT_STYLE;
2130	    wmPtr->exStyle = EX_TRANSIENT_STYLE;
2131	    parentHWND = Tk_GetHWND(Tk_WindowId(wmPtr->masterPtr));
2132	    if (! ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
2133		    (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE))) {
2134		wmPtr->style |= WS_THICKFRAME;
2135	    }
2136	} else {
2137	    wmPtr->style = WM_TOPLEVEL_STYLE;
2138	    wmPtr->exStyle = EX_TOPLEVEL_STYLE;
2139	}
2140
2141	wmPtr->style |= wmPtr->styleConfig;
2142	wmPtr->exStyle |= wmPtr->exStyleConfig;
2143
2144	if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE)
2145		&& (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
2146	    wmPtr->style &= ~ (WS_MAXIMIZEBOX | WS_SIZEBOX);
2147	}
2148
2149	/*
2150	 * Compute the geometry of the parent and child windows.
2151	 */
2152
2153	wmPtr->flags |= WM_CREATE_PENDING|WM_MOVE_PENDING;
2154	UpdateGeometryInfo((ClientData)winPtr);
2155	wmPtr->flags &= ~(WM_CREATE_PENDING|WM_MOVE_PENDING);
2156
2157	width = wmPtr->borderWidth + winPtr->changes.width;
2158	height = wmPtr->borderHeight + winPtr->changes.height;
2159
2160	/*
2161	 * Set the initial position from the user or program specified
2162	 * location. If nothing has been specified, then let the system pick a
2163	 * location. In full screen mode the x,y origin is 0,0 and the window
2164	 * width and height match that of the screen.
2165	 */
2166
2167	if (wmPtr->flags & WM_FULLSCREEN) {
2168	    x = 0;
2169	    y = 0;
2170	    width = WidthOfScreen(Tk_Screen(winPtr));
2171	    height = HeightOfScreen(Tk_Screen(winPtr));
2172	} else if (!(wmPtr->sizeHintsFlags & (USPosition | PPosition))
2173		&& (wmPtr->flags & WM_NEVER_MAPPED)) {
2174	    x = CW_USEDEFAULT;
2175	    y = CW_USEDEFAULT;
2176	} else {
2177	    x = winPtr->changes.x;
2178	    y = winPtr->changes.y;
2179	}
2180
2181	/*
2182	 * Create the containing window, and set the user data to point to the
2183	 * TkWindow.
2184	 */
2185
2186	tsdPtr->createWindow = winPtr;
2187	Tcl_WinUtfToTChar(((wmPtr->title != NULL) ?
2188		wmPtr->title : winPtr->nameUid), -1, &titleString);
2189
2190	Tcl_WinUtfToTChar(TK_WIN_TOPLEVEL_CLASS_NAME, -1, &classString);
2191
2192	wmPtr->wrapper = (*tkWinProcs->createWindowEx)(wmPtr->exStyle,
2193		(LPCTSTR) Tcl_DStringValue(&classString),
2194		(LPCTSTR) Tcl_DStringValue(&titleString),
2195		wmPtr->style, x, y, width, height,
2196		parentHWND, NULL, Tk_GetHINSTANCE(), NULL);
2197	Tcl_DStringFree(&classString);
2198	Tcl_DStringFree(&titleString);
2199	SetWindowLongPtr(wmPtr->wrapper, GWLP_USERDATA, (INT_PTR) winPtr);
2200	tsdPtr->createWindow = NULL;
2201
2202	if ((wmPtr->exStyleConfig & WS_EX_LAYERED)
2203		&& setLayeredWindowAttributesProc != NULL) {
2204	    /*
2205	     * The user supplies a double from [0..1], but Windows wants an
2206	     * int (transparent) 0..255 (opaque), so do the translation. Add
2207	     * the 0.5 to round the value.
2208	     */
2209
2210	    setLayeredWindowAttributesProc((HWND) wmPtr->wrapper,
2211		    wmPtr->colorref, (BYTE) (wmPtr->alpha * 255 + 0.5),
2212		    (unsigned)(LWA_ALPHA | (wmPtr->crefObj?LWA_COLORKEY:0)));
2213	} else {
2214	    /*
2215	     * Layering not used or supported.
2216	     */
2217	    wmPtr->alpha = 1.0;
2218	    if (wmPtr->crefObj) {
2219		Tcl_DecrRefCount(wmPtr->crefObj);
2220		wmPtr->crefObj = NULL;
2221	    }
2222	}
2223
2224	place.length = sizeof(WINDOWPLACEMENT);
2225	GetWindowPlacement(wmPtr->wrapper, &place);
2226	wmPtr->x = place.rcNormalPosition.left;
2227	wmPtr->y = place.rcNormalPosition.top;
2228
2229	if( !(winPtr->flags & TK_ALREADY_DEAD) )
2230	    TkInstallFrameMenu((Tk_Window) winPtr);
2231
2232	if (oldWrapper && (oldWrapper != wmPtr->wrapper)
2233		&& !(wmPtr->exStyle & WS_EX_TOPMOST)) {
2234	    /*
2235	     * We will adjust wrapper to have the same Z order as oldWrapper
2236	     * if it isn't a TOPMOST window.
2237	     */
2238
2239	    nextHWND = GetNextWindow(oldWrapper, GW_HWNDPREV);
2240	}
2241    }
2242
2243    /*
2244     * Now we need to reparent the contained window and set its style
2245     * appropriately. Be sure to update the style first so that Windows
2246     * doesn't try to set the focus to the child window.
2247     */
2248
2249    SetWindowLongPtr(child, GWL_STYLE,
2250	    WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
2251
2252    if (winPtr->flags & TK_EMBEDDED) {
2253	SetWindowLongPtr(child, GWLP_WNDPROC, (INT_PTR) TopLevelProc);
2254    }
2255
2256    SetParent(child, wmPtr->wrapper);
2257    if (oldWrapper) {
2258	hSmallIcon = (HICON) SendMessage(oldWrapper, WM_GETICON, ICON_SMALL,
2259		(LPARAM) NULL);
2260	hBigIcon = (HICON) SendMessage(oldWrapper, WM_GETICON, ICON_BIG,
2261		(LPARAM) NULL);
2262    }
2263
2264    if (oldWrapper && (oldWrapper != wmPtr->wrapper)
2265	    && (oldWrapper != GetDesktopWindow())) {
2266	SetWindowLongPtr(oldWrapper, GWLP_USERDATA, (LONG) NULL);
2267
2268	if (wmPtr->numTransients > 0) {
2269	    /*
2270	     * Unset the current wrapper as the parent for all transient
2271	     * children for whom this is the master
2272	     */
2273
2274	    WmInfo *wmPtr2;
2275
2276	    childStateInfo = (int *)
2277		    ckalloc((unsigned) wmPtr->numTransients * sizeof(int));
2278	    state = 0;
2279	    for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
2280		    wmPtr2 = wmPtr2->nextPtr) {
2281		if (wmPtr2->masterPtr == winPtr
2282			&& !(wmPtr2->flags & WM_NEVER_MAPPED)) {
2283		    childStateInfo[state++] = wmPtr2->hints.initial_state;
2284		    SetParent(TkWinGetHWND(wmPtr2->winPtr->window), NULL);
2285		}
2286	    }
2287	}
2288
2289	/*
2290	 * Remove the menubar before destroying the window so the menubar
2291	 * isn't destroyed.
2292	 */
2293
2294	SetMenu(oldWrapper, NULL);
2295	DestroyWindow(oldWrapper);
2296    }
2297
2298    wmPtr->flags &= ~WM_NEVER_MAPPED;
2299    if (winPtr->flags & TK_EMBEDDED
2300	    && SendMessage(wmPtr->wrapper, TK_ATTACHWINDOW, (WPARAM)child, 0)){
2301	SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ,
2302		Tk_ReqWidth((Tk_Window)winPtr),
2303		Tk_ReqHeight((Tk_Window)winPtr));
2304	SendMessage(wmPtr->wrapper, TK_SETMENU, (WPARAM) wmPtr->hMenu,
2305		(LPARAM) Tk_GetMenuHWND((Tk_Window) winPtr));
2306    }
2307
2308    /*
2309     * Force an initial transition from withdrawn to the real initial state.
2310     * Set the Z order based on previous wrapper before we set the state.
2311     */
2312
2313    state = wmPtr->hints.initial_state;
2314    wmPtr->hints.initial_state = WithdrawnState;
2315    if (nextHWND) {
2316	SetWindowPos(wmPtr->wrapper, nextHWND, 0, 0, 0, 0,
2317		SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOSENDCHANGING
2318		|SWP_NOOWNERZORDER);
2319    }
2320    TkpWmSetState(winPtr, state);
2321    wmPtr->hints.initial_state = state;
2322
2323    if (hSmallIcon != NULL) {
2324	SendMessage(wmPtr->wrapper,WM_SETICON,ICON_SMALL,(LPARAM)hSmallIcon);
2325    }
2326    if (hBigIcon != NULL) {
2327	SendMessage(wmPtr->wrapper,WM_SETICON,ICON_BIG,(LPARAM)hBigIcon);
2328    }
2329
2330    /*
2331     * If we are embedded then force a mapping of the window now, because we
2332     * do not necessarily own the wrapper and may not get another opportunity
2333     * to map ourselves. We should not be in either iconified or zoomed states
2334     * when we get here, so it is safe to just check for TK_EMBEDDED without
2335     * checking what state we are supposed to be in (default to NormalState).
2336     */
2337
2338    if (winPtr->flags & TK_EMBEDDED) {
2339	if(state+1 != SendMessage(wmPtr->wrapper, TK_STATE, state, 0)) {
2340	    TkpWmSetState(winPtr, NormalState);
2341	    wmPtr->hints.initial_state = NormalState;
2342	}
2343	XMapWindow(winPtr->display, winPtr->window);
2344    }
2345
2346    /*
2347     * Set up menus on the wrapper if required.
2348     */
2349
2350    if (wmPtr->hMenu != NULL) {
2351	wmPtr->flags |= WM_SYNC_PENDING;
2352	SetMenu(wmPtr->wrapper, wmPtr->hMenu);
2353	wmPtr->flags &= ~WM_SYNC_PENDING;
2354    }
2355
2356    if (childStateInfo) {
2357	if (wmPtr->numTransients > 0) {
2358	    /*
2359	     * Reset all transient children for whom this is the master.
2360	     */
2361
2362	    WmInfo *wmPtr2;
2363
2364	    state = 0;
2365	    for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
2366		    wmPtr2 = wmPtr2->nextPtr) {
2367		if (wmPtr2->masterPtr == winPtr
2368			&& !(wmPtr2->flags & WM_NEVER_MAPPED)) {
2369		    UpdateWrapper(wmPtr2->winPtr);
2370		    TkpWmSetState(wmPtr2->winPtr, childStateInfo[state++]);
2371		}
2372	    }
2373	}
2374
2375	ckfree((char *) childStateInfo);
2376    }
2377
2378    /*
2379     * If this is the first window created by the application, then we should
2380     * activate the initial window. Otherwise, if this had the focus, we need
2381     * to restore that.
2382     * XXX: Rewrapping generates a <FocusOut> and <FocusIn> that would best be
2383     * XXX: avoided, if we could safely mask them.
2384     */
2385
2386    if (tsdPtr->firstWindow) {
2387	tsdPtr->firstWindow = 0;
2388	SetActiveWindow(wmPtr->wrapper);
2389    } else if (focusHWND) {
2390	SetFocus(focusHWND);
2391    }
2392}
2393
2394/*
2395 *--------------------------------------------------------------
2396 *
2397 * TkWmMapWindow --
2398 *
2399 *	This function is invoked to map a top-level window. This module gets a
2400 *	chance to update all window-manager-related information in properties
2401 *	before the window manager sees the map event and checks the
2402 *	properties. It also gets to decide whether or not to even map the
2403 *	window after all.
2404 *
2405 * Results:
2406 *	None.
2407 *
2408 * Side effects:
2409 *	Properties of winPtr may get updated to provide up-to-date information
2410 *	to the window manager. The window may also get mapped, but it may not
2411 *	be if this function decides that isn't appropriate (e.g. because the
2412 *	window is withdrawn).
2413 *
2414 *--------------------------------------------------------------
2415 */
2416
2417void
2418TkWmMapWindow(
2419    TkWindow *winPtr)		/* Top-level window that's about to be
2420				 * mapped. */
2421{
2422    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2423    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
2424	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2425
2426    if (!tsdPtr->initialized) {
2427	InitWm();
2428    }
2429
2430    if (wmPtr->flags & WM_NEVER_MAPPED) {
2431	/*
2432	 * Don't map a transient if the master is not mapped.
2433	 */
2434
2435	if (wmPtr->masterPtr != NULL &&
2436		!Tk_IsMapped(wmPtr->masterPtr)) {
2437	    wmPtr->hints.initial_state = WithdrawnState;
2438	    return;
2439	}
2440    } else {
2441	if (wmPtr->hints.initial_state == WithdrawnState) {
2442	    return;
2443	}
2444
2445	/*
2446	 * Map the window in either the iconified or normal state. Note that
2447	 * we only send a map event if the window is in the normal state.
2448	 */
2449
2450	TkpWmSetState(winPtr, wmPtr->hints.initial_state);
2451    }
2452
2453    /*
2454     * This is the first time this window has ever been mapped. Store all the
2455     * window-manager-related information for the window.
2456     */
2457
2458    UpdateWrapper(winPtr);
2459}
2460
2461/*
2462 *--------------------------------------------------------------
2463 *
2464 * TkWmUnmapWindow --
2465 *
2466 *	This function is invoked to unmap a top-level window. The only thing
2467 *	it does special is unmap the decorative frame before unmapping the
2468 *	toplevel window.
2469 *
2470 * Results:
2471 *	None.
2472 *
2473 * Side effects:
2474 *	Unmaps the decorative frame and the window.
2475 *
2476 *--------------------------------------------------------------
2477 */
2478
2479void
2480TkWmUnmapWindow(
2481    TkWindow *winPtr)		/* Top-level window that's about to be
2482				 * unmapped. */
2483{
2484    TkpWmSetState(winPtr, WithdrawnState);
2485}
2486
2487/*
2488 *----------------------------------------------------------------------
2489 *
2490 * TkpWmSetState --
2491 *
2492 *	Sets the window manager state for the wrapper window of a given
2493 *	toplevel window.
2494 *
2495 * Results:
2496 *	None.
2497 *
2498 * Side effects:
2499 *	May maximize, minimize, restore, or withdraw a window.
2500 *
2501 *----------------------------------------------------------------------
2502 */
2503
2504void
2505TkpWmSetState(
2506    TkWindow *winPtr,		/* Toplevel window to operate on. */
2507    int state)			/* One of IconicState, ZoomState, NormalState,
2508				 * or WithdrawnState. */
2509{
2510    WmInfo *wmPtr = winPtr->wmInfoPtr;
2511    int cmd;
2512
2513    if (wmPtr->flags & WM_NEVER_MAPPED) {
2514	wmPtr->hints.initial_state = state;
2515	return;
2516    }
2517
2518    wmPtr->flags |= WM_SYNC_PENDING;
2519    if (state == WithdrawnState) {
2520	cmd = SW_HIDE;
2521    } else if (state == IconicState) {
2522	cmd = SW_SHOWMINNOACTIVE;
2523    } else if (state == NormalState) {
2524	cmd = SW_SHOWNOACTIVATE;
2525    } else if (state == ZoomState) {
2526	cmd = SW_SHOWMAXIMIZED;
2527    } else {
2528	return;
2529    }
2530
2531    ShowWindow(wmPtr->wrapper, cmd);
2532    wmPtr->flags &= ~WM_SYNC_PENDING;
2533}
2534
2535/*
2536 *----------------------------------------------------------------------
2537 *
2538 * TkpWmSetFullScreen --
2539 *
2540 *	Sets the fullscreen state for a toplevel window.
2541 *
2542 * Results:
2543 *	The WM_FULLSCREEN flag is updated.
2544 *
2545 * Side effects:
2546 *	May create a new wrapper window and raise it.
2547 *
2548 *----------------------------------------------------------------------
2549 */
2550
2551static void
2552TkpWmSetFullScreen(
2553    TkWindow *winPtr,		/* Toplevel window to operate on. */
2554    int full_screen_state)	/* True if window should be full screen */
2555{
2556    int changed = 0;
2557    int full_screen = False;
2558    WmInfo *wmPtr = winPtr->wmInfoPtr;
2559
2560    if (full_screen_state) {
2561	if (! (wmPtr->flags & WM_FULLSCREEN)) {
2562	    full_screen = True;
2563	    changed = 1;
2564	}
2565    } else {
2566	if (wmPtr->flags & WM_FULLSCREEN) {
2567	    full_screen = False;
2568	    changed = 1;
2569	}
2570    }
2571
2572    if (changed) {
2573	if (full_screen) {
2574	    wmPtr->flags |= WM_FULLSCREEN;
2575	    wmPtr->configX = wmPtr->x;
2576	    wmPtr->configY = wmPtr->y;
2577	} else {
2578	    wmPtr->flags &= ~WM_FULLSCREEN;
2579	    wmPtr->x = wmPtr->configX;
2580	    wmPtr->y = wmPtr->configY;
2581	}
2582
2583	/*
2584	 * If the window has been mapped, then we need to update the native
2585	 * wrapper window, and reset the focus to the widget that had it
2586	 * before.
2587	 */
2588
2589	if (!(wmPtr->flags & (WM_NEVER_MAPPED)
2590		&& !(winPtr->flags & TK_EMBEDDED))) {
2591	    TkWindow *focusWinPtr;
2592
2593	    UpdateWrapper(winPtr);
2594
2595	    focusWinPtr = TkGetFocusWin(winPtr);
2596	    if (focusWinPtr) {
2597		TkSetFocusWin(focusWinPtr, 1);
2598	    }
2599	}
2600    }
2601}
2602
2603/*
2604 *----------------------------------------------------------------------
2605 *
2606 * TkpWinGetState --
2607 *
2608 *	This function returns state value of a toplevel window.
2609 *
2610 * Results:
2611 *	none
2612 *
2613 * Side effects:
2614 *	May deiconify the toplevel window.
2615 *
2616 *----------------------------------------------------------------------
2617 */
2618
2619int
2620TkpWmGetState(
2621    TkWindow *winPtr)
2622{
2623    return winPtr->wmInfoPtr->hints.initial_state;
2624}
2625
2626/*
2627 *--------------------------------------------------------------
2628 *
2629 * TkWmDeadWindow --
2630 *
2631 *	This function is invoked when a top-level window is about to be
2632 *	deleted. It cleans up the wm-related data structures for the window.
2633 *
2634 * Results:
2635 *	None.
2636 *
2637 * Side effects:
2638 *	The WmInfo structure for winPtr gets freed up.
2639 *
2640 *--------------------------------------------------------------
2641 */
2642
2643void
2644TkWmDeadWindow(
2645    TkWindow *winPtr)		/* Top-level window that's being deleted. */
2646{
2647    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2648    WmInfo *wmPtr2;
2649
2650    if (wmPtr == NULL) {
2651	return;
2652    }
2653
2654    /*
2655     * Clean up event related window info.
2656     */
2657
2658    if (winPtr->dispPtr->firstWmPtr == wmPtr) {
2659	winPtr->dispPtr->firstWmPtr = wmPtr->nextPtr;
2660    } else {
2661	register WmInfo *prevPtr;
2662	for (prevPtr = winPtr->dispPtr->firstWmPtr; ;
2663		prevPtr = prevPtr->nextPtr) {
2664	    if (prevPtr == NULL) {
2665		Tcl_Panic("couldn't unlink window in TkWmDeadWindow");
2666	    }
2667	    if (prevPtr->nextPtr == wmPtr) {
2668		prevPtr->nextPtr = wmPtr->nextPtr;
2669		break;
2670	    }
2671	}
2672    }
2673
2674    /*
2675     * Reset all transient windows whose master is the dead window.
2676     */
2677
2678    for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
2679	 wmPtr2 = wmPtr2->nextPtr) {
2680	if (wmPtr2->masterPtr == winPtr) {
2681	    wmPtr->numTransients--;
2682	    Tk_DeleteEventHandler((Tk_Window) wmPtr2->masterPtr,
2683		    VisibilityChangeMask|StructureNotifyMask,
2684		    WmWaitVisibilityOrMapProc, (ClientData) wmPtr2->winPtr);
2685	    wmPtr2->masterPtr = NULL;
2686	    if ((wmPtr2->wrapper != None)
2687		    && !(wmPtr2->flags & (WM_NEVER_MAPPED))) {
2688		UpdateWrapper(wmPtr2->winPtr);
2689	    }
2690	}
2691    }
2692    if (wmPtr->numTransients != 0)
2693	Tcl_Panic("numTransients should be 0");
2694
2695    if (wmPtr->title != NULL) {
2696	ckfree(wmPtr->title);
2697    }
2698    if (wmPtr->iconName != NULL) {
2699	ckfree(wmPtr->iconName);
2700    }
2701    if (wmPtr->hints.flags & IconPixmapHint) {
2702	Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
2703    }
2704    if (wmPtr->hints.flags & IconMaskHint) {
2705	Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
2706    }
2707    if (wmPtr->leaderName != NULL) {
2708	ckfree(wmPtr->leaderName);
2709    }
2710    if (wmPtr->icon != NULL) {
2711	wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
2712	wmPtr2->iconFor = NULL;
2713    }
2714    if (wmPtr->iconFor != NULL) {
2715	wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
2716	wmPtr2->icon = NULL;
2717	wmPtr2->hints.flags &= ~IconWindowHint;
2718    }
2719    while (wmPtr->protPtr != NULL) {
2720	ProtocolHandler *protPtr;
2721
2722	protPtr = wmPtr->protPtr;
2723	wmPtr->protPtr = protPtr->nextPtr;
2724	Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
2725    }
2726    if (wmPtr->cmdArgv != NULL) {
2727	ckfree((char *) wmPtr->cmdArgv);
2728    }
2729    if (wmPtr->clientMachine != NULL) {
2730	ckfree((char *) wmPtr->clientMachine);
2731    }
2732    if (wmPtr->flags & WM_UPDATE_PENDING) {
2733	Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
2734    }
2735    if (wmPtr->masterPtr != NULL) {
2736	wmPtr2 = wmPtr->masterPtr->wmInfoPtr;
2737
2738	/*
2739	 * If we had a master, tell them that we aren't tied to them anymore.
2740	 */
2741
2742	if (wmPtr2 != NULL) {
2743	    wmPtr2->numTransients--;
2744	}
2745	Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
2746		VisibilityChangeMask|StructureNotifyMask,
2747		WmWaitVisibilityOrMapProc, (ClientData) winPtr);
2748	wmPtr->masterPtr = NULL;
2749    }
2750    if (wmPtr->crefObj != NULL) {
2751	Tcl_DecrRefCount(wmPtr->crefObj);
2752	wmPtr->crefObj = NULL;
2753    }
2754
2755    /*
2756     * Destroy the decorative frame window.
2757     */
2758
2759    if (!(winPtr->flags & TK_EMBEDDED)) {
2760	if (wmPtr->wrapper != NULL) {
2761	    DestroyWindow(wmPtr->wrapper);
2762	} else if (winPtr->window) {
2763	    DestroyWindow(Tk_GetHWND(winPtr->window));
2764	}
2765    } else {
2766	if (wmPtr->wrapper != NULL) {
2767	    SendMessage(wmPtr->wrapper, TK_DETACHWINDOW, 0, 0);
2768	}
2769    }
2770    if (wmPtr->iconPtr != NULL) {
2771	/*
2772	 * This may delete the icon resource data. I believe we should do this
2773	 * after destroying the decorative frame, because the decorative frame
2774	 * is using this icon.
2775	 */
2776
2777	DecrIconRefCount(wmPtr->iconPtr);
2778    }
2779
2780    ckfree((char *) wmPtr);
2781    winPtr->wmInfoPtr = NULL;
2782}
2783
2784/*
2785 *--------------------------------------------------------------
2786 *
2787 * TkWmSetClass --
2788 *
2789 *	This function is invoked whenever a top-level window's class is
2790 *	changed. If the window has been mapped then this function updates the
2791 *	window manager property for the class. If the window hasn't been
2792 *	mapped, the update is deferred until just before the first mapping.
2793 *
2794 * Results:
2795 *	None.
2796 *
2797 * Side effects:
2798 *	A window property may get updated.
2799 *
2800 *--------------------------------------------------------------
2801 */
2802
2803void
2804TkWmSetClass(
2805    TkWindow *winPtr)		/* Newly-created top-level window. */
2806{
2807    /* Do nothing */
2808    return;
2809}
2810
2811/*
2812 *----------------------------------------------------------------------
2813 *
2814 * Tk_WmObjCmd --
2815 *
2816 *	This function is invoked to process the "wm" Tcl command. See the user
2817 *	documentation for details on what it does.
2818 *
2819 * Results:
2820 *	A standard Tcl result.
2821 *
2822 * Side effects:
2823 *	See the user documentation.
2824 *
2825 *----------------------------------------------------------------------
2826 */
2827
2828	/* ARGSUSED */
2829int
2830Tk_WmObjCmd(
2831    ClientData clientData,	/* Main window associated with interpreter. */
2832    Tcl_Interp *interp,		/* Current interpreter. */
2833    int objc,			/* Number of arguments. */
2834    Tcl_Obj *CONST objv[])	/* Argument objects. */
2835{
2836    Tk_Window tkwin = (Tk_Window) clientData;
2837    static CONST char *optionStrings[] = {
2838	"aspect", "attributes", "client", "colormapwindows",
2839	"command", "deiconify", "focusmodel", "forget", "frame",
2840	"geometry", "grid", "group", "iconbitmap",
2841	"iconify", "iconmask", "iconname",
2842	"iconphoto", "iconposition",
2843	"iconwindow", "manage", "maxsize", "minsize", "overrideredirect",
2844	"positionfrom", "protocol", "resizable", "sizefrom",
2845	"stackorder", "state", "title", "transient",
2846	"withdraw", NULL
2847    };
2848    enum options {
2849	WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS,
2850	WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FORGET, WMOPT_FRAME,
2851	WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP, WMOPT_ICONBITMAP,
2852	WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME,
2853	WMOPT_ICONPHOTO, WMOPT_ICONPOSITION,
2854	WMOPT_ICONWINDOW, WMOPT_MANAGE, WMOPT_MAXSIZE, WMOPT_MINSIZE, WMOPT_OVERRIDEREDIRECT,
2855	WMOPT_POSITIONFROM, WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM,
2856	WMOPT_STACKORDER, WMOPT_STATE, WMOPT_TITLE, WMOPT_TRANSIENT,
2857	WMOPT_WITHDRAW
2858    };
2859    int index, length;
2860    char *argv1;
2861    TkWindow *winPtr, **winPtrPtr = &winPtr;
2862    TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
2863
2864    if (objc < 2) {
2865    wrongNumArgs:
2866	Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg ...?");
2867	return TCL_ERROR;
2868    }
2869
2870    argv1 = Tcl_GetStringFromObj(objv[1], &length);
2871    if ((argv1[0] == 't') && !strncmp(argv1, "tracing", (unsigned) length)
2872	    && (length >= 3)) {
2873	int wmTracing;
2874
2875	if ((objc != 2) && (objc != 3)) {
2876	    Tcl_WrongNumArgs(interp, 2, objv, "?boolean?");
2877	    return TCL_ERROR;
2878	}
2879	if (objc == 2) {
2880	    Tcl_SetResult(interp,
2881		    ((dispPtr->flags & TK_DISPLAY_WM_TRACING) ? "on" : "off"),
2882		    TCL_STATIC);
2883	    return TCL_OK;
2884	}
2885	if (Tcl_GetBooleanFromObj(interp, objv[2], &wmTracing) != TCL_OK) {
2886	    return TCL_ERROR;
2887	}
2888	if (wmTracing) {
2889	    dispPtr->flags |= TK_DISPLAY_WM_TRACING;
2890	} else {
2891	    dispPtr->flags &= ~TK_DISPLAY_WM_TRACING;
2892	}
2893	return TCL_OK;
2894    }
2895
2896    if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
2897	    &index) != TCL_OK) {
2898	return TCL_ERROR;
2899    }
2900
2901    if (objc < 3) {
2902	goto wrongNumArgs;
2903    }
2904
2905    if (TkGetWindowFromObj(interp, tkwin, objv[2], (Tk_Window *) winPtrPtr)
2906	    != TCL_OK) {
2907	return TCL_ERROR;
2908    }
2909    if (!Tk_IsTopLevel(winPtr) &&
2910	    (index != WMOPT_MANAGE) && (index != WMOPT_FORGET)) {
2911	Tcl_AppendResult(interp, "window \"", winPtr->pathName,
2912		"\" isn't a top-level window", NULL);
2913	return TCL_ERROR;
2914    }
2915
2916    switch ((enum options) index) {
2917    case WMOPT_ASPECT:
2918	return WmAspectCmd(tkwin, winPtr, interp, objc, objv);
2919    case WMOPT_ATTRIBUTES:
2920	return WmAttributesCmd(tkwin, winPtr, interp, objc, objv);
2921    case WMOPT_CLIENT:
2922	return WmClientCmd(tkwin, winPtr, interp, objc, objv);
2923    case WMOPT_COLORMAPWINDOWS:
2924	return WmColormapwindowsCmd(tkwin, winPtr, interp, objc, objv);
2925    case WMOPT_COMMAND:
2926	return WmCommandCmd(tkwin, winPtr, interp, objc, objv);
2927    case WMOPT_DEICONIFY:
2928	return WmDeiconifyCmd(tkwin, winPtr, interp, objc, objv);
2929    case WMOPT_FOCUSMODEL:
2930	return WmFocusmodelCmd(tkwin, winPtr, interp, objc, objv);
2931    case WMOPT_FORGET:
2932	return WmForgetCmd(tkwin, winPtr, interp, objc, objv);
2933    case WMOPT_FRAME:
2934	return WmFrameCmd(tkwin, winPtr, interp, objc, objv);
2935    case WMOPT_GEOMETRY:
2936	return WmGeometryCmd(tkwin, winPtr, interp, objc, objv);
2937    case WMOPT_GRID:
2938	return WmGridCmd(tkwin, winPtr, interp, objc, objv);
2939    case WMOPT_GROUP:
2940	return WmGroupCmd(tkwin, winPtr, interp, objc, objv);
2941    case WMOPT_ICONBITMAP:
2942	return WmIconbitmapCmd(tkwin, winPtr, interp, objc, objv);
2943    case WMOPT_ICONIFY:
2944	return WmIconifyCmd(tkwin, winPtr, interp, objc, objv);
2945    case WMOPT_ICONMASK:
2946	return WmIconmaskCmd(tkwin, winPtr, interp, objc, objv);
2947    case WMOPT_ICONNAME:
2948	return WmIconnameCmd(tkwin, winPtr, interp, objc, objv);
2949    case WMOPT_ICONPHOTO:
2950	return WmIconphotoCmd(tkwin, winPtr, interp, objc, objv);
2951    case WMOPT_ICONPOSITION:
2952	return WmIconpositionCmd(tkwin, winPtr, interp, objc, objv);
2953    case WMOPT_ICONWINDOW:
2954	return WmIconwindowCmd(tkwin, winPtr, interp, objc, objv);
2955    case WMOPT_MANAGE:
2956	return WmManageCmd(tkwin, winPtr, interp, objc, objv);
2957    case WMOPT_MAXSIZE:
2958	return WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv);
2959    case WMOPT_MINSIZE:
2960	return WmMinsizeCmd(tkwin, winPtr, interp, objc, objv);
2961    case WMOPT_OVERRIDEREDIRECT:
2962	return WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv);
2963    case WMOPT_POSITIONFROM:
2964	return WmPositionfromCmd(tkwin, winPtr, interp, objc, objv);
2965    case WMOPT_PROTOCOL:
2966	return WmProtocolCmd(tkwin, winPtr, interp, objc, objv);
2967    case WMOPT_RESIZABLE:
2968	return WmResizableCmd(tkwin, winPtr, interp, objc, objv);
2969    case WMOPT_SIZEFROM:
2970	return WmSizefromCmd(tkwin, winPtr, interp, objc, objv);
2971    case WMOPT_STACKORDER:
2972	return WmStackorderCmd(tkwin, winPtr, interp, objc, objv);
2973    case WMOPT_STATE:
2974	return WmStateCmd(tkwin, winPtr, interp, objc, objv);
2975    case WMOPT_TITLE:
2976	return WmTitleCmd(tkwin, winPtr, interp, objc, objv);
2977    case WMOPT_TRANSIENT:
2978	return WmTransientCmd(tkwin, winPtr, interp, objc, objv);
2979    case WMOPT_WITHDRAW:
2980	return WmWithdrawCmd(tkwin, winPtr, interp, objc, objv);
2981    }
2982
2983    /* This should not happen */
2984    return TCL_ERROR;
2985}
2986
2987/*
2988 *----------------------------------------------------------------------
2989 *
2990 * WmAspectCmd --
2991 *
2992 *	This function is invoked to process the "wm aspect" Tcl command. See
2993 *	the user documentation for details on what it does.
2994 *
2995 * Results:
2996 *	A standard Tcl result.
2997 *
2998 * Side effects:
2999 *	See the user documentation.
3000 *
3001 *----------------------------------------------------------------------
3002 */
3003
3004static int
3005WmAspectCmd(
3006    Tk_Window tkwin,		/* Main window of the application. */
3007    TkWindow *winPtr,		/* Toplevel to work with */
3008    Tcl_Interp *interp,		/* Current interpreter. */
3009    int objc,			/* Number of arguments. */
3010    Tcl_Obj *CONST objv[])	/* Argument objects. */
3011{
3012    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3013    int numer1, denom1, numer2, denom2;
3014
3015    if ((objc != 3) && (objc != 7)) {
3016	Tcl_WrongNumArgs(interp, 2, objv,
3017		"window ?minNumer minDenom maxNumer maxDenom?");
3018	return TCL_ERROR;
3019    }
3020    if (objc == 3) {
3021	if (wmPtr->sizeHintsFlags & PAspect) {
3022	    char buf[TCL_INTEGER_SPACE * 4];
3023
3024	    sprintf(buf, "%d %d %d %d", wmPtr->minAspect.x,
3025		    wmPtr->minAspect.y, wmPtr->maxAspect.x,
3026		    wmPtr->maxAspect.y);
3027	    Tcl_SetResult(interp, buf, TCL_VOLATILE);
3028	}
3029	return TCL_OK;
3030    }
3031    if (*Tcl_GetString(objv[3]) == '\0') {
3032	wmPtr->sizeHintsFlags &= ~PAspect;
3033    } else {
3034	if ((Tcl_GetIntFromObj(interp, objv[3], &numer1) != TCL_OK)
3035		|| (Tcl_GetIntFromObj(interp, objv[4], &denom1) != TCL_OK)
3036		|| (Tcl_GetIntFromObj(interp, objv[5], &numer2) != TCL_OK)
3037		|| (Tcl_GetIntFromObj(interp, objv[6], &denom2) != TCL_OK)) {
3038	    return TCL_ERROR;
3039	}
3040	if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) || (denom2 <= 0)) {
3041	    Tcl_SetResult(interp, "aspect number can't be <= 0", TCL_STATIC);
3042	    return TCL_ERROR;
3043	}
3044	wmPtr->minAspect.x = numer1;
3045	wmPtr->minAspect.y = denom1;
3046	wmPtr->maxAspect.x = numer2;
3047	wmPtr->maxAspect.y = denom2;
3048	wmPtr->sizeHintsFlags |= PAspect;
3049    }
3050    WmUpdateGeom(wmPtr, winPtr);
3051    return TCL_OK;
3052}
3053
3054/*
3055 *----------------------------------------------------------------------
3056 *
3057 * WmAttributesCmd --
3058 *
3059 *	This function is invoked to process the "wm attributes" Tcl command.
3060 *	See the user documentation for details on what it does.
3061 *
3062 * Results:
3063 *	A standard Tcl result.
3064 *
3065 * Side effects:
3066 *	See the user documentation.
3067 *
3068 *----------------------------------------------------------------------
3069 */
3070
3071static int
3072WmAttributesCmd(
3073    Tk_Window tkwin,		/* Main window of the application. */
3074    TkWindow *winPtr,		/* Toplevel to work with */
3075    Tcl_Interp *interp,		/* Current interpreter. */
3076    int objc,			/* Number of arguments. */
3077    Tcl_Obj *CONST objv[])	/* Argument objects. */
3078{
3079    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3080    LONG style, exStyle, styleBit, *stylePtr = NULL;
3081    char *string;
3082    int i, boolean, length;
3083    int config_fullscreen = 0, updatewrapper = 0;
3084    int fullscreen_attr_changed = 0, fullscreen_attr = 0;
3085
3086    if ((objc < 3) || ((objc > 5) && ((objc%2) == 0))) {
3087    configArgs:
3088	Tcl_WrongNumArgs(interp, 2, objv,
3089		"window"
3090		" ?-alpha ?double??"
3091		" ?-transparentcolor ?color??"
3092		" ?-disabled ?bool??"
3093		" ?-fullscreen ?bool??"
3094		" ?-toolwindow ?bool??"
3095		" ?-topmost ?bool??");
3096	return TCL_ERROR;
3097    }
3098    exStyle = wmPtr->exStyleConfig;
3099    style = wmPtr->styleConfig;
3100    if (objc == 3) {
3101	Tcl_Obj *objPtr = Tcl_NewObj();
3102	Tcl_ListObjAppendElement(NULL, objPtr,
3103		Tcl_NewStringObj("-alpha", -1));
3104	Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewDoubleObj(wmPtr->alpha));
3105	Tcl_ListObjAppendElement(NULL, objPtr,
3106		Tcl_NewStringObj("-transparentcolor", -1));
3107	Tcl_ListObjAppendElement(NULL, objPtr,
3108		wmPtr->crefObj ? wmPtr->crefObj : Tcl_NewObj());
3109	Tcl_ListObjAppendElement(NULL, objPtr,
3110		Tcl_NewStringObj("-disabled", -1));
3111	Tcl_ListObjAppendElement(NULL, objPtr,
3112		Tcl_NewBooleanObj((style & WS_DISABLED)));
3113	Tcl_ListObjAppendElement(NULL, objPtr,
3114		Tcl_NewStringObj("-fullscreen", -1));
3115	Tcl_ListObjAppendElement(NULL, objPtr,
3116		Tcl_NewBooleanObj((wmPtr->flags & WM_FULLSCREEN)));
3117	Tcl_ListObjAppendElement(NULL, objPtr,
3118		Tcl_NewStringObj("-toolwindow", -1));
3119	Tcl_ListObjAppendElement(NULL, objPtr,
3120		Tcl_NewBooleanObj((exStyle & WS_EX_TOOLWINDOW)));
3121	Tcl_ListObjAppendElement(NULL, objPtr,
3122		Tcl_NewStringObj("-topmost", -1));
3123	Tcl_ListObjAppendElement(NULL, objPtr,
3124		Tcl_NewBooleanObj((exStyle & WS_EX_TOPMOST)));
3125	Tcl_SetObjResult(interp, objPtr);
3126	return TCL_OK;
3127    }
3128    for (i = 3; i < objc; i += 2) {
3129	string = Tcl_GetStringFromObj(objv[i], &length);
3130	if ((length < 2) || (string[0] != '-')) {
3131	    goto configArgs;
3132	}
3133	if (strncmp(string, "-disabled", (unsigned) length) == 0) {
3134	    stylePtr = &style;
3135	    styleBit = WS_DISABLED;
3136	} else if ((strncmp(string, "-alpha", (unsigned) length) == 0)
3137		|| ((length > 2) && (strncmp(string, "-transparentcolor",
3138			(unsigned) length) == 0))) {
3139	    stylePtr = &exStyle;
3140	    styleBit = WS_EX_LAYERED;
3141	} else if (strncmp(string, "-fullscreen", (unsigned) length) == 0) {
3142	    config_fullscreen = 1;
3143	    styleBit = 0;
3144	} else if ((length > 3)
3145		&& (strncmp(string, "-toolwindow", (unsigned) length) == 0)) {
3146	    stylePtr = &exStyle;
3147	    styleBit = WS_EX_TOOLWINDOW;
3148	    if (objc != 4) {
3149		/*
3150		 * Changes to toolwindow style require an update
3151		 */
3152		updatewrapper = 1;
3153	    }
3154	} else if ((length > 3)
3155		&& (strncmp(string, "-topmost", (unsigned) length) == 0)) {
3156	    stylePtr = &exStyle;
3157	    styleBit = WS_EX_TOPMOST;
3158	    if ((i < objc-1) && (winPtr->flags & TK_EMBEDDED)) {
3159		Tcl_AppendResult(interp, "can't set topmost flag on ",
3160			winPtr->pathName, ": it is an embedded window", NULL);
3161		return TCL_ERROR;
3162	    }
3163	} else {
3164	    goto configArgs;
3165	}
3166	if (styleBit == WS_EX_LAYERED) {
3167	    if (objc == 4) {
3168		if (string[1] == 'a') {		/* -alpha */
3169		    Tcl_SetObjResult(interp, Tcl_NewDoubleObj(wmPtr->alpha));
3170		} else {			/* -transparentcolor */
3171		    Tcl_SetObjResult(interp,
3172			    wmPtr->crefObj ? wmPtr->crefObj : Tcl_NewObj());
3173		}
3174	    } else {
3175		if (string[1] == 'a') {		/* -alpha */
3176		    double dval;
3177
3178		    if (Tcl_GetDoubleFromObj(interp, objv[i+1], &dval)
3179			    != TCL_OK) {
3180			return TCL_ERROR;
3181		    }
3182
3183		    /*
3184		     * The user should give (transparent) 0 .. 1.0 (opaque),
3185		     * but we ignore the setting of this (it will always be 1)
3186		     * in the case that the API is not available.
3187		     */
3188		    if (dval < 0.0) {
3189			dval = 0;
3190		    } else if (dval > 1.0) {
3191			dval = 1;
3192		    }
3193		    wmPtr->alpha = dval;
3194		} else {			/* -transparentcolor */
3195		    char *crefstr = Tcl_GetStringFromObj(objv[i+1], &length);
3196
3197		    if (length == 0) {
3198			/* reset to no transparent color */
3199			if (wmPtr->crefObj) {
3200			    Tcl_DecrRefCount(wmPtr->crefObj);
3201			    wmPtr->crefObj = NULL;
3202			}
3203		    } else {
3204			XColor *cPtr =
3205			    Tk_GetColor(interp, tkwin, Tk_GetUid(crefstr));
3206			if (cPtr == NULL) {
3207			    return TCL_ERROR;
3208			}
3209
3210			if (wmPtr->crefObj) {
3211			    Tcl_DecrRefCount(wmPtr->crefObj);
3212			}
3213			wmPtr->crefObj = objv[i+1];
3214			Tcl_IncrRefCount(wmPtr->crefObj);
3215			wmPtr->colorref = RGB((BYTE) (cPtr->red >> 8),
3216				(BYTE) (cPtr->green >> 8),
3217				(BYTE) (cPtr->blue >> 8));
3218			Tk_FreeColor(cPtr);
3219		    }
3220		}
3221
3222		/*
3223		 * Only ever add the WS_EX_LAYERED bit, as it can cause
3224		 * flashing to change this window style.  This allows things
3225		 * like fading tooltips to avoid flash ugliness without
3226		 * forcing all window to be layered.
3227		 */
3228		if ((wmPtr->alpha < 1.0) || (wmPtr->crefObj != NULL)) {
3229		    *stylePtr |= styleBit;
3230		}
3231		if ((setLayeredWindowAttributesProc != NULL)
3232			&& (wmPtr->wrapper != NULL)) {
3233		    /*
3234		     * Set the window directly regardless of UpdateWrapper.
3235		     * The user supplies a double from [0..1], but Windows
3236		     * wants an int (transparent) 0..255 (opaque), so do the
3237		     * translation. Add the 0.5 to round the value.
3238		     */
3239
3240		    if (!(wmPtr->exStyleConfig & WS_EX_LAYERED)) {
3241			SetWindowLongPtr(wmPtr->wrapper, GWL_EXSTYLE,
3242				*stylePtr);
3243		    }
3244		    setLayeredWindowAttributesProc((HWND) wmPtr->wrapper,
3245			    wmPtr->colorref, (BYTE) (wmPtr->alpha * 255 + 0.5),
3246			    (unsigned) (LWA_ALPHA |
3247				    (wmPtr->crefObj ? LWA_COLORKEY : 0)));
3248		}
3249	    }
3250	} else {
3251	    if ((i < objc-1) &&
3252		    (Tcl_GetBooleanFromObj(interp, objv[i+1], &boolean)
3253			    != TCL_OK)) {
3254		return TCL_ERROR;
3255	    }
3256	    if (config_fullscreen) {
3257		if (objc == 4) {
3258		    Tcl_SetBooleanObj(Tcl_GetObjResult(interp),
3259			(wmPtr->flags & WM_FULLSCREEN));
3260		} else {
3261		    fullscreen_attr_changed = 1;
3262		    fullscreen_attr = boolean;
3263		}
3264		config_fullscreen = 0;
3265	    } else if (objc == 4) {
3266		Tcl_SetIntObj(Tcl_GetObjResult(interp),
3267			((*stylePtr & styleBit) != 0));
3268	    } else if (boolean) {
3269		*stylePtr |= styleBit;
3270	    } else {
3271		*stylePtr &= ~styleBit;
3272	    }
3273	}
3274	if ((styleBit == WS_EX_TOPMOST) && (wmPtr->wrapper != NULL)) {
3275	    /*
3276	     * Force the topmost position aspect to ensure that switching
3277	     * between (no)topmost reflects properly when rewrapped.
3278	     */
3279	    SetWindowPos(wmPtr->wrapper,
3280		    ((exStyle & WS_EX_TOPMOST) ?
3281			    HWND_TOPMOST : HWND_NOTOPMOST), 0, 0, 0, 0,
3282		    SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOSENDCHANGING
3283		    |SWP_NOOWNERZORDER);
3284	}
3285    }
3286    if (wmPtr->styleConfig != style) {
3287	/*
3288	 * Currently this means only WS_DISABLED changed, which we can effect
3289	 * with EnableWindow.
3290	 */
3291
3292	wmPtr->styleConfig = style;
3293	if ((wmPtr->exStyleConfig == exStyle)
3294		&& !(wmPtr->flags & WM_NEVER_MAPPED)) {
3295	    EnableWindow(wmPtr->wrapper, (style & WS_DISABLED) ? 0 : 1);
3296	}
3297    }
3298    if (wmPtr->exStyleConfig != exStyle) {
3299	wmPtr->exStyleConfig = exStyle;
3300	if (updatewrapper) {
3301	    /*
3302	     * UpdateWrapper ensure that all effects are properly handled,
3303	     * such as TOOLWINDOW disappearing from the taskbar.
3304	     */
3305
3306	    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3307		UpdateWrapper(winPtr);
3308	    }
3309	}
3310    }
3311    if (fullscreen_attr_changed) {
3312	if (fullscreen_attr) {
3313	    if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
3314		Tcl_AppendResult(interp,
3315			"can't set fullscreen attribute for \"",
3316			winPtr->pathName, "\": override-redirect flag is set",
3317			NULL);
3318		return TCL_ERROR;
3319	    }
3320
3321	    /*
3322	     * Check max width and height if set by the user, don't worry
3323	     * about the default values since they will likely be smaller than
3324	     * screen width/height.
3325	     */
3326
3327	    if (((wmPtr->maxWidth > 0) &&
3328		    (WidthOfScreen(Tk_Screen(winPtr)) > wmPtr->maxWidth)) ||
3329		    ((wmPtr->maxHeight > 0) &&
3330		    (HeightOfScreen(Tk_Screen(winPtr)) > wmPtr->maxHeight))) {
3331		Tcl_AppendResult(interp,
3332			"can't set fullscreen attribute for \"",
3333			winPtr->pathName, "\": max width/height is too small",
3334			NULL);
3335		return TCL_ERROR;
3336	    }
3337	}
3338
3339	TkpWmSetFullScreen(winPtr, fullscreen_attr);
3340    }
3341
3342    return TCL_OK;
3343}
3344
3345/*
3346 *----------------------------------------------------------------------
3347 *
3348 * WmClientCmd --
3349 *
3350 *	This function is invoked to process the "wm client" Tcl command. See
3351 *	the user documentation for details on what it does.
3352 *
3353 * Results:
3354 *	A standard Tcl result.
3355 *
3356 * Side effects:
3357 *	See the user documentation.
3358 *
3359 *----------------------------------------------------------------------
3360 */
3361
3362static int
3363WmClientCmd(
3364    Tk_Window tkwin,		/* Main window of the application. */
3365    TkWindow *winPtr,		/* Toplevel to work with */
3366    Tcl_Interp *interp,		/* Current interpreter. */
3367    int objc,			/* Number of arguments. */
3368    Tcl_Obj *CONST objv[])	/* Argument objects. */
3369{
3370    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3371    char *argv3;
3372    int length;
3373
3374    if ((objc != 3) && (objc != 4)) {
3375	Tcl_WrongNumArgs(interp, 2, objv, "window ?name?");
3376	return TCL_ERROR;
3377    }
3378    if (objc == 3) {
3379	if (wmPtr->clientMachine != NULL) {
3380	    Tcl_SetResult(interp, wmPtr->clientMachine, TCL_STATIC);
3381	}
3382	return TCL_OK;
3383    }
3384    argv3 = Tcl_GetStringFromObj(objv[3], &length);
3385    if (argv3[0] == 0) {
3386	if (wmPtr->clientMachine != NULL) {
3387	    ckfree((char *) wmPtr->clientMachine);
3388	    wmPtr->clientMachine = NULL;
3389	    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3390		XDeleteProperty(winPtr->display, winPtr->window,
3391			Tk_InternAtom((Tk_Window) winPtr,"WM_CLIENT_MACHINE"));
3392	    }
3393	}
3394	return TCL_OK;
3395    }
3396    if (wmPtr->clientMachine != NULL) {
3397	ckfree((char *) wmPtr->clientMachine);
3398    }
3399    wmPtr->clientMachine = (char *)
3400	    ckalloc((unsigned) (length + 1));
3401    strcpy(wmPtr->clientMachine, argv3);
3402    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3403	XTextProperty textProp;
3404
3405	if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
3406		!= 0) {
3407	    XSetWMClientMachine(winPtr->display, winPtr->window,
3408		    &textProp);
3409	    XFree((char *) textProp.value);
3410	}
3411    }
3412    return TCL_OK;
3413}
3414
3415/*
3416 *----------------------------------------------------------------------
3417 *
3418 * WmColormapwindowsCmd --
3419 *
3420 *	This function is invoked to process the "wm colormapwindows" Tcl
3421 *	command. See the user documentation for details on what it does.
3422 *
3423 * Results:
3424 *	A standard Tcl result.
3425 *
3426 * Side effects:
3427 *	See the user documentation.
3428 *
3429 *----------------------------------------------------------------------
3430 */
3431
3432static int
3433WmColormapwindowsCmd(
3434    Tk_Window tkwin,		/* Main window of the application. */
3435    TkWindow *winPtr,		/* Toplevel to work with */
3436    Tcl_Interp *interp,		/* Current interpreter. */
3437    int objc,			/* Number of arguments. */
3438    Tcl_Obj *CONST objv[])	/* Argument objects. */
3439{
3440    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3441    TkWindow **cmapList;
3442    TkWindow *winPtr2, **winPtr2Ptr = &winPtr2;
3443    int i, windowObjc, gotToplevel;
3444    Tcl_Obj **windowObjv;
3445
3446    if ((objc != 3) && (objc != 4)) {
3447	Tcl_WrongNumArgs(interp, 2, objv, "window ?windowList?");
3448	return TCL_ERROR;
3449    }
3450    if (objc == 3) {
3451	Tk_MakeWindowExist((Tk_Window) winPtr);
3452	for (i = 0; i < wmPtr->cmapCount; i++) {
3453	    if ((i == (wmPtr->cmapCount-1))
3454		    && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
3455		break;
3456	    }
3457	    Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
3458	}
3459	return TCL_OK;
3460    }
3461    if (Tcl_ListObjGetElements(interp, objv[3], &windowObjc, &windowObjv)
3462	    != TCL_OK) {
3463	return TCL_ERROR;
3464    }
3465    cmapList = (TkWindow **) ckalloc((unsigned)
3466	    ((windowObjc+1)*sizeof(TkWindow*)));
3467    gotToplevel = 0;
3468    for (i = 0; i < windowObjc; i++) {
3469	if (TkGetWindowFromObj(interp, tkwin, windowObjv[i],
3470		(Tk_Window *) winPtr2Ptr) != TCL_OK) {
3471	    ckfree((char *) cmapList);
3472	    return TCL_ERROR;
3473	}
3474	if (winPtr2 == winPtr) {
3475	    gotToplevel = 1;
3476	}
3477	if (winPtr2->window == None) {
3478	    Tk_MakeWindowExist((Tk_Window) winPtr2);
3479	}
3480	cmapList[i] = winPtr2;
3481    }
3482    if (!gotToplevel) {
3483	wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
3484	cmapList[windowObjc] = winPtr;
3485	windowObjc++;
3486    } else {
3487	wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
3488    }
3489    wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
3490    if (wmPtr->cmapList != NULL) {
3491	ckfree((char *)wmPtr->cmapList);
3492    }
3493    wmPtr->cmapList = cmapList;
3494    wmPtr->cmapCount = windowObjc;
3495
3496    /*
3497     * Now we need to force the updated colormaps to be installed.
3498     */
3499
3500    if (wmPtr == winPtr->dispPtr->foregroundWmPtr) {
3501	InstallColormaps(wmPtr->wrapper, WM_QUERYNEWPALETTE, 1);
3502    } else {
3503	InstallColormaps(wmPtr->wrapper, WM_PALETTECHANGED, 0);
3504    }
3505    return TCL_OK;
3506}
3507
3508/*
3509 *----------------------------------------------------------------------
3510 *
3511 * WmCommandCmd --
3512 *
3513 *	This function is invoked to process the "wm command" Tcl command. See
3514 *	the user documentation for details on what it does.
3515 *
3516 * Results:
3517 *	A standard Tcl result.
3518 *
3519 * Side effects:
3520 *	See the user documentation.
3521 *
3522 *----------------------------------------------------------------------
3523 */
3524
3525static int
3526WmCommandCmd(
3527    Tk_Window tkwin,		/* Main window of the application. */
3528    TkWindow *winPtr,		/* Toplevel to work with */
3529    Tcl_Interp *interp,		/* Current interpreter. */
3530    int objc,			/* Number of arguments. */
3531    Tcl_Obj *CONST objv[])	/* Argument objects. */
3532{
3533    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3534    char *argv3;
3535    int cmdArgc;
3536    CONST char **cmdArgv;
3537
3538    if ((objc != 3) && (objc != 4)) {
3539	Tcl_WrongNumArgs(interp, 2, objv, "window ?value?");
3540	return TCL_ERROR;
3541    }
3542    if (objc == 3) {
3543	if (wmPtr->cmdArgv != NULL) {
3544	    Tcl_SetResult(interp,
3545		    Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv), TCL_DYNAMIC);
3546	}
3547	return TCL_OK;
3548    }
3549    argv3 = Tcl_GetString(objv[3]);
3550    if (argv3[0] == 0) {
3551	if (wmPtr->cmdArgv != NULL) {
3552	    ckfree((char *) wmPtr->cmdArgv);
3553	    wmPtr->cmdArgv = NULL;
3554	    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3555		XDeleteProperty(winPtr->display, winPtr->window,
3556			Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND"));
3557	    }
3558	}
3559	return TCL_OK;
3560    }
3561    if (Tcl_SplitList(interp, argv3, &cmdArgc, &cmdArgv) != TCL_OK) {
3562	return TCL_ERROR;
3563    }
3564    if (wmPtr->cmdArgv != NULL) {
3565	ckfree((char *) wmPtr->cmdArgv);
3566    }
3567    wmPtr->cmdArgc = cmdArgc;
3568    wmPtr->cmdArgv = cmdArgv;
3569    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3570	XSetCommand(winPtr->display, winPtr->window, cmdArgv, cmdArgc);
3571    }
3572    return TCL_OK;
3573}
3574
3575/*
3576 *----------------------------------------------------------------------
3577 *
3578 * WmDeiconifyCmd --
3579 *
3580 *	This function is invoked to process the "wm deiconify" Tcl command.
3581 *	See the user documentation for details on what it does.
3582 *
3583 * Results:
3584 *	A standard Tcl result.
3585 *
3586 * Side effects:
3587 *	See the user documentation.
3588 *
3589 *----------------------------------------------------------------------
3590 */
3591
3592static int
3593WmDeiconifyCmd(
3594    Tk_Window tkwin,		/* Main window of the application. */
3595    TkWindow *winPtr,		/* Toplevel to work with */
3596    Tcl_Interp *interp,		/* Current interpreter. */
3597    int objc,			/* Number of arguments. */
3598    Tcl_Obj *CONST objv[])	/* Argument objects. */
3599{
3600    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3601
3602    if (objc != 3) {
3603	Tcl_WrongNumArgs(interp, 2, objv, "window");
3604	return TCL_ERROR;
3605    }
3606    if (wmPtr->iconFor != NULL) {
3607	Tcl_AppendResult(interp, "can't deiconify ", Tcl_GetString(objv[2]),
3608		": it is an icon for ", Tk_PathName(wmPtr->iconFor), NULL);
3609	return TCL_ERROR;
3610    }
3611    if (winPtr->flags & TK_EMBEDDED) {
3612	if (!SendMessage(wmPtr->wrapper, TK_DEICONIFY, 0, 0)) {
3613	    Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName,
3614		    ": the container does not support the request", NULL);
3615	    return TCL_ERROR;
3616	}
3617	return TCL_OK;
3618    }
3619    TkpWinToplevelDeiconify(winPtr);
3620    return TCL_OK;
3621}
3622
3623/*
3624 *----------------------------------------------------------------------
3625 *
3626 * WmFocusmodelCmd --
3627 *
3628 *	This function is invoked to process the "wm focusmodel" Tcl command.
3629 *	See the user documentation for details on what it does.
3630 *
3631 * Results:
3632 *	A standard Tcl result.
3633 *
3634 * Side effects:
3635 *	See the user documentation.
3636 *
3637 *----------------------------------------------------------------------
3638 */
3639
3640static int
3641WmFocusmodelCmd(
3642    Tk_Window tkwin,		/* Main window of the application. */
3643    TkWindow *winPtr,		/* Toplevel to work with */
3644    Tcl_Interp *interp,		/* Current interpreter. */
3645    int objc,			/* Number of arguments. */
3646    Tcl_Obj *CONST objv[])	/* Argument objects. */
3647{
3648    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3649    static CONST char *optionStrings[] = {
3650	"active", "passive", NULL
3651    };
3652    enum options {
3653	OPT_ACTIVE, OPT_PASSIVE
3654    };
3655    int index;
3656
3657    if ((objc != 3) && (objc != 4)) {
3658	Tcl_WrongNumArgs(interp, 2, objv, "window ?active|passive?");
3659	return TCL_ERROR;
3660    }
3661    if (objc == 3) {
3662	Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"),
3663		TCL_STATIC);
3664	return TCL_OK;
3665    }
3666
3667    if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
3668	    &index) != TCL_OK) {
3669	return TCL_ERROR;
3670    }
3671    if (index == OPT_ACTIVE) {
3672	wmPtr->hints.input = False;
3673    } else { /* OPT_PASSIVE */
3674	wmPtr->hints.input = True;
3675    }
3676    return TCL_OK;
3677}
3678
3679/*
3680 *----------------------------------------------------------------------
3681 *
3682 * WmForgetCmd --
3683 *
3684 *	This procedure is invoked to process the "wm forget" Tcl command.
3685 *	See the user documentation for details on what it does.
3686 *
3687 * Results:
3688 *	A standard Tcl result.
3689 *
3690 * Side effects:
3691 *	See the user documentation.
3692 *
3693 *----------------------------------------------------------------------
3694 */
3695
3696static int
3697WmForgetCmd(tkwin, winPtr, interp, objc, objv)
3698    Tk_Window tkwin;		/* Main window of the application. */
3699    TkWindow *winPtr;           /* Toplevel or Frame to work with */
3700    Tcl_Interp *interp;		/* Current interpreter. */
3701    int objc;			/* Number of arguments. */
3702    Tcl_Obj *CONST objv[];	/* Argument objects. */
3703{
3704    register Tk_Window frameWin = (Tk_Window)winPtr;
3705
3706    if (Tk_IsTopLevel(frameWin)) {
3707	Tk_UnmapWindow(frameWin);
3708	winPtr->flags &= ~(TK_TOP_HIERARCHY|TK_TOP_LEVEL|TK_HAS_WRAPPER|TK_WIN_MANAGED);
3709	if (Tk_IsMapped(Tk_Parent(frameWin))) {
3710	    RemapWindows(winPtr, Tk_GetHWND(winPtr->parentPtr->window));
3711	}
3712	TkWmDeadWindow(winPtr);
3713	/* flags (above) must be cleared before calling */
3714	/* TkMapTopFrame (below) */
3715	TkMapTopFrame(frameWin);
3716    } else {
3717	/* Already not managed by wm - ignore it */
3718    }
3719    return TCL_OK;
3720}
3721/*
3722 *----------------------------------------------------------------------
3723 *
3724 * WmFrameCmd --
3725 *
3726 *	This function is invoked to process the "wm frame" Tcl command. See
3727 *	the user documentation for details on what it does.
3728 *
3729 * Results:
3730 *	A standard Tcl result.
3731 *
3732 * Side effects:
3733 *	See the user documentation.
3734 *
3735 *----------------------------------------------------------------------
3736 */
3737
3738static int
3739WmFrameCmd(
3740    Tk_Window tkwin,		/* Main window of the application. */
3741    TkWindow *winPtr,		/* Toplevel to work with */
3742    Tcl_Interp *interp,		/* Current interpreter. */
3743    int objc,			/* Number of arguments. */
3744    Tcl_Obj *CONST objv[])	/* Argument objects. */
3745{
3746    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3747    HWND hwnd;
3748    char buf[TCL_INTEGER_SPACE];
3749
3750    if (objc != 3) {
3751	Tcl_WrongNumArgs(interp, 2, objv, "window");
3752	return TCL_ERROR;
3753    }
3754    if (Tk_WindowId((Tk_Window) winPtr) == None) {
3755	Tk_MakeWindowExist((Tk_Window) winPtr);
3756    }
3757    hwnd = wmPtr->wrapper;
3758    if (hwnd == NULL) {
3759	hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) winPtr));
3760    }
3761    sprintf(buf, "0x%x", (unsigned int) hwnd);
3762    Tcl_SetResult(interp, buf, TCL_VOLATILE);
3763    return TCL_OK;
3764}
3765
3766/*
3767 *----------------------------------------------------------------------
3768 *
3769 * WmGeometryCmd --
3770 *
3771 *	This function is invoked to process the "wm geometry" Tcl command.
3772 *	See the user documentation for details on what it does.
3773 *
3774 * Results:
3775 *	A standard Tcl result.
3776 *
3777 * Side effects:
3778 *	See the user documentation.
3779 *
3780 *----------------------------------------------------------------------
3781 */
3782
3783static int
3784WmGeometryCmd(
3785    Tk_Window tkwin,		/* Main window of the application. */
3786    TkWindow *winPtr,		/* Toplevel to work with */
3787    Tcl_Interp *interp,		/* Current interpreter. */
3788    int objc,			/* Number of arguments. */
3789    Tcl_Obj *CONST objv[])	/* Argument objects. */
3790{
3791    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3792    char xSign, ySign;
3793    int width, height;
3794    char *argv3;
3795
3796    if ((objc != 3) && (objc != 4)) {
3797	Tcl_WrongNumArgs(interp, 2, objv, "window ?newGeometry?");
3798	return TCL_ERROR;
3799    }
3800    if (objc == 3) {
3801	char buf[16 + TCL_INTEGER_SPACE * 4];
3802	int x, y;
3803
3804	xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
3805	ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
3806	if (wmPtr->gridWin != NULL) {
3807	    width = wmPtr->reqGridWidth + (winPtr->changes.width
3808		    - winPtr->reqWidth)/wmPtr->widthInc;
3809	    height = wmPtr->reqGridHeight + (winPtr->changes.height
3810		    - winPtr->reqHeight)/wmPtr->heightInc;
3811	} else {
3812	    width = winPtr->changes.width;
3813	    height = winPtr->changes.height;
3814	}
3815	if(winPtr->flags & TK_EMBEDDED) {
3816	    int result = SendMessage(wmPtr->wrapper, TK_MOVEWINDOW, -1, -1);
3817	    wmPtr->x = result >> 16;
3818	    wmPtr->y = result & 0x0000ffff;
3819	}
3820	x = wmPtr->x;
3821	y = wmPtr->y;
3822	sprintf(buf, "%dx%d%c%d%c%d", width, height, xSign, x, ySign, y);
3823	Tcl_SetResult(interp, buf, TCL_VOLATILE);
3824	return TCL_OK;
3825    }
3826    argv3 = Tcl_GetString(objv[3]);
3827    if (*argv3 == '\0') {
3828	wmPtr->width = -1;
3829	wmPtr->height = -1;
3830	WmUpdateGeom(wmPtr, winPtr);
3831	return TCL_OK;
3832    }
3833    return ParseGeometry(interp, argv3, winPtr);
3834}
3835
3836/*
3837 *----------------------------------------------------------------------
3838 *
3839 * WmGridCmd --
3840 *
3841 *	This function is invoked to process the "wm grid" Tcl command. See the
3842 *	user documentation for details on what it does.
3843 *
3844 * Results:
3845 *	A standard Tcl result.
3846 *
3847 * Side effects:
3848 *	See the user documentation.
3849 *
3850 *----------------------------------------------------------------------
3851 */
3852
3853static int
3854WmGridCmd(
3855    Tk_Window tkwin,		/* Main window of the application. */
3856    TkWindow *winPtr,		/* Toplevel to work with */
3857    Tcl_Interp *interp,		/* Current interpreter. */
3858    int objc,			/* Number of arguments. */
3859    Tcl_Obj *CONST objv[])	/* Argument objects. */
3860{
3861    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3862    int reqWidth, reqHeight, widthInc, heightInc;
3863
3864    if ((objc != 3) && (objc != 7)) {
3865	Tcl_WrongNumArgs(interp, 2, objv,
3866		"window ?baseWidth baseHeight widthInc heightInc?");
3867	return TCL_ERROR;
3868    }
3869    if (objc == 3) {
3870	if (wmPtr->sizeHintsFlags & PBaseSize) {
3871	    char buf[TCL_INTEGER_SPACE * 4];
3872
3873	    sprintf(buf, "%d %d %d %d", wmPtr->reqGridWidth,
3874		    wmPtr->reqGridHeight, wmPtr->widthInc,
3875		    wmPtr->heightInc);
3876	    Tcl_SetResult(interp, buf, TCL_VOLATILE);
3877	}
3878	return TCL_OK;
3879    }
3880    if (*Tcl_GetString(objv[3]) == '\0') {
3881	/*
3882	 * Turn off gridding and reset the width and height to make sense as
3883	 * ungridded numbers.
3884	 */
3885
3886	wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
3887	if (wmPtr->width != -1) {
3888	    wmPtr->width = winPtr->reqWidth + (wmPtr->width
3889		    - wmPtr->reqGridWidth)*wmPtr->widthInc;
3890	    wmPtr->height = winPtr->reqHeight + (wmPtr->height
3891		    - wmPtr->reqGridHeight)*wmPtr->heightInc;
3892	}
3893	wmPtr->widthInc = 1;
3894	wmPtr->heightInc = 1;
3895    } else {
3896	if ((Tcl_GetIntFromObj(interp, objv[3], &reqWidth) != TCL_OK)
3897		|| (Tcl_GetIntFromObj(interp, objv[4], &reqHeight) != TCL_OK)
3898		|| (Tcl_GetIntFromObj(interp, objv[5], &widthInc) != TCL_OK)
3899		|| (Tcl_GetIntFromObj(interp, objv[6], &heightInc) != TCL_OK)) {
3900	    return TCL_ERROR;
3901	}
3902	if (reqWidth < 0) {
3903	    Tcl_SetResult(interp, "baseWidth can't be < 0", TCL_STATIC);
3904	    return TCL_ERROR;
3905	}
3906	if (reqHeight < 0) {
3907	    Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC);
3908	    return TCL_ERROR;
3909	}
3910	if (widthInc <= 0) {
3911	    Tcl_SetResult(interp, "widthInc can't be <= 0", TCL_STATIC);
3912	    return TCL_ERROR;
3913	}
3914	if (heightInc <= 0) {
3915	    Tcl_SetResult(interp, "heightInc can't be <= 0", TCL_STATIC);
3916	    return TCL_ERROR;
3917	}
3918	Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
3919		heightInc);
3920    }
3921    WmUpdateGeom(wmPtr, winPtr);
3922    return TCL_OK;
3923}
3924
3925/*
3926 *----------------------------------------------------------------------
3927 *
3928 * WmGroupCmd --
3929 *
3930 *	This function is invoked to process the "wm group" Tcl command. See
3931 *	the user documentation for details on what it does.
3932 *
3933 * Results:
3934 *	A standard Tcl result.
3935 *
3936 * Side effects:
3937 *	See the user documentation.
3938 *
3939 *----------------------------------------------------------------------
3940 */
3941
3942static int
3943WmGroupCmd(
3944    Tk_Window tkwin,		/* Main window of the application. */
3945    TkWindow *winPtr,		/* Toplevel to work with */
3946    Tcl_Interp *interp,		/* Current interpreter. */
3947    int objc,			/* Number of arguments. */
3948    Tcl_Obj *CONST objv[])	/* Argument objects. */
3949{
3950    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3951    Tk_Window tkwin2;
3952    char *argv3;
3953    int length;
3954
3955    if ((objc != 3) && (objc != 4)) {
3956	Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?");
3957	return TCL_ERROR;
3958    }
3959    if (objc == 3) {
3960	if (wmPtr->hints.flags & WindowGroupHint) {
3961	    Tcl_SetResult(interp, wmPtr->leaderName, TCL_STATIC);
3962	}
3963	return TCL_OK;
3964    }
3965    argv3 = Tcl_GetStringFromObj(objv[3], &length);
3966    if (*argv3 == '\0') {
3967	wmPtr->hints.flags &= ~WindowGroupHint;
3968	if (wmPtr->leaderName != NULL) {
3969	    ckfree(wmPtr->leaderName);
3970	}
3971	wmPtr->leaderName = NULL;
3972    } else {
3973	if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) {
3974	    return TCL_ERROR;
3975	}
3976	Tk_MakeWindowExist(tkwin2);
3977	if (wmPtr->leaderName != NULL) {
3978	    ckfree(wmPtr->leaderName);
3979	}
3980	wmPtr->hints.window_group = Tk_WindowId(tkwin2);
3981	wmPtr->hints.flags |= WindowGroupHint;
3982	wmPtr->leaderName = ckalloc((unsigned) (length + 1));
3983	strcpy(wmPtr->leaderName, argv3);
3984    }
3985    return TCL_OK;
3986}
3987
3988/*
3989 *----------------------------------------------------------------------
3990 *
3991 * WmIconbitmapCmd --
3992 *
3993 *	This function is invoked to process the "wm iconbitmap" Tcl command.
3994 *	See the user documentation for details on what it does.
3995 *
3996 * Results:
3997 *	A standard Tcl result.
3998 *
3999 * Side effects:
4000 *	See the user documentation.
4001 *
4002 *----------------------------------------------------------------------
4003 */
4004
4005static int
4006WmIconbitmapCmd(
4007    Tk_Window tkwin,		/* Main window of the application. */
4008    TkWindow *winPtr,		/* Toplevel to work with */
4009    Tcl_Interp *interp,		/* Current interpreter. */
4010    int objc,			/* Number of arguments. */
4011    Tcl_Obj *CONST objv[])	/* Argument objects. */
4012{
4013    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4014    TkWindow *useWinPtr = winPtr; /* window to apply to (NULL if -default) */
4015    char *string;
4016
4017    if ((objc < 3) || (objc > 5)) {
4018	Tcl_WrongNumArgs(interp, 2, objv, "window ?-default? ?image?");
4019	return TCL_ERROR;
4020    } else if (objc == 5) {
4021	/*
4022	 * If we have 5 arguments, we must have a '-default' flag.
4023	 */
4024
4025	char *argv3 = Tcl_GetString(objv[3]);
4026
4027	if (strcmp(argv3, "-default")) {
4028	    Tcl_AppendResult(interp, "illegal option \"", argv3,
4029		    "\" must be \"-default\"", NULL);
4030	    return TCL_ERROR;
4031	}
4032	useWinPtr = NULL;
4033    } else if (objc == 3) {
4034	/*
4035	 * No arguments were given.
4036	 */
4037
4038	if (wmPtr->hints.flags & IconPixmapHint) {
4039	    Tcl_SetResult(interp, (char *)
4040		    Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_pixmap),
4041		    TCL_STATIC);
4042	}
4043	return TCL_OK;
4044    }
4045
4046    string = Tcl_GetString(objv[objc-1]);
4047    if (*string == '\0') {
4048	if (wmPtr->hints.icon_pixmap != None) {
4049	    Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
4050	    wmPtr->hints.icon_pixmap = None;
4051	}
4052	wmPtr->hints.flags &= ~IconPixmapHint;
4053	if (WinSetIcon(interp, NULL, (Tk_Window) useWinPtr) != TCL_OK) {
4054	    return TCL_ERROR;
4055	}
4056    } else {
4057	/*
4058	 * In the future this block of code will use Tk's 'image'
4059	 * functionality to allow all supported image formats. However, this
4060	 * will require a change to the way icons are handled. We will need to
4061	 * add icon<->image conversions routines.
4062	 *
4063	 * Until that happens we simply try to find an icon in the given
4064	 * argument, and if that fails, we use the older bitmap code. We do
4065	 * things this way round (icon then bitmap), because the bitmap code
4066	 * actually seems to have no visible effect, so we want to give the
4067	 * icon code the first try at doing something.
4068	 */
4069
4070	/*
4071	 * Either return NULL, or return a valid titlebaricon with its ref
4072	 * count already incremented.
4073	 */
4074
4075	WinIconPtr titlebaricon = ReadIconFromFile(interp, objv[objc-1]);
4076	if (titlebaricon != NULL) {
4077	    /*
4078	     * Try to set the icon for the window. If it is a '-default' icon,
4079	     * we must pass in NULL
4080	     */
4081
4082	    if (WinSetIcon(interp, titlebaricon, (Tk_Window) useWinPtr)
4083		    != TCL_OK) {
4084		/*
4085		 * We didn't use the titlebaricon after all.
4086		 */
4087
4088		DecrIconRefCount(titlebaricon);
4089		titlebaricon = NULL;
4090	    }
4091	}
4092	if (titlebaricon == NULL) {
4093	    /*
4094	     * We didn't manage to handle the argument as a valid icon. Try as
4095	     * a bitmap. First we must clear the error message which was
4096	     * placed in the interpreter.
4097	     */
4098
4099	    Pixmap pixmap;
4100	    Tcl_ResetResult(interp);
4101	    pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr, string);
4102	    if (pixmap == None) {
4103		return TCL_ERROR;
4104	    }
4105	    wmPtr->hints.icon_pixmap = pixmap;
4106	    wmPtr->hints.flags |= IconPixmapHint;
4107	    titlebaricon = GetIconFromPixmap(Tk_Display(winPtr), pixmap);
4108	    if (titlebaricon != NULL && WinSetIcon(interp, titlebaricon,
4109		    (Tk_Window) useWinPtr) != TCL_OK) {
4110		/*
4111		 * We didn't use the titlebaricon after all.
4112		 */
4113
4114		DecrIconRefCount(titlebaricon);
4115		titlebaricon = NULL;
4116	    }
4117	}
4118    }
4119    return TCL_OK;
4120}
4121
4122/*
4123 *----------------------------------------------------------------------
4124 *
4125 * WmIconifyCmd --
4126 *
4127 *	This function is invoked to process the "wm iconify" Tcl command. See
4128 *	the user documentation for details on what it does.
4129 *
4130 * Results:
4131 *	A standard Tcl result.
4132 *
4133 * Side effects:
4134 *	See the user documentation.
4135 *
4136 *----------------------------------------------------------------------
4137 */
4138
4139static int
4140WmIconifyCmd(
4141    Tk_Window tkwin,		/* Main window of the application. */
4142    TkWindow *winPtr,		/* Toplevel to work with */
4143    Tcl_Interp *interp,		/* Current interpreter. */
4144    int objc,			/* Number of arguments. */
4145    Tcl_Obj *CONST objv[])	/* Argument objects. */
4146{
4147    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4148    if (objc != 3) {
4149	Tcl_WrongNumArgs(interp, 2, objv, "window");
4150	return TCL_ERROR;
4151    }
4152    if (winPtr->flags & TK_EMBEDDED) {
4153	if(!SendMessage(wmPtr->wrapper, TK_ICONIFY, 0, 0)) {
4154	    Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
4155		    ": the container does not support the request", NULL);
4156	    return TCL_ERROR;
4157	}
4158    }
4159    if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
4160	Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
4161		"\": override-redirect flag is set", NULL);
4162	return TCL_ERROR;
4163    }
4164    if (wmPtr->masterPtr != NULL) {
4165	Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
4166		"\": it is a transient", NULL);
4167	return TCL_ERROR;
4168    }
4169    if (wmPtr->iconFor != NULL) {
4170	Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
4171		": it is an icon for ", Tk_PathName(wmPtr->iconFor), NULL);
4172	return TCL_ERROR;
4173    }
4174    TkpWmSetState(winPtr, IconicState);
4175    return TCL_OK;
4176}
4177
4178/*
4179 *----------------------------------------------------------------------
4180 *
4181 * WmIconmaskCmd --
4182 *
4183 *	This function is invoked to process the "wm iconmask" Tcl command.
4184 *	See the user documentation for details on what it does.
4185 *
4186 * Results:
4187 *	A standard Tcl result.
4188 *
4189 * Side effects:
4190 *	See the user documentation.
4191 *
4192 *----------------------------------------------------------------------
4193 */
4194
4195static int
4196WmIconmaskCmd(
4197    Tk_Window tkwin,		/* Main window of the application. */
4198    TkWindow *winPtr,		/* Toplevel to work with */
4199    Tcl_Interp *interp,		/* Current interpreter. */
4200    int objc,			/* Number of arguments. */
4201    Tcl_Obj *CONST objv[])	/* Argument objects. */
4202{
4203    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4204    Pixmap pixmap;
4205    char *argv3;
4206
4207    if ((objc != 3) && (objc != 4)) {
4208	Tcl_WrongNumArgs(interp, 2, objv, "window ?bitmap?");
4209	return TCL_ERROR;
4210    }
4211    if (objc == 3) {
4212	if (wmPtr->hints.flags & IconMaskHint) {
4213	    Tcl_SetResult(interp, (char *)
4214		    Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask),
4215		    TCL_STATIC);
4216	}
4217	return TCL_OK;
4218    }
4219    argv3 = Tcl_GetString(objv[3]);
4220    if (*argv3 == '\0') {
4221	if (wmPtr->hints.icon_mask != None) {
4222	    Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
4223	}
4224	wmPtr->hints.flags &= ~IconMaskHint;
4225    } else {
4226	pixmap = Tk_GetBitmap(interp, tkwin, argv3);
4227	if (pixmap == None) {
4228	    return TCL_ERROR;
4229	}
4230	wmPtr->hints.icon_mask = pixmap;
4231	wmPtr->hints.flags |= IconMaskHint;
4232    }
4233    return TCL_OK;
4234}
4235
4236/*
4237 *----------------------------------------------------------------------
4238 *
4239 * WmIconnameCmd --
4240 *
4241 *	This function is invoked to process the "wm iconname" Tcl command.
4242 *	See the user documentation for details on what it does.
4243 *
4244 * Results:
4245 *	A standard Tcl result.
4246 *
4247 * Side effects:
4248 *	See the user documentation.
4249 *
4250 *----------------------------------------------------------------------
4251 */
4252
4253static int
4254WmIconnameCmd(
4255    Tk_Window tkwin,		/* Main window of the application. */
4256    TkWindow *winPtr,		/* Toplevel to work with */
4257    Tcl_Interp *interp,		/* Current interpreter. */
4258    int objc,			/* Number of arguments. */
4259    Tcl_Obj *CONST objv[])	/* Argument objects. */
4260{
4261    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4262    char *argv3;
4263    int length;
4264
4265    if (objc > 4) {
4266	Tcl_WrongNumArgs(interp, 2, objv, "window ?newName?");
4267	return TCL_ERROR;
4268    }
4269    if (objc == 3) {
4270	Tcl_SetResult(interp,
4271		((wmPtr->iconName != NULL) ? wmPtr->iconName : ""),
4272		TCL_STATIC);
4273	return TCL_OK;
4274    } else {
4275	if (wmPtr->iconName != NULL) {
4276	    ckfree((char *) wmPtr->iconName);
4277	}
4278	argv3 = Tcl_GetStringFromObj(objv[3], &length);
4279	wmPtr->iconName = ckalloc((unsigned) (length + 1));
4280	strcpy(wmPtr->iconName, argv3);
4281	if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
4282	    XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
4283	}
4284    }
4285    return TCL_OK;
4286}
4287
4288/*
4289 *----------------------------------------------------------------------
4290 *
4291 * WmIconphotoCmd --
4292 *
4293 *	This function is invoked to process the "wm iconphoto" Tcl command.
4294 *	See the user documentation for details on what it does.
4295 *
4296 * Results:
4297 *	A standard Tcl result.
4298 *
4299 * Side effects:
4300 *	See the user documentation.
4301 *
4302 *----------------------------------------------------------------------
4303 */
4304
4305static int
4306WmIconphotoCmd(
4307    Tk_Window tkwin,		/* Main window of the application. */
4308    TkWindow *winPtr,		/* Toplevel to work with */
4309    Tcl_Interp *interp,		/* Current interpreter. */
4310    int objc,			/* Number of arguments. */
4311    Tcl_Obj *CONST objv[])	/* Argument objects. */
4312{
4313    TkWindow *useWinPtr = winPtr; /* window to apply to (NULL if -default) */
4314    Tk_PhotoHandle photo;
4315    Tk_PhotoImageBlock block;
4316    int i, width, height, idx, bufferSize, startObj = 3;
4317    union {unsigned char *ptr; void *voidPtr;} bgraPixel;
4318    void *bgraMaskPtr;
4319    BlockOfIconImagesPtr lpIR;
4320    WinIconPtr titlebaricon = NULL;
4321    HICON hIcon;
4322    unsigned size;
4323    BITMAPINFO bmInfo;
4324    ICONINFO iconInfo;
4325
4326    if (objc < 4) {
4327	Tcl_WrongNumArgs(interp, 2, objv,
4328		"window ?-default? image1 ?image2 ...?");
4329	return TCL_ERROR;
4330    }
4331
4332    /*
4333     * Iterate over all images to validate their existence.
4334     */
4335
4336    if (strcmp(Tcl_GetString(objv[3]), "-default") == 0) {
4337	useWinPtr = NULL;
4338	startObj = 4;
4339	if (objc == 4) {
4340	    Tcl_WrongNumArgs(interp, 2, objv,
4341		    "window ?-default? image1 ?image2 ...?");
4342	    return TCL_ERROR;
4343	}
4344    }
4345    for (i = startObj; i < objc; i++) {
4346	photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
4347	if (photo == NULL) {
4348	    Tcl_AppendResult(interp, "can't use \"", Tcl_GetString(objv[i]),
4349		    "\" as iconphoto: not a photo image", NULL);
4350	    return TCL_ERROR;
4351	}
4352    }
4353
4354    /*
4355     * We have calculated the size of the data. Try to allocate the needed
4356     * memory space.
4357     */
4358
4359    size = sizeof(BlockOfIconImages) + (sizeof(ICONIMAGE) * (objc-startObj-1));
4360    lpIR = (BlockOfIconImagesPtr) attemptckalloc(size);
4361    if (lpIR == NULL) {
4362	return TCL_ERROR;
4363    }
4364    ZeroMemory(lpIR, size);
4365
4366    lpIR->nNumImages = objc - startObj;
4367
4368    for (i = startObj; i < objc; i++) {
4369	photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
4370	Tk_PhotoGetSize(photo, &width, &height);
4371	Tk_PhotoGetImage(photo, &block);
4372
4373	/*
4374	 * Don't use CreateIcon to create the icon, as it requires color
4375	 * bitmap data in device-dependent format.  Instead we use
4376	 * CreateIconIndirect which takes device-independent bitmaps
4377	 * and converts them as required.  Initialise icon info structure.
4378	 */
4379
4380	ZeroMemory( &iconInfo, sizeof iconInfo );
4381	iconInfo.fIcon = TRUE;
4382
4383	/*
4384	 * Create device-independant color bitmap.
4385	 */
4386	ZeroMemory(&bmInfo,sizeof bmInfo);
4387	bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
4388	bmInfo.bmiHeader.biWidth = width;
4389	bmInfo.bmiHeader.biHeight = -height;
4390	bmInfo.bmiHeader.biPlanes = 1;
4391	bmInfo.bmiHeader.biBitCount = 32;
4392	bmInfo.bmiHeader.biCompression = BI_RGB;
4393
4394	iconInfo.hbmColor = CreateDIBSection( NULL, &bmInfo,
4395	    DIB_RGB_COLORS, &bgraPixel.voidPtr, NULL, 0 );
4396	if ( !iconInfo.hbmColor ) {
4397	    ckfree((char *) lpIR);
4398	    Tcl_AppendResult(interp, "failed to create color bitmap for \"",
4399		    Tcl_GetString(objv[i]), "\"", NULL);
4400	    return TCL_ERROR;
4401	}
4402
4403	/*
4404	 * Convert the photo image data into BGRA format (RGBQUAD).
4405	 */
4406	bufferSize = height * width * 4;
4407	for (idx = 0 ; idx < bufferSize ; idx += 4) {
4408	    bgraPixel.ptr[idx] = block.pixelPtr[idx+2];
4409	    bgraPixel.ptr[idx+1] = block.pixelPtr[idx+1];
4410	    bgraPixel.ptr[idx+2] = block.pixelPtr[idx+0];
4411	    bgraPixel.ptr[idx+3] = block.pixelPtr[idx+3];
4412	}
4413
4414	/*
4415	 * Create a dummy mask bitmap.  The contents of this don't
4416	 * appear to matter, as CreateIconIndirect will setup the icon
4417	 * mask based on the alpha channel in our color bitmap.
4418	 */
4419	bmInfo.bmiHeader.biBitCount = 1;
4420
4421	iconInfo.hbmMask = CreateDIBSection( NULL, &bmInfo,
4422	    DIB_RGB_COLORS, &bgraMaskPtr, NULL, 0 );
4423	if ( !iconInfo.hbmMask ) {
4424	    DeleteObject(iconInfo.hbmColor);
4425	    ckfree((char *) lpIR);
4426	    Tcl_AppendResult(interp, "failed to create mask bitmap for \"",
4427		    Tcl_GetString(objv[i]), "\"", NULL);
4428	    return TCL_ERROR;
4429	}
4430
4431	ZeroMemory( bgraMaskPtr, width*height/8 );
4432
4433	/*
4434	 * Create an icon from the bitmaps.
4435	 */
4436	hIcon = CreateIconIndirect( &iconInfo);
4437	DeleteObject(iconInfo.hbmColor);
4438	DeleteObject(iconInfo.hbmMask);
4439	if (hIcon == NULL) {
4440	    /*
4441	     * XXX should free up created icons.
4442	     */
4443
4444	    ckfree((char *) lpIR);
4445	    Tcl_AppendResult(interp, "failed to create icon for \"",
4446		    Tcl_GetString(objv[i]), "\"", NULL);
4447	    return TCL_ERROR;
4448	}
4449	lpIR->IconImages[i-startObj].Width = width;
4450	lpIR->IconImages[i-startObj].Height = height;
4451	lpIR->IconImages[i-startObj].Colors = 4;
4452	lpIR->IconImages[i-startObj].hIcon = hIcon;
4453    }
4454
4455    titlebaricon = (WinIconPtr) ckalloc(sizeof(WinIconInstance));
4456    titlebaricon->iconBlock = lpIR;
4457    titlebaricon->refCount = 1;
4458    if (WinSetIcon(interp, titlebaricon, (Tk_Window) useWinPtr) != TCL_OK) {
4459	/*
4460	 * We didn't use the titlebaricon after all.
4461	 */
4462
4463	DecrIconRefCount(titlebaricon);
4464	return TCL_ERROR;
4465    }
4466    return TCL_OK;
4467}
4468
4469/*
4470 *----------------------------------------------------------------------
4471 *
4472 * WmIconpositionCmd --
4473 *
4474 *	This function is invoked to process the "wm iconposition" Tcl command.
4475 *	See the user documentation for details on what it does.
4476 *
4477 * Results:
4478 *	A standard Tcl result.
4479 *
4480 * Side effects:
4481 *	See the user documentation.
4482 *
4483 *----------------------------------------------------------------------
4484 */
4485
4486static int
4487WmIconpositionCmd(
4488    Tk_Window tkwin,		/* Main window of the application. */
4489    TkWindow *winPtr,		/* Toplevel to work with */
4490    Tcl_Interp *interp,		/* Current interpreter. */
4491    int objc,			/* Number of arguments. */
4492    Tcl_Obj *CONST objv[])	/* Argument objects. */
4493{
4494    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4495    int x, y;
4496
4497    if ((objc != 3) && (objc != 5)) {
4498	Tcl_WrongNumArgs(interp, 2, objv, "window ?x y?");
4499	return TCL_ERROR;
4500    }
4501    if (objc == 3) {
4502	if (wmPtr->hints.flags & IconPositionHint) {
4503	    char buf[TCL_INTEGER_SPACE * 2];
4504
4505	    sprintf(buf, "%d %d", wmPtr->hints.icon_x,
4506		    wmPtr->hints.icon_y);
4507	    Tcl_SetResult(interp, buf, TCL_VOLATILE);
4508	}
4509	return TCL_OK;
4510    }
4511    if (*Tcl_GetString(objv[3]) == '\0') {
4512	wmPtr->hints.flags &= ~IconPositionHint;
4513    } else {
4514	if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
4515		|| (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)){
4516	    return TCL_ERROR;
4517	}
4518	wmPtr->hints.icon_x = x;
4519	wmPtr->hints.icon_y = y;
4520	wmPtr->hints.flags |= IconPositionHint;
4521    }
4522    return TCL_OK;
4523}
4524
4525/*
4526 *----------------------------------------------------------------------
4527 *
4528 * WmIconwindowCmd --
4529 *
4530 *	This function is invoked to process the "wm iconwindow" Tcl command.
4531 *	See the user documentation for details on what it does.
4532 *
4533 * Results:
4534 *	A standard Tcl result.
4535 *
4536 * Side effects:
4537 *	See the user documentation.
4538 *
4539 *----------------------------------------------------------------------
4540 */
4541
4542static int
4543WmIconwindowCmd(
4544    Tk_Window tkwin,		/* Main window of the application. */
4545    TkWindow *winPtr,		/* Toplevel to work with */
4546    Tcl_Interp *interp,		/* Current interpreter. */
4547    int objc,			/* Number of arguments. */
4548    Tcl_Obj *CONST objv[])	/* Argument objects. */
4549{
4550    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4551    Tk_Window tkwin2;
4552    WmInfo *wmPtr2;
4553    XSetWindowAttributes atts;
4554
4555    if ((objc != 3) && (objc != 4)) {
4556	Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?");
4557	return TCL_ERROR;
4558    }
4559    if (objc == 3) {
4560	if (wmPtr->icon != NULL) {
4561	    Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC);
4562	}
4563	return TCL_OK;
4564    }
4565    if (*Tcl_GetString(objv[3]) == '\0') {
4566	wmPtr->hints.flags &= ~IconWindowHint;
4567	if (wmPtr->icon != NULL) {
4568	    /*
4569	     * Let the window use button events again, then remove it as icon
4570	     * window.
4571	     */
4572
4573	    atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
4574		    | ButtonPressMask;
4575	    Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
4576	    wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
4577	    wmPtr2->iconFor = NULL;
4578	    wmPtr2->hints.initial_state = WithdrawnState;
4579	}
4580	wmPtr->icon = NULL;
4581    } else {
4582	if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) {
4583	    return TCL_ERROR;
4584	}
4585	if (!Tk_IsTopLevel(tkwin2)) {
4586	    Tcl_AppendResult(interp, "can't use ", Tcl_GetString(objv[3]),
4587		    " as icon window: not at top level", NULL);
4588	    return TCL_ERROR;
4589	}
4590	wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
4591	if (wmPtr2->iconFor != NULL) {
4592	    Tcl_AppendResult(interp, Tcl_GetString(objv[3]),
4593		    " is already an icon for ", Tk_PathName(wmPtr2->iconFor),
4594		    NULL);
4595	    return TCL_ERROR;
4596	}
4597	if (wmPtr->icon != NULL) {
4598	    WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
4599	    wmPtr3->iconFor = NULL;
4600
4601	    /*
4602	     * Let the window use button events again.
4603	     */
4604
4605	    atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
4606		    | ButtonPressMask;
4607	    Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
4608	}
4609
4610	/*
4611	 * Disable button events in the icon window: some window managers
4612	 * (like olvwm) want to get the events themselves, but X only allows
4613	 * one application at a time to receive button events for a window.
4614	 */
4615
4616	atts.event_mask = Tk_Attributes(tkwin2)->event_mask
4617		& ~ButtonPressMask;
4618	Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
4619	Tk_MakeWindowExist(tkwin2);
4620	wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
4621	wmPtr->hints.flags |= IconWindowHint;
4622	wmPtr->icon = tkwin2;
4623	wmPtr2->iconFor = (Tk_Window) winPtr;
4624	if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
4625	    wmPtr2->flags |= WM_WITHDRAWN;
4626	    TkpWmSetState(((TkWindow *) tkwin2), WithdrawnState);
4627	}
4628    }
4629    return TCL_OK;
4630}
4631
4632/*
4633 *----------------------------------------------------------------------
4634 *
4635 * WmManageCmd --
4636 *
4637 *	This procedure is invoked to process the "wm manage" Tcl command.
4638 *	See the user documentation for details on what it does.
4639 *
4640 * Results:
4641 *	A standard Tcl result.
4642 *
4643 * Side effects:
4644 *	See the user documentation.
4645 *
4646 *----------------------------------------------------------------------
4647 */
4648
4649static int
4650WmManageCmd(tkwin, winPtr, interp, objc, objv)
4651    Tk_Window tkwin;		/* Main window of the application. */
4652    TkWindow *winPtr;           /* Toplevel or Frame to work with */
4653    Tcl_Interp *interp;		/* Current interpreter. */
4654    int objc;			/* Number of arguments. */
4655    Tcl_Obj *CONST objv[];	/* Argument objects. */
4656{
4657    register Tk_Window frameWin = (Tk_Window)winPtr;
4658    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4659
4660    if (!Tk_IsTopLevel(frameWin)) {
4661	if (!Tk_IsManageable(frameWin)) {
4662	    Tcl_AppendResult(interp, "window \"",
4663		Tk_PathName(frameWin), "\" is not manageable: must be "
4664		"a frame, labelframe or toplevel", NULL);
4665	    return TCL_ERROR;
4666	}
4667	TkFocusSplit(winPtr);
4668	Tk_UnmapWindow(frameWin);
4669	winPtr->flags |= TK_TOP_HIERARCHY|TK_TOP_LEVEL|TK_HAS_WRAPPER|TK_WIN_MANAGED;
4670	RemapWindows(winPtr, NULL);
4671	if (wmPtr == NULL) {
4672	    TkWmNewWindow(winPtr);
4673	}
4674	wmPtr = winPtr->wmInfoPtr;
4675	winPtr->flags &= ~TK_MAPPED;
4676	/* flags (above) must be set before calling */
4677	/* TkMapTopFrame (below) */
4678	TkMapTopFrame (frameWin);
4679    } else if (Tk_IsTopLevel(frameWin)) {
4680	/* Already managed by wm - ignore it */
4681    }
4682    return TCL_OK;
4683}
4684
4685/*
4686 *----------------------------------------------------------------------
4687 *
4688 * WmMaxsizeCmd --
4689 *
4690 *	This function is invoked to process the "wm maxsize" Tcl command. See
4691 *	the user documentation for details on what it does.
4692 *
4693 * Results:
4694 *	A standard Tcl result.
4695 *
4696 * Side effects:
4697 *	See the user documentation.
4698 *
4699 *----------------------------------------------------------------------
4700 */
4701
4702static int
4703WmMaxsizeCmd(
4704    Tk_Window tkwin,		/* Main window of the application. */
4705    TkWindow *winPtr,		/* Toplevel to work with */
4706    Tcl_Interp *interp,		/* Current interpreter. */
4707    int objc,			/* Number of arguments. */
4708    Tcl_Obj *CONST objv[])	/* Argument objects. */
4709{
4710    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4711    int width, height;
4712
4713    if ((objc != 3) && (objc != 5)) {
4714	Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
4715	return TCL_ERROR;
4716    }
4717    if (objc == 3) {
4718	char buf[TCL_INTEGER_SPACE * 2];
4719
4720	GetMaxSize(wmPtr, &width, &height);
4721	sprintf(buf, "%d %d", width, height);
4722	Tcl_SetResult(interp, buf, TCL_VOLATILE);
4723	return TCL_OK;
4724    }
4725    if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
4726	    || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
4727	return TCL_ERROR;
4728    }
4729    wmPtr->maxWidth = width;
4730    wmPtr->maxHeight = height;
4731    WmUpdateGeom(wmPtr, winPtr);
4732    return TCL_OK;
4733}
4734
4735/*
4736 *----------------------------------------------------------------------
4737 *
4738 * WmMinsizeCmd --
4739 *
4740 *	This function is invoked to process the "wm minsize" Tcl command. See
4741 *	the user documentation for details on what it does.
4742 *
4743 * Results:
4744 *	A standard Tcl result.
4745 *
4746 * Side effects:
4747 *	See the user documentation.
4748 *
4749 *----------------------------------------------------------------------
4750 */
4751
4752static int
4753WmMinsizeCmd(
4754    Tk_Window tkwin,		/* Main window of the application. */
4755    TkWindow *winPtr,		/* Toplevel to work with */
4756    Tcl_Interp *interp,		/* Current interpreter. */
4757    int objc,			/* Number of arguments. */
4758    Tcl_Obj *CONST objv[])	/* Argument objects. */
4759{
4760    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4761    int width, height;
4762
4763    if ((objc != 3) && (objc != 5)) {
4764	Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
4765	return TCL_ERROR;
4766    }
4767    if (objc == 3) {
4768	char buf[TCL_INTEGER_SPACE * 2];
4769
4770	GetMinSize(wmPtr, &width, &height);
4771	sprintf(buf, "%d %d", width, height);
4772	Tcl_SetResult(interp, buf, TCL_VOLATILE);
4773	return TCL_OK;
4774    }
4775    if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
4776	    || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
4777	return TCL_ERROR;
4778    }
4779    wmPtr->minWidth = width;
4780    wmPtr->minHeight = height;
4781    WmUpdateGeom(wmPtr, winPtr);
4782    return TCL_OK;
4783}
4784
4785/*
4786 *----------------------------------------------------------------------
4787 *
4788 * WmOverrideredirectCmd --
4789 *
4790 *	This function is invoked to process the "wm overrideredirect" Tcl
4791 *	command. See the user documentation for details on what it does.
4792 *
4793 * Results:
4794 *	A standard Tcl result.
4795 *
4796 * Side effects:
4797 *	See the user documentation.
4798 *
4799 *----------------------------------------------------------------------
4800 */
4801
4802static int
4803WmOverrideredirectCmd(
4804    Tk_Window tkwin,		/* Main window of the application. */
4805    TkWindow *winPtr,		/* Toplevel to work with */
4806    Tcl_Interp *interp,		/* Current interpreter. */
4807    int objc,			/* Number of arguments. */
4808    Tcl_Obj *CONST objv[])	/* Argument objects. */
4809{
4810    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4811    int boolean, curValue;
4812    XSetWindowAttributes atts;
4813
4814    if ((objc != 3) && (objc != 4)) {
4815	Tcl_WrongNumArgs(interp, 2, objv, "window ?boolean?");
4816	return TCL_ERROR;
4817    }
4818    if(winPtr->flags & TK_EMBEDDED) {
4819	curValue = SendMessage(wmPtr->wrapper, TK_OVERRIDEREDIRECT, -1, -1)-1;
4820	if (curValue < 0) {
4821	    Tcl_AppendResult(interp,
4822		    "Container does not support overrideredirect", NULL);
4823	    return TCL_ERROR;
4824	}
4825    } else {
4826	curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect;
4827    }
4828    if (objc == 3) {
4829	Tcl_SetBooleanObj(Tcl_GetObjResult(interp), curValue);
4830	return TCL_OK;
4831    }
4832    if (Tcl_GetBooleanFromObj(interp, objv[3], &boolean) != TCL_OK) {
4833	return TCL_ERROR;
4834    }
4835    if (curValue != boolean) {
4836	if(winPtr->flags & TK_EMBEDDED) {
4837	    SendMessage(wmPtr->wrapper, TK_OVERRIDEREDIRECT, boolean, 0);
4838	} else {
4839	    /*
4840	     * Only do this if we are really changing value, because it causes
4841	     * some funky stuff to occur.
4842	     */
4843
4844	    atts.override_redirect = (boolean) ? True : False;
4845	    Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
4846		    &atts);
4847	    if (!(wmPtr->flags & (WM_NEVER_MAPPED))
4848		&& !(winPtr->flags & TK_EMBEDDED)) {
4849		UpdateWrapper(winPtr);
4850	    }
4851	}
4852    }
4853    return TCL_OK;
4854}
4855
4856/*
4857 *----------------------------------------------------------------------
4858 *
4859 * WmPositionfromCmd --
4860 *
4861 *	This function is invoked to process the "wm positionfrom" Tcl command.
4862 *	See the user documentation for details on what it does.
4863 *
4864 * Results:
4865 *	A standard Tcl result.
4866 *
4867 * Side effects:
4868 *	See the user documentation.
4869 *
4870 *----------------------------------------------------------------------
4871 */
4872
4873static int
4874WmPositionfromCmd(
4875    Tk_Window tkwin,		/* Main window of the application. */
4876    TkWindow *winPtr,		/* Toplevel to work with */
4877    Tcl_Interp *interp,		/* Current interpreter. */
4878    int objc,			/* Number of arguments. */
4879    Tcl_Obj *CONST objv[])	/* Argument objects. */
4880{
4881    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4882    static CONST char *optionStrings[] = {
4883	"program", "user", NULL
4884    };
4885    enum options {
4886	OPT_PROGRAM, OPT_USER
4887    };
4888    int index;
4889
4890    if ((objc != 3) && (objc != 4)) {
4891	Tcl_WrongNumArgs(interp, 2, objv, "window ?user/program?");
4892	return TCL_ERROR;
4893    }
4894    if (objc == 3) {
4895	if (wmPtr->sizeHintsFlags & USPosition) {
4896	    Tcl_SetResult(interp, "user", TCL_STATIC);
4897	} else if (wmPtr->sizeHintsFlags & PPosition) {
4898	    Tcl_SetResult(interp, "program", TCL_STATIC);
4899	}
4900	return TCL_OK;
4901    }
4902    if (*Tcl_GetString(objv[3]) == '\0') {
4903	wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
4904    } else {
4905	if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
4906		&index) != TCL_OK) {
4907	    return TCL_ERROR;
4908	}
4909	if (index == OPT_USER) {
4910	    wmPtr->sizeHintsFlags &= ~PPosition;
4911	    wmPtr->sizeHintsFlags |= USPosition;
4912	} else {
4913	    wmPtr->sizeHintsFlags &= ~USPosition;
4914	    wmPtr->sizeHintsFlags |= PPosition;
4915	}
4916    }
4917    WmUpdateGeom(wmPtr, winPtr);
4918    return TCL_OK;
4919}
4920
4921/*
4922 *----------------------------------------------------------------------
4923 *
4924 * WmProtocolCmd --
4925 *
4926 *	This function is invoked to process the "wm protocol" Tcl command.
4927 *	See the user documentation for details on what it does.
4928 *
4929 * Results:
4930 *	A standard Tcl result.
4931 *
4932 * Side effects:
4933 *	See the user documentation.
4934 *
4935 *----------------------------------------------------------------------
4936 */
4937
4938static int
4939WmProtocolCmd(
4940    Tk_Window tkwin,		/* Main window of the application. */
4941    TkWindow *winPtr,		/* Toplevel to work with */
4942    Tcl_Interp *interp,		/* Current interpreter. */
4943    int objc,			/* Number of arguments. */
4944    Tcl_Obj *CONST objv[])	/* Argument objects. */
4945{
4946    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4947    register ProtocolHandler *protPtr, *prevPtr;
4948    Atom protocol;
4949    char *cmd;
4950    int cmdLength;
4951
4952    if ((objc < 3) || (objc > 5)) {
4953	Tcl_WrongNumArgs(interp, 2, objv, "window ?name? ?command?");
4954	return TCL_ERROR;
4955    }
4956    if (objc == 3) {
4957	/*
4958	 * Return a list of all defined protocols for the window.
4959	 */
4960
4961	for (protPtr = wmPtr->protPtr; protPtr != NULL;
4962		protPtr = protPtr->nextPtr) {
4963	    Tcl_AppendElement(interp,
4964		    Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
4965	}
4966	return TCL_OK;
4967    }
4968    protocol = Tk_InternAtom((Tk_Window) winPtr, Tcl_GetString(objv[3]));
4969    if (objc == 4) {
4970	/*
4971	 * Return the command to handle a given protocol.
4972	 */
4973
4974	for (protPtr = wmPtr->protPtr; protPtr != NULL;
4975		protPtr = protPtr->nextPtr) {
4976	    if (protPtr->protocol == protocol) {
4977		Tcl_SetResult(interp, protPtr->command, TCL_STATIC);
4978		return TCL_OK;
4979	    }
4980	}
4981	return TCL_OK;
4982    }
4983
4984    /*
4985     * Delete any current protocol handler, then create a new one with the
4986     * specified command, unless the command is empty.
4987     */
4988
4989    for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
4990	    prevPtr = protPtr, protPtr = protPtr->nextPtr) {
4991	if (protPtr->protocol == protocol) {
4992	    if (prevPtr == NULL) {
4993		wmPtr->protPtr = protPtr->nextPtr;
4994	    } else {
4995		prevPtr->nextPtr = protPtr->nextPtr;
4996	    }
4997	    Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
4998	    break;
4999	}
5000    }
5001    cmd = Tcl_GetStringFromObj(objv[4], &cmdLength);
5002    if (cmdLength > 0) {
5003	protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
5004	protPtr->protocol = protocol;
5005	protPtr->nextPtr = wmPtr->protPtr;
5006	wmPtr->protPtr = protPtr;
5007	protPtr->interp = interp;
5008	strcpy(protPtr->command, cmd);
5009    }
5010    return TCL_OK;
5011}
5012
5013/*
5014 *----------------------------------------------------------------------
5015 *
5016 * WmResizableCmd --
5017 *
5018 *	This function is invoked to process the "wm resizable" Tcl command.
5019 *	See the user documentation for details on what it does.
5020 *
5021 * Results:
5022 *	A standard Tcl result.
5023 *
5024 * Side effects:
5025 *	See the user documentation.
5026 *
5027 *----------------------------------------------------------------------
5028 */
5029
5030static int
5031WmResizableCmd(
5032    Tk_Window tkwin,		/* Main window of the application. */
5033    TkWindow *winPtr,		/* Toplevel to work with */
5034    Tcl_Interp *interp,		/* Current interpreter. */
5035    int objc,			/* Number of arguments. */
5036    Tcl_Obj *CONST objv[])	/* Argument objects. */
5037{
5038    register WmInfo *wmPtr = winPtr->wmInfoPtr;
5039    int width, height;
5040
5041    if ((objc != 3) && (objc != 5)) {
5042	Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
5043	return TCL_ERROR;
5044    }
5045    if (objc == 3) {
5046	char buf[TCL_INTEGER_SPACE * 2];
5047
5048	sprintf(buf, "%d %d",
5049		(wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
5050		(wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
5051	Tcl_SetResult(interp, buf, TCL_VOLATILE);
5052	return TCL_OK;
5053    }
5054    if ((Tcl_GetBooleanFromObj(interp, objv[3], &width) != TCL_OK)
5055	    || (Tcl_GetBooleanFromObj(interp, objv[4], &height) != TCL_OK)) {
5056	return TCL_ERROR;
5057    }
5058    if (width) {
5059	wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
5060    } else {
5061	wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
5062    }
5063    if (height) {
5064	wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
5065    } else {
5066	wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
5067    }
5068    if (!((wmPtr->flags & WM_NEVER_MAPPED)
5069	    && !(winPtr->flags & TK_EMBEDDED))) {
5070	UpdateWrapper(winPtr);
5071    }
5072    WmUpdateGeom(wmPtr, winPtr);
5073    return TCL_OK;
5074}
5075
5076/*
5077 *----------------------------------------------------------------------
5078 *
5079 * WmSizefromCmd --
5080 *
5081 *	This function is invoked to process the "wm sizefrom" Tcl command.
5082 *	See the user documentation for details on what it does.
5083 *
5084 * Results:
5085 *	A standard Tcl result.
5086 *
5087 * Side effects:
5088 *	See the user documentation.
5089 *
5090 *----------------------------------------------------------------------
5091 */
5092
5093static int
5094WmSizefromCmd(
5095    Tk_Window tkwin,		/* Main window of the application. */
5096    TkWindow *winPtr,		/* Toplevel to work with */
5097    Tcl_Interp *interp,		/* Current interpreter. */
5098    int objc,			/* Number of arguments. */
5099    Tcl_Obj *CONST objv[])	/* Argument objects. */
5100{
5101    register WmInfo *wmPtr = winPtr->wmInfoPtr;
5102    static CONST char *optionStrings[] = {
5103	"program", "user", NULL
5104    };
5105    enum options {
5106	OPT_PROGRAM, OPT_USER
5107    };
5108    int index;
5109
5110    if ((objc != 3) && (objc != 4)) {
5111	Tcl_WrongNumArgs(interp, 2, objv, "window ?user|program?");
5112	return TCL_ERROR;
5113    }
5114    if (objc == 3) {
5115	if (wmPtr->sizeHintsFlags & USSize) {
5116	    Tcl_SetResult(interp, "user", TCL_STATIC);
5117	} else if (wmPtr->sizeHintsFlags & PSize) {
5118	    Tcl_SetResult(interp, "program", TCL_STATIC);
5119	}
5120	return TCL_OK;
5121    }
5122
5123    if (*Tcl_GetString(objv[3]) == '\0') {
5124	wmPtr->sizeHintsFlags &= ~(USSize|PSize);
5125    } else {
5126	if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
5127		&index) != TCL_OK) {
5128	    return TCL_ERROR;
5129	}
5130	if (index == OPT_USER) {
5131	    wmPtr->sizeHintsFlags &= ~PSize;
5132	    wmPtr->sizeHintsFlags |= USSize;
5133	} else { /* OPT_PROGRAM */
5134	    wmPtr->sizeHintsFlags &= ~USSize;
5135	    wmPtr->sizeHintsFlags |= PSize;
5136	}
5137    }
5138    WmUpdateGeom(wmPtr, winPtr);
5139    return TCL_OK;
5140}
5141
5142/*
5143 *----------------------------------------------------------------------
5144 *
5145 * WmStackorderCmd --
5146 *
5147 *	This function is invoked to process the "wm stackorder" Tcl command.
5148 *	See the user documentation for details on what it does.
5149 *
5150 * Results:
5151 *	A standard Tcl result.
5152 *
5153 * Side effects:
5154 *	See the user documentation.
5155 *
5156 *----------------------------------------------------------------------
5157 */
5158
5159static int
5160WmStackorderCmd(
5161    Tk_Window tkwin,		/* Main window of the application. */
5162    TkWindow *winPtr,		/* Toplevel to work with */
5163    Tcl_Interp *interp,		/* Current interpreter. */
5164    int objc,			/* Number of arguments. */
5165    Tcl_Obj *CONST objv[])	/* Argument objects. */
5166{
5167    TkWindow **windows, **window_ptr;
5168    static CONST char *optionStrings[] = {
5169	"isabove", "isbelow", NULL
5170    };
5171    enum options {
5172	OPT_ISABOVE, OPT_ISBELOW
5173    };
5174    int index;
5175
5176    if ((objc != 3) && (objc != 5)) {
5177	Tcl_WrongNumArgs(interp, 2, objv, "window ?isabove|isbelow window?");
5178	return TCL_ERROR;
5179    }
5180
5181    if (objc == 3) {
5182	windows = TkWmStackorderToplevel(winPtr);
5183	if (windows == NULL) {
5184	    Tcl_Panic("TkWmStackorderToplevel failed");
5185	} else {
5186	    for (window_ptr = windows; *window_ptr ; window_ptr++) {
5187		Tcl_AppendElement(interp, (*window_ptr)->pathName);
5188	    }
5189	    ckfree((char *) windows);
5190	    return TCL_OK;
5191	}
5192    } else {
5193	TkWindow *winPtr2, **winPtr2Ptr = &winPtr2;
5194	int index1=-1, index2=-1, result;
5195
5196	if (TkGetWindowFromObj(interp, tkwin, objv[4],
5197		(Tk_Window *) winPtr2Ptr) != TCL_OK) {
5198	    return TCL_ERROR;
5199	}
5200
5201	if (!Tk_IsTopLevel(winPtr2)) {
5202	    Tcl_AppendResult(interp, "window \"", winPtr2->pathName,
5203		    "\" isn't a top-level window", NULL);
5204	    return TCL_ERROR;
5205	}
5206
5207	if (!Tk_IsMapped(winPtr)) {
5208	    Tcl_AppendResult(interp, "window \"", winPtr->pathName,
5209		    "\" isn't mapped", NULL);
5210	    return TCL_ERROR;
5211	}
5212
5213	if (!Tk_IsMapped(winPtr2)) {
5214	    Tcl_AppendResult(interp, "window \"", winPtr2->pathName,
5215		    "\" isn't mapped", NULL);
5216	    return TCL_ERROR;
5217	}
5218
5219	/*
5220	 * Lookup stacking order of all toplevels that are children of "." and
5221	 * find the position of winPtr and winPtr2 in the stacking order.
5222	 */
5223
5224	windows = TkWmStackorderToplevel(winPtr->mainPtr->winPtr);
5225
5226	if (windows == NULL) {
5227	    Tcl_AppendResult(interp, "TkWmStackorderToplevel failed", NULL);
5228	    return TCL_ERROR;
5229	} else {
5230	    for (window_ptr = windows; *window_ptr ; window_ptr++) {
5231		if (*window_ptr == winPtr) {
5232		    index1 = (window_ptr - windows);
5233		}
5234		if (*window_ptr == winPtr2) {
5235		    index2 = (window_ptr - windows);
5236		}
5237	    }
5238	    if (index1 == -1) {
5239		Tcl_Panic("winPtr window not found");
5240	    }
5241	    if (index2 == -1) {
5242		Tcl_Panic("winPtr2 window not found");
5243	    }
5244
5245	    ckfree((char *) windows);
5246	}
5247
5248	if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
5249		&index) != TCL_OK) {
5250	    return TCL_ERROR;
5251	}
5252	if (index == OPT_ISABOVE) {
5253	    result = index1 > index2;
5254	} else { /* OPT_ISBELOW */
5255	    result = index1 < index2;
5256	}
5257	Tcl_SetIntObj(Tcl_GetObjResult(interp), result);
5258	return TCL_OK;
5259    }
5260    return TCL_OK;
5261}
5262
5263/*
5264 *----------------------------------------------------------------------
5265 *
5266 * WmStateCmd --
5267 *
5268 *	This function is invoked to process the "wm state" Tcl command. See
5269 *	the user documentation for details on what it does.
5270 *
5271 * Results:
5272 *	A standard Tcl result.
5273 *
5274 * Side effects:
5275 *	See the user documentation.
5276 *
5277 *----------------------------------------------------------------------
5278 */
5279
5280static int
5281WmStateCmd(
5282    Tk_Window tkwin,		/* Main window of the application. */
5283    TkWindow *winPtr,		/* Toplevel to work with */
5284    Tcl_Interp *interp,		/* Current interpreter. */
5285    int objc,			/* Number of arguments. */
5286    Tcl_Obj *CONST objv[])	/* Argument objects. */
5287{
5288    register WmInfo *wmPtr = winPtr->wmInfoPtr;
5289    static CONST char *optionStrings[] = {
5290	"normal", "iconic", "withdrawn", "zoomed", NULL
5291    };
5292    enum options {
5293	OPT_NORMAL, OPT_ICONIC, OPT_WITHDRAWN, OPT_ZOOMED
5294    };
5295    int index;
5296
5297    if ((objc < 3) || (objc > 4)) {
5298	Tcl_WrongNumArgs(interp, 2, objv, "window ?state?");
5299	return TCL_ERROR;
5300    }
5301    if (objc == 4) {
5302	if (wmPtr->iconFor != NULL) {
5303	    Tcl_AppendResult(interp, "can't change state of ",
5304		    Tcl_GetString(objv[2]), ": it is an icon for ",
5305		    Tk_PathName(wmPtr->iconFor), NULL);
5306	    return TCL_ERROR;
5307	}
5308	if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
5309		&index) != TCL_OK) {
5310	    return TCL_ERROR;
5311	}
5312
5313	if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
5314		&index) != TCL_OK) {
5315	    return TCL_ERROR;
5316	}
5317
5318	if (winPtr->flags & TK_EMBEDDED) {
5319	    int state = 0;
5320
5321	    switch (index) {
5322	    case OPT_NORMAL:
5323		state = NormalState;
5324		break;
5325	    case OPT_ICONIC:
5326		state = IconicState;
5327		break;
5328	    case OPT_WITHDRAWN:
5329		state = WithdrawnState;
5330		break;
5331	    case OPT_ZOOMED:
5332		state = ZoomState;
5333		break;
5334	    default:
5335		Tcl_Panic("unexpected index");
5336	    }
5337
5338	    if (state+1 != SendMessage(wmPtr->wrapper, TK_STATE, state, 0)) {
5339		Tcl_AppendResult(interp, "can't change state of ",
5340			winPtr->pathName,
5341			": the container does not support the request", NULL);
5342		return TCL_ERROR;
5343	    }
5344	    return TCL_OK;
5345	}
5346
5347	if (index == OPT_NORMAL) {
5348	    wmPtr->flags &= ~WM_WITHDRAWN;
5349	    TkpWmSetState(winPtr, NormalState);
5350
5351	    /*
5352	     * This varies from 'wm deiconify' because it does not force the
5353	     * window to be raised and receive focus.
5354	     */
5355	} else if (index == OPT_ICONIC) {
5356	    if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
5357		Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
5358			"\": override-redirect flag is set", NULL);
5359		return TCL_ERROR;
5360	    }
5361	    if (wmPtr->masterPtr != NULL) {
5362		Tcl_AppendResult(interp, "can't iconify \"",
5363			winPtr->pathName, "\": it is a transient", NULL);
5364		return TCL_ERROR;
5365	    }
5366	    TkpWmSetState(winPtr, IconicState);
5367	} else if (index == OPT_WITHDRAWN) {
5368	    wmPtr->flags |= WM_WITHDRAWN;
5369	    TkpWmSetState(winPtr, WithdrawnState);
5370	} else if (index == OPT_ZOOMED) {
5371	    TkpWmSetState(winPtr, ZoomState);
5372	} else {
5373	    Tcl_Panic("wm state not matched");
5374	}
5375    } else {
5376	if (wmPtr->iconFor != NULL) {
5377	    Tcl_SetResult(interp, "icon", TCL_STATIC);
5378	} else {
5379	    int state;
5380
5381	    if (winPtr->flags & TK_EMBEDDED) {
5382		state = SendMessage(wmPtr->wrapper, TK_STATE, -1, -1)-1;
5383	    } else {
5384		state = wmPtr->hints.initial_state;
5385	    }
5386	    switch (state) {
5387	    case NormalState:
5388		Tcl_SetResult(interp, "normal", TCL_STATIC);
5389		break;
5390	    case IconicState:
5391		Tcl_SetResult(interp, "iconic", TCL_STATIC);
5392		break;
5393	    case WithdrawnState:
5394		Tcl_SetResult(interp, "withdrawn", TCL_STATIC);
5395		break;
5396	    case ZoomState:
5397		Tcl_SetResult(interp, "zoomed", TCL_STATIC);
5398		break;
5399	    }
5400	}
5401    }
5402    return TCL_OK;
5403}
5404
5405/*
5406 *----------------------------------------------------------------------
5407 *
5408 * WmTitleCmd --
5409 *
5410 *	This function is invoked to process the "wm title" Tcl command. See
5411 *	the user documentation for details on what it does.
5412 *
5413 * Results:
5414 *	A standard Tcl result.
5415 *
5416 * Side effects:
5417 *	See the user documentation.
5418 *
5419 *----------------------------------------------------------------------
5420 */
5421
5422static int
5423WmTitleCmd(
5424    Tk_Window tkwin,		/* Main window of the application. */
5425    TkWindow *winPtr,		/* Toplevel to work with */
5426    Tcl_Interp *interp,		/* Current interpreter. */
5427    int objc,			/* Number of arguments. */
5428    Tcl_Obj *CONST objv[])	/* Argument objects. */
5429{
5430    register WmInfo *wmPtr = winPtr->wmInfoPtr;
5431    char *argv3;
5432    int length;
5433    HWND wrapper;
5434
5435    if (objc > 4) {
5436	Tcl_WrongNumArgs(interp, 2, objv, "window ?newTitle?");
5437	return TCL_ERROR;
5438    }
5439
5440    if(winPtr->flags & TK_EMBEDDED) {
5441	wrapper = (HWND)SendMessage(wmPtr->wrapper, TK_GETFRAMEWID, 0, 0);
5442    } else {
5443	wrapper = wmPtr->wrapper;
5444    }
5445    if (objc == 3) {
5446	if (wrapper) {
5447	    char buf[512];
5448	    Tcl_DString titleString;
5449	    int size = tkWinProcs->useWide ? 256 : 512;
5450
5451	    (*tkWinProcs->getWindowText)(wrapper, (LPCTSTR)buf, size);
5452	    Tcl_WinTCharToUtf(buf, -1, &titleString);
5453	    Tcl_SetResult(interp, Tcl_DStringValue(&titleString),TCL_VOLATILE);
5454	    Tcl_DStringFree(&titleString);
5455	} else {
5456	    Tcl_SetResult(interp, (char *)
5457		    ((wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid),
5458		    TCL_STATIC);
5459	}
5460    } else {
5461	if (wmPtr->title != NULL) {
5462	    ckfree((char *) wmPtr->title);
5463	}
5464	argv3 = Tcl_GetStringFromObj(objv[3], &length);
5465	wmPtr->title = ckalloc((unsigned) (length + 1));
5466	strcpy(wmPtr->title, argv3);
5467
5468	if (!(wmPtr->flags & WM_NEVER_MAPPED) && wmPtr->wrapper != NULL) {
5469	    Tcl_DString titleString;
5470	    Tcl_WinUtfToTChar(wmPtr->title, -1, &titleString);
5471	    (*tkWinProcs->setWindowText)(wrapper,
5472		    (LPCTSTR) Tcl_DStringValue(&titleString));
5473	    Tcl_DStringFree(&titleString);
5474	}
5475    }
5476    return TCL_OK;
5477}
5478
5479/*
5480 *----------------------------------------------------------------------
5481 *
5482 * WmTransientCmd --
5483 *
5484 *	This function is invoked to process the "wm transient" Tcl command.
5485 *	See the user documentation for details on what it does.
5486 *
5487 * Results:
5488 *	A standard Tcl result.
5489 *
5490 * Side effects:
5491 *	See the user documentation.
5492 *
5493 *----------------------------------------------------------------------
5494 */
5495
5496static int
5497WmTransientCmd(
5498    Tk_Window tkwin,		/* Main window of the application. */
5499    TkWindow *winPtr,		/* Toplevel to work with */
5500    Tcl_Interp *interp,		/* Current interpreter. */
5501    int objc,			/* Number of arguments. */
5502    Tcl_Obj *CONST objv[])	/* Argument objects. */
5503{
5504    register WmInfo *wmPtr = winPtr->wmInfoPtr;
5505    TkWindow *masterPtr = wmPtr->masterPtr, **masterPtrPtr = &masterPtr;
5506    WmInfo *wmPtr2;
5507
5508    if ((objc != 3) && (objc != 4)) {
5509	Tcl_WrongNumArgs(interp, 2, objv, "window ?master?");
5510	return TCL_ERROR;
5511    }
5512    if (objc == 3) {
5513	if (masterPtr != NULL) {
5514	    Tcl_SetResult(interp, Tk_PathName(masterPtr), TCL_STATIC);
5515	}
5516	return TCL_OK;
5517    }
5518    if (Tcl_GetString(objv[3])[0] == '\0') {
5519	if (masterPtr != NULL) {
5520	    /*
5521	     * If we had a master, tell them that we aren't tied to them
5522	     * anymore.
5523	     */
5524
5525	    masterPtr->wmInfoPtr->numTransients--;
5526	    Tk_DeleteEventHandler((Tk_Window) masterPtr,
5527		    VisibilityChangeMask|StructureNotifyMask,
5528		    WmWaitVisibilityOrMapProc, (ClientData) winPtr);
5529	}
5530
5531	wmPtr->masterPtr = NULL;
5532    } else {
5533	if (TkGetWindowFromObj(interp, tkwin, objv[3],
5534		(Tk_Window *) masterPtrPtr) != TCL_OK) {
5535	    return TCL_ERROR;
5536	}
5537	while (!Tk_TopWinHierarchy(masterPtr)) {
5538	    /*
5539	     * Ensure that the master window is actually a Tk toplevel.
5540	     */
5541
5542	    masterPtr = masterPtr->parentPtr;
5543	}
5544	Tk_MakeWindowExist((Tk_Window) masterPtr);
5545
5546	if (wmPtr->iconFor != NULL) {
5547	    Tcl_AppendResult(interp, "can't make \"", Tcl_GetString(objv[2]),
5548		    "\" a transient: it is an icon for ",
5549		    Tk_PathName(wmPtr->iconFor), NULL);
5550	    return TCL_ERROR;
5551	}
5552
5553	wmPtr2 = masterPtr->wmInfoPtr;
5554
5555	if (wmPtr2->iconFor != NULL) {
5556	    Tcl_AppendResult(interp, "can't make \"", Tcl_GetString(objv[3]),
5557		    "\" a master: it is an icon for ",
5558		    Tk_PathName(wmPtr2->iconFor), NULL);
5559	    return TCL_ERROR;
5560	}
5561
5562	if (masterPtr == winPtr) {
5563	    Tcl_AppendResult(interp, "can't make \"", Tk_PathName(winPtr),
5564		    "\" its own master", NULL);
5565	    return TCL_ERROR;
5566	} else if (masterPtr != wmPtr->masterPtr) {
5567	    /*
5568	     * Remove old master map/unmap binding before setting the new
5569	     * master. The event handler will ensure that transient states
5570	     * reflect the state of the master.
5571	     */
5572
5573	    if (wmPtr->masterPtr != NULL) {
5574		wmPtr->masterPtr->wmInfoPtr->numTransients--;
5575		Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
5576			VisibilityChangeMask|StructureNotifyMask,
5577			WmWaitVisibilityOrMapProc, (ClientData) winPtr);
5578	    }
5579
5580	    masterPtr->wmInfoPtr->numTransients++;
5581	    Tk_CreateEventHandler((Tk_Window) masterPtr,
5582		    VisibilityChangeMask|StructureNotifyMask,
5583		    WmWaitVisibilityOrMapProc, (ClientData) winPtr);
5584
5585	    wmPtr->masterPtr = masterPtr;
5586	}
5587    }
5588    if (!((wmPtr->flags & WM_NEVER_MAPPED)
5589	    && !(winPtr->flags & TK_EMBEDDED))) {
5590	if (wmPtr->masterPtr != NULL &&
5591		!Tk_IsMapped(wmPtr->masterPtr)) {
5592	    TkpWmSetState(winPtr, WithdrawnState);
5593	} else {
5594	    UpdateWrapper(winPtr);
5595	}
5596    }
5597    return TCL_OK;
5598}
5599
5600/*
5601 *----------------------------------------------------------------------
5602 *
5603 * WmWithdrawCmd --
5604 *
5605 *	This function is invoked to process the "wm withdraw" Tcl command.
5606 *	See the user documentation for details on what it does.
5607 *
5608 * Results:
5609 *	A standard Tcl result.
5610 *
5611 * Side effects:
5612 *	See the user documentation.
5613 *
5614 *----------------------------------------------------------------------
5615 */
5616
5617static int
5618WmWithdrawCmd(
5619    Tk_Window tkwin,		/* Main window of the application. */
5620    TkWindow *winPtr,		/* Toplevel to work with */
5621    Tcl_Interp *interp,		/* Current interpreter. */
5622    int objc,			/* Number of arguments. */
5623    Tcl_Obj *CONST objv[])	/* Argument objects. */
5624{
5625    register WmInfo *wmPtr = winPtr->wmInfoPtr;
5626
5627    if (objc != 3) {
5628	Tcl_WrongNumArgs(interp, 2, objv, "window");
5629	return TCL_ERROR;
5630    }
5631    if (wmPtr->iconFor != NULL) {
5632	Tcl_AppendResult(interp, "can't withdraw ", Tcl_GetString(objv[2]),
5633		": it is an icon for ", Tk_PathName(wmPtr->iconFor), NULL);
5634	return TCL_ERROR;
5635    }
5636
5637    if (winPtr->flags & TK_EMBEDDED) {
5638	if (SendMessage(wmPtr->wrapper, TK_WITHDRAW, 0, 0) < 0) {
5639	    Tcl_AppendResult(interp, "can't withdraw", Tcl_GetString(objv[2]),
5640		    ": the container does not support the request", NULL);
5641	    return TCL_ERROR;
5642	}
5643    } else {
5644	wmPtr->flags |= WM_WITHDRAWN;
5645	TkpWmSetState(winPtr, WithdrawnState);
5646    }
5647    return TCL_OK;
5648}
5649
5650/*
5651 * Invoked by those wm subcommands that affect geometry. Schedules a geometry
5652 * update.
5653 */
5654
5655static void
5656WmUpdateGeom(
5657    WmInfo *wmPtr,
5658    TkWindow *winPtr)
5659{
5660    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
5661	Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
5662	wmPtr->flags |= WM_UPDATE_PENDING;
5663    }
5664}
5665
5666	/*ARGSUSED*/
5667static void
5668WmWaitVisibilityOrMapProc(
5669    ClientData clientData,	/* Pointer to window. */
5670    XEvent *eventPtr)		/* Information about event. */
5671{
5672    TkWindow *winPtr = (TkWindow *) clientData;
5673    TkWindow *masterPtr = winPtr->wmInfoPtr->masterPtr;
5674
5675    if (masterPtr == NULL)
5676	return;
5677
5678    if (eventPtr->type == MapNotify) {
5679	if (!(winPtr->wmInfoPtr->flags & WM_WITHDRAWN)) {
5680	    TkpWmSetState(winPtr, NormalState);
5681	}
5682    } else if (eventPtr->type == UnmapNotify) {
5683	TkpWmSetState(winPtr, WithdrawnState);
5684    }
5685
5686    if (eventPtr->type == VisibilityNotify) {
5687	int state = masterPtr->wmInfoPtr->hints.initial_state;
5688
5689	if ((state == NormalState) || (state == ZoomState)) {
5690	    state = winPtr->wmInfoPtr->hints.initial_state;
5691	    if ((state == NormalState) || (state == ZoomState)) {
5692		UpdateWrapper(winPtr);
5693	    }
5694	}
5695    }
5696}
5697
5698/*
5699 *----------------------------------------------------------------------
5700 *
5701 * Tk_SetGrid --
5702 *
5703 *	This function is invoked by a widget when it wishes to set a grid
5704 *	coordinate system that controls the size of a top-level window. It
5705 *	provides a C interface equivalent to the "wm grid" command and is
5706 *	usually asscoiated with the -setgrid option.
5707 *
5708 * Results:
5709 *	None.
5710 *
5711 * Side effects:
5712 *	Grid-related information will be passed to the window manager, so that
5713 *	the top-level window associated with tkwin will resize on even grid
5714 *	units. If some other window already controls gridding for the
5715 *	top-level window then this function call has no effect.
5716 *
5717 *----------------------------------------------------------------------
5718 */
5719
5720void
5721Tk_SetGrid(
5722    Tk_Window tkwin,		/* Token for window. New window mgr info will
5723				 * be posted for the top-level window
5724				 * associated with this window. */
5725    int reqWidth,		/* Width (in grid units) corresponding to the
5726				 * requested geometry for tkwin. */
5727    int reqHeight,		/* Height (in grid units) corresponding to the
5728				 * requested geometry for tkwin. */
5729    int widthInc, int heightInc)/* Pixel increments corresponding to a change
5730				 * of one grid unit. */
5731{
5732    TkWindow *winPtr = (TkWindow *) tkwin;
5733    register WmInfo *wmPtr;
5734
5735    /*
5736     * Ensure widthInc and heightInc are greater than 0
5737     */
5738
5739    if (widthInc <= 0) {
5740	widthInc = 1;
5741    }
5742    if (heightInc <= 0) {
5743	heightInc = 1;
5744    }
5745
5746    /*
5747     * Find the top-level window for tkwin, plus the window manager
5748     * information.
5749     */
5750
5751    while (!(winPtr->flags & TK_TOP_HIERARCHY)) {
5752	winPtr = winPtr->parentPtr;
5753    }
5754    wmPtr = winPtr->wmInfoPtr;
5755    if (wmPtr == NULL) {
5756	return;
5757    }
5758
5759    if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
5760	return;
5761    }
5762
5763    if ((wmPtr->reqGridWidth == reqWidth)
5764	    && (wmPtr->reqGridHeight == reqHeight)
5765	    && (wmPtr->widthInc == widthInc)
5766	    && (wmPtr->heightInc == heightInc)
5767	    && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
5768		    == (PBaseSize|PResizeInc))) {
5769	return;
5770    }
5771
5772    /*
5773     * If gridding was previously off, then forget about any window size
5774     * requests made by the user or via "wm geometry": these are in pixel
5775     * units and there's no easy way to translate them to grid units since the
5776     * new requested size of the top-level window in pixels may not yet have
5777     * been registered yet (it may filter up the hierarchy in DoWhenIdle
5778     * handlers). However, if the window has never been mapped yet then just
5779     * leave the window size alone: assume that it is intended to be in grid
5780     * units but just happened to have been specified before this function was
5781     * called.
5782     */
5783
5784    if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
5785	wmPtr->width = -1;
5786	wmPtr->height = -1;
5787    }
5788
5789    /*
5790     * Set the new gridding information, and start the process of passing all
5791     * of this information to the window manager.
5792     */
5793
5794    wmPtr->gridWin = tkwin;
5795    wmPtr->reqGridWidth = reqWidth;
5796    wmPtr->reqGridHeight = reqHeight;
5797    wmPtr->widthInc = widthInc;
5798    wmPtr->heightInc = heightInc;
5799    wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
5800    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
5801	Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
5802	wmPtr->flags |= WM_UPDATE_PENDING;
5803    }
5804}
5805
5806/*
5807 *----------------------------------------------------------------------
5808 *
5809 * Tk_UnsetGrid --
5810 *
5811 *	This function cancels the effect of a previous call to Tk_SetGrid.
5812 *
5813 * Results:
5814 *	None.
5815 *
5816 * Side effects:
5817 *	If tkwin currently controls gridding for its top-level window,
5818 *	gridding is cancelled for that top-level window; if some other window
5819 *	controls gridding then this function has no effect.
5820 *
5821 *----------------------------------------------------------------------
5822 */
5823
5824void
5825Tk_UnsetGrid(
5826    Tk_Window tkwin)		/* Token for window that is currently
5827				 * controlling gridding. */
5828{
5829    TkWindow *winPtr = (TkWindow *) tkwin;
5830    register WmInfo *wmPtr;
5831
5832    /*
5833     * Find the top-level window for tkwin, plus the window manager
5834     * information.
5835     */
5836
5837    while (!(winPtr->flags & TK_TOP_HIERARCHY)) {
5838	winPtr = winPtr->parentPtr;
5839    }
5840    wmPtr = winPtr->wmInfoPtr;
5841    if (wmPtr == NULL) {
5842	return;
5843    }
5844
5845    if (tkwin != wmPtr->gridWin) {
5846	return;
5847    }
5848
5849    wmPtr->gridWin = NULL;
5850    wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
5851    if (wmPtr->width != -1) {
5852	wmPtr->width = winPtr->reqWidth + (wmPtr->width
5853		- wmPtr->reqGridWidth)*wmPtr->widthInc;
5854	wmPtr->height = winPtr->reqHeight + (wmPtr->height
5855		- wmPtr->reqGridHeight)*wmPtr->heightInc;
5856    }
5857    wmPtr->widthInc = 1;
5858    wmPtr->heightInc = 1;
5859
5860    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
5861	Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
5862	wmPtr->flags |= WM_UPDATE_PENDING;
5863    }
5864}
5865
5866/*
5867 *----------------------------------------------------------------------
5868 *
5869 * TopLevelEventProc --
5870 *
5871 *	This function is invoked when a top-level (or other externally-managed
5872 *	window) is restructured in any way.
5873 *
5874 * Results:
5875 *	None.
5876 *
5877 * Side effects:
5878 *	Tk's internal data structures for the window get modified to reflect
5879 *	the structural change.
5880 *
5881 *----------------------------------------------------------------------
5882 */
5883
5884static void
5885TopLevelEventProc(
5886    ClientData clientData,	/* Window for which event occurred. */
5887    XEvent *eventPtr)		/* Event that just happened. */
5888{
5889    register TkWindow *winPtr = (TkWindow *) clientData;
5890
5891    if (eventPtr->type == DestroyNotify) {
5892	Tk_ErrorHandler handler;
5893
5894	if (!(winPtr->flags & TK_ALREADY_DEAD)) {
5895	    /*
5896	     * A top-level window was deleted externally (e.g., by the window
5897	     * manager). This is probably not a good thing, but cleanup as
5898	     * best we can. The error handler is needed because
5899	     * Tk_DestroyWindow will try to destroy the window, but of course
5900	     * it's already gone.
5901	     */
5902
5903	    handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
5904		    (Tk_ErrorProc *) NULL, (ClientData) NULL);
5905	    Tk_DestroyWindow((Tk_Window) winPtr);
5906	    Tk_DeleteErrorHandler(handler);
5907	}
5908    }
5909}
5910
5911/*
5912 *----------------------------------------------------------------------
5913 *
5914 * TopLevelReqProc --
5915 *
5916 *	This function is invoked by the geometry manager whenever the
5917 *	requested size for a top-level window is changed.
5918 *
5919 * Results:
5920 *	None.
5921 *
5922 * Side effects:
5923 *	Arrange for the window to be resized to satisfy the request (this
5924 *	happens as a when-idle action).
5925 *
5926 *----------------------------------------------------------------------
5927 */
5928
5929	/* ARGSUSED */
5930static void
5931TopLevelReqProc(
5932    ClientData dummy,		/* Not used. */
5933    Tk_Window tkwin)		/* Information about window. */
5934{
5935    TkWindow *winPtr = (TkWindow *) tkwin;
5936    WmInfo *wmPtr;
5937
5938    wmPtr = winPtr->wmInfoPtr;
5939    if (wmPtr) {
5940	if ((winPtr->flags & TK_EMBEDDED) && (wmPtr->wrapper != NULL)) {
5941	    SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ, Tk_ReqWidth(tkwin),
5942		Tk_ReqHeight(tkwin));
5943	}
5944	if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
5945	    Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
5946	    wmPtr->flags |= WM_UPDATE_PENDING;
5947	}
5948    }
5949}
5950
5951/*
5952 *----------------------------------------------------------------------
5953 *
5954 * UpdateGeometryInfo --
5955 *
5956 *	This function is invoked when a top-level window is first mapped, and
5957 *	also as a when-idle function, to bring the geometry and/or position of
5958 *	a top-level window back into line with what has been requested by the
5959 *	user and/or widgets. This function doesn't return until the system has
5960 *	responded to the geometry change.
5961 *
5962 * Results:
5963 *	None.
5964 *
5965 * Side effects:
5966 *	The window's size and location may change, unless the WM prevents that
5967 *	from happening.
5968 *
5969 *----------------------------------------------------------------------
5970 */
5971
5972static void
5973UpdateGeometryInfo(
5974    ClientData clientData)	/* Pointer to the window's record. */
5975{
5976    int x, y;			/* Position of border on desktop. */
5977    int width, height;		/* Size of client area. */
5978    int min, max;
5979    RECT rect;
5980    register TkWindow *winPtr = (TkWindow *) clientData;
5981    register WmInfo *wmPtr = winPtr->wmInfoPtr;
5982
5983    wmPtr->flags &= ~WM_UPDATE_PENDING;
5984
5985    /*
5986     * If the window is minimized or maximized, we should not update our
5987     * geometry since it will end up with the wrong values. ConfigureToplevel
5988     * will reschedule UpdateGeometryInfo when the state of the window
5989     * changes.
5990     */
5991
5992    if (wmPtr->wrapper && (IsIconic(wmPtr->wrapper) ||
5993	    IsZoomed(wmPtr->wrapper) || (wmPtr->flags & WM_FULLSCREEN))) {
5994	return;
5995    }
5996
5997    /*
5998     * Compute the border size for the current window style. This size will
5999     * include the resize handles, the title bar and the menubar. Note that
6000     * this size will not be correct if the menubar spans multiple lines. The
6001     * height will be off by a multiple of the menubar height. It really only
6002     * measures the minimum size of the border.
6003     */
6004
6005    rect.left = rect.right = rect.top = rect.bottom = 0;
6006    AdjustWindowRectEx(&rect, wmPtr->style, wmPtr->hMenu != NULL,
6007	    wmPtr->exStyle);
6008    wmPtr->borderWidth = rect.right - rect.left;
6009    wmPtr->borderHeight = rect.bottom - rect.top;
6010
6011    /*
6012     * Compute the new size for the top-level window. See the user
6013     * documentation for details on this, but the size requested depends on
6014     * (a) the size requested internally by the window's widgets, (b) the size
6015     * requested by the user in a "wm geometry" command or via wm-based
6016     * interactive resizing (if any), (c) whether or not the window is
6017     * gridded, and (d) the current min or max size for the toplevel. Don't
6018     * permit sizes <= 0 because this upsets the X server.
6019     */
6020
6021    if (wmPtr->width == -1) {
6022	width = winPtr->reqWidth;
6023    } else if (wmPtr->gridWin != NULL) {
6024	width = winPtr->reqWidth
6025		+ (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
6026    } else {
6027	width = wmPtr->width;
6028    }
6029    if (width <= 0) {
6030	width = 1;
6031    }
6032
6033    /*
6034     * Account for window max/min width
6035     */
6036
6037    if (wmPtr->gridWin != NULL) {
6038	min = winPtr->reqWidth
6039		+ (wmPtr->minWidth - wmPtr->reqGridWidth)*wmPtr->widthInc;
6040	if (wmPtr->maxWidth > 0) {
6041	    max = winPtr->reqWidth
6042		    + (wmPtr->maxWidth - wmPtr->reqGridWidth)*wmPtr->widthInc;
6043	} else {
6044	    max = 0;
6045	}
6046    } else {
6047	min = wmPtr->minWidth;
6048	max = wmPtr->maxWidth;
6049    }
6050    if (width < min) {
6051	width = min;
6052    } else if ((max > 0) && (width > max)) {
6053	width = max;
6054    }
6055
6056    if (wmPtr->height == -1) {
6057	height = winPtr->reqHeight;
6058    } else if (wmPtr->gridWin != NULL) {
6059	height = winPtr->reqHeight
6060		+ (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
6061    } else {
6062	height = wmPtr->height;
6063    }
6064    if (height <= 0) {
6065	height = 1;
6066    }
6067
6068    /*
6069     * Account for window max/min height
6070     */
6071
6072    if (wmPtr->gridWin != NULL) {
6073	min = winPtr->reqHeight
6074		+ (wmPtr->minHeight - wmPtr->reqGridHeight)*wmPtr->heightInc;
6075	if (wmPtr->maxHeight > 0) {
6076	    max = winPtr->reqHeight
6077		    + (wmPtr->maxHeight-wmPtr->reqGridHeight)*wmPtr->heightInc;
6078	} else {
6079	    max = 0;
6080	}
6081    } else {
6082	min = wmPtr->minHeight;
6083	max = wmPtr->maxHeight;
6084    }
6085    if (height < min) {
6086	height = min;
6087    } else if ((max > 0) && (height > max)) {
6088	height = max;
6089    }
6090
6091    /*
6092     * Compute the new position for the upper-left pixel of the window's
6093     * decorative frame. This is tricky, because we need to include the border
6094     * widths supplied by a reparented parent in this calculation, but can't
6095     * use the parent's current overall size since that may change as a result
6096     * of this code.
6097     */
6098
6099    if (wmPtr->flags & WM_NEGATIVE_X) {
6100	x = DisplayWidth(winPtr->display, winPtr->screenNum) - wmPtr->x
6101		- (width + wmPtr->borderWidth);
6102    } else {
6103	x = wmPtr->x;
6104    }
6105    if (wmPtr->flags & WM_NEGATIVE_Y) {
6106	y = DisplayHeight(winPtr->display, winPtr->screenNum) - wmPtr->y
6107		- (height + wmPtr->borderHeight);
6108    } else {
6109	y = wmPtr->y;
6110    }
6111
6112    /*
6113     * Reconfigure the window if it isn't already configured correctly. Base
6114     * the size check on what we *asked for* last time, not what we got.
6115     * Return immediately if there have been no changes in the requested
6116     * geometry of the toplevel.
6117     */
6118
6119    /* TODO: need to add flag for possible menu size change */
6120
6121    if (!(wmPtr->flags & WM_MOVE_PENDING)
6122	    && (width == wmPtr->configWidth)
6123	    && (height == wmPtr->configHeight)) {
6124	return;
6125    }
6126    wmPtr->flags &= ~WM_MOVE_PENDING;
6127
6128    wmPtr->configWidth = width;
6129    wmPtr->configHeight = height;
6130
6131    /*
6132     * Don't bother moving the window if we are in the process of creating it.
6133     * Just update the geometry info based on what we asked for.
6134     */
6135
6136    if (wmPtr->flags & WM_CREATE_PENDING) {
6137	winPtr->changes.x = x;
6138	winPtr->changes.y = y;
6139	winPtr->changes.width = width;
6140	winPtr->changes.height = height;
6141	return;
6142    }
6143
6144    wmPtr->flags |= WM_SYNC_PENDING;
6145    if (winPtr->flags & TK_EMBEDDED) {
6146	/*
6147	 * The wrapper window is in a different process, so we need to send it
6148	 * a geometry request. This protocol assumes that the other process
6149	 * understands this Tk message, otherwise our requested geometry will
6150	 * be ignored.
6151	 */
6152
6153	SendMessage(wmPtr->wrapper, TK_MOVEWINDOW, x, y);
6154	SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ, width, height);
6155    } else {
6156	int reqHeight, reqWidth;
6157	RECT windowRect;
6158	int menuInc = GetSystemMetrics(SM_CYMENU);
6159	int newHeight;
6160
6161	/*
6162	 * We have to keep resizing the window until we get the requested
6163	 * height in the client area. If the client area has zero height, then
6164	 * the window rect is too small by definition. Try increasing the
6165	 * border height and try again. Once we have a positive size, then we
6166	 * can adjust the height exactly. If the window rect comes back
6167	 * smaller than we requested, we have hit the maximum constraints that
6168	 * Windows imposes. Once we find a positive client size, the next size
6169	 * is the one we try no matter what.
6170	 */
6171
6172	reqHeight = height + wmPtr->borderHeight;
6173	reqWidth = width + wmPtr->borderWidth;
6174
6175	while (1) {
6176	    MoveWindow(wmPtr->wrapper, x, y, reqWidth, reqHeight, TRUE);
6177	    GetWindowRect(wmPtr->wrapper, &windowRect);
6178	    newHeight = windowRect.bottom - windowRect.top;
6179
6180	    /*
6181	     * If the request wasn't satisfied, we have hit an external
6182	     * constraint and must stop.
6183	     */
6184
6185	    if (newHeight < reqHeight) {
6186		break;
6187	    }
6188
6189	    /*
6190	     * Now check the size of the client area against our ideal.
6191	     */
6192
6193	    GetClientRect(wmPtr->wrapper, &windowRect);
6194	    newHeight = windowRect.bottom - windowRect.top;
6195
6196	    if (newHeight == height) {
6197		/*
6198		 * We're done.
6199		 */
6200
6201		break;
6202	    } else if (newHeight > height) {
6203		/*
6204		 * One last resize to get rid of the extra space.
6205		 */
6206
6207		menuInc = newHeight - height;
6208		reqHeight -= menuInc;
6209		if (wmPtr->flags & WM_NEGATIVE_Y) {
6210		    y += menuInc;
6211		}
6212		MoveWindow(wmPtr->wrapper, x, y, reqWidth, reqHeight, TRUE);
6213		break;
6214	    }
6215
6216	    /*
6217	     * We didn't get enough space to satisfy our requested height, so
6218	     * the menu must have wrapped. Increase the size of the window by
6219	     * one menu height and move the window if it is positioned
6220	     * relative to the lower right corner of the screen.
6221	     */
6222
6223	    reqHeight += menuInc;
6224	    if (wmPtr->flags & WM_NEGATIVE_Y) {
6225		y -= menuInc;
6226	    }
6227	}
6228	if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
6229	    DrawMenuBar(wmPtr->wrapper);
6230	}
6231    }
6232    wmPtr->flags &= ~WM_SYNC_PENDING;
6233}
6234
6235/*
6236 *--------------------------------------------------------------
6237 *
6238 * ParseGeometry --
6239 *
6240 *	This function parses a geometry string and updates information used to
6241 *	control the geometry of a top-level window.
6242 *
6243 * Results:
6244 *	A standard Tcl return value, plus an error message in the interp's
6245 *	result if an error occurs.
6246 *
6247 * Side effects:
6248 *	The size and/or location of winPtr may change.
6249 *
6250 *--------------------------------------------------------------
6251 */
6252
6253static int
6254ParseGeometry(
6255    Tcl_Interp *interp,		/* Used for error reporting. */
6256    char *string,		/* String containing new geometry. Has the
6257				 * standard form "=wxh+x+y". */
6258    TkWindow *winPtr)		/* Pointer to top-level window whose geometry
6259				 * is to be changed. */
6260{
6261    register WmInfo *wmPtr = winPtr->wmInfoPtr;
6262    int x, y, width, height, flags;
6263    char *end;
6264    register char *p = string;
6265
6266    /*
6267     * The leading "=" is optional.
6268     */
6269
6270    if (*p == '=') {
6271	p++;
6272    }
6273
6274    /*
6275     * Parse the width and height, if they are present. Don't actually update
6276     * any of the fields of wmPtr until we've successfully parsed the entire
6277     * geometry string.
6278     */
6279
6280    width = wmPtr->width;
6281    height = wmPtr->height;
6282    x = wmPtr->x;
6283    y = wmPtr->y;
6284    flags = wmPtr->flags;
6285    if (isdigit(UCHAR(*p))) {
6286	width = strtoul(p, &end, 10);
6287	p = end;
6288	if (*p != 'x') {
6289	    goto error;
6290	}
6291	p++;
6292	if (!isdigit(UCHAR(*p))) {
6293	    goto error;
6294	}
6295	height = strtoul(p, &end, 10);
6296	p = end;
6297    }
6298
6299    /*
6300     * Parse the X and Y coordinates, if they are present.
6301     */
6302
6303    if (*p != '\0') {
6304	flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
6305	if (*p == '-') {
6306	    flags |= WM_NEGATIVE_X;
6307	} else if (*p != '+') {
6308	    goto error;
6309	}
6310	p++;
6311	if (!isdigit(UCHAR(*p)) && (*p != '-')) {
6312	    goto error;
6313	}
6314	x = strtol(p, &end, 10);
6315	p = end;
6316	if (*p == '-') {
6317	    flags |= WM_NEGATIVE_Y;
6318	} else if (*p != '+') {
6319	    goto error;
6320	}
6321	p++;
6322	if (!isdigit(UCHAR(*p)) && (*p != '-')) {
6323	    goto error;
6324	}
6325	y = strtol(p, &end, 10);
6326	if (*end != '\0') {
6327	    goto error;
6328	}
6329
6330	/*
6331	 * Assume that the geometry information came from the user, unless an
6332	 * explicit source has been specified. Otherwise most window managers
6333	 * assume that the size hints were program-specified and they ignore
6334	 * them.
6335	 */
6336
6337	if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
6338	    wmPtr->sizeHintsFlags |= USPosition;
6339	}
6340    }
6341
6342    /*
6343     * Everything was parsed OK. Update the fields of *wmPtr and arrange for
6344     * the appropriate information to be percolated out to the window manager
6345     * at the next idle moment.
6346     */
6347
6348    wmPtr->width = width;
6349    wmPtr->height = height;
6350    wmPtr->x = x;
6351    wmPtr->y = y;
6352    flags |= WM_MOVE_PENDING;
6353    wmPtr->flags = flags;
6354
6355    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
6356	Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
6357	wmPtr->flags |= WM_UPDATE_PENDING;
6358    }
6359    return TCL_OK;
6360
6361  error:
6362    Tcl_AppendResult(interp, "bad geometry specifier \"", string, "\"", NULL);
6363    return TCL_ERROR;
6364}
6365
6366/*
6367 *----------------------------------------------------------------------
6368 *
6369 * Tk_GetRootCoords --
6370 *
6371 *	Given a token for a window, this function traces through the window's
6372 *	lineage to find the (virtual) root-window coordinates corresponding to
6373 *	point (0,0) in the window.
6374 *
6375 * Results:
6376 *	The locations pointed to by xPtr and yPtr are filled in with the root
6377 *	coordinates of the (0,0) point in tkwin.
6378 *
6379 * Side effects:
6380 *	None.
6381 *
6382 *----------------------------------------------------------------------
6383 */
6384
6385void
6386Tk_GetRootCoords(
6387    Tk_Window tkwin,		/* Token for window. */
6388    int *xPtr,			/* Where to store x-displacement of (0,0). */
6389    int *yPtr)			/* Where to store y-displacement of (0,0). */
6390{
6391    register TkWindow *winPtr = (TkWindow *) tkwin;
6392
6393    /*
6394     * If the window is mapped, let Windows figure out the translation.
6395     */
6396
6397    if (winPtr->window != None) {
6398	HWND hwnd = Tk_GetHWND(winPtr->window);
6399	POINT point;
6400
6401	point.x = 0;
6402	point.y = 0;
6403
6404	ClientToScreen(hwnd, &point);
6405
6406	*xPtr = point.x;
6407	*yPtr = point.y;
6408    } else {
6409	*xPtr = 0;
6410	*yPtr = 0;
6411    }
6412}
6413
6414/*
6415 *----------------------------------------------------------------------
6416 *
6417 * Tk_CoordsToWindow --
6418 *
6419 *	Given the (virtual) root coordinates of a point, this function returns
6420 *	the token for the top-most window covering that point, if there exists
6421 *	such a window in this application.
6422 *
6423 * Results:
6424 *	The return result is either a token for the window corresponding to
6425 *	rootX and rootY, or else NULL to indicate that there is no such
6426 *	window.
6427 *
6428 * Side effects:
6429 *	None.
6430 *
6431 *----------------------------------------------------------------------
6432 */
6433
6434Tk_Window
6435Tk_CoordsToWindow(
6436    int rootX, int rootY,	/* Coordinates of point in root window. If a
6437				 * virtual-root window manager is in use,
6438				 * these coordinates refer to the virtual
6439				 * root, not the real root. */
6440    Tk_Window tkwin)		/* Token for any window in application; used
6441				 * to identify the display. */
6442{
6443    POINT pos;
6444    HWND hwnd;
6445    TkWindow *winPtr;
6446
6447    pos.x = rootX;
6448    pos.y = rootY;
6449    hwnd = WindowFromPoint(pos);
6450
6451    winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd);
6452    if (winPtr && (winPtr->mainPtr == ((TkWindow *) tkwin)->mainPtr)) {
6453	return (Tk_Window) winPtr;
6454    }
6455    return NULL;
6456}
6457
6458/*
6459 *----------------------------------------------------------------------
6460 *
6461 * Tk_GetVRootGeometry --
6462 *
6463 *	This function returns information about the virtual root window
6464 *	corresponding to a particular Tk window.
6465 *
6466 * Results:
6467 *	The values at xPtr, yPtr, widthPtr, and heightPtr are set with the
6468 *	offset and dimensions of the root window corresponding to tkwin. If
6469 *	tkwin is being managed by a virtual root window manager these values
6470 *	correspond to the virtual root window being used for tkwin; otherwise
6471 *	the offsets will be 0 and the dimensions will be those of the screen.
6472 *
6473 * Side effects:
6474 *	Vroot window information is refreshed if it is out of date.
6475 *
6476 *----------------------------------------------------------------------
6477 */
6478
6479void
6480Tk_GetVRootGeometry(
6481    Tk_Window tkwin,		/* Window whose virtual root is to be
6482				 * queried. */
6483    int *xPtr, int *yPtr,	/* Store x and y offsets of virtual root
6484				 * here. */
6485    int *widthPtr, int *heightPtr)
6486				/* Store dimensions of virtual root here. */
6487{
6488    TkWindow *winPtr = (TkWindow *) tkwin;
6489
6490    /*
6491     * XXX: This is not correct for multiple monitors. There may be many
6492     * changes required to get this right, and it may effect existing
6493     * applications that don't consider possible <0 vroot. See
6494     * http://msdn.microsoft.com/library/en-us/gdi/monitor_3lrn.asp for more
6495     * info.
6496     */
6497
6498    *xPtr = 0;
6499    *yPtr = 0;
6500    *widthPtr = DisplayWidth(winPtr->display, winPtr->screenNum);
6501    *heightPtr = DisplayHeight(winPtr->display, winPtr->screenNum);
6502}
6503
6504/*
6505 *----------------------------------------------------------------------
6506 *
6507 * Tk_MoveToplevelWindow --
6508 *
6509 *	This function is called instead of Tk_MoveWindow to adjust the x-y
6510 *	location of a top-level window. It delays the actual move to a later
6511 *	time and keeps window-manager information up-to-date with the move
6512 *
6513 * Results:
6514 *	None.
6515 *
6516 * Side effects:
6517 *	The window is eventually moved so that its upper-left corner
6518 *	(actually, the upper-left corner of the window's decorative frame, if
6519 *	there is one) is at (x,y).
6520 *
6521 *----------------------------------------------------------------------
6522 */
6523
6524void
6525Tk_MoveToplevelWindow(
6526    Tk_Window tkwin,		/* Window to move. */
6527    int x, int y)		/* New location for window (within parent). */
6528{
6529    TkWindow *winPtr = (TkWindow *) tkwin;
6530    register WmInfo *wmPtr = winPtr->wmInfoPtr;
6531
6532    if (!(winPtr->flags & TK_TOP_LEVEL)) {
6533	Tcl_Panic("Tk_MoveToplevelWindow called with non-toplevel window");
6534    }
6535    wmPtr->x = x;
6536    wmPtr->y = y;
6537    wmPtr->flags |= WM_MOVE_PENDING;
6538    wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
6539    if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
6540	wmPtr->sizeHintsFlags |= USPosition;
6541    }
6542
6543    /*
6544     * If the window has already been mapped, must bring its geometry
6545     * up-to-date immediately, otherwise an event might arrive from the server
6546     * that would overwrite wmPtr->x and wmPtr->y and lose the new position.
6547     */
6548
6549    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
6550	if (wmPtr->flags & WM_UPDATE_PENDING) {
6551	    Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
6552	}
6553	UpdateGeometryInfo((ClientData) winPtr);
6554    }
6555}
6556
6557/*
6558 *----------------------------------------------------------------------
6559 *
6560 * TkWmProtocolEventProc --
6561 *
6562 *	This function is called by the Tk_HandleEvent whenever a ClientMessage
6563 *	event arrives whose type is "WM_PROTOCOLS". This function handles the
6564 *	message from the window manager in an appropriate fashion.
6565 *
6566 * Results:
6567 *	None.
6568 *
6569 * Side effects:
6570 *	Depends on what sort of handler, if any, was set up for the protocol.
6571 *
6572 *----------------------------------------------------------------------
6573 */
6574
6575void
6576TkWmProtocolEventProc(
6577    TkWindow *winPtr,		/* Window to which the event was sent. */
6578    XEvent *eventPtr)		/* X event. */
6579{
6580    WmInfo *wmPtr;
6581    register ProtocolHandler *protPtr;
6582    Atom protocol;
6583    int result;
6584    Tcl_Interp *interp;
6585
6586    wmPtr = winPtr->wmInfoPtr;
6587    if (wmPtr == NULL) {
6588	return;
6589    }
6590    protocol = (Atom) eventPtr->xclient.data.l[0];
6591    for (protPtr = wmPtr->protPtr; protPtr != NULL;
6592	    protPtr = protPtr->nextPtr) {
6593	if (protocol == protPtr->protocol) {
6594	    /*
6595	     * Cache atom name, as we might destroy the window as a result of
6596	     * the eval.
6597	     */
6598
6599	    CONST char *name = Tk_GetAtomName((Tk_Window) winPtr, protocol);
6600
6601	    Tcl_Preserve((ClientData) protPtr);
6602	    interp = protPtr->interp;
6603	    Tcl_Preserve((ClientData) interp);
6604	    result = Tcl_GlobalEval(interp, protPtr->command);
6605	    if (result != TCL_OK) {
6606		Tcl_AddErrorInfo(interp, "\n    (command for \"");
6607		Tcl_AddErrorInfo(interp, name);
6608		Tcl_AddErrorInfo(interp, "\" window manager protocol)");
6609		Tcl_BackgroundError(interp);
6610	    }
6611	    Tcl_Release((ClientData) interp);
6612	    Tcl_Release((ClientData) protPtr);
6613	    return;
6614	}
6615    }
6616
6617    /*
6618     * No handler was present for this protocol. If this is a WM_DELETE_WINDOW
6619     * message then just destroy the window.
6620     */
6621
6622    if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
6623	Tk_DestroyWindow((Tk_Window) winPtr);
6624    }
6625}
6626
6627/*
6628 *----------------------------------------------------------------------
6629 *
6630 * TkWmStackorderToplevelEnumProc --
6631 *
6632 *	This function is invoked once for each HWND Window on the display as a
6633 *	result of calling EnumWindows from TkWmStackorderToplevel.
6634 *
6635 * Results:
6636 *	TRUE to request further iteration.
6637 *
6638 * Side effects:
6639 *	Adds entries to the passed array of TkWindows.
6640 *
6641 *----------------------------------------------------------------------
6642 */
6643
6644BOOL CALLBACK
6645TkWmStackorderToplevelEnumProc(
6646    HWND hwnd,			/* Handle to parent window */
6647    LPARAM lParam)		/* Application-defined value */
6648{
6649    Tcl_HashEntry *hPtr;
6650    TkWindow *childWinPtr;
6651
6652    TkWmStackorderToplevelPair *pair =
6653	    (TkWmStackorderToplevelPair *) lParam;
6654
6655    /*fprintf(stderr, "Looking up HWND %d\n", hwnd);*/
6656
6657    hPtr = Tcl_FindHashEntry(pair->table, (char *) hwnd);
6658    if (hPtr != NULL) {
6659	childWinPtr = (TkWindow *) Tcl_GetHashValue(hPtr);
6660
6661	/*
6662	 * Double check that same HWND does not get passed twice.
6663	 */
6664
6665	if (childWinPtr == NULL) {
6666	    Tcl_Panic("duplicate HWND in TkWmStackorderToplevelEnumProc");
6667	} else {
6668	    Tcl_SetHashValue(hPtr, NULL);
6669	}
6670	/*
6671	fprintf(stderr, "Found mapped HWND %d -> %x (%s)\n", hwnd,
6672		childWinPtr, childWinPtr->pathName);
6673	*/
6674	*(pair->window_ptr)-- = childWinPtr;
6675    }
6676    return TRUE;
6677}
6678
6679/*
6680 *----------------------------------------------------------------------
6681 *
6682 * TkWmStackorderToplevelWrapperMap --
6683 *
6684 *	This function will create a table that maps the wrapper HWND id for a
6685 *	toplevel to the TkWindow structure that is wraps.
6686 *
6687 * Results:
6688 *	None.
6689 *
6690 * Side effects:
6691 *	Adds entries to the passed hashtable.
6692 *
6693 *----------------------------------------------------------------------
6694 */
6695
6696static void
6697TkWmStackorderToplevelWrapperMap(
6698    TkWindow *winPtr,		/* TkWindow to recurse on */
6699    Display *display,		/* X display of parent window */
6700    Tcl_HashTable *table)	/* Table to maps HWND to TkWindow */
6701{
6702    TkWindow *childPtr;
6703    Tcl_HashEntry *hPtr;
6704    HWND wrapper;
6705    int newEntry;
6706
6707    if (Tk_IsMapped(winPtr) && Tk_IsTopLevel(winPtr) &&
6708	    !Tk_IsEmbedded(winPtr) && (winPtr->display == display)) {
6709	wrapper = TkWinGetWrapperWindow((Tk_Window) winPtr);
6710
6711	/*
6712	fprintf(stderr, "Mapped HWND %d to %x (%s)\n", wrapper,
6713		winPtr, winPtr->pathName);
6714	*/
6715
6716	hPtr = Tcl_CreateHashEntry(table, (char *) wrapper, &newEntry);
6717	Tcl_SetHashValue(hPtr, winPtr);
6718    }
6719
6720    for (childPtr = winPtr->childList; childPtr != NULL;
6721	    childPtr = childPtr->nextPtr) {
6722	TkWmStackorderToplevelWrapperMap(childPtr, display, table);
6723    }
6724}
6725/*
6726 *----------------------------------------------------------------------
6727 *
6728 * TkWmStackorderToplevel --
6729 *
6730 *	This function returns the stack order of toplevel windows.
6731 *
6732 * Results:
6733 *	An array of pointers to tk window objects in stacking order or else
6734 *	NULL if there was an error.
6735 *
6736 * Side effects:
6737 *	None.
6738 *
6739 *----------------------------------------------------------------------
6740 */
6741
6742TkWindow **
6743TkWmStackorderToplevel(
6744    TkWindow *parentPtr)	/* Parent toplevel window. */
6745{
6746    TkWmStackorderToplevelPair pair;
6747    TkWindow **windows;
6748    Tcl_HashTable table;
6749    Tcl_HashEntry *hPtr;
6750    Tcl_HashSearch search;
6751
6752    /*
6753     * Map HWND ids to a TkWindow of the wrapped toplevel.
6754     */
6755
6756    Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS);
6757    TkWmStackorderToplevelWrapperMap(parentPtr, parentPtr->display, &table);
6758
6759    windows = (TkWindow **) ckalloc((table.numEntries+1)
6760	* sizeof(TkWindow *));
6761
6762    /*
6763     * Special cases: If zero or one toplevels were mapped there is no need to
6764     * call EnumWindows.
6765     */
6766
6767    switch (table.numEntries) {
6768    case 0:
6769	windows[0] = NULL;
6770	goto done;
6771    case 1:
6772	hPtr = Tcl_FirstHashEntry(&table, &search);
6773	windows[0] = (TkWindow *) Tcl_GetHashValue(hPtr);
6774	windows[1] = NULL;
6775	goto done;
6776    }
6777
6778    /*
6779     * We will be inserting into the array starting at the end and working our
6780     * way to the beginning since EnumWindows returns windows in highest to
6781     * lowest order.
6782     */
6783
6784    pair.table = &table;
6785    pair.window_ptr = windows + table.numEntries;
6786    *pair.window_ptr-- = NULL;
6787
6788    if (EnumWindows((WNDENUMPROC) TkWmStackorderToplevelEnumProc,
6789	    (LPARAM) &pair) == 0) {
6790	ckfree((char *) windows);
6791	windows = NULL;
6792    } else if (pair.window_ptr != (windows-1)) {
6793	Tcl_Panic("num matched toplevel windows does not equal num children");
6794    }
6795
6796  done:
6797    Tcl_DeleteHashTable(&table);
6798    return windows;
6799}
6800
6801/*
6802 *----------------------------------------------------------------------
6803 *
6804 * TkWmRestackToplevel --
6805 *
6806 *	This function restacks a top-level window.
6807 *
6808 * Results:
6809 *	None.
6810 *
6811 * Side effects:
6812 *	WinPtr gets restacked as specified by aboveBelow and otherPtr. This
6813 *	function doesn't return until the restack has taken effect and the
6814 *	ConfigureNotify event for it has been received.
6815 *
6816 *----------------------------------------------------------------------
6817 */
6818
6819void
6820TkWmRestackToplevel(
6821    TkWindow *winPtr,		/* Window to restack. */
6822    int aboveBelow,		/* Gives relative position for restacking;
6823				 * must be Above or Below. */
6824    TkWindow *otherPtr)		/* Window relative to which to restack; if
6825				 * NULL, then winPtr gets restacked above or
6826				 * below *all* siblings. */
6827{
6828    HWND hwnd, insertAfter;
6829
6830    /*
6831     * Can't set stacking order properly until the window is on the screen
6832     * (mapping it may give it a reparent window).
6833     */
6834
6835    if (winPtr->window == None) {
6836	Tk_MakeWindowExist((Tk_Window) winPtr);
6837    }
6838    if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
6839	TkWmMapWindow(winPtr);
6840    }
6841    hwnd = (winPtr->wmInfoPtr->wrapper != NULL)
6842	? winPtr->wmInfoPtr->wrapper : Tk_GetHWND(winPtr->window);
6843
6844    if (otherPtr != NULL) {
6845	if (otherPtr->window == None) {
6846	    Tk_MakeWindowExist((Tk_Window) otherPtr);
6847	}
6848	if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
6849	    TkWmMapWindow(otherPtr);
6850	}
6851	insertAfter = (otherPtr->wmInfoPtr->wrapper != NULL)
6852		? otherPtr->wmInfoPtr->wrapper : Tk_GetHWND(otherPtr->window);
6853    } else {
6854	insertAfter = NULL;
6855    }
6856
6857    if (winPtr->flags & TK_EMBEDDED) {
6858	SendMessage(winPtr->wmInfoPtr->wrapper, TK_RAISEWINDOW,
6859		(WPARAM)insertAfter, aboveBelow);
6860    } else {
6861	TkWinSetWindowPos(hwnd, insertAfter, aboveBelow);
6862    }
6863}
6864
6865/*
6866 *----------------------------------------------------------------------
6867 *
6868 * TkWmAddToColormapWindows --
6869 *
6870 *	This function is called to add a given window to the
6871 *	WM_COLORMAP_WINDOWS property for its top-level, if it isn't already
6872 *	there. It is invoked by the Tk code that creates a new colormap, in
6873 *	order to make sure that colormap information is propagated to the
6874 *	window manager by default.
6875 *
6876 * Results:
6877 *	None.
6878 *
6879 * Side effects:
6880 *	WinPtr's window gets added to the WM_COLORMAP_WINDOWS property of its
6881 *	nearest top-level ancestor, unless the colormaps have been set
6882 *	explicitly with the "wm colormapwindows" command.
6883 *
6884 *----------------------------------------------------------------------
6885 */
6886
6887void
6888TkWmAddToColormapWindows(
6889    TkWindow *winPtr)		/* Window with a non-default colormap. Should
6890				 * not be a top-level window. */
6891{
6892    TkWindow *topPtr;
6893    TkWindow **oldPtr, **newPtr;
6894    int count, i;
6895
6896    if (winPtr->window == None) {
6897	return;
6898    }
6899
6900    for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
6901	if (topPtr == NULL) {
6902	    /*
6903	     * Window is being deleted. Skip the whole operation.
6904	     */
6905
6906	    return;
6907	}
6908	if (topPtr->flags & TK_TOP_HIERARCHY) {
6909	    break;
6910	}
6911    }
6912    if (topPtr->wmInfoPtr == NULL) {
6913	return;
6914    }
6915
6916    if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
6917	return;
6918    }
6919
6920    /*
6921     * Make sure that the window isn't already in the list.
6922     */
6923
6924    count = topPtr->wmInfoPtr->cmapCount;
6925    oldPtr = topPtr->wmInfoPtr->cmapList;
6926
6927    for (i = 0; i < count; i++) {
6928	if (oldPtr[i] == winPtr) {
6929	    return;
6930	}
6931    }
6932
6933    /*
6934     * Make a new bigger array and use it to reset the property.
6935     * Automatically add the toplevel itself as the last element of the list.
6936     */
6937
6938    newPtr = (TkWindow **) ckalloc((unsigned) ((count+2)*sizeof(TkWindow*)));
6939    if (count > 0) {
6940	memcpy(newPtr, oldPtr, count * sizeof(TkWindow*));
6941    }
6942    if (count == 0) {
6943	count++;
6944    }
6945    newPtr[count-1] = winPtr;
6946    newPtr[count] = topPtr;
6947    if (oldPtr != NULL) {
6948	ckfree((char *) oldPtr);
6949    }
6950
6951    topPtr->wmInfoPtr->cmapList = newPtr;
6952    topPtr->wmInfoPtr->cmapCount = count+1;
6953
6954    /*
6955     * Now we need to force the updated colormaps to be installed.
6956     */
6957
6958    if (topPtr->wmInfoPtr == winPtr->dispPtr->foregroundWmPtr) {
6959	InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_QUERYNEWPALETTE, 1);
6960    } else {
6961	InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_PALETTECHANGED, 0);
6962    }
6963}
6964
6965/*
6966 *----------------------------------------------------------------------
6967 *
6968 * TkWmRemoveFromColormapWindows --
6969 *
6970 *	This function is called to remove a given window from the
6971 *	WM_COLORMAP_WINDOWS property for its top-level. It is invoked when
6972 *	windows are deleted.
6973 *
6974 * Results:
6975 *	None.
6976 *
6977 * Side effects:
6978 *	WinPtr's window gets removed from the WM_COLORMAP_WINDOWS property of
6979 *	its nearest top-level ancestor, unless the top-level itself is being
6980 *	deleted too.
6981 *
6982 *----------------------------------------------------------------------
6983 */
6984
6985void
6986TkWmRemoveFromColormapWindows(
6987    TkWindow *winPtr)		/* Window that may be present in
6988				 * WM_COLORMAP_WINDOWS property for its
6989				 * top-level. Should not be a top-level
6990				 * window. */
6991{
6992    TkWindow *topPtr;
6993    TkWindow **oldPtr;
6994    int count, i, j;
6995
6996    for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
6997	if (topPtr == NULL) {
6998	    /*
6999	     * Ancestors have been deleted, so skip the whole operation.
7000	     * Seems like this can't ever happen?
7001	     */
7002
7003	    return;
7004	}
7005	if (topPtr->flags & TK_TOP_LEVEL) {
7006	    break;
7007	}
7008    }
7009    if (topPtr->flags & TK_ALREADY_DEAD) {
7010	/*
7011	 * Top-level is being deleted, so there's no need to cleanup the
7012	 * WM_COLORMAP_WINDOWS property.
7013	 */
7014
7015	return;
7016    }
7017
7018    if (topPtr->wmInfoPtr == NULL) {
7019	return;
7020    }
7021
7022    /*
7023     * Find the window and slide the following ones down to cover it up.
7024     */
7025
7026    count = topPtr->wmInfoPtr->cmapCount;
7027    oldPtr = topPtr->wmInfoPtr->cmapList;
7028    for (i = 0; i < count; i++) {
7029	if (oldPtr[i] == winPtr) {
7030	    for (j = i ; j < count-1; j++) {
7031		oldPtr[j] = oldPtr[j+1];
7032	    }
7033	    topPtr->wmInfoPtr->cmapCount = count-1;
7034	    break;
7035	}
7036    }
7037}
7038
7039/*
7040 *----------------------------------------------------------------------
7041 *
7042 * TkWinSetMenu--
7043 *
7044 *	Associcates a given HMENU to a window.
7045 *
7046 * Results:
7047 *	None.
7048 *
7049 * Side effects:
7050 *	The menu will end up being drawn in the window, and the geometry of
7051 *	the window will have to be changed.
7052 *
7053 *----------------------------------------------------------------------
7054 */
7055
7056void
7057TkWinSetMenu(
7058    Tk_Window tkwin,		/* the window to put the menu in */
7059    HMENU hMenu)		/* the menu to set */
7060{
7061    TkWindow *winPtr = (TkWindow *) tkwin;
7062    WmInfo *wmPtr = winPtr->wmInfoPtr;
7063
7064    /* Could be a Frame (i.e. not a Toplevel) */
7065    if (wmPtr == NULL)
7066	return;
7067
7068    wmPtr->hMenu = hMenu;
7069    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
7070	int syncPending = wmPtr->flags & WM_SYNC_PENDING;
7071
7072	wmPtr->flags |= WM_SYNC_PENDING;
7073	SetMenu(wmPtr->wrapper, hMenu);
7074	if (!syncPending) {
7075	    wmPtr->flags &= ~WM_SYNC_PENDING;
7076	}
7077    }
7078    if (!(winPtr->flags & TK_EMBEDDED)) {
7079	if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
7080	    Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
7081	    wmPtr->flags |= WM_UPDATE_PENDING|WM_MOVE_PENDING;
7082	}
7083    } else {
7084	SendMessage(wmPtr->wrapper, TK_SETMENU,
7085		(WPARAM)hMenu, (LPARAM)Tk_GetMenuHWND(tkwin));
7086    }
7087}
7088
7089/*
7090 *----------------------------------------------------------------------
7091 *
7092 * ConfigureTopLevel --
7093 *
7094 *	Generate a ConfigureNotify event based on the current position
7095 *	information. This function is called by TopLevelProc.
7096 *
7097 * Results:
7098 *	None.
7099 *
7100 * Side effects:
7101 *	Queues a new event.
7102 *
7103 *----------------------------------------------------------------------
7104 */
7105
7106static void
7107ConfigureTopLevel(
7108    WINDOWPOS *pos)
7109{
7110    TkWindow *winPtr = GetTopLevel(pos->hwnd);
7111    WmInfo *wmPtr;
7112    int state;			/* Current window state. */
7113    RECT rect;
7114    WINDOWPLACEMENT windowPos;
7115
7116    if (winPtr == NULL) {
7117	return;
7118    }
7119
7120    wmPtr = winPtr->wmInfoPtr;
7121
7122    /*
7123     * Determine the current window state.
7124     */
7125
7126    if (!IsWindowVisible(wmPtr->wrapper)) {
7127	state = WithdrawnState;
7128    } else {
7129	windowPos.length = sizeof(WINDOWPLACEMENT);
7130	GetWindowPlacement(wmPtr->wrapper, &windowPos);
7131	switch (windowPos.showCmd) {
7132	case SW_SHOWMAXIMIZED:
7133	    state = ZoomState;
7134	    break;
7135	case SW_SHOWMINIMIZED:
7136	    state = IconicState;
7137	    break;
7138	case SW_SHOWNORMAL:
7139	default:
7140	    state = NormalState;
7141	    break;
7142	}
7143    }
7144
7145    /*
7146     * If the state of the window just changed, be sure to update the
7147     * child window information.
7148     */
7149
7150    if (wmPtr->hints.initial_state != state) {
7151	wmPtr->hints.initial_state = state;
7152	switch (state) {
7153	case WithdrawnState:
7154	case IconicState:
7155	    XUnmapWindow(winPtr->display, winPtr->window);
7156	    break;
7157
7158	case NormalState:
7159	    /*
7160	     * Schedule a geometry update. Since we ignore geometry requests
7161	     * while in any other state, the geometry info may be stale.
7162	     */
7163
7164	    if (!(wmPtr->flags & WM_UPDATE_PENDING)) {
7165		Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
7166		wmPtr->flags |= WM_UPDATE_PENDING;
7167	    }
7168	    /* fall through */
7169	case ZoomState:
7170	    XMapWindow(winPtr->display, winPtr->window);
7171	    pos->flags |= SWP_NOMOVE | SWP_NOSIZE;
7172	    break;
7173	}
7174    }
7175
7176    /*
7177     * Don't report geometry changes in the Iconic or Withdrawn states.
7178     */
7179
7180    if (state == WithdrawnState || state == IconicState) {
7181	return;
7182    }
7183
7184
7185    /*
7186     * Compute the current geometry of the client area, reshape the Tk window
7187     * and generate a ConfigureNotify event.
7188     */
7189
7190    GetClientRect(wmPtr->wrapper, &rect);
7191    winPtr->changes.x = pos->x;
7192    winPtr->changes.y = pos->y;
7193    winPtr->changes.width = rect.right - rect.left;
7194    winPtr->changes.height = rect.bottom - rect.top;
7195    wmPtr->borderHeight = pos->cy - winPtr->changes.height;
7196    MoveWindow(Tk_GetHWND(winPtr->window), 0, 0,
7197	    winPtr->changes.width, winPtr->changes.height, TRUE);
7198    GenerateConfigureNotify(winPtr);
7199
7200    /*
7201     * Update window manager geometry info if needed.
7202     */
7203
7204    if (state == NormalState) {
7205
7206	/*
7207	 * Update size information from the event. There are a couple of
7208	 * tricky points here:
7209	 *
7210	 * 1. If the user changed the size externally then set wmPtr->width
7211	 *    and wmPtr->height just as if a "wm geometry" command had been
7212	 *    invoked with the same information.
7213	 * 2. However, if the size is changing in response to a request coming
7214	 *    from us (sync is set), then don't set wmPtr->width or
7215	 *    wmPtr->height (otherwise the window will stop tracking geometry
7216	 *    manager requests).
7217	 */
7218
7219	if (!(wmPtr->flags & WM_SYNC_PENDING)) {
7220	    if (!(pos->flags & SWP_NOSIZE)) {
7221		if ((wmPtr->width == -1)
7222			&& (winPtr->changes.width == winPtr->reqWidth)) {
7223		    /*
7224		     * Don't set external width, since the user didn't change
7225		     * it from what the widgets asked for.
7226		     */
7227		} else {
7228		    if (wmPtr->gridWin != NULL) {
7229			wmPtr->width = wmPtr->reqGridWidth
7230				+ (winPtr->changes.width - winPtr->reqWidth)
7231				/ wmPtr->widthInc;
7232			if (wmPtr->width < 0) {
7233			    wmPtr->width = 0;
7234			}
7235		    } else {
7236			wmPtr->width = winPtr->changes.width;
7237		    }
7238		}
7239		if ((wmPtr->height == -1)
7240			&& (winPtr->changes.height == winPtr->reqHeight)) {
7241		    /*
7242		     * Don't set external height, since the user didn't change
7243		     * it from what the widgets asked for.
7244		     */
7245		} else {
7246		    if (wmPtr->gridWin != NULL) {
7247			wmPtr->height = wmPtr->reqGridHeight
7248				+ (winPtr->changes.height - winPtr->reqHeight)
7249				/ wmPtr->heightInc;
7250			if (wmPtr->height < 0) {
7251			    wmPtr->height = 0;
7252			}
7253		    } else {
7254			wmPtr->height = winPtr->changes.height;
7255		    }
7256		}
7257		wmPtr->configWidth = winPtr->changes.width;
7258		wmPtr->configHeight = winPtr->changes.height;
7259	    }
7260
7261	    /*
7262	     * If the user moved the window, we should switch back to normal
7263	     * coordinates.
7264	     */
7265
7266	    if (!(pos->flags & SWP_NOMOVE)) {
7267		wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
7268	    }
7269	}
7270
7271	/*
7272	 * Update the wrapper window location information.
7273	 */
7274
7275	if (wmPtr->flags & WM_NEGATIVE_X) {
7276	    wmPtr->x = DisplayWidth(winPtr->display, winPtr->screenNum)
7277		    - winPtr->changes.x - (winPtr->changes.width
7278		    + wmPtr->borderWidth);
7279	} else {
7280	    wmPtr->x = winPtr->changes.x;
7281	}
7282	if (wmPtr->flags & WM_NEGATIVE_Y) {
7283	    wmPtr->y = DisplayHeight(winPtr->display, winPtr->screenNum)
7284		    - winPtr->changes.y - (winPtr->changes.height
7285		    + wmPtr->borderHeight);
7286	} else {
7287	    wmPtr->y = winPtr->changes.y;
7288	}
7289    }
7290}
7291
7292/*
7293 *----------------------------------------------------------------------
7294 *
7295 * GenerateConfigureNotify --
7296 *
7297 *	Generate a ConfigureNotify event from the current geometry information
7298 *	for the specified toplevel window.
7299 *
7300 * Results:
7301 *	None.
7302 *
7303 * Side effects:
7304 *	Sends an X event.
7305 *
7306 *----------------------------------------------------------------------
7307 */
7308
7309static void
7310GenerateConfigureNotify(
7311    TkWindow *winPtr)
7312{
7313    XEvent event;
7314
7315    /*
7316     * Generate a ConfigureNotify event.
7317     */
7318
7319    event.type = ConfigureNotify;
7320    event.xconfigure.serial = winPtr->display->request;
7321    event.xconfigure.send_event = False;
7322    event.xconfigure.display = winPtr->display;
7323    event.xconfigure.event = winPtr->window;
7324    event.xconfigure.window = winPtr->window;
7325    event.xconfigure.border_width = winPtr->changes.border_width;
7326    event.xconfigure.override_redirect = winPtr->atts.override_redirect;
7327    event.xconfigure.x = winPtr->changes.x;
7328    event.xconfigure.y = winPtr->changes.y;
7329    event.xconfigure.width = winPtr->changes.width;
7330    event.xconfigure.height = winPtr->changes.height;
7331    event.xconfigure.above = None;
7332    Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
7333}
7334
7335/*
7336 *----------------------------------------------------------------------
7337 *
7338 * InstallColormaps --
7339 *
7340 *	Installs the colormaps associated with the toplevel which is currently
7341 *	active.
7342 *
7343 * Results:
7344 *	None.
7345 *
7346 * Side effects:
7347 *	May change the system palette and generate damage.
7348 *
7349 *----------------------------------------------------------------------
7350 */
7351
7352static int
7353InstallColormaps(
7354    HWND hwnd,			/* Toplevel wrapper window whose colormaps
7355				 * should be installed. */
7356    int message,		/* Either WM_PALETTECHANGED or
7357				 * WM_QUERYNEWPALETTE */
7358    int isForemost)		/* 1 if window is foremost, else 0 */
7359{
7360    int i;
7361    HDC dc;
7362    HPALETTE oldPalette;
7363    TkWindow *winPtr = GetTopLevel(hwnd);
7364    WmInfo *wmPtr;
7365    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
7366	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
7367
7368    if (winPtr == NULL || (winPtr->flags & TK_ALREADY_DEAD) ) {
7369	return 0;
7370    }
7371
7372    wmPtr = winPtr->wmInfoPtr;
7373
7374    if (message == WM_QUERYNEWPALETTE) {
7375	/*
7376	 * Case 1: This window is about to become the foreground window, so we
7377	 * need to install the primary palette. If the system palette was
7378	 * updated, then Windows will generate a WM_PALETTECHANGED message.
7379	 * Otherwise, we have to synthesize one in order to ensure that the
7380	 * secondary palettes are installed properly.
7381	 */
7382
7383	winPtr->dispPtr->foregroundWmPtr = wmPtr;
7384
7385	if (wmPtr->cmapCount > 0) {
7386	    winPtr = wmPtr->cmapList[0];
7387	}
7388
7389	tsdPtr->systemPalette = TkWinGetPalette(winPtr->atts.colormap);
7390	dc = GetDC(hwnd);
7391	oldPalette = SelectPalette(dc, tsdPtr->systemPalette, FALSE);
7392	if (RealizePalette(dc)) {
7393	    RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
7394	} else if (wmPtr->cmapCount > 1) {
7395	    SelectPalette(dc, oldPalette, TRUE);
7396	    RealizePalette(dc);
7397	    ReleaseDC(hwnd, dc);
7398	    SendMessage(hwnd, WM_PALETTECHANGED, (WPARAM)hwnd,
7399		    (LPARAM)NULL);
7400	    return TRUE;
7401	}
7402
7403    } else {
7404	/*
7405	 * Window is being notified of a change in the system palette. If this
7406	 * window is the foreground window, then we should only install the
7407	 * secondary palettes, since the primary was installed in response to
7408	 * the WM_QUERYPALETTE message. Otherwise, install all of the
7409	 * palettes.
7410	 */
7411
7412
7413	if (!isForemost) {
7414	    if (wmPtr->cmapCount > 0) {
7415		winPtr = wmPtr->cmapList[0];
7416	    }
7417	    i = 1;
7418	} else {
7419	    if (wmPtr->cmapCount <= 1) {
7420		return TRUE;
7421	    }
7422	    winPtr = wmPtr->cmapList[1];
7423	    i = 2;
7424	}
7425	dc = GetDC(hwnd);
7426	oldPalette = SelectPalette(dc,
7427		TkWinGetPalette(winPtr->atts.colormap), TRUE);
7428	if (RealizePalette(dc)) {
7429	    RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
7430	}
7431	for (; i < wmPtr->cmapCount; i++) {
7432	    winPtr = wmPtr->cmapList[i];
7433	    SelectPalette(dc, TkWinGetPalette(winPtr->atts.colormap), TRUE);
7434	    if (RealizePalette(dc)) {
7435		RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
7436	    }
7437	}
7438    }
7439
7440    SelectPalette(dc, oldPalette, TRUE);
7441    RealizePalette(dc);
7442    ReleaseDC(hwnd, dc);
7443    return TRUE;
7444}
7445
7446/*
7447 *----------------------------------------------------------------------
7448 *
7449 * RefreshColormap --
7450 *
7451 *	This function is called to force all of the windows that use a given
7452 *	colormap to redraw themselves. The quickest way to do this is to
7453 *	iterate over the toplevels, looking in the cmapList for matches. This
7454 *	will quickly eliminate subtrees that don't use a given colormap.
7455 *
7456 * Results:
7457 *	None.
7458 *
7459 * Side effects:
7460 *	Causes damage events to be generated.
7461 *
7462 *----------------------------------------------------------------------
7463 */
7464
7465static void
7466RefreshColormap(
7467    Colormap colormap,
7468    TkDisplay *dispPtr)
7469{
7470    WmInfo *wmPtr;
7471    int i;
7472
7473    for (wmPtr = dispPtr->firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) {
7474	if (wmPtr->cmapCount > 0) {
7475	    for (i = 0; i < wmPtr->cmapCount; i++) {
7476		if ((wmPtr->cmapList[i]->atts.colormap == colormap)
7477			&& Tk_IsMapped(wmPtr->cmapList[i])) {
7478		    InvalidateSubTree(wmPtr->cmapList[i], colormap);
7479		}
7480	    }
7481	} else if ((wmPtr->winPtr->atts.colormap == colormap)
7482		&& Tk_IsMapped(wmPtr->winPtr)) {
7483	    InvalidateSubTree(wmPtr->winPtr, colormap);
7484	}
7485    }
7486}
7487
7488/*
7489 *----------------------------------------------------------------------
7490 *
7491 * InvalidateSubTree --
7492 *
7493 *	This function recursively generates damage for a window and all of its
7494 *	mapped children that belong to the same toplevel and are using the
7495 *	specified colormap.
7496 *
7497 * Results:
7498 *	None.
7499 *
7500 * Side effects:
7501 *	Generates damage for the specified subtree.
7502 *
7503 *----------------------------------------------------------------------
7504 */
7505
7506static void
7507InvalidateSubTree(
7508    TkWindow *winPtr,
7509    Colormap colormap)
7510{
7511    TkWindow *childPtr;
7512
7513    /*
7514     * Generate damage for the current window if it is using the specified
7515     * colormap.
7516     */
7517
7518    if (winPtr->atts.colormap == colormap) {
7519	InvalidateRect(Tk_GetHWND(winPtr->window), NULL, FALSE);
7520    }
7521
7522    for (childPtr = winPtr->childList; childPtr != NULL;
7523	    childPtr = childPtr->nextPtr) {
7524	/*
7525	 * We can stop the descent when we hit an unmapped or toplevel window.
7526	 */
7527
7528	if (!Tk_TopWinHierarchy(childPtr) && Tk_IsMapped(childPtr)) {
7529	    InvalidateSubTree(childPtr, colormap);
7530	}
7531    }
7532}
7533
7534/*
7535 *----------------------------------------------------------------------
7536 *
7537 * InvalidateSubTreeDepth --
7538 *
7539 *	This function recursively updates depth info for a window and all of
7540 *	its children that belong to the same toplevel.
7541 *
7542 * Results:
7543 *	None.
7544 *
7545 * Side effects:
7546 *	Sets the depth of each window to that of the display.
7547 *
7548 *----------------------------------------------------------------------
7549 */
7550
7551static void
7552InvalidateSubTreeDepth(
7553    TkWindow *winPtr)
7554{
7555    Display *display = Tk_Display(winPtr);
7556    int screenNum = Tk_ScreenNumber(winPtr);
7557    TkWindow *childPtr;
7558
7559    winPtr->depth = DefaultDepth(display, screenNum);
7560
7561#if 0
7562    /*
7563     * XXX: What other elements may require changes? Changing just the depth
7564     * works for standard windows and 16/24/32-bpp changes. I suspect 8-bit
7565     * (palettized) displays may require colormap and/or visual changes as
7566     * well.
7567     */
7568
7569    if (winPtr->window) {
7570	InvalidateRect(Tk_GetHWND(winPtr->window), NULL, FALSE);
7571    }
7572    winPtr->visual = DefaultVisual(display, screenNum);
7573    winPtr->atts.colormap = DefaultColormap(display, screenNum);
7574    winPtr->dirtyAtts |= CWColormap;
7575#endif
7576
7577    for (childPtr = winPtr->childList; childPtr != NULL;
7578	    childPtr = childPtr->nextPtr) {
7579	/*
7580	 * We can stop the descent when we hit a non-embedded toplevel window,
7581	 * as it should get its own message.
7582	 */
7583
7584	if (childPtr->flags & TK_EMBEDDED || !Tk_TopWinHierarchy(childPtr)) {
7585	    InvalidateSubTreeDepth(childPtr);
7586	}
7587    }
7588}
7589
7590/*
7591 *----------------------------------------------------------------------
7592 *
7593 * TkWinGetSystemPalette --
7594 *
7595 *	Retrieves the currently installed foreground palette.
7596 *
7597 * Results:
7598 *	Returns the global foreground palette, if there is one. Otherwise,
7599 *	returns NULL.
7600 *
7601 * Side effects:
7602 *	None.
7603 *
7604 *----------------------------------------------------------------------
7605 */
7606
7607HPALETTE
7608TkWinGetSystemPalette(void)
7609{
7610    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
7611	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
7612
7613    return tsdPtr->systemPalette;
7614}
7615
7616/*
7617 *----------------------------------------------------------------------
7618 *
7619 * GetMinSize --
7620 *
7621 *	This function computes the current minWidth and minHeight values for a
7622 *	window, taking into account the possibility that they may be
7623 *	defaulted.
7624 *
7625 * Results:
7626 *	The values at *minWidthPtr and *minHeightPtr are filled in with the
7627 *	minimum allowable dimensions of wmPtr's window, in grid units. If the
7628 *	requested minimum is smaller than the system required minimum, then
7629 *	this function computes the smallest size that will satisfy both the
7630 *	system and the grid constraints.
7631 *
7632 * Side effects:
7633 *	None.
7634 *
7635 *----------------------------------------------------------------------
7636 */
7637
7638static void
7639GetMinSize(
7640    WmInfo *wmPtr,		/* Window manager information for the
7641				 * window. */
7642    int *minWidthPtr,		/* Where to store the current minimum width of
7643				 * the window. */
7644    int *minHeightPtr)		/* Where to store the current minimum height
7645				 * of the window. */
7646{
7647    int tmp, base;
7648    TkWindow *winPtr = wmPtr->winPtr;
7649
7650    /*
7651     * Compute the minimum width by taking the default client size and
7652     * rounding it up to the nearest grid unit. Return the greater of the
7653     * default minimum and the specified minimum.
7654     */
7655
7656    tmp = wmPtr->defMinWidth - wmPtr->borderWidth;
7657    if (tmp < 0) {
7658	tmp = 0;
7659    }
7660    if (wmPtr->gridWin != NULL) {
7661	base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
7662	if (base < 0) {
7663	    base = 0;
7664	}
7665	tmp = ((tmp - base) + wmPtr->widthInc - 1)/wmPtr->widthInc;
7666    }
7667    if (tmp < wmPtr->minWidth) {
7668	tmp = wmPtr->minWidth;
7669    }
7670    *minWidthPtr = tmp;
7671
7672    /*
7673     * Compute the minimum height in a similar fashion.
7674     */
7675
7676    tmp = wmPtr->defMinHeight - wmPtr->borderHeight;
7677    if (tmp < 0) {
7678	tmp = 0;
7679    }
7680    if (wmPtr->gridWin != NULL) {
7681	base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
7682	if (base < 0) {
7683	    base = 0;
7684	}
7685	tmp = ((tmp - base) + wmPtr->heightInc - 1)/wmPtr->heightInc;
7686    }
7687    if (tmp < wmPtr->minHeight) {
7688	tmp = wmPtr->minHeight;
7689    }
7690    *minHeightPtr = tmp;
7691}
7692
7693/*
7694 *----------------------------------------------------------------------
7695 *
7696 * GetMaxSize --
7697 *
7698 *	This function computes the current maxWidth and maxHeight values for a
7699 *	window, taking into account the possibility that they may be
7700 *	defaulted.
7701 *
7702 * Results:
7703 *	The values at *maxWidthPtr and *maxHeightPtr are filled in with the
7704 *	maximum allowable dimensions of wmPtr's window, in grid units. If no
7705 *	maximum has been specified for the window, then this function computes
7706 *	the largest sizes that will fit on the screen.
7707 *
7708 * Side effects:
7709 *	None.
7710 *
7711 *----------------------------------------------------------------------
7712 */
7713
7714static void
7715GetMaxSize(
7716    WmInfo *wmPtr,		/* Window manager information for the
7717				 * window. */
7718    int *maxWidthPtr,		/* Where to store the current maximum width of
7719				 * the window. */
7720    int *maxHeightPtr)		/* Where to store the current maximum height
7721				 * of the window. */
7722{
7723    int tmp;
7724
7725    if (wmPtr->maxWidth > 0) {
7726	*maxWidthPtr = wmPtr->maxWidth;
7727    } else {
7728	/*
7729	 * Must compute a default width. Fill up the display, leaving a bit of
7730	 * extra space for the window manager's borders.
7731	 */
7732
7733	tmp = wmPtr->defMaxWidth - wmPtr->borderWidth;
7734	if (wmPtr->gridWin != NULL) {
7735	    /*
7736	     * Gridding is turned on; convert from pixels to grid units.
7737	     */
7738
7739	    tmp = wmPtr->reqGridWidth
7740		    + (tmp - wmPtr->winPtr->reqWidth)/wmPtr->widthInc;
7741	}
7742	*maxWidthPtr = tmp;
7743    }
7744    if (wmPtr->maxHeight > 0) {
7745	*maxHeightPtr = wmPtr->maxHeight;
7746    } else {
7747	tmp = wmPtr->defMaxHeight - wmPtr->borderHeight;
7748	if (wmPtr->gridWin != NULL) {
7749	    tmp = wmPtr->reqGridHeight
7750		    + (tmp - wmPtr->winPtr->reqHeight)/wmPtr->heightInc;
7751	}
7752	*maxHeightPtr = tmp;
7753    }
7754}
7755
7756/*
7757 *----------------------------------------------------------------------
7758 *
7759 * TopLevelProc --
7760 *
7761 *	Callback from Windows whenever an event occurs on a top level window.
7762 *
7763 * Results:
7764 *	Standard Windows return value.
7765 *
7766 * Side effects:
7767 *	Default window behavior.
7768 *
7769 *----------------------------------------------------------------------
7770 */
7771
7772static LRESULT CALLBACK
7773TopLevelProc(
7774    HWND hwnd,
7775    UINT message,
7776    WPARAM wParam,
7777    LPARAM lParam)
7778{
7779    if (message == WM_WINDOWPOSCHANGED || message == WM_WINDOWPOSCHANGING) {
7780	WINDOWPOS *pos = (WINDOWPOS *) lParam;
7781	TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(pos->hwnd);
7782
7783	if (winPtr == NULL) {
7784	    return 0;
7785	}
7786
7787	/*
7788	 * Update the shape of the contained window.
7789	 */
7790
7791	if (!(pos->flags & SWP_NOSIZE)) {
7792	    winPtr->changes.width = pos->cx;
7793	    winPtr->changes.height = pos->cy;
7794	}
7795	if (!(pos->flags & SWP_NOMOVE)) {
7796	    long result = SendMessage(winPtr->wmInfoPtr->wrapper,
7797		    TK_MOVEWINDOW, -1, -1);
7798	    winPtr->wmInfoPtr->x = winPtr->changes.x = result >> 16;
7799	    winPtr->wmInfoPtr->y = winPtr->changes.y = result & 0xffff;
7800	}
7801
7802	GenerateConfigureNotify(winPtr);
7803
7804	Tcl_ServiceAll();
7805	return 0;
7806    }
7807    return TkWinChildProc(hwnd, message, wParam, lParam);
7808}
7809
7810/*
7811 *----------------------------------------------------------------------
7812 *
7813 * WmProc --
7814 *
7815 *	Callback from Windows whenever an event occurs on the decorative
7816 *	frame.
7817 *
7818 * Results:
7819 *	Standard Windows return value.
7820 *
7821 * Side effects:
7822 *	Default window behavior.
7823 *
7824 *----------------------------------------------------------------------
7825 */
7826
7827static LRESULT CALLBACK
7828WmProc(
7829    HWND hwnd,
7830    UINT message,
7831    WPARAM wParam,
7832    LPARAM lParam)
7833{
7834    static int inMoveSize = 0;
7835    static int oldMode;		/* This static is set upon entering move/size
7836				 * mode and is used to reset the service mode
7837				 * after leaving move/size mode. Note that
7838				 * this mechanism assumes move/size is only
7839				 * one level deep. */
7840    LRESULT result = 0;
7841    TkWindow *winPtr = NULL;
7842
7843    switch (message) {
7844    case WM_KILLFOCUS:
7845    case WM_ERASEBKGND:
7846	result = 0;
7847	goto done;
7848
7849    case WM_ENTERSIZEMOVE:
7850	inMoveSize = 1;
7851
7852	/*
7853	 * Cancel any current mouse timer. If the mouse timer fires during the
7854	 * size/move mouse capture, it will release the capture, which is
7855	 * wrong.
7856	 */
7857
7858	TkWinCancelMouseTimer();
7859
7860	oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
7861	break;
7862
7863    case WM_ACTIVATE:
7864	if ( WA_ACTIVE == LOWORD(wParam) ) {
7865	    winPtr = GetTopLevel(hwnd);
7866	    if (winPtr && (TkGrabState(winPtr) == TK_GRAB_EXCLUDED)) {
7867		/*
7868		 * There is a grab in progress so queue an Activate event
7869		 */
7870
7871		GenerateActivateEvent(winPtr, &inMoveSize);
7872		result = 0;
7873		goto done;
7874	    }
7875	}
7876	/* fall through */
7877
7878    case WM_EXITSIZEMOVE:
7879	if (inMoveSize) {
7880	    inMoveSize = 0;
7881	    Tcl_SetServiceMode(oldMode);
7882	}
7883	break;
7884
7885    case WM_GETMINMAXINFO:
7886	SetLimits(hwnd, (MINMAXINFO *) lParam);
7887	result = 0;
7888	goto done;
7889
7890    case WM_DISPLAYCHANGE:
7891	/*
7892	 * Display and/or color resolution changed.
7893	 */
7894
7895	winPtr = GetTopLevel(hwnd);
7896	if (winPtr) {
7897	    Screen *screen = Tk_Screen(winPtr);
7898	    if (screen->root_depth != (int) wParam) {
7899		/*
7900		 * Color resolution changed, so do extensive rebuild of
7901		 * display parameters. This will affect the display for all Tk
7902		 * windows. We will receive this event for each toplevel, but
7903		 * this check makes us update only once, for the first
7904		 * toplevel that receives the message.
7905		 */
7906
7907		TkWinDisplayChanged(Tk_Display(winPtr));
7908	    } else {
7909		HDC dc = GetDC(NULL);
7910
7911		screen->width = LOWORD(lParam);		/* horizontal res */
7912		screen->height = HIWORD(lParam);	/* vertical res */
7913		screen->mwidth = MulDiv(screen->width, 254,
7914			GetDeviceCaps(dc, LOGPIXELSX) * 10);
7915		screen->mheight = MulDiv(screen->height, 254,
7916			GetDeviceCaps(dc, LOGPIXELSY) * 10);
7917		ReleaseDC(NULL, dc);
7918	    }
7919	    if (Tk_Depth(winPtr) != (int) wParam) {
7920		/*
7921		 * Defer the window depth check to here so that each toplevel
7922		 * will properly update depth info.
7923		 */
7924
7925		InvalidateSubTreeDepth(winPtr);
7926	    }
7927	}
7928	result = 0;
7929	goto done;
7930
7931    case WM_SYSCOLORCHANGE:
7932	/*
7933	 * XXX: Called when system color changes. We need to update any
7934	 * widgets that use a system color.
7935	 */
7936
7937	break;
7938
7939    case WM_PALETTECHANGED:
7940	result = InstallColormaps(hwnd, WM_PALETTECHANGED,
7941		hwnd == (HWND)wParam);
7942	goto done;
7943
7944    case WM_QUERYNEWPALETTE:
7945	result = InstallColormaps(hwnd, WM_QUERYNEWPALETTE, TRUE);
7946	goto done;
7947
7948    case WM_SETTINGCHANGE:
7949	if (wParam == SPI_SETNONCLIENTMETRICS) {
7950	    winPtr = GetTopLevel(hwnd);
7951	    TkWinSetupSystemFonts(winPtr->mainPtr);
7952	    result = 0;
7953	    goto done;
7954	}
7955	break;
7956
7957    case WM_WINDOWPOSCHANGED:
7958	ConfigureTopLevel((WINDOWPOS *) lParam);
7959	result = 0;
7960	goto done;
7961
7962    case WM_NCHITTEST: {
7963	winPtr = GetTopLevel(hwnd);
7964	if (winPtr && (TkGrabState(winPtr) == TK_GRAB_EXCLUDED)) {
7965	    /*
7966	     * This window is outside the grab heirarchy, so don't let any of
7967	     * the normal non-client processing occur. Note that this
7968	     * implementation is not strictly correct because the grab might
7969	     * change between now and when the event would have been processed
7970	     * by Tk, but it's close enough.
7971	     */
7972
7973	    result = HTCLIENT;
7974	    goto done;
7975	}
7976	break;
7977    }
7978
7979    case WM_MOUSEACTIVATE: {
7980	winPtr = GetTopLevel((HWND) wParam);
7981	if (winPtr && (TkGrabState(winPtr) != TK_GRAB_EXCLUDED)) {
7982	    /*
7983	     * This allows us to pass the message onto the native menus [Bug:
7984	     * 2272]
7985	     */
7986
7987	    result = (*tkWinProcs->defWindowProc)(hwnd, message,
7988		    wParam, lParam);
7989	    goto done;
7990	}
7991
7992	/*
7993	 * Don't activate the window yet since there is a grab that takes
7994	 * precedence. Instead we need to queue an event so we can check the
7995	 * grab state right before we handle the mouse event.
7996	 */
7997
7998	if (winPtr) {
7999	    GenerateActivateEvent(winPtr, &inMoveSize);
8000	}
8001	result = MA_NOACTIVATE;
8002	goto done;
8003    }
8004
8005    case WM_QUERYENDSESSION: {
8006	XEvent event;
8007
8008	/*
8009	 * Synthesize WM_SAVE_YOURSELF wm protocol message on Windows logout
8010	 * or restart.
8011	 */
8012	winPtr = GetTopLevel(hwnd);
8013	event.xclient.message_type =
8014	    Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS");
8015	event.xclient.data.l[0] =
8016	    Tk_InternAtom((Tk_Window) winPtr, "WM_SAVE_YOURSELF");
8017	TkWmProtocolEventProc(winPtr, &event);
8018	break;
8019    }
8020
8021    default:
8022	break;
8023    }
8024
8025    winPtr = GetTopLevel(hwnd);
8026    switch(message) {
8027    case WM_SYSCOMMAND:
8028	/*
8029	 * If there is a grab in effect then ignore the minimize command
8030	 * unless the grab is on the main window (.). This is to permit
8031	 * applications that leave a grab on . to work normally.
8032	 * All other toplevels are deemed non-minimizable when a grab is
8033	 * present.
8034	 * If there is a grab in effect and this window is outside the
8035	 * grab tree then ignore all system commands. [Bug 1847002]
8036	 */
8037
8038	if (winPtr) {
8039	    int cmd = wParam & 0xfff0;
8040	    int grab = TkGrabState(winPtr);
8041	    if ((SC_MINIMIZE == cmd)
8042		&& (grab == TK_GRAB_IN_TREE || grab == TK_GRAB_ANCESTOR)
8043		&& (winPtr != winPtr->mainPtr->winPtr)) {
8044		goto done;
8045	    }
8046	    if (grab == TK_GRAB_EXCLUDED
8047		&& !(SC_MOVE == cmd || SC_SIZE == cmd)) {
8048		goto done;
8049	    }
8050	}
8051	/* fall through */
8052
8053    case WM_INITMENU:
8054    case WM_COMMAND:
8055    case WM_MENUCHAR:
8056    case WM_MEASUREITEM:
8057    case WM_DRAWITEM:
8058    case WM_MENUSELECT:
8059    case WM_ENTERIDLE:
8060    case WM_INITMENUPOPUP:
8061	if (winPtr) {
8062	    HWND hMenuHWnd = Tk_GetEmbeddedMenuHWND((Tk_Window)winPtr);
8063
8064	    if (hMenuHWnd) {
8065		if (SendMessage(hMenuHWnd, message, wParam, lParam)) {
8066		    goto done;
8067		}
8068	    } else if (TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam,
8069		    &result)) {
8070		goto done;
8071	    }
8072	}
8073	break;
8074    }
8075
8076    if (winPtr && winPtr->window) {
8077	HWND child = Tk_GetHWND(winPtr->window);
8078
8079	if (message == WM_SETFOCUS) {
8080	    SetFocus(child);
8081	    result = 0;
8082	} else if (!Tk_TranslateWinEvent(child, message, wParam, lParam,
8083		&result)) {
8084	    result = (*tkWinProcs->defWindowProc)(hwnd, message,
8085		    wParam, lParam);
8086	}
8087    } else {
8088	result = (*tkWinProcs->defWindowProc)(hwnd, message, wParam, lParam);
8089    }
8090
8091  done:
8092    Tcl_ServiceAll();
8093    return result;
8094}
8095
8096/*
8097 *----------------------------------------------------------------------
8098 *
8099 * TkpMakeMenuWindow --
8100 *
8101 *	Configure the window to be either a pull-down (or pop-up) menu, or as
8102 *	a toplevel (torn-off) menu or palette.
8103 *
8104 * Results:
8105 *	None.
8106 *
8107 * Side effects:
8108 *	Changes the style bit used to create a new toplevel.
8109 *
8110 *----------------------------------------------------------------------
8111 */
8112
8113void
8114TkpMakeMenuWindow(
8115    Tk_Window tkwin,		/* New window. */
8116    int transient)		/* 1 means menu is only posted briefly as a
8117				 * popup or pulldown or cascade. 0 means menu
8118				 * is always visible, e.g. as a torn-off menu.
8119				 * Determines whether save_under and
8120				 * override_redirect should be set. */
8121{
8122    XSetWindowAttributes atts;
8123
8124    if (transient) {
8125	atts.override_redirect = True;
8126	atts.save_under = True;
8127    } else {
8128	atts.override_redirect = False;
8129	atts.save_under = False;
8130    }
8131
8132    if ((atts.override_redirect != Tk_Attributes(tkwin)->override_redirect)
8133	    || (atts.save_under != Tk_Attributes(tkwin)->save_under)) {
8134	Tk_ChangeWindowAttributes(tkwin,
8135		CWOverrideRedirect|CWSaveUnder, &atts);
8136    }
8137
8138}
8139
8140/*
8141 *----------------------------------------------------------------------
8142 *
8143 * TkWinGetWrapperWindow --
8144 *
8145 *	Gets the Windows HWND for a given window.
8146 *
8147 * Results:
8148 *	Returns the wrapper window for a Tk window.
8149 *
8150 * Side effects:
8151 *	None.
8152 *
8153 *----------------------------------------------------------------------
8154 */
8155
8156HWND
8157TkWinGetWrapperWindow(
8158    Tk_Window tkwin)		/* The window we need the wrapper from */
8159{
8160    TkWindow *winPtr = (TkWindow *)tkwin;
8161    return (winPtr->wmInfoPtr->wrapper);
8162}
8163
8164/*
8165 *----------------------------------------------------------------------
8166 *
8167 * TkWmFocusToplevel --
8168 *
8169 *	This is a utility function invoked by focus-management code. It exists
8170 *	because of the extra wrapper windows that exist under Unix; its job is
8171 *	to map from wrapper windows to the corresponding toplevel windows. On
8172 *	PCs and Macs there are no wrapper windows so no mapping is necessary;
8173 *	this function just determines whether a window is a toplevel or not.
8174 *
8175 * Results:
8176 *	If winPtr is a toplevel window, returns the pointer to the window;
8177 *	otherwise returns NULL.
8178 *
8179 * Side effects:
8180 *	None.
8181 *
8182 *----------------------------------------------------------------------
8183 */
8184
8185TkWindow *
8186TkWmFocusToplevel(
8187    TkWindow *winPtr)		/* Window that received a focus-related
8188				 * event. */
8189{
8190    if (!(winPtr->flags & TK_TOP_HIERARCHY)) {
8191	return NULL;
8192    }
8193    return winPtr;
8194}
8195
8196/*
8197 *----------------------------------------------------------------------
8198 *
8199 * TkpGetWrapperWindow --
8200 *
8201 *	This is a utility function invoked by focus-management code. It maps
8202 *	to the wrapper for a top-level, which is just the same as the
8203 *	top-level on Macs and PCs.
8204 *
8205 * Results:
8206 *	If winPtr is a toplevel window, returns the pointer to the window;
8207 *	otherwise returns NULL.
8208 *
8209 * Side effects:
8210 *	None.
8211 *
8212 *----------------------------------------------------------------------
8213 */
8214
8215TkWindow *
8216TkpGetWrapperWindow(
8217    TkWindow *winPtr)		/* Window that received a focus-related
8218				 * event. */
8219{
8220    if (!(winPtr->flags & TK_TOP_HIERARCHY)) {
8221	return NULL;
8222    }
8223    return winPtr;
8224}
8225
8226/*
8227 *----------------------------------------------------------------------
8228 *
8229 * GenerateActivateEvent --
8230 *
8231 *	This function is called to activate a Tk window.
8232 */
8233
8234static void
8235GenerateActivateEvent(TkWindow * winPtr, const int *flagPtr)
8236{
8237    ActivateEvent *eventPtr;
8238    eventPtr = (ActivateEvent *)ckalloc(sizeof(ActivateEvent));
8239    eventPtr->ev.proc = ActivateWindow;
8240    eventPtr->winPtr = winPtr;
8241    eventPtr->flagPtr = flagPtr;
8242    eventPtr->hwnd = Tk_GetHWND(winPtr->window);
8243    Tcl_QueueEvent((Tcl_Event *)eventPtr, TCL_QUEUE_TAIL);
8244}
8245
8246/*
8247 *----------------------------------------------------------------------
8248 *
8249 * ActivateWindow --
8250 *
8251 *	This function is called when an ActivateEvent is processed.
8252 *
8253 * Results:
8254 *	Returns 1 to indicate that the event was handled, else 0.
8255 *
8256 * Side effects:
8257 *	May activate the toplevel window associated with the event.
8258 *
8259 *----------------------------------------------------------------------
8260 */
8261
8262static int
8263ActivateWindow(
8264    Tcl_Event *evPtr,		/* Pointer to ActivateEvent. */
8265    int flags)			/* Notifier event mask. */
8266{
8267    ActivateEvent *eventPtr = (ActivateEvent *)evPtr;
8268    TkWindow *winPtr = eventPtr->winPtr;
8269
8270    if (! (flags & TCL_WINDOW_EVENTS)) {
8271	return 0;
8272    }
8273
8274    /*
8275     * Ensure the window has not been destroyed while we delayed
8276     * processing the WM_ACTIVATE message [Bug 2899949].
8277     */
8278
8279    if (!IsWindow(eventPtr->hwnd)) {
8280	return 1;
8281    }
8282
8283    /*
8284     * If the toplevel is in the middle of a move or size operation then
8285     * we must delay handling of this event to avoid stealing the focus
8286     * while the window manage is in control.
8287     */
8288
8289    if (eventPtr->flagPtr && *eventPtr->flagPtr) {
8290	return 0;
8291    }
8292
8293    /*
8294     * If the window is excluded by a grab, call SetFocus on the grabbed
8295     * window instead. [Bug 220908]
8296     */
8297
8298    if (winPtr) {
8299	Window window;
8300	if (TkGrabState(winPtr) != TK_GRAB_EXCLUDED) {
8301	    window = winPtr->window;
8302	} else {
8303	    window = winPtr->dispPtr->grabWinPtr->window;
8304	}
8305
8306	/*
8307	 * Ensure the window was not destroyed while we were postponing
8308	 * the activation [Bug 2799589]
8309	 */
8310
8311	if (window) {
8312	    SetFocus(Tk_GetHWND(window));
8313	}
8314    }
8315
8316    return 1;
8317}
8318
8319/*
8320 *----------------------------------------------------------------------
8321 *
8322 * TkWinSetForegroundWindow --
8323 *
8324 *	This function is a wrapper for SetForegroundWindow, calling it on the
8325 *	wrapper window because it has no affect on child windows.
8326 *
8327 * Results:
8328 *	none
8329 *
8330 * Side effects:
8331 *	May activate the toplevel window.
8332 *
8333 *----------------------------------------------------------------------
8334 */
8335
8336void
8337TkWinSetForegroundWindow(
8338    TkWindow *winPtr)
8339{
8340    register WmInfo *wmPtr = winPtr->wmInfoPtr;
8341
8342    if (wmPtr->wrapper != NULL) {
8343	SetForegroundWindow(wmPtr->wrapper);
8344    } else {
8345	SetForegroundWindow(Tk_GetHWND(winPtr->window));
8346    }
8347}
8348
8349/*
8350 *----------------------------------------------------------------------
8351 *
8352 * TkpWinToplevelWithdraw --
8353 *
8354 *	This function is to be used by a window manage to withdraw a toplevel
8355 *	window.
8356 *
8357 * Results:
8358 *	none
8359 *
8360 * Side effects:
8361 *	May withdraw the toplevel window.
8362 *
8363 *----------------------------------------------------------------------
8364 */
8365
8366void
8367TkpWinToplevelWithDraw(
8368    TkWindow *winPtr)
8369{
8370    register WmInfo *wmPtr = winPtr->wmInfoPtr;
8371    wmPtr->flags |= WM_WITHDRAWN;
8372    TkpWmSetState(winPtr, WithdrawnState);
8373}
8374
8375/*
8376 *----------------------------------------------------------------------
8377 *
8378 * TkpWinToplevelIconify --
8379 *
8380 *	This function is to be used by a window manage to iconify a toplevel
8381 *	window.
8382 *
8383 * Results:
8384 *	none
8385 *
8386 * Side effects:
8387 *	May iconify the toplevel window.
8388 *
8389 *----------------------------------------------------------------------
8390 */
8391
8392void
8393TkpWinToplevelIconify(
8394    TkWindow *winPtr)
8395{
8396    TkpWmSetState(winPtr, IconicState);
8397}
8398
8399/*
8400 *----------------------------------------------------------------------
8401 *
8402 * TkpWinToplevelDeiconify --
8403 *
8404 *	This function is to be used by a window manage to deiconify a toplevel
8405 *	window.
8406 *
8407 * Results:
8408 *	none
8409 *
8410 * Side effects:
8411 *	May deiconify the toplevel window.
8412 *
8413 *----------------------------------------------------------------------
8414 */
8415
8416void
8417TkpWinToplevelDeiconify(
8418    TkWindow *winPtr)
8419{
8420    register WmInfo *wmPtr = winPtr->wmInfoPtr;
8421
8422    wmPtr->flags &= ~WM_WITHDRAWN;
8423
8424    /*
8425     * If WM_UPDATE_PENDING is true, a pending UpdateGeometryInfo may need to
8426     * be called first to update a withdrawn toplevel's geometry before it is
8427     * deiconified by TkpWmSetState. Don't bother if we've never been mapped.
8428     */
8429
8430    if ((wmPtr->flags & WM_UPDATE_PENDING) &&
8431	    !(wmPtr->flags & WM_NEVER_MAPPED)) {
8432	Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
8433	UpdateGeometryInfo((ClientData) winPtr);
8434    }
8435
8436    /*
8437     * If we were in the ZoomState (maximized), 'wm deiconify' should not
8438     * cause the window to shrink
8439     */
8440
8441    if (wmPtr->hints.initial_state == ZoomState) {
8442	TkpWmSetState(winPtr, ZoomState);
8443    } else {
8444	TkpWmSetState(winPtr, NormalState);
8445    }
8446
8447    /*
8448     * An unmapped window will be mapped at idle time by a call to MapFrame.
8449     * That calls CreateWrapper which sets the focus and raises the window.
8450     */
8451
8452    if (wmPtr->flags & WM_NEVER_MAPPED) {
8453	return;
8454    }
8455
8456    /*
8457     * Follow Windows-like style here, raising the window to the top.
8458     */
8459
8460    TkWmRestackToplevel(winPtr, Above, NULL);
8461    if (!(Tk_Attributes((Tk_Window) winPtr)->override_redirect)) {
8462	TkSetFocusWin(winPtr, 1);
8463    }
8464}
8465
8466/*
8467 *----------------------------------------------------------------------
8468 *
8469 * TkpWinGeometryIsControlledByWm --
8470 *
8471 *	This function is to be used by a window manage to see if wm has
8472 *	canceled geometry control.
8473 *
8474 * Results:
8475 *	0 - if the window manager has canceled its control
8476 *	1 - if the window manager controls the geometry
8477 *
8478 * Side effects:
8479 *	None.
8480 *
8481 *----------------------------------------------------------------------
8482 */
8483
8484long
8485TkpWinToplevelIsControlledByWm(
8486    TkWindow *winPtr)
8487{
8488    register WmInfo *wmPtr = winPtr->wmInfoPtr;
8489
8490    if (wmPtr) {
8491	return ((wmPtr->width != -1) && (wmPtr->height != -1))? 1:0;
8492    } else {
8493	return 0;
8494    }
8495}
8496
8497/*
8498 *----------------------------------------------------------------------
8499 *
8500 * TkpWinToplevelMove --
8501 *
8502 *	This function is to be used by a container to move an embedded window.
8503 *
8504 * Results:
8505 *	position of the upper left frame in a 32-bit long:
8506 *		16-MSBits - x; 16-LSBits - y
8507 *
8508 * Side effects:
8509 *	May move the embedded window.
8510 *
8511 *----------------------------------------------------------------------
8512 */
8513
8514long
8515TkpWinToplevelMove(
8516    TkWindow *winPtr,
8517    int x, int y)
8518{
8519    register WmInfo *wmPtr = winPtr->wmInfoPtr;
8520
8521    if (wmPtr && x >= 0 && y >= 0 && !TkpWinToplevelIsControlledByWm(winPtr)) {
8522	Tk_MoveToplevelWindow((Tk_Window)winPtr, x, y);
8523    }
8524    return ((winPtr->changes.x << 16) & 0xffff0000)
8525	    | (winPtr->changes.y & 0xffff);
8526}
8527
8528/*
8529 *----------------------------------------------------------------------
8530 *
8531 * TkpWinToplevelOverrideRedirect --
8532 *
8533 *	This function is to be used by a container to overrideredirect the
8534 *	contaner's frame window.
8535 *
8536 * Results:
8537 *	The current overrideredirect value
8538 *
8539 * Side effects:
8540 *	May change the overrideredirect value of the container window
8541 *
8542 *----------------------------------------------------------------------
8543 */
8544
8545long
8546TkpWinToplevelOverrideRedirect(
8547    TkWindow *winPtr,
8548    int reqValue)
8549{
8550    int curValue;
8551    register WmInfo *wmPtr = winPtr->wmInfoPtr;
8552
8553    curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect;
8554    if(reqValue < 0) return curValue;
8555
8556    if (curValue != reqValue) {
8557	XSetWindowAttributes atts;
8558
8559	/*
8560	 * Only do this if we are really changing value, because it causes
8561	 * some funky stuff to occur
8562	 */
8563
8564	atts.override_redirect = reqValue ? True : False;
8565	Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
8566		&atts);
8567	if (!(wmPtr->flags & (WM_NEVER_MAPPED))
8568		&& !(winPtr->flags & TK_EMBEDDED)) {
8569	    UpdateWrapper(winPtr);
8570	}
8571    }
8572    return reqValue;
8573}
8574
8575/*
8576 *----------------------------------------------------------------------
8577 *
8578 * TkpWinToplevelDetachWindow --
8579 *
8580 *	This function is to be usd for changing a toplevel's wrapper or
8581 *	container.
8582 *
8583 * Results:
8584 *	The window's wrapper/container is removed.
8585 *
8586 * Side effects:
8587 *	None.
8588 *
8589 *----------------------------------------------------------------------
8590 */
8591
8592void
8593TkpWinToplevelDetachWindow(
8594    TkWindow *winPtr)
8595{
8596    register WmInfo *wmPtr = winPtr->wmInfoPtr;
8597
8598    if (winPtr->flags & TK_EMBEDDED) {
8599	int state = SendMessage(wmPtr->wrapper, TK_STATE, -1, -1) - 1;
8600
8601	SendMessage(wmPtr->wrapper, TK_SETMENU, 0, 0);
8602	SendMessage(wmPtr->wrapper, TK_DETACHWINDOW, 0, 0);
8603	winPtr->flags &= ~TK_EMBEDDED;
8604	winPtr->privatePtr = NULL;
8605	wmPtr->wrapper = None;
8606	if (state >= 0 && state <= 3) {
8607	    wmPtr->hints.initial_state = state;
8608	}
8609    }
8610    if (winPtr->flags & TK_TOP_LEVEL) {
8611	TkpWinToplevelOverrideRedirect(winPtr, 1);
8612    }
8613}
8614
8615/*
8616 *----------------------------------------------------------------------
8617 *
8618 * RemapWindows
8619 *
8620 *	Adjust parent/child relation ships of
8621 *	the given window hierarchy.
8622 *
8623 * Results:
8624 *	none
8625 *
8626 * Side effects:
8627 *	keeps windowing system happy
8628 *
8629 *----------------------------------------------------------------------
8630 */
8631
8632static void
8633RemapWindows(winPtr, parentHWND)
8634     TkWindow *winPtr;
8635     HWND parentHWND;
8636{
8637    TkWindow *childPtr;
8638
8639    /* Skip Menus as they are handled differently */
8640    if (strcmp(Tk_Class(winPtr), "Menu") == 0) {
8641	return;
8642    }
8643    if (winPtr->window) {
8644	SetParent(Tk_GetHWND(winPtr->window), parentHWND);
8645    }
8646
8647    /* Repeat for all the children */
8648    for (childPtr = winPtr->childList; childPtr != NULL;
8649	 childPtr = childPtr->nextPtr) {
8650	RemapWindows(childPtr,
8651		winPtr->window ? Tk_GetHWND(winPtr->window) : NULL);
8652    }
8653}
8654
8655/*
8656 * Local Variables:
8657 * mode: c
8658 * c-basic-offset: 4
8659 * fill-column: 78
8660 * End:
8661 */
8662