1/*
2 * tkCmds.c --
3 *
4 *	This file contains a collection of Tk-related Tcl commands that didn't
5 *	fit in any particular file of the toolkit.
6 *
7 * Copyright (c) 1990-1994 The Regents of the University of California.
8 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
9 * Copyright (c) 2000 Scriptics Corporation.
10 *
11 * See the file "license.terms" for information on usage and redistribution of
12 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 *
14 * RCS: @(#) $Id$
15 */
16
17#include "tkInt.h"
18
19#if defined(WIN32)
20#include "tkWinInt.h"
21#elif defined(MAC_OSX_TK)
22#include "tkMacOSXInt.h"
23#else
24#include "tkUnixInt.h"
25#endif
26
27/*
28 * Forward declarations for functions defined later in this file:
29 */
30
31static TkWindow *	GetTopHierarchy(Tk_Window tkwin);
32static char *		WaitVariableProc(ClientData clientData,
33			    Tcl_Interp *interp, const char *name1,
34			    const char *name2, int flags);
35static void		WaitVisibilityProc(ClientData clientData,
36			    XEvent *eventPtr);
37static void		WaitWindowProc(ClientData clientData,
38			    XEvent *eventPtr);
39
40/*
41 *----------------------------------------------------------------------
42 *
43 * Tk_BellObjCmd --
44 *
45 *	This function is invoked to process the "bell" Tcl command. See the
46 *	user documentation for details on what it does.
47 *
48 * Results:
49 *	A standard Tcl result.
50 *
51 * Side effects:
52 *	See the user documentation.
53 *
54 *----------------------------------------------------------------------
55 */
56
57int
58Tk_BellObjCmd(
59    ClientData clientData,	/* Main window associated with interpreter. */
60    Tcl_Interp *interp,		/* Current interpreter. */
61    int objc,			/* Number of arguments. */
62    Tcl_Obj *const objv[])	/* Argument objects. */
63{
64    static const char *bellOptions[] = {
65	"-displayof", "-nice", NULL
66    };
67    enum options { TK_BELL_DISPLAYOF, TK_BELL_NICE };
68    Tk_Window tkwin = (Tk_Window) clientData;
69    int i, index, nice = 0;
70
71    if (objc > 4) {
72    wrongArgs:
73	Tcl_WrongNumArgs(interp, 1, objv, "?-displayof window? ?-nice?");
74	return TCL_ERROR;
75    }
76
77    for (i = 1; i < objc; i++) {
78	if (Tcl_GetIndexFromObj(interp, objv[i], bellOptions, "option", 0,
79		&index) != TCL_OK) {
80	    return TCL_ERROR;
81	}
82	switch ((enum options) index) {
83	case TK_BELL_DISPLAYOF:
84	    if (++i >= objc) {
85		goto wrongArgs;
86	    }
87	    tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[i]), tkwin);
88	    if (tkwin == NULL) {
89		return TCL_ERROR;
90	    }
91	    break;
92	case TK_BELL_NICE:
93	    nice = 1;
94	    break;
95	}
96    }
97    XBell(Tk_Display(tkwin), 0);
98    if (!nice) {
99	XForceScreenSaver(Tk_Display(tkwin), ScreenSaverReset);
100    }
101    XFlush(Tk_Display(tkwin));
102    return TCL_OK;
103}
104
105/*
106 *----------------------------------------------------------------------
107 *
108 * Tk_BindObjCmd --
109 *
110 *	This function is invoked to process the "bind" Tcl command. See the
111 *	user documentation for details on what it does.
112 *
113 * Results:
114 *	A standard Tcl result.
115 *
116 * Side effects:
117 *	See the user documentation.
118 *
119 *----------------------------------------------------------------------
120 */
121
122int
123Tk_BindObjCmd(
124    ClientData clientData,	/* Main window associated with interpreter. */
125    Tcl_Interp *interp,		/* Current interpreter. */
126    int objc,			/* Number of arguments. */
127    Tcl_Obj *const objv[])	/* Argument objects. */
128{
129    Tk_Window tkwin = (Tk_Window) clientData;
130    TkWindow *winPtr;
131    ClientData object;
132    char *string;
133
134    if ((objc < 2) || (objc > 4)) {
135	Tcl_WrongNumArgs(interp, 1, objv, "window ?pattern? ?command?");
136	return TCL_ERROR;
137    }
138    string = Tcl_GetString(objv[1]);
139
140    /*
141     * Bind tags either a window name or a tag name for the first argument.
142     * If the argument starts with ".", assume it is a window; otherwise, it
143     * is a tag.
144     */
145
146    if (string[0] == '.') {
147	winPtr = (TkWindow *) Tk_NameToWindow(interp, string, tkwin);
148	if (winPtr == NULL) {
149	    return TCL_ERROR;
150	}
151	object = (ClientData) winPtr->pathName;
152    } else {
153	winPtr = (TkWindow *) clientData;
154	object = (ClientData) Tk_GetUid(string);
155    }
156
157    /*
158     * If there are four arguments, the command is modifying a binding. If
159     * there are three arguments, the command is querying a binding. If there
160     * are only two arguments, the command is querying all the bindings for
161     * the given tag/window.
162     */
163
164    if (objc == 4) {
165	int append = 0;
166	unsigned long mask;
167	char *sequence, *script;
168	sequence	= Tcl_GetString(objv[2]);
169	script		= Tcl_GetString(objv[3]);
170
171	/*
172	 * If the script is null, just delete the binding.
173	 */
174
175	if (script[0] == 0) {
176	    return Tk_DeleteBinding(interp, winPtr->mainPtr->bindingTable,
177		    object, sequence);
178	}
179
180	/*
181	 * If the script begins with "+", append this script to the existing
182	 * binding.
183	 */
184
185	if (script[0] == '+') {
186	    script++;
187	    append = 1;
188	}
189	mask = Tk_CreateBinding(interp, winPtr->mainPtr->bindingTable,
190		object, sequence, script, append);
191	if (mask == 0) {
192	    return TCL_ERROR;
193	}
194    } else if (objc == 3) {
195	const char *command;
196
197	command = Tk_GetBinding(interp, winPtr->mainPtr->bindingTable,
198		object, Tcl_GetString(objv[2]));
199	if (command == NULL) {
200	    Tcl_ResetResult(interp);
201	    return TCL_OK;
202	}
203	Tcl_SetResult(interp, (char *) command, TCL_STATIC);
204    } else {
205	Tk_GetAllBindings(interp, winPtr->mainPtr->bindingTable, object);
206    }
207    return TCL_OK;
208}
209
210/*
211 *----------------------------------------------------------------------
212 *
213 * TkBindEventProc --
214 *
215 *	This function is invoked by Tk_HandleEvent for each event; it causes
216 *	any appropriate bindings for that event to be invoked.
217 *
218 * Results:
219 *	None.
220 *
221 * Side effects:
222 *	Depends on what bindings have been established with the "bind"
223 *	command.
224 *
225 *----------------------------------------------------------------------
226 */
227
228void
229TkBindEventProc(
230    TkWindow *winPtr,		/* Pointer to info about window. */
231    XEvent *eventPtr)		/* Information about event. */
232{
233#define MAX_OBJS 20
234    ClientData objects[MAX_OBJS], *objPtr;
235    TkWindow *topLevPtr;
236    int i, count;
237    char *p;
238    Tcl_HashEntry *hPtr;
239
240    if ((winPtr->mainPtr == NULL) || (winPtr->mainPtr->bindingTable == NULL)) {
241	return;
242    }
243
244    objPtr = objects;
245    if (winPtr->numTags != 0) {
246	/*
247	 * Make a copy of the tags for the window, replacing window names with
248	 * pointers to the pathName from the appropriate window.
249	 */
250
251	if (winPtr->numTags > MAX_OBJS) {
252	    objPtr = (ClientData *) ckalloc((unsigned)
253		    (winPtr->numTags * sizeof(ClientData)));
254	}
255	for (i = 0; i < winPtr->numTags; i++) {
256	    p = (char *) winPtr->tagPtr[i];
257	    if (*p == '.') {
258		hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->nameTable, p);
259		if (hPtr != NULL) {
260		    p = ((TkWindow *) Tcl_GetHashValue(hPtr))->pathName;
261		} else {
262		    p = NULL;
263		}
264	    }
265	    objPtr[i] = (ClientData) p;
266	}
267	count = winPtr->numTags;
268    } else {
269	objPtr[0] = (ClientData) winPtr->pathName;
270	objPtr[1] = (ClientData) winPtr->classUid;
271	for (topLevPtr = winPtr;
272		(topLevPtr != NULL) && !(topLevPtr->flags & TK_TOP_HIERARCHY);
273		topLevPtr = topLevPtr->parentPtr) {
274	    /* Empty loop body. */
275	}
276	if ((winPtr != topLevPtr) && (topLevPtr != NULL)) {
277	    count = 4;
278	    objPtr[2] = (ClientData) topLevPtr->pathName;
279	} else {
280	    count = 3;
281	}
282	objPtr[count-1] = (ClientData) Tk_GetUid("all");
283    }
284    Tk_BindEvent(winPtr->mainPtr->bindingTable, eventPtr, (Tk_Window) winPtr,
285	    count, objPtr);
286    if (objPtr != objects) {
287	ckfree((char *) objPtr);
288    }
289}
290
291/*
292 *----------------------------------------------------------------------
293 *
294 * Tk_BindtagsObjCmd --
295 *
296 *	This function is invoked to process the "bindtags" Tcl command. See
297 *	the user documentation for details on what it does.
298 *
299 * Results:
300 *	A standard Tcl result.
301 *
302 * Side effects:
303 *	See the user documentation.
304 *
305 *----------------------------------------------------------------------
306 */
307
308int
309Tk_BindtagsObjCmd(
310    ClientData clientData,	/* Main window associated with interpreter. */
311    Tcl_Interp *interp,		/* Current interpreter. */
312    int objc,			/* Number of arguments. */
313    Tcl_Obj *const objv[])	/* Argument objects. */
314{
315    Tk_Window tkwin = (Tk_Window) clientData;
316    TkWindow *winPtr, *winPtr2;
317    int i, length;
318    char *p;
319    Tcl_Obj *listPtr, **tags;
320
321    if ((objc < 2) || (objc > 3)) {
322	Tcl_WrongNumArgs(interp, 1, objv, "window ?taglist?");
323	return TCL_ERROR;
324    }
325    winPtr = (TkWindow *) Tk_NameToWindow(interp, Tcl_GetString(objv[1]),
326	    tkwin);
327    if (winPtr == NULL) {
328	return TCL_ERROR;
329    }
330    if (objc == 2) {
331	listPtr = Tcl_NewObj();
332	Tcl_IncrRefCount(listPtr);
333	if (winPtr->numTags == 0) {
334	    Tcl_ListObjAppendElement(interp, listPtr,
335		    Tcl_NewStringObj(winPtr->pathName, -1));
336	    Tcl_ListObjAppendElement(interp, listPtr,
337		    Tcl_NewStringObj(winPtr->classUid, -1));
338	    winPtr2 = winPtr;
339	    while ((winPtr2 != NULL) && !(Tk_TopWinHierarchy(winPtr2))) {
340		winPtr2 = winPtr2->parentPtr;
341	    }
342	    if ((winPtr != winPtr2) && (winPtr2 != NULL)) {
343		Tcl_ListObjAppendElement(interp, listPtr,
344			Tcl_NewStringObj(winPtr2->pathName, -1));
345	    }
346	    Tcl_ListObjAppendElement(interp, listPtr,
347		    Tcl_NewStringObj("all", -1));
348	} else {
349	    for (i = 0; i < winPtr->numTags; i++) {
350		Tcl_ListObjAppendElement(interp, listPtr,
351			Tcl_NewStringObj((char *)winPtr->tagPtr[i], -1));
352	    }
353	}
354	Tcl_SetObjResult(interp, listPtr);
355	Tcl_DecrRefCount(listPtr);
356	return TCL_OK;
357    }
358    if (winPtr->tagPtr != NULL) {
359	TkFreeBindingTags(winPtr);
360    }
361    if (Tcl_ListObjGetElements(interp, objv[2], &length, &tags) != TCL_OK) {
362	return TCL_ERROR;
363    }
364    if (length == 0) {
365	return TCL_OK;
366    }
367
368    winPtr->numTags = length;
369    winPtr->tagPtr = (ClientData *) ckalloc((unsigned)
370	    (length * sizeof(ClientData)));
371    for (i = 0; i < length; i++) {
372	p = Tcl_GetString(tags[i]);
373	if (p[0] == '.') {
374	    char *copy;
375
376	    /*
377	     * Handle names starting with "." specially: store a malloc'ed
378	     * string, rather than a Uid; at event time we'll look up the name
379	     * in the window table and use the corresponding window, if there
380	     * is one.
381	     */
382
383	    copy = (char *) ckalloc((unsigned) (strlen(p) + 1));
384	    strcpy(copy, p);
385	    winPtr->tagPtr[i] = (ClientData) copy;
386	} else {
387	    winPtr->tagPtr[i] = (ClientData) Tk_GetUid(p);
388	}
389    }
390    return TCL_OK;
391}
392
393/*
394 *----------------------------------------------------------------------
395 *
396 * TkFreeBindingTags --
397 *
398 *	This function is called to free all of the binding tags associated
399 *	with a window; typically it is only invoked where there are
400 *	window-specific tags.
401 *
402 * Results:
403 *	None.
404 *
405 * Side effects:
406 *	Any binding tags for winPtr are freed.
407 *
408 *----------------------------------------------------------------------
409 */
410
411void
412TkFreeBindingTags(
413    TkWindow *winPtr)		/* Window whose tags are to be released. */
414{
415    int i;
416    char *p;
417
418    for (i = 0; i < winPtr->numTags; i++) {
419	p = (char *) (winPtr->tagPtr[i]);
420	if (*p == '.') {
421	    /*
422	     * Names starting with "." are malloced rather than Uids, so they
423	     * have to be freed.
424	     */
425
426	    ckfree(p);
427	}
428    }
429    ckfree((char *) winPtr->tagPtr);
430    winPtr->numTags = 0;
431    winPtr->tagPtr = NULL;
432}
433
434/*
435 *----------------------------------------------------------------------
436 *
437 * Tk_DestroyObjCmd --
438 *
439 *	This function is invoked to process the "destroy" Tcl command. See the
440 *	user documentation for details on what it does.
441 *
442 * Results:
443 *	A standard Tcl result.
444 *
445 * Side effects:
446 *	See the user documentation.
447 *
448 *----------------------------------------------------------------------
449 */
450
451int
452Tk_DestroyObjCmd(
453    ClientData clientData,	/* Main window associated with interpreter. */
454    Tcl_Interp *interp,		/* Current interpreter. */
455    int objc,			/* Number of arguments. */
456    Tcl_Obj *const objv[])	/* Argument objects. */
457{
458    Tk_Window window;
459    Tk_Window tkwin = (Tk_Window) clientData;
460    int i;
461
462    for (i = 1; i < objc; i++) {
463	window = Tk_NameToWindow(interp, Tcl_GetString(objv[i]), tkwin);
464	if (window == NULL) {
465	    Tcl_ResetResult(interp);
466	    continue;
467	}
468	Tk_DestroyWindow(window);
469	if (window == tkwin) {
470	    /*
471	     * We just deleted the main window for the application! This makes
472	     * it impossible to do anything more (tkwin isn't valid anymore).
473	     */
474
475	    break;
476	}
477    }
478    return TCL_OK;
479}
480
481/*
482 *----------------------------------------------------------------------
483 *
484 * Tk_LowerObjCmd --
485 *
486 *	This function is invoked to process the "lower" Tcl command. See the
487 *	user documentation for details on what it does.
488 *
489 * Results:
490 *	A standard Tcl result.
491 *
492 * Side effects:
493 *	See the user documentation.
494 *
495 *----------------------------------------------------------------------
496 */
497
498	/* ARGSUSED */
499int
500Tk_LowerObjCmd(
501    ClientData clientData,	/* Main window associated with interpreter. */
502    Tcl_Interp *interp,		/* Current interpreter. */
503    int objc,			/* Number of arguments. */
504    Tcl_Obj *const objv[])	/* Argument objects. */
505{
506    Tk_Window mainwin = (Tk_Window) clientData;
507    Tk_Window tkwin, other;
508
509    if ((objc != 2) && (objc != 3)) {
510	Tcl_WrongNumArgs(interp, 1, objv, "window ?belowThis?");
511	return TCL_ERROR;
512    }
513
514    tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[1]), mainwin);
515    if (tkwin == NULL) {
516	return TCL_ERROR;
517    }
518    if (objc == 2) {
519	other = NULL;
520    } else {
521	other = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), mainwin);
522	if (other == NULL) {
523	    return TCL_ERROR;
524	}
525    }
526    if (Tk_RestackWindow(tkwin, Below, other) != TCL_OK) {
527	Tcl_AppendResult(interp, "can't lower \"", Tcl_GetString(objv[1]),
528		"\" below \"", (other ? Tcl_GetString(objv[2]) : ""),
529		"\"", NULL);
530	return TCL_ERROR;
531    }
532    return TCL_OK;
533}
534
535/*
536 *----------------------------------------------------------------------
537 *
538 * Tk_RaiseObjCmd --
539 *
540 *	This function is invoked to process the "raise" Tcl command. See the
541 *	user documentation for details on what it does.
542 *
543 * Results:
544 *	A standard Tcl result.
545 *
546 * Side effects:
547 *	See the user documentation.
548 *
549 *----------------------------------------------------------------------
550 */
551
552	/* ARGSUSED */
553int
554Tk_RaiseObjCmd(
555    ClientData clientData,	/* Main window associated with interpreter. */
556    Tcl_Interp *interp,		/* Current interpreter. */
557    int objc,			/* Number of arguments. */
558    Tcl_Obj *const objv[])	/* Argument objects. */
559{
560    Tk_Window mainwin = (Tk_Window) clientData;
561    Tk_Window tkwin, other;
562
563    if ((objc != 2) && (objc != 3)) {
564	Tcl_WrongNumArgs(interp, 1, objv, "window ?aboveThis?");
565	return TCL_ERROR;
566    }
567
568    tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[1]), mainwin);
569    if (tkwin == NULL) {
570	return TCL_ERROR;
571    }
572    if (objc == 2) {
573	other = NULL;
574    } else {
575	other = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), mainwin);
576	if (other == NULL) {
577	    return TCL_ERROR;
578	}
579    }
580    if (Tk_RestackWindow(tkwin, Above, other) != TCL_OK) {
581	Tcl_AppendResult(interp, "can't raise \"", Tcl_GetString(objv[1]),
582		"\" above \"", (other ? Tcl_GetString(objv[2]) : ""),
583		"\"", NULL);
584	return TCL_ERROR;
585    }
586    return TCL_OK;
587}
588
589/*
590 *----------------------------------------------------------------------
591 *
592 * Tk_TkObjCmd --
593 *
594 *	This function is invoked to process the "tk" Tcl command. See the user
595 *	documentation for details on what it does.
596 *
597 * Results:
598 *	A standard Tcl result.
599 *
600 * Side effects:
601 *	See the user documentation.
602 *
603 *----------------------------------------------------------------------
604 */
605
606int
607Tk_TkObjCmd(
608    ClientData clientData,	/* Main window associated with interpreter. */
609    Tcl_Interp *interp,		/* Current interpreter. */
610    int objc,			/* Number of arguments. */
611    Tcl_Obj *const objv[])	/* Argument objects. */
612{
613    int index;
614    Tk_Window tkwin;
615    static const char *optionStrings[] = {
616	"appname",	"caret",	"scaling",	"useinputmethods",
617	"windowingsystem",		"inactive",	NULL
618    };
619    enum options {
620	TK_APPNAME,	TK_CARET,	TK_SCALING,	TK_USE_IM,
621	TK_WINDOWINGSYSTEM,		TK_INACTIVE
622    };
623
624    tkwin = (Tk_Window) clientData;
625
626    if (objc < 2) {
627	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
628	return TCL_ERROR;
629    }
630    if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
631	    &index) != TCL_OK) {
632	return TCL_ERROR;
633    }
634
635    switch ((enum options) index) {
636    case TK_APPNAME: {
637	TkWindow *winPtr;
638	char *string;
639
640	if (Tcl_IsSafe(interp)) {
641	    Tcl_SetResult(interp,
642		    "appname not accessible in a safe interpreter",
643		    TCL_STATIC);
644	    return TCL_ERROR;
645	}
646
647	winPtr = (TkWindow *) tkwin;
648
649	if (objc > 3) {
650	    Tcl_WrongNumArgs(interp, 2, objv, "?newName?");
651	    return TCL_ERROR;
652	}
653	if (objc == 3) {
654	    string = Tcl_GetString(objv[2]);
655	    winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, string));
656	}
657	Tcl_AppendResult(interp, winPtr->nameUid, NULL);
658	break;
659    }
660    case TK_CARET: {
661	Tcl_Obj *objPtr;
662	TkCaret *caretPtr;
663	Tk_Window window;
664	static const char *caretStrings[] = {
665	    "-x",	"-y", "-height", NULL
666	};
667	enum caretOptions {
668	    TK_CARET_X, TK_CARET_Y, TK_CARET_HEIGHT
669	};
670
671	if ((objc < 3) || ((objc > 4) && !(objc & 1))) {
672	    Tcl_WrongNumArgs(interp, 2, objv,
673		    "window ?-x x? ?-y y? ?-height height?");
674	    return TCL_ERROR;
675	}
676	window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin);
677	if (window == NULL) {
678	    return TCL_ERROR;
679	}
680	caretPtr = &(((TkWindow *) window)->dispPtr->caret);
681	if (objc == 3) {
682	    /*
683	     * Return all the current values
684	     */
685
686	    objPtr = Tcl_NewObj();
687	    Tcl_ListObjAppendElement(interp, objPtr,
688		    Tcl_NewStringObj("-height", 7));
689	    Tcl_ListObjAppendElement(interp, objPtr,
690		    Tcl_NewIntObj(caretPtr->height));
691	    Tcl_ListObjAppendElement(interp, objPtr,
692		    Tcl_NewStringObj("-x", 2));
693	    Tcl_ListObjAppendElement(interp, objPtr,
694		    Tcl_NewIntObj(caretPtr->x));
695	    Tcl_ListObjAppendElement(interp, objPtr,
696		    Tcl_NewStringObj("-y", 2));
697	    Tcl_ListObjAppendElement(interp, objPtr,
698		    Tcl_NewIntObj(caretPtr->y));
699	    Tcl_SetObjResult(interp, objPtr);
700	} else if (objc == 4) {
701	    int value;
702
703	    /*
704	     * Return the current value of the selected option
705	     */
706
707	    if (Tcl_GetIndexFromObj(interp, objv[3], caretStrings,
708		    "caret option", 0, &index) != TCL_OK) {
709		return TCL_ERROR;
710	    }
711	    if (index == TK_CARET_X) {
712		value = caretPtr->x;
713	    } else if (index == TK_CARET_Y) {
714		value = caretPtr->y;
715	    } else /* if (index == TK_CARET_HEIGHT) -- last case */ {
716		value = caretPtr->height;
717	    }
718	    Tcl_SetIntObj(Tcl_GetObjResult(interp), value);
719	} else {
720	    int i, value, x = 0, y = 0, height = -1;
721
722	    for (i = 3; i < objc; i += 2) {
723		if ((Tcl_GetIndexFromObj(interp, objv[i], caretStrings,
724			"caret option", 0, &index) != TCL_OK) ||
725			Tcl_GetIntFromObj(interp,objv[i+1],&value) != TCL_OK) {
726		    return TCL_ERROR;
727		}
728		if (index == TK_CARET_X) {
729		    x = value;
730		} else if (index == TK_CARET_Y) {
731		    y = value;
732		} else /* if (index == TK_CARET_HEIGHT) -- last case */ {
733		    height = value;
734		}
735	    }
736	    if (height < 0) {
737		height = Tk_Height(window);
738	    }
739	    Tk_SetCaretPos(window, x, y, height);
740	}
741	break;
742    }
743    case TK_SCALING: {
744	Screen *screenPtr;
745	int skip, width, height;
746	double d;
747
748	if (Tcl_IsSafe(interp)) {
749	    Tcl_SetResult(interp,
750		    "scaling not accessible in a safe interpreter",
751		    TCL_STATIC);
752	    return TCL_ERROR;
753	}
754
755	skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
756	if (skip < 0) {
757	    return TCL_ERROR;
758	}
759	screenPtr = Tk_Screen(tkwin);
760	if (objc - skip == 2) {
761	    d = 25.4 / 72;
762	    d *= WidthOfScreen(screenPtr);
763	    d /= WidthMMOfScreen(screenPtr);
764	    Tcl_SetDoubleObj(Tcl_GetObjResult(interp), d);
765	} else if (objc - skip == 3) {
766	    if (Tcl_GetDoubleFromObj(interp, objv[2+skip], &d) != TCL_OK) {
767		return TCL_ERROR;
768	    }
769	    d = (25.4 / 72) / d;
770	    width = (int) (d * WidthOfScreen(screenPtr) + 0.5);
771	    if (width <= 0) {
772		width = 1;
773	    }
774	    height = (int) (d * HeightOfScreen(screenPtr) + 0.5);
775	    if (height <= 0) {
776		height = 1;
777	    }
778	    WidthMMOfScreen(screenPtr) = width;
779	    HeightMMOfScreen(screenPtr) = height;
780	} else {
781	    Tcl_WrongNumArgs(interp, 2, objv,
782		    "?-displayof window? ?factor?");
783	    return TCL_ERROR;
784	}
785	break;
786    }
787    case TK_USE_IM: {
788	TkDisplay *dispPtr;
789	int skip;
790
791	if (Tcl_IsSafe(interp)) {
792	    Tcl_SetResult(interp,
793		    "useinputmethods not accessible in a safe interpreter",
794		    TCL_STATIC);
795	    return TCL_ERROR;
796	}
797
798	skip = TkGetDisplayOf(interp, objc-2, objv+2, &tkwin);
799	if (skip < 0) {
800	    return TCL_ERROR;
801	}
802	dispPtr = ((TkWindow *) tkwin)->dispPtr;
803	if ((objc - skip) == 3) {
804	    /*
805	     * In the case where TK_USE_INPUT_METHODS is not defined, this
806	     * will be ignored and we will always return 0. That will indicate
807	     * to the user that input methods are just not available.
808	     */
809
810	    int boolVal;
811
812	    if (Tcl_GetBooleanFromObj(interp, objv[2+skip],
813		    &boolVal) != TCL_OK) {
814		return TCL_ERROR;
815	    }
816#ifdef TK_USE_INPUT_METHODS
817	    if (boolVal) {
818		dispPtr->flags |= TK_DISPLAY_USE_IM;
819	    } else {
820		dispPtr->flags &= ~TK_DISPLAY_USE_IM;
821	    }
822#endif /* TK_USE_INPUT_METHODS */
823	} else if ((objc - skip) != 2) {
824	    Tcl_WrongNumArgs(interp, 2, objv,
825		    "?-displayof window? ?boolean?");
826	    return TCL_ERROR;
827	}
828	Tcl_SetBooleanObj(Tcl_GetObjResult(interp),
829		(int) (dispPtr->flags & TK_DISPLAY_USE_IM));
830	break;
831    }
832    case TK_WINDOWINGSYSTEM: {
833	const char *windowingsystem;
834
835	if (objc != 2) {
836	    Tcl_WrongNumArgs(interp, 2, objv, NULL);
837	    return TCL_ERROR;
838	}
839#if defined(WIN32)
840	windowingsystem = "win32";
841#elif defined(MAC_OSX_TK)
842	windowingsystem = "aqua";
843#else
844	windowingsystem = "x11";
845#endif
846	Tcl_SetStringObj(Tcl_GetObjResult(interp), windowingsystem, -1);
847	break;
848    }
849    case TK_INACTIVE: {
850	int skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
851
852	if (skip < 0) {
853	    return TCL_ERROR;
854	}
855	if (objc - skip == 2) {
856	    long inactive;
857
858	    inactive = (Tcl_IsSafe(interp) ? -1 :
859		    Tk_GetUserInactiveTime(Tk_Display(tkwin)));
860	    Tcl_SetObjResult(interp, Tcl_NewLongObj(inactive));
861
862	} else if (objc - skip == 3) {
863	    char *string;
864
865	    string = Tcl_GetString(objv[objc-1]);
866	    if (strcmp(string, "reset") != 0) {
867		Tcl_Obj *msg = Tcl_NewStringObj("bad option \"", -1);
868
869		Tcl_AppendStringsToObj(msg, string, "\": must be reset", NULL);
870		Tcl_SetObjResult(interp, msg);
871		return TCL_ERROR;
872	    }
873	    if (Tcl_IsSafe(interp)) {
874		Tcl_SetResult(interp,
875			"resetting the user inactivity timer "
876			"is not allowed in a safe interpreter", TCL_STATIC);
877		return TCL_ERROR;
878	    }
879	    Tk_ResetUserInactiveTime(Tk_Display(tkwin));
880	    Tcl_ResetResult(interp);
881	} else {
882	    Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? ?reset?");
883	    return TCL_ERROR;
884	}
885	break;
886    }
887    }
888    return TCL_OK;
889}
890
891/*
892 *----------------------------------------------------------------------
893 *
894 * Tk_TkwaitObjCmd --
895 *
896 *	This function is invoked to process the "tkwait" Tcl command. See the
897 *	user documentation for details on what it does.
898 *
899 * Results:
900 *	A standard Tcl result.
901 *
902 * Side effects:
903 *	See the user documentation.
904 *
905 *----------------------------------------------------------------------
906 */
907
908	/* ARGSUSED */
909int
910Tk_TkwaitObjCmd(
911    ClientData clientData,	/* Main window associated with interpreter. */
912    Tcl_Interp *interp,		/* Current interpreter. */
913    int objc,			/* Number of arguments. */
914    Tcl_Obj *const objv[])	/* Argument objects. */
915{
916    Tk_Window tkwin = (Tk_Window) clientData;
917    int done, index;
918    static const char *optionStrings[] = {
919	"variable", "visibility", "window", NULL
920    };
921    enum options {
922	TKWAIT_VARIABLE, TKWAIT_VISIBILITY, TKWAIT_WINDOW
923    };
924
925    if (objc != 3) {
926	Tcl_WrongNumArgs(interp, 1, objv, "variable|visibility|window name");
927	return TCL_ERROR;
928    }
929
930    if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
931	    &index) != TCL_OK) {
932	return TCL_ERROR;
933    }
934
935    switch ((enum options) index) {
936    case TKWAIT_VARIABLE:
937	if (Tcl_TraceVar(interp, Tcl_GetString(objv[2]),
938		TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
939		WaitVariableProc, (ClientData) &done) != TCL_OK) {
940	    return TCL_ERROR;
941	}
942	done = 0;
943	while (!done) {
944	    Tcl_DoOneEvent(0);
945	}
946	Tcl_UntraceVar(interp, Tcl_GetString(objv[2]),
947		TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
948		WaitVariableProc, (ClientData) &done);
949	break;
950
951    case TKWAIT_VISIBILITY: {
952	Tk_Window window;
953
954	window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin);
955	if (window == NULL) {
956	    return TCL_ERROR;
957	}
958	Tk_CreateEventHandler(window,
959		VisibilityChangeMask|StructureNotifyMask,
960		WaitVisibilityProc, (ClientData) &done);
961	done = 0;
962	while (!done) {
963	    Tcl_DoOneEvent(0);
964	}
965	if (done != 1) {
966	    /*
967	     * Note that we do not delete the event handler because it was
968	     * deleted automatically when the window was destroyed.
969	     */
970
971	    Tcl_ResetResult(interp);
972	    Tcl_AppendResult(interp, "window \"", Tcl_GetString(objv[2]),
973		    "\" was deleted before its visibility changed", NULL);
974	    return TCL_ERROR;
975	}
976	Tk_DeleteEventHandler(window,
977		VisibilityChangeMask|StructureNotifyMask,
978		WaitVisibilityProc, (ClientData) &done);
979	break;
980    }
981
982    case TKWAIT_WINDOW: {
983	Tk_Window window;
984
985	window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin);
986	if (window == NULL) {
987	    return TCL_ERROR;
988	}
989	Tk_CreateEventHandler(window, StructureNotifyMask,
990		WaitWindowProc, (ClientData) &done);
991	done = 0;
992	while (!done) {
993	    Tcl_DoOneEvent(0);
994	}
995
996	/*
997	 * Note: there's no need to delete the event handler. It was deleted
998	 * automatically when the window was destroyed.
999	 */
1000
1001	break;
1002    }
1003    }
1004
1005    /*
1006     * Clear out the interpreter's result, since it may have been set by event
1007     * handlers.
1008     */
1009
1010    Tcl_ResetResult(interp);
1011    return TCL_OK;
1012}
1013
1014	/* ARGSUSED */
1015static char *
1016WaitVariableProc(
1017    ClientData clientData,	/* Pointer to integer to set to 1. */
1018    Tcl_Interp *interp,		/* Interpreter containing variable. */
1019    const char *name1,		/* Name of variable. */
1020    const char *name2,		/* Second part of variable name. */
1021    int flags)			/* Information about what happened. */
1022{
1023    int *donePtr = (int *) clientData;
1024
1025    *donePtr = 1;
1026    return NULL;
1027}
1028
1029	/*ARGSUSED*/
1030static void
1031WaitVisibilityProc(
1032    ClientData clientData,	/* Pointer to integer to set to 1. */
1033    XEvent *eventPtr)		/* Information about event (not used). */
1034{
1035    int *donePtr = (int *) clientData;
1036
1037    if (eventPtr->type == VisibilityNotify) {
1038	*donePtr = 1;
1039    }
1040    if (eventPtr->type == DestroyNotify) {
1041	*donePtr = 2;
1042    }
1043}
1044
1045static void
1046WaitWindowProc(
1047    ClientData clientData,	/* Pointer to integer to set to 1. */
1048    XEvent *eventPtr)		/* Information about event. */
1049{
1050    int *donePtr = (int *) clientData;
1051
1052    if (eventPtr->type == DestroyNotify) {
1053	*donePtr = 1;
1054    }
1055}
1056
1057/*
1058 *----------------------------------------------------------------------
1059 *
1060 * Tk_UpdateObjCmd --
1061 *
1062 *	This function is invoked to process the "update" Tcl command. See the
1063 *	user documentation for details on what it does.
1064 *
1065 * Results:
1066 *	A standard Tcl result.
1067 *
1068 * Side effects:
1069 *	See the user documentation.
1070 *
1071 *----------------------------------------------------------------------
1072 */
1073
1074	/* ARGSUSED */
1075int
1076Tk_UpdateObjCmd(
1077    ClientData clientData,	/* Main window associated with interpreter. */
1078    Tcl_Interp *interp,		/* Current interpreter. */
1079    int objc,			/* Number of arguments. */
1080    Tcl_Obj *const objv[])	/* Argument objects. */
1081{
1082    static const char *updateOptions[] = {"idletasks", NULL};
1083    int flags, index;
1084    TkDisplay *dispPtr;
1085
1086    if (objc == 1) {
1087	flags = TCL_DONT_WAIT;
1088    } else if (objc == 2) {
1089	if (Tcl_GetIndexFromObj(interp, objv[1], updateOptions, "option", 0,
1090		&index) != TCL_OK) {
1091	    return TCL_ERROR;
1092	}
1093	flags = TCL_IDLE_EVENTS;
1094    } else {
1095	Tcl_WrongNumArgs(interp, 1, objv, "?idletasks?");
1096	return TCL_ERROR;
1097    }
1098
1099    /*
1100     * Handle all pending events, sync all displays, and repeat over and over
1101     * again until all pending events have been handled. Special note: it's
1102     * possible that the entire application could be destroyed by an event
1103     * handler that occurs during the update. Thus, don't use any information
1104     * from tkwin after calling Tcl_DoOneEvent.
1105     */
1106
1107    while (1) {
1108	while (Tcl_DoOneEvent(flags) != 0) {
1109	    /* Empty loop body */
1110	}
1111	for (dispPtr = TkGetDisplayList(); dispPtr != NULL;
1112		dispPtr = dispPtr->nextPtr) {
1113	    XSync(dispPtr->display, False);
1114	}
1115	if (Tcl_DoOneEvent(flags) == 0) {
1116	    break;
1117	}
1118    }
1119
1120    /*
1121     * Must clear the interpreter's result because event handlers could have
1122     * executed commands.
1123     */
1124
1125    Tcl_ResetResult(interp);
1126    return TCL_OK;
1127}
1128
1129/*
1130 *----------------------------------------------------------------------
1131 *
1132 * Tk_WinfoObjCmd --
1133 *
1134 *	This function is invoked to process the "winfo" Tcl command. See the
1135 *	user documentation for details on what it does.
1136 *
1137 * Results:
1138 *	A standard Tcl result.
1139 *
1140 * Side effects:
1141 *	See the user documentation.
1142 *
1143 *----------------------------------------------------------------------
1144 */
1145
1146int
1147Tk_WinfoObjCmd(
1148    ClientData clientData,	/* Main window associated with interpreter. */
1149    Tcl_Interp *interp,		/* Current interpreter. */
1150    int objc,			/* Number of arguments. */
1151    Tcl_Obj *const objv[])	/* Argument objects. */
1152{
1153    int index, x, y, width, height, useX, useY, class, skip;
1154    char *string;
1155    TkWindow *winPtr;
1156    Tk_Window tkwin;
1157    Tcl_Obj *resultPtr;
1158
1159    static const TkStateMap visualMap[] = {
1160	{PseudoColor,	"pseudocolor"},
1161	{GrayScale,	"grayscale"},
1162	{DirectColor,	"directcolor"},
1163	{TrueColor,	"truecolor"},
1164	{StaticColor,	"staticcolor"},
1165	{StaticGray,	"staticgray"},
1166	{-1,		NULL}
1167    };
1168    static const char *optionStrings[] = {
1169	"cells",	"children",	"class",	"colormapfull",
1170	"depth",	"geometry",	"height",	"id",
1171	"ismapped",	"manager",	"name",		"parent",
1172	"pointerx",	"pointery",	"pointerxy",	"reqheight",
1173	"reqwidth",	"rootx",	"rooty",	"screen",
1174	"screencells",	"screendepth",	"screenheight",	"screenwidth",
1175	"screenmmheight","screenmmwidth","screenvisual","server",
1176	"toplevel",	"viewable",	"visual",	"visualid",
1177	"vrootheight",	"vrootwidth",	"vrootx",	"vrooty",
1178	"width",	"x",		"y",
1179
1180	"atom",		"atomname",	"containing",	"interps",
1181	"pathname",
1182
1183	"exists",	"fpixels",	"pixels",	"rgb",
1184	"visualsavailable",
1185
1186	NULL
1187    };
1188    enum options {
1189	WIN_CELLS,	WIN_CHILDREN,	WIN_CLASS,	WIN_COLORMAPFULL,
1190	WIN_DEPTH,	WIN_GEOMETRY,	WIN_HEIGHT,	WIN_ID,
1191	WIN_ISMAPPED,	WIN_MANAGER,	WIN_NAME,	WIN_PARENT,
1192	WIN_POINTERX,	WIN_POINTERY,	WIN_POINTERXY,	WIN_REQHEIGHT,
1193	WIN_REQWIDTH,	WIN_ROOTX,	WIN_ROOTY,	WIN_SCREEN,
1194	WIN_SCREENCELLS,WIN_SCREENDEPTH,WIN_SCREENHEIGHT,WIN_SCREENWIDTH,
1195	WIN_SCREENMMHEIGHT,WIN_SCREENMMWIDTH,WIN_SCREENVISUAL,WIN_SERVER,
1196	WIN_TOPLEVEL,	WIN_VIEWABLE,	WIN_VISUAL,	WIN_VISUALID,
1197	WIN_VROOTHEIGHT,WIN_VROOTWIDTH,	WIN_VROOTX,	WIN_VROOTY,
1198	WIN_WIDTH,	WIN_X,		WIN_Y,
1199
1200	WIN_ATOM,	WIN_ATOMNAME,	WIN_CONTAINING,	WIN_INTERPS,
1201	WIN_PATHNAME,
1202
1203	WIN_EXISTS,	WIN_FPIXELS,	WIN_PIXELS,	WIN_RGB,
1204	WIN_VISUALSAVAILABLE
1205    };
1206
1207    tkwin = (Tk_Window) clientData;
1208
1209    if (objc < 2) {
1210	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
1211	return TCL_ERROR;
1212    }
1213    if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
1214	    &index) != TCL_OK) {
1215	return TCL_ERROR;
1216    }
1217
1218    if (index < WIN_ATOM) {
1219	if (objc != 3) {
1220	    Tcl_WrongNumArgs(interp, 2, objv, "window");
1221	    return TCL_ERROR;
1222	}
1223	string = Tcl_GetString(objv[2]);
1224	tkwin = Tk_NameToWindow(interp, string, tkwin);
1225	if (tkwin == NULL) {
1226	    return TCL_ERROR;
1227	}
1228    }
1229    winPtr = (TkWindow *) tkwin;
1230    resultPtr = Tcl_GetObjResult(interp);
1231
1232    switch ((enum options) index) {
1233    case WIN_CELLS:
1234	Tcl_SetIntObj(resultPtr, Tk_Visual(tkwin)->map_entries);
1235	break;
1236    case WIN_CHILDREN: {
1237	Tcl_Obj *strPtr;
1238
1239	winPtr = winPtr->childList;
1240	for ( ; winPtr != NULL; winPtr = winPtr->nextPtr) {
1241	    if (!(winPtr->flags & TK_ANONYMOUS_WINDOW)) {
1242		strPtr = Tcl_NewStringObj(winPtr->pathName, -1);
1243		Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
1244	    }
1245	}
1246	break;
1247    }
1248    case WIN_CLASS:
1249	Tcl_SetStringObj(resultPtr, Tk_Class(tkwin), -1);
1250	break;
1251    case WIN_COLORMAPFULL:
1252	Tcl_SetBooleanObj(resultPtr,
1253		TkpCmapStressed(tkwin, Tk_Colormap(tkwin)));
1254	break;
1255    case WIN_DEPTH:
1256	Tcl_SetIntObj(resultPtr, Tk_Depth(tkwin));
1257	break;
1258    case WIN_GEOMETRY: {
1259	char buf[16 + TCL_INTEGER_SPACE * 4];
1260
1261	sprintf(buf, "%dx%d+%d+%d", Tk_Width(tkwin), Tk_Height(tkwin),
1262		Tk_X(tkwin), Tk_Y(tkwin));
1263	Tcl_SetStringObj(resultPtr, buf, -1);
1264	break;
1265    }
1266    case WIN_HEIGHT:
1267	Tcl_SetIntObj(resultPtr, Tk_Height(tkwin));
1268	break;
1269    case WIN_ID: {
1270	char buf[TCL_INTEGER_SPACE];
1271
1272	Tk_MakeWindowExist(tkwin);
1273	TkpPrintWindowId(buf, Tk_WindowId(tkwin));
1274
1275	/*
1276	 * interp result may have changed, refetch it
1277	 */
1278
1279	resultPtr = Tcl_GetObjResult(interp);
1280	Tcl_SetStringObj(resultPtr, buf, -1);
1281	break;
1282    }
1283    case WIN_ISMAPPED:
1284	Tcl_SetBooleanObj(resultPtr, (int) Tk_IsMapped(tkwin));
1285	break;
1286    case WIN_MANAGER:
1287	if (winPtr->geomMgrPtr != NULL) {
1288	    Tcl_SetStringObj(resultPtr, winPtr->geomMgrPtr->name, -1);
1289	}
1290	break;
1291    case WIN_NAME:
1292	Tcl_SetStringObj(resultPtr, Tk_Name(tkwin), -1);
1293	break;
1294    case WIN_PARENT:
1295	if (winPtr->parentPtr != NULL) {
1296	    Tcl_SetStringObj(resultPtr, winPtr->parentPtr->pathName, -1);
1297	}
1298	break;
1299    case WIN_POINTERX:
1300	useX = 1;
1301	useY = 0;
1302	goto pointerxy;
1303    case WIN_POINTERY:
1304	useX = 0;
1305	useY = 1;
1306	goto pointerxy;
1307    case WIN_POINTERXY:
1308	useX = 1;
1309	useY = 1;
1310
1311    pointerxy:
1312	winPtr = GetTopHierarchy(tkwin);
1313	if (winPtr == NULL) {
1314	    x = -1;
1315	    y = -1;
1316	} else {
1317	    TkGetPointerCoords((Tk_Window) winPtr, &x, &y);
1318	}
1319	if (useX & useY) {
1320	    char buf[TCL_INTEGER_SPACE * 2];
1321
1322	    sprintf(buf, "%d %d", x, y);
1323	    Tcl_SetStringObj(resultPtr, buf, -1);
1324	} else if (useX) {
1325	    Tcl_SetIntObj(resultPtr, x);
1326	} else {
1327	    Tcl_SetIntObj(resultPtr, y);
1328	}
1329	break;
1330    case WIN_REQHEIGHT:
1331	Tcl_SetIntObj(resultPtr, Tk_ReqHeight(tkwin));
1332	break;
1333    case WIN_REQWIDTH:
1334	Tcl_SetIntObj(resultPtr, Tk_ReqWidth(tkwin));
1335	break;
1336    case WIN_ROOTX:
1337	Tk_GetRootCoords(tkwin, &x, &y);
1338	Tcl_SetIntObj(resultPtr, x);
1339	break;
1340    case WIN_ROOTY:
1341	Tk_GetRootCoords(tkwin, &x, &y);
1342	Tcl_SetIntObj(resultPtr, y);
1343	break;
1344    case WIN_SCREEN: {
1345	char buf[TCL_INTEGER_SPACE];
1346
1347	sprintf(buf, "%d", Tk_ScreenNumber(tkwin));
1348	Tcl_AppendStringsToObj(resultPtr, Tk_DisplayName(tkwin),".",buf, NULL);
1349	break;
1350    }
1351    case WIN_SCREENCELLS:
1352	Tcl_SetIntObj(resultPtr, CellsOfScreen(Tk_Screen(tkwin)));
1353	break;
1354    case WIN_SCREENDEPTH:
1355	Tcl_SetIntObj(resultPtr, DefaultDepthOfScreen(Tk_Screen(tkwin)));
1356	break;
1357    case WIN_SCREENHEIGHT:
1358	Tcl_SetIntObj(resultPtr, HeightOfScreen(Tk_Screen(tkwin)));
1359	break;
1360    case WIN_SCREENWIDTH:
1361	Tcl_SetIntObj(resultPtr, WidthOfScreen(Tk_Screen(tkwin)));
1362	break;
1363    case WIN_SCREENMMHEIGHT:
1364	Tcl_SetIntObj(resultPtr, HeightMMOfScreen(Tk_Screen(tkwin)));
1365	break;
1366    case WIN_SCREENMMWIDTH:
1367	Tcl_SetIntObj(resultPtr, WidthMMOfScreen(Tk_Screen(tkwin)));
1368	break;
1369    case WIN_SCREENVISUAL:
1370	class = DefaultVisualOfScreen(Tk_Screen(tkwin))->class;
1371	goto visual;
1372    case WIN_SERVER:
1373	TkGetServerInfo(interp, tkwin);
1374	break;
1375    case WIN_TOPLEVEL:
1376	winPtr = GetTopHierarchy(tkwin);
1377	if (winPtr != NULL) {
1378	    Tcl_SetStringObj(resultPtr, winPtr->pathName, -1);
1379	}
1380	break;
1381    case WIN_VIEWABLE: {
1382	int viewable = 0;
1383
1384	for ( ; ; winPtr = winPtr->parentPtr) {
1385	    if ((winPtr == NULL) || !(winPtr->flags & TK_MAPPED)) {
1386		break;
1387	    }
1388	    if (winPtr->flags & TK_TOP_HIERARCHY) {
1389		viewable = 1;
1390		break;
1391	    }
1392	}
1393
1394	Tcl_SetBooleanObj(resultPtr, viewable);
1395	break;
1396    }
1397    case WIN_VISUAL:
1398	class = Tk_Visual(tkwin)->class;
1399
1400    visual:
1401	string = TkFindStateString(visualMap, class);
1402	if (string == NULL) {
1403	    string = "unknown";
1404	}
1405	Tcl_SetStringObj(resultPtr, string, -1);
1406	break;
1407    case WIN_VISUALID: {
1408	char buf[TCL_INTEGER_SPACE];
1409
1410	sprintf(buf, "0x%x",
1411		(unsigned int) XVisualIDFromVisual(Tk_Visual(tkwin)));
1412	Tcl_SetStringObj(resultPtr, buf, -1);
1413	break;
1414    }
1415    case WIN_VROOTHEIGHT:
1416	Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
1417	Tcl_SetIntObj(resultPtr, height);
1418	break;
1419    case WIN_VROOTWIDTH:
1420	Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
1421	Tcl_SetIntObj(resultPtr, width);
1422	break;
1423    case WIN_VROOTX:
1424	Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
1425	Tcl_SetIntObj(resultPtr, x);
1426	break;
1427    case WIN_VROOTY:
1428	Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
1429	Tcl_SetIntObj(resultPtr, y);
1430	break;
1431    case WIN_WIDTH:
1432	Tcl_SetIntObj(resultPtr, Tk_Width(tkwin));
1433	break;
1434    case WIN_X:
1435	Tcl_SetIntObj(resultPtr, Tk_X(tkwin));
1436	break;
1437    case WIN_Y:
1438	Tcl_SetIntObj(resultPtr, Tk_Y(tkwin));
1439	break;
1440
1441	/*
1442	 * Uses -displayof.
1443	 */
1444
1445    case WIN_ATOM:
1446	skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
1447	if (skip < 0) {
1448	    return TCL_ERROR;
1449	}
1450	if (objc - skip != 3) {
1451	    Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? name");
1452	    return TCL_ERROR;
1453	}
1454	objv += skip;
1455	string = Tcl_GetString(objv[2]);
1456	Tcl_SetLongObj(resultPtr, (long) Tk_InternAtom(tkwin, string));
1457	break;
1458    case WIN_ATOMNAME: {
1459	const char *name;
1460	long id;
1461
1462	skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
1463	if (skip < 0) {
1464	    return TCL_ERROR;
1465	}
1466	if (objc - skip != 3) {
1467	    Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? id");
1468	    return TCL_ERROR;
1469	}
1470	objv += skip;
1471	if (Tcl_GetLongFromObj(interp, objv[2], &id) != TCL_OK) {
1472	    return TCL_ERROR;
1473	}
1474	name = Tk_GetAtomName(tkwin, (Atom) id);
1475	if (strcmp(name, "?bad atom?") == 0) {
1476	    string = Tcl_GetString(objv[2]);
1477	    Tcl_AppendStringsToObj(resultPtr,
1478		    "no atom exists with id \"", string, "\"", NULL);
1479	    return TCL_ERROR;
1480	}
1481	Tcl_SetStringObj(resultPtr, name, -1);
1482	break;
1483    }
1484    case WIN_CONTAINING:
1485	skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
1486	if (skip < 0) {
1487	    return TCL_ERROR;
1488	}
1489	if (objc - skip != 4) {
1490	    Tcl_WrongNumArgs(interp, 2, objv,
1491		    "?-displayof window? rootX rootY");
1492	    return TCL_ERROR;
1493	}
1494	objv += skip;
1495	string = Tcl_GetString(objv[2]);
1496	if (Tk_GetPixels(interp, tkwin, string, &x) != TCL_OK) {
1497	    return TCL_ERROR;
1498	}
1499	string = Tcl_GetString(objv[3]);
1500	if (Tk_GetPixels(interp, tkwin, string, &y) != TCL_OK) {
1501	    return TCL_ERROR;
1502	}
1503	tkwin = Tk_CoordsToWindow(x, y, tkwin);
1504	if (tkwin != NULL) {
1505	    Tcl_SetStringObj(resultPtr, Tk_PathName(tkwin), -1);
1506	}
1507	break;
1508    case WIN_INTERPS: {
1509	int result;
1510
1511	skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
1512	if (skip < 0) {
1513	    return TCL_ERROR;
1514	}
1515	if (objc - skip != 2) {
1516	    Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?");
1517	    return TCL_ERROR;
1518	}
1519	result = TkGetInterpNames(interp, tkwin);
1520	return result;
1521    }
1522    case WIN_PATHNAME: {
1523	Window id;
1524
1525	skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
1526	if (skip < 0) {
1527	    return TCL_ERROR;
1528	}
1529	if (objc - skip != 3) {
1530	    Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? id");
1531	    return TCL_ERROR;
1532	}
1533	string = Tcl_GetString(objv[2 + skip]);
1534	if (TkpScanWindowId(interp, string, &id) != TCL_OK) {
1535	    return TCL_ERROR;
1536	}
1537	winPtr = (TkWindow *)Tk_IdToWindow(Tk_Display(tkwin), id);
1538	if ((winPtr == NULL) ||
1539		(winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr)) {
1540	    Tcl_AppendStringsToObj(resultPtr, "window id \"", string,
1541		    "\" doesn't exist in this application", NULL);
1542	    return TCL_ERROR;
1543	}
1544
1545	/*
1546	 * If the window is a utility window with no associated path (such as
1547	 * a wrapper window or send communication window), just return an
1548	 * empty string.
1549	 */
1550
1551	tkwin = (Tk_Window) winPtr;
1552	if (Tk_PathName(tkwin) != NULL) {
1553	    Tcl_SetStringObj(resultPtr, Tk_PathName(tkwin), -1);
1554	}
1555	break;
1556    }
1557
1558	/*
1559	 * objv[3] is window.
1560	 */
1561
1562    case WIN_EXISTS: {
1563	int alive;
1564
1565	if (objc != 3) {
1566	    Tcl_WrongNumArgs(interp, 2, objv, "window");
1567	    return TCL_ERROR;
1568	}
1569	string = Tcl_GetString(objv[2]);
1570	winPtr = (TkWindow *) Tk_NameToWindow(interp, string, tkwin);
1571	Tcl_ResetResult(interp);
1572	resultPtr = Tcl_GetObjResult(interp);
1573
1574	alive = 1;
1575	if ((winPtr == NULL) || (winPtr->flags & TK_ALREADY_DEAD)) {
1576	    alive = 0;
1577	}
1578	Tcl_SetBooleanObj(resultPtr, alive);
1579	break;
1580    }
1581    case WIN_FPIXELS: {
1582	double mm, pixels;
1583
1584	if (objc != 4) {
1585	    Tcl_WrongNumArgs(interp, 2, objv, "window number");
1586	    return TCL_ERROR;
1587	}
1588	string = Tcl_GetString(objv[2]);
1589	tkwin = Tk_NameToWindow(interp, string, tkwin);
1590	if (tkwin == NULL) {
1591	    return TCL_ERROR;
1592	}
1593	string = Tcl_GetString(objv[3]);
1594	if (Tk_GetScreenMM(interp, tkwin, string, &mm) != TCL_OK) {
1595	    return TCL_ERROR;
1596	}
1597	pixels = mm * WidthOfScreen(Tk_Screen(tkwin))
1598		/ WidthMMOfScreen(Tk_Screen(tkwin));
1599	Tcl_SetDoubleObj(resultPtr, pixels);
1600	break;
1601    }
1602    case WIN_PIXELS: {
1603	int pixels;
1604
1605	if (objc != 4) {
1606	    Tcl_WrongNumArgs(interp, 2, objv, "window number");
1607	    return TCL_ERROR;
1608	}
1609	string = Tcl_GetString(objv[2]);
1610	tkwin = Tk_NameToWindow(interp, string, tkwin);
1611	if (tkwin == NULL) {
1612	    return TCL_ERROR;
1613	}
1614	string = Tcl_GetString(objv[3]);
1615	if (Tk_GetPixels(interp, tkwin, string, &pixels) != TCL_OK) {
1616	    return TCL_ERROR;
1617	}
1618	Tcl_SetIntObj(resultPtr, pixels);
1619	break;
1620    }
1621    case WIN_RGB: {
1622	XColor *colorPtr;
1623	char buf[TCL_INTEGER_SPACE * 3];
1624
1625	if (objc != 4) {
1626	    Tcl_WrongNumArgs(interp, 2, objv, "window colorName");
1627	    return TCL_ERROR;
1628	}
1629	string = Tcl_GetString(objv[2]);
1630	tkwin = Tk_NameToWindow(interp, string, tkwin);
1631	if (tkwin == NULL) {
1632	    return TCL_ERROR;
1633	}
1634	string = Tcl_GetString(objv[3]);
1635	colorPtr = Tk_GetColor(interp, tkwin, string);
1636	if (colorPtr == NULL) {
1637	    return TCL_ERROR;
1638	}
1639	sprintf(buf, "%d %d %d", colorPtr->red, colorPtr->green,
1640		colorPtr->blue);
1641	Tk_FreeColor(colorPtr);
1642	Tcl_SetStringObj(resultPtr, buf, -1);
1643	break;
1644    }
1645    case WIN_VISUALSAVAILABLE: {
1646	XVisualInfo template, *visInfoPtr;
1647	int count, i;
1648	int includeVisualId;
1649	Tcl_Obj *strPtr;
1650	char buf[16 + TCL_INTEGER_SPACE];
1651	char visualIdString[TCL_INTEGER_SPACE];
1652
1653	if (objc == 3) {
1654	    includeVisualId = 0;
1655	} else if ((objc == 4)
1656		&& (strcmp(Tcl_GetString(objv[3]), "includeids") == 0)) {
1657	    includeVisualId = 1;
1658	} else {
1659	    Tcl_WrongNumArgs(interp, 2, objv, "window ?includeids?");
1660	    return TCL_ERROR;
1661	}
1662
1663	string = Tcl_GetString(objv[2]);
1664	tkwin = Tk_NameToWindow(interp, string, tkwin);
1665	if (tkwin == NULL) {
1666	    return TCL_ERROR;
1667	}
1668
1669	template.screen = Tk_ScreenNumber(tkwin);
1670	visInfoPtr = XGetVisualInfo(Tk_Display(tkwin), VisualScreenMask,
1671		&template, &count);
1672	if (visInfoPtr == NULL) {
1673	    Tcl_SetStringObj(resultPtr,
1674		    "can't find any visuals for screen", -1);
1675	    return TCL_ERROR;
1676	}
1677	for (i = 0; i < count; i++) {
1678	    string = TkFindStateString(visualMap, visInfoPtr[i].class);
1679	    if (string == NULL) {
1680		strcpy(buf, "unknown");
1681	    } else {
1682		sprintf(buf, "%s %d", string, visInfoPtr[i].depth);
1683	    }
1684	    if (includeVisualId) {
1685		sprintf(visualIdString, " 0x%x",
1686			(unsigned int) visInfoPtr[i].visualid);
1687		strcat(buf, visualIdString);
1688	    }
1689	    strPtr = Tcl_NewStringObj(buf, -1);
1690	    Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
1691	}
1692	XFree((char *) visInfoPtr);
1693	break;
1694    }
1695    }
1696    return TCL_OK;
1697}
1698
1699#if 0
1700/*
1701 *----------------------------------------------------------------------
1702 *
1703 * Tk_WmObjCmd --
1704 *
1705 *	This function is invoked to process the "wm" Tcl command. See the user
1706 *	documentation for details on what it does.
1707 *
1708 * Results:
1709 *	A standard Tcl result.
1710 *
1711 * Side effects:
1712 *	See the user documentation.
1713 *
1714 *----------------------------------------------------------------------
1715 */
1716
1717	/* ARGSUSED */
1718int
1719Tk_WmObjCmd(
1720    ClientData clientData,	/* Main window associated with interpreter. */
1721    Tcl_Interp *interp,		/* Current interpreter. */
1722    int objc,			/* Number of arguments. */
1723    Tcl_Obj *const objv[])	/* Argument objects. */
1724{
1725    Tk_Window tkwin;
1726    TkWindow *winPtr;
1727
1728    static const char *optionStrings[] = {
1729	"aspect",	"client",	"command",	"deiconify",
1730	"focusmodel",	"frame",	"geometry",	"grid",
1731	"group",	"iconbitmap",	"iconify",	"iconmask",
1732	"iconname",	"iconposition",	"iconwindow",	"maxsize",
1733	"minsize",	"overrideredirect",	"positionfrom",	"protocol",
1734	"resizable",	"sizefrom",	"state",	"title",
1735	"tracing",	"transient",	"withdraw",	NULL
1736    };
1737    enum options {
1738	TKWM_ASPECT,	TKWM_CLIENT,	TKWM_COMMAND,	TKWM_DEICONIFY,
1739	TKWM_FOCUSMOD,	TKWM_FRAME,	TKWM_GEOMETRY,	TKWM_GRID,
1740	TKWM_GROUP,	TKWM_ICONBMP,	TKWM_ICONIFY,	TKWM_ICONMASK,
1741	TKWM_ICONNAME,	TKWM_ICONPOS,	TKWM_ICONWIN,	TKWM_MAXSIZE,
1742	TKWM_MINSIZE,	TKWM_OVERRIDE,	TKWM_POSFROM,	TKWM_PROTOCOL,
1743	TKWM_RESIZABLE,	TKWM_SIZEFROM,	TKWM_STATE,	TKWM_TITLE,
1744	TKWM_TRACING,	TKWM_TRANSIENT,	TKWM_WITHDRAW
1745    };
1746
1747    tkwin = (Tk_Window) clientData;
1748
1749    if (objc < 2) {
1750	Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg?");
1751	return TCL_ERROR;
1752    }
1753    if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
1754	    &index) != TCL_OK) {
1755	return TCL_ERROR;
1756    }
1757
1758    if (index == TKWM_TRACING) {
1759	int wmTracing;
1760	TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
1761
1762	if ((objc != 2) && (objc != 3)) {
1763	    Tcl_WrongNumArgs(interp, 1, objv, "tracing ?boolean?");
1764	    return TCL_ERROR;
1765	}
1766	if (objc == 2) {
1767	    Tcl_SetObjResult(interp,
1768		    Tcl_NewBooleanObj(dispPtr->flags & TK_DISPLAY_WM_TRACING));
1769	    return TCL_OK;
1770	}
1771	if (Tcl_GetBooleanFromObj(interp, objv[2], &wmTracing) != TCL_OK) {
1772	    return TCL_ERROR;
1773	}
1774	if (wmTracing) {
1775	    dispPtr->flags |= TK_DISPLAY_WM_TRACING;
1776	} else {
1777	    dispPtr->flags &= ~TK_DISPLAY_WM_TRACING;
1778	}
1779	return TCL_OK;
1780    }
1781
1782    if (objc < 3) {
1783	Tcl_WrongNumArgs(interp, 2, objv, "window ?arg?");
1784	return TCL_ERROR;
1785    }
1786
1787    winPtr = (TkWindow *) Tk_NameToWindow(interp,
1788	    Tcl_GetString(objv[2]), tkwin);
1789    if (winPtr == NULL) {
1790	return TCL_ERROR;
1791    }
1792    if (!(winPtr->flags & TK_TOP_LEVEL)) {
1793	Tcl_AppendResult(interp, "window \"", winPtr->pathName,
1794		"\" isn't a top-level window", NULL);
1795	return TCL_ERROR;
1796    }
1797
1798    switch ((enum options) index) {
1799    case TKWM_ASPECT:
1800	TkpWmAspectCmd(interp, tkwin, winPtr, objc, objv);
1801	break;
1802    case TKWM_CLIENT:
1803	TkpWmClientCmd(interp, tkwin, winPtr, objc, objv);
1804	break;
1805    case TKWM_COMMAND:
1806	TkpWmCommandCmd(interp, tkwin, winPtr, objc, objv);
1807	break;
1808    case TKWM_DEICONIFY:
1809	TkpWmDeiconifyCmd(interp, tkwin, winPtr, objc, objv);
1810	break;
1811    case TKWM_FOCUSMOD:
1812	TkpWmFocusmodCmd(interp, tkwin, winPtr, objc, objv);
1813	break;
1814    case TKWM_FRAME:
1815	TkpWmFrameCmd(interp, tkwin, winPtr, objc, objv);
1816	break;
1817    case TKWM_GEOMETRY:
1818	TkpWmGeometryCmd(interp, tkwin, winPtr, objc, objv);
1819	break;
1820    case TKWM_GRID:
1821	TkpWmGridCmd(interp, tkwin, winPtr, objc, objv);
1822	break;
1823    case TKWM_GROUP:
1824	TkpWmGroupCmd(interp, tkwin, winPtr, objc, objv);
1825	break;
1826    case TKWM_ICONBMP:
1827	TkpWmIconbitmapCmd(interp, tkwin, winPtr, objc, objv);
1828	break;
1829    case TKWM_ICONIFY:
1830	TkpWmIconifyCmd(interp, tkwin, winPtr, objc, objv);
1831	break;
1832    case TKWM_ICONMASK:
1833	TkpWmIconmaskCmd(interp, tkwin, winPtr, objc, objv);
1834	break;
1835    case TKWM_ICONNAME:
1836	/*
1837	 * Slight Unix variation.
1838	 */
1839	TkpWmIconnameCmd(interp, tkwin, winPtr, objc, objv);
1840	break;
1841    case TKWM_ICONPOS:
1842	/*
1843	 * nearly same - 1 line more on Unix.
1844	 */
1845	TkpWmIconpositionCmd(interp, tkwin, winPtr, objc, objv);
1846	break;
1847    case TKWM_ICONWIN:
1848	TkpWmIconwindowCmd(interp, tkwin, winPtr, objc, objv);
1849	break;
1850    case TKWM_MAXSIZE:
1851	/*
1852	 * Nearly same, win diffs.
1853	 */
1854	TkpWmMaxsizeCmd(interp, tkwin, winPtr, objc, objv);
1855	break;
1856    case TKWM_MINSIZE:
1857	/*
1858	 * Nearly same, win diffs
1859	 */
1860	TkpWmMinsizeCmd(interp, tkwin, winPtr, objc, objv);
1861	break;
1862    case TKWM_OVERRIDE:
1863	/*
1864	 * Almost same.
1865	 */
1866	TkpWmOverrideCmd(interp, tkwin, winPtr, objc, objv);
1867	break;
1868    case TKWM_POSFROM:
1869	/*
1870	 * Equal across platforms
1871	 */
1872	TkpWmPositionfromCmd(interp, tkwin, winPtr, objc, objv);
1873	break;
1874    case TKWM_PROTOCOL:
1875	/*
1876	 * Equal across platforms
1877	 */
1878	TkpWmProtocolCmd(interp, tkwin, winPtr, objc, objv);
1879	break;
1880    case TKWM_RESIZABLE:
1881	/*
1882	 * Almost same
1883	 */
1884	TkpWmResizableCmd(interp, tkwin, winPtr, objc, objv);
1885	break;
1886    case TKWM_SIZEFROM:
1887	/*
1888	 * Equal across platforms
1889	 */
1890	TkpWmSizefromCmd(interp, tkwin, winPtr, objc, objv);
1891	break;
1892    case TKWM_STATE:
1893	TkpWmStateCmd(interp, tkwin, winPtr, objc, objv);
1894	break;
1895    case TKWM_TITLE:
1896	TkpWmTitleCmd(interp, tkwin, winPtr, objc, objv);
1897	break;
1898    case TKWM_TRANSIENT:
1899	TkpWmTransientCmd(interp, tkwin, winPtr, objc, objv);
1900	break;
1901    case TKWM_WITHDRAW:
1902	TkpWmWithdrawCmd(interp, tkwin, winPtr, objc, objv);
1903	break;
1904    }
1905
1906  updateGeom:
1907    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1908	Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1909	wmPtr->flags |= WM_UPDATE_PENDING;
1910    }
1911    return TCL_OK;
1912}
1913#endif
1914
1915/*
1916 *----------------------------------------------------------------------
1917 *
1918 * TkGetDisplayOf --
1919 *
1920 *	Parses a "-displayof window" option for various commands. If present,
1921 *	the literal "-displayof" should be in objv[0] and the window name in
1922 *	objv[1].
1923 *
1924 * Results:
1925 *	The return value is 0 if the argument strings did not contain the
1926 *	"-displayof" option. The return value is 2 if the argument strings
1927 *	contained both the "-displayof" option and a valid window name.
1928 *	Otherwise, the return value is -1 if the window name was missing or
1929 *	did not specify a valid window.
1930 *
1931 *	If the return value was 2, *tkwinPtr is filled with the token for the
1932 *	window specified on the command line. If the return value was -1, an
1933 *	error message is left in interp's result object.
1934 *
1935 * Side effects:
1936 *	None.
1937 *
1938 *----------------------------------------------------------------------
1939 */
1940
1941int
1942TkGetDisplayOf(
1943    Tcl_Interp *interp,		/* Interpreter for error reporting. */
1944    int objc,			/* Number of arguments. */
1945    Tcl_Obj *const objv[],	/* Argument objects. If it is present,
1946				 * "-displayof" should be in objv[0] and
1947				 * objv[1] the name of a window. */
1948    Tk_Window *tkwinPtr)	/* On input, contains main window of
1949				 * application associated with interp. On
1950				 * output, filled with window specified as
1951				 * option to "-displayof" argument, or
1952				 * unmodified if "-displayof" argument was not
1953				 * present. */
1954{
1955    char *string;
1956    int length;
1957
1958    if (objc < 1) {
1959	return 0;
1960    }
1961    string = Tcl_GetStringFromObj(objv[0], &length);
1962    if ((length >= 2) &&
1963	    (strncmp(string, "-displayof", (unsigned) length) == 0)) {
1964        if (objc < 2) {
1965	    Tcl_SetStringObj(Tcl_GetObjResult(interp),
1966		    "value for \"-displayof\" missing", -1);
1967	    return -1;
1968	}
1969	*tkwinPtr = Tk_NameToWindow(interp, Tcl_GetString(objv[1]), *tkwinPtr);
1970	if (*tkwinPtr == NULL) {
1971	    return -1;
1972	}
1973	return 2;
1974    }
1975    return 0;
1976}
1977
1978/*
1979 *----------------------------------------------------------------------
1980 *
1981 * TkDeadAppCmd --
1982 *
1983 *	If an application has been deleted then all Tk commands will be
1984 *	re-bound to this function.
1985 *
1986 * Results:
1987 *	A standard Tcl error is reported to let the user know that the
1988 *	application is dead.
1989 *
1990 * Side effects:
1991 *	See the user documentation.
1992 *
1993 *----------------------------------------------------------------------
1994 */
1995
1996	/* ARGSUSED */
1997int
1998TkDeadAppCmd(
1999    ClientData clientData,	/* Dummy. */
2000    Tcl_Interp *interp,		/* Current interpreter. */
2001    int argc,			/* Number of arguments. */
2002    const char **argv)		/* Argument strings. */
2003{
2004    Tcl_AppendResult(interp, "can't invoke \"", argv[0],
2005	    "\" command:  application has been destroyed", NULL);
2006    return TCL_ERROR;
2007}
2008
2009/*
2010 *----------------------------------------------------------------------
2011 *
2012 * GetTopHierarchy --
2013 *
2014 *	Retrieves the top-of-hierarchy window which is the nearest ancestor of
2015 *	the specified window.
2016 *
2017 * Results:
2018 *	Returns the top-of-hierarchy window, or NULL if the window has no
2019 *	ancestor which is at the top of a physical window hierarchy.
2020 *
2021 * Side effects:
2022 *	None.
2023 *
2024 *----------------------------------------------------------------------
2025 */
2026
2027static TkWindow *
2028GetTopHierarchy(
2029    Tk_Window tkwin)		/* Window for which the top-of-hierarchy
2030				 * ancestor should be deterined. */
2031{
2032    TkWindow *winPtr = (TkWindow *) tkwin;
2033
2034    while ((winPtr != NULL) && !(winPtr->flags & TK_TOP_HIERARCHY)) {
2035	winPtr = winPtr->parentPtr;
2036    }
2037    return winPtr;
2038}
2039
2040/*
2041 * Local Variables:
2042 * mode: c
2043 * c-basic-offset: 4
2044 * fill-column: 78
2045 * End:
2046 */
2047