1/*
2 * tkMacOSXWm.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) 1994-1997 Sun Microsystems, Inc.
10 * Copyright 2001-2009, Apple Inc.
11 * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
12 *
13 * See the file "license.terms" for information on usage and redistribution
14 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 *
16 * RCS: @(#) $Id$
17 */
18
19#include "tkMacOSXPrivate.h"
20#include "tkScrollbar.h"
21#include "tkMacOSXWm.h"
22#include "tkMacOSXEvent.h"
23#include "tkMacOSXDebug.h"
24
25/*
26#ifdef TK_MAC_DEBUG
27#define TK_MAC_DEBUG_WINDOWS
28#endif
29*/
30
31/*
32 * Window attributes and classes
33 */
34
35#define WM_NSMASK_SHIFT 36
36#define tkWindowDoesNotHideAttribute \
37	((UInt64) 1 << kHIWindowBitDoesNotHide)
38#define tkCanJoinAllSpacesAttribute \
39	((UInt64) NSWindowCollectionBehaviorCanJoinAllSpaces << 34)
40#define tkMoveToActiveSpaceAttribute \
41	((UInt64) NSWindowCollectionBehaviorMoveToActiveSpace << 34)
42#define tkNonactivatingPanelAttribute \
43	((UInt64) NSNonactivatingPanelMask << WM_NSMASK_SHIFT)
44#define tkHUDWindowAttribute \
45	((UInt64) NSHUDWindowMask << WM_NSMASK_SHIFT)
46#define tkAlwaysValidAttributes (kWindowNoUpdatesAttribute \
47	| kWindowNoActivatesAttribute	    | kWindowHideOnSuspendAttribute \
48	| kWindowHideOnFullScreenAttribute  | kWindowNoConstrainAttribute \
49	| kWindowNoShadowAttribute	    | kWindowLiveResizeAttribute \
50	| kWindowOpaqueForEventsAttribute   | kWindowIgnoreClicksAttribute \
51	| kWindowDoesNotCycleAttribute	    | tkWindowDoesNotHideAttribute \
52	| tkCanJoinAllSpacesAttribute	    | tkMoveToActiveSpaceAttribute \
53	| tkNonactivatingPanelAttribute	    | tkHUDWindowAttribute)
54
55static const struct {
56    const UInt64 validAttrs, defaultAttrs, forceOnAttrs, forceOffAttrs;
57    int flags; NSUInteger styleMask;
58} macClassAttrs[] = {
59    [kAlertWindowClass] = {
60	.defaultAttrs = kWindowDoesNotCycleAttribute, },
61    [kMovableAlertWindowClass] = {
62	.defaultAttrs = kWindowDoesNotCycleAttribute, },
63    [kModalWindowClass] = {
64	.defaultAttrs = kWindowDoesNotCycleAttribute, },
65    [kMovableModalWindowClass] = {
66	.validAttrs = kWindowCloseBoxAttribute | kWindowMetalAttribute |
67		kWindowFullZoomAttribute | kWindowResizableAttribute,
68	.defaultAttrs = kWindowDoesNotCycleAttribute, },
69    [kFloatingWindowClass] = {
70	.validAttrs = kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute |
71		kWindowMetalAttribute | kWindowToolbarButtonAttribute |
72		kWindowNoTitleBarAttribute | kWindowFullZoomAttribute |
73		kWindowResizableAttribute | kWindowSideTitlebarAttribute,
74	.defaultAttrs = kWindowStandardFloatingAttributes |
75		kWindowHideOnSuspendAttribute | kWindowDoesNotCycleAttribute,
76	.forceOnAttrs = kWindowResizableAttribute,
77	.forceOffAttrs = kWindowCollapseBoxAttribute,
78	.styleMask = NSUtilityWindowMask, },
79    [kDocumentWindowClass] = {
80	.validAttrs = kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute |
81		kWindowMetalAttribute | kWindowToolbarButtonAttribute |
82		kWindowNoTitleBarAttribute |
83		kWindowUnifiedTitleAndToolbarAttribute |
84		kWindowInWindowMenuAttribute | kWindowFullZoomAttribute |
85		kWindowResizableAttribute,
86	.forceOnAttrs = kWindowResizableAttribute,
87	.defaultAttrs = kWindowStandardDocumentAttributes |
88		kWindowLiveResizeAttribute | kWindowInWindowMenuAttribute, },
89    [kUtilityWindowClass] = {
90	.validAttrs = kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute |
91		kWindowMetalAttribute | kWindowToolbarButtonAttribute |
92		kWindowNoTitleBarAttribute | kWindowFullZoomAttribute |
93		kWindowResizableAttribute | kWindowSideTitlebarAttribute,
94	.defaultAttrs = kWindowStandardFloatingAttributes |
95		kWindowHideOnFullScreenAttribute |
96		tkWindowDoesNotHideAttribute | tkNonactivatingPanelAttribute |
97		kWindowDoesNotCycleAttribute,
98	.forceOnAttrs = kWindowResizableAttribute,
99	.forceOffAttrs = kWindowCollapseBoxAttribute,
100	.flags = WM_TOPMOST,
101	.styleMask = NSUtilityWindowMask, },
102    [kHelpWindowClass] = {
103	.defaultAttrs = kWindowHideOnSuspendAttribute,
104	.forceOnAttrs = kWindowNoTitleBarAttribute |
105		kWindowDoesNotCycleAttribute,
106	.flags = WM_TOPMOST, },
107    [kSheetWindowClass] = {
108	.validAttrs = kWindowResizableAttribute,
109	.forceOnAttrs = kWindowNoTitleBarAttribute |
110		kWindowDoesNotCycleAttribute,
111	.styleMask = NSDocModalWindowMask, },
112    [kToolbarWindowClass] = {
113	.defaultAttrs = kWindowHideOnSuspendAttribute,
114	.forceOnAttrs = kWindowNoTitleBarAttribute |
115		kWindowDoesNotCycleAttribute,
116	.styleMask = NSUtilityWindowMask, },
117    [kPlainWindowClass] = {
118	.defaultAttrs = kWindowDoesNotCycleAttribute,
119	.forceOnAttrs = kWindowNoTitleBarAttribute, },
120    [kOverlayWindowClass] = {
121	.forceOnAttrs = kWindowNoTitleBarAttribute |
122		kWindowDoesNotCycleAttribute,
123	.flags = WM_TOPMOST | WM_TRANSPARENT, },
124    [kSheetAlertWindowClass] = {
125	.forceOnAttrs = kWindowNoTitleBarAttribute |
126		kWindowDoesNotCycleAttribute,
127	.styleMask = NSDocModalWindowMask, },
128    [kAltPlainWindowClass] = {
129	.defaultAttrs = kWindowDoesNotCycleAttribute,
130	.forceOnAttrs = kWindowNoTitleBarAttribute, },
131    [kSimpleWindowClass] = {
132	.defaultAttrs = kWindowDoesNotCycleAttribute,
133	.forceOnAttrs = kWindowNoTitleBarAttribute, },
134    [kDrawerWindowClass] = {
135	.validAttrs = kWindowMetalAttribute | kWindowResizableAttribute,
136	.forceOnAttrs = kWindowNoTitleBarAttribute |
137		kWindowDoesNotCycleAttribute, },
138};
139
140#define ForceAttributes(attributes, class) \
141	((attributes) & (~macClassAttrs[(class)].forceOffAttrs | \
142	(macClassAttrs[(class)].forceOnAttrs & ~kWindowResizableAttribute)))
143
144/*
145 * Data for [wm attributes] command:
146 */
147
148typedef enum {
149    WMATT_ALPHA, WMATT_FULLSCREEN, WMATT_MODIFIED, WMATT_NOTIFY,
150    WMATT_TITLEPATH, WMATT_TOPMOST, WMATT_TRANSPARENT,
151    _WMATT_LAST_ATTRIBUTE
152} WmAttribute;
153
154static const char *WmAttributeNames[] = {
155    "-alpha", "-fullscreen", "-modified", "-notify",
156    "-titlepath", "-topmost", "-transparent",
157    NULL
158};
159
160/*
161 * The variable below is used to enable or disable tracing in this module. If
162 * tracing is enabled, then information is printed on standard output about
163 * interesting interactions with the window manager.
164 */
165
166static int wmTracing = 0;
167
168/*
169 * The following structure is the official type record for geometry management
170 * of top-level windows.
171 */
172
173static void TopLevelReqProc(ClientData dummy, Tk_Window tkwin);
174
175static const Tk_GeomMgr wmMgrType = {
176    "wm",			/* name */
177    TopLevelReqProc,		/* requestProc */
178    NULL,			/* lostSlaveProc */
179};
180
181/*
182 * The following keeps state for Aqua dock icon bounce notification.
183 */
184
185static int tkMacOSXWmAttrNotifyVal = 0;
186
187/*
188 * Hash table for Mac Window -> TkWindow mapping.
189 */
190
191static Tcl_HashTable windowTable;
192static int windowHashInit = false;
193
194/*
195 * Forward declarations for procedures defined in this file:
196 */
197
198static NSRect		InitialWindowBounds(TkWindow *winPtr,
199			    NSWindow *macWindow);
200static int		ParseGeometry(Tcl_Interp *interp, char *string,
201			    TkWindow *winPtr);
202static void		TopLevelEventProc(ClientData clientData,
203			    XEvent *eventPtr);
204static void		WmStackorderToplevelWrapperMap(TkWindow *winPtr,
205			    Display *display, Tcl_HashTable *table);
206static void		UpdateGeometryInfo(ClientData clientData);
207static void		UpdateSizeHints(TkWindow *winPtr);
208static void		UpdateVRootGeometry(WmInfo *wmPtr);
209static int		WmAspectCmd(Tk_Window tkwin, TkWindow *winPtr,
210			    Tcl_Interp *interp, int objc,
211			    Tcl_Obj *const objv[]);
212static int		WmAttributesCmd(Tk_Window tkwin, TkWindow *winPtr,
213			    Tcl_Interp *interp, int objc,
214			    Tcl_Obj *const objv[]);
215static int		WmClientCmd(Tk_Window tkwin, TkWindow *winPtr,
216			    Tcl_Interp *interp, int objc,
217			    Tcl_Obj *const objv[]);
218static int		WmColormapwindowsCmd(Tk_Window tkwin,
219			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
220			    Tcl_Obj *const objv[]);
221static int		WmCommandCmd(Tk_Window tkwin, TkWindow *winPtr,
222			    Tcl_Interp *interp, int objc,
223			    Tcl_Obj *const objv[]);
224static int		WmDeiconifyCmd(Tk_Window tkwin, TkWindow *winPtr,
225			    Tcl_Interp *interp, int objc,
226			    Tcl_Obj *const objv[]);
227static int		WmFocusmodelCmd(Tk_Window tkwin, TkWindow *winPtr,
228			    Tcl_Interp *interp, int objc,
229			    Tcl_Obj *const objv[]);
230static int		WmForgetCmd(Tk_Window tkwin, TkWindow *winPtr,
231			    Tcl_Interp *interp, int objc,
232			    Tcl_Obj *const objv[]);
233static int		WmFrameCmd(Tk_Window tkwin, TkWindow *winPtr,
234			    Tcl_Interp *interp, int objc,
235			    Tcl_Obj *const objv[]);
236static int		WmGeometryCmd(Tk_Window tkwin, TkWindow *winPtr,
237			    Tcl_Interp *interp, int objc,
238			    Tcl_Obj *const objv[]);
239static int		WmGridCmd(Tk_Window tkwin, TkWindow *winPtr,
240			    Tcl_Interp *interp, int objc,
241			    Tcl_Obj *const objv[]);
242static int		WmGroupCmd(Tk_Window tkwin, TkWindow *winPtr,
243			    Tcl_Interp *interp, int objc,
244			    Tcl_Obj *const objv[]);
245static int		WmIconbitmapCmd(Tk_Window tkwin, TkWindow *winPtr,
246			    Tcl_Interp *interp, int objc,
247			    Tcl_Obj *const objv[]);
248static int		WmIconifyCmd(Tk_Window tkwin, TkWindow *winPtr,
249			    Tcl_Interp *interp, int objc,
250			    Tcl_Obj *const objv[]);
251static int		WmIconmaskCmd(Tk_Window tkwin, TkWindow *winPtr,
252			    Tcl_Interp *interp, int objc,
253			    Tcl_Obj *const objv[]);
254static int		WmIconnameCmd(Tk_Window tkwin, TkWindow *winPtr,
255			    Tcl_Interp *interp, int objc,
256			    Tcl_Obj *const objv[]);
257static int		WmIconphotoCmd(Tk_Window tkwin, TkWindow *winPtr,
258			    Tcl_Interp *interp, int objc,
259			    Tcl_Obj *const objv[]);
260static int		WmIconpositionCmd(Tk_Window tkwin, TkWindow *winPtr,
261			    Tcl_Interp *interp, int objc,
262			    Tcl_Obj *const objv[]);
263static int		WmIconwindowCmd(Tk_Window tkwin, TkWindow *winPtr,
264			    Tcl_Interp *interp, int objc,
265			    Tcl_Obj *const objv[]);
266static int		WmManageCmd(Tk_Window tkwin, TkWindow *winPtr,
267			    Tcl_Interp *interp, int objc,
268			    Tcl_Obj *const objv[]);
269static int		WmMaxsizeCmd(Tk_Window tkwin, TkWindow *winPtr,
270			    Tcl_Interp *interp, int objc,
271			    Tcl_Obj *const objv[]);
272static int		WmMinsizeCmd(Tk_Window tkwin, TkWindow *winPtr,
273			    Tcl_Interp *interp, int objc,
274			    Tcl_Obj *const objv[]);
275static int		WmOverrideredirectCmd(Tk_Window tkwin,
276			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
277			    Tcl_Obj *const objv[]);
278static int		WmPositionfromCmd(Tk_Window tkwin, TkWindow *winPtr,
279			    Tcl_Interp *interp, int objc,
280			    Tcl_Obj *const objv[]);
281static int		WmProtocolCmd(Tk_Window tkwin, TkWindow *winPtr,
282			    Tcl_Interp *interp, int objc,
283			    Tcl_Obj *const objv[]);
284static int		WmResizableCmd(Tk_Window tkwin, TkWindow *winPtr,
285			    Tcl_Interp *interp, int objc,
286			    Tcl_Obj *const objv[]);
287static int		WmSizefromCmd(Tk_Window tkwin, TkWindow *winPtr,
288			    Tcl_Interp *interp, int objc,
289			    Tcl_Obj *const objv[]);
290static int		WmStackorderCmd(Tk_Window tkwin, TkWindow *winPtr,
291			    Tcl_Interp *interp, int objc,
292			    Tcl_Obj *const objv[]);
293static int		WmStateCmd(Tk_Window tkwin, TkWindow *winPtr,
294			    Tcl_Interp *interp, int objc,
295			    Tcl_Obj *const objv[]);
296static int		WmTitleCmd(Tk_Window tkwin, TkWindow *winPtr,
297			    Tcl_Interp *interp, int objc,
298			    Tcl_Obj *const objv[]);
299static int		WmTransientCmd(Tk_Window tkwin, TkWindow *winPtr,
300			    Tcl_Interp *interp, int objc,
301			    Tcl_Obj *const objv[]);
302static int		WmWithdrawCmd(Tk_Window tkwin, TkWindow *winPtr,
303			    Tcl_Interp *interp, int objc,
304			    Tcl_Obj *const objv[]);
305static void		WmUpdateGeom(WmInfo *wmPtr, TkWindow *winPtr);
306static int		WmWinStyle(Tcl_Interp *interp, TkWindow *winPtr,
307			    int objc, Tcl_Obj *const objv[]);
308static void		ApplyWindowAttributeFlagChanges(TkWindow *winPtr,
309			    NSWindow *macWindow, UInt64 oldAttributes,
310			    int oldFlags, int create, int initial);
311static void		ApplyMasterOverrideChanges(TkWindow *winPtr,
312			    NSWindow *macWindow);
313static void		GetMinSize(TkWindow *winPtr, int *minWidthPtr,
314			    int *minHeightPtr);
315static void		GetMaxSize(TkWindow *winPtr, int *maxWidthPtr,
316			    int *maxHeightPtr);
317static void		RemapWindows(TkWindow *winPtr,
318			    MacDrawable *parentWin);
319
320#pragma mark TKWindow(TKWm)
321
322#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
323@interface NSWindow(TkWm)
324- (void)setCanCycle:(BOOL)canCycleFlag;
325@end
326#endif
327
328@interface NSDrawerWindow : NSWindow
329{
330    id _i1, _i2;
331}
332@end
333
334@implementation TKWindow
335@end
336
337@implementation TKWindow(TKWm)
338- (BOOL)canBecomeKeyWindow {
339    TkWindow *winPtr = TkMacOSXGetTkWindow(self);
340
341    return (winPtr && winPtr->wmInfoPtr && (winPtr->wmInfoPtr->macClass ==
342	    kHelpWindowClass || winPtr->wmInfoPtr->attributes &
343	    kWindowNoActivatesAttribute)) ? NO : YES;
344}
345@end
346
347#pragma mark -
348
349/*
350 *----------------------------------------------------------------------
351 *
352 * SetWindowSizeLimits --
353 *
354 *	Sets NSWindow size limits
355 *
356 * Results:
357 *	None.
358 *
359 * Side effects:
360 *	None.
361 *
362 *----------------------------------------------------------------------
363 */
364
365static void
366SetWindowSizeLimits(
367    TkWindow *winPtr)
368{
369    NSWindow *macWindow = TkMacOSXDrawableWindow(winPtr->window);
370    WmInfo *wmPtr = winPtr->wmInfoPtr;
371    int minWidth, minHeight, maxWidth, maxHeight, base;
372
373    if (!macWindow) {
374	return;
375    }
376    GetMinSize(winPtr, &minWidth, &minHeight);
377    GetMaxSize(winPtr, &maxWidth, &maxHeight);
378    if (wmPtr->gridWin) {
379	base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
380	if (base < 0) {
381	    base = 0;
382	}
383	minWidth = base + (minWidth * wmPtr->widthInc);
384	maxWidth = base + (maxWidth * wmPtr->widthInc);
385	base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
386	if (base < 0) {
387	    base = 0;
388	}
389	minHeight = base + (minHeight * wmPtr->heightInc);
390	maxHeight = base + (maxHeight * wmPtr->heightInc);
391    }
392    if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
393	minWidth = maxWidth = wmPtr->configWidth;
394    }
395    if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
396	minHeight = maxHeight = wmPtr->configHeight;
397    }
398    if (wmPtr->gridWin) {
399	[macWindow setResizeIncrements:NSMakeSize(wmPtr->widthInc,
400		wmPtr->heightInc)];
401    } else if (wmPtr->sizeHintsFlags & PAspect && wmPtr->minAspect.x ==
402	    wmPtr->maxAspect.x && wmPtr->minAspect.y == wmPtr->maxAspect.y) {
403	NSSize aspect = NSMakeSize(wmPtr->minAspect.x, wmPtr->minAspect.y);
404	CGFloat ratio = aspect.width/aspect.height;
405	[macWindow setContentAspectRatio:aspect];
406	if ((CGFloat)minWidth/(CGFloat)minHeight > ratio) {
407	    minHeight = lround(minWidth / ratio);
408	} else {
409	    minWidth = lround(minHeight * ratio);
410	}
411	if ((CGFloat)maxWidth/(CGFloat)maxHeight > ratio) {
412	    maxWidth = lround(maxHeight * ratio);
413	} else {
414	    maxHeight = lround(maxWidth / ratio);
415	}
416	if ((CGFloat)wmPtr->configWidth/(CGFloat)wmPtr->configHeight > ratio) {
417	    wmPtr->configWidth = lround(wmPtr->configHeight * ratio);
418	    if (wmPtr->configWidth < minWidth) {
419		wmPtr->configWidth = minWidth;
420		wmPtr->configHeight = minHeight;
421	    }
422	} else {
423	    wmPtr->configHeight = lround(wmPtr->configWidth / ratio);
424	    if (wmPtr->configHeight < minHeight) {
425		wmPtr->configWidth = minWidth;
426		wmPtr->configHeight = minHeight;
427	    }
428	}
429    } else {
430	[macWindow setResizeIncrements:NSMakeSize(1.0, 1.0)];
431    }
432    [macWindow setContentMinSize:NSMakeSize(minWidth, minHeight)];
433    [macWindow setContentMaxSize:NSMakeSize(maxWidth, maxHeight)];
434}
435
436/*
437 *----------------------------------------------------------------------
438 *
439 * FrontWindowAtPoint --
440 *
441 *	Find frontmost toplevel window at a given screen location.
442 *
443 * Results:
444 *	TkWindow*.
445 *
446 * Side effects:
447 *	None.
448 *
449 *----------------------------------------------------------------------
450 */
451
452static TkWindow*
453FrontWindowAtPoint(
454    int x, int y)
455{
456
457    NSPoint p = NSMakePoint(x, tkMacOSXZeroScreenHeight - y);
458    NSWindow *win = nil;
459    NSInteger windowCount;
460    NSInteger *windowNumbers;
461
462    NSCountWindows(&windowCount);
463    if (windowCount) {
464	windowNumbers = (NSInteger *) ckalloc(windowCount * sizeof(NSInteger));
465	NSWindowList(windowCount, windowNumbers);
466	for (NSInteger index = 0; index < windowCount; index++) {
467	    NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]];
468	    if (w && NSMouseInRect(p, [w frame], NO)) {
469		win = w;
470		break;
471	    }
472	}
473	ckfree((char *) windowNumbers);
474    }
475    return (win ? TkMacOSXGetTkWindow(win) : NULL);
476}
477
478
479/*
480 *----------------------------------------------------------------------
481 *
482 * TkWmNewWindow --
483 *
484 *	This procedure is invoked whenever a new top-level window is created.
485 *	Its job is to initialize the WmInfo structure for the window.
486 *
487 * Results:
488 *	None.
489 *
490 * Side effects:
491 *	A WmInfo structure gets allocated and initialized.
492 *
493 *----------------------------------------------------------------------
494 */
495
496void
497TkWmNewWindow(
498    TkWindow *winPtr)		/* Newly-created top-level window. */
499{
500    WmInfo *wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
501
502    wmPtr->winPtr = winPtr;
503    wmPtr->reparent = None;
504    wmPtr->titleUid = NULL;
505    wmPtr->iconName = NULL;
506    wmPtr->master = None;
507    wmPtr->hints.flags = InputHint | StateHint;
508    wmPtr->hints.input = True;
509    wmPtr->hints.initial_state = NormalState;
510    wmPtr->hints.icon_pixmap = None;
511    wmPtr->hints.icon_window = None;
512    wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
513    wmPtr->hints.icon_mask = None;
514    wmPtr->hints.window_group = None;
515    wmPtr->leaderName = NULL;
516    wmPtr->masterWindowName = NULL;
517    wmPtr->icon = NULL;
518    wmPtr->iconFor = NULL;
519    wmPtr->sizeHintsFlags = 0;
520    wmPtr->minWidth = wmPtr->minHeight = 1;
521    wmPtr->maxWidth = 0;
522    wmPtr->maxHeight = 0;
523    wmPtr->gridWin = NULL;
524    wmPtr->widthInc = wmPtr->heightInc = 1;
525    wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
526    wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
527    wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
528    wmPtr->gravity = NorthWestGravity;
529    wmPtr->width = -1;
530    wmPtr->height = -1;
531    wmPtr->x = winPtr->changes.x;
532    wmPtr->y = winPtr->changes.y;
533    wmPtr->parentWidth = winPtr->changes.width
534	    + 2*winPtr->changes.border_width;
535    wmPtr->parentHeight = winPtr->changes.height
536	    + 2*winPtr->changes.border_width;
537    wmPtr->xInParent = 0;
538    wmPtr->yInParent = 0;
539    wmPtr->cmapList = NULL;
540    wmPtr->cmapCount = 0;
541    wmPtr->configX = 0;
542    wmPtr->configY = 0;
543    wmPtr->configWidth = -1;
544    wmPtr->configHeight = -1;
545    wmPtr->vRoot = None;
546    wmPtr->protPtr = NULL;
547    wmPtr->cmdArgv = NULL;
548    wmPtr->clientMachine = NULL;
549    wmPtr->flags = WM_NEVER_MAPPED;
550    wmPtr->macClass = kDocumentWindowClass;
551    wmPtr->attributes = macClassAttrs[kDocumentWindowClass].defaultAttrs;
552    wmPtr->scrollWinPtr = NULL;
553    wmPtr->menuPtr = NULL;
554    wmPtr->window = nil;
555    winPtr->wmInfoPtr = wmPtr;
556
557    UpdateVRootGeometry(wmPtr);
558
559    /*
560     * Tk must monitor structure events for top-level windows, in order to
561     * detect size and position changes caused by window managers.
562     */
563
564    Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
565	    TopLevelEventProc, winPtr);
566
567    /*
568     * Arrange for geometry requests to be reflected from the window to the
569     * window manager.
570     */
571
572    Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
573}
574
575/*
576 *----------------------------------------------------------------------
577 *
578 * TkWmMapWindow --
579 *
580 *	This procedure is invoked to map a top-level window. This module gets
581 *	a chance to update all window-manager-related information in
582 *	properties before the window manager sees the map event and checks the
583 *	properties. It also gets to decide whether or not to even map the
584 *	window after all.
585 *
586 * Results:
587 *	None.
588 *
589 * Side effects:
590 *	Properties of winPtr may get updated to provide up-to-date information
591 *	to the window manager. The window may also get mapped, but it may not
592 *	be if this procedure decides that isn't appropriate (e.g. because the
593 *	window is withdrawn).
594 *
595 *----------------------------------------------------------------------
596 */
597
598void
599TkWmMapWindow(
600    TkWindow *winPtr)		/* Top-level window that's about to be
601				 * mapped. */
602{
603    WmInfo *wmPtr = winPtr->wmInfoPtr;
604
605    if (wmPtr->flags & WM_NEVER_MAPPED) {
606	/*
607	 * Create the underlying Mac window for this Tk window.
608	 */
609
610	if (!TkMacOSXHostToplevelExists(winPtr)) {
611	    TkMacOSXMakeRealWindowExist(winPtr);
612	}
613
614	wmPtr->flags &= ~WM_NEVER_MAPPED;
615
616	/*
617	 * Generate configure event when we first map the window.
618	 */
619
620	TkGenWMConfigureEvent((Tk_Window) winPtr, wmPtr->x, wmPtr->y, -1, -1,
621		TK_LOCATION_CHANGED);
622
623	/*
624	 * This is the first time this window has ever been mapped. Store all
625	 * the window-manager-related information for the window.
626	 */
627
628	if (wmPtr->titleUid == NULL) {
629	    wmPtr->titleUid = winPtr->nameUid;
630	}
631
632	if (!Tk_IsEmbedded(winPtr)) {
633	    TkSetWMName(winPtr, wmPtr->titleUid);
634	}
635
636	TkWmSetClass(winPtr);
637
638	if (wmPtr->iconName != NULL) {
639	    XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
640	}
641
642	wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
643    }
644    if (wmPtr->hints.initial_state == WithdrawnState) {
645	return;
646    }
647
648    /*
649     * TODO: we need to display a window if it's iconic on creation.
650     */
651
652    if (wmPtr->hints.initial_state == IconicState) {
653	return;
654    }
655
656    /*
657     * Update geometry information.
658     */
659
660    wmPtr->flags |= WM_ABOUT_TO_MAP;
661    if (wmPtr->flags & WM_UPDATE_PENDING) {
662	Tk_CancelIdleCall(UpdateGeometryInfo, winPtr);
663    }
664    UpdateGeometryInfo(winPtr);
665    wmPtr->flags &= ~WM_ABOUT_TO_MAP;
666
667    /*
668     * Map the window.
669     */
670
671    XMapWindow(winPtr->display, winPtr->window);
672}
673
674/*
675 *----------------------------------------------------------------------
676 *
677 * TkWmUnmapWindow --
678 *
679 *	This procedure is invoked to unmap a top-level window. On the
680 *	Macintosh all we do is call XUnmapWindow.
681 *
682 * Results:
683 *	None.
684 *
685 * Side effects:
686 *	Unmaps the window.
687 *
688 *----------------------------------------------------------------------
689 */
690
691void
692TkWmUnmapWindow(
693    TkWindow *winPtr)		/* Top-level window that's about to be
694				 * mapped. */
695{
696    XUnmapWindow(winPtr->display, winPtr->window);
697}
698
699/*
700 *----------------------------------------------------------------------
701 *
702 * TkWmDeadWindow --
703 *
704 *	This procedure is invoked when a top-level window is about to be
705 *	deleted. It cleans up the wm-related data structures for the window.
706 *
707 * Results:
708 *	None.
709 *
710 * Side effects:
711 *	The WmInfo structure for winPtr gets freed up.
712 *
713 *----------------------------------------------------------------------
714 */
715
716void
717TkWmDeadWindow(
718    TkWindow *winPtr)		/* Top-level window that's being deleted. */
719{
720    WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2;
721
722    if (wmPtr == NULL) {
723	return;
724    }
725    if (wmPtr->hints.flags & IconPixmapHint) {
726	Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
727    }
728    if (wmPtr->hints.flags & IconMaskHint) {
729	Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
730    }
731    if (wmPtr->iconName != NULL) {
732	ckfree(wmPtr->iconName);
733    }
734    if (wmPtr->leaderName != NULL) {
735	ckfree(wmPtr->leaderName);
736    }
737    if (wmPtr->masterWindowName != NULL) {
738	ckfree(wmPtr->masterWindowName);
739    }
740    if (wmPtr->icon != NULL) {
741	wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
742	wmPtr2->iconFor = NULL;
743    }
744    if (wmPtr->iconFor != NULL) {
745	wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
746	wmPtr2->icon = NULL;
747	wmPtr2->hints.flags &= ~IconWindowHint;
748    }
749    while (wmPtr->protPtr != NULL) {
750	ProtocolHandler *protPtr;
751
752	protPtr = wmPtr->protPtr;
753	wmPtr->protPtr = protPtr->nextPtr;
754	Tcl_EventuallyFree(protPtr, TCL_DYNAMIC);
755    }
756    if (wmPtr->cmdArgv != NULL) {
757	ckfree((char *) wmPtr->cmdArgv);
758    }
759    if (wmPtr->clientMachine != NULL) {
760	ckfree((char *) wmPtr->clientMachine);
761    }
762    if (wmPtr->flags & WM_UPDATE_PENDING) {
763	Tk_CancelIdleCall(UpdateGeometryInfo, winPtr);
764    }
765
766    /*
767     * Delete the Mac window and remove it from the windowTable. The window
768     * could be nil if the window was never mapped. However, we don't do this
769     * for embedded windows, they don't go in the window list, and they do not
770     * own their portPtr's.
771     */
772
773    NSWindow *window = wmPtr->window;
774    if (window && !Tk_IsEmbedded(winPtr) ) {
775	[[window parentWindow] removeChildWindow:window];
776	[window close];
777	TkMacOSXUnregisterMacWindow(window);
778	if (winPtr->window) {
779	    ((MacDrawable *)winPtr->window)->view = nil;
780	}
781	TkMacOSXMakeCollectableAndRelease(wmPtr->window);
782    }
783
784    ckfree((char *) wmPtr);
785    winPtr->wmInfoPtr = NULL;
786}
787
788/*
789 *----------------------------------------------------------------------
790 *
791 * TkWmSetClass --
792 *
793 *	This procedure is invoked whenever a top-level window's class is
794 *	changed. If the window has been mapped then this procedure updates the
795 *	window manager property for the class. If the window hasn't been
796 *	mapped, the update is deferred until just before the first mapping.
797 *
798 * Results:
799 *	None.
800 *
801 * Side effects:
802 *	A window property may get updated.
803 *
804 *----------------------------------------------------------------------
805 */
806
807void
808TkWmSetClass(
809    TkWindow *winPtr)		/* Newly-created top-level window. */
810{
811    return;
812}
813
814/*
815 *----------------------------------------------------------------------
816 *
817 * Tk_WmObjCmd --
818 *
819 *	This procedure is invoked to process the "wm" Tcl command. See the
820 *	user documentation for details on what it does.
821 *
822 * Results:
823 *	A standard Tcl result.
824 *
825 * Side effects:
826 *	See the user documentation.
827 *
828 *----------------------------------------------------------------------
829 */
830
831/* ARGSUSED */
832int
833Tk_WmObjCmd(
834    ClientData clientData,	/* Main window associated with interpreter. */
835    Tcl_Interp *interp,		/* Current interpreter. */
836    int objc,			/* Number of arguments. */
837    Tcl_Obj *const objv[])	/* Argument objects. */
838{
839    Tk_Window tkwin = (Tk_Window) clientData;
840    static const char *optionStrings[] = {
841	"aspect", "attributes", "client", "colormapwindows",
842	"command", "deiconify", "focusmodel", "forget",
843	"frame", "geometry", "grid", "group",
844	"iconbitmap", "iconify", "iconmask", "iconname",
845	"iconphoto", "iconposition", "iconwindow",
846	"manage", "maxsize", "minsize", "overrideredirect",
847	"positionfrom", "protocol", "resizable", "sizefrom",
848	"stackorder", "state", "title", "transient",
849	"withdraw", NULL };
850    enum options {
851	WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS,
852	WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FORGET,
853	WMOPT_FRAME, WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP,
854	WMOPT_ICONBITMAP, WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME,
855	WMOPT_ICONPHOTO, WMOPT_ICONPOSITION, WMOPT_ICONWINDOW,
856	WMOPT_MANAGE, WMOPT_MAXSIZE, WMOPT_MINSIZE, WMOPT_OVERRIDEREDIRECT,
857	WMOPT_POSITIONFROM, WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM,
858	WMOPT_STACKORDER, WMOPT_STATE, WMOPT_TITLE, WMOPT_TRANSIENT,
859	WMOPT_WITHDRAW };
860    int index, length;
861    char *argv1;
862    TkWindow *winPtr;
863
864    if (objc < 2) {
865    wrongNumArgs:
866	Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg ...?");
867	return TCL_ERROR;
868    }
869
870    argv1 = Tcl_GetStringFromObj(objv[1], &length);
871    if ((argv1[0] == 't') && (strncmp(argv1, "tracing", length) == 0)
872	&& (length >= 3)) {
873	if ((objc != 2) && (objc != 3)) {
874	    Tcl_WrongNumArgs(interp, 2, objv, "?boolean?");
875	    return TCL_ERROR;
876	}
877	if (objc == 2) {
878	    Tcl_SetResult(interp, ((wmTracing) ? "on" : "off"), TCL_STATIC);
879	    return TCL_OK;
880	}
881	return Tcl_GetBooleanFromObj(interp, objv[2], &wmTracing);
882    }
883
884    if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
885	    &index) != TCL_OK) {
886	return TCL_ERROR;
887    }
888
889    if (objc < 3) {
890	goto wrongNumArgs;
891    }
892
893    if (TkGetWindowFromObj(interp, tkwin, objv[2], (Tk_Window *) &winPtr)
894	!= TCL_OK) {
895	return TCL_ERROR;
896    }
897    if (!Tk_IsTopLevel(winPtr)
898	    && (index != WMOPT_MANAGE) && (index != WMOPT_FORGET)) {
899	Tcl_AppendResult(interp, "window \"", winPtr->pathName,
900		"\" isn't a top-level window", NULL);
901	return TCL_ERROR;
902    }
903
904    switch ((enum options) index) {
905    case WMOPT_ASPECT:
906	return WmAspectCmd(tkwin, winPtr, interp, objc, objv);
907    case WMOPT_ATTRIBUTES:
908	return WmAttributesCmd(tkwin, winPtr, interp, objc, objv);
909    case WMOPT_CLIENT:
910	return WmClientCmd(tkwin, winPtr, interp, objc, objv);
911    case WMOPT_COLORMAPWINDOWS:
912	return WmColormapwindowsCmd(tkwin, winPtr, interp, objc, objv);
913    case WMOPT_COMMAND:
914	return WmCommandCmd(tkwin, winPtr, interp, objc, objv);
915    case WMOPT_DEICONIFY:
916	return WmDeiconifyCmd(tkwin, winPtr, interp, objc, objv);
917    case WMOPT_FOCUSMODEL:
918	return WmFocusmodelCmd(tkwin, winPtr, interp, objc, objv);
919    case WMOPT_FORGET:
920	return WmForgetCmd(tkwin, winPtr, interp, objc, objv);
921    case WMOPT_FRAME:
922	return WmFrameCmd(tkwin, winPtr, interp, objc, objv);
923    case WMOPT_GEOMETRY:
924	return WmGeometryCmd(tkwin, winPtr, interp, objc, objv);
925    case WMOPT_GRID:
926	return WmGridCmd(tkwin, winPtr, interp, objc, objv);
927    case WMOPT_GROUP:
928	return WmGroupCmd(tkwin, winPtr, interp, objc, objv);
929    case WMOPT_ICONBITMAP:
930	return WmIconbitmapCmd(tkwin, winPtr, interp, objc, objv);
931    case WMOPT_ICONIFY:
932	return WmIconifyCmd(tkwin, winPtr, interp, objc, objv);
933    case WMOPT_ICONMASK:
934	return WmIconmaskCmd(tkwin, winPtr, interp, objc, objv);
935    case WMOPT_ICONNAME:
936	return WmIconnameCmd(tkwin, winPtr, interp, objc, objv);
937    case WMOPT_ICONPHOTO:
938	return WmIconphotoCmd(tkwin, winPtr, interp, objc, objv);
939    case WMOPT_ICONPOSITION:
940	return WmIconpositionCmd(tkwin, winPtr, interp, objc, objv);
941    case WMOPT_ICONWINDOW:
942	return WmIconwindowCmd(tkwin, winPtr, interp, objc, objv);
943    case WMOPT_MANAGE:
944	return WmManageCmd(tkwin, winPtr, interp, objc, objv);
945    case WMOPT_MAXSIZE:
946	return WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv);
947    case WMOPT_MINSIZE:
948	return WmMinsizeCmd(tkwin, winPtr, interp, objc, objv);
949    case WMOPT_OVERRIDEREDIRECT:
950	return WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv);
951    case WMOPT_POSITIONFROM:
952	return WmPositionfromCmd(tkwin, winPtr, interp, objc, objv);
953    case WMOPT_PROTOCOL:
954	return WmProtocolCmd(tkwin, winPtr, interp, objc, objv);
955    case WMOPT_RESIZABLE:
956	return WmResizableCmd(tkwin, winPtr, interp, objc, objv);
957    case WMOPT_SIZEFROM:
958	return WmSizefromCmd(tkwin, winPtr, interp, objc, objv);
959    case WMOPT_STACKORDER:
960	return WmStackorderCmd(tkwin, winPtr, interp, objc, objv);
961    case WMOPT_STATE:
962	return WmStateCmd(tkwin, winPtr, interp, objc, objv);
963    case WMOPT_TITLE:
964	return WmTitleCmd(tkwin, winPtr, interp, objc, objv);
965    case WMOPT_TRANSIENT:
966	return WmTransientCmd(tkwin, winPtr, interp, objc, objv);
967    case WMOPT_WITHDRAW:
968	return WmWithdrawCmd(tkwin, winPtr, interp, objc, objv);
969    }
970
971    /* This should not happen */
972    return TCL_ERROR;
973}
974
975/*
976 *----------------------------------------------------------------------
977 *
978 * WmAspectCmd --
979 *
980 *	This procedure is invoked to process the "wm aspect" Tcl command. See
981 *	the user documentation for details on what it does.
982 *
983 * Results:
984 *	A standard Tcl result.
985 *
986 * Side effects:
987 *	See the user documentation.
988 *
989 *----------------------------------------------------------------------
990 */
991
992static int
993WmAspectCmd(
994    Tk_Window tkwin,		/* Main window of the application. */
995    TkWindow *winPtr,		/* Toplevel to work with */
996    Tcl_Interp *interp,		/* Current interpreter. */
997    int objc,			/* Number of arguments. */
998    Tcl_Obj *const objv[])	/* Argument objects. */
999{
1000    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1001    int numer1, denom1, numer2, denom2;
1002
1003    if ((objc != 3) && (objc != 7)) {
1004	Tcl_WrongNumArgs(interp, 2, objv,
1005		"window ?minNumer minDenom maxNumer maxDenom?");
1006	return TCL_ERROR;
1007    }
1008    if (objc == 3) {
1009	if (wmPtr->sizeHintsFlags & PAspect) {
1010	    char buf[TCL_INTEGER_SPACE * 4];
1011
1012	    sprintf(buf, "%d %d %d %d", wmPtr->minAspect.x,
1013		    wmPtr->minAspect.y, wmPtr->maxAspect.x,
1014		    wmPtr->maxAspect.y);
1015	    Tcl_SetResult(interp, buf, TCL_VOLATILE);
1016	}
1017	return TCL_OK;
1018    }
1019    if (*Tcl_GetString(objv[3]) == '\0') {
1020	wmPtr->sizeHintsFlags &= ~PAspect;
1021    } else {
1022	if ((Tcl_GetIntFromObj(interp, objv[3], &numer1) != TCL_OK)
1023		|| (Tcl_GetIntFromObj(interp, objv[4], &denom1) != TCL_OK)
1024		|| (Tcl_GetIntFromObj(interp, objv[5], &numer2) != TCL_OK)
1025		|| (Tcl_GetIntFromObj(interp, objv[6], &denom2) != TCL_OK)) {
1026	    return TCL_ERROR;
1027	}
1028	if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
1029		(denom2 <= 0)) {
1030	    Tcl_SetResult(interp, "aspect number can't be <= 0", TCL_STATIC);
1031	    return TCL_ERROR;
1032	}
1033	wmPtr->minAspect.x = numer1;
1034	wmPtr->minAspect.y = denom1;
1035	wmPtr->maxAspect.x = numer2;
1036	wmPtr->maxAspect.y = denom2;
1037	wmPtr->sizeHintsFlags |= PAspect;
1038    }
1039    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1040    WmUpdateGeom(wmPtr, winPtr);
1041    return TCL_OK;
1042}
1043
1044/*
1045 *----------------------------------------------------------------------
1046 *
1047 * WmSetAttribute --
1048 *
1049 *	Helper routine for WmAttributesCmd. Sets the value of the specified
1050 *	attribute.
1051 *
1052 * Returns:
1053 *
1054 *	TCL_OK if successful, TCL_ERROR otherwise. In case of an error, leaves
1055 *	a message in the interpreter's result.
1056 *
1057 *----------------------------------------------------------------------
1058 */
1059
1060static int
1061WmSetAttribute(
1062    TkWindow *winPtr,		/* Toplevel to work with */
1063    NSWindow *macWindow,
1064    Tcl_Interp *interp,		/* Current interpreter */
1065    WmAttribute attribute,	/* Code of attribute to set */
1066    Tcl_Obj *value)		/* New value */
1067{
1068    WmInfo *wmPtr = winPtr->wmInfoPtr;
1069    int boolean;
1070
1071    switch (attribute) {
1072    case WMATT_ALPHA: {
1073	double dval;
1074
1075	if (Tcl_GetDoubleFromObj(interp, value, &dval) != TCL_OK) {
1076	    return TCL_ERROR;
1077	}
1078
1079	/*
1080	 * The user should give (transparent) 0 .. 1.0 (opaque)
1081	 */
1082
1083	if (dval < 0.0) {
1084	    dval = 0.0;
1085	} else if (dval > 1.0) {
1086	    dval = 1.0;
1087	}
1088	[macWindow setAlphaValue:dval];
1089	break;
1090    }
1091    case WMATT_FULLSCREEN:
1092	if (Tcl_GetBooleanFromObj(interp, value, &boolean) != TCL_OK) {
1093	    return TCL_ERROR;
1094	}
1095	if (boolean != ((wmPtr->flags & WM_FULLSCREEN) != 0)) {
1096	    if (TkMacOSXMakeFullscreen(winPtr, macWindow, boolean, interp)
1097		    != TCL_OK) {
1098		return TCL_ERROR;
1099	    }
1100	}
1101	break;
1102    case WMATT_MODIFIED:
1103	if (Tcl_GetBooleanFromObj(interp, value, &boolean) != TCL_OK) {
1104	    return TCL_ERROR;
1105	}
1106	if (boolean != [macWindow isDocumentEdited]) {
1107	    [macWindow setDocumentEdited:boolean];
1108	}
1109	break;
1110    case WMATT_NOTIFY:
1111	if (Tcl_GetBooleanFromObj(interp, value, &boolean) != TCL_OK) {
1112	    return TCL_ERROR;
1113	}
1114	if (boolean == !tkMacOSXWmAttrNotifyVal) {
1115	    static NSInteger request = -1;
1116
1117	    if (request >= 0) {
1118		[NSApp cancelUserAttentionRequest:request];
1119		request = -1;
1120	    }
1121	    if (boolean) {
1122		request = [NSApp requestUserAttention:NSCriticalRequest];
1123	    }
1124	    tkMacOSXWmAttrNotifyVal = boolean;
1125	}
1126	break;
1127    case WMATT_TITLEPATH: {
1128	const char *path = Tcl_FSGetNativePath(value);
1129	NSString *filename = @"";
1130
1131	if (path && *path) {
1132	    filename = [NSString stringWithUTF8String:path];
1133	}
1134	[macWindow setRepresentedFilename:filename];
1135	break;
1136    }
1137    case WMATT_TOPMOST:
1138	if (Tcl_GetBooleanFromObj(interp, value, &boolean) != TCL_OK) {
1139	    return TCL_ERROR;
1140	}
1141	if (boolean != ((wmPtr->flags & WM_TOPMOST) != 0)) {
1142	    int oldFlags = wmPtr->flags;
1143
1144	    if (boolean) {
1145		wmPtr->flags |= WM_TOPMOST;
1146	    } else {
1147		wmPtr->flags &= ~WM_TOPMOST;
1148	    }
1149	    ApplyWindowAttributeFlagChanges(winPtr, macWindow,
1150		    wmPtr->attributes, oldFlags, 1, 0);
1151	}
1152	break;
1153    case WMATT_TRANSPARENT:
1154	if (Tcl_GetBooleanFromObj(interp, value, &boolean) != TCL_OK) {
1155	    return TCL_ERROR;
1156	}
1157	if (boolean != ((wmPtr->flags & WM_TRANSPARENT) != 0)) {
1158	    UInt64 oldAttributes = wmPtr->attributes;
1159	    int oldFlags = wmPtr->flags;
1160
1161	    if (boolean) {
1162		wmPtr->flags |= WM_TRANSPARENT;
1163		wmPtr->attributes |= kWindowNoShadowAttribute;
1164	    } else {
1165		wmPtr->flags &= ~WM_TRANSPARENT;
1166		wmPtr->attributes &= ~kWindowNoShadowAttribute;
1167	    }
1168	    ApplyWindowAttributeFlagChanges(winPtr, macWindow, oldAttributes,
1169		    oldFlags, 1, 0);
1170	    [macWindow setBackgroundColor:boolean ? [NSColor clearColor] : nil];
1171	    [macWindow setOpaque:!boolean];
1172	    TkMacOSXInvalidateWindow((MacDrawable *) winPtr->window,
1173		    TK_PARENT_WINDOW);
1174	    }
1175	break;
1176    case _WMATT_LAST_ATTRIBUTE:
1177    default:
1178	return TCL_ERROR;
1179    }
1180    return TCL_OK;
1181}
1182
1183/*
1184 *----------------------------------------------------------------------
1185 *
1186 * WmGetAttribute --
1187 *
1188 *	Helper routine for WmAttributesCmd. Returns the current value of the
1189 *	specified attribute.
1190 *
1191 *----------------------------------------------------------------------
1192 */
1193
1194static Tcl_Obj *
1195WmGetAttribute(
1196    TkWindow *winPtr,		/* Toplevel to work with */
1197    NSWindow *macWindow,
1198    WmAttribute attribute)	/* Code of attribute to get */
1199{
1200    Tcl_Obj *result = NULL;
1201    WmInfo *wmPtr = winPtr->wmInfoPtr;
1202
1203    switch (attribute) {
1204    case WMATT_ALPHA:
1205	result = Tcl_NewDoubleObj([macWindow alphaValue]);
1206	break;
1207    case WMATT_FULLSCREEN:
1208	result = Tcl_NewBooleanObj(wmPtr->flags & WM_FULLSCREEN);
1209	break;
1210    case WMATT_MODIFIED:
1211	result = Tcl_NewBooleanObj([macWindow isDocumentEdited]);
1212	break;
1213    case WMATT_NOTIFY:
1214	result = Tcl_NewBooleanObj(tkMacOSXWmAttrNotifyVal);
1215	break;
1216    case WMATT_TITLEPATH:
1217	result = Tcl_NewStringObj([[macWindow representedFilename] UTF8String],
1218		-1);
1219	break;
1220    case WMATT_TOPMOST:
1221	result = Tcl_NewBooleanObj(wmPtr->flags & WM_TOPMOST);
1222	break;
1223    case WMATT_TRANSPARENT:
1224	result = Tcl_NewBooleanObj(wmPtr->flags & WM_TRANSPARENT);
1225	break;
1226    case _WMATT_LAST_ATTRIBUTE:
1227    default:
1228	break;
1229    }
1230    return result;
1231}
1232
1233/*
1234 *----------------------------------------------------------------------
1235 *
1236 * WmAttributesCmd --
1237 *
1238 *	This procedure is invoked to process the "wm attributes" Tcl command.
1239 *	See the user documentation for details on what it does.
1240 *
1241 * Results:
1242 *	A standard Tcl result.
1243 *
1244 * Side effects:
1245 *	See the user documentation.
1246 *
1247 *----------------------------------------------------------------------
1248 */
1249
1250static int
1251WmAttributesCmd(
1252    Tk_Window tkwin,		/* Main window of the application. */
1253    TkWindow *winPtr,		/* Toplevel to work with */
1254    Tcl_Interp *interp,		/* Current interpreter. */
1255    int objc,			/* Number of arguments. */
1256    Tcl_Obj *const objv[])	/* Argument objects. */
1257{
1258    int attribute = 0;
1259    NSWindow *macWindow;
1260
1261    if (winPtr->window == None) {
1262	Tk_MakeWindowExist((Tk_Window) winPtr);
1263    }
1264    if (!TkMacOSXHostToplevelExists(winPtr)) {
1265	TkMacOSXMakeRealWindowExist(winPtr);
1266    }
1267    macWindow = TkMacOSXDrawableWindow(winPtr->window);
1268
1269    if (objc == 3) {		/* wm attributes $win */
1270	Tcl_Obj *result = Tcl_NewListObj(0,0);
1271
1272	for (attribute = 0; attribute < _WMATT_LAST_ATTRIBUTE; ++attribute) {
1273	    Tcl_ListObjAppendElement(interp, result,
1274		    Tcl_NewStringObj(WmAttributeNames[attribute], -1));
1275	    Tcl_ListObjAppendElement(interp, result,
1276		    WmGetAttribute(winPtr, macWindow, attribute));
1277	}
1278	Tcl_SetObjResult(interp, result);
1279    } else if (objc == 4)  {	/* wm attributes $win -attribute */
1280	if (Tcl_GetIndexFromObj(interp, objv[3], WmAttributeNames,
1281		    "attribute", 0, &attribute) != TCL_OK) {
1282	    return TCL_ERROR;
1283	}
1284	Tcl_SetObjResult(interp, WmGetAttribute(winPtr, macWindow, attribute));
1285    } else if ((objc - 3) % 2 == 0) {	/* wm attributes $win -att value... */
1286	int i;
1287
1288	for (i = 3; i < objc; i += 2) {
1289	    if (Tcl_GetIndexFromObj(interp, objv[i], WmAttributeNames,
1290			"attribute", 0, &attribute) != TCL_OK) {
1291		return TCL_ERROR;
1292	    }
1293	    if (WmSetAttribute(winPtr, macWindow, interp, attribute, objv[i+1])
1294		    != TCL_OK) {
1295		return TCL_ERROR;
1296	    }
1297	}
1298    } else {
1299	Tcl_WrongNumArgs(interp, 2, objv, "window ?-attribute ?value ...??");
1300	return TCL_ERROR;
1301    }
1302    return TCL_OK;
1303}
1304
1305/*
1306 *----------------------------------------------------------------------
1307 *
1308 * WmClientCmd --
1309 *
1310 *	This procedure is invoked to process the "wm client" Tcl command. See
1311 *	the user documentation for details on what it does.
1312 *
1313 * Results:
1314 *	A standard Tcl result.
1315 *
1316 * Side effects:
1317 *	See the user documentation.
1318 *
1319 *----------------------------------------------------------------------
1320 */
1321
1322static int
1323WmClientCmd(
1324    Tk_Window tkwin,		/* Main window of the application. */
1325    TkWindow *winPtr,		/* Toplevel to work with */
1326    Tcl_Interp *interp,		/* Current interpreter. */
1327    int objc,			/* Number of arguments. */
1328    Tcl_Obj *const objv[])	/* Argument objects. */
1329{
1330    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1331    char *argv3;
1332    int length;
1333
1334    if ((objc != 3) && (objc != 4)) {
1335	Tcl_WrongNumArgs(interp, 2, objv, "window ?name?");
1336	return TCL_ERROR;
1337    }
1338    if (objc == 3) {
1339	if (wmPtr->clientMachine != NULL) {
1340	    Tcl_SetResult(interp, wmPtr->clientMachine, TCL_STATIC);
1341	}
1342	return TCL_OK;
1343    }
1344    argv3 = Tcl_GetStringFromObj(objv[3], &length);
1345    if (argv3[0] == 0) {
1346	if (wmPtr->clientMachine != NULL) {
1347	    ckfree((char *) wmPtr->clientMachine);
1348	    wmPtr->clientMachine = NULL;
1349	}
1350	return TCL_OK;
1351    }
1352    if (wmPtr->clientMachine != NULL) {
1353	ckfree((char *) wmPtr->clientMachine);
1354    }
1355    wmPtr->clientMachine = ckalloc((unsigned) length + 1);
1356    strcpy(wmPtr->clientMachine, argv3);
1357    return TCL_OK;
1358}
1359
1360/*
1361 *----------------------------------------------------------------------
1362 *
1363 * WmColormapwindowsCmd --
1364 *
1365 *	This procedure is invoked to process the "wm colormapwindows" Tcl
1366 *	command. See the user documentation for details on what it does.
1367 *
1368 * Results:
1369 *	A standard Tcl result.
1370 *
1371 * Side effects:
1372 *	See the user documentation.
1373 *
1374 *----------------------------------------------------------------------
1375 */
1376
1377static int
1378WmColormapwindowsCmd(
1379    Tk_Window tkwin,		/* Main window of the application. */
1380    TkWindow *winPtr,		/* Toplevel to work with */
1381    Tcl_Interp *interp,		/* Current interpreter. */
1382    int objc,			/* Number of arguments. */
1383    Tcl_Obj *const objv[])	/* Argument objects. */
1384{
1385    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1386    TkWindow **cmapList;
1387    TkWindow *winPtr2;
1388    int i, windowObjc, gotToplevel = 0;
1389    Tcl_Obj **windowObjv;
1390
1391    if ((objc != 3) && (objc != 4)) {
1392	Tcl_WrongNumArgs(interp, 2, objv, "window ?windowList?");
1393	return TCL_ERROR;
1394    }
1395    if (objc == 3) {
1396	Tk_MakeWindowExist((Tk_Window) winPtr);
1397	for (i = 0; i < wmPtr->cmapCount; i++) {
1398	    if ((i == (wmPtr->cmapCount-1))
1399		&& (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
1400		break;
1401	    }
1402	    Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
1403	}
1404	return TCL_OK;
1405    }
1406    if (Tcl_ListObjGetElements(interp, objv[3], &windowObjc, &windowObjv)
1407	!= TCL_OK) {
1408	return TCL_ERROR;
1409    }
1410    cmapList = (TkWindow **) ckalloc((unsigned)
1411	    ((windowObjc+1) * sizeof(TkWindow*)));
1412    for (i = 0; i < windowObjc; i++) {
1413	if (TkGetWindowFromObj(interp, tkwin, windowObjv[i],
1414		(Tk_Window *) &winPtr2) != TCL_OK) {
1415	    ckfree((char *) cmapList);
1416	    return TCL_ERROR;
1417	}
1418	if (winPtr2 == winPtr) {
1419	    gotToplevel = 1;
1420	}
1421	if (winPtr2->window == None) {
1422	    Tk_MakeWindowExist((Tk_Window) winPtr2);
1423	}
1424	cmapList[i] = winPtr2;
1425    }
1426    if (!gotToplevel) {
1427	wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
1428	cmapList[windowObjc] = winPtr;
1429	windowObjc++;
1430    } else {
1431	wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
1432    }
1433    wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
1434    if (wmPtr->cmapList != NULL) {
1435	ckfree((char *) wmPtr->cmapList);
1436    }
1437    wmPtr->cmapList = cmapList;
1438    wmPtr->cmapCount = windowObjc;
1439
1440    /*
1441     * On the Macintosh all of this is just an excercise in compatability as
1442     * we don't support colormaps. If we did they would be installed here.
1443     */
1444
1445    return TCL_OK;
1446}
1447
1448/*
1449 *----------------------------------------------------------------------
1450 *
1451 * WmCommandCmd --
1452 *
1453 *	This procedure is invoked to process the "wm command" Tcl command. See
1454 *	the user documentation for details on what it does.
1455 *
1456 * Results:
1457 *	A standard Tcl result.
1458 *
1459 * Side effects:
1460 *	See the user documentation.
1461 *
1462 *----------------------------------------------------------------------
1463 */
1464
1465static int
1466WmCommandCmd(
1467    Tk_Window tkwin,		/* Main window of the application. */
1468    TkWindow *winPtr,		/* Toplevel to work with */
1469    Tcl_Interp *interp,		/* Current interpreter. */
1470    int objc,			/* Number of arguments. */
1471    Tcl_Obj *const objv[])	/* Argument objects. */
1472{
1473    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1474    char *argv3;
1475    int cmdArgc;
1476    const char **cmdArgv;
1477
1478    if ((objc != 3) && (objc != 4)) {
1479	Tcl_WrongNumArgs(interp, 2, objv, "window ?value?");
1480	return TCL_ERROR;
1481    }
1482    if (objc == 3) {
1483	if (wmPtr->cmdArgv != NULL) {
1484		argv3 = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
1485	    Tcl_SetResult(interp, argv3, TCL_VOLATILE);
1486	    ckfree(argv3);
1487	}
1488	return TCL_OK;
1489    }
1490    argv3 = Tcl_GetString(objv[3]);
1491    if (argv3[0] == 0) {
1492	if (wmPtr->cmdArgv != NULL) {
1493	    ckfree((char *) wmPtr->cmdArgv);
1494	    wmPtr->cmdArgv = NULL;
1495	}
1496	return TCL_OK;
1497    }
1498    if (Tcl_SplitList(interp, argv3, &cmdArgc, &cmdArgv) != TCL_OK) {
1499	return TCL_ERROR;
1500    }
1501    if (wmPtr->cmdArgv != NULL) {
1502	ckfree((char *) wmPtr->cmdArgv);
1503    }
1504    wmPtr->cmdArgc = cmdArgc;
1505    wmPtr->cmdArgv = cmdArgv;
1506    return TCL_OK;
1507}
1508
1509/*
1510 *----------------------------------------------------------------------
1511 *
1512 * WmDeiconifyCmd --
1513 *
1514 *	This procedure is invoked to process the "wm deiconify" Tcl command.
1515 *	See the user documentation for details on what it does.
1516 *
1517 * Results:
1518 *	A standard Tcl result.
1519 *
1520 * Side effects:
1521 *	See the user documentation.
1522 *
1523 *----------------------------------------------------------------------
1524 */
1525
1526static int
1527WmDeiconifyCmd(
1528    Tk_Window tkwin,		/* Main window of the application. */
1529    TkWindow *winPtr,		/* Toplevel to work with */
1530    Tcl_Interp *interp,		/* Current interpreter. */
1531    int objc,			/* Number of arguments. */
1532    Tcl_Obj *const objv[])	/* Argument objects. */
1533{
1534    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1535
1536    if (objc != 3) {
1537	Tcl_WrongNumArgs(interp, 2, objv, "window");
1538	return TCL_ERROR;
1539    }
1540    if (wmPtr->iconFor != NULL) {
1541	Tcl_AppendResult(interp, "can't deiconify ", Tcl_GetString(objv[2]),
1542		": it is an icon for ", Tk_PathName(wmPtr->iconFor), NULL);
1543	return TCL_ERROR;
1544    }
1545    if (winPtr->flags & TK_EMBEDDED) {
1546	Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName,
1547		": it is an embedded window", NULL);
1548	return TCL_ERROR;
1549    }
1550    TkpWmSetState(winPtr, TkMacOSXIsWindowZoomed(winPtr) ?
1551	    ZoomState : NormalState);
1552    return TCL_OK;
1553}
1554
1555/*
1556 *----------------------------------------------------------------------
1557 *
1558 * WmFocusmodelCmd --
1559 *
1560 *	This procedure is invoked to process the "wm focusmodel" Tcl command.
1561 *	See the user documentation for details on what it does.
1562 *
1563 * Results:
1564 *	A standard Tcl result.
1565 *
1566 * Side effects:
1567 *	See the user documentation.
1568 *
1569 *----------------------------------------------------------------------
1570 */
1571
1572static int
1573WmFocusmodelCmd(
1574    Tk_Window tkwin,		/* Main window of the application. */
1575    TkWindow *winPtr,		/* Toplevel to work with */
1576    Tcl_Interp *interp,		/* Current interpreter. */
1577    int objc,			/* Number of arguments. */
1578    Tcl_Obj *const objv[])	/* Argument objects. */
1579{
1580    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1581    static const char *optionStrings[] = {
1582	"active", "passive", NULL };
1583    enum options {
1584	OPT_ACTIVE, OPT_PASSIVE };
1585    int index;
1586
1587    if ((objc != 3) && (objc != 4)) {
1588	Tcl_WrongNumArgs(interp, 2, objv, "window ?active|passive?");
1589	return TCL_ERROR;
1590    }
1591    if (objc == 3) {
1592	Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"),
1593		TCL_STATIC);
1594	return TCL_OK;
1595    }
1596
1597    if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
1598	    &index) != TCL_OK) {
1599	return TCL_ERROR;
1600    }
1601    if (index == OPT_ACTIVE) {
1602	wmPtr->hints.input = False;
1603    } else { /* OPT_PASSIVE */
1604	wmPtr->hints.input = True;
1605    }
1606    return TCL_OK;
1607}
1608
1609/*
1610 *----------------------------------------------------------------------
1611 *
1612 * WmForgetCmd --
1613 *
1614 *	This procedure is invoked to process the "wm forget" Tcl command.
1615 *	See the user documentation for details on what it does.
1616 *
1617 * Results:
1618 *	A standard Tcl result.
1619 *
1620 * Side effects:
1621 *	See the user documentation.
1622 *
1623 *----------------------------------------------------------------------
1624 */
1625
1626static int
1627WmForgetCmd(
1628    Tk_Window tkwin,		/* Main window of the application. */
1629    TkWindow *winPtr,		/* Toplevel or Frame to work with */
1630    Tcl_Interp *interp,		/* Current interpreter. */
1631    int objc,			/* Number of arguments. */
1632    Tcl_Obj *const objv[])	/* Argument objects. */
1633{
1634#if 1
1635    Tcl_AppendResult(interp, "wm forget is not yet supported", NULL);
1636    return TCL_ERROR;
1637#else
1638    register Tk_Window frameWin = (Tk_Window)winPtr;
1639    char *oldClass = (char*)Tk_Class(frameWin);
1640
1641    if (Tk_IsTopLevel(frameWin)) {
1642	MacDrawable *macWin = (MacDrawable *) winPtr->window;
1643	CGrafPtr destPort = TkMacOSXGetDrawablePort(winPtr->window);
1644
1645	TkFocusJoin(winPtr);
1646	Tk_UnmapWindow(frameWin);
1647
1648	if (destPort != NULL) {
1649	    WindowRef winRef = GetWindowFromPort(destPort);
1650
1651	    TkMacOSXUnregisterMacWindow(winRef);
1652	    DisposeWindow(winRef);
1653	}
1654	macWin->grafPtr = NULL;
1655	macWin->toplevel = winPtr->parentPtr->privatePtr->toplevel;
1656	macWin->flags &= ~TK_HOST_EXISTS;
1657
1658	RemapWindows(winPtr, macWin);
1659	TkWmDeadWindow(winPtr);
1660	winPtr->flags &=
1661		~(TK_TOP_HIERARCHY|TK_TOP_LEVEL|TK_HAS_WRAPPER|TK_WIN_MANAGED);
1662
1663	TkMapTopFrame(frameWin);
1664    } else {
1665	/* Already not managed by wm - ignore it */
1666    }
1667    return TCL_OK;
1668#endif
1669}
1670
1671/*
1672 *----------------------------------------------------------------------
1673 *
1674 * WmFrameCmd --
1675 *
1676 *	This procedure is invoked to process the "wm frame" Tcl command. See
1677 *	the user documentation for details on what it does.
1678 *
1679 * Results:
1680 *	A standard Tcl result.
1681 *
1682 * Side effects:
1683 *	See the user documentation.
1684 *
1685 *----------------------------------------------------------------------
1686 */
1687
1688static int
1689WmFrameCmd(
1690    Tk_Window tkwin,		/* Main window of the application. */
1691    TkWindow *winPtr,		/* Toplevel to work with */
1692    Tcl_Interp *interp,		/* Current interpreter. */
1693    int objc,			/* Number of arguments. */
1694    Tcl_Obj *const objv[])	/* Argument objects. */
1695{
1696    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1697    Window window;
1698    char buf[TCL_INTEGER_SPACE];
1699
1700    if (objc != 3) {
1701	Tcl_WrongNumArgs(interp, 2, objv, "window");
1702	return TCL_ERROR;
1703    }
1704    window = wmPtr->reparent;
1705    if (window == None) {
1706	window = Tk_WindowId((Tk_Window) winPtr);
1707    }
1708    sprintf(buf, "0x%x", (unsigned) window);
1709    Tcl_SetResult(interp, buf, TCL_VOLATILE);
1710    return TCL_OK;
1711}
1712
1713/*
1714 *----------------------------------------------------------------------
1715 *
1716 * WmGeometryCmd --
1717 *
1718 *	This procedure is invoked to process the "wm geometry" Tcl command.
1719 *	See the user documentation for details on what it does.
1720 *
1721 * Results:
1722 *	A standard Tcl result.
1723 *
1724 * Side effects:
1725 *	See the user documentation.
1726 *
1727 *----------------------------------------------------------------------
1728 */
1729
1730static int
1731WmGeometryCmd(
1732    Tk_Window tkwin,		/* Main window of the application. */
1733    TkWindow *winPtr,		/* Toplevel to work with */
1734    Tcl_Interp *interp,		/* Current interpreter. */
1735    int objc,			/* Number of arguments. */
1736    Tcl_Obj *const objv[])	/* Argument objects. */
1737{
1738    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1739    char xSign, ySign;
1740    int width, height;
1741    char *argv3;
1742
1743    if ((objc != 3) && (objc != 4)) {
1744	Tcl_WrongNumArgs(interp, 2, objv, "window ?newGeometry?");
1745	return TCL_ERROR;
1746    }
1747    if (objc == 3) {
1748	char buf[16 + TCL_INTEGER_SPACE * 4];
1749
1750	xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
1751	ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
1752	if (wmPtr->gridWin != NULL) {
1753	    width = wmPtr->reqGridWidth + (winPtr->changes.width
1754		    - winPtr->reqWidth)/wmPtr->widthInc;
1755	    height = wmPtr->reqGridHeight + (winPtr->changes.height
1756		    - winPtr->reqHeight)/wmPtr->heightInc;
1757	} else {
1758	    width = winPtr->changes.width;
1759	    height = winPtr->changes.height;
1760	}
1761	sprintf(buf, "%dx%d%c%d%c%d",
1762		width, height, xSign, wmPtr->x, ySign, wmPtr->y);
1763	Tcl_SetResult(interp, buf, TCL_VOLATILE);
1764	return TCL_OK;
1765    }
1766    argv3 = Tcl_GetString(objv[3]);
1767    if (*argv3 == '\0') {
1768	wmPtr->width = -1;
1769	wmPtr->height = -1;
1770	WmUpdateGeom(wmPtr, winPtr);
1771	return TCL_OK;
1772    }
1773    return ParseGeometry(interp, argv3, winPtr);
1774}
1775
1776/*
1777 *----------------------------------------------------------------------
1778 *
1779 * WmGridCmd --
1780 *
1781 *	This procedure is invoked to process the "wm grid" Tcl command. See
1782 *	the user documentation for details on what it does.
1783 *
1784 * Results:
1785 *	A standard Tcl result.
1786 *
1787 * Side effects:
1788 *	See the user documentation.
1789 *
1790 *----------------------------------------------------------------------
1791 */
1792
1793static int
1794WmGridCmd(
1795    Tk_Window tkwin,		/* Main window of the application. */
1796    TkWindow *winPtr,		/* Toplevel to work with */
1797    Tcl_Interp *interp,		/* Current interpreter. */
1798    int objc,			/* Number of arguments. */
1799    Tcl_Obj *const objv[])	/* Argument objects. */
1800{
1801    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1802    int reqWidth, reqHeight, widthInc, heightInc;
1803
1804    if ((objc != 3) && (objc != 7)) {
1805	Tcl_WrongNumArgs(interp, 2, objv,
1806		"window ?baseWidth baseHeight widthInc heightInc?");
1807	return TCL_ERROR;
1808    }
1809    if (objc == 3) {
1810	if (wmPtr->sizeHintsFlags & PBaseSize) {
1811	    char buf[TCL_INTEGER_SPACE * 4];
1812
1813	    sprintf(buf, "%d %d %d %d", wmPtr->reqGridWidth,
1814		    wmPtr->reqGridHeight, wmPtr->widthInc,
1815		    wmPtr->heightInc);
1816	    Tcl_SetResult(interp, buf, TCL_VOLATILE);
1817	}
1818	return TCL_OK;
1819    }
1820    if (*Tcl_GetString(objv[3]) == '\0') {
1821	/*
1822	 * Turn off gridding and reset the width and height to make sense as
1823	 * ungridded numbers.
1824	 */
1825
1826	wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
1827	if (wmPtr->width != -1) {
1828	    wmPtr->width = winPtr->reqWidth + (wmPtr->width
1829		    - wmPtr->reqGridWidth)*wmPtr->widthInc;
1830	    wmPtr->height = winPtr->reqHeight + (wmPtr->height
1831		    - wmPtr->reqGridHeight)*wmPtr->heightInc;
1832	}
1833	wmPtr->widthInc = 1;
1834	wmPtr->heightInc = 1;
1835    } else {
1836	if ((Tcl_GetIntFromObj(interp, objv[3], &reqWidth) != TCL_OK)
1837		|| (Tcl_GetIntFromObj(interp, objv[4], &reqHeight) != TCL_OK)
1838		|| (Tcl_GetIntFromObj(interp, objv[5], &widthInc) != TCL_OK)
1839		|| (Tcl_GetIntFromObj(interp, objv[6], &heightInc)!=TCL_OK)) {
1840	    return TCL_ERROR;
1841	}
1842	if (reqWidth < 0) {
1843	    Tcl_SetResult(interp, "baseWidth can't be < 0", TCL_STATIC);
1844	    return TCL_ERROR;
1845	}
1846	if (reqHeight < 0) {
1847	    Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC);
1848	    return TCL_ERROR;
1849	}
1850	if (widthInc <= 0) {
1851	    Tcl_SetResult(interp, "widthInc can't be <= 0", TCL_STATIC);
1852	    return TCL_ERROR;
1853	}
1854	if (heightInc <= 0) {
1855	    Tcl_SetResult(interp, "heightInc can't be <= 0", TCL_STATIC);
1856	    return TCL_ERROR;
1857	}
1858	Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
1859		heightInc);
1860    }
1861    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1862    WmUpdateGeom(wmPtr, winPtr);
1863    return TCL_OK;
1864}
1865
1866/*
1867 *----------------------------------------------------------------------
1868 *
1869 * WmGroupCmd --
1870 *
1871 *	This procedure is invoked to process the "wm group" Tcl command. See
1872 *	the user documentation for details on what it does.
1873 *
1874 * Results:
1875 *	A standard Tcl result.
1876 *
1877 * Side effects:
1878 *	See the user documentation.
1879 *
1880 *----------------------------------------------------------------------
1881 */
1882
1883static int
1884WmGroupCmd(
1885    Tk_Window tkwin,		/* Main window of the application. */
1886    TkWindow *winPtr,		/* Toplevel to work with */
1887    Tcl_Interp *interp,		/* Current interpreter. */
1888    int objc,			/* Number of arguments. */
1889    Tcl_Obj *const objv[])	/* Argument objects. */
1890{
1891    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1892    Tk_Window tkwin2;
1893    char *argv3;
1894    int length;
1895
1896    if ((objc != 3) && (objc != 4)) {
1897	Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?");
1898	return TCL_ERROR;
1899    }
1900    if (objc == 3) {
1901	if (wmPtr->hints.flags & WindowGroupHint) {
1902	    Tcl_SetResult(interp, wmPtr->leaderName, TCL_STATIC);
1903	}
1904	return TCL_OK;
1905    }
1906    argv3 = Tcl_GetStringFromObj(objv[3], &length);
1907    if (*argv3 == '\0') {
1908	wmPtr->hints.flags &= ~WindowGroupHint;
1909	if (wmPtr->leaderName != NULL) {
1910	    ckfree(wmPtr->leaderName);
1911	}
1912	wmPtr->leaderName = NULL;
1913    } else {
1914	if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) {
1915	    return TCL_ERROR;
1916	}
1917	Tk_MakeWindowExist(tkwin2);
1918	if (wmPtr->leaderName != NULL) {
1919	    ckfree(wmPtr->leaderName);
1920	}
1921	wmPtr->hints.window_group = Tk_WindowId(tkwin2);
1922	wmPtr->hints.flags |= WindowGroupHint;
1923	wmPtr->leaderName = ckalloc((unsigned) (length + 1));
1924	strcpy(wmPtr->leaderName, argv3);
1925    }
1926    return TCL_OK;
1927}
1928
1929/*
1930 *----------------------------------------------------------------------
1931 *
1932 * WmIconbitmapCmd --
1933 *
1934 *	This procedure is invoked to process the "wm iconbitmap" Tcl command.
1935 *	See the user documentation for details on what it does.
1936 *
1937 * Results:
1938 *	A standard Tcl result.
1939 *
1940 * Side effects:
1941 *	See the user documentation.
1942 *
1943 *----------------------------------------------------------------------
1944 */
1945
1946static int
1947WmIconbitmapCmd(
1948    Tk_Window tkwin,		/* Main window of the application. */
1949    TkWindow *winPtr,		/* Toplevel to work with */
1950    Tcl_Interp *interp,		/* Current interpreter. */
1951    int objc,			/* Number of arguments. */
1952    Tcl_Obj *const objv[])	/* Argument objects. */
1953{
1954    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1955    Pixmap pixmap;
1956    char *str;
1957    int len;
1958
1959    if ((objc != 3) && (objc != 4)) {
1960	Tcl_WrongNumArgs(interp, 2, objv, "window ?bitmap?");
1961	return TCL_ERROR;
1962    }
1963    if (objc == 3) {
1964	if (wmPtr->hints.flags & IconPixmapHint) {
1965	    Tcl_SetResult(interp, (char*)Tk_NameOfBitmap(winPtr->display,
1966		    wmPtr->hints.icon_pixmap), TCL_STATIC);
1967	}
1968	return TCL_OK;
1969    }
1970    str = Tcl_GetStringFromObj(objv[3], &len);
1971    if (winPtr->window == None) {
1972	Tk_MakeWindowExist((Tk_Window) winPtr);
1973    }
1974    if (!TkMacOSXHostToplevelExists(winPtr)) {
1975	TkMacOSXMakeRealWindowExist(winPtr);
1976    }
1977    if (WmSetAttribute(winPtr, TkMacOSXDrawableWindow(winPtr->window), interp,
1978	    WMATT_TITLEPATH, objv[3]) == TCL_OK) {
1979	if (!len) {
1980	    if (wmPtr->hints.icon_pixmap != None) {
1981		Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
1982		wmPtr->hints.icon_pixmap = None;
1983	    }
1984	    wmPtr->hints.flags &= ~IconPixmapHint;
1985	}
1986    } else {
1987	pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr, Tk_GetUid(str));
1988	if (pixmap == None) {
1989	    return TCL_ERROR;
1990	}
1991	wmPtr->hints.icon_pixmap = pixmap;
1992	wmPtr->hints.flags |= IconPixmapHint;
1993    }
1994    return TCL_OK;
1995}
1996
1997/*
1998 *----------------------------------------------------------------------
1999 *
2000 * WmIconifyCmd --
2001 *
2002 *	This procedure is invoked to process the "wm iconify" Tcl command. See
2003 *	the user documentation for details on what it does.
2004 *
2005 * Results:
2006 *	A standard Tcl result.
2007 *
2008 * Side effects:
2009 *	See the user documentation.
2010 *
2011 *----------------------------------------------------------------------
2012 */
2013
2014static int
2015WmIconifyCmd(
2016    Tk_Window tkwin,		/* Main window of the application. */
2017    TkWindow *winPtr,		/* Toplevel to work with */
2018    Tcl_Interp *interp,		/* Current interpreter. */
2019    int objc,			/* Number of arguments. */
2020    Tcl_Obj *const objv[])	/* Argument objects. */
2021{
2022    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2023    if (objc != 3) {
2024	Tcl_WrongNumArgs(interp, 2, objv, "window");
2025	return TCL_ERROR;
2026    }
2027    if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
2028	Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
2029		"\": override-redirect flag is set", NULL);
2030	return TCL_ERROR;
2031    }
2032    if (wmPtr->master != None) {
2033	Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
2034		"\": it is a transient", NULL);
2035	return TCL_ERROR;
2036    }
2037    if (wmPtr->iconFor != NULL) {
2038	Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
2039		": it is an icon for ", Tk_PathName(wmPtr->iconFor), NULL);
2040	return TCL_ERROR;
2041    }
2042    if (winPtr->flags & TK_EMBEDDED) {
2043	Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
2044		": it is an embedded window", NULL);
2045	return TCL_ERROR;
2046    }
2047    TkpWmSetState(winPtr, IconicState);
2048    return TCL_OK;
2049}
2050
2051/*
2052 *----------------------------------------------------------------------
2053 *
2054 * WmIconmaskCmd --
2055 *
2056 *	This procedure is invoked to process the "wm iconmask" Tcl command.
2057 *	See the user documentation for details on what it does.
2058 *
2059 * Results:
2060 *	A standard Tcl result.
2061 *
2062 * Side effects:
2063 *	See the user documentation.
2064 *
2065 *----------------------------------------------------------------------
2066 */
2067
2068static int
2069WmIconmaskCmd(
2070    Tk_Window tkwin,		/* Main window of the application. */
2071    TkWindow *winPtr,		/* Toplevel to work with */
2072    Tcl_Interp *interp,		/* Current interpreter. */
2073    int objc,			/* Number of arguments. */
2074    Tcl_Obj *const objv[])	/* Argument objects. */
2075{
2076    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2077    Pixmap pixmap;
2078    char *argv3;
2079
2080    if ((objc != 3) && (objc != 4)) {
2081	Tcl_WrongNumArgs(interp, 2, objv, "window ?bitmap?");
2082	return TCL_ERROR;
2083    }
2084    if (objc == 3) {
2085	if (wmPtr->hints.flags & IconMaskHint) {
2086	    Tcl_SetResult(interp, (char *) Tk_NameOfBitmap(winPtr->display,
2087		    wmPtr->hints.icon_mask), TCL_STATIC);
2088	}
2089	return TCL_OK;
2090    }
2091    argv3 = Tcl_GetString(objv[3]);
2092    if (*argv3 == '\0') {
2093	if (wmPtr->hints.icon_mask != None) {
2094	    Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
2095	}
2096	wmPtr->hints.flags &= ~IconMaskHint;
2097    } else {
2098	pixmap = Tk_GetBitmap(interp, tkwin, argv3);
2099	if (pixmap == None) {
2100	    return TCL_ERROR;
2101	}
2102	wmPtr->hints.icon_mask = pixmap;
2103	wmPtr->hints.flags |= IconMaskHint;
2104    }
2105    return TCL_OK;
2106}
2107
2108/*
2109 *----------------------------------------------------------------------
2110 *
2111 * WmIconnameCmd --
2112 *
2113 *	This procedure is invoked to process the "wm iconname" Tcl command.
2114 *	See the user documentation for details on what it does.
2115 *
2116 * Results:
2117 *	A standard Tcl result.
2118 *
2119 * Side effects:
2120 *	See the user documentation.
2121 *
2122 *----------------------------------------------------------------------
2123 */
2124
2125static int
2126WmIconnameCmd(
2127    Tk_Window tkwin,		/* Main window of the application. */
2128    TkWindow *winPtr,		/* Toplevel to work with */
2129    Tcl_Interp *interp,		/* Current interpreter. */
2130    int objc,			/* Number of arguments. */
2131    Tcl_Obj *const objv[])	/* Argument objects. */
2132{
2133    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2134    const char *argv3;
2135    int length;
2136
2137    if (objc > 4) {
2138	Tcl_WrongNumArgs(interp, 2, objv, "window ?newName?");
2139	return TCL_ERROR;
2140    }
2141    if (objc == 3) {
2142	if (wmPtr->iconName != NULL) {
2143	    Tcl_SetObjResult(interp, Tcl_NewStringObj(wmPtr->iconName, -1));
2144	}
2145	return TCL_OK;
2146    }
2147
2148    if (wmPtr->iconName != NULL) {
2149	ckfree((char *) wmPtr->iconName);
2150    }
2151    argv3 = Tcl_GetStringFromObj(objv[3], &length);
2152    wmPtr->iconName = ckalloc((unsigned) length + 1);
2153    strcpy(wmPtr->iconName, argv3);
2154    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
2155	XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
2156    }
2157    return TCL_OK;
2158}
2159
2160/*
2161 *----------------------------------------------------------------------
2162 *
2163 * WmIconphotoCmd --
2164 *
2165 *	This procedure is invoked to process the "wm iconphoto" Tcl command.
2166 *	See the user documentation for details on what it does. Not yet
2167 *	implemented for OS X.
2168 *
2169 * Results:
2170 *	A standard Tcl result.
2171 *
2172 * Side effects:
2173 *	See the user documentation.
2174 *
2175 *----------------------------------------------------------------------
2176 */
2177
2178static int
2179WmIconphotoCmd(
2180    Tk_Window tkwin,		/* Main window of the application. */
2181    TkWindow *winPtr,		/* Toplevel to work with */
2182    Tcl_Interp *interp,		/* Current interpreter. */
2183    int objc,			/* Number of arguments. */
2184    Tcl_Obj *const objv[])	/* Argument objects. */
2185{
2186    Tk_PhotoHandle photo;
2187    int i, width, height, isDefault = 0;
2188
2189    if (objc < 4) {
2190	Tcl_WrongNumArgs(interp, 2, objv,
2191		"window ?-default? image1 ?image2 ...?");
2192	return TCL_ERROR;
2193    }
2194    if (strcmp(Tcl_GetString(objv[3]), "-default") == 0) {
2195	isDefault = 1;
2196	if (objc == 4) {
2197	    Tcl_WrongNumArgs(interp, 2, objv,
2198		    "window ?-default? image1 ?image2 ...?");
2199	    return TCL_ERROR;
2200	}
2201    }
2202
2203    /*
2204     * Iterate over all images to retrieve their sizes, in order to allocate a
2205     * buffer large enough to hold all images.
2206     */
2207
2208    for (i = 3 + isDefault; i < objc; i++) {
2209	photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
2210	if (photo == NULL) {
2211	    Tcl_AppendResult(interp, "can't use \"", Tcl_GetString(objv[i]),
2212		    "\" as iconphoto: not a photo image", NULL);
2213	    return TCL_ERROR;
2214	}
2215	Tk_PhotoGetSize(photo, &width, &height);
2216    }
2217
2218    /*
2219     * TODO: This requires implementation for OS X, but we silently return for
2220     * now.
2221     */
2222
2223    return TCL_OK;
2224}
2225
2226/*
2227 *----------------------------------------------------------------------
2228 *
2229 * WmIconpositionCmd --
2230 *
2231 *	This procedure is invoked to process the "wm iconposition" Tcl
2232 *	command. See the user documentation for details on what it does.
2233 *
2234 * Results:
2235 *	A standard Tcl result.
2236 *
2237 * Side effects:
2238 *	See the user documentation.
2239 *
2240 *----------------------------------------------------------------------
2241 */
2242
2243static int
2244WmIconpositionCmd(
2245    Tk_Window tkwin,		/* Main window of the application. */
2246    TkWindow *winPtr,		/* Toplevel to work with */
2247    Tcl_Interp *interp,		/* Current interpreter. */
2248    int objc,			/* Number of arguments. */
2249    Tcl_Obj *const objv[])	/* Argument objects. */
2250{
2251    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2252    int x, y;
2253
2254    if ((objc != 3) && (objc != 5)) {
2255	Tcl_WrongNumArgs(interp, 2, objv, "window ?x y?");
2256	return TCL_ERROR;
2257    }
2258    if (objc == 3) {
2259	if (wmPtr->hints.flags & IconPositionHint) {
2260	    char buf[TCL_INTEGER_SPACE * 2];
2261
2262	    sprintf(buf, "%d %d", wmPtr->hints.icon_x,
2263		    wmPtr->hints.icon_y);
2264	    Tcl_SetResult(interp, buf, TCL_VOLATILE);
2265	}
2266	return TCL_OK;
2267    }
2268    if (*Tcl_GetString(objv[3]) == '\0') {
2269	wmPtr->hints.flags &= ~IconPositionHint;
2270    } else {
2271	if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
2272	    || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)){
2273	    return TCL_ERROR;
2274	}
2275	wmPtr->hints.icon_x = x;
2276	wmPtr->hints.icon_y = y;
2277	wmPtr->hints.flags |= IconPositionHint;
2278    }
2279    return TCL_OK;
2280}
2281
2282/*
2283 *----------------------------------------------------------------------
2284 *
2285 * WmIconwindowCmd --
2286 *
2287 *	This procedure is invoked to process the "wm iconwindow" Tcl command.
2288 *	See the user documentation for details on what it does.
2289 *
2290 * Results:
2291 *	A standard Tcl result.
2292 *
2293 * Side effects:
2294 *	See the user documentation.
2295 *
2296 *----------------------------------------------------------------------
2297 */
2298
2299static int
2300WmIconwindowCmd(
2301    Tk_Window tkwin,		/* Main window of the application. */
2302    TkWindow *winPtr,		/* Toplevel to work with */
2303    Tcl_Interp *interp,		/* Current interpreter. */
2304    int objc,			/* Number of arguments. */
2305    Tcl_Obj *const objv[])	/* Argument objects. */
2306{
2307    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2308    Tk_Window tkwin2;
2309    WmInfo *wmPtr2;
2310
2311    if ((objc != 3) && (objc != 4)) {
2312	Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?");
2313	return TCL_ERROR;
2314    }
2315    if (objc == 3) {
2316	if (wmPtr->icon != NULL) {
2317	    Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC);
2318	}
2319	return TCL_OK;
2320    }
2321    if (*Tcl_GetString(objv[3]) == '\0') {
2322	wmPtr->hints.flags &= ~IconWindowHint;
2323	if (wmPtr->icon != NULL) {
2324	    wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
2325	    wmPtr2->iconFor = NULL;
2326	    wmPtr2->hints.initial_state = WithdrawnState;
2327	}
2328	wmPtr->icon = NULL;
2329    } else {
2330	if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) {
2331	    return TCL_ERROR;
2332	}
2333	if (!Tk_IsTopLevel(tkwin2)) {
2334	    Tcl_AppendResult(interp, "can't use ", Tcl_GetString(objv[3]),
2335		    " as icon window: not at top level", NULL);
2336	    return TCL_ERROR;
2337	}
2338	wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
2339	if (wmPtr2->iconFor != NULL) {
2340	    Tcl_AppendResult(interp, Tcl_GetString(objv[3]),
2341		    " is already an icon for ",
2342		    Tk_PathName(wmPtr2->iconFor), NULL);
2343	    return TCL_ERROR;
2344	}
2345	if (wmPtr->icon != NULL) {
2346	    WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
2347	    wmPtr3->iconFor = NULL;
2348	}
2349	Tk_MakeWindowExist(tkwin2);
2350	wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
2351	wmPtr->hints.flags |= IconWindowHint;
2352	wmPtr->icon = tkwin2;
2353	wmPtr2->iconFor = (Tk_Window) winPtr;
2354	if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
2355	    /*
2356	     * Don't have iconwindows on the Mac. We just withdraw.
2357	     */
2358
2359	    Tk_UnmapWindow(tkwin2);
2360	}
2361    }
2362    return TCL_OK;
2363}
2364
2365/*
2366 *----------------------------------------------------------------------
2367 *
2368 * WmManageCmd --
2369 *
2370 *	This procedure is invoked to process the "wm manage" Tcl command. See
2371 *	the user documentation for details on what it does.
2372 *
2373 * Results:
2374 *	A standard Tcl result.
2375 *
2376 * Side effects:
2377 *	See the user documentation.
2378 *
2379 *----------------------------------------------------------------------
2380 */
2381
2382static int
2383WmManageCmd(
2384    Tk_Window tkwin,		/* Main window of the application. */
2385    TkWindow *winPtr,           /* Toplevel or Frame to work with */
2386    Tcl_Interp *interp,		/* Current interpreter. */
2387    int objc,			/* Number of arguments. */
2388    Tcl_Obj *const objv[])	/* Argument objects. */
2389{
2390#if 1
2391    Tcl_AppendResult(interp, "wm manage is not yet supported", NULL);
2392    return TCL_ERROR;
2393#else
2394    register Tk_Window frameWin = (Tk_Window)winPtr;
2395    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2396    char *oldClass = (char*)Tk_Class(frameWin);
2397
2398    if (!Tk_IsTopLevel(frameWin)) {
2399	MacDrawable *macWin = (MacDrawable *) winPtr->window;
2400
2401	if (!Tk_IsManageable(frameWin)) {
2402	    Tcl_AppendResult(interp, "window \"",
2403		Tk_PathName(frameWin), "\" is not manageable: must be "
2404		"a frame, labelframe or toplevel", NULL);
2405	    return TCL_ERROR;
2406	}
2407	TkFocusSplit(winPtr);
2408	Tk_UnmapWindow(frameWin);
2409	if (wmPtr == NULL) {
2410	    TkWmNewWindow(winPtr);
2411	    if (winPtr->window == None) {
2412		Tk_MakeWindowExist((Tk_Window) winPtr);
2413		macWin = (MacDrawable *) winPtr->window;
2414	    }
2415	    TkWmMapWindow(winPtr);
2416	    Tk_UnmapWindow(frameWin);
2417	}
2418	wmPtr = winPtr->wmInfoPtr;
2419	winPtr->flags &= ~TK_MAPPED;
2420	macWin->grafPtr = NULL;
2421	macWin->toplevel = macWin;
2422	RemapWindows(winPtr, macWin);
2423	winPtr->flags |=
2424		(TK_TOP_HIERARCHY|TK_TOP_LEVEL|TK_HAS_WRAPPER|TK_WIN_MANAGED);
2425	TkMapTopFrame(frameWin);
2426    } else if (Tk_IsTopLevel(frameWin)) {
2427	/* Already managed by wm - ignore it */
2428    }
2429    return TCL_OK;
2430#endif
2431}
2432
2433/*
2434 *----------------------------------------------------------------------
2435 *
2436 * WmMaxsizeCmd --
2437 *
2438 *	This procedure is invoked to process the "wm maxsize" Tcl command. See
2439 *	the user documentation for details on what it does.
2440 *
2441 * Results:
2442 *	A standard Tcl result.
2443 *
2444 * Side effects:
2445 *	See the user documentation.
2446 *
2447 *----------------------------------------------------------------------
2448 */
2449
2450static int
2451WmMaxsizeCmd(
2452    Tk_Window tkwin,		/* Main window of the application. */
2453    TkWindow *winPtr,		/* Toplevel to work with */
2454    Tcl_Interp *interp,		/* Current interpreter. */
2455    int objc,			/* Number of arguments. */
2456    Tcl_Obj *const objv[])	/* Argument objects. */
2457{
2458    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2459    int width, height;
2460
2461    if ((objc != 3) && (objc != 5)) {
2462	Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
2463	return TCL_ERROR;
2464    }
2465    if (objc == 3) {
2466	char buf[TCL_INTEGER_SPACE * 2];
2467
2468	GetMaxSize(winPtr, &width, &height);
2469	sprintf(buf, "%d %d", width, height);
2470	Tcl_SetResult(interp, buf, TCL_VOLATILE);
2471	return TCL_OK;
2472    }
2473    if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
2474	|| (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
2475	return TCL_ERROR;
2476    }
2477    wmPtr->maxWidth = width;
2478    wmPtr->maxHeight = height;
2479    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2480    WmUpdateGeom(wmPtr, winPtr);
2481    return TCL_OK;
2482}
2483
2484/*
2485 *----------------------------------------------------------------------
2486 *
2487 * WmMinsizeCmd --
2488 *
2489 *	This procedure is invoked to process the "wm minsize" Tcl command. See
2490 *	the user documentation for details on what it does.
2491 *
2492 * Results:
2493 *	A standard Tcl result.
2494 *
2495 * Side effects:
2496 *	See the user documentation.
2497 *
2498 *----------------------------------------------------------------------
2499 */
2500
2501static int
2502WmMinsizeCmd(
2503    Tk_Window tkwin,		/* Main window of the application. */
2504    TkWindow *winPtr,		/* Toplevel to work with */
2505    Tcl_Interp *interp,		/* Current interpreter. */
2506    int objc,			/* Number of arguments. */
2507    Tcl_Obj *const objv[])	/* Argument objects. */
2508{
2509    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2510    int width, height;
2511
2512    if ((objc != 3) && (objc != 5)) {
2513	Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
2514	return TCL_ERROR;
2515    }
2516    if (objc == 3) {
2517	char buf[TCL_INTEGER_SPACE * 2];
2518
2519	GetMinSize(winPtr, &width, &height);
2520	sprintf(buf, "%d %d", width, height);
2521	Tcl_SetResult(interp, buf, TCL_VOLATILE);
2522	return TCL_OK;
2523    }
2524    if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
2525	    || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
2526	return TCL_ERROR;
2527    }
2528    wmPtr->minWidth = width;
2529    wmPtr->minHeight = height;
2530    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2531    WmUpdateGeom(wmPtr, winPtr);
2532    return TCL_OK;
2533}
2534
2535/*
2536 *----------------------------------------------------------------------
2537 *
2538 * WmOverrideredirectCmd --
2539 *
2540 *	This procedure is invoked to process the "wm overrideredirect" Tcl
2541 *	command. See the user documentation for details on what it does.
2542 *
2543 * Results:
2544 *	A standard Tcl result.
2545 *
2546 * Side effects:
2547 *	See the user documentation.
2548 *
2549 *----------------------------------------------------------------------
2550 */
2551
2552static int
2553WmOverrideredirectCmd(
2554    Tk_Window tkwin,		/* Main window of the application. */
2555    TkWindow *winPtr,		/* Toplevel to work with */
2556    Tcl_Interp *interp,		/* Current interpreter. */
2557    int objc,			/* Number of arguments. */
2558    Tcl_Obj *const objv[])	/* Argument objects. */
2559{
2560    int boolean;
2561    XSetWindowAttributes atts;
2562
2563    if ((objc != 3) && (objc != 4)) {
2564	Tcl_WrongNumArgs(interp, 2, objv, "window ?boolean?");
2565	return TCL_ERROR;
2566    }
2567    if (objc == 3) {
2568	Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
2569		Tk_Attributes((Tk_Window) winPtr)->override_redirect));
2570	return TCL_OK;
2571    }
2572    if (Tcl_GetBooleanFromObj(interp, objv[3], &boolean) != TCL_OK) {
2573	return TCL_ERROR;
2574    }
2575    atts.override_redirect = (boolean) ? True : False;
2576    Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect, &atts);
2577    ApplyMasterOverrideChanges(winPtr, NULL);
2578    return TCL_OK;
2579}
2580
2581/*
2582 *----------------------------------------------------------------------
2583 *
2584 * WmPositionfromCmd --
2585 *
2586 *	This procedure is invoked to process the "wm positionfrom" Tcl
2587 *	command. See the user documentation for details on what it does.
2588 *
2589 * Results:
2590 *	A standard Tcl result.
2591 *
2592 * Side effects:
2593 *	See the user documentation.
2594 *
2595 *----------------------------------------------------------------------
2596 */
2597
2598static int
2599WmPositionfromCmd(
2600    Tk_Window tkwin,		/* Main window of the application. */
2601    TkWindow *winPtr,		/* Toplevel to work with */
2602    Tcl_Interp *interp,		/* Current interpreter. */
2603    int objc,			/* Number of arguments. */
2604    Tcl_Obj *const objv[])	/* Argument objects. */
2605{
2606    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2607    static const char *optionStrings[] = {
2608	"program", "user", NULL };
2609    enum options {
2610	OPT_PROGRAM, OPT_USER };
2611    int index;
2612
2613    if ((objc != 3) && (objc != 4)) {
2614	Tcl_WrongNumArgs(interp, 2, objv, "window ?user/program?");
2615	return TCL_ERROR;
2616    }
2617    if (objc == 3) {
2618	if (wmPtr->sizeHintsFlags & USPosition) {
2619	    Tcl_SetResult(interp, "user", TCL_STATIC);
2620	} else if (wmPtr->sizeHintsFlags & PPosition) {
2621	    Tcl_SetResult(interp, "program", TCL_STATIC);
2622	}
2623	return TCL_OK;
2624    }
2625    if (*Tcl_GetString(objv[3]) == '\0') {
2626	wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
2627    } else {
2628	if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
2629		&index) != TCL_OK) {
2630	    return TCL_ERROR;
2631	}
2632	if (index == OPT_USER) {
2633	    wmPtr->sizeHintsFlags &= ~PPosition;
2634	    wmPtr->sizeHintsFlags |= USPosition;
2635	} else {
2636	    wmPtr->sizeHintsFlags &= ~USPosition;
2637	    wmPtr->sizeHintsFlags |= PPosition;
2638	}
2639    }
2640    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2641    WmUpdateGeom(wmPtr, winPtr);
2642    return TCL_OK;
2643}
2644
2645/*
2646 *----------------------------------------------------------------------
2647 *
2648 * WmProtocolCmd --
2649 *
2650 *	This procedure is invoked to process the "wm protocol" Tcl command.
2651 *	See the user documentation for details on what it does.
2652 *
2653 * Results:
2654 *	A standard Tcl result.
2655 *
2656 * Side effects:
2657 *	See the user documentation.
2658 *
2659 *----------------------------------------------------------------------
2660 */
2661
2662static int
2663WmProtocolCmd(
2664    Tk_Window tkwin,		/* Main window of the application. */
2665    TkWindow *winPtr,		/* Toplevel to work with */
2666    Tcl_Interp *interp,		/* Current interpreter. */
2667    int objc,			/* Number of arguments. */
2668    Tcl_Obj *const objv[])	/* Argument objects. */
2669{
2670    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2671    register ProtocolHandler *protPtr, *prevPtr;
2672    Atom protocol;
2673    char *cmd;
2674    int cmdLength;
2675
2676    if ((objc < 3) || (objc > 5)) {
2677	Tcl_WrongNumArgs(interp, 2, objv, "window ?name? ?command?");
2678	return TCL_ERROR;
2679    }
2680    if (objc == 3) {
2681	/*
2682	 * Return a list of all defined protocols for the window.
2683	 */
2684
2685	for (protPtr = wmPtr->protPtr; protPtr != NULL;
2686		protPtr = protPtr->nextPtr) {
2687	    Tcl_AppendElement(interp,
2688		    Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
2689	}
2690	return TCL_OK;
2691    }
2692    protocol = Tk_InternAtom((Tk_Window) winPtr, Tcl_GetString(objv[3]));
2693    if (objc == 4) {
2694	/*
2695	 * Return the command to handle a given protocol.
2696	 */
2697
2698	for (protPtr = wmPtr->protPtr; protPtr != NULL;
2699		protPtr = protPtr->nextPtr) {
2700	    if (protPtr->protocol == protocol) {
2701		Tcl_SetResult(interp, protPtr->command, TCL_STATIC);
2702		return TCL_OK;
2703	    }
2704	}
2705	return TCL_OK;
2706    }
2707
2708    /*
2709     * Delete any current protocol handler, then create a new one with the
2710     * specified command, unless the command is empty.
2711     */
2712
2713    for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
2714	prevPtr = protPtr, protPtr = protPtr->nextPtr) {
2715	if (protPtr->protocol == protocol) {
2716	    if (prevPtr == NULL) {
2717		wmPtr->protPtr = protPtr->nextPtr;
2718	    } else {
2719		prevPtr->nextPtr = protPtr->nextPtr;
2720	    }
2721	    Tcl_EventuallyFree(protPtr, TCL_DYNAMIC);
2722	    break;
2723	}
2724    }
2725    cmd = Tcl_GetStringFromObj(objv[4], &cmdLength);
2726    if (cmdLength > 0) {
2727	protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
2728	protPtr->protocol = protocol;
2729	protPtr->nextPtr = wmPtr->protPtr;
2730	wmPtr->protPtr = protPtr;
2731	protPtr->interp = interp;
2732	strcpy(protPtr->command, cmd);
2733    }
2734    return TCL_OK;
2735}
2736
2737/*
2738 *----------------------------------------------------------------------
2739 *
2740 * WmResizableCmd --
2741 *
2742 *	This procedure is invoked to process the "wm resizable" Tcl command.
2743 *	See the user documentation for details on what it does.
2744 *
2745 * Results:
2746 *	A standard Tcl result.
2747 *
2748 * Side effects:
2749 *	See the user documentation.
2750 *
2751 *----------------------------------------------------------------------
2752 */
2753
2754static int
2755WmResizableCmd(
2756    Tk_Window tkwin,		/* Main window of the application. */
2757    TkWindow *winPtr,		/* Toplevel to work with */
2758    Tcl_Interp *interp,		/* Current interpreter. */
2759    int objc,			/* Number of arguments. */
2760    Tcl_Obj *const objv[])	/* Argument objects. */
2761{
2762    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2763    int width, height;
2764    UInt64 oldAttributes = wmPtr->attributes;
2765    int oldFlags = wmPtr->flags;
2766
2767    if ((objc != 3) && (objc != 5)) {
2768	Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
2769	return TCL_ERROR;
2770    }
2771    if (objc == 3) {
2772	char buf[TCL_INTEGER_SPACE * 2];
2773
2774	sprintf(buf, "%d %d",
2775		(wmPtr->flags  & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
2776		(wmPtr->flags  & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
2777	Tcl_SetResult(interp, buf, TCL_VOLATILE);
2778	return TCL_OK;
2779    }
2780    if ((Tcl_GetBooleanFromObj(interp, objv[3], &width) != TCL_OK)
2781	|| (Tcl_GetBooleanFromObj(interp, objv[4], &height) != TCL_OK)) {
2782	return TCL_ERROR;
2783    }
2784    if (width) {
2785	wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
2786	wmPtr->attributes |= kWindowHorizontalZoomAttribute;
2787    } else {
2788	wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
2789	wmPtr->attributes &= ~kWindowHorizontalZoomAttribute;
2790    }
2791    if (height) {
2792	wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
2793	wmPtr->attributes |= kWindowVerticalZoomAttribute;
2794    } else {
2795	wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
2796	wmPtr->attributes &= ~kWindowVerticalZoomAttribute;
2797    }
2798    if (width || height) {
2799	wmPtr->attributes |= kWindowResizableAttribute;
2800    } else {
2801	wmPtr->attributes &= ~kWindowResizableAttribute;
2802    }
2803    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2804    if (wmPtr->scrollWinPtr != NULL) {
2805	TkScrollbarEventuallyRedraw((TkScrollbar *)
2806		wmPtr->scrollWinPtr->instanceData);
2807    }
2808    WmUpdateGeom(wmPtr, winPtr);
2809    ApplyWindowAttributeFlagChanges(winPtr, NULL, oldAttributes, oldFlags, 1,0);
2810    return TCL_OK;
2811}
2812
2813/*
2814 *----------------------------------------------------------------------
2815 *
2816 * WmSizefromCmd --
2817 *
2818 *	This procedure is invoked to process the "wm sizefrom" Tcl command.
2819 *	See the user documentation for details on what it does.
2820 *
2821 * Results:
2822 *	A standard Tcl result.
2823 *
2824 * Side effects:
2825 *	See the user documentation.
2826 *
2827 *----------------------------------------------------------------------
2828 */
2829
2830static int
2831WmSizefromCmd(
2832    Tk_Window tkwin,		/* Main window of the application. */
2833    TkWindow *winPtr,		/* Toplevel to work with */
2834    Tcl_Interp *interp,		/* Current interpreter. */
2835    int objc,			/* Number of arguments. */
2836    Tcl_Obj *const objv[])	/* Argument objects. */
2837{
2838    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2839    static const char *optionStrings[] = {
2840	"program", "user", NULL };
2841    enum options {
2842	OPT_PROGRAM, OPT_USER };
2843    int index;
2844
2845    if ((objc != 3) && (objc != 4)) {
2846	Tcl_WrongNumArgs(interp, 2, objv, "window ?user|program?");
2847	return TCL_ERROR;
2848    }
2849    if (objc == 3) {
2850	if (wmPtr->sizeHintsFlags & USSize) {
2851	    Tcl_SetResult(interp, "user", TCL_STATIC);
2852	} else if (wmPtr->sizeHintsFlags & PSize) {
2853	    Tcl_SetResult(interp, "program", TCL_STATIC);
2854	}
2855	return TCL_OK;
2856    }
2857
2858    if (*Tcl_GetString(objv[3]) == '\0') {
2859	wmPtr->sizeHintsFlags &= ~(USSize|PSize);
2860    } else {
2861	if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
2862		&index) != TCL_OK) {
2863	    return TCL_ERROR;
2864	}
2865	if (index == OPT_USER) {
2866	    wmPtr->sizeHintsFlags &= ~PSize;
2867	    wmPtr->sizeHintsFlags |= USSize;
2868	} else { /* OPT_PROGRAM */
2869	    wmPtr->sizeHintsFlags &= ~USSize;
2870	    wmPtr->sizeHintsFlags |= PSize;
2871	}
2872    }
2873    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2874    WmUpdateGeom(wmPtr, winPtr);
2875    return TCL_OK;
2876}
2877
2878/*
2879 *----------------------------------------------------------------------
2880 *
2881 * WmStackorderCmd --
2882 *
2883 *	This procedure is invoked to process the "wm stackorder" Tcl command.
2884 *	See the user documentation for details on what it does.
2885 *
2886 * Results:
2887 *	A standard Tcl result.
2888 *
2889 * Side effects:
2890 *	See the user documentation.
2891 *
2892 *----------------------------------------------------------------------
2893 */
2894
2895static int
2896WmStackorderCmd(
2897    Tk_Window tkwin,		/* Main window of the application. */
2898    TkWindow *winPtr,		/* Toplevel to work with */
2899    Tcl_Interp *interp,		/* Current interpreter. */
2900    int objc,			/* Number of arguments. */
2901    Tcl_Obj *const objv[])	/* Argument objects. */
2902{
2903    TkWindow **windows, **window_ptr;
2904    static const char *optionStrings[] = {
2905	"isabove", "isbelow", NULL };
2906    enum options {
2907	OPT_ISABOVE, OPT_ISBELOW };
2908    int index;
2909
2910    if ((objc != 3) && (objc != 5)) {
2911	Tcl_WrongNumArgs(interp, 2, objv, "window ?isabove|isbelow window?");
2912	return TCL_ERROR;
2913    }
2914
2915    if (objc == 3) {
2916	windows = TkWmStackorderToplevel(winPtr);
2917	if (windows == NULL) {
2918	    Tcl_Panic("TkWmStackorderToplevel failed");
2919	}
2920
2921	for (window_ptr = windows; *window_ptr ; window_ptr++) {
2922	    Tcl_AppendElement(interp, (*window_ptr)->pathName);
2923	}
2924	ckfree((char *) windows);
2925	return TCL_OK;
2926    } else {
2927	TkWindow *winPtr2;
2928	int index1=-1, index2=-1, result;
2929
2930	if (TkGetWindowFromObj(interp, tkwin, objv[4], (Tk_Window *) &winPtr2)
2931	    != TCL_OK) {
2932	    return TCL_ERROR;
2933	}
2934
2935	if (!Tk_IsTopLevel(winPtr2)) {
2936	    Tcl_AppendResult(interp, "window \"", winPtr2->pathName,
2937		    "\" isn't a top-level window", NULL);
2938	    return TCL_ERROR;
2939	}
2940
2941	if (!Tk_IsMapped(winPtr)) {
2942	    Tcl_AppendResult(interp, "window \"", winPtr->pathName,
2943		    "\" isn't mapped", NULL);
2944	    return TCL_ERROR;
2945	}
2946
2947	if (!Tk_IsMapped(winPtr2)) {
2948	    Tcl_AppendResult(interp, "window \"", winPtr2->pathName,
2949		    "\" isn't mapped", NULL);
2950	    return TCL_ERROR;
2951	}
2952
2953	/*
2954	 * Lookup stacking order of all toplevels that are children of "." and
2955	 * find the position of winPtr and winPtr2 in the stacking order.
2956	 */
2957
2958	windows = TkWmStackorderToplevel(winPtr->mainPtr->winPtr);
2959	if (windows == NULL) {
2960	    Tcl_AppendResult(interp, "TkWmStackorderToplevel failed", NULL);
2961	    return TCL_ERROR;
2962	}
2963
2964	for (window_ptr = windows; *window_ptr ; window_ptr++) {
2965	    if (*window_ptr == winPtr) {
2966		index1 = (window_ptr - windows);
2967	    }
2968	    if (*window_ptr == winPtr2) {
2969		index2 = (window_ptr - windows);
2970	    }
2971	}
2972	if (index1 == -1) {
2973	    Tcl_Panic("winPtr window not found");
2974	}
2975	if (index2 == -1) {
2976	    Tcl_Panic("winPtr2 window not found");
2977	}
2978
2979	ckfree((char *) windows);
2980
2981	if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
2982		&index) != TCL_OK) {
2983	    return TCL_ERROR;
2984	}
2985	if (index == OPT_ISABOVE) {
2986	    result = index1 > index2;
2987	} else { /* OPT_ISBELOW */
2988	    result = index1 < index2;
2989	}
2990	Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
2991	return TCL_OK;
2992    }
2993    return TCL_OK;
2994}
2995
2996/*
2997 *----------------------------------------------------------------------
2998 *
2999 * WmStateCmd --
3000 *
3001 *	This procedure is invoked to process the "wm state" Tcl command. See
3002 *	the user documentation for details on what it does.
3003 *
3004 * Results:
3005 *	A standard Tcl result.
3006 *
3007 * Side effects:
3008 *	See the user documentation.
3009 *
3010 *----------------------------------------------------------------------
3011 */
3012
3013static int
3014WmStateCmd(
3015    Tk_Window tkwin,		/* Main window of the application. */
3016    TkWindow *winPtr,		/* Toplevel to work with */
3017    Tcl_Interp *interp,		/* Current interpreter. */
3018    int objc,			/* Number of arguments. */
3019    Tcl_Obj *const objv[])	/* Argument objects. */
3020{
3021    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3022    static const char *optionStrings[] = {
3023	"normal", "iconic", "withdrawn", "zoomed", NULL };
3024    enum options {
3025	OPT_NORMAL, OPT_ICONIC, OPT_WITHDRAWN, OPT_ZOOMED };
3026    int index;
3027
3028    if ((objc < 3) || (objc > 4)) {
3029	Tcl_WrongNumArgs(interp, 2, objv, "window ?state?");
3030	return TCL_ERROR;
3031    }
3032    if (objc == 4) {
3033	if (wmPtr->iconFor != NULL) {
3034	    Tcl_AppendResult(interp, "can't change state of ",
3035		    Tcl_GetString(objv[2]), ": it is an icon for ",
3036		    Tk_PathName(wmPtr->iconFor), NULL);
3037	    return TCL_ERROR;
3038	}
3039	if (winPtr->flags & TK_EMBEDDED) {
3040	    Tcl_AppendResult(interp, "can't change state of ",
3041		    winPtr->pathName, ": it is an embedded window", NULL);
3042	    return TCL_ERROR;
3043	}
3044
3045	if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
3046				&index) != TCL_OK) {
3047	    return TCL_ERROR;
3048	}
3049
3050	if (index == OPT_NORMAL) {
3051	    TkpWmSetState(winPtr, NormalState);
3052
3053	    /*
3054	     * This varies from 'wm deiconify' because it does not force the
3055	     * window to be raised and receive focus
3056	     */
3057	} else if (index == OPT_ICONIC) {
3058	    if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
3059		Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
3060			"\": override-redirect flag is set", NULL);
3061		return TCL_ERROR;
3062	    }
3063	    if (wmPtr->master != None) {
3064		Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
3065			"\": it is a transient", NULL);
3066		return TCL_ERROR;
3067	    }
3068	    TkpWmSetState(winPtr, IconicState);
3069	} else if (index == OPT_WITHDRAWN) {
3070	    TkpWmSetState(winPtr, WithdrawnState);
3071	} else { /* OPT_ZOOMED */
3072	    TkpWmSetState(winPtr, ZoomState);
3073	}
3074    } else if (wmPtr->iconFor != NULL) {
3075	Tcl_SetResult(interp, "icon", TCL_STATIC);
3076    } else {
3077	if (wmPtr->hints.initial_state == NormalState ||
3078		wmPtr->hints.initial_state == ZoomState) {
3079	    wmPtr->hints.initial_state = (TkMacOSXIsWindowZoomed(winPtr) ?
3080		    ZoomState : NormalState);
3081	}
3082	switch (wmPtr->hints.initial_state) {
3083	case NormalState:
3084	    Tcl_SetResult(interp, "normal", TCL_STATIC);
3085	    break;
3086	case IconicState:
3087	    Tcl_SetResult(interp, "iconic", TCL_STATIC);
3088	    break;
3089	case WithdrawnState:
3090	    Tcl_SetResult(interp, "withdrawn", TCL_STATIC);
3091	    break;
3092	case ZoomState:
3093	    Tcl_SetResult(interp, "zoomed", TCL_STATIC);
3094	    break;
3095	}
3096    }
3097    return TCL_OK;
3098}
3099
3100/*
3101 *----------------------------------------------------------------------
3102 *
3103 * WmTitleCmd --
3104 *
3105 *	This procedure is invoked to process the "wm title" Tcl command. See
3106 *	the user documentation for details on what it does.
3107 *
3108 * Results:
3109 *	A standard Tcl result.
3110 *
3111 * Side effects:
3112 *	See the user documentation.
3113 *
3114 *----------------------------------------------------------------------
3115 */
3116
3117static int
3118WmTitleCmd(
3119    Tk_Window tkwin,		/* Main window of the application. */
3120    TkWindow *winPtr,		/* Toplevel to work with */
3121    Tcl_Interp *interp,		/* Current interpreter. */
3122    int objc,			/* Number of arguments. */
3123    Tcl_Obj *const objv[])	/* Argument objects. */
3124{
3125    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3126    char *argv3;
3127    int length;
3128
3129    if (objc > 4) {
3130	Tcl_WrongNumArgs(interp, 2, objv, "window ?newTitle?");
3131	return TCL_ERROR;
3132    }
3133    if (objc == 3) {
3134	Tcl_SetResult(interp, (char *)((wmPtr->titleUid != NULL) ?
3135		wmPtr->titleUid : winPtr->nameUid), TCL_STATIC);
3136	return TCL_OK;
3137    }
3138    argv3 = Tcl_GetStringFromObj(objv[3], &length);
3139    wmPtr->titleUid = Tk_GetUid(argv3);
3140    if (!(wmPtr->flags & WM_NEVER_MAPPED) && !Tk_IsEmbedded(winPtr)) {
3141	TkSetWMName(winPtr, wmPtr->titleUid);
3142    }
3143    return TCL_OK;
3144}
3145
3146/*
3147 *----------------------------------------------------------------------
3148 *
3149 * WmTransientCmd --
3150 *
3151 *	This procedure is invoked to process the "wm transient" Tcl command.
3152 *	See the user documentation for details on what it does.
3153 *
3154 * Results:
3155 *	A standard Tcl result.
3156 *
3157 * Side effects:
3158 *	See the user documentation.
3159 *
3160 *----------------------------------------------------------------------
3161 */
3162
3163static int
3164WmTransientCmd(
3165    Tk_Window tkwin,		/* Main window of the application. */
3166    TkWindow *winPtr,		/* Toplevel to work with */
3167    Tcl_Interp *interp,		/* Current interpreter. */
3168    int objc,			/* Number of arguments. */
3169    Tcl_Obj *const objv[])	/* Argument objects. */
3170{
3171    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3172    Tk_Window master;
3173    WmInfo *wmPtr2;
3174    char *masterWindowName;
3175    int length;
3176
3177    if ((objc != 3) && (objc != 4)) {
3178	Tcl_WrongNumArgs(interp, 2, objv, "window ?master?");
3179	return TCL_ERROR;
3180    }
3181    if (objc == 3) {
3182	if (wmPtr->master != None) {
3183	    Tcl_SetResult(interp, wmPtr->masterWindowName, TCL_STATIC);
3184	}
3185	return TCL_OK;
3186    }
3187    if (Tcl_GetString(objv[3])[0] == '\0') {
3188	wmPtr->master = None;
3189	if (wmPtr->masterWindowName != NULL) {
3190	    ckfree(wmPtr->masterWindowName);
3191	}
3192	wmPtr->masterWindowName = NULL;
3193    } else {
3194	if (TkGetWindowFromObj(interp, tkwin, objv[3], &master) != TCL_OK) {
3195	    return TCL_ERROR;
3196	}
3197	Tk_MakeWindowExist(master);
3198
3199	if (wmPtr->iconFor != NULL) {
3200	    Tcl_AppendResult(interp, "can't make \"", Tcl_GetString(objv[2]),
3201		    "\" a transient: it is an icon for ",
3202		    Tk_PathName(wmPtr->iconFor), NULL);
3203	    return TCL_ERROR;
3204	}
3205
3206	wmPtr2 = ((TkWindow *) master)->wmInfoPtr;
3207
3208	/* Under some circumstances, wmPtr2 is NULL here */
3209	if (wmPtr2 != NULL && wmPtr2->iconFor != NULL) {
3210	    Tcl_AppendResult(interp, "can't make \"", Tcl_GetString(objv[3]),
3211		    "\" a master: it is an icon for ",
3212		    Tk_PathName(wmPtr2->iconFor), NULL);
3213	    return TCL_ERROR;
3214	}
3215
3216	if ((TkWindow *) master == winPtr) {
3217	    Tcl_AppendResult(interp, "can't make \"", Tk_PathName(winPtr),
3218		    "\" its own master", NULL);
3219	    return TCL_ERROR;
3220	}
3221
3222	wmPtr->master = Tk_WindowId(master);
3223	masterWindowName = Tcl_GetStringFromObj(objv[3], &length);
3224	if (wmPtr->masterWindowName != NULL) {
3225	    ckfree(wmPtr->masterWindowName);
3226	}
3227	wmPtr->masterWindowName = ckalloc((unsigned) length+1);
3228	strcpy(wmPtr->masterWindowName, masterWindowName);
3229    }
3230    ApplyMasterOverrideChanges(winPtr, NULL);
3231    return TCL_OK;
3232}
3233
3234/*
3235 *----------------------------------------------------------------------
3236 *
3237 * WmWithdrawCmd --
3238 *
3239 *	This procedure is invoked to process the "wm withdraw" Tcl command.
3240 *	See the user documentation for details on what it does.
3241 *
3242 * Results:
3243 *	A standard Tcl result.
3244 *
3245 * Side effects:
3246 *	See the user documentation.
3247 *
3248 *----------------------------------------------------------------------
3249 */
3250
3251static int
3252WmWithdrawCmd(
3253    Tk_Window tkwin,		/* Main window of the application. */
3254    TkWindow *winPtr,		/* Toplevel to work with */
3255    Tcl_Interp *interp,		/* Current interpreter. */
3256    int objc,			/* Number of arguments. */
3257    Tcl_Obj *const objv[])	/* Argument objects. */
3258{
3259    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3260
3261    if (objc != 3) {
3262	Tcl_WrongNumArgs(interp, 2, objv, "window");
3263	return TCL_ERROR;
3264    }
3265    if (wmPtr->iconFor != NULL) {
3266	Tcl_AppendResult(interp, "can't withdraw ", Tcl_GetString(objv[2]),
3267		": it is an icon for ", Tk_PathName(wmPtr->iconFor), NULL);
3268	return TCL_ERROR;
3269    }
3270    TkpWmSetState(winPtr, WithdrawnState);
3271    return TCL_OK;
3272}
3273
3274/*
3275 * Invoked by those wm subcommands that affect geometry.
3276 * Schedules a geometry update.
3277 */
3278
3279static void
3280WmUpdateGeom(
3281    WmInfo *wmPtr,
3282    TkWindow *winPtr)
3283{
3284    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
3285	Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
3286	wmPtr->flags |= WM_UPDATE_PENDING;
3287    }
3288}
3289
3290/*
3291 *----------------------------------------------------------------------
3292 *
3293 * Tk_SetGrid --
3294 *
3295 *	This procedure is invoked by a widget when it wishes to set a grid
3296 *	coordinate system that controls the size of a top-level window. It
3297 *	provides a C interface equivalent to the "wm grid" command and is
3298 *	usually asscoiated with the -setgrid option.
3299 *
3300 * Results:
3301 *	None.
3302 *
3303 * Side effects:
3304 *	Grid-related information will be passed to the window manager, so that
3305 *	the top-level window associated with tkwin will resize on even grid
3306 *	units. If some other window already controls gridding for the
3307 *	top-level window then this procedure call has no effect.
3308 *
3309 *----------------------------------------------------------------------
3310 */
3311
3312void
3313Tk_SetGrid(
3314    Tk_Window tkwin,		/* Token for window. New window mgr info will
3315				 * be posted for the top-level window
3316				 * associated with this window. */
3317    int reqWidth,		/* Width (in grid units) corresponding to the
3318				 * requested geometry for tkwin. */
3319    int reqHeight,		/* Height (in grid units) corresponding to the
3320				 * requested geometry for tkwin. */
3321    int widthInc, int heightInc)/* Pixel increments corresponding to a change
3322				 * of one grid unit. */
3323{
3324    TkWindow *winPtr = (TkWindow *) tkwin;
3325    WmInfo *wmPtr;
3326
3327    /*
3328     * Ensure widthInc and heightInc are greater than 0
3329     */
3330
3331    if (widthInc <= 0) {
3332	widthInc = 1;
3333    }
3334    if (heightInc <= 0) {
3335	heightInc = 1;
3336    }
3337
3338    /*
3339     * Find the top-level window for tkwin, plus the window manager
3340     * information.
3341     */
3342
3343    while (!(winPtr->flags & TK_TOP_LEVEL)) {
3344	winPtr = winPtr->parentPtr;
3345    }
3346    wmPtr = winPtr->wmInfoPtr;
3347
3348    if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
3349	return;
3350    }
3351
3352    if ((wmPtr->reqGridWidth == reqWidth)
3353	    && (wmPtr->reqGridHeight == reqHeight)
3354	    && (wmPtr->widthInc == widthInc)
3355	    && (wmPtr->heightInc == heightInc)
3356	    && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
3357		    == (PBaseSize|PResizeInc))) {
3358	return;
3359    }
3360
3361    /*
3362     * If gridding was previously off, then forget about any window size
3363     * requests made by the user or via "wm geometry": these are in pixel
3364     * units and there's no easy way to translate them to grid units since the
3365     * new requested size of the top-level window in pixels may not yet have
3366     * been registered yet (it may filter up the hierarchy in DoWhenIdle
3367     * handlers). However, if the window has never been mapped yet then just
3368     * leave the window size alone: assume that it is intended to be in grid
3369     * units but just happened to have been specified before this procedure
3370     * was called.
3371     */
3372
3373    if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
3374	wmPtr->width = -1;
3375	wmPtr->height = -1;
3376    }
3377
3378    /*
3379     * Set the new gridding information, and start the process of passing all
3380     * of this information to the window manager.
3381     */
3382
3383    wmPtr->gridWin = tkwin;
3384    wmPtr->reqGridWidth = reqWidth;
3385    wmPtr->reqGridHeight = reqHeight;
3386    wmPtr->widthInc = widthInc;
3387    wmPtr->heightInc = heightInc;
3388    wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
3389    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
3390    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
3391	Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
3392	wmPtr->flags |= WM_UPDATE_PENDING;
3393    }
3394}
3395
3396/*
3397 *----------------------------------------------------------------------
3398 *
3399 * Tk_UnsetGrid --
3400 *
3401 *	This procedure cancels the effect of a previous call to Tk_SetGrid.
3402 *
3403 * Results:
3404 *	None.
3405 *
3406 * Side effects:
3407 *	If tkwin currently controls gridding for its top-level window,
3408 *	gridding is cancelled for that top-level window; if some other window
3409 *	controls gridding then this procedure has no effect.
3410 *
3411 *----------------------------------------------------------------------
3412 */
3413
3414void
3415Tk_UnsetGrid(
3416    Tk_Window tkwin)		/* Token for window that is currently
3417				 * controlling gridding. */
3418{
3419    TkWindow *winPtr = (TkWindow *) tkwin;
3420    WmInfo *wmPtr;
3421
3422    /*
3423     * Find the top-level window for tkwin, plus the window manager
3424     * information.
3425     */
3426
3427    while (!(winPtr->flags & TK_TOP_LEVEL)) {
3428	winPtr = winPtr->parentPtr;
3429    }
3430    wmPtr = winPtr->wmInfoPtr;
3431    if (tkwin != wmPtr->gridWin) {
3432	return;
3433    }
3434
3435    wmPtr->gridWin = NULL;
3436    wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
3437    if (wmPtr->width != -1) {
3438	wmPtr->width = winPtr->reqWidth + (wmPtr->width
3439		- wmPtr->reqGridWidth)*wmPtr->widthInc;
3440	wmPtr->height = winPtr->reqHeight + (wmPtr->height
3441		- wmPtr->reqGridHeight)*wmPtr->heightInc;
3442    }
3443    wmPtr->widthInc = 1;
3444    wmPtr->heightInc = 1;
3445
3446    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
3447    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
3448	Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
3449	wmPtr->flags |= WM_UPDATE_PENDING;
3450    }
3451}
3452
3453/*
3454 *----------------------------------------------------------------------
3455 *
3456 * TopLevelEventProc --
3457 *
3458 *	This procedure is invoked when a top-level (or other externally-
3459 *	managed window) is restructured in any way.
3460 *
3461 * Results:
3462 *	None.
3463 *
3464 * Side effects:
3465 *	Tk's internal data structures for the window get modified to reflect
3466 *	the structural change.
3467 *
3468 *----------------------------------------------------------------------
3469 */
3470
3471static void
3472TopLevelEventProc(
3473    ClientData clientData,	/* Window for which event occurred. */
3474    XEvent *eventPtr)		/* Event that just happened. */
3475{
3476    TkWindow *winPtr = clientData;
3477
3478    winPtr->wmInfoPtr->flags |= WM_VROOT_OFFSET_STALE;
3479    if (eventPtr->type == DestroyNotify) {
3480	if (!(winPtr->flags & TK_ALREADY_DEAD)) {
3481	    /*
3482	     * A top-level window was deleted externally (e.g., by the window
3483	     * manager). This is probably not a good thing, but cleanup as
3484	     * best we can. The error handler is needed because
3485	     * Tk_DestroyWindow will try to destroy the window, but of course
3486	     * it's already gone.
3487	     */
3488
3489	    Tk_ErrorHandler handler = Tk_CreateErrorHandler(winPtr->display,
3490		    -1, -1, -1, NULL, NULL);
3491
3492	    Tk_DestroyWindow((Tk_Window) winPtr);
3493	    Tk_DeleteErrorHandler(handler);
3494	}
3495	if (wmTracing) {
3496	    TkMacOSXDbgMsg("TopLevelEventProc: %s deleted", winPtr->pathName);
3497	}
3498    } else if (eventPtr->type == ReparentNotify) {
3499	Tcl_Panic("recieved unwanted reparent event");
3500    }
3501}
3502
3503/*
3504 *----------------------------------------------------------------------
3505 *
3506 * TopLevelReqProc --
3507 *
3508 *	This procedure is invoked by the geometry manager whenever the
3509 *	requested size for a top-level window is changed.
3510 *
3511 * Results:
3512 *	None.
3513 *
3514 * Side effects:
3515 *	Arrange for the window to be resized to satisfy the request (this
3516 *	happens as a when-idle action).
3517 *
3518 *----------------------------------------------------------------------
3519 */
3520
3521	/* ARGSUSED */
3522static void
3523TopLevelReqProc(
3524    ClientData dummy,		/* Not used. */
3525    Tk_Window tkwin)		/* Information about window. */
3526{
3527    TkWindow *winPtr = (TkWindow *) tkwin;
3528    WmInfo *wmPtr;
3529
3530    wmPtr = winPtr->wmInfoPtr;
3531    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
3532    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
3533	Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
3534	wmPtr->flags |= WM_UPDATE_PENDING;
3535    }
3536}
3537
3538/*
3539 *----------------------------------------------------------------------
3540 *
3541 * UpdateGeometryInfo --
3542 *
3543 *	This procedure is invoked when a top-level window is first mapped, and
3544 *	also as a when-idle procedure, to bring the geometry and/or position
3545 *	of a top-level window back into line with what has been requested by
3546 *	the user and/or widgets. This procedure doesn't return until the
3547 *	window manager has responded to the geometry change.
3548 *
3549 * Results:
3550 *	None.
3551 *
3552 * Side effects:
3553 *	The window's size and location may change, unless the WM prevents that
3554 *	from happening.
3555 *
3556 *----------------------------------------------------------------------
3557 */
3558
3559static void
3560UpdateGeometryInfo(
3561    ClientData clientData)	/* Pointer to the window's record. */
3562{
3563    TkWindow *winPtr = clientData;
3564    WmInfo *wmPtr = winPtr->wmInfoPtr;
3565    int x, y, width, height, min, max;
3566
3567    wmPtr->flags &= ~WM_UPDATE_PENDING;
3568
3569    if (wmPtr->flags & WM_FULLSCREEN) {
3570	return;
3571    }
3572
3573    /*
3574     * Compute the new size for the top-level window. See the user
3575     * documentation for details on this, but the size requested depends on
3576     * (a) the size requested internally by the window's widgets, (b) the size
3577     * requested by the user in a "wm geometry" command or via wm-based
3578     * interactive resizing (if any), and (c) whether or not the window is
3579     * gridded. Don't permit sizes <= 0 because this upsets the X server.
3580     */
3581
3582    if (wmPtr->width == -1) {
3583	width = winPtr->reqWidth;
3584    } else if (wmPtr->gridWin != NULL) {
3585	width = winPtr->reqWidth
3586		+ (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
3587    } else {
3588	width = wmPtr->width;
3589    }
3590    if (width <= 0) {
3591	width = 1;
3592    }
3593
3594    /*
3595     * Account for window max/min width
3596     */
3597
3598    if (wmPtr->gridWin != NULL) {
3599	min = winPtr->reqWidth
3600		+ (wmPtr->minWidth - wmPtr->reqGridWidth)*wmPtr->widthInc;
3601	if (wmPtr->maxWidth > 0) {
3602	    max = winPtr->reqWidth
3603		    + (wmPtr->maxWidth - wmPtr->reqGridWidth)*wmPtr->widthInc;
3604	} else {
3605	    max = 0;
3606	}
3607    } else {
3608	min = wmPtr->minWidth;
3609	max = wmPtr->maxWidth;
3610    }
3611    if (width < min) {
3612	width = min;
3613    } else if ((max > 0) && (width > max)) {
3614	width = max;
3615    }
3616
3617    if (wmPtr->height == -1) {
3618	height = winPtr->reqHeight;
3619    } else if (wmPtr->gridWin != NULL) {
3620	height = winPtr->reqHeight
3621		+ (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
3622    } else {
3623	height = wmPtr->height;
3624    }
3625    if (height <= 0) {
3626	height = 1;
3627    }
3628
3629    /*
3630     * Account for window max/min height
3631     */
3632
3633    if (wmPtr->gridWin != NULL) {
3634	min = winPtr->reqHeight
3635		+ (wmPtr->minHeight - wmPtr->reqGridHeight)*wmPtr->heightInc;
3636	if (wmPtr->maxHeight > 0) {
3637	    max = winPtr->reqHeight
3638		    + (wmPtr->maxHeight-wmPtr->reqGridHeight)*wmPtr->heightInc;
3639	} else {
3640	    max = 0;
3641	}
3642    } else {
3643	min = wmPtr->minHeight;
3644	max = wmPtr->maxHeight;
3645    }
3646    if (height < min) {
3647	height = min;
3648    } else if ((max > 0) && (height > max)) {
3649	height = max;
3650    }
3651
3652    /*
3653     * Compute the new position for the upper-left pixel of the window's
3654     * decorative frame. This is tricky, because we need to include the border
3655     * widths supplied by a reparented parent in this calculation, but can't
3656     * use the parent's current overall size since that may change as a result
3657     * of this code.
3658     */
3659
3660    if (wmPtr->flags & WM_NEGATIVE_X) {
3661	x = wmPtr->vRootWidth - wmPtr->x
3662	    - (width + (wmPtr->parentWidth - winPtr->changes.width));
3663    } else {
3664	x =  wmPtr->x;
3665    }
3666    if (wmPtr->flags & WM_NEGATIVE_Y) {
3667	y = wmPtr->vRootHeight - wmPtr->y
3668	    - (height + (wmPtr->parentHeight - winPtr->changes.height));
3669    } else {
3670	y =  wmPtr->y;
3671    }
3672
3673    /*
3674     * If the window's size is going to change and the window is supposed to
3675     * not be resizable by the user, then we have to update the size hints.
3676     * There may also be a size-hint-update request pending from somewhere
3677     * else, too.
3678     */
3679
3680    if (((width != winPtr->changes.width)
3681	    || (height != winPtr->changes.height))
3682	    && (wmPtr->gridWin == NULL)
3683	    && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
3684	wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
3685    }
3686    if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) {
3687	UpdateSizeHints(winPtr);
3688    }
3689
3690    /*
3691     * Reconfigure the window if it isn't already configured correctly. A few
3692     * tricky points:
3693     *
3694     * 1. If the window is embedded and the container is also in this process,
3695     *    don't actually reconfigure the window; just pass the desired size on
3696     *    to the container. Also, zero out any position information, since
3697     *    embedded windows are not allowed to move.
3698     * 2. Sometimes the window manager will give us a different size than we
3699     *    asked for (e.g. mwm has a minimum size for windows), so base the
3700     *    size check on what we *asked for* last time, not what we got.
3701     * 3. Don't move window unless a new position has been requested for it.
3702     *    This is because of "features" in some window managers (e.g. twm, as
3703     *    of 4/24/91) where they don't interpret coordinates according to
3704     *    ICCCM. Moving a window to its current location may cause it to shift
3705     *    position on the screen.
3706     */
3707
3708    if (Tk_IsEmbedded(winPtr)) {
3709	TkWindow *contWinPtr = TkpGetOtherWindow(winPtr);
3710
3711	/*
3712	 * TODO: Here we should handle out of process embedding.
3713	 */
3714
3715	if (contWinPtr != NULL) {
3716	    /*
3717	     * This window is embedded and the container is also in this
3718	     * process, so we don't need to do anything special about the
3719	     * geometry, except to make sure that the desired size is known by
3720	     * the container. Also, zero out any position information, since
3721	     * embedded windows are not allowed to move.
3722	     */
3723
3724	    wmPtr->x = wmPtr->y = 0;
3725	    wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
3726	    Tk_GeometryRequest((Tk_Window) contWinPtr, width, height);
3727	}
3728	return;
3729    }
3730    if (wmPtr->flags & WM_MOVE_PENDING) {
3731	wmPtr->configWidth = width;
3732	wmPtr->configHeight = height;
3733	if (wmTracing) {
3734	    TkMacOSXDbgMsg("Moving to %d %d, resizing to %d x %d", x, y,
3735		    width, height);
3736	}
3737	SetWindowSizeLimits(winPtr);
3738	wmPtr->flags |= WM_SYNC_PENDING;
3739	XMoveResizeWindow(winPtr->display, winPtr->window, x, y,
3740		wmPtr->configWidth, wmPtr->configHeight);
3741	wmPtr->flags &= ~WM_SYNC_PENDING;
3742    } else if ((width != wmPtr->configWidth)
3743	    || (height != wmPtr->configHeight)) {
3744	wmPtr->configWidth = width;
3745	wmPtr->configHeight = height;
3746	if (wmTracing) {
3747	    TkMacOSXDbgMsg("Resizing to %d x %d\n", width, height);
3748	}
3749	SetWindowSizeLimits(winPtr);
3750	wmPtr->flags |= WM_SYNC_PENDING;
3751	XResizeWindow(winPtr->display, winPtr->window, wmPtr->configWidth,
3752		wmPtr->configHeight);
3753	wmPtr->flags &= ~WM_SYNC_PENDING;
3754    } else {
3755	SetWindowSizeLimits(winPtr);
3756    }
3757}
3758
3759/*
3760 *----------------------------------------------------------------------
3761 *
3762 * UpdateSizeHints --
3763 *
3764 *	This procedure is called to update the window manager's size hints
3765 *	information from the information in a WmInfo structure.
3766 *
3767 * Results:
3768 *	None.
3769 *
3770 * Side effects:
3771 *	Properties get changed for winPtr.
3772 *
3773 *----------------------------------------------------------------------
3774 */
3775
3776static void
3777UpdateSizeHints(
3778    TkWindow *winPtr)
3779{
3780    WmInfo *wmPtr = winPtr->wmInfoPtr;
3781
3782    wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS;
3783}
3784
3785/*
3786 *----------------------------------------------------------------------
3787 *
3788 * ParseGeometry --
3789 *
3790 *	This procedure parses a geometry string and updates information used
3791 *	to control the geometry of a top-level window.
3792 *
3793 * Results:
3794 *	A standard Tcl return value, plus an error message in the interp's
3795 *	result if an error occurs.
3796 *
3797 * Side effects:
3798 *	The size and/or location of winPtr may change.
3799 *
3800 *----------------------------------------------------------------------
3801 */
3802
3803static int
3804ParseGeometry(
3805    Tcl_Interp *interp,		/* Used for error reporting. */
3806    char *string,		/* String containing new geometry. Has the
3807				 * standard form "=wxh+x+y". */
3808    TkWindow *winPtr)		/* Pointer to top-level window whose geometry
3809				 * is to be changed. */
3810{
3811    WmInfo *wmPtr = winPtr->wmInfoPtr;
3812    int x, y, width, height, flags;
3813    char *end;
3814    char *p = string;
3815
3816    /*
3817     * The leading "=" is optional.
3818     */
3819
3820    if (*p == '=') {
3821	p++;
3822    }
3823
3824    /*
3825     * Parse the width and height, if they are present. Don't actually update
3826     * any of the fields of wmPtr until we've successfully parsed the entire
3827     * geometry string.
3828     */
3829
3830    width = wmPtr->width;
3831    height = wmPtr->height;
3832    x = wmPtr->x;
3833    y = wmPtr->y;
3834    flags = wmPtr->flags;
3835    if (isdigit(UCHAR(*p))) {
3836	width = strtoul(p, &end, 10);
3837	p = end;
3838	if (*p != 'x') {
3839	    goto error;
3840	}
3841	p++;
3842	if (!isdigit(UCHAR(*p))) {
3843	    goto error;
3844	}
3845	height = strtoul(p, &end, 10);
3846	p = end;
3847    }
3848
3849    /*
3850     * Parse the X and Y coordinates, if they are present.
3851     */
3852
3853    if (*p != '\0') {
3854	flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
3855	if (*p == '-') {
3856	    flags |= WM_NEGATIVE_X;
3857	} else if (*p != '+') {
3858	    goto error;
3859	}
3860	p++;
3861	if (!isdigit(UCHAR(*p)) && (*p != '-')) {
3862	    goto error;
3863	}
3864	x = strtol(p, &end, 10);
3865	p = end;
3866	if (*p == '-') {
3867	    flags |= WM_NEGATIVE_Y;
3868	} else if (*p != '+') {
3869	    goto error;
3870	}
3871	p++;
3872	if (!isdigit(UCHAR(*p)) && (*p != '-')) {
3873	    goto error;
3874	}
3875	y = strtol(p, &end, 10);
3876	if (*end != '\0') {
3877	    goto error;
3878	}
3879
3880	/*
3881	 * Assume that the geometry information came from the user, unless an
3882	 * explicit source has been specified. Otherwise most window managers
3883	 * assume that the size hints were program-specified and they ignore
3884	 * them.
3885	 */
3886
3887	if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
3888	    wmPtr->sizeHintsFlags |= USPosition;
3889	    flags |= WM_UPDATE_SIZE_HINTS;
3890	}
3891    }
3892
3893    /*
3894     * Everything was parsed OK. Update the fields of *wmPtr and arrange for
3895     * the appropriate information to be percolated out to the window manager
3896     * at the next idle moment.
3897     */
3898
3899    wmPtr->width = width;
3900    wmPtr->height = height;
3901    if ((x != wmPtr->x) || (y != wmPtr->y)
3902	    || ((flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y))
3903		    != (wmPtr->flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y)))) {
3904	if (wmPtr->flags & WM_FULLSCREEN) {
3905	    wmPtr->configX = x;
3906	    wmPtr->configY = y;
3907	} else {
3908	    wmPtr->x = x;
3909	    wmPtr->y = y;
3910	}
3911	flags |= WM_MOVE_PENDING;
3912    }
3913    wmPtr->flags = flags;
3914
3915    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
3916	Tcl_DoWhenIdle(UpdateGeometryInfo, winPtr);
3917	wmPtr->flags |= WM_UPDATE_PENDING;
3918    }
3919    return TCL_OK;
3920
3921  error:
3922    Tcl_AppendResult(interp, "bad geometry specifier \"", string, "\"", NULL);
3923    return TCL_ERROR;
3924}
3925
3926/*
3927 *----------------------------------------------------------------------
3928 *
3929 * Tk_GetRootCoords --
3930 *
3931 *	Given a token for a window, this procedure traces through the window's
3932 *	lineage to find the (virtual) root-window coordinates corresponding to
3933 *	point (0,0) in the window.
3934 *
3935 * Results:
3936 *	The locations pointed to by xPtr and yPtr are filled in with the root
3937 *	coordinates of the (0,0) point in tkwin. If a virtual root window is
3938 *	in effect for the window, then the coordinates in the virtual root are
3939 *	returned.
3940 *
3941 * Side effects:
3942 *	None.
3943 *
3944 *----------------------------------------------------------------------
3945 */
3946
3947void
3948Tk_GetRootCoords(
3949    Tk_Window tkwin,		/* Token for window. */
3950    int *xPtr,			/* Where to store x-displacement of (0,0). */
3951    int *yPtr)			/* Where to store y-displacement of (0,0). */
3952{
3953    int x, y;
3954    TkWindow *winPtr = (TkWindow *) tkwin;
3955
3956    /*
3957     * Search back through this window's parents all the way to a top-level
3958     * window, combining the offsets of each window within its parent.
3959     */
3960
3961    x = y = 0;
3962    while (1) {
3963	x += winPtr->changes.x + winPtr->changes.border_width;
3964	y += winPtr->changes.y + winPtr->changes.border_width;
3965	if (winPtr->flags & TK_TOP_LEVEL) {
3966	    TkWindow *otherPtr;
3967
3968	    if (!(Tk_IsEmbedded(winPtr))) {
3969		x += winPtr->wmInfoPtr->xInParent;
3970		y += winPtr->wmInfoPtr->yInParent;
3971		break;
3972	    }
3973
3974	    otherPtr = TkpGetOtherWindow(winPtr);
3975	    if (otherPtr == NULL) {
3976		if (tkMacOSXEmbedHandler->getOffsetProc != NULL) {
3977		    Point theOffset;
3978
3979		    /*
3980		     * We do not require that the changes.x & changes.y for a
3981		     * non-Tk master window be kept up to date. So we first
3982		     * subtract off the possibly bogus values that have been
3983		     * added on at the top of this pass through the loop, and
3984		     * then call out to the getOffsetProc to give us the
3985		     * correct offset.
3986		     */
3987
3988		    x -= winPtr->changes.x + winPtr->changes.border_width;
3989		    y -= winPtr->changes.y + winPtr->changes.border_width;
3990
3991		    tkMacOSXEmbedHandler->getOffsetProc((Tk_Window) winPtr,
3992			    &theOffset);
3993
3994		    x += theOffset.h;
3995		    y += theOffset.v;
3996		}
3997		break;
3998	    }
3999
4000	    /*
4001	     * The container window is in the same application. Query its
4002	     * coordinates.
4003	     */
4004
4005	    winPtr = otherPtr;
4006
4007	    /*
4008	     * Remember to offset by the container window here, since at the
4009	     * end of this if branch, we will pop out to the container's
4010	     * parent...
4011	     */
4012
4013	    x += winPtr->changes.x + winPtr->changes.border_width;
4014	    y += winPtr->changes.y + winPtr->changes.border_width;
4015	}
4016	winPtr = winPtr->parentPtr;
4017    }
4018    *xPtr = x;
4019    *yPtr = y;
4020}
4021
4022/*
4023 *----------------------------------------------------------------------
4024 *
4025 * Tk_CoordsToWindow --
4026 *
4027 *	This is a Macintosh specific implementation of this function. Given
4028 *	the root coordinates of a point, this procedure returns the token for
4029 *	the top-most window covering that point, if there exists such a window
4030 *	in this application.
4031 *
4032 * Results:
4033 *	The return result is either a token for the window corresponding to
4034 *	rootX and rootY, or else NULL to indicate that there is no such
4035 *	window.
4036 *
4037 * Side effects:
4038 *	None.
4039 *
4040 *----------------------------------------------------------------------
4041 */
4042
4043Tk_Window
4044Tk_CoordsToWindow(
4045    int rootX, int rootY,	/* Coordinates of point in root window. If a
4046				 * virtual-root window manager is in use,
4047				 * these coordinates refer to the virtual
4048				 * root, not the real root. */
4049    Tk_Window tkwin)		/* Token for any window in application; used
4050				 * to identify the display. */
4051{
4052    TkWindow *winPtr, *childPtr;
4053    TkWindow *nextPtr;		/* Coordinates of highest child found so far
4054				 * that contains point. */
4055    int x, y;			/* Coordinates in winPtr. */
4056    int tmpx, tmpy, bd;
4057
4058    /*
4059     * Step 1: find the top-level window that contains the desired point.
4060     */
4061
4062    winPtr = FrontWindowAtPoint(rootX, rootY);
4063    if (!winPtr) {
4064	return NULL;
4065    }
4066
4067    /*
4068     * Step 2: work down through the hierarchy underneath this window. At each
4069     * level, scan through all the children to find the highest one in the
4070     * stacking order that contains the point. Then repeat the whole process
4071     * on that child.
4072     */
4073
4074    x = rootX - winPtr->wmInfoPtr->xInParent;
4075    y = rootY - winPtr->wmInfoPtr->yInParent;
4076    while (1) {
4077	x -= winPtr->changes.x;
4078	y -= winPtr->changes.y;
4079	nextPtr = NULL;
4080
4081	/*
4082	 * Container windows cannot have children. So if it is a container,
4083	 * look there, otherwise inspect the children.
4084	 */
4085
4086	if (Tk_IsContainer(winPtr)) {
4087	    childPtr = TkpGetOtherWindow(winPtr);
4088	    if (childPtr != NULL) {
4089		if (Tk_IsMapped(childPtr)) {
4090		    tmpx = x - childPtr->changes.x;
4091		    tmpy = y - childPtr->changes.y;
4092		    bd = childPtr->changes.border_width;
4093
4094		    if ((tmpx >= -bd) && (tmpy >= -bd)
4095			    && (tmpx < (childPtr->changes.width + bd))
4096			    && (tmpy < (childPtr->changes.height + bd))) {
4097			nextPtr = childPtr;
4098		    }
4099		}
4100	    }
4101
4102	    /*
4103	     * TODO: Here we should handle out of process embedding.
4104	     */
4105	} else {
4106	    for (childPtr = winPtr->childList; childPtr != NULL;
4107		    childPtr = childPtr->nextPtr) {
4108		if (!Tk_IsMapped(childPtr) ||
4109			(childPtr->flags & TK_TOP_LEVEL)) {
4110		    continue;
4111		}
4112		tmpx = x - childPtr->changes.x;
4113		tmpy = y - childPtr->changes.y;
4114		bd = childPtr->changes.border_width;
4115		if ((tmpx >= -bd) && (tmpy >= -bd)
4116			&& (tmpx < (childPtr->changes.width + bd))
4117			&& (tmpy < (childPtr->changes.height + bd))) {
4118		    nextPtr = childPtr;
4119		}
4120	    }
4121	}
4122	if (nextPtr == NULL) {
4123	    break;
4124	}
4125	winPtr = nextPtr;
4126    }
4127    return (Tk_Window) winPtr;
4128}
4129
4130/*
4131 *----------------------------------------------------------------------
4132 *
4133 * Tk_TopCoordsToWindow --
4134 *
4135 *	Given a Tk Window, and coordinates of a point relative to that window
4136 *	this procedure returns the top-most child of the window (excluding
4137 *	toplevels) covering that point, if there exists such a window in this
4138 *	application. It also sets newX, and newY to the coords of the point
4139 *	relative to the window returned.
4140 *
4141 * Results:
4142 *	The return result is either a token for the window corresponding to
4143 *	rootX and rootY, or else NULL to indicate that there is no such
4144 *	window. newX and newY are also set to the coords of the point relative
4145 *	to the returned window.
4146 *
4147 * Side effects:
4148 *	None.
4149 *
4150 *----------------------------------------------------------------------
4151 */
4152
4153Tk_Window
4154Tk_TopCoordsToWindow(
4155    Tk_Window tkwin,		/* Token for a Tk Window which defines the
4156				 * coordinates for rootX & rootY */
4157    int rootX, int rootY,	/* Coordinates of a point in tkWin. */
4158    int *newX, int *newY)	/* Coordinates of point in the upperMost child
4159				 * of tkWin containing (rootX,rootY) */
4160{
4161    TkWindow *winPtr, *childPtr;
4162    TkWindow *nextPtr;		/* Coordinates of highest child found so far
4163				 * that contains point. */
4164    int x, y;			/* Coordinates in winPtr. */
4165    Window *children;		/* Children of winPtr, or NULL. */
4166
4167    winPtr = (TkWindow *) tkwin;
4168    x = rootX;
4169    y = rootY;
4170    while (1) {
4171	nextPtr = NULL;
4172	children = NULL;
4173
4174	/*
4175	 * Container windows cannot have children. So if it is a container,
4176	 * look there, otherwise inspect the children.
4177	 */
4178
4179	if (Tk_IsContainer(winPtr)) {
4180	    childPtr = TkpGetOtherWindow(winPtr);
4181	    if (childPtr != NULL) {
4182		if (Tk_IsMapped(childPtr) &&
4183			x > childPtr->changes.x &&
4184			x < childPtr->changes.x + childPtr->changes.width &&
4185			y > childPtr->changes.y &&
4186			y < childPtr->changes.y + childPtr->changes.height) {
4187		    nextPtr = childPtr;
4188		}
4189	    }
4190
4191	    /*
4192	     * TODO: Here we should handle out of process embedding.
4193	     */
4194	} else {
4195	    for (childPtr = winPtr->childList; childPtr != NULL;
4196		    childPtr = childPtr->nextPtr) {
4197		if (!Tk_IsMapped(childPtr) ||
4198			(childPtr->flags & TK_TOP_LEVEL)) {
4199		    continue;
4200		}
4201		if (x < childPtr->changes.x || y < childPtr->changes.y) {
4202		    continue;
4203		}
4204		if (x > childPtr->changes.x + childPtr->changes.width ||
4205			y > childPtr->changes.y + childPtr->changes.height) {
4206		    continue;
4207		}
4208		nextPtr = childPtr;
4209	    }
4210	}
4211	if (nextPtr == NULL) {
4212	    break;
4213	}
4214	winPtr = nextPtr;
4215	x -= winPtr->changes.x;
4216	y -= winPtr->changes.y;
4217    }
4218    *newX = x;
4219    *newY = y;
4220    return (Tk_Window) winPtr;
4221}
4222
4223/*
4224 *----------------------------------------------------------------------
4225 *
4226 * UpdateVRootGeometry --
4227 *
4228 *	This procedure is called to update all the virtual root geometry
4229 *	information in wmPtr.
4230 *
4231 * Results:
4232 *	None.
4233 *
4234 * Side effects:
4235 *	The vRootX, vRootY, vRootWidth, and vRootHeight fields in wmPtr are
4236 *	filled with the most up-to-date information.
4237 *
4238 *----------------------------------------------------------------------
4239 */
4240
4241static void
4242UpdateVRootGeometry(
4243    WmInfo *wmPtr)		/* Window manager information to be updated.
4244				 * The wmPtr->vRoot field must be valid. */
4245{
4246    TkWindow *winPtr = wmPtr->winPtr;
4247    unsigned int bd, dummy;
4248    Window dummy2;
4249    Status status;
4250    Tk_ErrorHandler handler;
4251
4252    /*
4253     * If this isn't a virtual-root window manager, just return information
4254     * about the screen.
4255     */
4256
4257    wmPtr->flags &= ~WM_VROOT_OFFSET_STALE;
4258    if (wmPtr->vRoot == None) {
4259	noVRoot:
4260	wmPtr->vRootX = wmPtr->vRootY = 0;
4261	wmPtr->vRootWidth = DisplayWidth(winPtr->display, winPtr->screenNum);
4262	wmPtr->vRootHeight = DisplayHeight(winPtr->display, winPtr->screenNum);
4263	return;
4264    }
4265
4266    /*
4267     * Refresh the virtual root information if it's out of date.
4268     */
4269
4270    handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1, NULL, NULL);
4271    status = XGetGeometry(winPtr->display, wmPtr->vRoot,
4272	    &dummy2, &wmPtr->vRootX, &wmPtr->vRootY,
4273	    &wmPtr->vRootWidth, &wmPtr->vRootHeight, &bd, &dummy);
4274    if (wmTracing) {
4275	TkMacOSXDbgMsg("x = %d, y = %d, width = %d, height = %d, status = %d",
4276		wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth,
4277		wmPtr->vRootHeight, status);
4278    }
4279    Tk_DeleteErrorHandler(handler);
4280    if (status == 0) {
4281	/*
4282	 * The virtual root is gone! Pretend that it never existed.
4283	 */
4284
4285	wmPtr->vRoot = None;
4286	goto noVRoot;
4287    }
4288}
4289
4290/*
4291 *----------------------------------------------------------------------
4292 *
4293 * Tk_GetVRootGeometry --
4294 *
4295 *	This procedure returns information about the virtual root window
4296 *	corresponding to a particular Tk window.
4297 *
4298 * Results:
4299 *	The values at xPtr, yPtr, widthPtr, and heightPtr are set with the
4300 *	offset and dimensions of the root window corresponding to tkwin. If
4301 *	tkwin is being managed by a virtual root window manager these values
4302 *	correspond to the virtual root window being used for tkwin; otherwise
4303 *	the offsets will be 0 and the dimensions will be those of the screen.
4304 *
4305 * Side effects:
4306 *	Vroot window information is refreshed if it is out of date.
4307 *
4308 *----------------------------------------------------------------------
4309 */
4310
4311void
4312Tk_GetVRootGeometry(
4313    Tk_Window tkwin,		/* Window whose virtual root is to be
4314				 * queried. */
4315    int *xPtr, int *yPtr,	/* Store x and y offsets of virtual root
4316				 * here. */
4317    int *widthPtr,		/* Store dimensions of virtual root here. */
4318    int *heightPtr)
4319{
4320    WmInfo *wmPtr;
4321    TkWindow *winPtr = (TkWindow *) tkwin;
4322
4323    /*
4324     * Find the top-level window for tkwin, and locate the window manager
4325     * information for that window.
4326     */
4327
4328    while (!(winPtr->flags & TK_TOP_LEVEL)) {
4329	winPtr = winPtr->parentPtr;
4330    }
4331    wmPtr = winPtr->wmInfoPtr;
4332
4333    /*
4334     * Make sure that the geometry information is up-to-date, then copy it out
4335     * to the caller.
4336     */
4337
4338    if (wmPtr->flags & WM_VROOT_OFFSET_STALE) {
4339	UpdateVRootGeometry(wmPtr);
4340    }
4341    *xPtr = wmPtr->vRootX;
4342    *yPtr = wmPtr->vRootY;
4343    *widthPtr = wmPtr->vRootWidth;
4344    *heightPtr = wmPtr->vRootHeight;
4345}
4346
4347/*
4348 *----------------------------------------------------------------------
4349 *
4350 * Tk_MoveToplevelWindow --
4351 *
4352 *	This procedure is called instead of Tk_MoveWindow to adjust the x-y
4353 *	location of a top-level window. It delays the actual move to a later
4354 *	time and keeps window-manager information up-to-date with the move.
4355 *
4356 * Results:
4357 *	None.
4358 *
4359 * Side effects:
4360 *	The window is eventually moved so that its upper-left corner
4361 *	(actually, the upper-left corner of the window's decorative frame, if
4362 *	there is one) is at (x,y).
4363 *
4364 *----------------------------------------------------------------------
4365 */
4366
4367void
4368Tk_MoveToplevelWindow(
4369    Tk_Window tkwin,		/* Window to move. */
4370    int x, int y)		/* New location for window (within parent). */
4371{
4372    TkWindow *winPtr = (TkWindow *) tkwin;
4373    WmInfo *wmPtr = winPtr->wmInfoPtr;
4374
4375    if (!(winPtr->flags & TK_TOP_LEVEL)) {
4376	Tcl_Panic("Tk_MoveToplevelWindow called with non-toplevel window");
4377    }
4378    wmPtr->x = x;
4379    wmPtr->y = y;
4380    wmPtr->flags |= WM_MOVE_PENDING;
4381    wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
4382    if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
4383	wmPtr->sizeHintsFlags |= USPosition;
4384	wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
4385    }
4386
4387    /*
4388     * If the window has already been mapped, must bring its geometry
4389     * up-to-date immediately, otherwise an event might arrive from the server
4390     * that would overwrite wmPtr->x and wmPtr->y and lose the new position.
4391     */
4392
4393    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
4394	if (wmPtr->flags & WM_UPDATE_PENDING) {
4395	    Tk_CancelIdleCall(UpdateGeometryInfo, winPtr);
4396	}
4397	UpdateGeometryInfo(winPtr);
4398    }
4399}
4400
4401/*
4402 *----------------------------------------------------------------------
4403 *
4404 * TkWmRestackToplevel --
4405 *
4406 *	This procedure restacks a top-level window.
4407 *
4408 * Results:
4409 *	None.
4410 *
4411 * Side effects:
4412 *	WinPtr gets restacked as specified by aboveBelow and otherPtr. This
4413 *	procedure doesn't return until the restack has taken effect and the
4414 *	ConfigureNotify event for it has been received.
4415 *
4416 *----------------------------------------------------------------------
4417 */
4418
4419void
4420TkWmRestackToplevel(
4421    TkWindow *winPtr,		/* Window to restack. */
4422    int aboveBelow,		/* Gives relative position for restacking;
4423				 * must be Above or Below. */
4424    TkWindow *otherPtr)		/* Window relative to which to restack; if
4425				 * NULL, then winPtr gets restacked above or
4426				 * below *all* siblings. */
4427{
4428    NSWindow *macWindow;
4429    NSInteger otherMacWindowNumber;
4430
4431    /*
4432     * Get the mac window. Make sure it exists & is mapped.
4433     */
4434
4435    if (winPtr->window == None) {
4436	Tk_MakeWindowExist((Tk_Window) winPtr);
4437    }
4438    if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
4439	/*
4440	 * Can't set stacking order properly until the window is on the screen
4441	 * (mapping it may give it a reparent window), so make sure it's on
4442	 * the screen.
4443	 */
4444
4445	TkWmMapWindow(winPtr);
4446    }
4447    macWindow = TkMacOSXDrawableWindow(winPtr->window);
4448
4449    /*
4450     * Get the window in which a raise or lower is in relation to.
4451     */
4452
4453    if (otherPtr != NULL) {
4454	if (otherPtr->window == None) {
4455	    Tk_MakeWindowExist((Tk_Window) otherPtr);
4456	}
4457	if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
4458	    TkWmMapWindow(otherPtr);
4459	}
4460	otherMacWindowNumber = [TkMacOSXDrawableWindow(otherPtr->window)
4461		windowNumber];
4462    } else {
4463	otherMacWindowNumber = 0;
4464    }
4465    [macWindow orderWindow:(aboveBelow == Above ? NSWindowAbove : NSWindowBelow)
4466	    relativeTo:otherMacWindowNumber];
4467}
4468
4469/*
4470 *----------------------------------------------------------------------
4471 *
4472 * TkWmAddToColormapWindows --
4473 *
4474 *	This procedure is called to add a given window to the
4475 *	WM_COLORMAP_WINDOWS property for its top-level, if it isn't already
4476 *	there. It is invoked by the Tk code that creates a new colormap, in
4477 *	order to make sure that colormap information is propagated to the
4478 *	window manager by default.
4479 *
4480 * Results:
4481 *	None.
4482 *
4483 * Side effects:
4484 *	WinPtr's window gets added to the WM_COLORMAP_WINDOWS property of its
4485 *	nearest top-level ancestor, unless the colormaps have been set
4486 *	explicitly with the "wm colormapwindows" command.
4487 *
4488 *----------------------------------------------------------------------
4489 */
4490
4491void
4492TkWmAddToColormapWindows(
4493    TkWindow *winPtr)		/* Window with a non-default colormap. Should
4494				 * not be a top-level window. */
4495{
4496    TkWindow *topPtr;
4497    TkWindow **oldPtr, **newPtr;
4498    int count, i;
4499
4500    if (winPtr->window == None) {
4501	return;
4502    }
4503
4504    for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
4505	if (topPtr == NULL) {
4506	    /*
4507	     * Window is being deleted. Skip the whole operation.
4508	     */
4509
4510	    return;
4511	}
4512	if (topPtr->flags & TK_TOP_LEVEL) {
4513	    break;
4514	}
4515    }
4516    if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
4517	return;
4518    }
4519
4520    /*
4521     * Make sure that the window isn't already in the list.
4522     */
4523
4524    count = topPtr->wmInfoPtr->cmapCount;
4525    oldPtr = topPtr->wmInfoPtr->cmapList;
4526
4527    for (i = 0; i < count; i++) {
4528	if (oldPtr[i] == winPtr) {
4529	    return;
4530	}
4531    }
4532
4533    /*
4534     * Make a new bigger array and use it to reset the property. Automatically
4535     * add the toplevel itself as the last element of the list.
4536     */
4537
4538    newPtr = (TkWindow **) ckalloc((unsigned) (count+2)*sizeof(TkWindow *));
4539    if (count > 0) {
4540	memcpy(newPtr, oldPtr, count * sizeof(TkWindow *));
4541    }
4542    if (count == 0) {
4543	count++;
4544    }
4545    newPtr[count-1] = winPtr;
4546    newPtr[count] = topPtr;
4547    if (oldPtr != NULL) {
4548	ckfree((char *) oldPtr);
4549    }
4550
4551    topPtr->wmInfoPtr->cmapList = newPtr;
4552    topPtr->wmInfoPtr->cmapCount = count+1;
4553
4554    /*
4555     * On the Macintosh all of this is just an excercise in compatability as
4556     * we don't support colormaps. If we did they would be installed here.
4557     */
4558}
4559
4560/*
4561 *----------------------------------------------------------------------
4562 *
4563 * TkWmRemoveFromColormapWindows --
4564 *
4565 *	This procedure is called to remove a given window from the
4566 *	WM_COLORMAP_WINDOWS property for its top-level. It is invoked when
4567 *	windows are deleted.
4568 *
4569 * Results:
4570 *	None.
4571 *
4572 * Side effects:
4573 *	WinPtr's window gets removed from the WM_COLORMAP_WINDOWS property of
4574 *	its nearest top-level ancestor, unless the top-level itself is being
4575 *	deleted too.
4576 *
4577 *----------------------------------------------------------------------
4578 */
4579
4580void
4581TkWmRemoveFromColormapWindows(
4582    TkWindow *winPtr)		/* Window that may be present in
4583				 * WM_COLORMAP_WINDOWS property for its
4584				 * top-level. Should not be a top-level
4585				 * window. */
4586{
4587    TkWindow *topPtr, **oldPtr;
4588    int count, i, j;
4589
4590    for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
4591	if (topPtr == NULL) {
4592	    /*
4593	     * Ancestors have been deleted, so skip the whole operation. Seems
4594	     * like this can't ever happen?
4595	     */
4596
4597	    return;
4598	}
4599	if (topPtr->flags & TK_TOP_LEVEL) {
4600	    break;
4601	}
4602    }
4603    if (topPtr->flags & TK_ALREADY_DEAD) {
4604	/*
4605	 * Top-level is being deleted, so there's no need to cleanup the
4606	 * WM_COLORMAP_WINDOWS property.
4607	 */
4608
4609	return;
4610    }
4611
4612    /*
4613     * Find the window and slide the following ones down to cover it up.
4614     */
4615
4616    count = topPtr->wmInfoPtr->cmapCount;
4617    oldPtr = topPtr->wmInfoPtr->cmapList;
4618    for (i = 0; i < count; i++) {
4619	if (oldPtr[i] == winPtr) {
4620	    for (j = i ; j < count-1; j++) {
4621		oldPtr[j] = oldPtr[j+1];
4622	    }
4623	    topPtr->wmInfoPtr->cmapCount = count - 1;
4624	    break;
4625	}
4626    }
4627}
4628
4629/*
4630 *----------------------------------------------------------------------
4631 *
4632 * TkGetPointerCoords --
4633 *
4634 *	Fetch the position of the mouse pointer.
4635 *
4636 * Results:
4637 *	*xPtr and *yPtr are filled in with the (virtual) root coordinates of
4638 *	the mouse pointer for tkwin's display. If the pointer isn't on tkwin's
4639 *	screen, then -1 values are returned for both coordinates. The argument
4640 *	tkwin must be a toplevel window.
4641 *
4642 * Side effects:
4643 *	None.
4644 *
4645 *----------------------------------------------------------------------
4646 */
4647
4648void
4649TkGetPointerCoords(
4650    Tk_Window tkwin,		/* Toplevel window that identifies screen on
4651				 * which lookup is to be done. */
4652    int *xPtr, int *yPtr)	/* Store pointer coordinates here. */
4653{
4654    XQueryPointer(NULL, None, NULL, NULL, xPtr, yPtr, NULL, NULL, NULL);
4655}
4656
4657/*
4658 *----------------------------------------------------------------------
4659 *
4660 * InitialWindowBounds --
4661 *
4662 *	This function calculates the initial bounds for a new Mac toplevel
4663 *	window. Unless the geometry is specified by the user this code will
4664 *	auto place the windows in a cascade diagonially across the main
4665 *	monitor of the Mac.
4666 *
4667 * Results:
4668 *	Window bounds.
4669 *
4670 * Side effects:
4671 *	None.
4672 *
4673 *----------------------------------------------------------------------
4674 */
4675
4676static NSRect
4677InitialWindowBounds(
4678    TkWindow *winPtr,		/* Window to get initial bounds for. */
4679    NSWindow *macWindow)
4680{
4681    WmInfo *wmPtr = winPtr->wmInfoPtr;
4682
4683    if (!(wmPtr->sizeHintsFlags & (USPosition | PPosition))) {
4684	static NSPoint cascadePoint = { .x = 0, .y = 0 };
4685	NSRect frame;
4686
4687	cascadePoint = [macWindow cascadeTopLeftFromPoint:cascadePoint];
4688	frame = [macWindow frame];
4689	wmPtr->x = frame.origin.x;
4690	wmPtr->y = tkMacOSXZeroScreenHeight - (frame.origin.y +
4691		frame.size.height);
4692    }
4693    return NSMakeRect(wmPtr->x, wmPtr->y, winPtr->changes.width,
4694	    winPtr->changes.height);
4695}
4696
4697/*
4698 *----------------------------------------------------------------------
4699 *
4700 * TkMacOSXResizable --
4701 *
4702 *	This function determines if the passed in window is part of a toplevel
4703 *	window that is resizable. If the window is resizable in the x, y or
4704 *	both directions, true is returned.
4705 *
4706 * Results:
4707 *	True if resizable, false otherwise.
4708 *
4709 * Side effects:
4710 *	None.
4711 *
4712 *----------------------------------------------------------------------
4713 */
4714
4715int
4716TkMacOSXResizable(
4717    TkWindow *winPtr)		/* Tk window or NULL. */
4718{
4719    WmInfo *wmPtr;
4720
4721    if (winPtr == NULL) {
4722	return false;
4723    }
4724    while (winPtr->wmInfoPtr == NULL) {
4725	winPtr = winPtr->parentPtr;
4726    }
4727
4728    wmPtr = winPtr->wmInfoPtr;
4729    if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
4730	    (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
4731	return false;
4732    } else {
4733	return true;
4734    }
4735}
4736
4737/*
4738 *----------------------------------------------------------------------
4739 *
4740 * TkMacOSXGrowToplevel --
4741 *
4742 *	The function is invoked when the user clicks in the grow region of a
4743 *	Tk window. The function will handle the dragging procedure and not
4744 *	return until completed. Finally, the function may place information
4745 *	Tk's event queue is the window was resized.
4746 *
4747 * Results:
4748 *	True if events were placed on event queue, false otherwise.
4749 *
4750 * Side effects:
4751 *	None.
4752 *
4753 *----------------------------------------------------------------------
4754 */
4755
4756int
4757TkMacOSXGrowToplevel(
4758    void *whichWindow,
4759    XPoint start)
4760{
4761    return false;
4762}
4763
4764/*
4765 *----------------------------------------------------------------------
4766 *
4767 * TkSetWMName --
4768 *
4769 *	Set the title for a toplevel window. If the window is embedded, do not
4770 *	change the window title.
4771 *
4772 * Results:
4773 *	None.
4774 *
4775 * Side effects:
4776 *	The title of the window is changed.
4777 *
4778 *----------------------------------------------------------------------
4779 */
4780
4781void
4782TkSetWMName(
4783    TkWindow *winPtr,
4784    Tk_Uid titleUid)
4785{
4786    if (Tk_IsEmbedded(winPtr)) {
4787	return;
4788    }
4789
4790    NSString *title = [[NSString alloc] initWithUTF8String:titleUid];
4791    [TkMacOSXDrawableWindow(winPtr->window) setTitle:title];
4792    [title release];
4793}
4794
4795/*
4796 *----------------------------------------------------------------------
4797 *
4798 * TkGetTransientMaster --
4799 *
4800 *	If the passed window has the TRANSIENT_FOR property set this will
4801 *	return the master window. Otherwise it will return None.
4802 *
4803 * Results:
4804 *	The master window or None.
4805 *
4806 * Side effects:
4807 *	None.
4808 *
4809 *----------------------------------------------------------------------
4810 */
4811
4812Window
4813TkGetTransientMaster(
4814    TkWindow *winPtr)
4815{
4816    if (winPtr->wmInfoPtr != NULL) {
4817	return winPtr->wmInfoPtr->master;
4818    }
4819    return None;
4820}
4821
4822/*
4823 *----------------------------------------------------------------------
4824 *
4825 * TkMacOSXGetXWindow --
4826 *
4827 *	Returns the X window Id associated with the given NSWindow*.
4828 *
4829 * Results:
4830 *	The window id is returned. None is returned if not a Tk window.
4831 *
4832 * Side effects:
4833 *	None.
4834 *
4835 *----------------------------------------------------------------------
4836 */
4837
4838Window
4839TkMacOSXGetXWindow(
4840    void *macWinPtr)
4841{
4842    Tcl_HashEntry *hPtr;
4843
4844    if (!macWinPtr || !windowHashInit) {
4845	return None;
4846    }
4847    hPtr = Tcl_FindHashEntry(&windowTable, macWinPtr);
4848    if (hPtr == NULL) {
4849	return None;
4850    }
4851    return (Window) Tcl_GetHashValue(hPtr);
4852}
4853
4854/*
4855 *----------------------------------------------------------------------
4856 *
4857 * TkMacOSXGetTkWindow --
4858 *
4859 *	Returns the TkWindow* associated with the given NSWindow*.
4860 *
4861 * Results:
4862 *	The TkWindow* returned. NULL is returned if not a Tk window.
4863 *
4864 * Side effects:
4865 *	None.
4866 *
4867 *----------------------------------------------------------------------
4868 */
4869
4870TkWindow*
4871TkMacOSXGetTkWindow(
4872    NSWindow *w)
4873{
4874    Window window = TkMacOSXGetXWindow(w);
4875    TkDisplay *dispPtr = TkGetDisplayList();
4876
4877    return (window != None ?
4878	    (TkWindow *)Tk_IdToWindow(dispPtr->display, window) : NULL);
4879}
4880
4881/*
4882 *----------------------------------------------------------------------
4883 *
4884 * TkMacOSXIsWindowZoomed --
4885 *
4886 *	Ask Carbon if the given window is in the zoomed out state. Because
4887 *	dragging & growing a window can change the Carbon zoom state, we
4888 *	cannot rely on wmInfoPtr->hints.initial_state for this information.
4889 *
4890 * Results:
4891 *	True if window is zoomed out, false otherwise.
4892 *
4893 * Side effects:
4894 *	None.
4895 *
4896 *----------------------------------------------------------------------
4897 */
4898
4899MODULE_SCOPE int
4900TkMacOSXIsWindowZoomed(
4901    TkWindow *winPtr)
4902{
4903    return [TkMacOSXDrawableWindow(winPtr->window) isZoomed];
4904}
4905
4906/*
4907 *----------------------------------------------------------------------
4908 *
4909 * TkMacOSXZoomToplevel --
4910 *
4911 *	The function is invoked when the user clicks in the zoom region of a
4912 *	Tk window or when the window state is set/unset to "zoomed" manually.
4913 *	If the window is to be zoomed (in or out), the window size is changed
4914 *	and events are generated to let Tk know what happened.
4915 *
4916 * Results:
4917 *	True if events were placed on event queue, false otherwise.
4918 *
4919 * Side effects:
4920 *	The window may be resized & events placed on Tk's queue.
4921 *
4922 *----------------------------------------------------------------------
4923 */
4924
4925int
4926TkMacOSXZoomToplevel(
4927    void *whichWindow,		/* The Macintosh window to zoom. */
4928    short zoomPart)		/* Either inZoomIn or inZoomOut */
4929{
4930    NSWindow *window = whichWindow;
4931    TkWindow *winPtr = TkMacOSXGetTkWindow(window);
4932    WmInfo *wmPtr;
4933
4934    if (!winPtr || !winPtr->wmInfoPtr) {
4935	return false;
4936    }
4937    wmPtr = winPtr->wmInfoPtr;
4938    if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
4939	    (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
4940	return false;
4941    }
4942
4943    /*
4944     * Do nothing if already in desired zoom state.
4945     */
4946
4947    if (![window isZoomed] == (zoomPart == inZoomIn)) {
4948	return false;
4949    }
4950    [window zoom:NSApp];
4951    wmPtr->hints.initial_state =
4952	    (zoomPart == inZoomIn ? NormalState : ZoomState);
4953    return true;
4954}
4955
4956/*
4957 *----------------------------------------------------------------------
4958 *
4959 * TkUnsupported1Cmd --
4960 *
4961 *	This procedure is invoked to process the
4962 *	"::tk::unsupported::MacWindowStyle" Tcl command. This command allows
4963 *	you to set the style of decoration for a Macintosh window.
4964 *
4965 * Results:
4966 *	A standard Tcl result.
4967 *
4968 * Side effects:
4969 *	Changes the style of a new Mac window.
4970 *
4971 *----------------------------------------------------------------------
4972 */
4973
4974/* ARGSUSED */
4975int
4976TkUnsupported1ObjCmd(
4977    ClientData clientData,	/* Main window associated with interpreter. */
4978    Tcl_Interp *interp,		/* Current interpreter. */
4979    int objc,			/* Number of arguments. */
4980    Tcl_Obj *const objv[])	/* Argument objects. */
4981{
4982    static const char *subcmds[] = {
4983	"style", NULL
4984    };
4985    enum SubCmds {
4986	TKMWS_STYLE
4987    };
4988    Tk_Window tkwin = clientData;
4989    TkWindow *winPtr;
4990    int index;
4991
4992    if (objc < 3) {
4993	Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg ...?");
4994	return TCL_ERROR;
4995    }
4996
4997    winPtr = (TkWindow *)
4998	    Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin);
4999    if (winPtr == NULL) {
5000	return TCL_ERROR;
5001    }
5002    if (!(winPtr->flags & TK_TOP_LEVEL)) {
5003	Tcl_ResetResult(interp);
5004	Tcl_AppendResult(interp, "window \"", winPtr->pathName,
5005		"\" isn't a top-level window", NULL);
5006	return TCL_ERROR;
5007    }
5008
5009    if (Tcl_GetIndexFromObj(interp, objv[1], subcmds, "option", 0,
5010	    &index) != TCL_OK) {
5011	return TCL_ERROR;
5012    }
5013    if (((enum SubCmds) index) == TKMWS_STYLE) {
5014	if ((objc < 3) || (objc > 5)) {
5015	    Tcl_WrongNumArgs(interp, 2, objv, "window ?class attributes?");
5016	    return TCL_ERROR;
5017	}
5018	return WmWinStyle(interp, winPtr, objc, objv);
5019    }
5020    /* won't be reached */
5021    return TCL_ERROR;
5022}
5023
5024/*
5025 *----------------------------------------------------------------------
5026 *
5027 * WmWinStyle --
5028 *
5029 *	This procedure is invoked to process the
5030 *	"::tk::unsupported::MacWindowStyle style" subcommand. This command
5031 *	allows you to set the style of decoration for a Macintosh window.
5032 *
5033 * Results:
5034 *	A standard Tcl result.
5035 *
5036 * Side effects:
5037 *	Changes the style of a new Mac window.
5038 *
5039 *----------------------------------------------------------------------
5040 */
5041
5042static int
5043WmWinStyle(
5044    Tcl_Interp *interp,		/* Current interpreter. */
5045    TkWindow *winPtr,		/* Window to be manipulated. */
5046    int objc,			/* Number of arguments. */
5047    Tcl_Obj * const objv[])	/* Argument objects. */
5048{
5049    struct StrIntMap {
5050	const char *strValue;
5051	UInt64 intValue;
5052    };
5053    static const struct StrIntMap classMap[] = {
5054	{ "alert",		kAlertWindowClass			     },
5055	{ "moveableAlert",	kMovableAlertWindowClass		     },
5056	{ "modal",		kModalWindowClass			     },
5057	{ "moveableModal",	kMovableModalWindowClass		     },
5058	{ "floating",		kFloatingWindowClass			     },
5059	{ "document",		kDocumentWindowClass			     },
5060	{ "utility",		kUtilityWindowClass			     },
5061	{ "help",		kHelpWindowClass			     },
5062	{ "sheet",		kSheetWindowClass			     },
5063	{ "toolbar",		kToolbarWindowClass			     },
5064	{ "plain",		kPlainWindowClass			     },
5065	{ "overlay",		kOverlayWindowClass			     },
5066	{ "sheetAlert",		kSheetAlertWindowClass			     },
5067	{ "altPlain",		kAltPlainWindowClass			     },
5068	{ "simple",		kSimpleWindowClass			     },
5069	{ "drawer",		kDrawerWindowClass			     },
5070	{ NULL }
5071    };
5072    static const struct StrIntMap compositeAttrMap[] = {
5073	{ "none",		kWindowNoAttributes			     },
5074	{ "standardDocument",	kWindowStandardDocumentAttributes	     },
5075	{ "standardFloating",	kWindowStandardFloatingAttributes	     },
5076	{ "fullZoom",		kWindowFullZoomAttribute		     },
5077	{ NULL }
5078    };
5079    static const struct StrIntMap attrMap[] = {
5080	{ "closeBox",		kWindowCloseBoxAttribute		     },
5081	{ "horizontalZoom",	kWindowHorizontalZoomAttribute		     },
5082	{ "verticalZoom",	kWindowVerticalZoomAttribute		     },
5083	{ "collapseBox",	kWindowCollapseBoxAttribute		     },
5084	{ "resizable",		kWindowResizableAttribute		     },
5085	{ "sideTitlebar",	kWindowSideTitlebarAttribute		     },
5086	{ "toolbarButton",	kWindowToolbarButtonAttribute		     },
5087	{ "unifiedTitleAndToolbar", kWindowUnifiedTitleAndToolbarAttribute   },
5088	{ "metal",		kWindowMetalAttribute			     },
5089	{ "noTitleBar",		kWindowNoTitleBarAttribute		     },
5090	{ "texturedSquareCorners", kWindowTexturedSquareCornersAttribute     },
5091	{ "metalNoContentSeparator", kWindowMetalNoContentSeparatorAttribute },
5092	{ "doesNotCycle",	kWindowDoesNotCycleAttribute		     },
5093	{ "noUpdates",		kWindowNoUpdatesAttribute		     },
5094	{ "noActivates",	kWindowNoActivatesAttribute		     },
5095	{ "opaqueForEvents",	kWindowOpaqueForEventsAttribute		     },
5096	{ "noShadow",		kWindowNoShadowAttribute		     },
5097	{ "hideOnSuspend",	kWindowHideOnSuspendAttribute		     },
5098	{ "hideOnFullScreen",	kWindowHideOnFullScreenAttribute	     },
5099	{ "inWindowMenu",	kWindowInWindowMenuAttribute		     },
5100	{ "liveResize",		kWindowLiveResizeAttribute		     },
5101	{ "ignoreClicks",	kWindowIgnoreClicksAttribute		     },
5102	{ "noConstrain",	kWindowNoConstrainAttribute		     },
5103	{ "doesNotHide",	tkWindowDoesNotHideAttribute		     },
5104	{ "canJoinAllSpaces",	tkCanJoinAllSpacesAttribute		     },
5105	{ "moveToActiveSpace",	tkMoveToActiveSpaceAttribute		     },
5106	{ "nonActivating",	tkNonactivatingPanelAttribute		     },
5107	{ "hud",		tkHUDWindowAttribute			     },
5108	{ NULL }
5109    };
5110    int index, i;
5111    WmInfo *wmPtr = winPtr->wmInfoPtr;
5112
5113    if (objc == 3) {
5114	Tcl_Obj *attributeList, *newResult = NULL;
5115	UInt64 attributes;
5116
5117	for (i = 0; classMap[i].strValue != NULL; i++) {
5118	    if (wmPtr->macClass == classMap[i].intValue) {
5119		newResult = Tcl_NewStringObj(classMap[i].strValue, -1);
5120		break;
5121	    }
5122	}
5123	if (newResult == NULL) {
5124	    Tcl_Panic("invalid class");
5125	}
5126
5127	attributeList = Tcl_NewListObj(0, NULL);
5128	attributes = wmPtr->attributes;
5129
5130	for (i = 0; compositeAttrMap[i].strValue != NULL; i++) {
5131	    UInt64 intValue = compositeAttrMap[i].intValue;
5132
5133	    if (intValue && (attributes & intValue) == intValue) {
5134		Tcl_ListObjAppendElement(interp, attributeList,
5135			Tcl_NewStringObj(compositeAttrMap[i].strValue,
5136			-1));
5137		attributes &= ~intValue;
5138		break;
5139	    }
5140	}
5141	for (i = 0; attrMap[i].strValue != NULL; i++) {
5142	    if (attributes & attrMap[i].intValue) {
5143		Tcl_ListObjAppendElement(interp, attributeList,
5144			Tcl_NewStringObj(attrMap[i].strValue, -1));
5145	    }
5146	}
5147	Tcl_ListObjAppendElement(interp, newResult, attributeList);
5148	Tcl_SetObjResult(interp, newResult);
5149    } else {
5150	int attrObjc;
5151	Tcl_Obj **attrObjv = NULL;
5152	WindowClass macClass;
5153	UInt64 oldAttributes = wmPtr->attributes;
5154	int oldFlags = wmPtr->flags;
5155
5156	if (Tcl_GetIndexFromObjStruct(interp, objv[3], classMap,
5157		sizeof(struct StrIntMap), "class", 0, &index) != TCL_OK) {
5158	    goto badClassAttrs;
5159	}
5160	macClass = classMap[index].intValue;
5161	if (objc == 5) {
5162	    if (Tcl_ListObjGetElements(interp, objv[4], &attrObjc, &attrObjv)
5163		    != TCL_OK) {
5164		goto badClassAttrs;
5165	    }
5166	    wmPtr->attributes = kWindowNoAttributes;
5167	    for (i = 0; i < attrObjc; i++) {
5168		if (Tcl_GetIndexFromObjStruct(interp, attrObjv[i],
5169			compositeAttrMap, sizeof(struct StrIntMap),
5170			"attribute", 0, &index) == TCL_OK) {
5171		    wmPtr->attributes |= compositeAttrMap[index].intValue;
5172		} else if (Tcl_GetIndexFromObjStruct(interp, attrObjv[i],
5173			attrMap, sizeof(struct StrIntMap),
5174			"attribute", 0, &index) == TCL_OK) {
5175		    Tcl_ResetResult(interp);
5176		    wmPtr->attributes |= attrMap[index].intValue;
5177		} else {
5178		    goto badClassAttrs;
5179		}
5180	    }
5181	} else {
5182	    wmPtr->attributes = macClassAttrs[macClass].defaultAttrs;
5183	}
5184	wmPtr->attributes &= (tkAlwaysValidAttributes |
5185		macClassAttrs[macClass].validAttrs);
5186	wmPtr->flags |= macClassAttrs[macClass].flags;
5187	wmPtr->macClass = macClass;
5188	ApplyWindowAttributeFlagChanges(winPtr, NULL, oldAttributes, oldFlags,
5189		0, 1);
5190	return TCL_OK;
5191
5192    badClassAttrs:
5193	wmPtr->attributes = oldAttributes;
5194	return TCL_ERROR;
5195    }
5196    return TCL_OK;
5197}
5198
5199/*
5200 *----------------------------------------------------------------------
5201 *
5202 * TkpMakeMenuWindow --
5203 *
5204 *	Configure the window to be either a undecorated pull-down (or pop-up)
5205 *	menu, or as a toplevel floating menu (palette).
5206 *
5207 * Results:
5208 *	None.
5209 *
5210 * Side effects:
5211 *	Changes the style bit used to create a new Mac toplevel.
5212 *
5213 *----------------------------------------------------------------------
5214 */
5215
5216void
5217TkpMakeMenuWindow(
5218    Tk_Window tkwin,		/* New window. */
5219    int transient)		/* 1 means menu is only posted briefly as a
5220				 * popup or pulldown or cascade. 0 means menu
5221				 * is always visible, e.g. as a floating
5222				 * menu. */
5223{
5224    TkWindow *winPtr = (TkWindow *) tkwin;
5225
5226    if (transient) {
5227	winPtr->wmInfoPtr->macClass = kSimpleWindowClass;
5228	winPtr->wmInfoPtr->attributes = kWindowNoActivatesAttribute;
5229    } else {
5230	winPtr->wmInfoPtr->macClass = kFloatingWindowClass;
5231	winPtr->wmInfoPtr->attributes = kWindowStandardFloatingAttributes;
5232	winPtr->wmInfoPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
5233	winPtr->wmInfoPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
5234    }
5235}
5236
5237/*
5238 *----------------------------------------------------------------------
5239 *
5240 * TkMacOSXMakeRealWindowExist --
5241 *
5242 *	This function finally creates the real Macintosh window that the Mac
5243 *	actually understands.
5244 *
5245 * Results:
5246 *	None.
5247 *
5248 * Side effects:
5249 *	A new Macintosh toplevel is created.
5250 *
5251 *----------------------------------------------------------------------
5252 */
5253
5254void
5255TkMacOSXMakeRealWindowExist(
5256    TkWindow *winPtr)		/* Tk window. */
5257{
5258    WmInfo *wmPtr = winPtr->wmInfoPtr;
5259    MacDrawable *macWin;
5260
5261    if (TkMacOSXHostToplevelExists(winPtr)) {
5262	return;
5263    }
5264
5265    macWin = (MacDrawable *) winPtr->window;
5266
5267    /*
5268     * If this is embedded, make sure its container's toplevel exists,
5269     * then return...
5270     */
5271
5272    if (Tk_IsEmbedded(winPtr)) {
5273	TkWindow *contWinPtr = TkpGetOtherWindow(winPtr);
5274
5275	if (contWinPtr != NULL) {
5276	    TkMacOSXMakeRealWindowExist(
5277		    contWinPtr->privatePtr->toplevel->winPtr);
5278	    macWin->flags |= TK_HOST_EXISTS;
5279	    return;
5280	}
5281
5282	if (tkMacOSXEmbedHandler == NULL) {
5283	    Tcl_Panic("TkMacOSXMakeRealWindowExist could not find container");
5284	}
5285	if (tkMacOSXEmbedHandler->containerExistProc &&
5286		tkMacOSXEmbedHandler->containerExistProc((Tk_Window) winPtr)
5287		!= TCL_OK) {
5288	    Tcl_Panic("ContainerExistProc could not make container");
5289	}
5290	return;
5291
5292	/*
5293	 * TODO: Here we should handle out of process embedding.
5294	 */
5295    }
5296
5297    WindowClass macClass = wmPtr->macClass;
5298    wmPtr->attributes &= (tkAlwaysValidAttributes |
5299	    macClassAttrs[macClass].validAttrs);
5300    wmPtr->flags |= macClassAttrs[macClass].flags |
5301	    ((wmPtr->attributes & kWindowResizableAttribute) ? 0 :
5302	    WM_WIDTH_NOT_RESIZABLE|WM_HEIGHT_NOT_RESIZABLE);
5303    UInt64 attributes = (wmPtr->attributes &
5304	    ~macClassAttrs[macClass].forceOffAttrs) |
5305	    macClassAttrs[macClass].forceOnAttrs;
5306    NSUInteger styleMask = macClassAttrs[macClass].styleMask |
5307	((attributes & kWindowNoTitleBarAttribute) ? 0 : NSTitledWindowMask) |
5308	((attributes & kWindowCloseBoxAttribute) ? NSClosableWindowMask : 0) |
5309	((attributes & kWindowCollapseBoxAttribute) ?
5310		NSMiniaturizableWindowMask : 0) |
5311	((attributes & kWindowResizableAttribute) ? NSResizableWindowMask : 0) |
5312	((attributes & kWindowMetalAttribute) ?
5313		NSTexturedBackgroundWindowMask : 0) |
5314	((attributes & kWindowUnifiedTitleAndToolbarAttribute) ?
5315		NSUnifiedTitleAndToolbarWindowMask : 0) |
5316	((attributes & kWindowSideTitlebarAttribute) ? 1 << 9 : 0) |
5317	(attributes >> WM_NSMASK_SHIFT);
5318    Class winClass = (macClass == kDrawerWindowClass ? [NSDrawerWindow class] :
5319	    (styleMask & (NSUtilityWindowMask|NSDocModalWindowMask|
5320	    NSNonactivatingPanelMask|NSHUDWindowMask)) ? [NSPanel class] :
5321	    [TKWindow class]);
5322    NSRect structureRect = [winClass frameRectForContentRect:NSZeroRect
5323	    styleMask:styleMask];
5324    NSRect contentRect = NSMakeRect(5 - structureRect.origin.x,
5325	    tkMacOSXZeroScreenHeight - (tkMacOSXZeroScreenTop + 5 +
5326	    structureRect.origin.y + structureRect.size.height + 200), 200, 200);
5327    NSWindow *window = [[winClass alloc] initWithContentRect:contentRect
5328	    styleMask:styleMask backing:NSBackingStoreBuffered defer:YES];
5329    if (!window) {
5330	Tcl_Panic("couldn't allocate new Mac window");
5331    }
5332    TkMacOSXMakeUncollectable(window);
5333    TKContentView *contentView = [[TKContentView alloc]
5334	    initWithFrame:NSZeroRect];
5335    [window setContentView:contentView];
5336    [contentView release];
5337    [window setDelegate:NSApp];
5338    [window setAcceptsMouseMovedEvents:YES];
5339    [window setReleasedWhenClosed:NO];
5340    [window setAutodisplay:NO];
5341    if (styleMask & NSUtilityWindowMask) {
5342	[(NSPanel*)window setFloatingPanel:YES];
5343    }
5344    if ((styleMask & (NSTexturedBackgroundWindowMask|NSHUDWindowMask)) &&
5345	    !(styleMask & NSDocModalWindowMask)) {
5346        /*
5347	 * Workaround for [Bug 2824538]: Texured windows are draggable
5348	 *                               from opaque content.
5349	 */
5350	[window setMovableByWindowBackground:NO];
5351    }
5352    [window setDocumentEdited:NO];
5353    wmPtr->window = window;
5354    macWin->view = contentView;
5355    TkMacOSXApplyWindowAttributes(winPtr, window);
5356
5357    NSRect geometry = InitialWindowBounds(winPtr, window);
5358    geometry.size.width +=  structureRect.size.width;
5359    geometry.size.height += structureRect.size.height;
5360    geometry.origin.y = tkMacOSXZeroScreenHeight - (geometry.origin.y +
5361	    geometry.size.height);
5362    [window setFrame:geometry display:NO];
5363
5364    TkMacOSXRegisterOffScreenWindow((Window) macWin, window);
5365    macWin->flags |= TK_HOST_EXISTS;
5366}
5367
5368/*
5369 *----------------------------------------------------------------------
5370 *
5371 * TkMacOSXRegisterOffScreenWindow --
5372 *
5373 *	This function adds the passed in Off Screen Port to the hash table
5374 *	that maps Mac windows to root X windows.
5375 *
5376 * Results:
5377 *	None.
5378 *
5379 * Side effects:
5380 *	An entry is added to the windowTable hash table.
5381 *
5382 *----------------------------------------------------------------------
5383 */
5384
5385void
5386TkMacOSXRegisterOffScreenWindow(
5387    Window window,		/* Window structure. */
5388    void *portPtr)		/* Pointer to a Mac Window. */
5389{
5390    Tcl_HashEntry *valueHashPtr;
5391    int isNew;
5392
5393    if (!windowHashInit) {
5394	Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
5395	windowHashInit = true;
5396    }
5397    valueHashPtr = Tcl_CreateHashEntry(&windowTable, (char *) portPtr, &isNew);
5398    if (!isNew) {
5399	Tcl_Panic("Same macintosh window allocated twice!");
5400    }
5401    Tcl_SetHashValue(valueHashPtr, window);
5402}
5403
5404/*
5405 *----------------------------------------------------------------------
5406 *
5407 * TkMacOSXUnregisterMacWindow --
5408 *
5409 *	Given a macintosh port window, this function removes the association
5410 *	between this window and the root X window that Tk cares about.
5411 *
5412 * Results:
5413 *	None.
5414 *
5415 * Side effects:
5416 *	An entry is removed from the windowTable hash table.
5417 *
5418 *----------------------------------------------------------------------
5419 */
5420
5421void
5422TkMacOSXUnregisterMacWindow(
5423    void *macWinPtr)	/* Reference to a Mac Window */
5424{
5425    Tcl_HashEntry *entryPtr;
5426
5427    if (!windowHashInit) {
5428	Tcl_Panic("TkMacOSXUnregisterMacWindow: unmapping before inited");
5429    }
5430    entryPtr = Tcl_FindHashEntry(&windowTable, macWinPtr);
5431    if (!entryPtr) {
5432	TkMacOSXDbgMsg("Failed to find window %p", macWinPtr);
5433    } else {
5434	Tcl_DeleteHashEntry(entryPtr);
5435    }
5436}
5437
5438/*
5439 *----------------------------------------------------------------------
5440 *
5441 * TkMacOSXSetScrollbarGrow --
5442 *
5443 *	Sets a flag for a toplevel window indicating that the passed Tk
5444 *	scrollbar window will display the grow region for the toplevel window.
5445 *
5446 * Results:
5447 *	None.
5448 *
5449 * Side effects:
5450 *	A flag is set int windows toplevel parent.
5451 *
5452 *----------------------------------------------------------------------
5453 */
5454
5455void
5456TkMacOSXSetScrollbarGrow(
5457    TkWindow *winPtr,		/* Tk scrollbar window. */
5458    int flag)			/* Boolean value true or false. */
5459{
5460    if (flag) {
5461	winPtr->privatePtr->toplevel->flags |= TK_SCROLLBAR_GROW;
5462	winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = winPtr;
5463    } else if (winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr
5464	    == winPtr) {
5465	winPtr->privatePtr->toplevel->flags &= ~TK_SCROLLBAR_GROW;
5466	winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = NULL;
5467    }
5468}
5469
5470/*
5471 *----------------------------------------------------------------------
5472 *
5473 * TkWmFocusToplevel --
5474 *
5475 *	This is a utility procedure invoked by focus-management code. It
5476 *	exists because of the extra wrapper windows that exist under Unix; its
5477 *	job is to map from wrapper windows to the corresponding toplevel
5478 *	windows. On PCs and Macs there are no wrapper windows so no mapping is
5479 *	necessary; this procedure just determines whether a window is a
5480 *	toplevel or not.
5481 *
5482 * Results:
5483 *	If winPtr is a toplevel window, returns the pointer to the window;
5484 *	otherwise returns NULL.
5485 *
5486 * Side effects:
5487 *	None.
5488 *
5489 *----------------------------------------------------------------------
5490 */
5491
5492TkWindow *
5493TkWmFocusToplevel(
5494    TkWindow *winPtr)		/* Window that received a focus-related
5495				 * event. */
5496{
5497    if (!(winPtr->flags & TK_TOP_LEVEL)) {
5498	return NULL;
5499    }
5500    return winPtr;
5501}
5502
5503/*
5504 *----------------------------------------------------------------------
5505 *
5506 * TkpGetWrapperWindow --
5507 *
5508 *	This is a utility procedure invoked by focus-management code. It maps
5509 *	to the wrapper for a top-level, which is just the same as the
5510 *	top-level on Macs and PCs.
5511 *
5512 * Results:
5513 *	If winPtr is a toplevel window, returns the pointer to the window;
5514 *	otherwise returns NULL.
5515 *
5516 * Side effects:
5517 *	None.
5518 *
5519 *----------------------------------------------------------------------
5520 */
5521
5522TkWindow *
5523TkpGetWrapperWindow(
5524    TkWindow *winPtr)		/* Window that received a focus-related
5525				 * event. */
5526{
5527    if (!(winPtr->flags & TK_TOP_LEVEL)) {
5528	return NULL;
5529    }
5530    return winPtr;
5531}
5532
5533/*
5534 *----------------------------------------------------------------------
5535 *
5536 * TkpWmSetState --
5537 *
5538 *	Sets the window manager state for the wrapper window of a given
5539 *	toplevel window.
5540 *
5541 * Results:
5542 *	None.
5543 *
5544 * Side effects:
5545 *	May maximize, minimize, restore, or withdraw a window.
5546 *
5547 *----------------------------------------------------------------------
5548 */
5549
5550void
5551TkpWmSetState(
5552    TkWindow *winPtr,		/* Toplevel window to operate on. */
5553    int state)			/* One of IconicState, ZoomState, NormalState,
5554				 * or WithdrawnState. */
5555{
5556    WmInfo *wmPtr = winPtr->wmInfoPtr;
5557    NSWindow *macWin;
5558
5559    wmPtr->hints.initial_state = state;
5560    if (wmPtr->flags & WM_NEVER_MAPPED) {
5561	return;
5562    }
5563
5564    macWin = TkMacOSXDrawableWindow(winPtr->window);
5565
5566    if (state == WithdrawnState) {
5567	Tk_UnmapWindow((Tk_Window) winPtr);
5568    } else if (state == IconicState) {
5569	/*
5570	 * The window always gets unmapped. If we can show the icon version of
5571	 * the window we also collapse it.
5572	 */
5573
5574	if (macWin && ([macWin styleMask] & NSMiniaturizableWindowMask) &&
5575		![macWin isMiniaturized]) {
5576	    [macWin miniaturize:NSApp];
5577	}
5578	Tk_UnmapWindow((Tk_Window) winPtr);
5579    } else if (state == NormalState || state == ZoomState) {
5580	Tk_MapWindow((Tk_Window) winPtr);
5581	if (macWin && ([macWin styleMask] & NSMiniaturizableWindowMask) &&
5582		[macWin isMiniaturized]) {
5583	    [macWin deminiaturize:NSApp];
5584	}
5585	TkMacOSXZoomToplevel(macWin, state == NormalState ? inZoomIn :
5586		inZoomOut);
5587    }
5588}
5589
5590/*
5591 *----------------------------------------------------------------------
5592 *
5593 * TkpIsWindowFloating --
5594 *
5595 *	Returns 1 if a window is floating, 0 otherwise.
5596 *
5597 * Results:
5598 *	1 or 0 depending on window's floating attribute.
5599 *
5600 * Side effects:
5601 *	None.
5602 *
5603 *----------------------------------------------------------------------
5604 */
5605
5606int
5607TkpIsWindowFloating(
5608    void *wRef)
5609{
5610    return [(NSWindow *)wRef level] == kCGFloatingWindowLevel;
5611}
5612
5613/*
5614 *----------------------------------------------------------------------
5615 *
5616 * TkMacOSXWindowClass --
5617 *
5618 *	Returns OS X window class of window
5619 *
5620 * Results:
5621 *	1 or 0 depending on window's floating attribute.
5622 *
5623 * Side effects:
5624 *	None.
5625 *
5626 *----------------------------------------------------------------------
5627 */
5628
5629MODULE_SCOPE WindowClass
5630TkMacOSXWindowClass(
5631    TkWindow *winPtr)
5632{
5633    return winPtr->wmInfoPtr->macClass;
5634}
5635
5636/*
5637 *--------------------------------------------------------------
5638 *
5639 * TkMacOSXWindowOffset --
5640 *
5641 *	Determines the x and y offset from the orgin of the toplevel window
5642 *	dressing (the structure region, i.e. title bar) and the orgin of the
5643 *	content area.
5644 *
5645 * Results:
5646 *	The x & y offset in pixels.
5647 *
5648 * Side effects:
5649 *	None.
5650 *
5651 *----------------------------------------------------------------------
5652 */
5653
5654void
5655TkMacOSXWindowOffset(
5656    void *wRef,
5657    int *xOffset,
5658    int *yOffset)
5659{
5660    TkWindow *winPtr = TkMacOSXGetTkWindow(wRef);
5661
5662    if (winPtr && winPtr->wmInfoPtr) {
5663	*xOffset = winPtr->wmInfoPtr->xInParent;
5664	*yOffset = winPtr->wmInfoPtr->yInParent;
5665    } else {
5666	*xOffset = 0;
5667	*yOffset = 0;
5668    }
5669}
5670
5671/*
5672 *----------------------------------------------------------------------
5673 *
5674 * TkpGetMS --
5675 *
5676 *	Return a relative time in milliseconds. It doesn't matter when the
5677 *	epoch was.
5678 *
5679 * Results:
5680 *	Number of milliseconds.
5681 *
5682 * Side effects:
5683 *	None.
5684 *
5685 *----------------------------------------------------------------------
5686 */
5687
5688unsigned long
5689TkpGetMS(void)
5690{
5691    Tcl_Time now;
5692
5693    Tcl_GetTime(&now);
5694    return (long) now.sec * 1000 + now.usec / 1000;
5695}
5696
5697/*
5698 *----------------------------------------------------------------------
5699 *
5700 * XSetInputFocus --
5701 *
5702 *	Change the focus window for the application.
5703 *
5704 * Results:
5705 *	None.
5706 *
5707 * Side effects:
5708 *	None.
5709 *
5710 *----------------------------------------------------------------------
5711 */
5712
5713void
5714XSetInputFocus(
5715    Display* display,
5716    Window focus,
5717    int revert_to,
5718    Time time)
5719{
5720    /*
5721     * Don't need to do a thing. Tk manages the focus for us.
5722     */
5723}
5724
5725/*
5726 *----------------------------------------------------------------------
5727 *
5728 * TkpChangeFocus --
5729 *
5730 *	This procedure is a stub on the Mac because we always own the focus if
5731 *	we are a front most application.
5732 *
5733 * Results:
5734 *	The return value is the serial number of the command that changed the
5735 *	focus. It may be needed by the caller to filter out focus change
5736 *	events that were queued before the command. If the procedure doesn't
5737 *	actually change the focus then it returns 0.
5738 *
5739 * Side effects:
5740 *	None.
5741 *
5742 *----------------------------------------------------------------------
5743 */
5744
5745int
5746TkpChangeFocus(
5747    TkWindow *winPtr,		/* Window that is to receive the X focus. */
5748    int force)			/* Non-zero means claim the focus even if it
5749				 * didn't originally belong to topLevelPtr's
5750				 * application. */
5751{
5752    /*
5753     * We don't really need to do anything on the Mac. Tk will keep all this
5754     * state for us.
5755     */
5756
5757    if (winPtr->atts.override_redirect) {
5758	return 0;
5759    }
5760
5761    /*
5762     * Remember the current serial number for the X server and issue a dummy
5763     * server request. This marks the position at which we changed the focus,
5764     * so we can distinguish FocusIn and FocusOut events on either side of the
5765     * mark.
5766     */
5767
5768    return NextRequest(winPtr->display);
5769}
5770
5771/*
5772 *----------------------------------------------------------------------
5773 *
5774 * WmStackorderToplevelWrapperMap --
5775 *
5776 *	This procedure will create a table that maps the reparent wrapper X id
5777 *	for a toplevel to the TkWindow structure that is wraps. Tk keeps track
5778 *	of a mapping from the window X id to the TkWindow structure but that
5779 *	does us no good here since we only get the X id of the wrapper window.
5780 *	Only those toplevel windows that are mapped have a position in the
5781 *	stacking order.
5782 *
5783 * Results:
5784 *	None.
5785 *
5786 * Side effects:
5787 *	Adds entries to the passed hashtable.
5788 *
5789 *----------------------------------------------------------------------
5790 */
5791
5792static void
5793WmStackorderToplevelWrapperMap(
5794    TkWindow *winPtr,		/* TkWindow to recurse on */
5795    Display *display,		/* X display of parent window */
5796    Tcl_HashTable *table)	/* Maps mac window to TkWindow */
5797{
5798    TkWindow *childPtr;
5799    Tcl_HashEntry *hPtr;
5800    int newEntry;
5801
5802    if (Tk_IsMapped(winPtr) && Tk_IsTopLevel(winPtr)
5803	    && (winPtr->display == display)) {
5804	hPtr = Tcl_CreateHashEntry(table,
5805		(char*) TkMacOSXDrawableWindow(winPtr->window), &newEntry);
5806	Tcl_SetHashValue(hPtr, winPtr);
5807    }
5808
5809    for (childPtr = winPtr->childList; childPtr != NULL;
5810	    childPtr = childPtr->nextPtr) {
5811	WmStackorderToplevelWrapperMap(childPtr, display, table);
5812    }
5813}
5814
5815/*
5816 *----------------------------------------------------------------------
5817 *
5818 * TkWmStackorderToplevel --
5819 *
5820 *	This procedure returns the stack order of toplevel windows.
5821 *
5822 * Results:
5823 *	An array of pointers to tk window objects in stacking order or else
5824 *	NULL if there was an error.
5825 *
5826 * Side effects:
5827 *	None.
5828 *
5829 *----------------------------------------------------------------------
5830 */
5831
5832TkWindow **
5833TkWmStackorderToplevel(
5834    TkWindow *parentPtr)	/* Parent toplevel window. */
5835{
5836    TkWindow *childWinPtr, **windows, **window_ptr;
5837    Tcl_HashTable table;
5838    Tcl_HashEntry *hPtr;
5839    Tcl_HashSearch search;
5840    NSInteger windowCount;
5841    NSInteger *windowNumbers;
5842
5843    /*
5844     * Map mac windows to a TkWindow of the wrapped toplevel.
5845     */
5846
5847    Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS);
5848    WmStackorderToplevelWrapperMap(parentPtr, parentPtr->display, &table);
5849
5850    windows = (TkWindow **)
5851	    ckalloc((table.numEntries+1) * sizeof(TkWindow *));
5852
5853    /*
5854     * Special cases: If zero or one toplevels were mapped there is no need to
5855     * enumerate Windows.
5856     */
5857
5858    switch (table.numEntries) {
5859    case 0:
5860	windows[0] = NULL;
5861	goto done;
5862    case 1:
5863	hPtr = Tcl_FirstHashEntry(&table, &search);
5864	windows[0] = Tcl_GetHashValue(hPtr);
5865	windows[1] = NULL;
5866	goto done;
5867    }
5868
5869    NSCountWindows(&windowCount);
5870    if (!windowCount) {
5871	ckfree((char *) windows);
5872	windows = NULL;
5873    } else {
5874	window_ptr = windows + table.numEntries;
5875	*window_ptr-- = NULL;
5876	windowNumbers = (NSInteger *) ckalloc(windowCount * sizeof(NSInteger));
5877	NSWindowList(windowCount, windowNumbers);
5878	for (NSInteger index = 0; index < windowCount; index++) {
5879	    NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]];
5880
5881	    if (w) {
5882		hPtr = Tcl_FindHashEntry(&table, (char*) w);
5883		if (hPtr != NULL) {
5884		    childWinPtr = Tcl_GetHashValue(hPtr);
5885		    *window_ptr-- = childWinPtr;
5886		}
5887	    }
5888	}
5889	if (window_ptr != (windows-1)) {
5890	    Tcl_Panic("num matched toplevel windows does not equal num "
5891		    "children");
5892	}
5893	ckfree((char *) windowNumbers);
5894    }
5895
5896  done:
5897    Tcl_DeleteHashTable(&table);
5898    return windows;
5899}
5900
5901/*
5902 *----------------------------------------------------------------------
5903 *
5904 * TkMacOSXApplyWindowAttributes --
5905 *
5906 *	This procedure applies all window attributes to the NSWindow.
5907 *
5908 * Results:
5909 *	None.
5910 *
5911 * Side effects:
5912 *	None.
5913 *
5914 *----------------------------------------------------------------------
5915 */
5916
5917void
5918TkMacOSXApplyWindowAttributes(
5919    TkWindow *winPtr,
5920    NSWindow *macWindow)
5921{
5922    WmInfo *wmPtr = winPtr->wmInfoPtr;
5923    ApplyWindowAttributeFlagChanges(winPtr, macWindow, 0, 0, 0, 1);
5924    if (wmPtr->master != None || winPtr->atts.override_redirect) {
5925	ApplyMasterOverrideChanges(winPtr, macWindow);
5926    }
5927}
5928
5929/*
5930 *----------------------------------------------------------------------
5931 *
5932 * ApplyWindowAttributeFlagChanges --
5933 *
5934 *	This procedure applies window attribute and flag changes.
5935 *
5936 * Results:
5937 *	None.
5938 *
5939 * Side effects:
5940 *	None.
5941 *
5942 *----------------------------------------------------------------------
5943 */
5944
5945static void
5946ApplyWindowAttributeFlagChanges(
5947    TkWindow *winPtr,
5948    NSWindow *macWindow,
5949    UInt64 oldAttributes,
5950    int oldFlags,
5951    int create,
5952    int initial)
5953{
5954    WmInfo *wmPtr = winPtr->wmInfoPtr;
5955    UInt64 newAttributes = ForceAttributes(wmPtr->attributes, wmPtr->macClass);
5956    UInt64 changedAttributes = newAttributes ^ ForceAttributes(oldAttributes,
5957	    wmPtr->macClass);
5958
5959    if (changedAttributes || wmPtr->flags != oldFlags || initial) {
5960	if (!macWindow) {
5961	    if (winPtr->window == None) {
5962		if (create) {
5963		    Tk_MakeWindowExist((Tk_Window) winPtr);
5964		} else {
5965		    return;
5966		}
5967	    }
5968	    if (!TkMacOSXHostToplevelExists(winPtr)) {
5969		if (create) {
5970		    TkMacOSXMakeRealWindowExist(winPtr);
5971		} else {
5972		    return;
5973		}
5974	    }
5975	    macWindow = TkMacOSXDrawableWindow(winPtr->window);
5976	}
5977	if ((changedAttributes & kWindowCloseBoxAttribute) || initial) {
5978	    [[macWindow standardWindowButton:NSWindowCloseButton]
5979		    setEnabled:!!(newAttributes & kWindowCloseBoxAttribute)];
5980	}
5981	if ((changedAttributes & kWindowCollapseBoxAttribute) || initial) {
5982	    [[macWindow standardWindowButton:NSWindowMiniaturizeButton]
5983		    setEnabled:!!(newAttributes & kWindowCollapseBoxAttribute)];
5984	}
5985	if ((changedAttributes & (kWindowResizableAttribute |
5986		kWindowFullZoomAttribute)) || initial) {
5987	    [macWindow setShowsResizeIndicator:
5988		    !!(newAttributes & kWindowResizableAttribute)];
5989	    [[macWindow standardWindowButton:NSWindowZoomButton]
5990		    setEnabled:(newAttributes & kWindowResizableAttribute) &&
5991		    (newAttributes & kWindowFullZoomAttribute)];
5992	    if (newAttributes & kWindowResizableAttribute) {
5993		wmPtr->flags &= ~(WM_WIDTH_NOT_RESIZABLE |
5994			WM_HEIGHT_NOT_RESIZABLE);
5995	    } else {
5996		wmPtr->flags |= (WM_WIDTH_NOT_RESIZABLE |
5997			WM_HEIGHT_NOT_RESIZABLE);
5998	    }
5999	    WmUpdateGeom(wmPtr, winPtr);
6000	}
6001	if ((changedAttributes & kWindowToolbarButtonAttribute) || initial) {
6002	    [macWindow setShowsToolbarButton:
6003		    !!(newAttributes & kWindowToolbarButtonAttribute)];
6004	    if ((newAttributes & kWindowToolbarButtonAttribute) &&
6005		    ![macWindow toolbar]) {
6006		NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@""];
6007		[toolbar setVisible:NO];
6008		[macWindow setToolbar:toolbar];
6009		[toolbar release];
6010		NSCell *toolbarButtonCell = [[macWindow standardWindowButton:
6011			NSWindowToolbarButton] cell];
6012		[toolbarButtonCell setTarget:[macWindow contentView]];
6013		[toolbarButtonCell setAction:@selector(tkToolbarButton:)];
6014	    }
6015	}
6016	if ((changedAttributes & kWindowNoShadowAttribute) || initial) {
6017	    [macWindow setHasShadow:
6018		    !(newAttributes & kWindowNoShadowAttribute)];
6019	}
6020	if ((changedAttributes & kWindowHideOnSuspendAttribute) || initial) {
6021	    [macWindow setHidesOnDeactivate:
6022		    !!(newAttributes & kWindowHideOnSuspendAttribute)];
6023	}
6024	if ((changedAttributes & kWindowInWindowMenuAttribute) || initial) {
6025	    [macWindow setExcludedFromWindowsMenu:
6026		    !(newAttributes & kWindowInWindowMenuAttribute)];
6027	}
6028	if ((changedAttributes & kWindowIgnoreClicksAttribute) || initial) {
6029	    [macWindow setIgnoresMouseEvents:
6030		    !!(newAttributes & kWindowIgnoreClicksAttribute)];
6031	}
6032	if ((changedAttributes & tkWindowDoesNotHideAttribute) || initial) {
6033	    [macWindow setCanHide:
6034		    !(newAttributes & tkWindowDoesNotHideAttribute)];
6035	}
6036	if ((changedAttributes & (kWindowDoesNotCycleAttribute |
6037		tkCanJoinAllSpacesAttribute | tkMoveToActiveSpaceAttribute)) ||
6038		initial) {
6039	    NSWindowCollectionBehavior b = NSWindowCollectionBehaviorDefault;
6040	    if (newAttributes & tkCanJoinAllSpacesAttribute) {
6041		b |= NSWindowCollectionBehaviorCanJoinAllSpaces;
6042	    } else if (newAttributes & tkMoveToActiveSpaceAttribute) {
6043		b |= NSWindowCollectionBehaviorMoveToActiveSpace;
6044	    }
6045#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
6046	    if (newAttributes & kWindowDoesNotCycleAttribute) {
6047		b |= NSWindowCollectionBehaviorIgnoresCycle;
6048	    } else {
6049		b |= NSWindowCollectionBehaviorParticipatesInCycle;
6050	    }
6051#endif
6052	    [macWindow setCollectionBehavior:b];
6053#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
6054	    if (((changedAttributes & kWindowDoesNotCycleAttribute) || initial)
6055#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
6056		    && tkMacOSXMacOSXVersion < 1006
6057#endif
6058	    ) {
6059		[macWindow setCanCycle:
6060			!(newAttributes & kWindowDoesNotCycleAttribute)];
6061	    }
6062#endif
6063	}
6064	if ((wmPtr->flags & WM_TOPMOST) != (oldFlags & WM_TOPMOST)) {
6065	    [macWindow setLevel:(wmPtr->flags & WM_TOPMOST) ?
6066		    kCGUtilityWindowLevel : ([macWindow isKindOfClass:
6067		    [NSPanel class]] && [macWindow isFloatingPanel] ?
6068		    kCGFloatingWindowLevel : kCGNormalWindowLevel)];
6069	}
6070
6071	/*
6072	 * The change of window class/attributes might have changed the window
6073	 * structure widths:
6074	 */
6075
6076	NSRect structureRect = [macWindow frameRectForContentRect:NSZeroRect];
6077	wmPtr->xInParent = -structureRect.origin.x;
6078	wmPtr->yInParent = structureRect.origin.y + structureRect.size.height;
6079	wmPtr->parentWidth = winPtr->changes.width + structureRect.size.width;
6080	wmPtr->parentHeight = winPtr->changes.height + structureRect.size.height;
6081    }
6082}
6083
6084/*
6085 *----------------------------------------------------------------------
6086 *
6087 * ApplyMasterOverrideChanges --
6088 *
6089 *	This procedure applies changes to override_redirect or master.
6090 *
6091 * Results:
6092 *	None.
6093 *
6094 * Side effects:
6095 *	None.
6096 *
6097 *----------------------------------------------------------------------
6098 */
6099
6100static void
6101ApplyMasterOverrideChanges(
6102    TkWindow *winPtr,
6103    NSWindow *macWindow)
6104{
6105    WmInfo *wmPtr = winPtr->wmInfoPtr;
6106    UInt64 oldAttributes = wmPtr->attributes;
6107    int oldFlags = wmPtr->flags;
6108
6109    /*
6110     * FIX: We need an UpdateWrapper equivalent to make this 100% correct
6111     */
6112
6113    if (winPtr->atts.override_redirect) {
6114	if (wmPtr->macClass == kDocumentWindowClass) {
6115	    wmPtr->macClass = kSimpleWindowClass;
6116	    wmPtr->attributes = macClassAttrs[kSimpleWindowClass].defaultAttrs;
6117	}
6118	wmPtr->attributes |= kWindowNoActivatesAttribute;
6119    } else {
6120	if (wmPtr->macClass == kSimpleWindowClass &&
6121		oldAttributes == kWindowNoActivatesAttribute) {
6122	    wmPtr->macClass = kDocumentWindowClass;
6123	    wmPtr->attributes =
6124		    macClassAttrs[kDocumentWindowClass].defaultAttrs;
6125	}
6126	wmPtr->attributes &= ~kWindowNoActivatesAttribute;
6127    }
6128    if (!macWindow && winPtr->window != None &&
6129	    TkMacOSXHostToplevelExists(winPtr)) {
6130	macWindow = TkMacOSXDrawableWindow(winPtr->window);
6131    }
6132    if (macWindow) {
6133	if (winPtr->atts.override_redirect && wmPtr->master != None) {
6134	    wmPtr->flags |= WM_TOPMOST;
6135	} else {
6136	    wmPtr->flags &= ~WM_TOPMOST;
6137	}
6138	NSWindow *parentWindow = [macWindow parentWindow];
6139	if (wmPtr->master != None) {
6140	    TkDisplay *dispPtr = TkGetDisplayList();
6141	    TkWindow *masterWinPtr = (TkWindow *)
6142		    Tk_IdToWindow(dispPtr->display, wmPtr->master);
6143
6144	    if (masterWinPtr && masterWinPtr->window != None &&
6145		    TkMacOSXHostToplevelExists(masterWinPtr)) {
6146		NSWindow *masterMacWin =
6147			TkMacOSXDrawableWindow(masterWinPtr->window);
6148
6149		if (masterMacWin && masterMacWin != parentWindow &&
6150			(winPtr->flags & TK_MAPPED)) {
6151		    if (parentWindow) {
6152			[parentWindow removeChildWindow:macWindow];
6153		    }
6154		    [masterMacWin addChildWindow:macWindow
6155			    ordered:NSWindowAbove];
6156		    if (wmPtr->flags & WM_TOPMOST) {
6157			[macWindow setLevel:kCGUtilityWindowLevel];
6158		    }
6159		}
6160	    }
6161	} else if (parentWindow) {
6162	    [parentWindow removeChildWindow:macWindow];
6163	}
6164	ApplyWindowAttributeFlagChanges(winPtr, macWindow, oldAttributes,
6165		oldFlags, 0, 0);
6166    }
6167}
6168
6169/*
6170 *----------------------------------------------------------------------
6171 *
6172 * TkMacOSXMakeFullscreen --
6173 *
6174 *	This procedure sets a fullscreen window to the size of the screen.
6175 *
6176 * Results:
6177 *	A standard Tcl result.
6178 *
6179 * Side effects:
6180 *	None.
6181 *
6182 *----------------------------------------------------------------------
6183 */
6184
6185int
6186TkMacOSXMakeFullscreen(
6187    TkWindow *winPtr,
6188    NSWindow *window,
6189    int fullscreen,
6190    Tcl_Interp *interp)
6191{
6192    WmInfo *wmPtr = winPtr->wmInfoPtr;
6193    int result = TCL_OK, wasFullscreen = (wmPtr->flags & WM_FULLSCREEN);
6194
6195    if (fullscreen) {
6196	int screenWidth =  WidthOfScreen(Tk_Screen(winPtr));
6197	int screenHeight = HeightOfScreen(Tk_Screen(winPtr));
6198
6199	/*
6200	 * Check max width and height if set by the user.
6201	 */
6202
6203	if ((wmPtr->maxWidth > 0 && wmPtr->maxWidth < screenWidth)
6204		|| (wmPtr->maxHeight > 0 && wmPtr->maxHeight < screenHeight)) {
6205	    if (interp) {
6206		Tcl_AppendResult(interp,
6207			"can't set fullscreen attribute for \"",
6208			winPtr->pathName,
6209			"\": max width/height is too small", NULL);
6210	    }
6211	    result = TCL_ERROR;
6212	    wmPtr->flags &= ~WM_FULLSCREEN;
6213	} else {
6214	    NSRect bounds = [window contentRectForFrameRect:[window frame]];
6215	    NSRect screenBounds = NSMakeRect(0, 0, screenWidth, screenHeight);
6216
6217	    if (!NSEqualRects(bounds, screenBounds) && !wasFullscreen) {
6218		wmPtr->configX = wmPtr->x;
6219		wmPtr->configY = wmPtr->y;
6220		wmPtr->configAttributes = wmPtr->attributes;
6221		wmPtr->attributes &= ~kWindowResizableAttribute;
6222		ApplyWindowAttributeFlagChanges(winPtr, window,
6223			wmPtr->configAttributes, wmPtr->flags, 1, 0);
6224		wmPtr->flags |= WM_SYNC_PENDING;
6225		[window setFrame:[window frameRectForContentRect:
6226			screenBounds] display:YES];
6227		wmPtr->flags &= ~WM_SYNC_PENDING;
6228	    }
6229	    wmPtr->flags |= WM_FULLSCREEN;
6230	}
6231    } else {
6232	wmPtr->flags &= ~WM_FULLSCREEN;
6233    }
6234    TkMacOSXEnterExitFullscreen(winPtr, [window isKeyWindow]);
6235    if (wasFullscreen && !(wmPtr->flags & WM_FULLSCREEN)) {
6236	UInt64 oldAttributes = wmPtr->attributes;
6237	NSRect bounds = NSMakeRect(wmPtr->configX, tkMacOSXZeroScreenHeight -
6238		(wmPtr->configY + wmPtr->yInParent + wmPtr->configHeight),
6239		wmPtr->xInParent + wmPtr->configWidth,
6240		wmPtr->yInParent + wmPtr->configHeight);
6241
6242	wmPtr->attributes |= wmPtr->configAttributes &
6243		kWindowResizableAttribute;
6244	ApplyWindowAttributeFlagChanges(winPtr, window, oldAttributes,
6245		wmPtr->flags, 1, 0);
6246	wmPtr->flags |= WM_SYNC_PENDING;
6247	[window setFrame:[window frameRectForContentRect:bounds] display:YES];
6248	wmPtr->flags &= ~WM_SYNC_PENDING;
6249    }
6250    return result;
6251}
6252
6253/*
6254 *----------------------------------------------------------------------
6255 *
6256 * TkMacOSXEnterExitFullscreen --
6257 *
6258 *	This procedure enters or exits fullscreen mode if required.
6259 *
6260 * Results:
6261 *	None.
6262 *
6263 * Side effects:
6264 *	None.
6265 *
6266 *----------------------------------------------------------------------
6267 */
6268
6269void
6270TkMacOSXEnterExitFullscreen(
6271    TkWindow *winPtr,
6272    int active)
6273{
6274    WmInfo *wmPtr = winPtr->wmInfoPtr;
6275    NSWindow *window = TkMacOSXDrawableWindow(winPtr->window);
6276    SystemUIMode mode;
6277    SystemUIOptions options;
6278
6279    GetSystemUIMode(&mode, &options);
6280    if (window && wmPtr && (wmPtr->flags & WM_FULLSCREEN) && active) {
6281	static SystemUIMode fullscreenMode = 0;
6282	static SystemUIOptions fullscreenOptions = 0;
6283
6284	if (!fullscreenMode) {
6285	    fullscreenMode = kUIModeAllSuppressed;
6286	}
6287	if (mode != fullscreenMode) {
6288	    ChkErr(SetSystemUIMode, fullscreenMode, fullscreenOptions);
6289	    wmPtr->flags |= WM_SYNC_PENDING;
6290	    [window setFrame:[window frameRectForContentRect:NSMakeRect(0, 0,
6291		    WidthOfScreen(Tk_Screen(winPtr)),
6292		    HeightOfScreen(Tk_Screen(winPtr)))] display:YES];
6293	    wmPtr->flags &= ~WM_SYNC_PENDING;
6294	}
6295    } else {
6296	if (mode != kUIModeNormal) {
6297	    ChkErr(SetSystemUIMode, kUIModeNormal, 0);
6298	}
6299    }
6300}
6301
6302/*
6303 *----------------------------------------------------------------------
6304 *
6305 * GetMinSize --
6306 *
6307 *	This function computes the current minWidth and minHeight values for a
6308 *	window, taking into account the possibility that they may be
6309 *	defaulted.
6310 *
6311 * Results:
6312 *	The values at *minWidthPtr and *minHeightPtr are filled in with the
6313 *	minimum allowable dimensions of wmPtr's window, in grid units. If the
6314 *	requested minimum is smaller than the system required minimum, then
6315 *	this function computes the smallest size that will satisfy both the
6316 *	system and the grid constraints.
6317 *
6318 * Side effects:
6319 *	None.
6320 *
6321 *----------------------------------------------------------------------
6322 */
6323
6324static void
6325GetMinSize(
6326    TkWindow *winPtr,		/* Toplevel window to operate on. */
6327    int *minWidthPtr,		/* Where to store the current minimum width of
6328				 * the window. */
6329    int *minHeightPtr)		/* Where to store the current minimum height
6330				 * of the window. */
6331{
6332    WmInfo *wmPtr = winPtr->wmInfoPtr;
6333    int minWidth = 1, minHeight = 1;
6334
6335    /*
6336     * Compute the minimum width & height by taking the default client size and
6337     * rounding it up to the nearest grid unit. Return the greater of the
6338     * default minimum and the specified minimum.
6339     */
6340
6341    switch (wmPtr->macClass) {
6342    case kDocumentWindowClass:
6343    case kMovableAlertWindowClass:
6344    case kMovableModalWindowClass:
6345	minWidth = 72;
6346	if (wmPtr->attributes & kWindowResizableAttribute) {
6347	    minHeight = 15;
6348	}
6349	if (wmPtr->attributes & kWindowToolbarButtonAttribute) {
6350	    minWidth += 29;
6351	}
6352	break;
6353    case kFloatingWindowClass:
6354    case kUtilityWindowClass:
6355	minWidth = 59;
6356	if (wmPtr->attributes & kWindowResizableAttribute) {
6357	    minHeight = 11;
6358	}
6359	if (wmPtr->attributes & kWindowSideTitlebarAttribute) {
6360	    int tmp = minWidth;
6361
6362	    minWidth = minHeight;
6363	    minHeight = tmp;
6364	} else if (wmPtr->attributes & kWindowToolbarButtonAttribute) {
6365	    minWidth += 29;
6366	}
6367	break;
6368    default:
6369	if (wmPtr->attributes & kWindowResizableAttribute) {
6370	    minWidth = 15;
6371	    minHeight = 15;
6372	}
6373	break;
6374    }
6375
6376    if (wmPtr->gridWin != NULL) {
6377	int base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
6378
6379	if (base < 0) {
6380	    base = 0;
6381	}
6382	minWidth = ((minWidth - base) + wmPtr->widthInc-1)/wmPtr->widthInc;
6383	base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
6384	if (base < 0) {
6385	    base = 0;
6386	}
6387	minHeight = ((minHeight - base) + wmPtr->heightInc-1)/wmPtr->heightInc;
6388    }
6389    if (minWidth < wmPtr->minWidth) {
6390	minWidth = wmPtr->minWidth;
6391    }
6392    if (minHeight < wmPtr->minHeight) {
6393	minHeight = wmPtr->minHeight;
6394    }
6395    *minWidthPtr = minWidth;
6396    *minHeightPtr = minHeight;
6397}
6398
6399/*
6400 *----------------------------------------------------------------------
6401 *
6402 * GetMaxSize --
6403 *
6404 *	This function computes the current maxWidth and maxHeight values for a
6405 *	window, taking into account the possibility that they may be
6406 *	defaulted.
6407 *
6408 * Results:
6409 *	The values at *maxWidthPtr and *maxHeightPtr are filled in with the
6410 *	maximum allowable dimensions of wmPtr's window, in grid units. If no
6411 *	maximum has been specified for the window, then this function computes
6412 *	the largest sizes that will fit on the screen.
6413 *
6414 * Side effects:
6415 *	None.
6416 *
6417 *----------------------------------------------------------------------
6418 */
6419
6420static void
6421GetMaxSize(
6422    TkWindow *winPtr,		/* Toplevel window to operate on. */
6423    int *maxWidthPtr,		/* Where to store the current maximum width of
6424				 * the window. */
6425    int *maxHeightPtr)		/* Where to store the current maximum height
6426				 * of the window. */
6427{
6428    WmInfo *wmPtr = winPtr->wmInfoPtr;
6429    NSRect *maxBounds = (NSRect*)(winPtr->display->screens->ext_data);
6430
6431    if (wmPtr->maxWidth > 0) {
6432	*maxWidthPtr = wmPtr->maxWidth;
6433    } else {
6434	int maxWidth = maxBounds->size.width - wmPtr->xInParent;
6435
6436	if (wmPtr->gridWin != NULL) {
6437	    maxWidth = wmPtr->reqGridWidth
6438		    + (maxWidth - winPtr->reqWidth)/wmPtr->widthInc;
6439	}
6440	*maxWidthPtr = maxWidth;
6441    }
6442    if (wmPtr->maxHeight > 0) {
6443	*maxHeightPtr = wmPtr->maxHeight;
6444    } else {
6445	int maxHeight = maxBounds->size.height - wmPtr->yInParent;
6446
6447	if (wmPtr->gridWin != NULL) {
6448	    maxHeight = wmPtr->reqGridHeight
6449		    + (maxHeight - winPtr->reqHeight)/wmPtr->heightInc;
6450	}
6451	*maxHeightPtr = maxHeight;
6452    }
6453}
6454
6455/*
6456 *----------------------------------------------------------------------
6457 *
6458 * RemapWindows
6459 *
6460 *	Adjust parent/child relation ships of the given window hierarchy.
6461 *
6462 * Results:
6463 *	none
6464 *
6465 * Side effects:
6466 *	keeps windowing system (X11) happy
6467 *
6468 *----------------------------------------------------------------------
6469 */
6470
6471static void
6472RemapWindows(
6473    TkWindow *winPtr,
6474    MacDrawable *parentWin)
6475{
6476    TkWindow *childPtr;
6477
6478    /*
6479     * Remove the OS specific window. It will get rebuilt when the window gets
6480     * Mapped.
6481     */
6482
6483    if (winPtr->window != None) {
6484	MacDrawable *macWin = (MacDrawable *) winPtr->window;
6485
6486	macWin->toplevel = parentWin->toplevel;
6487	winPtr->flags &= ~TK_MAPPED;
6488#ifdef TK_REBUILD_TOPLEVEL
6489	winPtr->flags |= TK_REBUILD_TOPLEVEL;
6490#endif
6491    }
6492
6493    /* Repeat for all the children */
6494    for (childPtr = winPtr->childList; childPtr != NULL;
6495	    childPtr = childPtr->nextPtr) {
6496	RemapWindows(childPtr, (MacDrawable *) winPtr->window);
6497    }
6498}
6499
6500/*
6501 * Local Variables:
6502 * mode: c
6503 * c-basic-offset: 4
6504 * fill-column: 79
6505 * coding: utf-8
6506 * End:
6507 */
6508