diff options
Diffstat (limited to 'blt/src/bltContainer.c')
-rw-r--r-- | blt/src/bltContainer.c | 1701 |
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 */ |