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