1 /*
2  * tkCmds.c --
3  *
4  *	This file contains a collection of Tk-related Tcl commands
5  *	that didn't 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-1996 Sun Microsystems, Inc.
9  *
10  * See the file "license.terms" for information on usage and redistribution
11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12  *
13  * SCCS: @(#) tkCmds.c 1.110 96/04/03 15:54:47
14  */
15 
16 #include "tkInt.h"
17 #include <errno.h>
18 
19 /*
20  * Forward declarations for procedures defined later in this file:
21  */
22 
23 static Tk_Window	GetDisplayOf _ANSI_ARGS_((Tcl_Interp *interp,
24 			    Tk_Window tkwin, char **argv));
25 static TkWindow *	GetToplevel _ANSI_ARGS_((Tk_Window tkwin));
26 static char *		WaitVariableProc _ANSI_ARGS_((ClientData clientData,
27 			    Tcl_Interp *interp, char *name1, char *name2,
28 			    int flags));
29 static void		WaitVisibilityProc _ANSI_ARGS_((ClientData clientData,
30 			    XEvent *eventPtr));
31 static void		WaitWindowProc _ANSI_ARGS_((ClientData clientData,
32 			    XEvent *eventPtr));
33 
34 /*
35  *----------------------------------------------------------------------
36  *
37  * Tk_BellCmd --
38  *
39  *	This procedure is invoked to process the "bell" Tcl command.
40  *	See the user documentation for details on what it does.
41  *
42  * Results:
43  *	A standard Tcl result.
44  *
45  * Side effects:
46  *	See the user documentation.
47  *
48  *----------------------------------------------------------------------
49  */
50 
51 int
Tk_BellCmd(clientData,interp,argc,argv)52 Tk_BellCmd(clientData, interp, argc, argv)
53     ClientData clientData;	/* Main window associated with interpreter. */
54     Tcl_Interp *interp;		/* Current interpreter. */
55     int argc;			/* Number of arguments. */
56     char **argv;		/* Argument strings. */
57 {
58     Tk_Window tkwin = (Tk_Window) clientData;
59     size_t length;
60 
61     if ((argc != 1) && (argc != 3)) {
62 	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
63 		" ?-displayof window?\"", (char *) NULL);
64 	return TCL_ERROR;
65     }
66 
67     if (argc == 3) {
68 	length = strlen(argv[1]);
69 	if ((length < 2) || (strncmp(argv[1], "-displayof", length) != 0)) {
70 	    Tcl_AppendResult(interp, "bad option \"", argv[1],
71 		    "\": must be -displayof", (char *) NULL);
72 	    return TCL_ERROR;
73 	}
74 	tkwin = Tk_NameToWindow(interp, argv[2], tkwin);
75 	if (tkwin == NULL) {
76 	    return TCL_ERROR;
77 	}
78     }
79     XBell(Tk_Display(tkwin), 0);
80     XForceScreenSaver(Tk_Display(tkwin), ScreenSaverReset);
81     XFlush(Tk_Display(tkwin));
82     return TCL_OK;
83 }
84 
85 /*
86  *----------------------------------------------------------------------
87  *
88  * Tk_BindCmd --
89  *
90  *	This procedure is invoked to process the "bind" Tcl command.
91  *	See the user documentation for details on what it does.
92  *
93  * Results:
94  *	A standard Tcl result.
95  *
96  * Side effects:
97  *	See the user documentation.
98  *
99  *----------------------------------------------------------------------
100  */
101 
102 int
Tk_BindCmd(clientData,interp,argc,argv)103 Tk_BindCmd(clientData, interp, argc, argv)
104     ClientData clientData;	/* Main window associated with interpreter. */
105     Tcl_Interp *interp;		/* Current interpreter. */
106     int argc;			/* Number of arguments. */
107     char **argv;		/* Argument strings. */
108 {
109     Tk_Window tkwin = (Tk_Window) clientData;
110     TkWindow *winPtr;
111     ClientData object;
112 
113     if ((argc < 2) || (argc > 4)) {
114 	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
115 		" window ?pattern? ?command?\"", (char *) NULL);
116 	return TCL_ERROR;
117     }
118     if (argv[1][0] == '.') {
119 	winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin);
120 	if (winPtr == NULL) {
121 	    return TCL_ERROR;
122 	}
123 	object = (ClientData) winPtr->pathName;
124     } else {
125 	winPtr = (TkWindow *) clientData;
126 	object = (ClientData) Tk_GetUid(argv[1]);
127     }
128 
129     if (argc == 4) {
130 	int append = 0;
131 	unsigned long mask;
132 
133 	if (argv[3][0] == 0) {
134 	    return Tk_DeleteBinding(interp, winPtr->mainPtr->bindingTable,
135 		    object, argv[2]);
136 	}
137 	if (argv[3][0] == '+') {
138 	    argv[3]++;
139 	    append = 1;
140 	}
141 	mask = Tk_CreateBinding(interp, winPtr->mainPtr->bindingTable,
142 		object, argv[2], argv[3], append);
143 	if (mask == 0) {
144 	    return TCL_ERROR;
145 	}
146     } else if (argc == 3) {
147 	char *command;
148 
149 	command = Tk_GetBinding(interp, winPtr->mainPtr->bindingTable,
150 		object, argv[2]);
151 	if (command == NULL) {
152 	    Tcl_ResetResult(interp);
153 	    return TCL_OK;
154 	}
155 	interp->result = command;
156     } else {
157 	Tk_GetAllBindings(interp, winPtr->mainPtr->bindingTable, object);
158     }
159     return TCL_OK;
160 }
161 
162 /*
163  *----------------------------------------------------------------------
164  *
165  * TkBindEventProc --
166  *
167  *	This procedure is invoked by Tk_HandleEvent for each event;  it
168  *	causes any appropriate bindings for that event to be invoked.
169  *
170  * Results:
171  *	None.
172  *
173  * Side effects:
174  *	Depends on what bindings have been established with the "bind"
175  *	command.
176  *
177  *----------------------------------------------------------------------
178  */
179 
180 void
TkBindEventProc(winPtr,eventPtr)181 TkBindEventProc(winPtr, eventPtr)
182     TkWindow *winPtr;			/* Pointer to info about window. */
183     XEvent *eventPtr;			/* Information about event. */
184 {
185 #define MAX_OBJS 20
186     ClientData objects[MAX_OBJS], *objPtr;
187     static Tk_Uid allUid = NULL;
188     TkWindow *topLevPtr;
189     int i, count;
190     char *p;
191     Tcl_HashEntry *hPtr;
192 
193     if ((winPtr->mainPtr == NULL) || (winPtr->mainPtr->bindingTable == NULL)) {
194 	return;
195     }
196 
197     objPtr = objects;
198     if (winPtr->numTags != 0) {
199 	/*
200 	 * Make a copy of the tags for the window, replacing window names
201 	 * with pointers to the pathName from the appropriate window.
202 	 */
203 
204 	if (winPtr->numTags > MAX_OBJS) {
205 	    objPtr = (ClientData *) ckalloc((unsigned)
206 		    (winPtr->numTags * sizeof(ClientData)));
207 	}
208 	for (i = 0; i < winPtr->numTags; i++) {
209 	    p = (char *) winPtr->tagPtr[i];
210 	    if (*p == '.') {
211 		hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->nameTable, p);
212 		if (hPtr != NULL) {
213 		    p = ((TkWindow *) Tcl_GetHashValue(hPtr))->pathName;
214 		} else {
215 		    p = NULL;
216 		}
217 	    }
218 	    objPtr[i] = (ClientData) p;
219 	}
220 	count = winPtr->numTags;
221     } else {
222 	objPtr[0] = (ClientData) winPtr->pathName;
223 	objPtr[1] = (ClientData) winPtr->classUid;
224 	for (topLevPtr = winPtr;
225 		(topLevPtr != NULL) && !(topLevPtr->flags & TK_TOP_LEVEL);
226 		topLevPtr = topLevPtr->parentPtr) {
227 	    /* Empty loop body. */
228 	}
229 	if ((winPtr != topLevPtr) && (topLevPtr != NULL)) {
230 	    count = 4;
231 	    objPtr[2] = (ClientData) topLevPtr->pathName;
232 	} else {
233 	    count = 3;
234 	}
235 	if (allUid == NULL) {
236 	    allUid = Tk_GetUid("all");
237 	}
238 	objPtr[count-1] = (ClientData) allUid;
239     }
240     Tk_BindEvent(winPtr->mainPtr->bindingTable, eventPtr, (Tk_Window) winPtr,
241 	    count, objPtr);
242     if (objPtr != objects) {
243 	ckfree((char *) objPtr);
244     }
245 }
246 
247 /*
248  *----------------------------------------------------------------------
249  *
250  * Tk_BindtagsCmd --
251  *
252  *	This procedure is invoked to process the "bindtags" Tcl command.
253  *	See the user documentation for details on what it does.
254  *
255  * Results:
256  *	A standard Tcl result.
257  *
258  * Side effects:
259  *	See the user documentation.
260  *
261  *----------------------------------------------------------------------
262  */
263 
264 int
Tk_BindtagsCmd(clientData,interp,argc,argv)265 Tk_BindtagsCmd(clientData, interp, argc, argv)
266     ClientData clientData;	/* Main window associated with interpreter. */
267     Tcl_Interp *interp;		/* Current interpreter. */
268     int argc;			/* Number of arguments. */
269     char **argv;		/* Argument strings. */
270 {
271     Tk_Window tkwin = (Tk_Window) clientData;
272     TkWindow *winPtr, *winPtr2;
273     int i, tagArgc;
274     char *p, **tagArgv;
275 
276     if ((argc < 2) || (argc > 3)) {
277 	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
278 		" window ?tags?\"", (char *) NULL);
279 	return TCL_ERROR;
280     }
281     winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin);
282     if (winPtr == NULL) {
283 	return TCL_ERROR;
284     }
285     if (argc == 2) {
286 	if (winPtr->numTags == 0) {
287 	    Tcl_AppendElement(interp, winPtr->pathName);
288 	    Tcl_AppendElement(interp, winPtr->classUid);
289 	    for (winPtr2 = winPtr;
290 		    (winPtr2 != NULL) && !(winPtr2->flags & TK_TOP_LEVEL);
291 		    winPtr2 = winPtr2->parentPtr) {
292 		/* Empty loop body. */
293 	    }
294 	    if ((winPtr != winPtr2) && (winPtr2 != NULL)) {
295 		Tcl_AppendElement(interp, winPtr2->pathName);
296 	    }
297 	    Tcl_AppendElement(interp, "all");
298 	} else {
299 	    for (i = 0; i < winPtr->numTags; i++) {
300 		Tcl_AppendElement(interp, (char *) winPtr->tagPtr[i]);
301 	    }
302 	}
303 	return TCL_OK;
304     }
305     if (winPtr->tagPtr != NULL) {
306 	TkFreeBindingTags(winPtr);
307     }
308     if (argv[2][0] == 0) {
309 	return TCL_OK;
310     }
311     if (Tcl_SplitList(interp, argv[2], &tagArgc, &tagArgv) != TCL_OK) {
312 	return TCL_ERROR;
313     }
314     winPtr->numTags = tagArgc;
315     winPtr->tagPtr = (ClientData *) ckalloc((unsigned)
316 	    (tagArgc * sizeof(ClientData)));
317     for (i = 0; i < tagArgc; i++) {
318 	p = tagArgv[i];
319 	if (p[0] == '.') {
320 	    char *copy;
321 
322 	    /*
323 	     * Handle names starting with "." specially: store a malloc'ed
324 	     * string, rather than a Uid;  at event time we'll look up the
325 	     * name in the window table and use the corresponding window,
326 	     * if there is one.
327 	     */
328 
329 	    copy = (char *) ckalloc((unsigned) (strlen(p) + 1));
330 	    strcpy(copy, p);
331 	    winPtr->tagPtr[i] = (ClientData) copy;
332 	} else {
333 	    winPtr->tagPtr[i] = (ClientData) Tk_GetUid(p);
334 	}
335     }
336     ckfree((char *) tagArgv);
337     return TCL_OK;
338 }
339 
340 /*
341  *----------------------------------------------------------------------
342  *
343  * TkFreeBindingTags --
344  *
345  *	This procedure is called to free all of the binding tags
346  *	associated with a window;  typically it is only invoked where
347  *	there are window-specific tags.
348  *
349  * Results:
350  *	None.
351  *
352  * Side effects:
353  *	Any binding tags for winPtr are freed.
354  *
355  *----------------------------------------------------------------------
356  */
357 
358 void
TkFreeBindingTags(winPtr)359 TkFreeBindingTags(winPtr)
360     TkWindow *winPtr;		/* Window whose tags are to be released. */
361 {
362     int i;
363     char *p;
364 
365     for (i = 0; i < winPtr->numTags; i++) {
366 	p = (char *) (winPtr->tagPtr[i]);
367 	if (*p == '.') {
368 	    /*
369 	     * Names starting with "." are malloced rather than Uids, so
370 	     * they have to be freed.
371 	     */
372 
373 	    ckfree(p);
374 	}
375     }
376     ckfree((char *) winPtr->tagPtr);
377     winPtr->numTags = 0;
378     winPtr->tagPtr = NULL;
379 }
380 
381 /*
382  *----------------------------------------------------------------------
383  *
384  * Tk_DestroyCmd --
385  *
386  *	This procedure is invoked to process the "destroy" Tcl command.
387  *	See the user documentation for details on what it does.
388  *
389  * Results:
390  *	A standard Tcl result.
391  *
392  * Side effects:
393  *	See the user documentation.
394  *
395  *----------------------------------------------------------------------
396  */
397 
398 int
Tk_DestroyCmd(clientData,interp,argc,argv)399 Tk_DestroyCmd(clientData, interp, argc, argv)
400     ClientData clientData;		/* Main window associated with
401 				 * interpreter. */
402     Tcl_Interp *interp;		/* Current interpreter. */
403     int argc;			/* Number of arguments. */
404     char **argv;		/* Argument strings. */
405 {
406     Tk_Window window;
407     Tk_Window tkwin = (Tk_Window) clientData;
408     int i;
409 
410     for (i = 1; i < argc; i++) {
411 	window = Tk_NameToWindow(interp, argv[i], tkwin);
412 	if (window == NULL) {
413 	    return TCL_ERROR;
414 	}
415 	Tk_DestroyWindow(window);
416     }
417     return TCL_OK;
418 }
419 
420 /*
421  *----------------------------------------------------------------------
422  *
423  * Tk_LowerCmd --
424  *
425  *	This procedure is invoked to process the "lower" Tcl command.
426  *	See the user documentation for details on what it does.
427  *
428  * Results:
429  *	A standard Tcl result.
430  *
431  * Side effects:
432  *	See the user documentation.
433  *
434  *----------------------------------------------------------------------
435  */
436 
437 	/* ARGSUSED */
438 int
Tk_LowerCmd(clientData,interp,argc,argv)439 Tk_LowerCmd(clientData, interp, argc, argv)
440     ClientData clientData;	/* Main window associated with
441 				 * interpreter. */
442     Tcl_Interp *interp;		/* Current interpreter. */
443     int argc;			/* Number of arguments. */
444     char **argv;		/* Argument strings. */
445 {
446     Tk_Window main = (Tk_Window) clientData;
447     Tk_Window tkwin, other;
448 
449     if ((argc != 2) && (argc != 3)) {
450 	Tcl_AppendResult(interp, "wrong # args: should be \"",
451 		argv[0], " window ?belowThis?\"", (char *) NULL);
452 	return TCL_ERROR;
453     }
454 
455     tkwin = Tk_NameToWindow(interp, argv[1], main);
456     if (tkwin == NULL) {
457 	return TCL_ERROR;
458     }
459     if (argc == 2) {
460 	other = NULL;
461     } else {
462 	other = Tk_NameToWindow(interp, argv[2], main);
463 	if (other == NULL) {
464 	    return TCL_ERROR;
465 	}
466     }
467     if (Tk_RestackWindow(tkwin, Below, other) != TCL_OK) {
468 	Tcl_AppendResult(interp, "can't lower \"", argv[1], "\" below \"",
469 		argv[2], "\"", (char *) NULL);
470 	return TCL_ERROR;
471     }
472     return TCL_OK;
473 }
474 
475 /*
476  *----------------------------------------------------------------------
477  *
478  * Tk_RaiseCmd --
479  *
480  *	This procedure is invoked to process the "raise" Tcl command.
481  *	See the user documentation for details on what it does.
482  *
483  * Results:
484  *	A standard Tcl result.
485  *
486  * Side effects:
487  *	See the user documentation.
488  *
489  *----------------------------------------------------------------------
490  */
491 
492 	/* ARGSUSED */
493 int
Tk_RaiseCmd(clientData,interp,argc,argv)494 Tk_RaiseCmd(clientData, interp, argc, argv)
495     ClientData clientData;	/* Main window associated with
496 				 * interpreter. */
497     Tcl_Interp *interp;		/* Current interpreter. */
498     int argc;			/* Number of arguments. */
499     char **argv;		/* Argument strings. */
500 {
501     Tk_Window main = (Tk_Window) clientData;
502     Tk_Window tkwin, other;
503 
504     if ((argc != 2) && (argc != 3)) {
505 	Tcl_AppendResult(interp, "wrong # args: should be \"",
506 		argv[0], " window ?aboveThis?\"", (char *) NULL);
507 	return TCL_ERROR;
508     }
509 
510     tkwin = Tk_NameToWindow(interp, argv[1], main);
511     if (tkwin == NULL) {
512 	return TCL_ERROR;
513     }
514     if (argc == 2) {
515 	other = NULL;
516     } else {
517 	other = Tk_NameToWindow(interp, argv[2], main);
518 	if (other == NULL) {
519 	    return TCL_ERROR;
520 	}
521     }
522     if (Tk_RestackWindow(tkwin, Above, other) != TCL_OK) {
523 	Tcl_AppendResult(interp, "can't raise \"", argv[1], "\" above \"",
524 		argv[2], "\"", (char *) NULL);
525 	return TCL_ERROR;
526     }
527     return TCL_OK;
528 }
529 
530 /*
531  *----------------------------------------------------------------------
532  *
533  * Tk_TkCmd --
534  *
535  *	This procedure is invoked to process the "tk" Tcl command.
536  *	See the user documentation for details on what it does.
537  *
538  * Results:
539  *	A standard Tcl result.
540  *
541  * Side effects:
542  *	See the user documentation.
543  *
544  *----------------------------------------------------------------------
545  */
546 
547 	/* ARGSUSED */
548 int
Tk_TkCmd(clientData,interp,argc,argv)549 Tk_TkCmd(clientData, interp, argc, argv)
550     ClientData clientData;	/* Main window associated with
551 				 * interpreter. */
552     Tcl_Interp *interp;		/* Current interpreter. */
553     int argc;			/* Number of arguments. */
554     char **argv;		/* Argument strings. */
555 {
556     char c;
557     size_t length;
558     Tk_Window tkwin = (Tk_Window) clientData;
559     TkWindow *winPtr;
560 
561     if (argc < 2) {
562 	Tcl_AppendResult(interp, "wrong # args: should be \"",
563 		argv[0], " option ?arg?\"", (char *) NULL);
564 	return TCL_ERROR;
565     }
566     c = argv[1][0];
567     length = strlen(argv[1]);
568     if ((c == 'a') && (strncmp(argv[1], "appname", length) == 0)) {
569 	winPtr = ((TkWindow *) tkwin)->mainPtr->winPtr;
570 	if (argc > 3) {
571 	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
572 		    " appname ?newName?\"", (char *) NULL);
573 	    return TCL_ERROR;
574 	}
575 	if (argc == 3) {
576 	    winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, argv[2]));
577 	}
578 	interp->result = winPtr->nameUid;
579     } else {
580 	Tcl_AppendResult(interp, "bad option \"", argv[1],
581 		"\": must be appname", (char *) NULL);
582 	return TCL_ERROR;
583     }
584     return TCL_OK;
585 }
586 
587 /*
588  *----------------------------------------------------------------------
589  *
590  * Tk_TkwaitCmd --
591  *
592  *	This procedure is invoked to process the "tkwait" Tcl command.
593  *	See the user documentation for details on what it does.
594  *
595  * Results:
596  *	A standard Tcl result.
597  *
598  * Side effects:
599  *	See the user documentation.
600  *
601  *----------------------------------------------------------------------
602  */
603 
604 	/* ARGSUSED */
605 int
Tk_TkwaitCmd(clientData,interp,argc,argv)606 Tk_TkwaitCmd(clientData, interp, argc, argv)
607     ClientData clientData;	/* Main window associated with
608 				 * interpreter. */
609     Tcl_Interp *interp;		/* Current interpreter. */
610     int argc;			/* Number of arguments. */
611     char **argv;		/* Argument strings. */
612 {
613     Tk_Window tkwin = (Tk_Window) clientData;
614     int c, done;
615     size_t length;
616 
617     if (argc != 3) {
618 	Tcl_AppendResult(interp, "wrong # args: should be \"",
619 		argv[0], " variable|visibility|window name\"", (char *) NULL);
620 	return TCL_ERROR;
621     }
622     c = argv[1][0];
623     length = strlen(argv[1]);
624     if ((c == 'v') && (strncmp(argv[1], "variable", length) == 0)
625 	    && (length >= 2)) {
626 	if (Tcl_TraceVar(interp, argv[2],
627 		TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
628 		WaitVariableProc, (ClientData) &done) != TCL_OK) {
629 	    return TCL_ERROR;
630 	}
631 	done = 0;
632 	while (!done) {
633 	    Tcl_DoOneEvent(0);
634 	}
635 	Tcl_UntraceVar(interp, argv[2],
636 		TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
637 		WaitVariableProc, (ClientData) &done);
638     } else if ((c == 'v') && (strncmp(argv[1], "visibility", length) == 0)
639 	    && (length >= 2)) {
640 	Tk_Window window;
641 
642 	window = Tk_NameToWindow(interp, argv[2], tkwin);
643 	if (window == NULL) {
644 	    return TCL_ERROR;
645 	}
646 	Tk_CreateEventHandler(window, VisibilityChangeMask|StructureNotifyMask,
647 	    WaitVisibilityProc, (ClientData) &done);
648 	done = 0;
649 	while (!done) {
650 	    Tcl_DoOneEvent(0);
651 	}
652 	if (done != 1) {
653 	    /*
654 	     * Note that we do not delete the event handler because it
655 	     * was deleted automatically when the window was destroyed.
656 	     */
657 
658 	    Tcl_ResetResult(interp);
659 	    Tcl_AppendResult(interp, "window \"", argv[2],
660 		    "\" was deleted before its visibility changed",
661 		    (char *) NULL);
662 	    return TCL_ERROR;
663 	}
664 	Tk_DeleteEventHandler(window, VisibilityChangeMask|StructureNotifyMask,
665 	    WaitVisibilityProc, (ClientData) &done);
666     } else if ((c == 'w') && (strncmp(argv[1], "window", length) == 0)) {
667 	Tk_Window window;
668 
669 	window = Tk_NameToWindow(interp, argv[2], tkwin);
670 	if (window == NULL) {
671 	    return TCL_ERROR;
672 	}
673 	Tk_CreateEventHandler(window, StructureNotifyMask,
674 	    WaitWindowProc, (ClientData) &done);
675 	done = 0;
676 	while (!done) {
677 	    Tcl_DoOneEvent(0);
678 	}
679 	/*
680 	 * Note:  there's no need to delete the event handler.  It was
681 	 * deleted automatically when the window was destroyed.
682 	 */
683     } else {
684 	Tcl_AppendResult(interp, "bad option \"", argv[1],
685 		"\": must be variable, visibility, or window", (char *) NULL);
686 	return TCL_ERROR;
687     }
688 
689     /*
690      * Clear out the interpreter's result, since it may have been set
691      * by event handlers.
692      */
693 
694     Tcl_ResetResult(interp);
695     return TCL_OK;
696 }
697 
698 	/* ARGSUSED */
699 static char *
WaitVariableProc(clientData,interp,name1,name2,flags)700 WaitVariableProc(clientData, interp, name1, name2, flags)
701     ClientData clientData;	/* Pointer to integer to set to 1. */
702     Tcl_Interp *interp;		/* Interpreter containing variable. */
703     char *name1;		/* Name of variable. */
704     char *name2;		/* Second part of variable name. */
705     int flags;			/* Information about what happened. */
706 {
707     int *donePtr = (int *) clientData;
708 
709     *donePtr = 1;
710     return (char *) NULL;
711 }
712 
713 	/*ARGSUSED*/
714 static void
WaitVisibilityProc(clientData,eventPtr)715 WaitVisibilityProc(clientData, eventPtr)
716     ClientData clientData;	/* Pointer to integer to set to 1. */
717     XEvent *eventPtr;		/* Information about event (not used). */
718 {
719     int *donePtr = (int *) clientData;
720 
721     if (eventPtr->type == VisibilityNotify) {
722 	*donePtr = 1;
723     }
724     if (eventPtr->type == DestroyNotify) {
725 	*donePtr = 2;
726     }
727 }
728 
729 static void
WaitWindowProc(clientData,eventPtr)730 WaitWindowProc(clientData, eventPtr)
731     ClientData clientData;	/* Pointer to integer to set to 1. */
732     XEvent *eventPtr;		/* Information about event. */
733 {
734     int *donePtr = (int *) clientData;
735 
736     if (eventPtr->type == DestroyNotify) {
737 	*donePtr = 1;
738     }
739 }
740 
741 /*
742  *----------------------------------------------------------------------
743  *
744  * Tk_UpdateCmd --
745  *
746  *	This procedure is invoked to process the "update" Tcl command.
747  *	See the user documentation for details on what it does.
748  *
749  * Results:
750  *	A standard Tcl result.
751  *
752  * Side effects:
753  *	See the user documentation.
754  *
755  *----------------------------------------------------------------------
756  */
757 
758 	/* ARGSUSED */
759 int
Tk_UpdateCmd(clientData,interp,argc,argv)760 Tk_UpdateCmd(clientData, interp, argc, argv)
761     ClientData clientData;	/* Main window associated with
762 				 * interpreter. */
763     Tcl_Interp *interp;		/* Current interpreter. */
764     int argc;			/* Number of arguments. */
765     char **argv;		/* Argument strings. */
766 {
767     Tk_Window tkwin = (Tk_Window) clientData;
768     int flags;
769     Display *display;
770 
771     if (argc == 1) {
772 	flags = TCL_DONT_WAIT;
773     } else if (argc == 2) {
774 	if (strncmp(argv[1], "idletasks", strlen(argv[1])) != 0) {
775 	    Tcl_AppendResult(interp, "bad option \"", argv[1],
776 		    "\": must be idletasks", (char *) NULL);
777 	    return TCL_ERROR;
778 	}
779 	flags = TCL_IDLE_EVENTS;
780     } else {
781 	Tcl_AppendResult(interp, "wrong # args: should be \"",
782 		argv[0], " ?idletasks?\"", (char *) NULL);
783 	return TCL_ERROR;
784     }
785 
786     /*
787      * Handle all pending events, sync the display, and repeat over
788      * and over again until all pending events have been handled.
789      * Special note:  it's possible that the entire application could
790      * be destroyed by an event handler that occurs during the update.
791      * Thus, don't use any information from tkwin after calling
792      * Tcl_DoOneEvent.
793      */
794 
795     display = Tk_Display(tkwin);
796     while (1) {
797 	while (Tcl_DoOneEvent(flags) != 0) {
798 	    /* Empty loop body */
799 	}
800 	XSync(display, False);
801 	if (Tcl_DoOneEvent(flags) == 0) {
802 	    break;
803 	}
804     }
805 
806     /*
807      * Must clear the interpreter's result because event handlers could
808      * have executed commands.
809      */
810 
811     Tcl_ResetResult(interp);
812     return TCL_OK;
813 }
814 
815 /*
816  *----------------------------------------------------------------------
817  *
818  * Tk_WinfoCmd --
819  *
820  *	This procedure is invoked to process the "winfo" Tcl command.
821  *	See the user documentation for details on what it does.
822  *
823  * Results:
824  *	A standard Tcl result.
825  *
826  * Side effects:
827  *	See the user documentation.
828  *
829  *----------------------------------------------------------------------
830  */
831 
832 int
Tk_WinfoCmd(clientData,interp,argc,argv)833 Tk_WinfoCmd(clientData, interp, argc, argv)
834     ClientData clientData;	/* Main window associated with
835 				 * interpreter. */
836     Tcl_Interp *interp;		/* Current interpreter. */
837     int argc;			/* Number of arguments. */
838     char **argv;		/* Argument strings. */
839 {
840     Tk_Window tkwin = (Tk_Window) clientData;
841     size_t length;
842     char c, *argName;
843     Tk_Window window;
844     register TkWindow *winPtr;
845 
846 #define SETUP(name) \
847     if (argc != 3) {\
848 	argName = name; \
849 	goto wrongArgs; \
850     } \
851     window = Tk_NameToWindow(interp, argv[2], tkwin); \
852     if (window == NULL) { \
853 	return TCL_ERROR; \
854     }
855 
856     if (argc < 2) {
857 	Tcl_AppendResult(interp, "wrong # args: should be \"",
858 		argv[0], " option ?arg?\"", (char *) NULL);
859 	return TCL_ERROR;
860     }
861     c = argv[1][0];
862     length = strlen(argv[1]);
863     if ((c == 'a') && (strcmp(argv[1], "atom") == 0)) {
864 	char *atomName;
865 
866 	if (argc == 3) {
867 	    atomName = argv[2];
868 	} else if (argc == 5) {
869 	    atomName = argv[4];
870 	    tkwin = GetDisplayOf(interp, tkwin, argv+2);
871 	    if (tkwin == NULL) {
872 		return TCL_ERROR;
873 	    }
874 	} else {
875 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
876 		    argv[0], " atom ?-displayof window? name\"",
877 		    (char *) NULL);
878 	    return TCL_ERROR;
879 	}
880 	sprintf(interp->result, "%ld", Tk_InternAtom(tkwin, atomName));
881     } else if ((c == 'a') && (strncmp(argv[1], "atomname", length) == 0)
882 	    && (length >= 5)) {
883 	Atom atom;
884 	char *name, *id;
885 
886 	if (argc == 3) {
887 	    id = argv[2];
888 	} else if (argc == 5) {
889 	    id = argv[4];
890 	    tkwin = GetDisplayOf(interp, tkwin, argv+2);
891 	    if (tkwin == NULL) {
892 		return TCL_ERROR;
893 	    }
894 	} else {
895 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
896 		    argv[0], " atomname ?-displayof window? id\"",
897 		    (char *) NULL);
898 	    return TCL_ERROR;
899 	}
900 	if (Tcl_GetInt(interp, id, (int *) &atom) != TCL_OK) {
901 	    return TCL_ERROR;
902 	}
903 	name = Tk_GetAtomName(tkwin, atom);
904 	if (strcmp(name, "?bad atom?") == 0) {
905 	    Tcl_AppendResult(interp, "no atom exists with id \"",
906 		    argv[2], "\"", (char *) NULL);
907 	    return TCL_ERROR;
908 	}
909 	interp->result = name;
910     } else if ((c == 'c') && (strncmp(argv[1], "cells", length) == 0)
911 	    && (length >= 2)) {
912 	SETUP("cells");
913 	sprintf(interp->result, "%d", Tk_Visual(window)->map_entries);
914     } else if ((c == 'c') && (strncmp(argv[1], "children", length) == 0)
915 	    && (length >= 2)) {
916 	SETUP("children");
917 	for (winPtr = ((TkWindow *) window)->childList; winPtr != NULL;
918 		winPtr = winPtr->nextPtr) {
919 	    Tcl_AppendElement(interp, winPtr->pathName);
920 	}
921     } else if ((c == 'c') && (strncmp(argv[1], "class", length) == 0)
922 	    && (length >= 2)) {
923 	SETUP("class");
924 	interp->result = Tk_Class(window);
925     } else if ((c == 'c') && (strncmp(argv[1], "colormapfull", length) == 0)
926 	    && (length >= 3)) {
927 	SETUP("colormapfull");
928 	interp->result = (TkCmapStressed(window, Tk_Colormap(window)))
929 		? "1" : "0";
930     } else if ((c == 'c') && (strncmp(argv[1], "containing", length) == 0)
931 	    && (length >= 3)) {
932 	int rootX, rootY, index;
933 
934 	if (argc == 4) {
935 	    index = 2;
936 	} else if (argc == 6) {
937 	    index = 4;
938 	    tkwin = GetDisplayOf(interp, tkwin, argv+2);
939 	    if (tkwin == NULL) {
940 		return TCL_ERROR;
941 	    }
942 	} else {
943 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
944 		    argv[0], " containing ?-displayof window? rootX rootY\"",
945 		    (char *) NULL);
946 	    return TCL_ERROR;
947 	}
948 	if ((Tk_GetPixels(interp, tkwin, argv[index], &rootX) != TCL_OK)
949 		|| (Tk_GetPixels(interp, tkwin, argv[index+1], &rootY)
950 		!= TCL_OK)) {
951 	    return TCL_ERROR;
952 	}
953 	window = Tk_CoordsToWindow(rootX, rootY, tkwin);
954 	if (window != NULL) {
955 	    interp->result = Tk_PathName(window);
956 	}
957     } else if ((c == 'd') && (strncmp(argv[1], "depth", length) == 0)) {
958 	SETUP("depth");
959 	sprintf(interp->result, "%d", Tk_Depth(window));
960     } else if ((c == 'e') && (strncmp(argv[1], "exists", length) == 0)) {
961 	if (argc != 3) {
962 	    argName = "exists";
963 	    goto wrongArgs;
964 	}
965 	window = Tk_NameToWindow(interp, argv[2], tkwin);
966 	if ((window == NULL)
967 		|| (((TkWindow *) window)->flags & TK_ALREADY_DEAD)) {
968 	    interp->result = "0";
969 	} else {
970 	    interp->result = "1";
971 	}
972     } else if ((c == 'f') && (strncmp(argv[1], "fpixels", length) == 0)
973 	    && (length >= 2)) {
974 	double mm, pixels;
975 
976 	if (argc != 4) {
977 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
978 		    argv[0], " fpixels window number\"", (char *) NULL);
979 	    return TCL_ERROR;
980 	}
981 	window = Tk_NameToWindow(interp, argv[2], tkwin);
982 	if (window == NULL) {
983 	    return TCL_ERROR;
984 	}
985 	if (Tk_GetScreenMM(interp, window, argv[3], &mm) != TCL_OK) {
986 	    return TCL_ERROR;
987 	}
988 	pixels = mm * WidthOfScreen(Tk_Screen(window))
989 		/ WidthMMOfScreen(Tk_Screen(window));
990 	Tcl_PrintDouble(interp, pixels, interp->result);
991     } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)) {
992 	SETUP("geometry");
993 	sprintf(interp->result, "%dx%d+%d+%d", Tk_Width(window),
994 		Tk_Height(window), Tk_X(window), Tk_Y(window));
995     } else if ((c == 'h') && (strncmp(argv[1], "height", length) == 0)) {
996 	SETUP("height");
997 	sprintf(interp->result, "%d", Tk_Height(window));
998     } else if ((c == 'i') && (strcmp(argv[1], "id") == 0)) {
999 	SETUP("id");
1000 	Tk_MakeWindowExist(window);
1001 	sprintf(interp->result, "0x%x", (unsigned int) Tk_WindowId(window));
1002     } else if ((c == 'i') && (strncmp(argv[1], "interps", length) == 0)
1003 	    && (length >= 2)) {
1004 	if (argc == 4) {
1005 	    tkwin = GetDisplayOf(interp, tkwin, argv+2);
1006 	    if (tkwin == NULL) {
1007 		return TCL_ERROR;
1008 	    }
1009 	} else if (argc != 2) {
1010 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
1011 		    argv[0], " interps ?-displayof window?\"",
1012 		    (char *) NULL);
1013 	    return TCL_ERROR;
1014 	}
1015 	return TkGetInterpNames(interp, tkwin);
1016     } else if ((c == 'i') && (strncmp(argv[1], "ismapped", length) == 0)
1017 	    && (length >= 2)) {
1018 	SETUP("ismapped");
1019 	interp->result = Tk_IsMapped(window) ? "1" : "0";
1020     } else if ((c == 'm') && (strncmp(argv[1], "manager", length) == 0)) {
1021 	SETUP("manager");
1022 	winPtr = (TkWindow *) window;
1023 	if (winPtr->geomMgrPtr != NULL) {
1024 	    interp->result = winPtr->geomMgrPtr->name;
1025 	}
1026     } else if ((c == 'n') && (strncmp(argv[1], "name", length) == 0)) {
1027 	SETUP("name");
1028 	interp->result = Tk_Name(window);
1029     } else if ((c == 'p') && (strncmp(argv[1], "parent", length) == 0)) {
1030 	SETUP("parent");
1031 	winPtr = (TkWindow *) window;
1032 	if (winPtr->parentPtr != NULL) {
1033 	    interp->result = winPtr->parentPtr->pathName;
1034 	}
1035     } else if ((c == 'p') && (strncmp(argv[1], "pathname", length) == 0)
1036 	    && (length >= 2)) {
1037 	int index, id;
1038 
1039 	if (argc == 3) {
1040 	    index = 2;
1041 	} else if (argc == 5) {
1042 	    index = 4;
1043 	    tkwin = GetDisplayOf(interp, tkwin, argv+2);
1044 	    if (tkwin == NULL) {
1045 		return TCL_ERROR;
1046 	    }
1047 	} else {
1048 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
1049 		    argv[0], " pathname ?-displayof window? id\"",
1050 		    (char *) NULL);
1051 	    return TCL_ERROR;
1052 	}
1053 	if (Tcl_GetInt(interp, argv[index], &id) != TCL_OK) {
1054 	    return TCL_ERROR;
1055 	}
1056 	window = Tk_IdToWindow(Tk_Display(tkwin), (Window) id);
1057 	if ((window == NULL) || (((TkWindow *) window)->mainPtr
1058 		!= ((TkWindow *) tkwin)->mainPtr)) {
1059 	    Tcl_AppendResult(interp, "window id \"", argv[index],
1060 		    "\" doesn't exist in this application", (char *) NULL);
1061 	    return TCL_ERROR;
1062 	}
1063 	interp->result = Tk_PathName(window);
1064     } else if ((c == 'p') && (strncmp(argv[1], "pixels", length) == 0)
1065 	    && (length >= 2)) {
1066 	int pixels;
1067 
1068 	if (argc != 4) {
1069 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
1070 		    argv[0], " pixels window number\"", (char *) NULL);
1071 	    return TCL_ERROR;
1072 	}
1073 	window = Tk_NameToWindow(interp, argv[2], tkwin);
1074 	if (window == NULL) {
1075 	    return TCL_ERROR;
1076 	}
1077 	if (Tk_GetPixels(interp, window, argv[3], &pixels) != TCL_OK) {
1078 	    return TCL_ERROR;
1079 	}
1080 	sprintf(interp->result, "%d", pixels);
1081     } else if ((c == 'p') && (strcmp(argv[1], "pointerx") == 0)) {
1082 	int x, y;
1083 
1084 	SETUP("pointerx");
1085 	winPtr = GetToplevel(window);
1086 	if (winPtr == NULL) {
1087 	    x = -1;
1088 	} else {
1089 	    TkGetPointerCoords((Tk_Window)winPtr, &x, &y);
1090 	}
1091 	sprintf(interp->result, "%d", x);
1092     } else if ((c == 'p') && (strcmp(argv[1], "pointerxy") == 0)) {
1093 	int x, y;
1094 
1095 	SETUP("pointerxy");
1096 	winPtr = GetToplevel(window);
1097 	if (winPtr == NULL) {
1098 	    x = -1;
1099 	} else {
1100 	    TkGetPointerCoords((Tk_Window)winPtr, &x, &y);
1101 	}
1102 	sprintf(interp->result, "%d %d", x, y);
1103     } else if ((c == 'p') && (strcmp(argv[1], "pointery") == 0)) {
1104 	int x, y;
1105 
1106 	SETUP("pointery");
1107 	winPtr = GetToplevel(window);
1108 	if (winPtr == NULL) {
1109 	    y = -1;
1110 	} else {
1111 	    TkGetPointerCoords((Tk_Window)winPtr, &x, &y);
1112 	}
1113 	sprintf(interp->result, "%d", y);
1114     } else if ((c == 'r') && (strncmp(argv[1], "reqheight", length) == 0)
1115 	    && (length >= 4)) {
1116 	SETUP("reqheight");
1117 	sprintf(interp->result, "%d", Tk_ReqHeight(window));
1118     } else if ((c == 'r') && (strncmp(argv[1], "reqwidth", length) == 0)
1119 	    && (length >= 4)) {
1120 	SETUP("reqwidth");
1121 	sprintf(interp->result, "%d", Tk_ReqWidth(window));
1122     } else if ((c == 'r') && (strncmp(argv[1], "rgb", length) == 0)
1123 	    && (length >= 2)) {
1124 	XColor *colorPtr;
1125 
1126 	if (argc != 4) {
1127 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
1128 		    argv[0], " rgb window colorName\"", (char *) NULL);
1129 	    return TCL_ERROR;
1130 	}
1131 	window = Tk_NameToWindow(interp, argv[2], tkwin);
1132 	if (window == NULL) {
1133 	    return TCL_ERROR;
1134 	}
1135 	colorPtr = Tk_GetColor(interp, window, argv[3]);
1136 	if (colorPtr == NULL) {
1137 	    return TCL_ERROR;
1138 	}
1139 	sprintf(interp->result, "%d %d %d", colorPtr->red, colorPtr->green,
1140 		colorPtr->blue);
1141 	Tk_FreeColor(colorPtr);
1142     } else if ((c == 'r') && (strcmp(argv[1], "rootx") == 0)) {
1143 	int x, y;
1144 
1145 	SETUP("rootx");
1146 	Tk_GetRootCoords(window, &x, &y);
1147 	sprintf(interp->result, "%d", x);
1148     } else if ((c == 'r') && (strcmp(argv[1], "rooty") == 0)) {
1149 	int x, y;
1150 
1151 	SETUP("rooty");
1152 	Tk_GetRootCoords(window, &x, &y);
1153 	sprintf(interp->result, "%d", y);
1154     } else if ((c == 's') && (strcmp(argv[1], "screen") == 0)) {
1155 	char string[20];
1156 
1157 	SETUP("screen");
1158 	sprintf(string, "%d", Tk_ScreenNumber(window));
1159 	Tcl_AppendResult(interp, Tk_DisplayName(window), ".", string,
1160 		(char *) NULL);
1161     } else if ((c == 's') && (strncmp(argv[1], "screencells", length) == 0)
1162 	    && (length >= 7)) {
1163 	SETUP("screencells");
1164 	sprintf(interp->result, "%d", CellsOfScreen(Tk_Screen(window)));
1165     } else if ((c == 's') && (strncmp(argv[1], "screendepth", length) == 0)
1166 	    && (length >= 7)) {
1167 	SETUP("screendepth");
1168 	sprintf(interp->result, "%d", DefaultDepthOfScreen(Tk_Screen(window)));
1169     } else if ((c == 's') && (strncmp(argv[1], "screenheight", length) == 0)
1170 	    && (length >= 7)) {
1171 	SETUP("screenheight");
1172 	sprintf(interp->result, "%d",  HeightOfScreen(Tk_Screen(window)));
1173     } else if ((c == 's') && (strncmp(argv[1], "screenmmheight", length) == 0)
1174 	    && (length >= 9)) {
1175 	SETUP("screenmmheight");
1176 	sprintf(interp->result, "%d",  HeightMMOfScreen(Tk_Screen(window)));
1177     } else if ((c == 's') && (strncmp(argv[1], "screenmmwidth", length) == 0)
1178 	    && (length >= 9)) {
1179 	SETUP("screenmmwidth");
1180 	sprintf(interp->result, "%d",  WidthMMOfScreen(Tk_Screen(window)));
1181     } else if ((c == 's') && (strncmp(argv[1], "screenvisual", length) == 0)
1182 	    && (length >= 7)) {
1183 	SETUP("screenvisual");
1184 	switch (DefaultVisualOfScreen(Tk_Screen(window))->class) {
1185 	    case PseudoColor:	interp->result = "pseudocolor"; break;
1186 	    case GrayScale:	interp->result = "grayscale"; break;
1187 	    case DirectColor:	interp->result = "directcolor"; break;
1188 	    case TrueColor:	interp->result = "truecolor"; break;
1189 	    case StaticColor:	interp->result = "staticcolor"; break;
1190 	    case StaticGray:	interp->result = "staticgray"; break;
1191 	    default:		interp->result = "unknown"; break;
1192 	}
1193     } else if ((c == 's') && (strncmp(argv[1], "screenwidth", length) == 0)
1194 	    && (length >= 7)) {
1195 	SETUP("screenwidth");
1196 	sprintf(interp->result, "%d",  WidthOfScreen(Tk_Screen(window)));
1197     } else if ((c == 's') && (strncmp(argv[1], "server", length) == 0)
1198 	    && (length >= 2)) {
1199 	SETUP("server");
1200 	TkGetServerInfo(interp, window);
1201     } else if ((c == 't') && (strncmp(argv[1], "toplevel", length) == 0)) {
1202 	SETUP("toplevel");
1203 	winPtr = GetToplevel(window);
1204 	if (winPtr != NULL) {
1205 	    interp->result = winPtr->pathName;
1206 	}
1207     } else if ((c == 'v') && (strncmp(argv[1], "viewable", length) == 0)
1208 	    && (length >= 3)) {
1209 	SETUP("viewable");
1210 	for (winPtr = (TkWindow *) window; ; winPtr = winPtr->parentPtr) {
1211 	    if ((winPtr == NULL) || !(winPtr->flags & TK_MAPPED)) {
1212 		interp->result = "0";
1213 		break;
1214 	    }
1215 	    if (winPtr->flags & TK_TOP_LEVEL) {
1216 		interp->result = "1";
1217 		break;
1218 	    }
1219 	}
1220     } else if ((c == 'v') && (strcmp(argv[1], "visual") == 0)) {
1221 	SETUP("visual");
1222 	switch (Tk_Visual(window)->class) {
1223 	    case PseudoColor:	interp->result = "pseudocolor"; break;
1224 	    case GrayScale:	interp->result = "grayscale"; break;
1225 	    case DirectColor:	interp->result = "directcolor"; break;
1226 	    case TrueColor:	interp->result = "truecolor"; break;
1227 	    case StaticColor:	interp->result = "staticcolor"; break;
1228 	    case StaticGray:	interp->result = "staticgray"; break;
1229 	    default:		interp->result = "unknown"; break;
1230 	}
1231     } else if ((c == 'v') && (strncmp(argv[1], "visualid", length) == 0)
1232 	       && (length >= 7)) {
1233 	SETUP("visualid");
1234 	sprintf(interp->result, "0x%x", (unsigned int)
1235 		XVisualIDFromVisual(Tk_Visual(window)));
1236     } else if ((c == 'v') && (strncmp(argv[1], "visualsavailable", length) == 0)
1237 	    && (length >= 7)) {
1238 	XVisualInfo template, *visInfoPtr;
1239 	int count, i;
1240 	char string[70], visualIdString[16], *fmt;
1241 	int includeVisualId;
1242 
1243 	if (argc == 3) {
1244 	    includeVisualId = 0;
1245 	} else if ((argc == 4)
1246 		&& (strncmp(argv[3], "includeids", strlen(argv[3])) == 0)) {
1247 	    includeVisualId = 1;
1248 	} else {
1249 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
1250 		    argv[0], " visualsavailable window ?includeids?\"",
1251 		    (char *) NULL);
1252 	    return TCL_ERROR;
1253 	}
1254 
1255 	window = Tk_NameToWindow(interp, argv[2], tkwin);
1256 	if (window == NULL) {
1257 	  return TCL_ERROR;
1258 	}
1259 
1260 	template.screen = Tk_ScreenNumber(window);
1261 	visInfoPtr = XGetVisualInfo(Tk_Display(window), VisualScreenMask,
1262 		&template, &count);
1263 	if (visInfoPtr == NULL) {
1264 	    interp->result = "can't find any visuals for screen";
1265 	    return TCL_ERROR;
1266 	}
1267 	for (i = 0; i < count; i++) {
1268 	    switch (visInfoPtr[i].class) {
1269 		case PseudoColor:	fmt = "pseudocolor %d"; break;
1270 		case GrayScale:		fmt = "grayscale %d"; break;
1271 		case DirectColor:	fmt = "directcolor %d"; break;
1272 		case TrueColor:		fmt = "truecolor %d"; break;
1273 		case StaticColor:	fmt = "staticcolor %d"; break;
1274 		case StaticGray:	fmt = "staticgray %d"; break;
1275 		default:		fmt = "unknown"; break;
1276 	    }
1277 	    sprintf(string, fmt, visInfoPtr[i].depth);
1278 	    if (includeVisualId) {
1279 		sprintf(visualIdString, " 0x%x",
1280 			(unsigned int) visInfoPtr[i].visualid);
1281 		strcat(string, visualIdString);
1282 	    }
1283 	    Tcl_AppendElement(interp, string);
1284 	}
1285 	XFree((char *) visInfoPtr);
1286     } else if ((c == 'v') && (strncmp(argv[1], "vrootheight", length) == 0)
1287 	    && (length >= 6)) {
1288 	int x, y;
1289 	int width, height;
1290 
1291 	SETUP("vrootheight");
1292 	Tk_GetVRootGeometry(window, &x, &y, &width, &height);
1293 	sprintf(interp->result, "%d", height);
1294     } else if ((c == 'v') && (strncmp(argv[1], "vrootwidth", length) == 0)
1295 	    && (length >= 6)) {
1296 	int x, y;
1297 	int width, height;
1298 
1299 	SETUP("vrootwidth");
1300 	Tk_GetVRootGeometry(window, &x, &y, &width, &height);
1301 	sprintf(interp->result, "%d", width);
1302     } else if ((c == 'v') && (strcmp(argv[1], "vrootx") == 0)) {
1303 	int x, y;
1304 	int width, height;
1305 
1306 	SETUP("vrootx");
1307 	Tk_GetVRootGeometry(window, &x, &y, &width, &height);
1308 	sprintf(interp->result, "%d", x);
1309     } else if ((c == 'v') && (strcmp(argv[1], "vrooty") == 0)) {
1310 	int x, y;
1311 	int width, height;
1312 
1313 	SETUP("vrooty");
1314 	Tk_GetVRootGeometry(window, &x, &y, &width, &height);
1315 	sprintf(interp->result, "%d", y);
1316     } else if ((c == 'w') && (strncmp(argv[1], "width", length) == 0)) {
1317 	SETUP("width");
1318 	sprintf(interp->result, "%d", Tk_Width(window));
1319     } else if ((c == 'x') && (argv[1][1] == '\0')) {
1320 	SETUP("x");
1321 	sprintf(interp->result, "%d", Tk_X(window));
1322     } else if ((c == 'y') && (argv[1][1] == '\0')) {
1323 	SETUP("y");
1324 	sprintf(interp->result, "%d", Tk_Y(window));
1325     } else {
1326 	Tcl_AppendResult(interp, "bad option \"", argv[1],
1327 		"\": must be atom, atomname, cells, children, ",
1328 		"class, colormapfull, containing, depth, exists, fpixels, ",
1329 		"geometry, height, ",
1330 		"id, interps, ismapped, manager, name, parent, pathname, ",
1331 		"pixels, pointerx, pointerxy, pointery, reqheight, ",
1332 		"reqwidth, rgb, ",
1333 		"rootx, rooty, ",
1334 		"screen, screencells, screendepth, screenheight, ",
1335 		"screenmmheight, screenmmwidth, screenvisual, ",
1336 		"screenwidth, server, ",
1337 		"toplevel, viewable, visual, visualid, visualsavailable, ",
1338 		"vrootheight, vrootwidth, vrootx, vrooty, ",
1339 		"width, x, or y", (char *) NULL);
1340 	return TCL_ERROR;
1341     }
1342     return TCL_OK;
1343 
1344     wrongArgs:
1345     Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1346 	    argv[0], " ", argName, " window\"", (char *) NULL);
1347     return TCL_ERROR;
1348 }
1349 
1350 /*
1351  *----------------------------------------------------------------------
1352  *
1353  * GetDisplayOf --
1354  *
1355  *	Parses a "-displayof" option for the "winfo" command.
1356  *
1357  * Results:
1358  *	The return value is a token for the window specified in
1359  *	argv[1].  If argv[0] and argv[1] couldn't be parsed, NULL
1360  *	is returned and an error is left in interp->result.
1361  *
1362  * Side effects:
1363  *	None.
1364  *
1365  *----------------------------------------------------------------------
1366  */
1367 
1368 static Tk_Window
GetDisplayOf(interp,tkwin,argv)1369 GetDisplayOf(interp, tkwin, argv)
1370     Tcl_Interp *interp;		/* Interpreter for error reporting. */
1371     Tk_Window tkwin;		/* Window to use for looking up window
1372 				 * given in argv[1]. */
1373     char **argv;		/* Array of two strings.   First must be
1374 				 * "-displayof" or an abbreviation, second
1375 				 * must be window name. */
1376 {
1377     size_t length;
1378 
1379     length = strlen(argv[0]);
1380     if ((length < 2) || (strncmp(argv[0], "-displayof", length) != 0)) {
1381 	Tcl_AppendResult(interp, "bad argument \"", argv[0],
1382 		"\": must be -displayof", (char *) NULL);
1383 	return (Tk_Window) NULL;
1384     }
1385     return Tk_NameToWindow(interp, argv[1], tkwin);
1386 }
1387 
1388 /*
1389  *----------------------------------------------------------------------
1390  *
1391  * TkDeadAppCmd --
1392  *
1393  *	If an application has been deleted then all Tk commands will be
1394  *	re-bound to this procedure.
1395  *
1396  * Results:
1397  *	A standard Tcl error is reported to let the user know that
1398  *	the application is dead.
1399  *
1400  * Side effects:
1401  *	See the user documentation.
1402  *
1403  *----------------------------------------------------------------------
1404  */
1405 
1406 	/* ARGSUSED */
1407 int
TkDeadAppCmd(clientData,interp,argc,argv)1408 TkDeadAppCmd(clientData, interp, argc, argv)
1409     ClientData clientData;	/* Dummy. */
1410     Tcl_Interp *interp;		/* Current interpreter. */
1411     int argc;			/* Number of arguments. */
1412     char **argv;		/* Argument strings. */
1413 {
1414     Tcl_AppendResult(interp, "can't invoke \"", argv[0],
1415 	    "\" command:  application has been destroyed", (char *) NULL);
1416     return TCL_ERROR;
1417 }
1418 
1419 /*
1420  *----------------------------------------------------------------------
1421  *
1422  * GetToplevel --
1423  *
1424  *	Retrieves the toplevel window which is the nearest ancestor of
1425  *	of the specified window.
1426  *
1427  * Results:
1428  *	Returns the toplevel window or NULL if the window has no
1429  *	ancestor which is a toplevel.
1430  *
1431  * Side effects:
1432  *	None.
1433  *
1434  *----------------------------------------------------------------------
1435  */
1436 
1437 static TkWindow *
GetToplevel(tkwin)1438 GetToplevel(tkwin)
1439     Tk_Window tkwin;		/* Window for which the toplevel should be
1440 				 * deterined. */
1441 {
1442      TkWindow *winPtr = (TkWindow *) tkwin;
1443 
1444      while (!(winPtr->flags & TK_TOP_LEVEL)) {
1445 	 winPtr = winPtr->parentPtr;
1446 	 if (winPtr == NULL) {
1447 	     return NULL;
1448 	 }
1449      }
1450      return winPtr;
1451 }
1452