home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / generic / tkFrame.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  29.1 KB  |  940 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkFrame.c --
  3.  *
  4.  *    This module implements "frame"  and "toplevel" widgets for
  5.  *    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-1995 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.  * SCCS: @(#) tkFrame.c 1.82 97/08/08 17:26:26
  16.  */
  17.  
  18. #include "default.h"
  19. #include "tkPort.h"
  20. #include "tkInt.h"
  21.  
  22. /*
  23.  * A data structure of the following type is kept for each
  24.  * frame that currently exists for this process:
  25.  */
  26.  
  27. typedef struct {
  28.     Tk_Window tkwin;        /* Window that embodies the frame.  NULL
  29.                  * means that the window has been destroyed
  30.                  * but the data structures haven't yet been
  31.                  * cleaned up. */
  32.     Display *display;        /* Display containing widget.  Used, among
  33.                  * other things, so that resources can be
  34.                  * freed even after tkwin has gone away. */
  35.     Tcl_Interp *interp;        /* Interpreter associated with widget.  Used
  36.                  * to delete widget command. */
  37.     Tcl_Command widgetCmd;    /* Token for frame's widget command. */
  38.     char *className;        /* Class name for widget (from configuration
  39.                  * option).  Malloc-ed. */
  40.     int mask;            /* Either FRAME or TOPLEVEL;  used to select
  41.                  * which configuration options are valid for
  42.                  * widget. */
  43.     char *screenName;        /* Screen on which widget is created.  Non-null
  44.                  * only for top-levels.  Malloc-ed, may be
  45.                  * NULL. */
  46.     char *visualName;        /* Textual description of visual for window,
  47.                  * from -visual option.  Malloc-ed, may be
  48.                  * NULL. */
  49.     char *colormapName;        /* Textual description of colormap for window,
  50.                  * from -colormap option.  Malloc-ed, may be
  51.                  * NULL. */
  52.     char *menuName;        /* Textual description of menu to use for
  53.                  * menubar. Malloc-ed, may be NULL. */
  54.     Colormap colormap;        /* If not None, identifies a colormap
  55.                  * allocated for this window, which must be
  56.                  * freed when the window is deleted. */
  57.     Tk_3DBorder border;        /* Structure used to draw 3-D border and
  58.                  * background.  NULL means no background
  59.                  * or border. */
  60.     int borderWidth;        /* Width of 3-D border (if any). */
  61.     int relief;            /* 3-d effect: TK_RELIEF_RAISED etc. */
  62.     int highlightWidth;        /* Width in pixels of highlight to draw
  63.                  * around widget when it has the focus.
  64.                  * 0 means don't draw a highlight. */
  65.     XColor *highlightBgColorPtr;
  66.                 /* Color for drawing traversal highlight
  67.                  * area when highlight is off. */
  68.     XColor *highlightColorPtr;    /* Color for drawing traversal highlight. */
  69.     int width;            /* Width to request for window.  <= 0 means
  70.                  * don't request any size. */
  71.     int height;            /* Height to request for window.  <= 0 means
  72.                  * don't request any size. */
  73.     Tk_Cursor cursor;        /* Current cursor for window, or None. */
  74.     char *takeFocus;        /* Value of -takefocus option;  not used in
  75.                  * the C code, but used by keyboard traversal
  76.                  * scripts.  Malloc'ed, but may be NULL. */
  77.     int isContainer;        /* 1 means this window is a container, 0 means
  78.                  * that it isn't. */
  79.     char *useThis;        /* If the window is embedded, this points to
  80.                  * the name of the window in which it is
  81.                  * embedded (malloc'ed).  For non-embedded
  82.                  * windows this is NULL. */
  83.     int flags;            /* Various flags;  see below for
  84.                  * definitions. */
  85. } Frame;
  86.  
  87. /*
  88.  * Flag bits for frames:
  89.  *
  90.  * REDRAW_PENDING:        Non-zero means a DoWhenIdle handler
  91.  *                has already been queued to redraw
  92.  *                this window.
  93.  * GOT_FOCUS:            Non-zero means this widget currently
  94.  *                has the input focus.
  95.  */
  96.  
  97. #define REDRAW_PENDING        1
  98. #define GOT_FOCUS        4
  99.  
  100. /*
  101.  * The following flag bits are used so that there can be separate
  102.  * defaults for some configuration options for frames and toplevels.
  103.  */
  104.  
  105. #define FRAME        TK_CONFIG_USER_BIT
  106. #define TOPLEVEL    (TK_CONFIG_USER_BIT << 1)
  107. #define BOTH        (FRAME | TOPLEVEL)
  108.  
  109. static Tk_ConfigSpec configSpecs[] = {
  110.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  111.     DEF_FRAME_BG_COLOR, Tk_Offset(Frame, border),
  112.     BOTH|TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK},
  113.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  114.     DEF_FRAME_BG_MONO, Tk_Offset(Frame, border),
  115.     BOTH|TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK},
  116.     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
  117.     (char *) NULL, 0, BOTH},
  118.     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
  119.     (char *) NULL, 0, BOTH},
  120.     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  121.     DEF_FRAME_BORDER_WIDTH, Tk_Offset(Frame, borderWidth), BOTH},
  122.     {TK_CONFIG_STRING, "-class", "class", "Class",
  123.     DEF_FRAME_CLASS, Tk_Offset(Frame, className), FRAME},
  124.     {TK_CONFIG_STRING, "-class", "class", "Class",
  125.     DEF_TOPLEVEL_CLASS, Tk_Offset(Frame, className), TOPLEVEL},
  126.     {TK_CONFIG_STRING, "-colormap", "colormap", "Colormap",
  127.     DEF_FRAME_COLORMAP, Tk_Offset(Frame, colormapName),
  128.     BOTH|TK_CONFIG_NULL_OK},
  129.     {TK_CONFIG_BOOLEAN, "-container", "container", "Container",
  130.     DEF_FRAME_CONTAINER, Tk_Offset(Frame, isContainer), BOTH},
  131.     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
  132.     DEF_FRAME_CURSOR, Tk_Offset(Frame, cursor), BOTH|TK_CONFIG_NULL_OK},
  133.     {TK_CONFIG_PIXELS, "-height", "height", "Height",
  134.     DEF_FRAME_HEIGHT, Tk_Offset(Frame, height), BOTH},
  135.     {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
  136.     "HighlightBackground", DEF_FRAME_HIGHLIGHT_BG,
  137.     Tk_Offset(Frame, highlightBgColorPtr), BOTH},
  138.     {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
  139.     DEF_FRAME_HIGHLIGHT, Tk_Offset(Frame, highlightColorPtr), BOTH},
  140.     {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
  141.     "HighlightThickness",
  142.     DEF_FRAME_HIGHLIGHT_WIDTH, Tk_Offset(Frame, highlightWidth), BOTH},
  143.     {TK_CONFIG_STRING, "-menu", "menu", "Menu",
  144.     DEF_TOPLEVEL_MENU, Tk_Offset(Frame, menuName),
  145.     TOPLEVEL|TK_CONFIG_NULL_OK},
  146.     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
  147.     DEF_FRAME_RELIEF, Tk_Offset(Frame, relief), BOTH},
  148.     {TK_CONFIG_STRING, "-screen", "screen", "Screen",
  149.     DEF_TOPLEVEL_SCREEN, Tk_Offset(Frame, screenName),
  150.     TOPLEVEL|TK_CONFIG_NULL_OK},
  151.     {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
  152.     DEF_FRAME_TAKE_FOCUS, Tk_Offset(Frame, takeFocus),
  153.     BOTH|TK_CONFIG_NULL_OK},
  154.     {TK_CONFIG_STRING, "-use", "use", "Use",
  155.     DEF_FRAME_USE, Tk_Offset(Frame, useThis), TOPLEVEL|TK_CONFIG_NULL_OK},
  156.     {TK_CONFIG_STRING, "-visual", "visual", "Visual",
  157.     DEF_FRAME_VISUAL, Tk_Offset(Frame, visualName),
  158.     BOTH|TK_CONFIG_NULL_OK},
  159.     {TK_CONFIG_PIXELS, "-width", "width", "Width",
  160.     DEF_FRAME_WIDTH, Tk_Offset(Frame, width), BOTH},
  161.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  162.     (char *) NULL, 0, 0}
  163. };
  164.  
  165. /*
  166.  * Forward declarations for procedures defined later in this file:
  167.  */
  168.  
  169. static int        ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp,
  170.                 Frame *framePtr, int argc, char **argv,
  171.                 int flags));
  172. static void        DestroyFrame _ANSI_ARGS_((char *memPtr));
  173. static void        DisplayFrame _ANSI_ARGS_((ClientData clientData));
  174. static void        FrameCmdDeletedProc _ANSI_ARGS_((
  175.                 ClientData clientData));
  176. static void        FrameEventProc _ANSI_ARGS_((ClientData clientData,
  177.                 XEvent *eventPtr));
  178. static int        FrameWidgetCmd _ANSI_ARGS_((ClientData clientData,
  179.                 Tcl_Interp *interp, int argc, char **argv));
  180. static void        MapFrame _ANSI_ARGS_((ClientData clientData));
  181.  
  182. /*
  183.  *--------------------------------------------------------------
  184.  *
  185.  * Tk_FrameCmd, Tk_ToplevelCmd --
  186.  *
  187.  *    These procedures are invoked to process the "frame" and
  188.  *    "toplevel" Tcl commands.  See the user documentation for
  189.  *    details on what they do.
  190.  *
  191.  * Results:
  192.  *    A standard Tcl result.
  193.  *
  194.  * Side effects:
  195.  *    See the user documentation.  These procedures are just wrappers;
  196.  *    they call ButtonCreate to do all of the real work.
  197.  *
  198.  *--------------------------------------------------------------
  199.  */
  200.  
  201. int
  202. Tk_FrameCmd(clientData, interp, argc, argv)
  203.     ClientData clientData;    /* Main window associated with
  204.                  * interpreter. */
  205.     Tcl_Interp *interp;        /* Current interpreter. */
  206.     int argc;            /* Number of arguments. */
  207.     char **argv;        /* Argument strings. */
  208. {
  209.     return TkCreateFrame(clientData, interp, argc, argv, 0, (char *) NULL);
  210. }
  211.  
  212. int
  213. Tk_ToplevelCmd(clientData, interp, argc, argv)
  214.     ClientData clientData;    /* Main window associated with
  215.                  * interpreter. */
  216.     Tcl_Interp *interp;        /* Current interpreter. */
  217.     int argc;            /* Number of arguments. */
  218.     char **argv;        /* Argument strings. */
  219. {
  220.     return TkCreateFrame(clientData, interp, argc, argv, 1, (char *) NULL);
  221. }
  222.  
  223. /*
  224.  *--------------------------------------------------------------
  225.  *
  226.  * TkFrameCreate --
  227.  *
  228.  *    This procedure is invoked to process the "frame" and "toplevel"
  229.  *    Tcl commands;  it is also invoked directly by Tk_Init to create
  230.  *    a new main window.  See the user documentation for the "frame"
  231.  *    and "toplevel" commands for details on what it does.
  232.  *
  233.  * Results:
  234.  *    A standard Tcl result.
  235.  *
  236.  * Side effects:
  237.  *    See the user documentation.
  238.  *
  239.  *--------------------------------------------------------------
  240.  */
  241.  
  242. int
  243. TkCreateFrame(clientData, interp, argc, argv, toplevel, appName)
  244.     ClientData clientData;    /* Main window associated with interpreter.
  245.                  * If we're called by Tk_Init to create a
  246.                  * new application, then this is NULL. */
  247.     Tcl_Interp *interp;        /* Current interpreter. */
  248.     int argc;            /* Number of arguments. */
  249.     char **argv;        /* Argument strings. */
  250.     int toplevel;        /* Non-zero means create a toplevel window,
  251.                  * zero means create a frame. */
  252.     char *appName;        /* Should only be non-NULL if clientData is
  253.                  * NULL:  gives the base name to use for the
  254.                  * new application. */
  255. {
  256.     Tk_Window tkwin = (Tk_Window) clientData;
  257.     Frame *framePtr;
  258.     Tk_Window new;
  259.     char *className, *screenName, *visualName, *colormapName, *arg, *useOption;
  260.     int i, c, length, depth;
  261.     unsigned int mask;
  262.     Colormap colormap;
  263.     Visual *visual;
  264.  
  265.     if (argc < 2) {
  266.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  267.         argv[0], " pathName ?options?\"", (char *) NULL);
  268.     return TCL_ERROR;
  269.     }
  270.  
  271.     /*
  272.      * Pre-process the argument list.  Scan through it to find any
  273.      * "-class", "-screen", "-visual", and "-colormap" options.  These
  274.      * arguments need to be processed specially, before the window
  275.      * is configured using the usual Tk mechanisms.
  276.      */
  277.  
  278.     className = colormapName = screenName = visualName = useOption = NULL;
  279.     colormap = None;
  280.     for (i = 2; i < argc; i += 2) {
  281.     arg = argv[i];
  282.     length = strlen(arg);
  283.     if (length < 2) {
  284.         continue;
  285.     }
  286.     c = arg[1];
  287.     if ((c == 'c') && (strncmp(arg, "-class", strlen(arg)) == 0)
  288.         && (length >= 3)) {
  289.         className = argv[i+1];
  290.     } else if ((c == 'c')
  291.         && (strncmp(arg, "-colormap", strlen(arg)) == 0)) {
  292.         colormapName = argv[i+1];
  293.     } else if ((c == 's') && toplevel
  294.         && (strncmp(arg, "-screen", strlen(arg)) == 0)) {
  295.         screenName = argv[i+1];
  296.     } else if ((c == 'u') && toplevel
  297.         && (strncmp(arg, "-use", strlen(arg)) == 0)) {
  298.         useOption = argv[i+1];
  299.     } else if ((c == 'v')
  300.         && (strncmp(arg, "-visual", strlen(arg)) == 0)) {
  301.         visualName = argv[i+1];
  302.     }
  303.     }
  304.  
  305.     /*
  306.      * Create the window, and deal with the special options -use,
  307.      * -classname, -colormap, -screenname, and -visual.  These options
  308.      * must be handle before calling ConfigureFrame below, and they must
  309.      * also be processed in a particular order, for the following
  310.      * reasons:
  311.      * 1. Must set the window's class before calling ConfigureFrame,
  312.      *    so that unspecified options are looked up in the option
  313.      *    database using the correct class.
  314.      * 2. Must set visual information before calling ConfigureFrame
  315.      *    so that colors are allocated in a proper colormap.
  316.      * 3. Must call TkpUseWindow before setting non-default visual
  317.      *    information, since TkpUseWindow changes the defaults.
  318.      */
  319.  
  320.     if (screenName == NULL) {
  321.     screenName = (toplevel) ? "" : NULL;
  322.     }
  323.     if (tkwin != NULL) {
  324.     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenName);
  325.     } else {
  326.     /*
  327.      * We were called from Tk_Init;  create a new application.
  328.      */
  329.  
  330.     if (appName == NULL) {
  331.         panic("TkCreateFrame didn't get application name");
  332.     }
  333.     new = TkCreateMainWindow(interp, screenName, appName);
  334.     }
  335.     if (new == NULL) {
  336.     goto error;
  337.     }
  338.     if (className == NULL) {
  339.     className = Tk_GetOption(new, "class", "Class");
  340.     if (className == NULL) {
  341.         className = (toplevel) ? "Toplevel" : "Frame";
  342.     }
  343.     }
  344.     Tk_SetClass(new, className);
  345.     if (useOption == NULL) {
  346.     useOption = Tk_GetOption(new, "use", "Use");
  347.     }
  348.     if (useOption != NULL) {
  349.     if (TkpUseWindow(interp, new, useOption) != TCL_OK) {
  350.         goto error;
  351.     }
  352.     }
  353.     if (visualName == NULL) {
  354.     visualName = Tk_GetOption(new, "visual", "Visual");
  355.     }
  356.     if (colormapName == NULL) {
  357.     colormapName = Tk_GetOption(new, "colormap", "Colormap");
  358.     }
  359.     if (visualName != NULL) {
  360.     visual = Tk_GetVisual(interp, new, visualName, &depth,
  361.         (colormapName == NULL) ? &colormap : (Colormap *) NULL);
  362.     if (visual == NULL) {
  363.         goto error;
  364.     }
  365.     Tk_SetWindowVisual(new, visual, depth, colormap);
  366.     }
  367.     if (colormapName != NULL) {
  368.     colormap = Tk_GetColormap(interp, new, colormapName);
  369.     if (colormap == None) {
  370.         goto error;
  371.     }
  372.     Tk_SetWindowColormap(new, colormap);
  373.     }
  374.  
  375.     /*
  376.      * For top-level windows, provide an initial geometry request of
  377.      * 200x200,  just so the window looks nicer on the screen if it
  378.      * doesn't request a size for itself.
  379.      */
  380.  
  381.     if (toplevel) {
  382.     Tk_GeometryRequest(new, 200, 200);
  383.     }
  384.  
  385.     /*
  386.      * Create the widget record, process configuration options, and
  387.      * create event handlers.  Then fill in a few additional fields
  388.      * in the widget record from the special options.
  389.      */
  390.  
  391.     framePtr = (Frame *) ckalloc(sizeof(Frame));
  392.     framePtr->tkwin = new;
  393.     framePtr->display = Tk_Display(new);
  394.     framePtr->interp = interp;
  395.     framePtr->widgetCmd = Tcl_CreateCommand(interp,
  396.         Tk_PathName(new), FrameWidgetCmd,
  397.         (ClientData) framePtr, FrameCmdDeletedProc);
  398.     framePtr->className = NULL;
  399.     framePtr->mask = (toplevel) ? TOPLEVEL : FRAME;
  400.     framePtr->screenName = NULL;
  401.     framePtr->visualName = NULL;
  402.     framePtr->colormapName = NULL;
  403.     framePtr->colormap = colormap;
  404.     framePtr->border = NULL;
  405.     framePtr->borderWidth = 0;
  406.     framePtr->relief = TK_RELIEF_FLAT;
  407.     framePtr->highlightWidth = 0;
  408.     framePtr->highlightBgColorPtr = NULL;
  409.     framePtr->highlightColorPtr = NULL;
  410.     framePtr->width = 0;
  411.     framePtr->height = 0;
  412.     framePtr->cursor = None;
  413.     framePtr->takeFocus = NULL;
  414.     framePtr->isContainer = 0;
  415.     framePtr->useThis = NULL;
  416.     framePtr->flags = 0;
  417.     framePtr->menuName = NULL;
  418.  
  419.     /*
  420.      * Store backreference to frame widget in window structure.
  421.      */
  422.     TkSetClassProcs(new, NULL, (ClientData) framePtr);
  423.  
  424.     mask = ExposureMask | StructureNotifyMask | FocusChangeMask;
  425.     if (toplevel) {
  426.         mask |= ActivateMask;
  427.     }
  428.     Tk_CreateEventHandler(new, mask, FrameEventProc, (ClientData) framePtr);
  429.     if (ConfigureFrame(interp, framePtr, argc-2, argv+2, 0) != TCL_OK) {
  430.     goto error;
  431.     }
  432.     if ((framePtr->isContainer)) {
  433.     if (framePtr->useThis == NULL) {
  434.         TkpMakeContainer(framePtr->tkwin);
  435.     } else {
  436.         Tcl_AppendResult(interp,"A window cannot have both the -use ",
  437.             "and the -container option set.");
  438.         return TCL_ERROR;
  439.     }
  440.     }
  441.     if (toplevel) {
  442.     Tcl_DoWhenIdle(MapFrame, (ClientData) framePtr);
  443.     }
  444.     interp->result = Tk_PathName(new);
  445.     return TCL_OK;
  446.  
  447.     error:
  448.     if (new != NULL) {
  449.     Tk_DestroyWindow(new);
  450.     }
  451.     return TCL_ERROR;
  452. }
  453.  
  454. /*
  455.  *--------------------------------------------------------------
  456.  *
  457.  * FrameWidgetCmd --
  458.  *
  459.  *    This procedure is invoked to process the Tcl command
  460.  *    that corresponds to a frame widget.  See the user
  461.  *    documentation for details on what it does.
  462.  *
  463.  * Results:
  464.  *    A standard Tcl result.
  465.  *
  466.  * Side effects:
  467.  *    See the user documentation.
  468.  *
  469.  *--------------------------------------------------------------
  470.  */
  471.  
  472. static int
  473. FrameWidgetCmd(clientData, interp, argc, argv)
  474.     ClientData clientData;    /* Information about frame widget. */
  475.     Tcl_Interp *interp;        /* Current interpreter. */
  476.     int argc;            /* Number of arguments. */
  477.     char **argv;        /* Argument strings. */
  478. {
  479.     register Frame *framePtr = (Frame *) clientData;
  480.     int result;
  481.     size_t length;
  482.     int c, i;
  483.  
  484.     if (argc < 2) {
  485.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  486.         argv[0], " option ?arg arg ...?\"", (char *) NULL);
  487.     return TCL_ERROR;
  488.     }
  489.     Tcl_Preserve((ClientData) framePtr);
  490.     c = argv[1][0];
  491.     length = strlen(argv[1]);
  492.     if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
  493.         && (length >= 2)) {
  494.     if (argc != 3) {
  495.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  496.             argv[0], " cget option\"",
  497.             (char *) NULL);
  498.         result = TCL_ERROR;
  499.         goto done;
  500.     }
  501.     result = Tk_ConfigureValue(interp, framePtr->tkwin, configSpecs,
  502.         (char *) framePtr, argv[2], framePtr->mask);
  503.     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
  504.         && (length >= 2)) {
  505.     if (argc == 2) {
  506.         result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs,
  507.             (char *) framePtr, (char *) NULL, framePtr->mask);
  508.     } else if (argc == 3) {
  509.         result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs,
  510.             (char *) framePtr, argv[2], framePtr->mask);
  511.     } else {
  512.         /*
  513.          * Don't allow the options -class, -colormap, -container,
  514.          * -newcmap, -screen, -use, or -visual to be changed.
  515.          */
  516.  
  517.         for (i = 2; i < argc; i++) {
  518.         length = strlen(argv[i]);
  519.         if (length < 2) {
  520.             continue;
  521.         }
  522.         c = argv[i][1];
  523.         if (((c == 'c') && (strncmp(argv[i], "-class", length) == 0)
  524.             && (length >= 2))
  525.             || ((c == 'c') && (framePtr->mask == TOPLEVEL)
  526.             && (strncmp(argv[i], "-colormap", length) == 0)
  527.             && (length >= 3))
  528.             || ((c == 'c')
  529.             && (strncmp(argv[i], "-container", length) == 0)
  530.             && (length >= 3))
  531.             || ((c == 's') && (framePtr->mask == TOPLEVEL)
  532.             && (strncmp(argv[i], "-screen", length) == 0))
  533.             || ((c == 'u') && (framePtr->mask == TOPLEVEL)
  534.             && (strncmp(argv[i], "-use", length) == 0))
  535.             || ((c == 'v') && (framePtr->mask == TOPLEVEL)
  536.             && (strncmp(argv[i], "-visual", length) == 0))) {
  537.             Tcl_AppendResult(interp, "can't modify ", argv[i],
  538.                 " option after widget is created", (char *) NULL);
  539.             result = TCL_ERROR;
  540.             goto done;
  541.         }
  542.         }
  543.         result = ConfigureFrame(interp, framePtr, argc-2, argv+2,
  544.             TK_CONFIG_ARGV_ONLY);
  545.     }
  546.     } else {
  547.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  548.         "\": must be cget or configure", (char *) NULL);
  549.     result = TCL_ERROR;
  550.     }
  551.  
  552.     done:
  553.     Tcl_Release((ClientData) framePtr);
  554.     return result;
  555. }
  556.  
  557. /*
  558.  *----------------------------------------------------------------------
  559.  *
  560.  * DestroyFrame --
  561.  *
  562.  *    This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
  563.  *    to clean up the internal structure of a frame at a safe time
  564.  *    (when no-one is using it anymore).
  565.  *
  566.  * Results:
  567.  *    None.
  568.  *
  569.  * Side effects:
  570.  *    Everything associated with the frame is freed up.
  571.  *
  572.  *----------------------------------------------------------------------
  573.  */
  574.  
  575. static void
  576. DestroyFrame(memPtr)
  577.     char *memPtr;        /* Info about frame widget. */
  578. {
  579.     register Frame *framePtr = (Frame *) memPtr;
  580.  
  581.     Tk_FreeOptions(configSpecs, (char *) framePtr, framePtr->display,
  582.         framePtr->mask);
  583.     if (framePtr->colormap != None) {
  584.     Tk_FreeColormap(framePtr->display, framePtr->colormap);
  585.     }
  586.     ckfree((char *) framePtr);
  587. }
  588.  
  589. /*
  590.  *----------------------------------------------------------------------
  591.  *
  592.  * ConfigureFrame --
  593.  *
  594.  *    This procedure is called to process an argv/argc list, plus
  595.  *    the Tk option database, in order to configure (or
  596.  *    reconfigure) a frame widget.
  597.  *
  598.  * Results:
  599.  *    The return value is a standard Tcl result.  If TCL_ERROR is
  600.  *    returned, then interp->result contains an error message.
  601.  *
  602.  * Side effects:
  603.  *    Configuration information, such as text string, colors, font,
  604.  *    etc. get set for framePtr;  old resources get freed, if there
  605.  *    were any.
  606.  *
  607.  *----------------------------------------------------------------------
  608.  */
  609.  
  610. static int
  611. ConfigureFrame(interp, framePtr, argc, argv, flags)
  612.     Tcl_Interp *interp;        /* Used for error reporting. */
  613.     register Frame *framePtr;    /* Information about widget;  may or may
  614.                  * not already have values for some fields. */
  615.     int argc;            /* Number of valid entries in argv. */
  616.     char **argv;        /* Arguments. */
  617.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  618. {
  619.     char *oldMenuName;
  620.     
  621.     /*
  622.      * Need the old menubar name for the menu code to delete it.
  623.      */
  624.     
  625.     if (framePtr->menuName == NULL) {
  626.         oldMenuName = NULL;
  627.     } else {
  628.         oldMenuName = ckalloc(strlen(framePtr->menuName) + 1);
  629.         strcpy(oldMenuName, framePtr->menuName);
  630.     }
  631.     
  632.     if (Tk_ConfigureWidget(interp, framePtr->tkwin, configSpecs,
  633.         argc, argv, (char *) framePtr, flags | framePtr->mask) != TCL_OK) {
  634.     return TCL_ERROR;
  635.     }
  636.  
  637.     if (((oldMenuName == NULL) && (framePtr->menuName != NULL))
  638.         || ((oldMenuName != NULL) && (framePtr->menuName == NULL))
  639.         || ((oldMenuName != NULL) && (framePtr->menuName != NULL)
  640.         && strcmp(oldMenuName, framePtr->menuName) != 0)) {
  641.     TkSetWindowMenuBar(interp, framePtr->tkwin, oldMenuName,
  642.         framePtr->menuName);
  643.     }
  644.     
  645.     if (framePtr->border != NULL) {
  646.     Tk_SetBackgroundFromBorder(framePtr->tkwin, framePtr->border);
  647.     } else {
  648.     Tk_SetWindowBackgroundPixmap(framePtr->tkwin, None);
  649.     }
  650.  
  651.     if (framePtr->highlightWidth < 0) {
  652.     framePtr->highlightWidth = 0;
  653.     }
  654.     Tk_SetInternalBorder(framePtr->tkwin,
  655.         framePtr->borderWidth + framePtr->highlightWidth);
  656.     if ((framePtr->width > 0) || (framePtr->height > 0)) {
  657.     Tk_GeometryRequest(framePtr->tkwin, framePtr->width,
  658.         framePtr->height);
  659.     }
  660.  
  661.     if (oldMenuName != NULL) {
  662.         ckfree(oldMenuName);
  663.     }
  664.  
  665.     if (Tk_IsMapped(framePtr->tkwin)) {
  666.     if (!(framePtr->flags & REDRAW_PENDING)) {
  667.         Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  668.     }
  669.     framePtr->flags |= REDRAW_PENDING;
  670.     }
  671.     return TCL_OK;
  672. }
  673.  
  674. /*
  675.  *----------------------------------------------------------------------
  676.  *
  677.  * DisplayFrame --
  678.  *
  679.  *    This procedure is invoked to display a frame widget.
  680.  *
  681.  * Results:
  682.  *    None.
  683.  *
  684.  * Side effects:
  685.  *    Commands are output to X to display the frame in its
  686.  *    current mode.
  687.  *
  688.  *----------------------------------------------------------------------
  689.  */
  690.  
  691. static void
  692. DisplayFrame(clientData)
  693.     ClientData clientData;    /* Information about widget. */
  694. {
  695.     register Frame *framePtr = (Frame *) clientData;
  696.     register Tk_Window tkwin = framePtr->tkwin;
  697.     GC gc;
  698.  
  699.     framePtr->flags &= ~REDRAW_PENDING;
  700.     if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)
  701.         || framePtr->isContainer) {
  702.     return;
  703.     }
  704.  
  705.     if (framePtr->border != NULL) {
  706.     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
  707.         framePtr->border, framePtr->highlightWidth,
  708.         framePtr->highlightWidth,
  709.         Tk_Width(tkwin) - 2*framePtr->highlightWidth,
  710.         Tk_Height(tkwin) - 2*framePtr->highlightWidth,
  711.         framePtr->borderWidth, framePtr->relief);
  712.     }
  713.     if (framePtr->highlightWidth != 0) {
  714.     if (framePtr->flags & GOT_FOCUS) {
  715.         gc = Tk_GCForColor(framePtr->highlightColorPtr,
  716.             Tk_WindowId(tkwin));
  717.     } else {
  718.         gc = Tk_GCForColor(framePtr->highlightBgColorPtr,
  719.             Tk_WindowId(tkwin));
  720.     }
  721.     Tk_DrawFocusHighlight(tkwin, gc, framePtr->highlightWidth,
  722.         Tk_WindowId(tkwin));
  723.     }
  724. }
  725.  
  726. /*
  727.  *--------------------------------------------------------------
  728.  *
  729.  * FrameEventProc --
  730.  *
  731.  *    This procedure is invoked by the Tk dispatcher on
  732.  *    structure changes to a frame.  For frames with 3D
  733.  *    borders, this procedure is also invoked for exposures.
  734.  *
  735.  * Results:
  736.  *    None.
  737.  *
  738.  * Side effects:
  739.  *    When the window gets deleted, internal structures get
  740.  *    cleaned up.  When it gets exposed, it is redisplayed.
  741.  *
  742.  *--------------------------------------------------------------
  743.  */
  744.  
  745. static void
  746. FrameEventProc(clientData, eventPtr)
  747.     ClientData clientData;    /* Information about window. */
  748.     register XEvent *eventPtr;    /* Information about event. */
  749. {
  750.     register Frame *framePtr = (Frame *) clientData;
  751.  
  752.     if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0))
  753.         || (eventPtr->type == ConfigureNotify)) {
  754.     goto redraw;
  755.     } else if (eventPtr->type == DestroyNotify) {
  756.     if (framePtr->menuName != NULL) {
  757.         TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin,
  758.             framePtr->menuName, NULL);
  759.         ckfree(framePtr->menuName);
  760.         framePtr->menuName = NULL;
  761.     }
  762.     if (framePtr->tkwin != NULL) {
  763.  
  764.         /*
  765.          * If this window is a container, then this event could be
  766.          * coming from the embedded application, in which case
  767.          * Tk_DestroyWindow hasn't been called yet.  When Tk_DestroyWindow
  768.          * is called later, then another destroy event will be generated.
  769.          * We need to be sure we ignore the second event, since the frame
  770.          * could be gone by then.  To do so, delete the event handler
  771.          * explicitly (normally it's done implicitly by Tk_DestroyWindow).
  772.          */
  773.     
  774.         Tk_DeleteEventHandler(framePtr->tkwin,
  775.             ExposureMask|StructureNotifyMask|FocusChangeMask,
  776.             FrameEventProc, (ClientData) framePtr);
  777.         framePtr->tkwin = NULL;
  778.             Tcl_DeleteCommandFromToken(framePtr->interp, framePtr->widgetCmd);
  779.     }
  780.     if (framePtr->flags & REDRAW_PENDING) {
  781.         Tcl_CancelIdleCall(DisplayFrame, (ClientData) framePtr);
  782.     }
  783.     Tcl_CancelIdleCall(MapFrame, (ClientData) framePtr);
  784.     Tcl_EventuallyFree((ClientData) framePtr, DestroyFrame);
  785.     } else if (eventPtr->type == FocusIn) {
  786.     if (eventPtr->xfocus.detail != NotifyInferior) {
  787.         framePtr->flags |= GOT_FOCUS;
  788.         if (framePtr->highlightWidth > 0) {
  789.         goto redraw;
  790.         }
  791.     }
  792.     } else if (eventPtr->type == FocusOut) {
  793.     if (eventPtr->xfocus.detail != NotifyInferior) {
  794.         framePtr->flags &= ~GOT_FOCUS;
  795.         if (framePtr->highlightWidth > 0) {
  796.         goto redraw;
  797.         }
  798.     }
  799.     } else if (eventPtr->type == ActivateNotify) {
  800.         TkpSetMainMenubar(framePtr->interp, framePtr->tkwin,
  801.             framePtr->menuName);
  802.     }
  803.     return;
  804.  
  805.     redraw:
  806.     if ((framePtr->tkwin != NULL) && !(framePtr->flags & REDRAW_PENDING)) {
  807.     Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  808.     framePtr->flags |= REDRAW_PENDING;
  809.     }
  810. }
  811.  
  812. /*
  813.  *----------------------------------------------------------------------
  814.  *
  815.  * FrameCmdDeletedProc --
  816.  *
  817.  *    This procedure is invoked when a widget command is deleted.  If
  818.  *    the widget isn't already in the process of being destroyed,
  819.  *    this command destroys it.
  820.  *
  821.  * Results:
  822.  *    None.
  823.  *
  824.  * Side effects:
  825.  *    The widget is destroyed.
  826.  *
  827.  *----------------------------------------------------------------------
  828.  */
  829.  
  830. static void
  831. FrameCmdDeletedProc(clientData)
  832.     ClientData clientData;    /* Pointer to widget record for widget. */
  833. {
  834.     Frame *framePtr = (Frame *) clientData;
  835.     Tk_Window tkwin = framePtr->tkwin;
  836.  
  837.     if (framePtr->menuName != NULL) {
  838.     TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin,
  839.         framePtr->menuName, NULL);
  840.     ckfree(framePtr->menuName);
  841.     framePtr->menuName = NULL;
  842.     }
  843.  
  844.     /*
  845.      * This procedure could be invoked either because the window was
  846.      * destroyed and the command was then deleted (in which case tkwin
  847.      * is NULL) or because the command was deleted, and then this procedure
  848.      * destroys the widget.
  849.      */
  850.  
  851.     if (tkwin != NULL) {
  852.     framePtr->tkwin = NULL;
  853.     Tk_DestroyWindow(tkwin);
  854.     }
  855. }
  856.  
  857. /*
  858.  *----------------------------------------------------------------------
  859.  *
  860.  * MapFrame --
  861.  *
  862.  *    This procedure is invoked as a when-idle handler to map a
  863.  *    newly-created top-level frame.
  864.  *
  865.  * Results:
  866.  *    None.
  867.  *
  868.  * Side effects:
  869.  *    The frame given by the clientData argument is mapped.
  870.  *
  871.  *----------------------------------------------------------------------
  872.  */
  873.  
  874. static void
  875. MapFrame(clientData)
  876.     ClientData clientData;        /* Pointer to frame structure. */
  877. {
  878.     Frame *framePtr = (Frame *) clientData;
  879.  
  880.     /*
  881.      * Wait for all other background events to be processed before
  882.      * mapping window.  This ensures that the window's correct geometry
  883.      * will have been determined before it is first mapped, so that the
  884.      * window manager doesn't get a false idea of its desired geometry.
  885.      */
  886.  
  887.     Tcl_Preserve((ClientData) framePtr);
  888.     while (1) {
  889.     if (Tcl_DoOneEvent(TCL_IDLE_EVENTS) == 0) {
  890.         break;
  891.     }
  892.  
  893.     /*
  894.      * After each event, make sure that the window still exists
  895.      * and quit if the window has been destroyed.
  896.      */
  897.  
  898.     if (framePtr->tkwin == NULL) {
  899.         Tcl_Release((ClientData) framePtr);
  900.         return;
  901.     }
  902.     }
  903.     Tk_MapWindow(framePtr->tkwin);
  904.     Tcl_Release((ClientData) framePtr);
  905. }
  906.  
  907. /*
  908.  *--------------------------------------------------------------
  909.  *
  910.  * TkInstallFrameMenu --
  911.  *
  912.  *    This function is needed when a Windows HWND is created
  913.  *    and a menubar has been set to the window with a system
  914.  *    menu. It notifies the menu package so that the system
  915.  *    menu can be rebuilt.
  916.  *
  917.  * Results:
  918.  *    None.
  919.  *
  920.  * Side effects:
  921.  *    The system menu (if any) is created for the menubar
  922.  *    associated with this frame.
  923.  *
  924.  *--------------------------------------------------------------
  925.  */
  926.  
  927. void
  928. TkInstallFrameMenu(tkwin)
  929.     Tk_Window tkwin;        /* The window that was just created. */
  930. {
  931.     TkWindow *winPtr = (TkWindow *) tkwin;
  932.  
  933.     if (winPtr->mainPtr != NULL) {
  934.     Frame *framePtr;
  935.     framePtr = (Frame*) winPtr->instanceData;
  936.     TkpMenuNotifyToplevelCreate(winPtr->mainPtr->interp, 
  937.         framePtr->menuName);
  938.     }
  939. }
  940.