summaryrefslogtreecommitdiff
path: root/blt/src/bltContainer.c
diff options
context:
space:
mode:
Diffstat (limited to 'blt/src/bltContainer.c')
-rw-r--r--blt/src/bltContainer.c1701
1 files changed, 1701 insertions, 0 deletions
diff --git a/blt/src/bltContainer.c b/blt/src/bltContainer.c
new file mode 100644
index 00000000000..bc343755456
--- /dev/null
+++ b/blt/src/bltContainer.c
@@ -0,0 +1,1701 @@
+
+/*
+ * bltContainer.c --
+ *
+ * This module implements a container widget for the BLT toolkit.
+ *
+ * Copyright 1998 Lucent Technologies, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies or any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Lucent Technologies disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness. In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ *
+ * Container widget created by George A. Howlett
+ */
+
+#include "bltInt.h"
+
+#ifndef NO_CONTAINER
+#include "bltChain.h"
+#ifndef WIN32
+#include <X11/Xproto.h>
+#include <X11/Xutil.h>
+#endif
+
+#define XDEBUG
+
+#define SEARCH_TRIES 100 /* Maximum number of attempts to check for
+ * a given window before failing. */
+#define SEARCH_INTERVAL 20 /* Number milliseconds to wait after each
+ * attempt to find a window. */
+
+#define SEARCH_TKWIN (1<<0) /* Search via Tk window pathname. */
+#define SEARCH_XID (1<<1) /* Search via an XID 0x0000000. */
+#define SEARCH_CMD (1<<2) /* Search via a command-line arguments. */
+#define SEARCH_NAME (1<<3) /* Search via the application name. */
+#define SEARCH_ALL (SEARCH_TKWIN | SEARCH_XID | SEARCH_CMD | SEARCH_NAME)
+
+#define CONTAINER_REDRAW (1<<1)
+#define CONTAINER_MAPPED (1<<2)
+#define CONTAINER_FOCUS (1<<4)
+#define CONTAINER_INIT (1<<5)
+#define CONTAINER_MOVE (1<<7)
+
+#define DEF_CONTAINER_BG_MONO STD_MONO_NORMAL_BG
+#define DEF_CONTAINER_BG_COLOR STD_COLOR_NORMAL_BG
+#define DEF_CONTAINER_BORDER_WIDTH STD_BORDERWIDTH
+#define DEF_CONTAINER_COMMAND (char *)NULL
+#define DEF_CONTAINER_CURSOR (char *)NULL
+#define DEF_CONTAINER_HEIGHT "0"
+#define DEF_CONTAINER_HIGHLIGHT_BG_COLOR STD_COLOR_NORMAL_BG
+#define DEF_CONTAINER_HIGHLIGHT_BG_MONO STD_MONO_NORMAL_BG
+#define DEF_CONTAINER_HIGHLIGHT_COLOR RGB_BLACK
+#define DEF_CONTAINER_HIGHLIGHT_WIDTH "2"
+#define DEF_CONTAINER_RELIEF "sunken"
+#define DEF_CONTAINER_TAKE_FOCUS "0"
+#define DEF_CONTAINER_TIMEOUT "20"
+#define DEF_CONTAINER_WIDTH "0"
+#define DEF_CONTAINER_WINDOW (char *)NULL
+
+#if (TK_MAJOR_VERSION == 4)
+#define TK_REPARENTED 0x2000
+#endif
+
+typedef struct SearchInfoStruct SearchInfo;
+typedef void (SearchProc) _ANSI_ARGS_((Display *display, Window window,
+ SearchInfo *searchPtr));
+
+struct SearchInfoStruct {
+ SearchProc *proc;
+ char *pattern; /* Search pattern. */
+
+ Window window; /* XID of last window that matches criteria. */
+ int nMatches; /* Number of windows that match the pattern. */
+ int saveNames; /* Indicates to save the names of the
+ * window XIDs that match the search
+ * criteria. */
+ Tcl_DString dString; /* Will contain the strings of the
+ * window XIDs matching the search
+ * criteria. */
+};
+
+typedef struct {
+ Tk_Window tkwin; /* Window that embodies the widget.
+ * NULL means that the window has been
+ * destroyed but the data structures
+ * haven't yet been cleaned up.*/
+
+ Display *display; /* Display containing widget; needed,
+ * among other things, to release
+ * resources after tkwin has already
+ * gone away. */
+
+ Tcl_Interp *interp; /* Interpreter associated with widget. */
+
+ Tcl_Command cmdToken; /* Token for widget's command. */
+
+ unsigned int flags; /* For bit-field definitions, see above. */
+
+ int inset; /* Total width of borders; focus
+ * highlight and 3-D border. Indicates
+ * the offset from outside edges to
+ * leave room for borders. */
+
+ Tk_Cursor cursor; /* X Cursor */
+
+ Tk_3DBorder border; /* 3D border surrounding the adopted
+ * window. */
+ int borderWidth; /* Width of 3D border. */
+ int relief; /* 3D border relief. */
+
+ Tk_Window tkToplevel; /* Toplevel (wrapper) window of
+ * container. It's used to track the
+ * location of the container. If it
+ * moves we need to notify the
+ * embedded application. */
+ /*
+ * Focus highlight ring
+ */
+ int highlightWidth; /* Width in pixels of highlight to
+ * draw around widget when it has the
+ * focus. <= 0 means don't draw a
+ * highlight. */
+ XColor *highlightBgColor; /* Color for drawing traversal
+ * highlight area when highlight is
+ * off. */
+ XColor *highlightColor; /* Color for drawing traversal highlight. */
+
+ GC highlightGC; /* GC for focus highlight. */
+
+ char *takeFocus; /* Says whether to select this widget during
+ * tab traveral operations. This value isn't
+ * used in C code, but for the widget's Tcl
+ * bindings. */
+
+ int reqWidth, reqHeight; /* Requested dimensions of the container
+ * window. */
+
+ Window adopted; /* X window Id or Win32 handle of adopted
+ * window contained by the widget. If None,
+ * no window has been reparented. */
+ Tk_Window tkAdopted; /* Non-NULL if this is a Tk window that's
+ * been adopted. */
+ int adoptedX, adoptedY; /* Current position of the adopted window. */
+ int adoptedWidth; /* Current width of the adopted window. */
+ int adoptedHeight; /* Current height of the adopted window. */
+
+ int origX, origY;
+ int origWidth, origHeight; /* Dimensions of the window when it
+ * was adopted. When the window is
+ * released it's returned to it's
+ * original dimensions. */
+
+ int timeout;
+} Container;
+
+
+static Tk_OptionParseProc StringToXID;
+static Tk_OptionPrintProc XIDToString;
+
+static Tk_CustomOption XIDOption =
+{
+ StringToXID, XIDToString, (ClientData)(SEARCH_TKWIN | SEARCH_XID),
+};
+
+#ifndef WIN32
+static Tk_CustomOption XIDNameOption =
+{
+ StringToXID, XIDToString, (ClientData)SEARCH_NAME,
+};
+
+static Tk_CustomOption XIDCmdOption =
+{
+ StringToXID, XIDToString, (ClientData)SEARCH_CMD,
+};
+#endif
+
+extern Tk_CustomOption bltDistanceOption;
+extern Tk_CustomOption bltPositiveCountOption;
+
+static Tk_ConfigSpec configSpecs[] =
+{
+ {TK_CONFIG_BORDER, "-background", "background", "Background",
+ DEF_CONTAINER_BG_MONO, Tk_Offset(Container, border),
+ TK_CONFIG_MONO_ONLY},
+ {TK_CONFIG_BORDER, "-background", "background", "Background",
+ DEF_CONTAINER_BG_COLOR, Tk_Offset(Container, border),
+ TK_CONFIG_COLOR_ONLY},
+ {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0},
+ {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0},
+ {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth",
+ DEF_CONTAINER_BORDER_WIDTH, Tk_Offset(Container, borderWidth),
+ TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
+#ifndef WIN32
+ {TK_CONFIG_CUSTOM, "-command", "command", "Command",
+ DEF_CONTAINER_WINDOW, Tk_Offset(Container, adopted),
+ TK_CONFIG_DONT_SET_DEFAULT, &XIDCmdOption},
+#endif
+ {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
+ DEF_CONTAINER_CURSOR, Tk_Offset(Container, cursor), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_CUSTOM, "-height", "height", "Height",
+ DEF_CONTAINER_HEIGHT, Tk_Offset(Container, reqHeight),
+ TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
+ {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
+ "HighlightBackground", DEF_CONTAINER_HIGHLIGHT_BG_COLOR,
+ Tk_Offset(Container, highlightBgColor), TK_CONFIG_COLOR_ONLY},
+ {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
+ "HighlightBackground", DEF_CONTAINER_HIGHLIGHT_BG_MONO,
+ Tk_Offset(Container, highlightBgColor), TK_CONFIG_MONO_ONLY},
+ {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
+ DEF_CONTAINER_HIGHLIGHT_COLOR,
+ Tk_Offset(Container, highlightColor), 0},
+ {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
+ "HighlightThickness",
+ DEF_CONTAINER_HIGHLIGHT_WIDTH, Tk_Offset(Container, highlightWidth),
+ TK_CONFIG_DONT_SET_DEFAULT},
+#ifndef WIN32
+ {TK_CONFIG_CUSTOM, "-name", "name", "Name",
+ DEF_CONTAINER_WINDOW, Tk_Offset(Container, adopted),
+ TK_CONFIG_DONT_SET_DEFAULT, &XIDNameOption},
+#endif
+ {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
+ DEF_CONTAINER_RELIEF, Tk_Offset(Container, relief), 0},
+ {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
+ DEF_CONTAINER_TAKE_FOCUS, Tk_Offset(Container, takeFocus),
+ TK_CONFIG_NULL_OK},
+ {TK_CONFIG_CUSTOM, "-timeout", "timeout", "Timeout",
+ DEF_CONTAINER_TIMEOUT, Tk_Offset(Container, timeout),
+ TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveCountOption},
+ {TK_CONFIG_CUSTOM, "-width", "width", "Width",
+ DEF_CONTAINER_WIDTH, Tk_Offset(Container, reqWidth),
+ TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
+ {TK_CONFIG_CUSTOM, "-window", "window", "Window",
+ DEF_CONTAINER_WINDOW, Tk_Offset(Container, adopted),
+ TK_CONFIG_DONT_SET_DEFAULT, &XIDOption},
+ {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
+ (char *)NULL, 0, 0}
+};
+
+/* Forward Declarations */
+static Tcl_IdleProc DisplayContainer;
+static Tcl_CmdProc ContainerInstCmd;
+static Tcl_CmdDeleteProc ContainerInstCmdDeleteProc;
+static Tk_EventProc ToplevelEventProc;
+static Tk_GenericProc AdoptedWindowEventProc;
+static Tk_EventProc ContainerEventProc;
+static Tcl_FreeProc DestroyContainer;
+static Tcl_CmdProc ContainerCmd;
+
+static void EventuallyRedraw _ANSI_ARGS_((Container *cntrPtr));
+
+#ifdef notdef
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetWindowId --
+ *
+ * Returns the XID for the Tk_Window given. Starting in Tk 8.0,
+ * the toplevel widgets are wrapped by another window.
+ * Currently there's no way to get at that window, other than
+ * what is done here: query the X window hierarchy and grab the
+ * parent.
+ *
+ * Results:
+ * Returns the X Window ID of the widget. If it's a toplevel, then
+ * the XID of the wrapper is returned.
+ *
+ *----------------------------------------------------------------------
+ */
+Window
+GetXID(tkwin)
+ Tk_Window tkwin;
+{
+ HWND hWnd;
+ TkWinWindow *twdPtr;
+
+ hWnd = Tk_GetHWND(Tk_WindowId(tkwin));
+#if (TK_MAJOR_VERSION > 4)
+ if (Tk_IsTopLevel(tkwin)) {
+ hWnd = GetParent(hWnd);
+ }
+#endif /* TK_MAJOR_VERSION > 4 */
+ twdPtr = Blt_Malloc(sizeof(TkWinWindow));
+ twdPtr->handle = hWnd;
+ twdPtr->type = TWD_WINDOW;
+ twdPtr->winPtr = tkwin;
+ return (Window)twdPtr;
+}
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NameOfId --
+ *
+ * Returns a string representing the given XID.
+ *
+ * Results:
+ * A static string containing either the hexidecimal number or
+ * the pathname of a Tk window.
+ *
+ *----------------------------------------------------------------------
+ */
+static char *
+NameOfId(display, window)
+ Display *display; /* Display containing both the container widget
+ * and the adopted window. */
+ Window window; /* XID of the adopted window. */
+{
+ if (window != None) {
+ Tk_Window tkwin;
+ static char string[200];
+
+ /* See first if it's a window that Tk knows about. */
+ /*
+ * Note: If the wrapper window is reparented, Tk pretends it's
+ * no longer connected to the toplevel, so if you look for
+ * the child of the wrapper tkwin, it's NULL.
+ */
+ tkwin = Tk_IdToWindow(display, window);
+ if ((tkwin != NULL) && (Tk_PathName(tkwin) != NULL)) {
+ return Tk_PathName(tkwin);
+ }
+ sprintf(string, "0x%x", (unsigned int)window);
+ return string;
+ }
+ return ""; /* Return empty string if XID is None. */
+}
+
+#ifndef WIN32
+/*
+ *----------------------------------------------------------------------
+ *
+ * XGeometryErrorProc --
+ *
+ * Flags errors generated from XGetGeometry calls to the X server.
+ *
+ * Results:
+ * Always returns 0.
+ *
+ * Side Effects:
+ * Sets a flag, indicating an error occurred.
+ *
+ *----------------------------------------------------------------------
+ */
+/* ARGSUSED */
+static int
+XGeometryErrorProc(clientData, eventPtr)
+ ClientData clientData;
+ XErrorEvent *eventPtr; /* Not used. */
+{
+ int *errorPtr = clientData;
+
+ *errorPtr = TCL_ERROR;
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetAdoptedWindowGeometry --
+ *
+ * Computes the requested geometry of the container using the
+ * size of adopted window as a reference.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side Effects:
+ * Sets a flag, indicating an error occurred.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+GetAdoptedWindowGeometry(interp, cntrPtr)
+ Tcl_Interp *interp;
+ Container *cntrPtr;
+{
+ int x, y, width, height, borderWidth, depth;
+ int xOffset, yOffset;
+ Window root, dummy;
+ Tk_ErrorHandler handler;
+ int result;
+ int any = -1;
+
+ width = height = 1;
+ xOffset = yOffset = 0;
+ if (cntrPtr->adopted != None) {
+ handler = Tk_CreateErrorHandler(cntrPtr->display, any, X_GetGeometry,
+ any, XGeometryErrorProc, &result);
+ root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
+ XTranslateCoordinates(cntrPtr->display, cntrPtr->adopted,
+ root, 0, 0, &xOffset, &yOffset, &dummy);
+ result = XGetGeometry(cntrPtr->display, cntrPtr->adopted, &root,
+ &x, &y, (unsigned int *)&width, (unsigned int *)&height,
+ (unsigned int *)&borderWidth, (unsigned int *)&depth);
+ Tk_DeleteErrorHandler(handler);
+ XSync(cntrPtr->display, False);
+ if (result == 0) {
+ Tcl_AppendResult(interp, "can't get geometry for \"",
+ NameOfId(cntrPtr->display, cntrPtr->adopted), "\"",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ cntrPtr->origX = xOffset;
+ cntrPtr->origY = yOffset;
+ cntrPtr->origWidth = width;
+ cntrPtr->origHeight = height;
+ } else {
+ cntrPtr->origX = cntrPtr->origY = 0;
+ cntrPtr->origWidth = cntrPtr->origHeight = 0;
+ }
+ cntrPtr->adoptedX = x;
+ cntrPtr->adoptedY = y;
+ cntrPtr->adoptedWidth = width;
+ cntrPtr->adoptedHeight = height;
+ return TCL_OK;
+}
+
+/*
+ * ------------------------------------------------------------------------
+ *
+ * GetChildren --
+ *
+ * Returns a chain of the child windows according to their stacking
+ * order. The window ids are ordered from top to bottom.
+ *
+ * ------------------------------------------------------------------------
+ */
+static Blt_Chain *
+GetChildren(display, window)
+ Display *display;
+ Window window;
+{
+ Window *children;
+ unsigned int nChildren;
+ Window dummy;
+
+ if (!XQueryTree(display, window, &dummy /*parent*/, &dummy /*root*/,
+ &children, &nChildren)) {
+ return NULL;
+ }
+ if (nChildren > 0) {
+ Blt_Chain *chainPtr;
+ register int i;
+
+ chainPtr = Blt_ChainCreate();
+ for (i = 0; i < nChildren; i++) {
+ /*
+ * XQuery returns windows in bottom to top order.
+ * We'll reverse the order.
+ */
+ Blt_ChainPrepend(chainPtr, (ClientData)children[i]);
+ }
+ if (children != NULL) {
+ XFree((char *)children);
+ }
+ return chainPtr;
+ }
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NameSearch --
+ *
+ * Traverses the entire window hierarchy, searching for windows
+ * matching the name field in the SearchInfo structure. This
+ * routine is recursively called for each successive level in
+ * the window hierarchy.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The SearchInfo structure will track the number of windows that
+ * match the given criteria.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+NameSearch(display, window, searchPtr)
+ Display *display;
+ Window window;
+ SearchInfo *searchPtr;
+{
+ Blt_Chain *chainPtr;
+ char *wmName;
+
+ if (XFetchName(display, window, &wmName)) {
+ /* Compare the name of the window to the search pattern. */
+ if (Tcl_StringMatch(wmName, searchPtr->pattern)) {
+ if (searchPtr->saveNames) { /* Record names of matching windows. */
+ Tcl_DStringAppendElement(&(searchPtr->dString),
+ NameOfId(display, window));
+ Tcl_DStringAppendElement(&(searchPtr->dString), wmName);
+ }
+ searchPtr->window = window;
+ searchPtr->nMatches++;
+ }
+ XFree(wmName);
+ }
+ /* Process the window's descendants. */
+ chainPtr = GetChildren(display, window);
+ if (chainPtr != NULL) {
+ Blt_ChainLink *linkPtr;
+ Window child;
+
+ for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL;
+ linkPtr = Blt_ChainNextLink(linkPtr)) {
+ child = (Window)Blt_ChainGetValue(linkPtr);
+ NameSearch(display, child, searchPtr);
+ }
+ Blt_ChainDestroy(chainPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CmdSearch --
+ *
+ * Traverses the entire window hierarchy, searching for windows
+ * matching the command-line specified in the SearchInfo structure.
+ * This routine is recursively called for each successive level
+ * in the window hierarchy.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The SearchInfo structure will track the number of windows that
+ * match the given command-line.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+CmdSearch(display, window, searchPtr)
+ Display *display;
+ Window window;
+ SearchInfo *searchPtr;
+{
+ Blt_Chain *chainPtr;
+ int cmdArgc;
+ char **cmdArgv;
+
+ if (XGetCommand(display, window, &cmdArgv, &cmdArgc)) {
+ char *string;
+
+ string = Tcl_Merge(cmdArgc, cmdArgv);
+ XFreeStringList(cmdArgv);
+ if (Tcl_StringMatch(string, searchPtr->pattern)) {
+ if (searchPtr->saveNames) { /* Record names of matching windows. */
+ Tcl_DStringAppendElement(&(searchPtr->dString),
+ NameOfId(display, window));
+ Tcl_DStringAppendElement(&(searchPtr->dString), string);
+ }
+ searchPtr->window = window;
+ searchPtr->nMatches++;
+ }
+ Blt_Free(string);
+ }
+ /* Process the window's descendants. */
+ chainPtr = GetChildren(display, window);
+ if (chainPtr != NULL) {
+ Blt_ChainLink *linkPtr;
+ Window child;
+
+ for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL;
+ linkPtr = Blt_ChainNextLink(linkPtr)) {
+ child = (Window)Blt_ChainGetValue(linkPtr);
+ CmdSearch(display, child, searchPtr);
+ }
+ Blt_ChainDestroy(chainPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TimeoutProc --
+ *
+ * Procedure called when the timer event elapses. Used to wait
+ * between attempts checking for the designated window.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Sets a flag, indicating the timeout occurred.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TimeoutProc(clientData)
+ ClientData clientData;
+{
+ int *expirePtr = clientData;
+
+ *expirePtr = TRUE;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TestAndWaitForWindow --
+ *
+ * Searches, possibly multiple times, for windows matching the
+ * criteria given, using the search proc also given.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Sets a flag, indicating the timeout occurred.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TestAndWaitForWindow(cntrPtr, searchPtr)
+ Container *cntrPtr; /* Container widget record. */
+ SearchInfo *searchPtr; /* Search criteria. */
+{
+ Window root;
+ Tcl_TimerToken timerToken;
+ int expire;
+ int i;
+
+ /* Get the root window to start the search. */
+ root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
+ timerToken = NULL;
+ for (i = 0; i < SEARCH_TRIES; i++) {
+ searchPtr->nMatches = 0;
+ (*searchPtr->proc)(cntrPtr->display, root, searchPtr);
+ if (searchPtr->nMatches > 0) {
+ if (timerToken != NULL) {
+ Tcl_DeleteTimerHandler(timerToken);
+ }
+ return;
+ }
+ expire = FALSE;
+ /*
+ * If the X11 application associated with the adopted window
+ * was just started (via "exec" or "bgexec"), the window may
+ * not exist yet. We have to wait a little bit for the program
+ * to start up. Create a timer event break us out of an wait
+ * loop. We'll wait for a given interval for the adopted window
+ * to appear.
+ */
+ timerToken = Tcl_CreateTimerHandler(cntrPtr->timeout, TimeoutProc,
+ &expire);
+ while (!expire) {
+ /* Should file events be allowed? */
+ Tcl_DoOneEvent(TCL_TIMER_EVENTS | TCL_WINDOW_EVENTS |
+ TCL_FILE_EVENTS);
+ }
+ }
+}
+#else
+
+
+/*
+ * ------------------------------------------------------------------------
+ *
+ * GetChildren --
+ *
+ * Returns a chain of the child windows according to their stacking
+ * order. The window ids are ordered from top to bottom.
+ *
+ * ------------------------------------------------------------------------
+ */
+static Blt_Chain *
+GetChildren(Display *display, Window window)
+{
+ Blt_Chain *chainPtr;
+ HWND hWnd;
+ HWND parent;
+
+ parent = Tk_GetHWND(window);
+ chainPtr = Blt_ChainCreate();
+ for (hWnd = GetTopWindow(parent); hWnd != NULL;
+ hWnd = GetNextWindow(hWnd, GW_HWNDNEXT)) {
+ Blt_ChainAppend(chainPtr, (ClientData)hWnd);
+ }
+ return chainPtr;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetAdoptedWindowGeometry --
+ *
+ * Computes the requested geometry of the container using the
+ * size of adopted window as a reference.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side Effects:
+ * Sets a flag, indicating an error occurred.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+GetAdoptedWindowGeometry(Tcl_Interp *interp, Container *cntrPtr)
+{
+ int x, y, width, height;
+ int xOffset, yOffset;
+ Window root, dummy;
+ int any = -1;
+
+ width = height = 1;
+ xOffset = yOffset = 0;
+
+ if (cntrPtr->adopted != None) {
+ HWND hWnd;
+ RECT rect;
+
+ hWnd = Tk_GetHWND(cntrPtr->adopted);
+ if (GetWindowRect(hWnd, &rect)) {
+ x = rect.left;
+ y = rect.top;
+ width = rect.right - rect.left + 1;
+ height = rect.bottom - rect.top + 1;
+ } else {
+ Tcl_AppendResult(interp, "can't get geometry for \"",
+ NameOfId(cntrPtr->display, cntrPtr->adopted), "\"",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
+ XTranslateCoordinates(cntrPtr->display, cntrPtr->adopted,
+ root, 0, 0, &xOffset, &yOffset, &dummy);
+ cntrPtr->origX = xOffset;
+ cntrPtr->origY = yOffset;
+ cntrPtr->origWidth = width;
+ cntrPtr->origHeight = height;
+ } else {
+ cntrPtr->origX = cntrPtr->origY = 0;
+ cntrPtr->origWidth = cntrPtr->origHeight = 0;
+ }
+ cntrPtr->adoptedX = x;
+ cntrPtr->adoptedY = y;
+ cntrPtr->adoptedWidth = width;
+ cntrPtr->adoptedHeight = height;
+ return TCL_OK;
+}
+
+#endif /*WIN32*/
+
+/*
+ * ------------------------------------------------------------------------
+ *
+ * MapTree --
+ *
+ * Maps each window in the hierarchy. This is needed because
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Each window in the hierarchy is mapped.
+ *
+ * ------------------------------------------------------------------------
+ */
+static void
+MapTree(display, window)
+ Display *display;
+ Window window;
+{
+ Blt_Chain *chainPtr;
+
+ XMapWindow(display, window);
+ chainPtr = GetChildren(display, window);
+ if (chainPtr != NULL) {
+ Blt_ChainLink *linkPtr;
+ Window child;
+
+ for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL;
+ linkPtr = Blt_ChainNextLink(linkPtr)) {
+ child = (Window)Blt_ChainGetValue(linkPtr);
+ MapTree(display, child);
+ }
+ Blt_ChainDestroy(chainPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringToXID --
+ *
+ * Converts a string into an X window Id.
+ *
+ * Results:
+ * If the string is successfully converted, TCL_OK is returned.
+ * Otherwise, TCL_ERROR is returned and an error message is left
+ * in interpreter's result field.
+ *
+ *---------------------------------------------------------------------- */
+/*ARGSUSED*/
+static int
+StringToXID(clientData, interp, parent, string, widgRec, offset)
+ ClientData clientData; /* Not used. */
+ Tcl_Interp *interp; /* Interpreter to send results back to */
+ Tk_Window parent; /* Parent window */
+ char *string; /* String representation. */
+ char *widgRec; /* Widget record */
+ int offset; /* Offset to field in structure */
+{
+ unsigned int flags = (int)clientData;
+ Container *cntrPtr = (Container *)widgRec;
+ Window *winPtr = (Window *) (widgRec + offset);
+ Tk_Window tkAdopted;
+ Window window;
+
+ tkAdopted = NULL;
+ if ((flags & SEARCH_TKWIN) && (string[0] == '.')) {
+ Tk_Window tkwin;
+
+ tkwin = Tk_NameToWindow(interp, string, Tk_MainWindow(interp));
+ if (tkwin == NULL) {
+ return TCL_ERROR;
+ }
+ if (!Tk_IsTopLevel(tkwin)) {
+ Tcl_AppendResult(interp, "can't reparent non-toplevel Tk windows",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ tkAdopted = tkwin;
+ Tk_MakeWindowExist(tkwin);
+ window = Blt_GetRealWindowId(tkwin);
+#ifndef WIN32
+ } else if ((flags & SEARCH_XID) && (string[0] == '0') &&
+ (string[1] == 'x')) {
+ int token;
+
+ /* Hexidecimal string specifying the Window token. */
+ if (Tcl_GetInt(interp, string, &token) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ window = token;
+ } else if ((string == NULL) || (string[0] == '\0')) {
+ window = None;
+ } else {
+ SearchInfo search;
+
+ memset(&search, 0, sizeof(search));
+ if (flags & (SEARCH_NAME | SEARCH_CMD)) {
+ search.pattern = string;
+ if (flags & SEARCH_NAME) {
+ search.proc = NameSearch;
+ } else if (flags & SEARCH_CMD) {
+ search.proc = CmdSearch;
+ }
+ TestAndWaitForWindow(cntrPtr, &search);
+ if (search.nMatches > 1) {
+ Tcl_AppendResult(interp, "more than one window matches \"",
+ string, "\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+ }
+ if (search.nMatches == 0) {
+ Tcl_AppendResult(interp, "can't find window from pattern \"",
+ string, "\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+ window = search.window;
+#endif /*WIN32*/
+ }
+ if (*winPtr != None) {
+ Window root;
+
+ root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
+ if (Blt_ReparentWindow(cntrPtr->display, *winPtr, root,
+ cntrPtr->origX, cntrPtr->origY)
+ != TCL_OK) {
+ Tcl_AppendResult(interp, "can't restore \"",
+ NameOfId(cntrPtr->display, *winPtr),
+ "\" window to root", (char *)NULL);
+ return TCL_ERROR;
+ }
+ cntrPtr->flags &= ~CONTAINER_MAPPED;
+ if (cntrPtr->tkAdopted == NULL) {
+ /* This wasn't a Tk window. So deselect the event mask. */
+ XSelectInput(cntrPtr->display, *winPtr, 0);
+ } else {
+ MapTree(cntrPtr->display, *winPtr);
+ }
+ XMoveResizeWindow(cntrPtr->display, *winPtr, cntrPtr->origX,
+ cntrPtr->origY, cntrPtr->origWidth, cntrPtr->origHeight);
+ }
+ cntrPtr->tkAdopted = tkAdopted;
+ *winPtr = window;
+ return TCL_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XIDToString --
+ *
+ * Converts the Tk window back to its string representation (i.e.
+ * its name).
+ *
+ * Results:
+ * The name of the window is returned.
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static char *
+XIDToString(clientData, parent, widgRec, offset, freeProcPtr)
+ ClientData clientData; /* Not used. */
+ Tk_Window parent; /* Not used. */
+ char *widgRec; /* Widget record */
+ int offset; /* Offset of field in record */
+ Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */
+{
+ Container *cntrPtr = (Container *) widgRec;
+ Window window = *(Window *)(widgRec + offset);
+
+ if (cntrPtr->tkAdopted != NULL) {
+ return Tk_PathName(cntrPtr->tkAdopted);
+ }
+ return NameOfId(cntrPtr->display, window);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * EventuallyRedraw --
+ *
+ * Queues a request to redraw the widget at the next idle point.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Information gets redisplayed. Right now we don't do selective
+ * redisplays: the whole window will be redrawn.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+EventuallyRedraw(cntrPtr)
+ Container *cntrPtr;
+{
+ if ((cntrPtr->tkwin != NULL) && !(cntrPtr->flags & CONTAINER_REDRAW)) {
+ cntrPtr->flags |= CONTAINER_REDRAW;
+ Tcl_DoWhenIdle(DisplayContainer, cntrPtr);
+ }
+}
+
+/*
+ * --------------------------------------------------------------
+ *
+ * AdoptedWindowEventProc --
+ *
+ * This procedure is invoked by the Tk dispatcher for various
+ * events on the encapsulated window.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * When the window gets deleted, internal structures get
+ * cleaned up. When it gets resized or exposed, it's redisplayed.
+ *
+ * --------------------------------------------------------------
+ */
+static int
+AdoptedWindowEventProc(clientData, eventPtr)
+ ClientData clientData; /* Information about the tab window. */
+ XEvent *eventPtr; /* Information about event. */
+{
+ Container *cntrPtr = (Container *) clientData;
+
+ if (eventPtr->xany.window != cntrPtr->adopted) {
+ return 0;
+ }
+ if (eventPtr->type == DestroyNotify) {
+ cntrPtr->adopted = None;
+ EventuallyRedraw(cntrPtr);
+ }
+ return 1;
+}
+
+/*
+ * --------------------------------------------------------------
+ *
+ * ContainerEventProc --
+ *
+ * This procedure is invoked by the Tk dispatcher for various
+ * events on container widgets.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * When the window gets deleted, internal structures get
+ * cleaned up. When it gets exposed, it is redisplayed.
+ *
+ * --------------------------------------------------------------
+ */
+static void
+ContainerEventProc(clientData, eventPtr)
+ ClientData clientData; /* Information about window. */
+ XEvent *eventPtr; /* Information about event. */
+{
+ Container *cntrPtr = clientData;
+
+ switch (eventPtr->type) {
+ case Expose:
+ if (eventPtr->xexpose.count == 0) {
+ EventuallyRedraw(cntrPtr);
+ }
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ if (eventPtr->xfocus.detail != NotifyInferior) {
+ if (eventPtr->type == FocusIn) {
+ cntrPtr->flags |= CONTAINER_FOCUS;
+ } else {
+ cntrPtr->flags &= ~CONTAINER_FOCUS;
+ }
+ EventuallyRedraw(cntrPtr);
+ }
+ break;
+
+ case ConfigureNotify:
+ EventuallyRedraw(cntrPtr);
+ break;
+
+ case DestroyNotify:
+ if (cntrPtr->tkwin != NULL) {
+ cntrPtr->tkwin = NULL;
+ Tcl_DeleteCommandFromToken(cntrPtr->interp, cntrPtr->cmdToken);
+ }
+ if (cntrPtr->flags & CONTAINER_REDRAW) {
+ Tcl_CancelIdleCall(DisplayContainer, cntrPtr);
+ }
+ Tcl_EventuallyFree(cntrPtr, DestroyContainer);
+ break;
+ }
+}
+
+/*
+ * --------------------------------------------------------------
+ *
+ * ToplevelEventProc --
+ *
+ * Some applications assume that they are always a toplevel
+ * window and play tricks accordingly. For example, Netscape
+ * positions menus in relation to the toplevel. But if the
+ * container's toplevel is moved, this positioning is wrong.
+ * So watch if the toplevel is moved.
+ *
+ * [This would be easier and cleaner if Tk toplevels weren't so
+ * botched by the addition of menubars. It's not enough to
+ * track the )
+ *
+ * Results:
+ * None.
+ *
+ * --------------------------------------------------------------
+ */
+static void
+ToplevelEventProc(clientData, eventPtr)
+ ClientData clientData; /* Information about the tab window. */
+ XEvent *eventPtr; /* Information about event. */
+{
+ Container *cntrPtr = clientData;
+
+ if ((cntrPtr->adopted != None) && (cntrPtr->tkwin != NULL) &&
+ (eventPtr->type == ConfigureNotify)) {
+ cntrPtr->flags |= CONTAINER_MOVE;
+ EventuallyRedraw(cntrPtr);
+ }
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * DestroyContainer --
+ *
+ * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
+ * to clean up the internal structure of the widget at a safe
+ * time (when no-one is using it anymore).
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Everything associated with the widget is freed up.
+ *
+ * ----------------------------------------------------------------------
+ */
+static void
+DestroyContainer(dataPtr)
+ DestroyData dataPtr; /* Pointer to the widget record. */
+{
+ Container *cntrPtr = (Container *) dataPtr;
+
+ if (cntrPtr->highlightGC != NULL) {
+ Tk_FreeGC(cntrPtr->display, cntrPtr->highlightGC);
+ }
+ if (cntrPtr->flags & CONTAINER_INIT) {
+ Tk_DeleteGenericHandler(AdoptedWindowEventProc, cntrPtr);
+ }
+ if (cntrPtr->tkToplevel != NULL) {
+ Tk_DeleteEventHandler(cntrPtr->tkToplevel, StructureNotifyMask,
+ ToplevelEventProc, cntrPtr);
+ }
+ Tk_FreeOptions(configSpecs, (char *)cntrPtr, cntrPtr->display, 0);
+ Blt_Free(cntrPtr);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * ConfigureContainer --
+ *
+ * This procedure is called to process an argv/argc list, plus
+ * the Tk option database, in order to configure (or reconfigure)
+ * the widget.
+ *
+ * Results:
+ * The return value is a standard Tcl result. If TCL_ERROR is
+ * returned, then interp->result contains an error message.
+ *
+ * Side Effects:
+ * Configuration information, such as text string, colors, font,
+ * etc. get set for cntrPtr; old resources get freed, if there
+ * were any. The widget is redisplayed.
+ *
+ * ----------------------------------------------------------------------
+ */
+static int
+ConfigureContainer(interp, cntrPtr, argc, argv, flags)
+ Tcl_Interp *interp; /* Interpreter to report errors. */
+ Container *cntrPtr; /* Information about widget; may or
+ * may not already have values for
+ * some fields. */
+ int argc;
+ char **argv;
+ int flags;
+{
+ XGCValues gcValues;
+ unsigned long gcMask;
+ GC newGC;
+ int width, height;
+
+ if (Tk_ConfigureWidget(interp, cntrPtr->tkwin, configSpecs, argc, argv,
+ (char *)cntrPtr, flags) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ cntrPtr->inset = cntrPtr->borderWidth + cntrPtr->highlightWidth;
+ if (Tk_WindowId(cntrPtr->tkwin) == None) {
+ Tk_MakeWindowExist(cntrPtr->tkwin);
+ }
+ if (GetAdoptedWindowGeometry(interp, cntrPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (Blt_ConfigModified(configSpecs, "-window", "-name", "-command",
+ (char *)NULL)) {
+ cntrPtr->flags &= ~CONTAINER_MAPPED;
+ if (cntrPtr->adopted != None) {
+ if (Blt_ReparentWindow(cntrPtr->display, cntrPtr->adopted,
+ Tk_WindowId(cntrPtr->tkwin), cntrPtr->inset,
+ cntrPtr->inset) != TCL_OK) {
+ Tcl_AppendResult(interp, "can't adopt window \"",
+ NameOfId(cntrPtr->display, cntrPtr->adopted),
+ "\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+ XSelectInput(cntrPtr->display, cntrPtr->adopted,
+ StructureNotifyMask);
+ if ((cntrPtr->flags & CONTAINER_INIT) == 0) {
+ Tk_CreateGenericHandler(AdoptedWindowEventProc, cntrPtr);
+ cntrPtr->flags |= CONTAINER_INIT;
+ }
+ }
+ }
+ /* Add the designated inset to the requested dimensions. */
+ width = cntrPtr->origWidth + 2 * cntrPtr->inset;
+ height = cntrPtr->origHeight + 2 * cntrPtr->inset;
+
+ if (cntrPtr->reqWidth > 0) {
+ width = cntrPtr->reqWidth;
+ }
+ if (cntrPtr->reqHeight > 0) {
+ height = cntrPtr->reqHeight;
+ }
+ /* Set the requested width and height for the container. */
+ if ((Tk_ReqWidth(cntrPtr->tkwin) != width) ||
+ (Tk_ReqHeight(cntrPtr->tkwin) != height)) {
+ Tk_GeometryRequest(cntrPtr->tkwin, width, height);
+ }
+
+ /*
+ * GC for focus highlight.
+ */
+ gcMask = GCForeground;
+ gcValues.foreground = cntrPtr->highlightColor->pixel;
+ newGC = Tk_GetGC(cntrPtr->tkwin, gcMask, &gcValues);
+ if (cntrPtr->highlightGC != NULL) {
+ Tk_FreeGC(cntrPtr->display, cntrPtr->highlightGC);
+ }
+ cntrPtr->highlightGC = newGC;
+
+ EventuallyRedraw(cntrPtr);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ContainerInstCmdDeleteProc --
+ *
+ * This procedure can be called if the window was destroyed
+ * (tkwin will be NULL) and the command was deleted
+ * automatically. In this case, we need to do nothing.
+ *
+ * Otherwise this routine was called because the command was
+ * deleted. Then we need to clean-up and destroy the widget.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The widget is destroyed.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+ContainerInstCmdDeleteProc(clientData)
+ ClientData clientData; /* Pointer to widget record for widget. */
+{
+ Container *cntrPtr = clientData;
+
+ if (cntrPtr->tkwin != NULL) {
+ Tk_Window tkwin;
+
+ tkwin = cntrPtr->tkwin;
+ cntrPtr->tkwin = NULL;
+ Tk_DestroyWindow(tkwin);
+#ifdef ITCL_NAMESPACES
+ Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL);
+#endif /* ITCL_NAMESPACES */
+ }
+}
+
+/*
+ * ------------------------------------------------------------------------
+ *
+ * ContainerCmd --
+ *
+ * This procedure is invoked to process the Tcl command that
+ * corresponds to a widget managed by this module. See the user
+ * documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side Effects:
+ * See the user documentation.
+ *
+ * -----------------------------------------------------------------------
+ */
+/* ARGSUSED */
+static int
+ContainerCmd(clientData, interp, argc, argv)
+ ClientData clientData; /* Main window associated with interpreter. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ Container *cntrPtr;
+ Tk_Window tkwin;
+ unsigned int mask;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " pathName ?option value?...\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+ tkwin = Tk_MainWindow(interp);
+ tkwin = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *)NULL);
+ if (tkwin == NULL) {
+ return TCL_ERROR;
+ }
+ cntrPtr = Blt_Calloc(1, sizeof(Container));
+ assert(cntrPtr);
+ cntrPtr->tkwin = tkwin;
+ cntrPtr->display = Tk_Display(tkwin);
+ cntrPtr->interp = interp;
+ cntrPtr->flags = 0;
+ cntrPtr->timeout = SEARCH_INTERVAL;
+ cntrPtr->borderWidth = cntrPtr->highlightWidth = 2;
+ cntrPtr->relief = TK_RELIEF_SUNKEN;
+ Tk_SetClass(tkwin, "Container");
+#if (TK_MAJOR_VERSION > 4)
+ Blt_SetWindowInstanceData(tkwin, cntrPtr);
+#endif
+ if (ConfigureContainer(interp, cntrPtr, argc - 2, argv + 2, 0) != TCL_OK) {
+ Tk_DestroyWindow(cntrPtr->tkwin);
+ return TCL_ERROR;
+ }
+ mask = (StructureNotifyMask | ExposureMask | FocusChangeMask);
+ Tk_CreateEventHandler(tkwin, mask, ContainerEventProc, cntrPtr);
+ cntrPtr->cmdToken = Tcl_CreateCommand(interp, argv[1], ContainerInstCmd,
+ cntrPtr, ContainerInstCmdDeleteProc);
+#ifdef ITCL_NAMESPACES
+ Itk_SetWidgetCommand(cntrPtr->tkwin, cntrPtr->cmdToken);
+#endif
+ Tk_MakeWindowExist(tkwin);
+
+ Tcl_SetResult(interp, Tk_PathName(cntrPtr->tkwin), TCL_VOLATILE);
+ return TCL_OK;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * DisplayContainer --
+ *
+ * This procedure is invoked to display the widget.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The widget is redisplayed.
+ *
+ * ----------------------------------------------------------------------
+ */
+static void
+DisplayContainer(clientData)
+ ClientData clientData; /* Information about widget. */
+{
+ Container *cntrPtr = clientData;
+ Drawable drawable;
+ int width, height;
+
+ cntrPtr->flags &= ~CONTAINER_REDRAW;
+ if (cntrPtr->tkwin == NULL) {
+ return; /* Window has been destroyed. */
+ }
+ if (!Tk_IsMapped(cntrPtr->tkwin)) {
+ return;
+ }
+ drawable = Tk_WindowId(cntrPtr->tkwin);
+
+#ifndef WIN32
+ if (cntrPtr->tkToplevel == NULL) {
+ Window window;
+ Tk_Window tkToplevel;
+
+ /* Create an event handler for the toplevel of the container. */
+ tkToplevel = Blt_Toplevel(cntrPtr->tkwin);
+ window = Blt_GetRealWindowId(tkToplevel);
+ cntrPtr->tkToplevel = Tk_IdToWindow(cntrPtr->display, window);
+ if (cntrPtr->tkToplevel != NULL) {
+ Tk_CreateEventHandler(cntrPtr->tkToplevel, StructureNotifyMask,
+ ToplevelEventProc, cntrPtr);
+ }
+ }
+#endif /* WIN32 */
+ if (cntrPtr->adopted != None) {
+#ifndef WIN32
+ if (cntrPtr->flags & CONTAINER_MOVE) {
+ /*
+ * Some applications like Netscape cache its location to
+ * position its popup menus. But when it's reparented, it
+ * thinks it's always at the same position. It doesn't
+ * know when the container's moved. The hack here is to
+ * force the application to update its coordinates by
+ * moving the adopted window (over by 1 pixel and
+ * then back in case the application is comparing the last
+ * location).
+ */
+ XMoveWindow(cntrPtr->display, cntrPtr->adopted,
+ cntrPtr->inset + 1, cntrPtr->inset + 1);
+ XMoveWindow(cntrPtr->display, cntrPtr->adopted,
+ cntrPtr->inset, cntrPtr->inset);
+ cntrPtr->flags &= ~CONTAINER_MOVE;
+ }
+#endif /* WIN32 */
+ /* Compute the available space inside the container. */
+ width = Tk_Width(cntrPtr->tkwin) - (2 * cntrPtr->inset);
+ height = Tk_Height(cntrPtr->tkwin) - (2 * cntrPtr->inset);
+
+ if ((cntrPtr->adoptedX != cntrPtr->inset) ||
+ (cntrPtr->adoptedY != cntrPtr->inset) ||
+ (cntrPtr->adoptedWidth != width) ||
+ (cntrPtr->adoptedHeight != height)) {
+ /* Resize the window to the new size */
+ if (width < 1) {
+ width = 1;
+ }
+ if (height < 1) {
+ height = 1;
+ }
+ XMoveResizeWindow(cntrPtr->display, cntrPtr->adopted,
+ cntrPtr->inset, cntrPtr->inset, width, height);
+ cntrPtr->adoptedWidth = width;
+ cntrPtr->adoptedHeight = height;
+ cntrPtr->adoptedX = cntrPtr->adoptedY = cntrPtr->inset;
+ if (cntrPtr->tkAdopted != NULL) {
+ Tk_ResizeWindow(cntrPtr->tkAdopted, width, height);
+ }
+ }
+#ifndef WIN32
+ if (!(cntrPtr->flags & CONTAINER_MAPPED)) {
+ XMapWindow(cntrPtr->display, cntrPtr->adopted);
+ cntrPtr->flags |= CONTAINER_MAPPED;
+ }
+#endif
+ if (cntrPtr->borderWidth > 0) {
+ Tk_Draw3DRectangle(cntrPtr->tkwin, drawable, cntrPtr->border,
+ cntrPtr->highlightWidth, cntrPtr->highlightWidth,
+ Tk_Width(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth,
+ Tk_Height(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth,
+ cntrPtr->borderWidth, cntrPtr->relief);
+ }
+ } else {
+ Tk_Fill3DRectangle(cntrPtr->tkwin, drawable, cntrPtr->border,
+ cntrPtr->highlightWidth, cntrPtr->highlightWidth,
+ Tk_Width(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth,
+ Tk_Height(cntrPtr->tkwin) - 2 * cntrPtr->highlightWidth,
+ cntrPtr->borderWidth, cntrPtr->relief);
+ }
+
+ /* Draw focus highlight ring. */
+ if (cntrPtr->highlightWidth > 0) {
+ XColor *color;
+ GC gc;
+
+ color = (cntrPtr->flags & CONTAINER_FOCUS)
+ ? cntrPtr->highlightColor : cntrPtr->highlightBgColor;
+ gc = Tk_GCForColor(color, drawable);
+ Tk_DrawFocusHighlight(cntrPtr->tkwin, gc, cntrPtr->highlightWidth,
+ drawable);
+ }
+}
+
+#ifdef notdef
+/*
+ *----------------------------------------------------------------------
+ *
+ * SendOp --
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+SendOp(cntrPtr, interp, argc, argv)
+ Container *cntrPtr;
+ Tcl_Interp *interp;
+ int argc; /* Not used. */
+ char **argv;
+{
+
+ if (cntrPtr->adopted != None) {
+ XEvent event;
+ char *p;
+ KeySym symbol;
+ int xid;
+ Window window;
+
+ if (Tcl_GetInt(interp, argv[2], &xid) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ window = (Window)xid;
+ event.xkey.type = KeyPress;
+ event.xkey.serial = 0;
+ event.xkey.display = cntrPtr->display;
+ event.xkey.window = event.xkey.subwindow = window;
+ event.xkey.time = CurrentTime;
+ event.xkey.x = event.xkey.x = 100;
+ event.xkey.root =
+ RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
+ event.xkey.x_root = Tk_X(cntrPtr->tkwin) + cntrPtr->inset;
+ event.xkey.x_root = Tk_Y(cntrPtr->tkwin) + cntrPtr->inset;
+ event.xkey.state = 0;
+ event.xkey.same_screen = TRUE;
+
+ for (p = argv[3]; *p != '\0'; p++) {
+ if (*p == '\r') {
+ symbol = XStringToKeysym("Return");
+ } else if (*p == ' ') {
+ symbol = XStringToKeysym("space");
+ } else {
+ char save;
+
+ save = *(p+1);
+ *(p+1) = '\0';
+ symbol = XStringToKeysym(p);
+ *(p+1) = save;
+ }
+ event.xkey.keycode = XKeysymToKeycode(cntrPtr->display, symbol);
+ event.xkey.type = KeyPress;
+ if (!XSendEvent(cntrPtr->display, window, False, KeyPress, &event)) {
+ fprintf(stderr, "send press event failed\n");
+ }
+ event.xkey.type = KeyRelease;
+ if (!XSendEvent(cntrPtr->display, window, False, KeyRelease,
+ &event)) {
+ fprintf(stderr, "send release event failed\n");
+ }
+ }
+ }
+ return TCL_OK;
+}
+#endif
+
+#ifndef WIN32
+/*
+ *----------------------------------------------------------------------
+ *
+ * FindOp --
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+FindOp(cntrPtr, interp, argc, argv)
+ Container *cntrPtr;
+ Tcl_Interp *interp;
+ int argc; /* Not used. */
+ char **argv;
+{
+ Window root;
+ SearchInfo search;
+
+ memset(&search, 0, sizeof(search));
+ search.pattern = argv[3];
+ Tcl_DStringInit(&(search.dString));
+ search.saveNames = TRUE; /* Indicates to record all matching XIDs. */
+ if (strcmp(argv[2], "-name") == 0) {
+ search.proc = NameSearch;
+ } else if (strcmp(argv[2], "-command") == 0) {
+ search.proc = CmdSearch;
+ } else {
+ Tcl_AppendResult(interp, "missing \"-name\" or \"-command\" switch",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ root = RootWindow(cntrPtr->display, Tk_ScreenNumber(cntrPtr->tkwin));
+ (*search.proc)(cntrPtr->display, root, &search);
+ Tcl_DStringResult(interp, &search.dString);
+ return TCL_OK;
+}
+#endif /*WIN32*/
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CgetOp --
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+CgetOp(cntrPtr, interp, argc, argv)
+ Container *cntrPtr;
+ Tcl_Interp *interp;
+ int argc; /* Not used. */
+ char **argv;
+{
+ return Tk_ConfigureValue(interp, cntrPtr->tkwin, configSpecs,
+ (char *)cntrPtr, argv[2], 0);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ConfigureOp --
+ *
+ * This procedure is called to process an argv/argc list, plus
+ * the Tk option database, in order to configure (or reconfigure)
+ * the widget.
+ *
+ * Results:
+ * A standard Tcl result. If TCL_ERROR is returned, then
+ * interp->result contains an error message.
+ *
+ * Side Effects:
+ * Configuration information, such as text string, colors, font,
+ * etc. get set for cntrPtr; old resources get freed, if there
+ * were any. The widget is redisplayed.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+ConfigureOp(cntrPtr, interp, argc, argv)
+ Container *cntrPtr;
+ Tcl_Interp *interp;
+ int argc;
+ char **argv;
+{
+ if (argc == 2) {
+ return Tk_ConfigureInfo(interp, cntrPtr->tkwin, configSpecs,
+ (char *)cntrPtr, (char *)NULL, 0);
+ } else if (argc == 3) {
+ return Tk_ConfigureInfo(interp, cntrPtr->tkwin, configSpecs,
+ (char *)cntrPtr, argv[2], 0);
+ }
+ if (ConfigureContainer(interp, cntrPtr, argc - 2, argv + 2,
+ TK_CONFIG_ARGV_ONLY) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ EventuallyRedraw(cntrPtr);
+ return TCL_OK;
+}
+
+/*
+ * --------------------------------------------------------------
+ *
+ * ContainerCmd --
+ *
+ * This procedure is invoked to process the "container" command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ * --------------------------------------------------------------
+ */
+static Blt_OpSpec opSpecs[] =
+{
+ {"cget", 2, (Blt_Op)CgetOp, 3, 3, "option",},
+ {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?option value?...",},
+#ifndef WIN32
+ {"find", 1, (Blt_Op)FindOp, 3, 4, "?-command|-name? pattern",},
+#endif /*WIN32*/
+#ifdef notdef
+ {"send", 1, (Blt_Op)SendOp, 4, 4, "window string",},
+#endif
+};
+
+static int nSpecs = sizeof(opSpecs) / sizeof(Blt_OpSpec);
+
+static int
+ContainerInstCmd(clientData, interp, argc, argv)
+ ClientData clientData; /* Information about the widget. */
+ Tcl_Interp *interp; /* Interpreter to report errors back to. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Vector of argument strings. */
+{
+ Blt_Op proc;
+ Container *cntrPtr = clientData;
+ int result;
+
+ proc = Blt_GetOp(interp, nSpecs, opSpecs, BLT_OP_ARG1, argc, argv, 0);
+ if (proc == NULL) {
+ return TCL_ERROR;
+ }
+ Tcl_Preserve(cntrPtr);
+ result = (*proc)(cntrPtr, interp, argc, argv);
+ Tcl_Release(cntrPtr);
+ return result;
+}
+
+int
+Blt_ContainerInit(interp)
+ Tcl_Interp *interp;
+{
+ static Blt_CmdSpec cmdSpec =
+ {
+ "container", ContainerCmd,
+ };
+ if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) {
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+#endif /* NO_CONTAINER */