5 * This module implements a container widget for the BLT toolkit.
7 * Copyright 1998 Lucent Technologies, Inc.
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that the copyright notice and warranty
13 * disclaimer appear in supporting documentation, and that the names
14 * of Lucent Technologies or any of their entities not be used in
15 * advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission.
18 * Lucent Technologies disclaims all warranties with regard to this
19 * software, including all implied warranties of merchantability and
20 * fitness. In no event shall Lucent Technologies be liable for any
21 * special, indirect or consequential damages or any damages
22 * whatsoever resulting from loss of use, data or profits, whether in
23 * an action of contract, negligence or other tortuous action, arising
24 * out of or in connection with the use or performance of this
27 * Container widget created by George A. Howlett
35 #include <X11/Xproto.h>
36 #include <X11/Xutil.h>
41 #define SEARCH_TRIES 100 /* Maximum number of attempts to check for
42 * a given window before failing. */
43 #define SEARCH_INTERVAL 20 /* Number milliseconds to wait after each
44 * attempt to find a window. */
46 #define SEARCH_TKWIN (1<<0) /* Search via Tk window pathname. */
47 #define SEARCH_XID (1<<1) /* Search via an XID 0x0000000. */
48 #define SEARCH_CMD (1<<2) /* Search via a command-line arguments. */
49 #define SEARCH_NAME (1<<3) /* Search via the application name. */
50 #define SEARCH_ALL (SEARCH_TKWIN | SEARCH_XID | SEARCH_CMD | SEARCH_NAME)
52 #define CONTAINER_REDRAW (1<<1)
53 #define CONTAINER_MAPPED (1<<2)
54 #define CONTAINER_FOCUS (1<<4)
55 #define CONTAINER_INIT (1<<5)
56 #define CONTAINER_MOVE (1<<7)
58 #define DEF_CONTAINER_BG_MONO STD_NORMAL_BG_MONO
59 #define DEF_CONTAINER_BACKGROUND STD_NORMAL_BACKGROUND
60 #define DEF_CONTAINER_BORDERWIDTH STD_BORDERWIDTH
61 #define DEF_CONTAINER_COMMAND (char *)NULL
62 #define DEF_CONTAINER_CURSOR (char *)NULL
63 #define DEF_CONTAINER_HEIGHT "0"
64 #define DEF_CONTAINER_HIGHLIGHT_BACKGROUND STD_NORMAL_BACKGROUND
65 #define DEF_CONTAINER_HIGHLIGHT_BG_MONO STD_NORMAL_BG_MONO
66 #define DEF_CONTAINER_HIGHLIGHT_COLOR RGB_BLACK
67 #define DEF_CONTAINER_HIGHLIGHT_WIDTH "2"
68 #define DEF_CONTAINER_RELIEF "sunken"
69 #define DEF_CONTAINER_TAKE_FOCUS "0"
70 #define DEF_CONTAINER_TIMEOUT "20"
71 #define DEF_CONTAINER_WIDTH "0"
72 #define DEF_CONTAINER_WINDOW (char *)NULL
74 #if (TK_MAJOR_VERSION == 4)
75 #define TK_REPARENTED 0x2000
78 typedef struct SearchInfoStruct SearchInfo;
79 typedef void (SearchProc) _ANSI_ARGS_((Display *display, Window window,
80 SearchInfo *searchPtr));
82 struct SearchInfoStruct {
84 char *pattern; /* Search pattern. */
86 Window window; /* XID of last window that matches criteria. */
87 int nMatches; /* Number of windows that match the pattern. */
88 int saveNames; /* Indicates to save the names of the
89 * window XIDs that match the search
91 Tcl_DString dString; /* Will contain the strings of the
92 * window XIDs matching the search
97 Tk_Window tkwin; /* Window that embodies the widget.
98 * NULL means that the window has been
99 * destroyed but the data structures
100 * haven't yet been cleaned up.*/
102 Display *display; /* Display containing widget; needed,
103 * among other things, to release
104 * resources after tkwin has already
107 Tcl_Interp *interp; /* Interpreter associated with widget. */
109 Tcl_Command cmdToken; /* Token for widget's command. */
111 unsigned int flags; /* For bit-field definitions, see above. */
113 int inset; /* Total width of borders; focus
114 * highlight and 3-D border. Indicates
115 * the offset from outside edges to
116 * leave room for borders. */
118 Tk_Cursor cursor; /* X Cursor */
120 Tk_3DBorder border; /* 3D border surrounding the adopted
122 int borderWidth; /* Width of 3D border. */
123 int relief; /* 3D border relief. */
125 Tk_Window tkToplevel; /* Toplevel (wrapper) window of
126 * container. It's used to track the
127 * location of the container. If it
128 * moves we need to notify the
129 * embedded application. */
131 * Focus highlight ring
133 int highlightWidth; /* Width in pixels of highlight to
134 * draw around widget when it has the
135 * focus. <= 0 means don't draw a
137 XColor *highlightBgColor; /* Color for drawing traversal
138 * highlight area when highlight is
140 XColor *highlightColor; /* Color for drawing traversal highlight. */
142 GC highlightGC; /* GC for focus highlight. */
144 char *takeFocus; /* Says whether to select this widget during
145 * tab traveral operations. This value isn't
146 * used in C code, but for the widget's Tcl
149 int reqWidth, reqHeight; /* Requested dimensions of the container
152 Window adopted; /* X window Id or Win32 handle of adopted
153 * window contained by the widget. If None,
154 * no window has been reparented. */
155 Tk_Window tkAdopted; /* Non-NULL if this is a Tk window that's
157 int adoptedX, adoptedY; /* Current position of the adopted window. */
158 int adoptedWidth; /* Current width of the adopted window. */
159 int adoptedHeight; /* Current height of the adopted window. */
162 int origWidth, origHeight; /* Dimensions of the window when it
163 * was adopted. When the window is
164 * released it's returned to it's
165 * original dimensions. */
171 static Tk_OptionParseProc StringToXID;
172 static Tk_OptionPrintProc XIDToString;
174 static Tk_CustomOption XIDOption =
176 StringToXID, XIDToString, (ClientData)(SEARCH_TKWIN | SEARCH_XID),
180 static Tk_CustomOption XIDNameOption =
182 StringToXID, XIDToString, (ClientData)SEARCH_NAME,
185 static Tk_CustomOption XIDCmdOption =
187 StringToXID, XIDToString, (ClientData)SEARCH_CMD,
191 extern Tk_CustomOption bltDistanceOption;
192 extern Tk_CustomOption bltPositiveCountOption;
194 static Tk_ConfigSpec configSpecs[] =
196 {TK_CONFIG_BORDER, "-background", "background", "Background",
197 DEF_CONTAINER_BG_MONO, Tk_Offset(Container, border),
198 TK_CONFIG_MONO_ONLY},
199 {TK_CONFIG_BORDER, "-background", "background", "Background",
200 DEF_CONTAINER_BACKGROUND, Tk_Offset(Container, border),
201 TK_CONFIG_COLOR_ONLY},
202 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0},
203 {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0},
204 {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth",
205 DEF_CONTAINER_BORDERWIDTH, Tk_Offset(Container, borderWidth),
206 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
208 {TK_CONFIG_CUSTOM, "-command", "command", "Command",
209 DEF_CONTAINER_WINDOW, Tk_Offset(Container, adopted),
210 TK_CONFIG_DONT_SET_DEFAULT, &XIDCmdOption},
212 {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
213 DEF_CONTAINER_CURSOR, Tk_Offset(Container, cursor), TK_CONFIG_NULL_OK},
214 {TK_CONFIG_CUSTOM, "-height", "height", "Height",
215 DEF_CONTAINER_HEIGHT, Tk_Offset(Container, reqHeight),
216 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
217 {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
218 "HighlightBackground", DEF_CONTAINER_HIGHLIGHT_BACKGROUND,
219 Tk_Offset(Container, highlightBgColor), TK_CONFIG_COLOR_ONLY},
220 {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
221 "HighlightBackground", DEF_CONTAINER_HIGHLIGHT_BG_MONO,
222 Tk_Offset(Container, highlightBgColor), TK_CONFIG_MONO_ONLY},
223 {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
224 DEF_CONTAINER_HIGHLIGHT_COLOR,
225 Tk_Offset(Container, highlightColor), 0},
226 {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
227 "HighlightThickness",
228 DEF_CONTAINER_HIGHLIGHT_WIDTH, Tk_Offset(Container, highlightWidth),
229 TK_CONFIG_DONT_SET_DEFAULT},
231 {TK_CONFIG_CUSTOM, "-name", "name", "Name",
232 DEF_CONTAINER_WINDOW, Tk_Offset(Container, adopted),
233 TK_CONFIG_DONT_SET_DEFAULT, &XIDNameOption},
235 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
236 DEF_CONTAINER_RELIEF, Tk_Offset(Container, relief), 0},
237 {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
238 DEF_CONTAINER_TAKE_FOCUS, Tk_Offset(Container, takeFocus),
240 {TK_CONFIG_CUSTOM, "-timeout", "timeout", "Timeout",
241 DEF_CONTAINER_TIMEOUT, Tk_Offset(Container, timeout),
242 TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveCountOption},
243 {TK_CONFIG_CUSTOM, "-width", "width", "Width",
244 DEF_CONTAINER_WIDTH, Tk_Offset(Container, reqWidth),
245 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
246 {TK_CONFIG_CUSTOM, "-window", "window", "Window",
247 DEF_CONTAINER_WINDOW, Tk_Offset(Container, adopted),
248 TK_CONFIG_DONT_SET_DEFAULT, &XIDOption},
249 {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
253 /* Forward Declarations */
254 static Tcl_IdleProc DisplayContainer;
255 static Tcl_CmdProc ContainerInstCmd;
256 static Tcl_CmdDeleteProc ContainerInstCmdDeleteProc;
257 static Tk_EventProc ToplevelEventProc;
258 static Tk_GenericProc AdoptedWindowEventProc;
259 static Tk_EventProc ContainerEventProc;
260 static Tcl_FreeProc DestroyContainer;
261 static Tcl_CmdProc ContainerCmd;
263 static void EventuallyRedraw _ANSI_ARGS_((Container *cntrPtr));
267 *----------------------------------------------------------------------
271 * Returns the XID for the Tk_Window given. Starting in Tk 8.0,
272 * the toplevel widgets are wrapped by another window.
273 * Currently there's no way to get at that window, other than
274 * what is done here: query the X window hierarchy and grab the
278 * Returns the X Window ID of the widget. If it's a toplevel, then
279 * the XID of the wrapper is returned.
281 *----------------------------------------------------------------------
290 hWnd = Tk_GetHWND(Tk_WindowId(tkwin));
291 #if (TK_MAJOR_VERSION > 4)
292 if (Tk_IsTopLevel(tkwin)) {
293 hWnd = GetParent(hWnd);
295 #endif /* TK_MAJOR_VERSION > 4 */
296 twdPtr = Blt_Malloc(sizeof(TkWinWindow));
297 twdPtr->handle = hWnd;
298 twdPtr->type = TWD_WINDOW;
299 twdPtr->winPtr = tkwin;
300 return (Window)twdPtr;
305 *----------------------------------------------------------------------
309 * Returns a string representing the given XID.
312 * A static string containing either the hexidecimal number or
313 * the pathname of a Tk window.
315 *----------------------------------------------------------------------
318 NameOfId(display, window)
319 Display *display; /* Display containing both the container widget
320 * and the adopted window. */
321 Window window; /* XID of the adopted window. */
323 if (window != None) {
325 static char string[200];
327 /* See first if it's a window that Tk knows about. */
329 * Note: If the wrapper window is reparented, Tk pretends it's
330 * no longer connected to the toplevel, so if you look for
331 * the child of the wrapper tkwin, it's NULL.
333 tkwin = Tk_IdToWindow(display, window);
334 if ((tkwin != NULL) && (Tk_PathName(tkwin) != NULL)) {
335 return Tk_PathName(tkwin);
337 sprintf(string, "0x%x", (unsigned int)window);
340 return ""; /* Return empty string if XID is None. */
345 *----------------------------------------------------------------------
347 * XGeometryErrorProc --
349 * Flags errors generated from XGetGeometry calls to the X server.
355 * Sets a flag, indicating an error occurred.
357 *----------------------------------------------------------------------
361 XGeometryErrorProc(clientData, eventPtr)
362 ClientData clientData;
363 XErrorEvent *eventPtr; /* Not used. */
365 int *errorPtr = clientData;
367 *errorPtr = TCL_ERROR;
372 *----------------------------------------------------------------------
374 * GetAdoptedWindowGeometry --
376 * Computes the requested geometry of the container using the
377 * size of adopted window as a reference.
380 * A standard Tcl result.
383 * Sets a flag, indicating an error occurred.
385 *----------------------------------------------------------------------
388 GetAdoptedWindowGeometry(interp, cntrPtr)
392 int x, y, width, height, borderWidth, depth;
393 int xOffset, yOffset;
395 Tk_ErrorHandler handler;
400 xOffset = yOffset = 0;
401 if (cntrPtr->adopted != None) {
402 handler = Tk_CreateErrorHandler(cntrPtr->display, any, X_GetGeometry,
403 any, XGeometryErrorProc, &result);
404 root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
405 XTranslateCoordinates(cntrPtr->display, cntrPtr->adopted,
406 root, 0, 0, &xOffset, &yOffset, &dummy);
407 result = XGetGeometry(cntrPtr->display, cntrPtr->adopted, &root,
408 &x, &y, (unsigned int *)&width, (unsigned int *)&height,
409 (unsigned int *)&borderWidth, (unsigned int *)&depth);
410 Tk_DeleteErrorHandler(handler);
411 XSync(cntrPtr->display, False);
413 Tcl_AppendResult(interp, "can't get geometry for \"",
414 NameOfId(cntrPtr->display, cntrPtr->adopted), "\"",
418 cntrPtr->origX = xOffset;
419 cntrPtr->origY = yOffset;
420 cntrPtr->origWidth = width;
421 cntrPtr->origHeight = height;
423 cntrPtr->origX = cntrPtr->origY = 0;
424 cntrPtr->origWidth = cntrPtr->origHeight = 0;
426 cntrPtr->adoptedX = x;
427 cntrPtr->adoptedY = y;
428 cntrPtr->adoptedWidth = width;
429 cntrPtr->adoptedHeight = height;
434 * ------------------------------------------------------------------------
438 * Returns a chain of the child windows according to their stacking
439 * order. The window ids are ordered from top to bottom.
441 * ------------------------------------------------------------------------
444 GetChildren(display, window)
449 unsigned int nChildren;
452 if (!XQueryTree(display, window, &dummy /*parent*/, &dummy /*root*/,
453 &children, &nChildren)) {
460 chainPtr = Blt_ChainCreate();
461 for (i = 0; i < nChildren; i++) {
463 * XQuery returns windows in bottom to top order.
464 * We'll reverse the order.
466 Blt_ChainPrepend(chainPtr, (ClientData)children[i]);
468 if (children != NULL) {
469 XFree((char *)children);
477 *----------------------------------------------------------------------
481 * Traverses the entire window hierarchy, searching for windows
482 * matching the name field in the SearchInfo structure. This
483 * routine is recursively called for each successive level in
484 * the window hierarchy.
490 * The SearchInfo structure will track the number of windows that
491 * match the given criteria.
493 *----------------------------------------------------------------------
496 NameSearch(display, window, searchPtr)
499 SearchInfo *searchPtr;
504 if (XFetchName(display, window, &wmName)) {
505 /* Compare the name of the window to the search pattern. */
506 if (Tcl_StringMatch(wmName, searchPtr->pattern)) {
507 if (searchPtr->saveNames) { /* Record names of matching windows. */
508 Tcl_DStringAppendElement(&(searchPtr->dString),
509 NameOfId(display, window));
510 Tcl_DStringAppendElement(&(searchPtr->dString), wmName);
512 searchPtr->window = window;
513 searchPtr->nMatches++;
517 /* Process the window's descendants. */
518 chainPtr = GetChildren(display, window);
519 if (chainPtr != NULL) {
520 Blt_ChainLink *linkPtr;
523 for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL;
524 linkPtr = Blt_ChainNextLink(linkPtr)) {
525 child = (Window)Blt_ChainGetValue(linkPtr);
526 NameSearch(display, child, searchPtr);
528 Blt_ChainDestroy(chainPtr);
533 *----------------------------------------------------------------------
537 * Traverses the entire window hierarchy, searching for windows
538 * matching the command-line specified in the SearchInfo structure.
539 * This routine is recursively called for each successive level
540 * in the window hierarchy.
546 * The SearchInfo structure will track the number of windows that
547 * match the given command-line.
549 *----------------------------------------------------------------------
552 CmdSearch(display, window, searchPtr)
555 SearchInfo *searchPtr;
561 if (XGetCommand(display, window, &cmdArgv, &cmdArgc)) {
564 string = Tcl_Merge(cmdArgc, cmdArgv);
565 XFreeStringList(cmdArgv);
566 if (Tcl_StringMatch(string, searchPtr->pattern)) {
567 if (searchPtr->saveNames) { /* Record names of matching windows. */
568 Tcl_DStringAppendElement(&(searchPtr->dString),
569 NameOfId(display, window));
570 Tcl_DStringAppendElement(&(searchPtr->dString), string);
572 searchPtr->window = window;
573 searchPtr->nMatches++;
577 /* Process the window's descendants. */
578 chainPtr = GetChildren(display, window);
579 if (chainPtr != NULL) {
580 Blt_ChainLink *linkPtr;
583 for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL;
584 linkPtr = Blt_ChainNextLink(linkPtr)) {
585 child = (Window)Blt_ChainGetValue(linkPtr);
586 CmdSearch(display, child, searchPtr);
588 Blt_ChainDestroy(chainPtr);
593 *----------------------------------------------------------------------
597 * Procedure called when the timer event elapses. Used to wait
598 * between attempts checking for the designated window.
604 * Sets a flag, indicating the timeout occurred.
606 *----------------------------------------------------------------------
609 TimeoutProc(clientData)
610 ClientData clientData;
612 int *expirePtr = clientData;
618 *----------------------------------------------------------------------
620 * TestAndWaitForWindow --
622 * Searches, possibly multiple times, for windows matching the
623 * criteria given, using the search proc also given.
629 * Sets a flag, indicating the timeout occurred.
631 *----------------------------------------------------------------------
634 TestAndWaitForWindow(cntrPtr, searchPtr)
635 Container *cntrPtr; /* Container widget record. */
636 SearchInfo *searchPtr; /* Search criteria. */
639 Tcl_TimerToken timerToken;
643 /* Get the root window to start the search. */
644 root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
646 for (i = 0; i < SEARCH_TRIES; i++) {
647 searchPtr->nMatches = 0;
648 (*searchPtr->proc)(cntrPtr->display, root, searchPtr);
649 if (searchPtr->nMatches > 0) {
650 if (timerToken != NULL) {
651 Tcl_DeleteTimerHandler(timerToken);
657 * If the X11 application associated with the adopted window
658 * was just started (via "exec" or "bgexec"), the window may
659 * not exist yet. We have to wait a little bit for the program
660 * to start up. Create a timer event break us out of an wait
661 * loop. We'll wait for a given interval for the adopted window
664 timerToken = Tcl_CreateTimerHandler(cntrPtr->timeout, TimeoutProc,
667 /* Should file events be allowed? */
668 Tcl_DoOneEvent(TCL_TIMER_EVENTS | TCL_WINDOW_EVENTS |
677 * ------------------------------------------------------------------------
681 * Returns a chain of the child windows according to their stacking
682 * order. The window ids are ordered from top to bottom.
684 * ------------------------------------------------------------------------
687 GetChildren(Display *display, Window window)
693 parent = Tk_GetHWND(window);
694 chainPtr = Blt_ChainCreate();
695 for (hWnd = GetTopWindow(parent); hWnd != NULL;
696 hWnd = GetNextWindow(hWnd, GW_HWNDNEXT)) {
697 Blt_ChainAppend(chainPtr, (ClientData)hWnd);
704 *----------------------------------------------------------------------
706 * GetAdoptedWindowGeometry --
708 * Computes the requested geometry of the container using the
709 * size of adopted window as a reference.
712 * A standard Tcl result.
715 * Sets a flag, indicating an error occurred.
717 *----------------------------------------------------------------------
720 GetAdoptedWindowGeometry(Tcl_Interp *interp, Container *cntrPtr)
722 int x, y, width, height;
723 int xOffset, yOffset;
727 xOffset = yOffset = 0;
729 if (cntrPtr->adopted != None) {
733 hWnd = Tk_GetHWND(cntrPtr->adopted);
734 if (GetWindowRect(hWnd, &rect)) {
737 width = rect.right - rect.left + 1;
738 height = rect.bottom - rect.top + 1;
740 Tcl_AppendResult(interp, "can't get geometry for \"",
741 NameOfId(cntrPtr->display, cntrPtr->adopted), "\"",
745 root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
746 XTranslateCoordinates(cntrPtr->display, cntrPtr->adopted,
747 root, 0, 0, &xOffset, &yOffset, &dummy);
748 cntrPtr->origX = xOffset;
749 cntrPtr->origY = yOffset;
750 cntrPtr->origWidth = width;
751 cntrPtr->origHeight = height;
753 cntrPtr->origX = cntrPtr->origY = 0;
754 cntrPtr->origWidth = cntrPtr->origHeight = 0;
756 cntrPtr->adoptedX = x;
757 cntrPtr->adoptedY = y;
758 cntrPtr->adoptedWidth = width;
759 cntrPtr->adoptedHeight = height;
766 * ------------------------------------------------------------------------
770 * Maps each window in the hierarchy. This is needed because
776 * Each window in the hierarchy is mapped.
778 * ------------------------------------------------------------------------
781 MapTree(display, window)
787 XMapWindow(display, window);
788 chainPtr = GetChildren(display, window);
789 if (chainPtr != NULL) {
790 Blt_ChainLink *linkPtr;
793 for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL;
794 linkPtr = Blt_ChainNextLink(linkPtr)) {
795 child = (Window)Blt_ChainGetValue(linkPtr);
796 MapTree(display, child);
798 Blt_ChainDestroy(chainPtr);
803 *----------------------------------------------------------------------
807 * Converts a string into an X window Id.
810 * If the string is successfully converted, TCL_OK is returned.
811 * Otherwise, TCL_ERROR is returned and an error message is left
812 * in interpreter's result field.
814 *---------------------------------------------------------------------- */
817 StringToXID(clientData, interp, parent, string, widgRec, offset)
818 ClientData clientData; /* Not used. */
819 Tcl_Interp *interp; /* Interpreter to send results back to */
820 Tk_Window parent; /* Parent window */
821 char *string; /* String representation. */
822 char *widgRec; /* Widget record */
823 int offset; /* Offset to field in structure */
825 unsigned int flags = (int)clientData;
826 Container *cntrPtr = (Container *)widgRec;
827 Window *winPtr = (Window *) (widgRec + offset);
834 if ((flags & SEARCH_TKWIN) && string && ((string[0] == '.') ||
835 ((!strncmp(string, "interp", 6)) && ((cp = strchr(string, '.')))))) {
837 Tcl_Interp *slave = NULL;
839 if (string[0] != '.') {
840 /* Accept an interp prefix before the window. */
841 strncpy(buf, string, (cp-string));
842 buf[(cp-string)] = 0;
844 slave = Tcl_GetSlave(interp, buf);
846 Tcl_AppendResult(interp, "cant find slave: ", buf,
853 tkwin = Tk_NameToWindow(slave, string, Tk_MainWindow(slave));
857 if (!Tk_IsTopLevel(tkwin)) {
858 Tcl_AppendResult(interp, "can't reparent non-toplevel Tk windows",
863 Tk_MakeWindowExist(tkwin);
864 if (!Tk_IsMapped(tkwin)) {
865 /* Forced mapping fails to get dimensions. */
866 /* Tk_MapWindow(tkwin); */
867 Tcl_AppendResult(interp, "Tk window unmapped, try tkwait visibility ",
868 string, (char *)NULL);
871 window = Blt_GetRealWindowId(tkwin);
873 } else if ((flags & SEARCH_XID) && (string[0] == '0') &&
874 (string[1] == 'x')) {
877 /* Hexidecimal string specifying the Window token. */
878 if (Tcl_GetInt(interp, string, &token) != TCL_OK) {
882 } else if ((string == NULL) || (string[0] == '\0')) {
887 memset(&search, 0, sizeof(search));
888 if (flags & (SEARCH_NAME | SEARCH_CMD)) {
889 search.pattern = string;
890 if (flags & SEARCH_NAME) {
891 search.proc = NameSearch;
892 } else if (flags & SEARCH_CMD) {
893 search.proc = CmdSearch;
895 TestAndWaitForWindow(cntrPtr, &search);
896 if (search.nMatches > 1) {
897 Tcl_AppendResult(interp, "more than one window matches \"",
898 string, "\"", (char *)NULL);
902 if (search.nMatches == 0) {
903 Tcl_AppendResult(interp, "can't find window from pattern \"",
904 string, "\"", (char *)NULL);
907 window = search.window;
910 if (*winPtr != None) {
913 root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
914 if (Blt_ReparentWindow(cntrPtr->display, *winPtr, root,
915 cntrPtr->origX, cntrPtr->origY)
917 Tcl_AppendResult(interp, "can't restore \"",
918 NameOfId(cntrPtr->display, *winPtr),
919 "\" window to root", (char *)NULL);
922 cntrPtr->flags &= ~CONTAINER_MAPPED;
923 if (cntrPtr->tkAdopted == NULL) {
924 /* This wasn't a Tk window. So deselect the event mask. */
925 XSelectInput(cntrPtr->display, *winPtr, 0);
927 MapTree(cntrPtr->display, *winPtr);
929 XMoveResizeWindow(cntrPtr->display, *winPtr, cntrPtr->origX,
930 cntrPtr->origY, cntrPtr->origWidth, cntrPtr->origHeight);
932 cntrPtr->tkAdopted = tkAdopted;
939 *----------------------------------------------------------------------
943 * Converts the Tk window back to its string representation (i.e.
947 * The name of the window is returned.
949 *----------------------------------------------------------------------
953 XIDToString(clientData, parent, widgRec, offset, freeProcPtr)
954 ClientData clientData; /* Not used. */
955 Tk_Window parent; /* Not used. */
956 char *widgRec; /* Widget record */
957 int offset; /* Offset of field in record */
958 Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */
960 Container *cntrPtr = (Container *) widgRec;
961 Window window = *(Window *)(widgRec + offset);
963 if (cntrPtr->tkAdopted != NULL) {
964 return Tk_PathName(cntrPtr->tkAdopted);
966 return NameOfId(cntrPtr->display, window);
971 *----------------------------------------------------------------------
973 * EventuallyRedraw --
975 * Queues a request to redraw the widget at the next idle point.
981 * Information gets redisplayed. Right now we don't do selective
982 * redisplays: the whole window will be redrawn.
984 *----------------------------------------------------------------------
987 EventuallyRedraw(cntrPtr)
990 if ((cntrPtr->tkwin != NULL) && !(cntrPtr->flags & CONTAINER_REDRAW)) {
991 cntrPtr->flags |= CONTAINER_REDRAW;
992 Tcl_DoWhenIdle(DisplayContainer, cntrPtr);
997 * --------------------------------------------------------------
999 * AdoptedWindowEventProc --
1001 * This procedure is invoked by the Tk dispatcher for various
1002 * events on the encapsulated window.
1008 * When the window gets deleted, internal structures get
1009 * cleaned up. When it gets resized or exposed, it's redisplayed.
1011 * --------------------------------------------------------------
1014 AdoptedWindowEventProc(clientData, eventPtr)
1015 ClientData clientData; /* Information about the tab window. */
1016 XEvent *eventPtr; /* Information about event. */
1018 Container *cntrPtr = (Container *) clientData;
1020 if (eventPtr->xany.window != cntrPtr->adopted) {
1023 if (eventPtr->type == DestroyNotify) {
1024 cntrPtr->adopted = None;
1025 EventuallyRedraw(cntrPtr);
1031 * --------------------------------------------------------------
1033 * ContainerEventProc --
1035 * This procedure is invoked by the Tk dispatcher for various
1036 * events on container widgets.
1042 * When the window gets deleted, internal structures get
1043 * cleaned up. When it gets exposed, it is redisplayed.
1045 * --------------------------------------------------------------
1048 ContainerEventProc(clientData, eventPtr)
1049 ClientData clientData; /* Information about window. */
1050 XEvent *eventPtr; /* Information about event. */
1052 Container *cntrPtr = clientData;
1054 switch (eventPtr->type) {
1056 if (eventPtr->xexpose.count == 0) {
1057 EventuallyRedraw(cntrPtr);
1063 if (eventPtr->xfocus.detail != NotifyInferior) {
1064 if (eventPtr->type == FocusIn) {
1065 cntrPtr->flags |= CONTAINER_FOCUS;
1067 cntrPtr->flags &= ~CONTAINER_FOCUS;
1069 EventuallyRedraw(cntrPtr);
1073 case ConfigureNotify:
1074 EventuallyRedraw(cntrPtr);
1078 if (cntrPtr->tkwin != NULL) {
1079 cntrPtr->tkwin = NULL;
1080 Tcl_DeleteCommandFromToken(cntrPtr->interp, cntrPtr->cmdToken);
1082 if (cntrPtr->flags & CONTAINER_REDRAW) {
1083 Tcl_CancelIdleCall(DisplayContainer, cntrPtr);
1085 Tcl_EventuallyFree(cntrPtr, DestroyContainer);
1091 * --------------------------------------------------------------
1093 * ToplevelEventProc --
1095 * Some applications assume that they are always a toplevel
1096 * window and play tricks accordingly. For example, Netscape
1097 * positions menus in relation to the toplevel. But if the
1098 * container's toplevel is moved, this positioning is wrong.
1099 * So watch if the toplevel is moved.
1101 * [This would be easier and cleaner if Tk toplevels weren't so
1102 * botched by the addition of menubars. It's not enough to
1108 * --------------------------------------------------------------
1111 ToplevelEventProc(clientData, eventPtr)
1112 ClientData clientData; /* Information about the tab window. */
1113 XEvent *eventPtr; /* Information about event. */
1115 Container *cntrPtr = clientData;
1117 if ((cntrPtr->adopted != None) && (cntrPtr->tkwin != NULL) &&
1118 (eventPtr->type == ConfigureNotify)) {
1119 cntrPtr->flags |= CONTAINER_MOVE;
1120 EventuallyRedraw(cntrPtr);
1125 * ----------------------------------------------------------------------
1127 * DestroyContainer --
1129 * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
1130 * to clean up the internal structure of the widget at a safe
1131 * time (when no-one is using it anymore).
1137 * Everything associated with the widget is freed up.
1139 * ----------------------------------------------------------------------
1142 DestroyContainer(dataPtr)
1143 DestroyData dataPtr; /* Pointer to the widget record. */
1145 Container *cntrPtr = (Container *) dataPtr;
1147 if (cntrPtr->highlightGC != NULL) {
1148 Tk_FreeGC(cntrPtr->display, cntrPtr->highlightGC);
1150 if (cntrPtr->flags & CONTAINER_INIT) {
1151 Tk_DeleteGenericHandler(AdoptedWindowEventProc, cntrPtr);
1153 if (cntrPtr->tkToplevel != NULL) {
1154 Tk_DeleteEventHandler(cntrPtr->tkToplevel, StructureNotifyMask,
1155 ToplevelEventProc, cntrPtr);
1157 Tk_FreeOptions(configSpecs, (char *)cntrPtr, cntrPtr->display, 0);
1162 * ----------------------------------------------------------------------
1164 * ConfigureContainer --
1166 * This procedure is called to process an argv/argc list, plus
1167 * the Tk option database, in order to configure (or reconfigure)
1171 * The return value is a standard Tcl result. If TCL_ERROR is
1172 * returned, then interp->result contains an error message.
1175 * Configuration information, such as text string, colors, font,
1176 * etc. get set for cntrPtr; old resources get freed, if there
1177 * were any. The widget is redisplayed.
1179 * ----------------------------------------------------------------------
1182 ConfigureContainer(interp, cntrPtr, argc, argv, flags)
1183 Tcl_Interp *interp; /* Interpreter to report errors. */
1184 Container *cntrPtr; /* Information about widget; may or
1185 * may not already have values for
1192 unsigned long gcMask;
1196 if (Tk_ConfigureWidget(interp, cntrPtr->tkwin, configSpecs, argc, argv,
1197 (char *)cntrPtr, flags) != TCL_OK) {
1200 cntrPtr->inset = cntrPtr->borderWidth + cntrPtr->highlightWidth;
1201 if (Tk_WindowId(cntrPtr->tkwin) == None) {
1202 Tk_MakeWindowExist(cntrPtr->tkwin);
1204 if (GetAdoptedWindowGeometry(interp, cntrPtr) != TCL_OK) {
1207 if (Blt_ConfigModified(configSpecs, interp, "-window", "-name", "-command",
1209 cntrPtr->flags &= ~CONTAINER_MAPPED;
1210 if (cntrPtr->adopted != None) {
1211 if (Blt_ReparentWindow(cntrPtr->display, cntrPtr->adopted,
1212 Tk_WindowId(cntrPtr->tkwin), cntrPtr->inset,
1213 cntrPtr->inset) != TCL_OK) {
1214 Tcl_AppendResult(interp, "can't adopt window \"",
1215 NameOfId(cntrPtr->display, cntrPtr->adopted),
1216 "\"", (char *)NULL);
1219 XSelectInput(cntrPtr->display, cntrPtr->adopted,
1220 StructureNotifyMask);
1221 if ((cntrPtr->flags & CONTAINER_INIT) == 0) {
1222 Tk_CreateGenericHandler(AdoptedWindowEventProc, cntrPtr);
1223 cntrPtr->flags |= CONTAINER_INIT;
1227 /* Add the designated inset to the requested dimensions. */
1228 width = cntrPtr->origWidth + 2 * cntrPtr->inset;
1229 height = cntrPtr->origHeight + 2 * cntrPtr->inset;
1231 if (cntrPtr->reqWidth > 0) {
1232 width = cntrPtr->reqWidth;
1234 if (cntrPtr->reqHeight > 0) {
1235 height = cntrPtr->reqHeight;
1237 /* Set the requested width and height for the container. */
1238 if ((Tk_ReqWidth(cntrPtr->tkwin) != width) ||
1239 (Tk_ReqHeight(cntrPtr->tkwin) != height)) {
1240 Tk_GeometryRequest(cntrPtr->tkwin, width, height);
1244 * GC for focus highlight.
1246 gcMask = GCForeground;
1247 gcValues.foreground = cntrPtr->highlightColor->pixel;
1248 newGC = Tk_GetGC(cntrPtr->tkwin, gcMask, &gcValues);
1249 if (cntrPtr->highlightGC != NULL) {
1250 Tk_FreeGC(cntrPtr->display, cntrPtr->highlightGC);
1252 cntrPtr->highlightGC = newGC;
1254 EventuallyRedraw(cntrPtr);
1259 *----------------------------------------------------------------------
1261 * ContainerInstCmdDeleteProc --
1263 * This procedure can be called if the window was destroyed
1264 * (tkwin will be NULL) and the command was deleted
1265 * automatically. In this case, we need to do nothing.
1267 * Otherwise this routine was called because the command was
1268 * deleted. Then we need to clean-up and destroy the widget.
1274 * The widget is destroyed.
1276 *----------------------------------------------------------------------
1279 ContainerInstCmdDeleteProc(clientData)
1280 ClientData clientData; /* Pointer to widget record for widget. */
1282 Container *cntrPtr = clientData;
1284 if (cntrPtr->tkwin != NULL) {
1287 tkwin = cntrPtr->tkwin;
1288 cntrPtr->tkwin = NULL;
1289 Tk_DestroyWindow(tkwin);
1290 #ifdef ITCL_NAMESPACES
1291 Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL);
1292 #endif /* ITCL_NAMESPACES */
1297 * ------------------------------------------------------------------------
1301 * This procedure is invoked to process the Tcl command that
1302 * corresponds to a widget managed by this module. See the user
1303 * documentation for details on what it does.
1306 * A standard Tcl result.
1309 * See the user documentation.
1311 * -----------------------------------------------------------------------
1315 ContainerCmd(clientData, interp, argc, argv)
1316 ClientData clientData; /* Main window associated with interpreter. */
1317 Tcl_Interp *interp; /* Current interpreter. */
1318 int argc; /* Number of arguments. */
1319 char **argv; /* Argument strings. */
1326 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1327 " pathName ?option value?...\"", (char *)NULL);
1330 tkwin = Tk_MainWindow(interp);
1331 tkwin = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *)NULL);
1332 if (tkwin == NULL) {
1335 cntrPtr = Blt_Calloc(1, sizeof(Container));
1337 cntrPtr->tkwin = tkwin;
1338 cntrPtr->display = Tk_Display(tkwin);
1339 cntrPtr->interp = interp;
1341 cntrPtr->timeout = SEARCH_INTERVAL;
1342 cntrPtr->borderWidth = cntrPtr->highlightWidth = 2;
1343 cntrPtr->relief = TK_RELIEF_SUNKEN;
1344 Tk_SetClass(tkwin, "Container");
1345 #if (TK_MAJOR_VERSION > 4)
1346 Blt_SetWindowInstanceData(tkwin, cntrPtr);
1348 if (ConfigureContainer(interp, cntrPtr, argc - 2, argv + 2, 0) != TCL_OK) {
1349 Tk_DestroyWindow(cntrPtr->tkwin);
1352 mask = (StructureNotifyMask | ExposureMask | FocusChangeMask);
1353 Tk_CreateEventHandler(tkwin, mask, ContainerEventProc, cntrPtr);
1354 cntrPtr->cmdToken = Tcl_CreateCommand(interp, argv[1], ContainerInstCmd,
1355 cntrPtr, ContainerInstCmdDeleteProc);
1356 #ifdef ITCL_NAMESPACES
1357 Itk_SetWidgetCommand(cntrPtr->tkwin, cntrPtr->cmdToken);
1359 Tk_MakeWindowExist(tkwin);
1361 Tcl_SetResult(interp, Tk_PathName(cntrPtr->tkwin), TCL_VOLATILE);
1366 * ----------------------------------------------------------------------
1368 * DisplayContainer --
1370 * This procedure is invoked to display the widget.
1376 * The widget is redisplayed.
1378 * ----------------------------------------------------------------------
1381 DisplayContainer(clientData)
1382 ClientData clientData; /* Information about widget. */
1384 Container *cntrPtr = clientData;
1388 cntrPtr->flags &= ~CONTAINER_REDRAW;
1389 if (cntrPtr->tkwin == NULL) {
1390 return; /* Window has been destroyed. */
1392 if (!Tk_IsMapped(cntrPtr->tkwin)) {
1395 drawable = Tk_WindowId(cntrPtr->tkwin);
1398 if (cntrPtr->tkToplevel == NULL) {
1400 Tk_Window tkToplevel;
1402 /* Create an event handler for the toplevel of the container. */
1403 tkToplevel = Blt_Toplevel(cntrPtr->tkwin);
1404 window = Blt_GetRealWindowId(tkToplevel);
1405 cntrPtr->tkToplevel = Tk_IdToWindow(cntrPtr->display, window);
1406 if (cntrPtr->tkToplevel != NULL) {
1407 Tk_CreateEventHandler(cntrPtr->tkToplevel, StructureNotifyMask,
1408 ToplevelEventProc, cntrPtr);
1412 if (cntrPtr->adopted != None) {
1414 if (cntrPtr->flags & CONTAINER_MOVE) {
1416 * Some applications like Netscape cache its location to
1417 * position its popup menus. But when it's reparented, it
1418 * thinks it's always at the same position. It doesn't
1419 * know when the container's moved. The hack here is to
1420 * force the application to update its coordinates by
1421 * moving the adopted window (over by 1 pixel and
1422 * then back in case the application is comparing the last
1425 XMoveWindow(cntrPtr->display, cntrPtr->adopted,
1426 cntrPtr->inset + 1, cntrPtr->inset + 1);
1427 XMoveWindow(cntrPtr->display, cntrPtr->adopted,
1428 cntrPtr->inset, cntrPtr->inset);
1429 cntrPtr->flags &= ~CONTAINER_MOVE;
1432 /* Compute the available space inside the container. */
1433 width = Tk_Width(cntrPtr->tkwin) - (2 * cntrPtr->inset);
1434 height = Tk_Height(cntrPtr->tkwin) - (2 * cntrPtr->inset);
1436 if ((cntrPtr->adoptedX != cntrPtr->inset) ||
1437 (cntrPtr->adoptedY != cntrPtr->inset) ||
1438 (cntrPtr->adoptedWidth != width) ||
1439 (cntrPtr->adoptedHeight != height)) {
1440 /* Resize the window to the new size */
1447 XMoveResizeWindow(cntrPtr->display, cntrPtr->adopted,
1448 cntrPtr->inset, cntrPtr->inset, width, height);
1449 cntrPtr->adoptedWidth = width;
1450 cntrPtr->adoptedHeight = height;
1451 cntrPtr->adoptedX = cntrPtr->adoptedY = cntrPtr->inset;
1452 if (cntrPtr->tkAdopted != NULL) {
1453 Tk_ResizeWindow(cntrPtr->tkAdopted, width, height);
1457 if (!(cntrPtr->flags & CONTAINER_MAPPED)) {
1458 XMapWindow(cntrPtr->display, cntrPtr->adopted);
1459 cntrPtr->flags |= CONTAINER_MAPPED;
1462 if (cntrPtr->borderWidth > 0) {
1463 Blt_Draw3DRectangle(cntrPtr->tkwin, drawable, cntrPtr->border,
1464 cntrPtr->highlightWidth, cntrPtr->highlightWidth,
1465 Tk_Width(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth,
1466 Tk_Height(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth,
1467 cntrPtr->borderWidth, cntrPtr->relief);
1470 Blt_Fill3DRectangle(cntrPtr->tkwin, drawable, cntrPtr->border,
1471 cntrPtr->highlightWidth, cntrPtr->highlightWidth,
1472 Tk_Width(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth,
1473 Tk_Height(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth,
1474 cntrPtr->borderWidth, cntrPtr->relief);
1477 /* Draw focus highlight ring. */
1478 if (cntrPtr->highlightWidth > 0) {
1482 color = (cntrPtr->flags & CONTAINER_FOCUS)
1483 ? cntrPtr->highlightColor : cntrPtr->highlightBgColor;
1484 gc = Tk_GCForColor(color, drawable);
1485 Tk_DrawFocusHighlight(cntrPtr->tkwin, gc, cntrPtr->highlightWidth,
1492 *----------------------------------------------------------------------
1496 *----------------------------------------------------------------------
1500 SendOp(cntrPtr, interp, argc, argv)
1503 int argc; /* Not used. */
1507 if (cntrPtr->adopted != None) {
1514 if (Tcl_GetInt(interp, argv[2], &xid) != TCL_OK) {
1517 window = (Window)xid;
1518 event.xkey.type = KeyPress;
1519 event.xkey.serial = 0;
1520 event.xkey.display = cntrPtr->display;
1521 event.xkey.window = event.xkey.subwindow = window;
1522 event.xkey.time = CurrentTime;
1523 event.xkey.x = event.xkey.x = 100;
1525 RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
1526 event.xkey.x_root = Tk_X(cntrPtr->tkwin) + cntrPtr->inset;
1527 event.xkey.x_root = Tk_Y(cntrPtr->tkwin) + cntrPtr->inset;
1528 event.xkey.state = 0;
1529 event.xkey.same_screen = TRUE;
1531 for (p = argv[3]; *p != '\0'; p++) {
1533 symbol = XStringToKeysym("Return");
1534 } else if (*p == ' ') {
1535 symbol = XStringToKeysym("space");
1541 symbol = XStringToKeysym(p);
1544 event.xkey.keycode = XKeysymToKeycode(cntrPtr->display, symbol);
1545 event.xkey.type = KeyPress;
1546 if (!XSendEvent(cntrPtr->display, window, False, KeyPress, &event)) {
1547 fprintf(stderr, "send press event failed\n");
1549 event.xkey.type = KeyRelease;
1550 if (!XSendEvent(cntrPtr->display, window, False, KeyRelease,
1552 fprintf(stderr, "send release event failed\n");
1562 *----------------------------------------------------------------------
1566 *----------------------------------------------------------------------
1570 FindOp(cntrPtr, interp, argc, argv)
1573 int argc; /* Not used. */
1579 memset(&search, 0, sizeof(search));
1580 search.pattern = argv[3];
1581 Tcl_DStringInit(&(search.dString));
1582 search.saveNames = TRUE; /* Indicates to record all matching XIDs. */
1583 if (strcmp(argv[2], "-name") == 0) {
1584 search.proc = NameSearch;
1585 } else if (strcmp(argv[2], "-command") == 0) {
1586 search.proc = CmdSearch;
1588 Tcl_AppendResult(interp, "missing \"-name\" or \"-command\" switch",
1592 root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
1593 (*search.proc)(cntrPtr->display, root, &search);
1594 Tcl_DStringResult(interp, &search.dString);
1600 *----------------------------------------------------------------------
1604 *----------------------------------------------------------------------
1608 CgetOp(cntrPtr, interp, argc, argv)
1611 int argc; /* Not used. */
1614 return Tk_ConfigureValue(interp, cntrPtr->tkwin, configSpecs,
1615 (char *)cntrPtr, argv[2], 0);
1619 *----------------------------------------------------------------------
1623 * This procedure is called to process an argv/argc list, plus
1624 * the Tk option database, in order to configure (or reconfigure)
1628 * A standard Tcl result. If TCL_ERROR is returned, then
1629 * interp->result contains an error message.
1632 * Configuration information, such as text string, colors, font,
1633 * etc. get set for cntrPtr; old resources get freed, if there
1634 * were any. The widget is redisplayed.
1636 *----------------------------------------------------------------------
1639 ConfigureOp(cntrPtr, interp, argc, argv)
1646 return Tk_ConfigureInfo(interp, cntrPtr->tkwin, configSpecs,
1647 (char *)cntrPtr, (char *)NULL, 0);
1648 } else if (argc == 3) {
1649 return Tk_ConfigureInfo(interp, cntrPtr->tkwin, configSpecs,
1650 (char *)cntrPtr, argv[2], 0);
1652 if (ConfigureContainer(interp, cntrPtr, argc - 2, argv + 2,
1653 TK_CONFIG_ARGV_ONLY) != TCL_OK) {
1656 EventuallyRedraw(cntrPtr);
1661 * --------------------------------------------------------------
1665 * This procedure is invoked to process the "container" command.
1666 * See the user documentation for details on what it does.
1669 * A standard Tcl result.
1672 * See the user documentation.
1674 * --------------------------------------------------------------
1676 static Blt_OpSpec opSpecs[] =
1678 {"cget", 2, (Blt_Op)CgetOp, 3, 3, "option",},
1679 {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?option value?...",},
1681 {"find", 1, (Blt_Op)FindOp, 3, 4, "?-command|-name? pattern",},
1684 {"send", 1, (Blt_Op)SendOp, 4, 4, "window string",},
1688 static int nSpecs = sizeof(opSpecs) / sizeof(Blt_OpSpec);
1691 ContainerInstCmd(clientData, interp, argc, argv)
1692 ClientData clientData; /* Information about the widget. */
1693 Tcl_Interp *interp; /* Interpreter to report errors back to. */
1694 int argc; /* Number of arguments. */
1695 char **argv; /* Vector of argument strings. */
1698 Container *cntrPtr = clientData;
1701 proc = Blt_GetOp(interp, nSpecs, opSpecs, BLT_OP_ARG1, argc, argv, 0);
1705 Tcl_Preserve(cntrPtr);
1706 result = (*proc)(cntrPtr, interp, argc, argv);
1707 Tcl_Release(cntrPtr);
1712 Blt_ContainerInit(interp)
1715 static Blt_CmdSpec cmdSpec =
1717 "container", ContainerCmd,
1719 if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) {
1725 #endif /* NO_CONTAINER */