tkFrame.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:60k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkFrame.c --
  3.  *
  4.  * This module implements "frame", "labelframe" and "toplevel" widgets
  5.  *      for the Tk toolkit.  Frames are windows with a background color
  6.  * and possibly a 3-D effect, but not much else in the way of
  7.  * attributes.
  8.  *
  9.  * Copyright (c) 1990-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tkFrame.c,v 1.15.2.4 2007/04/29 02:24:02 das Exp $
  16.  */
  17. #include "default.h"
  18. #include "tkPort.h"
  19. #include "tkInt.h"
  20. /*
  21.  * The following enum is used to define the type of the frame.
  22.  */
  23. enum FrameType {
  24.     TYPE_FRAME, TYPE_TOPLEVEL, TYPE_LABELFRAME
  25. };
  26. /*
  27.  * A data structure of the following type is kept for each
  28.  * frame that currently exists for this process:
  29.  */
  30. typedef struct {
  31.     Tk_Window tkwin; /* Window that embodies the frame.  NULL
  32.  * means that the window has been destroyed
  33.  * but the data structures haven't yet been
  34.  * cleaned up. */
  35.     Display *display; /* Display containing widget.  Used, among
  36.  * other things, so that resources can be
  37.  * freed even after tkwin has gone away. */
  38.     Tcl_Interp *interp; /* Interpreter associated with widget.  Used
  39.  * to delete widget command. */
  40.     Tcl_Command widgetCmd; /* Token for frame's widget command. */
  41.     Tk_OptionTable optionTable; /* Table that defines configuration options
  42.  * available for this widget. */
  43.     char *className; /* Class name for widget (from configuration
  44.  * option).  Malloc-ed. */
  45.     enum FrameType type; /* Type of widget, such as TYPE_FRAME. */
  46.     char *screenName; /* Screen on which widget is created.  Non-null
  47.  * only for top-levels.  Malloc-ed, may be
  48.  * NULL. */
  49.     char *visualName; /* Textual description of visual for window,
  50.  * from -visual option.  Malloc-ed, may be
  51.  * NULL. */
  52.     char *colormapName; /* Textual description of colormap for window,
  53.  * from -colormap option.  Malloc-ed, may be
  54.  * NULL. */
  55.     char *menuName; /* Textual description of menu to use for
  56.  * menubar. Malloc-ed, may be NULL. */
  57.     Colormap colormap; /* If not None, identifies a colormap
  58.  * allocated for this window, which must be
  59.  * freed when the window is deleted. */
  60.     Tk_3DBorder border; /* Structure used to draw 3-D border and
  61.  * background.  NULL means no background
  62.  * or border. */
  63.     int borderWidth; /* Width of 3-D border (if any). */
  64.     int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */
  65.     int highlightWidth; /* Width in pixels of highlight to draw
  66.  * around widget when it has the focus.
  67.  * 0 means don't draw a highlight. */
  68.     XColor *highlightBgColorPtr;
  69. /* Color for drawing traversal highlight
  70.  * area when highlight is off. */
  71.     XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
  72.     int width; /* Width to request for window.  <= 0 means
  73.  * don't request any size. */
  74.     int height; /* Height to request for window.  <= 0 means
  75.  * don't request any size. */
  76.     Tk_Cursor cursor; /* Current cursor for window, or None. */
  77.     char *takeFocus; /* Value of -takefocus option;  not used in
  78.  * the C code, but used by keyboard traversal
  79.  * scripts.  Malloc'ed, but may be NULL. */
  80.     int isContainer; /* 1 means this window is a container, 0 means
  81.  * that it isn't. */
  82.     char *useThis; /* If the window is embedded, this points to
  83.  * the name of the window in which it is
  84.  * embedded (malloc'ed).  For non-embedded
  85.  * windows this is NULL. */
  86.     int flags; /* Various flags;  see below for
  87.  * definitions. */
  88.     Tcl_Obj *padXPtr; /* Value of -padx option: specifies how many
  89.  * pixels of extra space to leave on left and
  90.  * right of child area. */
  91.     int padX; /* Integer value corresponding to padXPtr. */
  92.     Tcl_Obj *padYPtr; /* Value of -padx option: specifies how many
  93.  * pixels of extra space to leave above and
  94.  * below child area. */
  95.     int padY; /* Integer value corresponding to padYPtr. */
  96. } Frame;
  97. /*
  98.  * A data structure of the following type is kept for each labelframe
  99.  * widget managed by this file:
  100.  */
  101. typedef struct {
  102.     Frame frame; /* A pointer to the generic frame structure.
  103.  * This must be the first element of the
  104.  * Labelframe. */
  105.     /*
  106.      * Labelframe specific configuration settings.
  107.      */
  108.     Tcl_Obj *textPtr; /* Value of -text option: specifies text to
  109.  * display in button. */
  110.     Tk_Font tkfont; /* Value of -font option: specifies font
  111.  * to use for display text. */
  112.     XColor *textColorPtr; /* Value of -fg option: specifies foreground
  113.  * color in normal mode. */
  114.     int labelAnchor; /* Value of -labelanchor option: specifies
  115.  * where to place the label. */
  116.     Tk_Window labelWin; /* Value of -labelwidget option: Window to
  117.                                  * use as label for the frame. */
  118.     /*
  119.      * Labelframe specific fields for use with configuration settings above.
  120.      */
  121.     GC textGC; /* GC for drawing text in normal mode. */
  122.     Tk_TextLayout textLayout; /* Stored text layout information. */
  123.     XRectangle labelBox; /* The label's actual size and position. */
  124.     int labelReqWidth; /* The label's requested width. */
  125.     int labelReqHeight; /* The label's requested height. */
  126.     int labelTextX, labelTextY; /* Position of the text to be drawn. */
  127. } Labelframe;
  128. /*
  129.  * The following macros define how many extra pixels to leave
  130.  * around a label's text.
  131.  */
  132. #define LABELSPACING 1
  133. #define LABELMARGIN 4
  134. /*
  135.  * Flag bits for frames:
  136.  *
  137.  * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
  138.  * has already been queued to redraw
  139.  * this window.
  140.  * GOT_FOCUS: Non-zero means this widget currently
  141.  * has the input focus.
  142.  */
  143. #define REDRAW_PENDING 1
  144. #define GOT_FOCUS 4
  145. /*
  146.  * The following enum is used to define a type for the -labelanchor option
  147.  * of the Labelframe widget.  These values are used as indices into the 
  148.  * string table below.
  149.  */
  150. enum labelanchor {
  151.     LABELANCHOR_E, LABELANCHOR_EN, LABELANCHOR_ES,
  152.     LABELANCHOR_N, LABELANCHOR_NE, LABELANCHOR_NW,
  153.     LABELANCHOR_S, LABELANCHOR_SE, LABELANCHOR_SW,
  154.     LABELANCHOR_W, LABELANCHOR_WN, LABELANCHOR_WS
  155. };
  156. static char *labelAnchorStrings[] = {
  157.     "e", "en", "es", "n", "ne", "nw", "s", "se", "sw", "w", "wn", "ws",
  158.     (char *) NULL
  159. };
  160. /*
  161.  * Information used for parsing configuration options.  There are
  162.  * one common table used by all and one table for each widget class.
  163.  */
  164. static Tk_OptionSpec commonOptSpec[] = {
  165.     {TK_OPTION_BORDER, "-background", "background", "Background",
  166. DEF_FRAME_BG_COLOR, -1, Tk_Offset(Frame, border),
  167. TK_OPTION_NULL_OK, (ClientData) DEF_FRAME_BG_MONO, 0},
  168.     {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
  169. (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
  170.     {TK_OPTION_STRING, "-colormap", "colormap", "Colormap",
  171. DEF_FRAME_COLORMAP, -1, Tk_Offset(Frame, colormapName),
  172. TK_OPTION_NULL_OK, 0, 0},
  173.     {TK_OPTION_BOOLEAN, "-container", "container", "Container",
  174. DEF_FRAME_CONTAINER, -1, Tk_Offset(Frame, isContainer),
  175. 0, 0, 0},
  176.     {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
  177. DEF_FRAME_CURSOR, -1, Tk_Offset(Frame, cursor),
  178. TK_OPTION_NULL_OK, 0, 0},
  179.     {TK_OPTION_PIXELS, "-height", "height", "Height",
  180. DEF_FRAME_HEIGHT, -1, Tk_Offset(Frame, height),
  181. 0, 0, 0},
  182.     {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground",
  183. "HighlightBackground", DEF_FRAME_HIGHLIGHT_BG, -1,
  184. Tk_Offset(Frame, highlightBgColorPtr), 0, 0, 0},
  185.     {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
  186. DEF_FRAME_HIGHLIGHT, -1, Tk_Offset(Frame, highlightColorPtr),
  187. 0, 0, 0},
  188.     {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
  189. "HighlightThickness", DEF_FRAME_HIGHLIGHT_WIDTH, -1,
  190. Tk_Offset(Frame, highlightWidth), 0, 0, 0},
  191.     {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
  192. DEF_FRAME_PADX, Tk_Offset(Frame, padXPtr),
  193. Tk_Offset(Frame, padX), 0, 0, 0},
  194.     {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
  195. DEF_FRAME_PADY, Tk_Offset(Frame, padYPtr),
  196. Tk_Offset(Frame, padY), 0, 0, 0},
  197.     {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
  198. DEF_FRAME_TAKE_FOCUS, -1, Tk_Offset(Frame, takeFocus),
  199. TK_OPTION_NULL_OK, 0, 0},
  200.     {TK_OPTION_STRING, "-visual", "visual", "Visual",
  201. DEF_FRAME_VISUAL, -1, Tk_Offset(Frame, visualName),
  202. TK_OPTION_NULL_OK, 0, 0},
  203.     {TK_OPTION_PIXELS, "-width", "width", "Width",
  204. DEF_FRAME_WIDTH, -1, Tk_Offset(Frame, width),
  205. 0, 0, 0},
  206.     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
  207. (char *) NULL, 0, 0, 0, 0, 0}
  208. };
  209. static Tk_OptionSpec frameOptSpec[] = {
  210.     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
  211. (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
  212.     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  213. DEF_FRAME_BORDER_WIDTH, -1, Tk_Offset(Frame, borderWidth),
  214.         0, 0, 0},
  215.     {TK_OPTION_STRING, "-class", "class", "Class",
  216. DEF_FRAME_CLASS, -1, Tk_Offset(Frame, className),
  217. 0, 0, 0},
  218.     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
  219. DEF_FRAME_RELIEF, -1, Tk_Offset(Frame, relief),
  220. 0, 0, 0},
  221.     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
  222. (char *) NULL, 0, 0, 0, (ClientData) commonOptSpec, 0}
  223. };
  224. static Tk_OptionSpec toplevelOptSpec[] = {
  225.     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
  226. (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
  227.     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  228. DEF_FRAME_BORDER_WIDTH, -1, Tk_Offset(Frame, borderWidth),
  229.         0, 0, 0},
  230.     {TK_OPTION_STRING, "-class", "class", "Class",
  231. DEF_TOPLEVEL_CLASS, -1, Tk_Offset(Frame, className),
  232. 0, 0, 0},
  233.     {TK_OPTION_STRING, "-menu", "menu", "Menu",
  234. DEF_TOPLEVEL_MENU, -1, Tk_Offset(Frame, menuName),
  235. TK_OPTION_NULL_OK, 0, 0},
  236.     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
  237. DEF_FRAME_RELIEF, -1, Tk_Offset(Frame, relief),
  238. 0, 0, 0},
  239.     {TK_OPTION_STRING, "-screen", "screen", "Screen",
  240. DEF_TOPLEVEL_SCREEN, -1, Tk_Offset(Frame, screenName),
  241. TK_OPTION_NULL_OK, 0, 0},
  242.     {TK_OPTION_STRING, "-use", "use", "Use",
  243. DEF_TOPLEVEL_USE, -1, Tk_Offset(Frame, useThis),
  244. TK_OPTION_NULL_OK, 0, 0},
  245.     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
  246. (char *) NULL, 0, 0, 0, (ClientData) commonOptSpec, 0}
  247. };
  248. static Tk_OptionSpec labelframeOptSpec[] = {
  249.     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
  250. (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
  251.     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  252. DEF_LABELFRAME_BORDER_WIDTH, -1, Tk_Offset(Frame, borderWidth),
  253.         0, 0, 0},
  254.     {TK_OPTION_STRING, "-class", "class", "Class",
  255. DEF_LABELFRAME_CLASS, -1, Tk_Offset(Frame, className),
  256. 0, 0, 0},
  257.     {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
  258. (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
  259.     {TK_OPTION_FONT, "-font", "font", "Font",
  260. DEF_LABELFRAME_FONT, -1, Tk_Offset(Labelframe, tkfont), 0, 0, 0},
  261.     {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
  262. DEF_LABELFRAME_FG, -1, Tk_Offset(Labelframe, textColorPtr), 0, 0, 0},
  263.     {TK_OPTION_STRING_TABLE, "-labelanchor", "labelAnchor", "LabelAnchor",
  264. DEF_LABELFRAME_LABELANCHOR, -1, Tk_Offset(Labelframe, labelAnchor),
  265.         0, (ClientData) labelAnchorStrings, 0},
  266.     {TK_OPTION_WINDOW, "-labelwidget", "labelWidget", "LabelWidget",
  267.         (char *) NULL, -1, Tk_Offset(Labelframe, labelWin),
  268.         TK_OPTION_NULL_OK, 0, 0},
  269.     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
  270. DEF_LABELFRAME_RELIEF, -1, Tk_Offset(Frame, relief),
  271. 0, 0, 0},
  272.     {TK_OPTION_STRING, "-text", "text", "Text",
  273. DEF_LABELFRAME_TEXT, Tk_Offset(Labelframe, textPtr), -1,
  274. TK_OPTION_NULL_OK, 0, 0},
  275.     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
  276. (char *) NULL, 0, 0, 0, (ClientData) commonOptSpec, 0}
  277. };
  278. /*
  279.  * Class names for widgets, indexed by FrameType.
  280.  */
  281. static char *classNames[] = {"Frame", "Toplevel", "Labelframe"};
  282. /*
  283.  * The following table maps from FrameType to the option template for
  284.  * that class of widgets.
  285.  */
  286. static Tk_OptionSpec *optionSpecs[] = {
  287.     frameOptSpec,
  288.     toplevelOptSpec,
  289.     labelframeOptSpec,
  290. };
  291. /*
  292.  * Forward declarations for procedures defined later in this file:
  293.  */
  294. static void ComputeFrameGeometry _ANSI_ARGS_((Frame *framePtr));
  295. static int ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp,
  296.     Frame *framePtr, int objc, Tcl_Obj *CONST objv[]));
  297. static int CreateFrame _ANSI_ARGS_((ClientData clientData,
  298.     Tcl_Interp *interp, int objc, Tcl_Obj *CONST argv[],
  299.     enum FrameType type, char *appName));
  300. static void DestroyFrame _ANSI_ARGS_((char *memPtr));
  301. static void DestroyFramePartly _ANSI_ARGS_((Frame *framePtr));
  302. static void DisplayFrame _ANSI_ARGS_((ClientData clientData));
  303. static void FrameCmdDeletedProc _ANSI_ARGS_((
  304.     ClientData clientData));
  305. static void FrameEventProc _ANSI_ARGS_((ClientData clientData,
  306.     XEvent *eventPtr));
  307. static void FrameLostSlaveProc _ANSI_ARGS_((
  308.     ClientData clientData, Tk_Window tkwin));
  309. static void FrameRequestProc _ANSI_ARGS_((ClientData clientData,
  310.     Tk_Window tkwin));
  311. static void FrameStructureProc _ANSI_ARGS_((
  312.     ClientData clientData, XEvent *eventPtr));
  313. static int FrameWidgetObjCmd _ANSI_ARGS_((ClientData clientData,
  314.     Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
  315. static void FrameWorldChanged _ANSI_ARGS_((
  316.     ClientData instanceData));
  317. static void MapFrame _ANSI_ARGS_((ClientData clientData));
  318. /*
  319.  * The structure below defines frame class behavior by means of procedures
  320.  * that can be invoked from generic window code.
  321.  */
  322. static Tk_ClassProcs frameClass = {
  323.     sizeof(Tk_ClassProcs), /* size */
  324.     FrameWorldChanged /* worldChangedProc */
  325. };
  326. /*
  327.  * The structure below defines the official type record for the
  328.  * labelframe's geometry manager:
  329.  */
  330. static Tk_GeomMgr frameGeomType = {
  331.     "labelframe", /* name */
  332.     FrameRequestProc, /* requestProc */
  333.     FrameLostSlaveProc /* lostSlaveProc */
  334. };
  335. /*
  336.  *--------------------------------------------------------------
  337.  *
  338.  * Tk_FrameObjCmd, Tk_ToplevelObjCmd, Tk_LabelframeObjCmd --
  339.  *
  340.  * These procedures are invoked to process the "frame",
  341.  *      "toplevel" and "labelframe" Tcl commands.  See the user
  342.  *      documentation for details on what they do.
  343.  *
  344.  * Results:
  345.  * A standard Tcl result.
  346.  *
  347.  * Side effects:
  348.  * See the user documentation.  These procedures are just wrappers;
  349.  * they call CreateFrame to do all of the real work.
  350.  *
  351.  *--------------------------------------------------------------
  352.  */
  353. int
  354. Tk_FrameObjCmd(clientData, interp, objc, objv)
  355.     ClientData clientData; /* Either NULL or pointer to option table. */
  356.     Tcl_Interp *interp; /* Current interpreter. */
  357.     int objc; /* Number of arguments. */
  358.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  359. {
  360.     return CreateFrame(clientData, interp, objc, objv, TYPE_FRAME,
  361.     (char *) NULL);
  362. }
  363. int
  364. Tk_ToplevelObjCmd(clientData, interp, objc, objv)
  365.     ClientData clientData; /* Either NULL or pointer to option table. */
  366.     Tcl_Interp *interp; /* Current interpreter. */
  367.     int objc; /* Number of arguments. */
  368.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  369. {
  370.     return CreateFrame(clientData, interp, objc, objv, TYPE_TOPLEVEL,
  371.     (char *) NULL);
  372. }
  373. int
  374. Tk_LabelframeObjCmd(clientData, interp, objc, objv)
  375.     ClientData clientData; /* Either NULL or pointer to option table. */
  376.     Tcl_Interp *interp; /* Current interpreter. */
  377.     int objc; /* Number of arguments. */
  378.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  379. {
  380.     return CreateFrame(clientData, interp, objc, objv, TYPE_LABELFRAME,
  381.     (char *) NULL);
  382. }
  383. /*
  384.  *--------------------------------------------------------------
  385.  *
  386.  * TkCreateFrame --
  387.  *
  388.  * This procedure is the old command procedure for the "frame"
  389.  *      and "toplevel" commands.  Now it is used directly by Tk_Init to
  390.  *      create a new main window.  See the user documentation for the
  391.  *      "frame" and "toplevel" commands for details on what it does.
  392.  *
  393.  * Results:
  394.  * A standard Tcl result.
  395.  *
  396.  * Side effects:
  397.  * See the user documentation.
  398.  *
  399.  *--------------------------------------------------------------
  400.  */
  401. int
  402. TkCreateFrame(clientData, interp, argc, argv, toplevel, appName)
  403.     ClientData clientData; /* Either NULL or pointer to option table. */
  404.     Tcl_Interp *interp; /* Current interpreter. */
  405.     int argc; /* Number of arguments. */
  406.     char **argv; /* Argument strings. */
  407.     int toplevel; /* Non-zero means create a toplevel window,
  408.  * zero means create a frame. */
  409.     char *appName; /* Should only be non-NULL if there is no main
  410.  * window associated with the interpreter.
  411.  * Gives the base name to use for the
  412.  * new application. */
  413. {
  414.     int result, i;
  415.     Tcl_Obj **objv = (Tcl_Obj **) ckalloc((argc+1) * sizeof(Tcl_Obj **));
  416.     for (i=0; i<argc; i++) {
  417. objv[i] = Tcl_NewStringObj(argv[i], -1);
  418. Tcl_IncrRefCount(objv[i]);
  419.     }
  420.     objv[argc] = NULL;
  421.     result = CreateFrame(clientData, interp, argc, objv,
  422.     toplevel ? TYPE_TOPLEVEL : TYPE_FRAME, appName);
  423.     for (i=0; i<argc; i++) {
  424. Tcl_DecrRefCount(objv[i]);
  425.     }
  426.     ckfree((char *) objv);
  427.     return result;
  428. }
  429. static int
  430. CreateFrame(clientData, interp, objc, objv, type, appName)
  431.     ClientData clientData; /* NULL. */
  432.     Tcl_Interp *interp; /* Current interpreter. */
  433.     int objc; /* Number of arguments. */
  434.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  435.     enum FrameType type; /* What widget type to create. */
  436.     char *appName; /* Should only be non-NULL if there are no
  437.  * Main window associated with the interpreter.
  438.  * Gives the base name to use for the
  439.  * new application. */
  440. {
  441.     Tk_Window tkwin;
  442.     Frame *framePtr;
  443.     Tk_OptionTable optionTable;
  444.     Tk_Window new;
  445.     CONST char *className, *screenName, *visualName, *colormapName, *arg, *useOption;
  446.     int i, c, depth, length;
  447.     unsigned int mask;
  448.     Colormap colormap;
  449.     Visual *visual;
  450.     if (objc < 2) {
  451. Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
  452. return TCL_ERROR;
  453.     }
  454.     /*
  455.      * Create the option table for this widget class.  If it has already
  456.      * been created, the cached pointer will be returned.
  457.      */
  458.     optionTable = Tk_CreateOptionTable(interp, optionSpecs[type]);
  459.     /*
  460.      * Pre-process the argument list.  Scan through it to find any
  461.      * "-class", "-screen", "-visual", and "-colormap" options.  These
  462.      * arguments need to be processed specially, before the window
  463.      * is configured using the usual Tk mechanisms.
  464.      */
  465.     className = colormapName = screenName = visualName = useOption = NULL;
  466.     colormap = None;
  467.     for (i = 2; i < objc; i += 2) {
  468. arg = Tcl_GetStringFromObj(objv[i], &length);
  469. if (length < 2) {
  470.     continue;
  471. }
  472. c = arg[1];
  473. if ((c == 'c') && (strncmp(arg, "-class", (unsigned) length) == 0)
  474. && (length >= 3)) {
  475.     className = Tcl_GetString(objv[i+1]);
  476. } else if ((c == 'c')
  477. && (strncmp(arg, "-colormap", (unsigned) length) == 0)) {
  478.     colormapName = Tcl_GetString(objv[i+1]);
  479. } else if ((c == 's') && (type == TYPE_TOPLEVEL)
  480. && (strncmp(arg, "-screen", (unsigned) length) == 0)) {
  481.     screenName = Tcl_GetString(objv[i+1]);
  482. } else if ((c == 'u') && (type == TYPE_TOPLEVEL)
  483. && (strncmp(arg, "-use", (unsigned) length) == 0)) {
  484.     useOption = Tcl_GetString(objv[i+1]);
  485. } else if ((c == 'v')
  486. && (strncmp(arg, "-visual", (unsigned) length) == 0)) {
  487.     visualName = Tcl_GetString(objv[i+1]);
  488. }
  489.     }
  490.     /*
  491.      * Create the window, and deal with the special options -use,
  492.      * -classname, -colormap, -screenname, and -visual.  These options
  493.      * must be handle before calling ConfigureFrame below, and they must
  494.      * also be processed in a particular order, for the following
  495.      * reasons:
  496.      * 1. Must set the window's class before calling ConfigureFrame,
  497.      *    so that unspecified options are looked up in the option
  498.      *    database using the correct class.
  499.      * 2. Must set visual information before calling ConfigureFrame
  500.      *    so that colors are allocated in a proper colormap.
  501.      * 3. Must call TkpUseWindow before setting non-default visual
  502.      *    information, since TkpUseWindow changes the defaults.
  503.      */
  504.     if (screenName == NULL) {
  505. screenName = (type == TYPE_TOPLEVEL) ? "" : NULL;
  506.     }
  507.     /*
  508.      * Main window associated with interpreter.
  509.      * If we're called by Tk_Init to create a
  510.      * new application, then this is NULL.
  511.      */
  512.     tkwin = Tk_MainWindow(interp);
  513.     if (tkwin != NULL) {
  514. new = Tk_CreateWindowFromPath(interp, tkwin, Tcl_GetString(objv[1]),
  515. screenName);
  516.     } else if (appName == NULL) {
  517. /*
  518.  * This occurs when someone tried to create a frame/toplevel
  519.  * while we are being destroyed.  Let an error be thrown.
  520.  */
  521. Tcl_AppendResult(interp, "unable to create widget "",
  522. Tcl_GetString(objv[1]), """, (char *) NULL);
  523. new = NULL;
  524.     } else {
  525. /*
  526.  * We were called from Tk_Init;  create a new application.
  527.  */
  528. new = TkCreateMainWindow(interp, screenName, appName);
  529.     }
  530.     if (new == NULL) {
  531. goto error;
  532.     }
  533.     if (className == NULL) {
  534. className = Tk_GetOption(new, "class", "Class");
  535. if (className == NULL) {
  536.     className = classNames[type];
  537. }
  538.     }
  539.     Tk_SetClass(new, className);
  540.     if (useOption == NULL) {
  541. useOption = Tk_GetOption(new, "use", "Use");
  542.     }
  543.     if ((useOption != NULL) && (*useOption != 0)) {
  544. if (TkpUseWindow(interp, new, useOption) != TCL_OK) {
  545.     goto error;
  546. }
  547.     }
  548.     if (visualName == NULL) {
  549. visualName = Tk_GetOption(new, "visual", "Visual");
  550.     }
  551.     if (colormapName == NULL) {
  552. colormapName = Tk_GetOption(new, "colormap", "Colormap");
  553.     }
  554.     if ((colormapName != NULL) && (*colormapName == 0)) {
  555. colormapName = NULL;
  556.     }
  557.     if (visualName != NULL) {
  558. visual = Tk_GetVisual(interp, new, visualName, &depth,
  559. (colormapName == NULL) ? &colormap : (Colormap *) NULL);
  560. if (visual == NULL) {
  561.     goto error;
  562. }
  563. Tk_SetWindowVisual(new, visual, depth, colormap);
  564.     }
  565.     if (colormapName != NULL) {
  566. colormap = Tk_GetColormap(interp, new, colormapName);
  567. if (colormap == None) {
  568.     goto error;
  569. }
  570. Tk_SetWindowColormap(new, colormap);
  571.     }
  572.     /*
  573.      * For top-level windows, provide an initial geometry request of
  574.      * 200x200,  just so the window looks nicer on the screen if it
  575.      * doesn't request a size for itself.
  576.      */
  577.     if (type == TYPE_TOPLEVEL) {
  578. Tk_GeometryRequest(new, 200, 200);
  579.     }
  580.     /*
  581.      * Create the widget record, process configuration options, and
  582.      * create event handlers.  Then fill in a few additional fields
  583.      * in the widget record from the special options.
  584.      */
  585.     if (type == TYPE_LABELFRAME) {
  586. framePtr = (Frame *) ckalloc(sizeof(Labelframe));
  587. memset((void *) framePtr, 0, (sizeof(Labelframe)));
  588.     } else {
  589. framePtr = (Frame *) ckalloc(sizeof(Frame));
  590. memset((void *) framePtr, 0, (sizeof(Frame)));
  591.     }
  592.     framePtr->tkwin = new;
  593.     framePtr->display = Tk_Display(new);
  594.     framePtr->interp = interp;
  595.     framePtr->widgetCmd = Tcl_CreateObjCommand(interp,
  596.     Tk_PathName(new), FrameWidgetObjCmd,
  597.     (ClientData) framePtr, FrameCmdDeletedProc);
  598.     framePtr->optionTable = optionTable;
  599.     framePtr->type = type;
  600.     framePtr->colormap = colormap;
  601.     framePtr->relief = TK_RELIEF_FLAT;
  602.     framePtr->cursor = None;
  603.     if (framePtr->type == TYPE_LABELFRAME) {
  604. Labelframe *labelframePtr = (Labelframe *) framePtr;
  605. labelframePtr->labelAnchor = LABELANCHOR_NW;
  606. labelframePtr->textGC = None;
  607.     }
  608.     /*
  609.      * Store backreference to frame widget in window structure.
  610.      */
  611.     Tk_SetClassProcs(new, &frameClass, (ClientData) framePtr);
  612.     mask = ExposureMask | StructureNotifyMask | FocusChangeMask;
  613.     if (type == TYPE_TOPLEVEL) {
  614.         mask |= ActivateMask;
  615.     }
  616.     Tk_CreateEventHandler(new, mask, FrameEventProc, (ClientData) framePtr);
  617.     if ((Tk_InitOptions(interp, (char *) framePtr, optionTable, new)
  618.     != TCL_OK) ||
  619.     (ConfigureFrame(interp, framePtr, objc-2, objv+2) != TCL_OK)) {
  620. goto error;
  621.     }
  622.     if ((framePtr->isContainer)) {
  623. if (framePtr->useThis == NULL) {
  624.     TkpMakeContainer(framePtr->tkwin);
  625. } else {
  626.     Tcl_AppendResult(interp, "A window cannot have both the -use ",
  627.     "and the -container option set.", (char *) NULL);
  628.     goto error;
  629. }
  630.     }
  631.     if (type == TYPE_TOPLEVEL) {
  632. Tcl_DoWhenIdle(MapFrame, (ClientData) framePtr);
  633.     }
  634.     Tcl_SetResult(interp, Tk_PathName(new), TCL_STATIC);
  635.     return TCL_OK;
  636.     error:
  637.     if (new != NULL) {
  638. Tk_DestroyWindow(new);
  639.     }
  640.     return TCL_ERROR;
  641. }
  642. /*
  643.  *--------------------------------------------------------------
  644.  *
  645.  * FrameWidgetObjCmd --
  646.  *
  647.  * This procedure is invoked to process the Tcl command
  648.  * that corresponds to a frame widget.  See the user
  649.  * documentation for details on what it does.
  650.  *
  651.  * Results:
  652.  * A standard Tcl result.
  653.  *
  654.  * Side effects:
  655.  * See the user documentation.
  656.  *
  657.  *--------------------------------------------------------------
  658.  */
  659. static int
  660. FrameWidgetObjCmd(clientData, interp, objc, objv)
  661.     ClientData clientData; /* Information about frame widget. */
  662.     Tcl_Interp *interp; /* Current interpreter. */
  663.     int objc; /* Number of arguments. */
  664.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  665. {
  666.     static CONST char *frameOptions[] = {
  667. "cget", "configure", (char *) NULL
  668.     };
  669.     enum options {
  670. FRAME_CGET, FRAME_CONFIGURE
  671.     };
  672.     register Frame *framePtr = (Frame *) clientData;
  673.     int result = TCL_OK, index;
  674.     int c, i, length;
  675.     Tcl_Obj *objPtr;
  676.     if (objc < 2) {
  677. Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
  678. return TCL_ERROR;
  679.     }
  680.     if (Tcl_GetIndexFromObj(interp, objv[1], frameOptions, "option", 0,
  681.     &index) != TCL_OK) {
  682. return TCL_ERROR;
  683.     }
  684.     Tcl_Preserve((ClientData) framePtr);
  685.     switch ((enum options) index) {
  686.       case FRAME_CGET: {
  687. if (objc != 3) {
  688.     Tcl_WrongNumArgs(interp, 2, objv, "option");
  689.     result = TCL_ERROR;
  690.     goto done;
  691. }
  692.         objPtr = Tk_GetOptionValue(interp, (char *) framePtr,
  693. framePtr->optionTable, objv[2], framePtr->tkwin);
  694.         if (objPtr == NULL) {
  695.     result = TCL_ERROR;
  696.     goto done;
  697.         } else {
  698.     Tcl_SetObjResult(interp, objPtr);
  699.         }
  700. break;
  701.       }
  702.       case FRAME_CONFIGURE: {
  703. if (objc <= 3) {
  704.     objPtr = Tk_GetOptionInfo(interp, (char *) framePtr,
  705.     framePtr->optionTable,
  706.     (objc == 3) ? objv[2] : (Tcl_Obj *) NULL,
  707.     framePtr->tkwin);
  708.     if (objPtr == NULL) {
  709. result = TCL_ERROR;
  710. goto done;
  711.     } else {
  712. Tcl_SetObjResult(interp, objPtr);
  713.     }
  714. } else {
  715.     /*
  716.      * Don't allow the options -class, -colormap, -container,
  717.      * -newcmap, -screen, -use, or -visual to be changed.
  718.      */
  719.     for (i = 2; i < objc; i++) {
  720. char *arg = Tcl_GetStringFromObj(objv[i], &length);
  721. if (length < 2) {
  722.     continue;
  723. }
  724. c = arg[1];
  725. if (((c == 'c')
  726. && (strncmp(arg, "-class", (unsigned) length) == 0)
  727. && (length >= 2))
  728. || ((c == 'c')
  729. && (strncmp(arg, "-colormap", (unsigned) length) == 0)
  730. && (length >= 3))
  731. || ((c == 'c')
  732. && (strncmp(arg, "-container", (unsigned) length) == 0)
  733. && (length >= 3))
  734. || ((c == 's') && (framePtr->type == TYPE_TOPLEVEL)
  735. && (strncmp(arg, "-screen", (unsigned) length) == 0))
  736. || ((c == 'u') && (framePtr->type == TYPE_TOPLEVEL)
  737. && (strncmp(arg, "-use", (unsigned) length) == 0))
  738. || ((c == 'v')
  739. && (strncmp(arg, "-visual", (unsigned) length) ==0))) {
  740.     Tcl_AppendResult(interp, "can't modify ", arg,
  741.     " option after widget is created", (char *) NULL);
  742.     result = TCL_ERROR;
  743.     goto done;
  744. }
  745.     }
  746.     result = ConfigureFrame(interp, framePtr, objc-2, objv+2);
  747. }
  748. break;
  749.       }
  750.     }
  751.     done:
  752.     Tcl_Release((ClientData) framePtr);
  753.     return result;
  754. }
  755. /*
  756.  *----------------------------------------------------------------------
  757.  *
  758.  * DestroyFrame --
  759.  *
  760.  * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
  761.  * to clean up the internal structure of a frame at a safe time
  762.  * (when no-one is using it anymore).
  763.  *
  764.  * Results:
  765.  * None.
  766.  *
  767.  * Side effects:
  768.  * Everything associated with the frame is freed up.
  769.  *
  770.  *----------------------------------------------------------------------
  771.  */
  772. static void
  773. DestroyFrame(memPtr)
  774.     char *memPtr; /* Info about frame widget. */
  775. {
  776.     register Frame *framePtr = (Frame *) memPtr;
  777.     register Labelframe *labelframePtr = (Labelframe *) memPtr;
  778.     if (framePtr->type == TYPE_LABELFRAME) {
  779. Tk_FreeTextLayout(labelframePtr->textLayout);
  780. if (labelframePtr->textGC != None) {
  781.     Tk_FreeGC(framePtr->display, labelframePtr->textGC);
  782. }
  783.     }
  784.     if (framePtr->colormap != None) {
  785. Tk_FreeColormap(framePtr->display, framePtr->colormap);
  786.     }
  787.     ckfree((char *) framePtr);
  788. }
  789. /*
  790.  *----------------------------------------------------------------------
  791.  *
  792.  * DestroyFramePartly --
  793.  *
  794.  * This procedure is invoked to clean up everything that needs
  795.  *      tkwin to be defined when deleted.  During the destruction
  796.  *      process tkwin is always set to NULL and this procedure must
  797.  *      be called before that happens.
  798.  *
  799.  * Results:
  800.  * None.
  801.  *
  802.  * Side effects:
  803.  * Some things associated with the frame are freed up.
  804.  *
  805.  *----------------------------------------------------------------------
  806.  */
  807. static void
  808. DestroyFramePartly(framePtr)
  809.     Frame *framePtr; /* Info about frame widget. */
  810. {
  811.     register Labelframe *labelframePtr = (Labelframe *) framePtr;
  812.     if (framePtr->type == TYPE_LABELFRAME && labelframePtr->labelWin != NULL) {
  813. Tk_DeleteEventHandler(labelframePtr->labelWin, StructureNotifyMask,
  814. FrameStructureProc, (ClientData) framePtr);
  815. Tk_ManageGeometry(labelframePtr->labelWin, (Tk_GeomMgr *) NULL,
  816. (ClientData) NULL);
  817. if (framePtr->tkwin != Tk_Parent(labelframePtr->labelWin)) {
  818.     Tk_UnmaintainGeometry(labelframePtr->labelWin, framePtr->tkwin);
  819. }
  820. Tk_UnmapWindow(labelframePtr->labelWin);
  821. labelframePtr->labelWin = NULL;
  822.     }
  823.     Tk_FreeConfigOptions((char *) framePtr, framePtr->optionTable,
  824.             framePtr->tkwin);
  825. }
  826. /*
  827.  *----------------------------------------------------------------------
  828.  *
  829.  * ConfigureFrame --
  830.  *
  831.  * This procedure is called to process an objv/objc list, plus
  832.  * the Tk option database, in order to configure (or
  833.  * reconfigure) a frame widget.
  834.  *
  835.  * Results:
  836.  * The return value is a standard Tcl result.  If TCL_ERROR is
  837.  * returned, then the interp's result contains an error message.
  838.  *
  839.  * Side effects:
  840.  * Configuration information, such as text string, colors, font,
  841.  * etc. get set for framePtr;  old resources get freed, if there
  842.  * were any.
  843.  *
  844.  *----------------------------------------------------------------------
  845.  */
  846. static int
  847. ConfigureFrame(interp, framePtr, objc, objv)
  848.     Tcl_Interp *interp; /* Used for error reporting. */
  849.     register Frame *framePtr; /* Information about widget;  may or may
  850.  * not already have values for some fields. */
  851.     int objc; /* Number of valid entries in objv. */
  852.     Tcl_Obj *CONST objv[]; /* Arguments. */
  853. {
  854.     Tk_SavedOptions savedOptions;
  855.     char *oldMenuName;
  856.     Tk_Window oldWindow = NULL;
  857.     Labelframe *labelframePtr = (Labelframe *) framePtr;
  858.     /*
  859.      * Need the old menubar name for the menu code to delete it.
  860.      */
  861.     
  862.     if (framePtr->menuName == NULL) {
  863.      oldMenuName = NULL;
  864.     } else {
  865.      oldMenuName = ckalloc(strlen(framePtr->menuName) + 1);
  866.      strcpy(oldMenuName, framePtr->menuName);
  867.     }
  868.     if (framePtr->type == TYPE_LABELFRAME) {
  869. oldWindow = labelframePtr->labelWin;
  870.     }
  871.     if (Tk_SetOptions(interp, (char *) framePtr,
  872.     framePtr->optionTable, objc, objv,
  873.     framePtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) {
  874. if (oldMenuName != NULL) {
  875.     ckfree(oldMenuName);
  876. }
  877. return TCL_ERROR;
  878.     } else {
  879. Tk_FreeSavedOptions(&savedOptions);
  880.     }
  881.     /*
  882.      * A few of the options require additional processing.
  883.      */
  884.     if (((oldMenuName == NULL) && (framePtr->menuName != NULL))
  885.     || ((oldMenuName != NULL) && (framePtr->menuName == NULL))
  886.     || ((oldMenuName != NULL) && (framePtr->menuName != NULL)
  887.     && strcmp(oldMenuName, framePtr->menuName) != 0)) {
  888. TkSetWindowMenuBar(interp, framePtr->tkwin, oldMenuName,
  889. framePtr->menuName);
  890.     }
  891.     if (oldMenuName != NULL) {
  892.      ckfree(oldMenuName);
  893.     }
  894.     if (framePtr->border != NULL) {
  895. Tk_SetBackgroundFromBorder(framePtr->tkwin, framePtr->border);
  896.     } else {
  897. Tk_SetWindowBackgroundPixmap(framePtr->tkwin, None);
  898.     }
  899.     if (framePtr->highlightWidth < 0) {
  900. framePtr->highlightWidth = 0;
  901.     }
  902.     if (framePtr->padX < 0) {
  903. framePtr->padX = 0;
  904.     }
  905.     if (framePtr->padY < 0) {
  906. framePtr->padY = 0;
  907.     }
  908.     /*
  909.      * If a -labelwidget is specified, check that it is valid and set
  910.      * up geometry management for it.
  911.      */
  912.     if (framePtr->type == TYPE_LABELFRAME) {
  913. if (oldWindow != labelframePtr->labelWin) {
  914.     if (oldWindow != NULL) {
  915. Tk_DeleteEventHandler(oldWindow, StructureNotifyMask,
  916. FrameStructureProc, (ClientData) framePtr);
  917. Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL,
  918. (ClientData) NULL);
  919. Tk_UnmaintainGeometry(oldWindow, framePtr->tkwin);
  920. Tk_UnmapWindow(oldWindow);
  921.     }
  922.     if (labelframePtr->labelWin != NULL) {
  923. Tk_Window ancestor, parent, sibling = NULL;
  924. /*
  925.  * Make sure that the frame is either the parent of the
  926.  * window used as label or a descendant of that
  927.  * parent.  Also, don't allow a top-level window to be
  928.  * managed inside the frame.
  929.  */
  930. parent = Tk_Parent(labelframePtr->labelWin);
  931. for (ancestor = framePtr->tkwin; ;
  932.      ancestor = Tk_Parent(ancestor)) {
  933.     if (ancestor == parent) {
  934. break;
  935.     }
  936.     sibling = ancestor;
  937.     if (Tk_IsTopLevel(ancestor)) {
  938. badWindow:
  939. Tcl_AppendResult(interp, "can't use ",
  940. Tk_PathName(labelframePtr->labelWin),
  941. " as label in this frame", (char *) NULL);
  942. labelframePtr->labelWin = NULL;
  943. return TCL_ERROR;
  944.     }
  945. }
  946. if (Tk_IsTopLevel(labelframePtr->labelWin)) {
  947.     goto badWindow;
  948. }
  949. if (labelframePtr->labelWin == framePtr->tkwin) {
  950.     goto badWindow;
  951. }
  952. Tk_CreateEventHandler(labelframePtr->labelWin,
  953. StructureNotifyMask, FrameStructureProc,
  954. (ClientData) framePtr);
  955. Tk_ManageGeometry(labelframePtr->labelWin, &frameGeomType,
  956. (ClientData) framePtr);
  957. /*
  958.  * If the frame is not parent to the label, make
  959.  * sure the label is above its sibling in the stacking
  960.  * order.
  961.  */
  962. if (sibling != NULL) {
  963.     Tk_RestackWindow(labelframePtr->labelWin, Above, sibling);
  964. }
  965.     }
  966. }
  967.     }
  968.     FrameWorldChanged((ClientData) framePtr);
  969.     return TCL_OK;
  970. }
  971. /*
  972.  *---------------------------------------------------------------------------
  973.  *
  974.  * FrameWorldChanged --
  975.  *
  976.  *      This procedure is called when the world has changed in some
  977.  *      way and the widget needs to recompute all its graphics contexts
  978.  * and determine its new geometry.
  979.  *
  980.  * Results:
  981.  *      None.
  982.  *
  983.  * Side effects:
  984.  *      Frame will be relayed out and redisplayed.
  985.  *
  986.  *---------------------------------------------------------------------------
  987.  */
  988.  
  989. static void
  990. FrameWorldChanged(instanceData)
  991.     ClientData instanceData; /* Information about widget. */
  992. {
  993.     Frame *framePtr = (Frame *) instanceData;
  994.     Labelframe *labelframePtr = (Labelframe *) framePtr;
  995.     Tk_Window tkwin = framePtr->tkwin;
  996.     XGCValues gcValues;
  997.     GC gc;
  998.     int anyTextLabel, anyWindowLabel;
  999.     int bWidthLeft, bWidthRight, bWidthTop, bWidthBottom;
  1000.     char *labelText;
  1001.     anyTextLabel = (framePtr->type == TYPE_LABELFRAME) &&
  1002.     (labelframePtr->textPtr != NULL) &&
  1003.     (labelframePtr->labelWin == NULL);
  1004.     anyWindowLabel = (framePtr->type == TYPE_LABELFRAME) &&
  1005.     (labelframePtr->labelWin != NULL);
  1006.     if (framePtr->type == TYPE_LABELFRAME) {
  1007. /*
  1008.  * The textGC is needed even in the labelWin case, so it's
  1009.  * always created for a labelframe.
  1010.  */
  1011. gcValues.font = Tk_FontId(labelframePtr->tkfont);
  1012. gcValues.foreground = labelframePtr->textColorPtr->pixel;
  1013. gcValues.graphics_exposures = False;
  1014. gc = Tk_GetGC(tkwin, GCForeground | GCFont | GCGraphicsExposures,
  1015. &gcValues);
  1016. if (labelframePtr->textGC != None) {
  1017.     Tk_FreeGC(framePtr->display, labelframePtr->textGC);
  1018. }
  1019. labelframePtr->textGC = gc;
  1020. /*
  1021.  * Calculate label size.
  1022.  */
  1023. labelframePtr->labelReqWidth = labelframePtr->labelReqHeight = 0;
  1024. if (anyTextLabel) {
  1025.     labelText = Tcl_GetString(labelframePtr->textPtr);
  1026.     Tk_FreeTextLayout(labelframePtr->textLayout);
  1027.     labelframePtr->textLayout = Tk_ComputeTextLayout(labelframePtr->tkfont,
  1028.     labelText, -1, 0, TK_JUSTIFY_CENTER, 0,
  1029.     &labelframePtr->labelReqWidth, &labelframePtr->labelReqHeight);
  1030.     labelframePtr->labelReqWidth += 2 * LABELSPACING;
  1031.     labelframePtr->labelReqHeight += 2 * LABELSPACING;
  1032. } else if (anyWindowLabel) {
  1033.     labelframePtr->labelReqWidth = Tk_ReqWidth(labelframePtr->labelWin);
  1034.     labelframePtr->labelReqHeight = Tk_ReqHeight(labelframePtr->labelWin);
  1035. }
  1036. /* 
  1037.  * Make sure label size is at least as big as the border.
  1038.  * This simplifies later calculations and gives a better
  1039.  * appearance with thick borders.
  1040.  */
  1041.      
  1042. if ((labelframePtr->labelAnchor >= LABELANCHOR_N) && 
  1043. (labelframePtr->labelAnchor <= LABELANCHOR_SW)) {
  1044.     if (labelframePtr->labelReqHeight < framePtr->borderWidth) {
  1045. labelframePtr->labelReqHeight = framePtr->borderWidth;
  1046.     }
  1047. } else {
  1048.     if (labelframePtr->labelReqWidth < framePtr->borderWidth) {
  1049. labelframePtr->labelReqWidth = framePtr->borderWidth;
  1050.     }
  1051. }
  1052.     }
  1053.     /*
  1054.      * Calculate individual border widths.
  1055.      */
  1056.     bWidthBottom = bWidthTop = bWidthRight = bWidthLeft = 
  1057.             framePtr->borderWidth + framePtr->highlightWidth;
  1058.     bWidthLeft   += framePtr->padX;
  1059.     bWidthRight  += framePtr->padX;
  1060.     bWidthTop    += framePtr->padY;
  1061.     bWidthBottom += framePtr->padY;
  1062.     
  1063.     if (anyTextLabel || anyWindowLabel) {
  1064. switch (labelframePtr->labelAnchor) {
  1065.   case LABELANCHOR_E:
  1066.   case LABELANCHOR_EN:
  1067.   case LABELANCHOR_ES:
  1068.     bWidthRight += labelframePtr->labelReqWidth -
  1069.     framePtr->borderWidth;
  1070.     break;
  1071.   case LABELANCHOR_N:
  1072.   case LABELANCHOR_NE:
  1073.   case LABELANCHOR_NW:
  1074.     bWidthTop += labelframePtr->labelReqHeight - framePtr->borderWidth;
  1075.     break;
  1076.   case LABELANCHOR_S:
  1077.   case LABELANCHOR_SE:
  1078.   case LABELANCHOR_SW:
  1079.     bWidthBottom += labelframePtr->labelReqHeight -
  1080.     framePtr->borderWidth;
  1081.     break;
  1082.   default:
  1083.     bWidthLeft += labelframePtr->labelReqWidth - framePtr->borderWidth;
  1084.     break;
  1085. }
  1086.     }
  1087.     Tk_SetInternalBorderEx(tkwin, bWidthLeft, bWidthRight, bWidthTop,
  1088.     bWidthBottom);
  1089.     ComputeFrameGeometry(framePtr);
  1090.     /*
  1091.      * A labelframe should request size for its label.
  1092.      */
  1093.     if (framePtr->type == TYPE_LABELFRAME) {
  1094. int minwidth = labelframePtr->labelReqWidth;
  1095. int minheight = labelframePtr->labelReqHeight;
  1096. int padding = framePtr->highlightWidth;
  1097. if (framePtr->borderWidth > 0) {
  1098.     padding += framePtr->borderWidth + LABELMARGIN;
  1099. }
  1100. padding *= 2;
  1101. if ((labelframePtr->labelAnchor >= LABELANCHOR_N) && 
  1102. (labelframePtr->labelAnchor <= LABELANCHOR_SW)) {
  1103.     minwidth += padding;
  1104.     minheight += framePtr->borderWidth + framePtr->highlightWidth;
  1105. } else {
  1106.     minheight += padding;
  1107.     minwidth += framePtr->borderWidth + framePtr->highlightWidth;
  1108. }
  1109. Tk_SetMinimumRequestSize(tkwin, minwidth, minheight);
  1110.     }
  1111.     if ((framePtr->width > 0) || (framePtr->height > 0)) {
  1112. Tk_GeometryRequest(tkwin, framePtr->width, framePtr->height);
  1113.     }
  1114.     if (Tk_IsMapped(tkwin)) {
  1115. if (!(framePtr->flags & REDRAW_PENDING)) {
  1116.     Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  1117. }
  1118. framePtr->flags |= REDRAW_PENDING;
  1119.     }
  1120. }
  1121. /*
  1122.  *----------------------------------------------------------------------
  1123.  *
  1124.  * ComputeFrameGeometry --
  1125.  *
  1126.  * This procedure is called to compute various geometrical
  1127.  * information for a frame, such as where various things get
  1128.  * displayed.  It's called when the window is reconfigured.
  1129.  *
  1130.  * Results:
  1131.  * None.
  1132.  *
  1133.  * Side effects:
  1134.  * Display-related numbers get changed in *framePtr.
  1135.  *
  1136.  *----------------------------------------------------------------------
  1137.  */
  1138. static void
  1139. ComputeFrameGeometry(framePtr)
  1140.     register Frame *framePtr; /* Information about widget. */
  1141. {
  1142.     int otherWidth, otherHeight, otherWidthT, otherHeightT, padding;
  1143.     int maxWidth, maxHeight;
  1144.     Tk_Window tkwin;
  1145.     Labelframe *labelframePtr = (Labelframe *) framePtr;
  1146.     /*
  1147.      * We have nothing to do here unless there is a label.
  1148.      */
  1149.     if (framePtr->type != TYPE_LABELFRAME) return;
  1150.     if ((labelframePtr->textPtr == NULL) &&
  1151.     (labelframePtr->labelWin == NULL))  return;
  1152.     tkwin = framePtr->tkwin;
  1153.     /* 
  1154.      * Calculate the available size for the label
  1155.      */
  1156.     labelframePtr->labelBox.width = labelframePtr->labelReqWidth;
  1157.     labelframePtr->labelBox.height = labelframePtr->labelReqHeight;
  1158.     padding = framePtr->highlightWidth;
  1159.     if (framePtr->borderWidth > 0) {
  1160.         padding += framePtr->borderWidth + LABELMARGIN;
  1161.     }
  1162.     padding *= 2;
  1163.     maxHeight = Tk_Height(tkwin);
  1164.     maxWidth  = Tk_Width(tkwin);
  1165.     if ((labelframePtr->labelAnchor >= LABELANCHOR_N) && 
  1166.             (labelframePtr->labelAnchor <= LABELANCHOR_SW)) {
  1167. maxWidth -= padding;
  1168. if (maxWidth < 1) maxWidth = 1;
  1169.     } else {
  1170. maxHeight -= padding;
  1171. if (maxHeight < 1) maxHeight = 1;
  1172.     }
  1173.     if (labelframePtr->labelBox.width > maxWidth) {
  1174. labelframePtr->labelBox.width = maxWidth;
  1175.     }
  1176.     if (labelframePtr->labelBox.height > maxHeight) {
  1177. labelframePtr->labelBox.height = maxHeight;
  1178.     }
  1179.     /*
  1180.      * Calculate label and text position.
  1181.      * The text's position is based on the requested size (= the text's
  1182.      * real size) to get proper alignment if the text does not fit.
  1183.      */
  1184.     otherWidth   = Tk_Width(tkwin)  - labelframePtr->labelBox.width;
  1185.     otherHeight  = Tk_Height(tkwin) - labelframePtr->labelBox.height;
  1186.     otherWidthT  = Tk_Width(tkwin)  - labelframePtr->labelReqWidth;
  1187.     otherHeightT = Tk_Height(tkwin) - labelframePtr->labelReqHeight;
  1188.     padding = framePtr->highlightWidth;
  1189.     switch (labelframePtr->labelAnchor) {
  1190.       case LABELANCHOR_E:
  1191.       case LABELANCHOR_EN:
  1192.       case LABELANCHOR_ES:
  1193.         labelframePtr->labelTextX = otherWidthT - padding;
  1194.         labelframePtr->labelBox.x = otherWidth - padding;
  1195.         break;
  1196.       case LABELANCHOR_N:
  1197.       case LABELANCHOR_NE:
  1198.       case LABELANCHOR_NW:
  1199.         labelframePtr->labelTextY = padding;
  1200.         labelframePtr->labelBox.y = padding;
  1201.         break;
  1202.       case LABELANCHOR_S:
  1203.       case LABELANCHOR_SE:
  1204.       case LABELANCHOR_SW:
  1205.         labelframePtr->labelTextY = otherHeightT - padding;
  1206.         labelframePtr->labelBox.y = otherHeight - padding;
  1207.         break;
  1208.       default:
  1209.         labelframePtr->labelTextX = padding;
  1210.         labelframePtr->labelBox.x = padding;
  1211.         break;
  1212.     }
  1213.     if (framePtr->borderWidth > 0) {
  1214.         padding += framePtr->borderWidth + LABELMARGIN;
  1215.     }
  1216.     switch (labelframePtr->labelAnchor) {
  1217.       case LABELANCHOR_NW:
  1218.       case LABELANCHOR_SW:
  1219.         labelframePtr->labelTextX = padding;
  1220.         labelframePtr->labelBox.x = padding;
  1221.         break;
  1222.       case LABELANCHOR_N:
  1223.       case LABELANCHOR_S:
  1224.         labelframePtr->labelTextX = otherWidthT / 2;
  1225.         labelframePtr->labelBox.x = otherWidth / 2;
  1226.         break;
  1227.       case LABELANCHOR_NE:
  1228.       case LABELANCHOR_SE:
  1229.         labelframePtr->labelTextX = otherWidthT - padding;
  1230.         labelframePtr->labelBox.x = otherWidth - padding;
  1231.         break;
  1232.       case LABELANCHOR_EN:
  1233.       case LABELANCHOR_WN:
  1234.         labelframePtr->labelTextY = padding;
  1235.         labelframePtr->labelBox.y = padding;
  1236.         break;
  1237.       case LABELANCHOR_E:
  1238.       case LABELANCHOR_W:
  1239.         labelframePtr->labelTextY = otherHeightT / 2;
  1240.         labelframePtr->labelBox.y = otherHeight / 2;
  1241.         break;
  1242.       default:
  1243. labelframePtr->labelTextY = otherHeightT - padding;
  1244. labelframePtr->labelBox.y = otherHeight - padding;
  1245.         break;
  1246.     }
  1247. }
  1248. /*
  1249.  *----------------------------------------------------------------------
  1250.  *
  1251.  * DisplayFrame --
  1252.  *
  1253.  * This procedure is invoked to display a frame widget.
  1254.  *
  1255.  * Results:
  1256.  * None.
  1257.  *
  1258.  * Side effects:
  1259.  * Commands are output to X to display the frame in its
  1260.  * current mode.
  1261.  *
  1262.  *----------------------------------------------------------------------
  1263.  */
  1264. static void
  1265. DisplayFrame(clientData)
  1266.     ClientData clientData; /* Information about widget. */
  1267. {
  1268.     register Frame *framePtr = (Frame *) clientData;
  1269.     register Tk_Window tkwin = framePtr->tkwin;
  1270.     int bdX1, bdY1, bdX2, bdY2, hlWidth;
  1271.     Pixmap pixmap;
  1272.     TkRegion clipRegion = NULL;
  1273.     framePtr->flags &= ~REDRAW_PENDING;
  1274.     if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)
  1275.         || framePtr->isContainer) {
  1276. return;
  1277.     }
  1278.     /*
  1279.      * Highlight shall always be drawn if it exists, so do that first.
  1280.      */
  1281.     hlWidth = framePtr->highlightWidth;
  1282.     if (hlWidth != 0) {
  1283.         GC fgGC, bgGC;
  1284. bgGC = Tk_GCForColor(framePtr->highlightBgColorPtr,
  1285. Tk_WindowId(tkwin));
  1286. if (framePtr->flags & GOT_FOCUS) {
  1287.     fgGC = Tk_GCForColor(framePtr->highlightColorPtr,
  1288.     Tk_WindowId(tkwin));
  1289.     TkpDrawHighlightBorder(tkwin, fgGC, bgGC, hlWidth,
  1290.     Tk_WindowId(tkwin));
  1291. } else {
  1292.     TkpDrawHighlightBorder(tkwin, bgGC, bgGC, hlWidth,
  1293.     Tk_WindowId(tkwin));
  1294. }
  1295.     }
  1296.     /*
  1297.      * If -background is set to "", no interior is drawn.
  1298.      */
  1299.     if (framePtr->border == NULL) return;
  1300.     if (framePtr->type != TYPE_LABELFRAME) {
  1301. /*
  1302.  * Pass to platform specific draw function.  In general, it just
  1303.  * draws a simple rectangle, but it may "theme" the background.
  1304.  */
  1305. noLabel:
  1306. TkpDrawFrame(tkwin, framePtr->border, hlWidth,
  1307. framePtr->borderWidth, framePtr->relief);
  1308.     } else {
  1309. Labelframe *labelframePtr = (Labelframe *) framePtr;
  1310. if ((labelframePtr->textPtr == NULL) &&
  1311. (labelframePtr->labelWin == NULL)) {
  1312.     goto noLabel;
  1313. }
  1314. #ifndef TK_NO_DOUBLE_BUFFERING
  1315. /*
  1316.  * In order to avoid screen flashes, this procedure redraws the
  1317.  * frame into off-screen memory, then copies it back on-screen 
  1318.  * in a single operation.  This means there's no point in time 
  1319.  * where the on-screen image has been cleared.
  1320.  */
  1321. pixmap = Tk_GetPixmap(framePtr->display, Tk_WindowId(tkwin),
  1322. Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  1323. #else
  1324. pixmap = Tk_WindowId(tkwin);
  1325. #endif /* TK_NO_DOUBLE_BUFFERING */
  1326. /* 
  1327.  * Clear the pixmap.
  1328.  */
  1329. Tk_Fill3DRectangle(tkwin, pixmap, framePtr->border, 0, 0,
  1330. Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
  1331. /*
  1332.  * Calculate how the label affects the border's position.
  1333.  */
  1334. bdX1 = bdY1 = hlWidth;
  1335. bdX2 = Tk_Width(tkwin) - hlWidth;
  1336. bdY2 = Tk_Height(tkwin) - hlWidth;
  1337. switch (labelframePtr->labelAnchor) {
  1338.   case LABELANCHOR_E:
  1339.   case LABELANCHOR_EN:
  1340.   case LABELANCHOR_ES:
  1341.     bdX2 -= (labelframePtr->labelBox.width - framePtr->borderWidth)
  1342.     / 2;
  1343.     break;
  1344.   case LABELANCHOR_N:
  1345.   case LABELANCHOR_NE:
  1346.   case LABELANCHOR_NW:
  1347.     /* 
  1348.      * Since the glyphs of the text tend to be in the lower part
  1349.              * we favor a lower border position by rounding up.
  1350.      */
  1351.     bdY1 += (labelframePtr->labelBox.height - framePtr->borderWidth +1)
  1352.     / 2;
  1353.     break;
  1354.   case LABELANCHOR_S:
  1355.   case LABELANCHOR_SE:
  1356.   case LABELANCHOR_SW:
  1357.     bdY2 -= (labelframePtr->labelBox.height - framePtr->borderWidth)
  1358.     / 2;
  1359.     break;
  1360.   default:
  1361.     bdX1 += (labelframePtr->labelBox.width - framePtr->borderWidth)
  1362.     / 2;
  1363.     break;
  1364. }
  1365. /* 
  1366.          * Draw border
  1367.          */
  1368. Tk_Draw3DRectangle(tkwin, pixmap, framePtr->border, bdX1, bdY1,
  1369. bdX2 - bdX1, bdY2 - bdY1, framePtr->borderWidth,
  1370. framePtr->relief);
  1371.         if (labelframePtr->labelWin == NULL) {
  1372.             /* 
  1373.              * Clear behind the label
  1374.              */
  1375.             Tk_Fill3DRectangle(tkwin, pixmap,
  1376.                     framePtr->border, labelframePtr->labelBox.x,
  1377.                     labelframePtr->labelBox.y, labelframePtr->labelBox.width,
  1378.                     labelframePtr->labelBox.height, 0, TK_RELIEF_FLAT);
  1379.             /*
  1380.              * Draw label.
  1381.      * If there is not room for the entire label, use clipping to
  1382.      * get a nice appearance.
  1383.              */
  1384.     
  1385.     if ((labelframePtr->labelBox.width < labelframePtr->labelReqWidth)
  1386.     || (labelframePtr->labelBox.height < 
  1387.     labelframePtr->labelReqHeight)) {
  1388. clipRegion = TkCreateRegion();
  1389. TkUnionRectWithRegion(&labelframePtr->labelBox, clipRegion,
  1390. clipRegion);
  1391. TkSetRegion(framePtr->display, labelframePtr->textGC,
  1392. clipRegion);
  1393.     }
  1394.             Tk_DrawTextLayout(framePtr->display, pixmap,
  1395.                     labelframePtr->textGC, labelframePtr->textLayout,
  1396.                     labelframePtr->labelTextX + LABELSPACING,
  1397.                     labelframePtr->labelTextY + LABELSPACING, 0, -1);
  1398.     if (clipRegion != NULL) {
  1399. XSetClipMask(framePtr->display, labelframePtr->textGC, None);
  1400. TkDestroyRegion(clipRegion);
  1401.     }
  1402.         } else {
  1403.     /*
  1404.      * Reposition and map the window (but in different ways depending
  1405.      * on whether the frame is the window's parent).
  1406.      */
  1407.             
  1408.     if (framePtr->tkwin == Tk_Parent(labelframePtr->labelWin)) {
  1409. if ((labelframePtr->labelBox.x != Tk_X(labelframePtr->labelWin))
  1410. || (labelframePtr->labelBox.y !=
  1411. Tk_Y(labelframePtr->labelWin))
  1412. || (labelframePtr->labelBox.width != 
  1413. Tk_Width(labelframePtr->labelWin))
  1414. || (labelframePtr->labelBox.height != 
  1415. Tk_Height(labelframePtr->labelWin))) {
  1416.     Tk_MoveResizeWindow(labelframePtr->labelWin,
  1417.     labelframePtr->labelBox.x, labelframePtr->labelBox.y, 
  1418.     labelframePtr->labelBox.width,
  1419.     labelframePtr->labelBox.height);
  1420. }
  1421. Tk_MapWindow(labelframePtr->labelWin);
  1422.     } else {
  1423. Tk_MaintainGeometry(labelframePtr->labelWin, framePtr->tkwin, 
  1424. labelframePtr->labelBox.x, labelframePtr->labelBox.y,
  1425. labelframePtr->labelBox.width,
  1426. labelframePtr->labelBox.height);
  1427.     }
  1428. }
  1429. #ifndef TK_NO_DOUBLE_BUFFERING
  1430. /*
  1431.  * Everything's been redisplayed;  now copy the pixmap onto the screen
  1432.  * and free up the pixmap.
  1433.  */
  1434. XCopyArea(framePtr->display, pixmap, Tk_WindowId(tkwin),
  1435. labelframePtr->textGC, hlWidth, hlWidth,
  1436. (unsigned) (Tk_Width(tkwin) - 2 * hlWidth),
  1437. (unsigned) (Tk_Height(tkwin) - 2 * hlWidth),
  1438. hlWidth, hlWidth);
  1439. Tk_FreePixmap(framePtr->display, pixmap);
  1440. #endif /* TK_NO_DOUBLE_BUFFERING */
  1441.     }
  1442. }
  1443. /*
  1444.  *--------------------------------------------------------------
  1445.  *
  1446.  * FrameEventProc --
  1447.  *
  1448.  * This procedure is invoked by the Tk dispatcher on
  1449.  * structure changes to a frame.  For frames with 3D
  1450.  * borders, this procedure is also invoked for exposures.
  1451.  *
  1452.  * Results:
  1453.  * None.
  1454.  *
  1455.  * Side effects:
  1456.  * When the window gets deleted, internal structures get
  1457.  * cleaned up.  When it gets exposed, it is redisplayed.
  1458.  *
  1459.  *--------------------------------------------------------------
  1460.  */
  1461. static void
  1462. FrameEventProc(clientData, eventPtr)
  1463.     ClientData clientData; /* Information about window. */
  1464.     register XEvent *eventPtr; /* Information about event. */
  1465. {
  1466.     register Frame *framePtr = (Frame *) clientData;
  1467.     if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
  1468. goto redraw;
  1469.     } else if (eventPtr->type == ConfigureNotify) {
  1470. ComputeFrameGeometry(framePtr);
  1471. goto redraw;
  1472.     } else if (eventPtr->type == DestroyNotify) {
  1473. if (framePtr->menuName != NULL) {
  1474.     TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin,
  1475.     framePtr->menuName, NULL);
  1476.     ckfree(framePtr->menuName);
  1477.     framePtr->menuName = NULL;
  1478. }
  1479. if (framePtr->tkwin != NULL) {
  1480.     /*
  1481.      * If this window is a container, then this event could be
  1482.      * coming from the embedded application, in which case
  1483.      * Tk_DestroyWindow hasn't been called yet.  When Tk_DestroyWindow
  1484.      * is called later, then another destroy event will be generated.
  1485.      * We need to be sure we ignore the second event, since the frame
  1486.      * could be gone by then.  To do so, delete the event handler
  1487.      * explicitly (normally it's done implicitly by Tk_DestroyWindow).
  1488.      */
  1489.     /*
  1490.      * Since the tkwin pointer will be gone when we reach
  1491.      * DestroyFrame, we must free all options now.
  1492.      */
  1493.             DestroyFramePartly(framePtr);
  1494.     Tk_DeleteEventHandler(framePtr->tkwin,
  1495.     ExposureMask|StructureNotifyMask|FocusChangeMask,
  1496.     FrameEventProc, (ClientData) framePtr);
  1497.     framePtr->tkwin = NULL;
  1498.             Tcl_DeleteCommandFromToken(framePtr->interp, framePtr->widgetCmd);
  1499. }
  1500. if (framePtr->flags & REDRAW_PENDING) {
  1501.     Tcl_CancelIdleCall(DisplayFrame, (ClientData) framePtr);
  1502. }
  1503. Tcl_CancelIdleCall(MapFrame, (ClientData) framePtr);
  1504. Tcl_EventuallyFree((ClientData) framePtr, DestroyFrame);
  1505.     } else if (eventPtr->type == FocusIn) {
  1506. if (eventPtr->xfocus.detail != NotifyInferior) {
  1507.     framePtr->flags |= GOT_FOCUS;
  1508.     if (framePtr->highlightWidth > 0) {
  1509. goto redraw;
  1510.     }
  1511. }
  1512.     } else if (eventPtr->type == FocusOut) {
  1513. if (eventPtr->xfocus.detail != NotifyInferior) {
  1514.     framePtr->flags &= ~GOT_FOCUS;
  1515.     if (framePtr->highlightWidth > 0) {
  1516. goto redraw;
  1517.     }
  1518. }
  1519.     } else if (eventPtr->type == ActivateNotify) {
  1520.      TkpSetMainMenubar(framePtr->interp, framePtr->tkwin,
  1521.      framePtr->menuName);
  1522.     }
  1523.     return;
  1524.     redraw:
  1525.     if ((framePtr->tkwin != NULL) && !(framePtr->flags & REDRAW_PENDING)) {
  1526. Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  1527. framePtr->flags |= REDRAW_PENDING;
  1528.     }
  1529. }
  1530. /*
  1531.  *----------------------------------------------------------------------
  1532.  *
  1533.  * FrameCmdDeletedProc --
  1534.  *
  1535.  * This procedure is invoked when a widget command is deleted.  If
  1536.  * the widget isn't already in the process of being destroyed,
  1537.  * this command destroys it.
  1538.  *
  1539.  * Results:
  1540.  * None.
  1541.  *
  1542.  * Side effects:
  1543.  * The widget is destroyed.
  1544.  *
  1545.  *----------------------------------------------------------------------
  1546.  */
  1547. static void
  1548. FrameCmdDeletedProc(clientData)
  1549.     ClientData clientData; /* Pointer to widget record for widget. */
  1550. {
  1551.     Frame *framePtr = (Frame *) clientData;
  1552.     Tk_Window tkwin = framePtr->tkwin;
  1553.     if (framePtr->menuName != NULL) {
  1554. TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin,
  1555. framePtr->menuName, NULL);
  1556. ckfree(framePtr->menuName);
  1557. framePtr->menuName = NULL;
  1558.     }
  1559.     /*
  1560.      * This procedure could be invoked either because the window was
  1561.      * destroyed and the command was then deleted (in which case tkwin
  1562.      * is NULL) or because the command was deleted, and then this procedure
  1563.      * destroys the widget.
  1564.      */
  1565.     if (tkwin != NULL) {
  1566. /* 
  1567.  * Some options need tkwin to be freed, so we free them here,
  1568.  * before setting tkwin to NULL.
  1569.  */
  1570.         DestroyFramePartly(framePtr);
  1571. framePtr->tkwin = NULL;
  1572. Tk_DestroyWindow(tkwin);
  1573.     }
  1574. }
  1575. /*
  1576.  *----------------------------------------------------------------------
  1577.  *
  1578.  * MapFrame --
  1579.  *
  1580.  * This procedure is invoked as a when-idle handler to map a
  1581.  * newly-created top-level frame.
  1582.  *
  1583.  * Results:
  1584.  * None.
  1585.  *
  1586.  * Side effects:
  1587.  * The frame given by the clientData argument is mapped.
  1588.  *
  1589.  *----------------------------------------------------------------------
  1590.  */
  1591. static void
  1592. MapFrame(clientData)
  1593.     ClientData clientData; /* Pointer to frame structure. */
  1594. {
  1595.     Frame *framePtr = (Frame *) clientData;
  1596.     /*
  1597.      * Wait for all other background events to be processed before
  1598.      * mapping window.  This ensures that the window's correct geometry
  1599.      * will have been determined before it is first mapped, so that the
  1600.      * window manager doesn't get a false idea of its desired geometry.
  1601.      */
  1602.     Tcl_Preserve((ClientData) framePtr);
  1603.     while (1) {
  1604. if (Tcl_DoOneEvent(TCL_IDLE_EVENTS) == 0) {
  1605.     break;
  1606. }
  1607. /*
  1608.  * After each event, make sure that the window still exists
  1609.  * and quit if the window has been destroyed.
  1610.  */
  1611. if (framePtr->tkwin == NULL) {
  1612.     Tcl_Release((ClientData) framePtr);
  1613.     return;
  1614. }
  1615.     }
  1616.     Tk_MapWindow(framePtr->tkwin);
  1617.     Tcl_Release((ClientData) framePtr);
  1618. }
  1619. /*
  1620.  *--------------------------------------------------------------
  1621.  *
  1622.  * TkInstallFrameMenu --
  1623.  *
  1624.  * This function is needed when a Windows HWND is created
  1625.  * and a menubar has been set to the window with a system
  1626.  * menu. It notifies the menu package so that the system
  1627.  * menu can be rebuilt.
  1628.  *
  1629.  * Results:
  1630.  * None.
  1631.  *
  1632.  * Side effects:
  1633.  * The system menu (if any) is created for the menubar
  1634.  * associated with this frame.
  1635.  *
  1636.  *--------------------------------------------------------------
  1637.  */
  1638. void
  1639. TkInstallFrameMenu(tkwin)
  1640.     Tk_Window tkwin; /* The window that was just created. */
  1641. {
  1642.     TkWindow *winPtr = (TkWindow *) tkwin;
  1643.     if (winPtr->mainPtr != NULL) {
  1644. Frame *framePtr;
  1645. framePtr = (Frame*) winPtr->instanceData;
  1646. if (framePtr == NULL) {
  1647.     panic("TkInstallFrameMenu couldn't get frame pointer");
  1648. }
  1649. TkpMenuNotifyToplevelCreate(winPtr->mainPtr->interp, 
  1650. framePtr->menuName);
  1651.     }
  1652. }
  1653. /*
  1654.  *--------------------------------------------------------------
  1655.  *
  1656.  * FrameStructureProc --
  1657.  *
  1658.  * This procedure is invoked whenever StructureNotify events
  1659.  * occur for a window that's managed as label for the frame.
  1660.  * This procudure's only purpose is to clean up when windows
  1661.  * are deleted.
  1662.  *
  1663.  * Results:
  1664.  * None.
  1665.  *
  1666.  * Side effects:
  1667.  * The window is disassociated from the frame when it is
  1668.  * deleted.
  1669.  *
  1670.  *--------------------------------------------------------------
  1671.  */
  1672. static void
  1673. FrameStructureProc(clientData, eventPtr)
  1674.     ClientData clientData; /* Pointer to record describing frame. */
  1675.     XEvent *eventPtr; /* Describes what just happened. */
  1676. {
  1677.     Labelframe *labelframePtr = (Labelframe *) clientData;
  1678.     if (eventPtr->type == DestroyNotify) {
  1679. /*
  1680.  * This should only happen in a labelframe but it doesn't
  1681.  * hurt to be careful.
  1682.  */
  1683. if (labelframePtr->frame.type == TYPE_LABELFRAME) {
  1684.     labelframePtr->labelWin = NULL;
  1685.     FrameWorldChanged((ClientData) labelframePtr);
  1686. }
  1687.     }
  1688. }
  1689. /*
  1690.  *--------------------------------------------------------------
  1691.  *
  1692.  * FrameRequestProc --
  1693.  *
  1694.  * This procedure is invoked whenever a window that's associated
  1695.  * with a frame changes its requested dimensions.
  1696.  *
  1697.  * Results:
  1698.  * None.
  1699.  *
  1700.  * Side effects:
  1701.  * The size and location on the screen of the window may change.
  1702.  * depending on the options specified for the frame.
  1703.  *
  1704.  *--------------------------------------------------------------
  1705.  */
  1706. static void
  1707. FrameRequestProc(clientData, tkwin)
  1708.     ClientData clientData; /* Pointer to record for frame. */
  1709.     Tk_Window tkwin; /* Window that changed its desired
  1710.  * size. */
  1711. {
  1712.     Frame *framePtr = (Frame *) clientData;
  1713.     FrameWorldChanged((ClientData) framePtr);
  1714. }
  1715. /*
  1716.  *--------------------------------------------------------------
  1717.  *
  1718.  * FrameLostSlaveProc --
  1719.  *
  1720.  * This procedure is invoked by Tk whenever some other geometry
  1721.  * claims control over a slave that used to be managed by us.
  1722.  *
  1723.  * Results:
  1724.  * None.
  1725.  *
  1726.  * Side effects:
  1727.  * Forgets all frame-related information about the slave.
  1728.  *
  1729.  *--------------------------------------------------------------
  1730.  */
  1731. static void
  1732. FrameLostSlaveProc(clientData, tkwin)
  1733.     ClientData clientData; /* Frame structure for slave window that
  1734.  * was stolen away. */
  1735.     Tk_Window tkwin; /* Tk's handle for the slave window. */
  1736. {
  1737.     Frame *framePtr = (Frame *) clientData;
  1738.     Labelframe *labelframePtr = (Labelframe *) clientData;
  1739.     /*
  1740.      * This should only happen in a labelframe but it doesn't
  1741.      * hurt to be careful.
  1742.      */
  1743.     
  1744.     if (labelframePtr->frame.type == TYPE_LABELFRAME) {
  1745. Tk_DeleteEventHandler(labelframePtr->labelWin, StructureNotifyMask,
  1746. FrameStructureProc, (ClientData) labelframePtr);
  1747. if (framePtr->tkwin != Tk_Parent(labelframePtr->labelWin)) {
  1748.     Tk_UnmaintainGeometry(labelframePtr->labelWin, framePtr->tkwin);
  1749. }
  1750. Tk_UnmapWindow(labelframePtr->labelWin);
  1751. labelframePtr->labelWin = NULL;
  1752.     }
  1753.     FrameWorldChanged((ClientData) framePtr);
  1754. }
  1755. /*
  1756.  *--------------------------------------------------------------
  1757.  *
  1758.  * TkToplevelWindowFromCommandToken --
  1759.  *
  1760.  * If the given command name to the command for a toplevel window
  1761.  * in the given interpreter, return the tkwin for that toplevel
  1762.  * window.  Note that this lookup can't be done using the
  1763.  * standard tkwin internal table because the command might have
  1764.  * been renamed.
  1765.  *
  1766.  * Results:
  1767.  * A Tk_Window token, or NULL if the name does not refer to a
  1768.  * toplevel window.
  1769.  *
  1770.  * Side effects:
  1771.  * None.
  1772.  *
  1773.  *--------------------------------------------------------------
  1774.  */
  1775. Tk_Window
  1776. TkToplevelWindowForCommand(interp, cmdName)
  1777.     Tcl_Interp *interp;
  1778.     CONST char *cmdName;
  1779. {
  1780.     Tcl_CmdInfo cmdInfo;
  1781.     Frame *framePtr;
  1782.     if (Tcl_GetCommandInfo(interp, cmdName, &cmdInfo) == 0) {
  1783. return NULL;
  1784.     }
  1785.     if (cmdInfo.objProc != FrameWidgetObjCmd) {
  1786. return NULL;
  1787.     }
  1788.     framePtr = (Frame *) cmdInfo.objClientData;
  1789.     if (framePtr->type != TYPE_TOPLEVEL) {
  1790. return NULL;
  1791.     }
  1792.     return framePtr->tkwin;
  1793. }