home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkFrame.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-16  |  15.7 KB  |  515 lines

  1. /* 
  2.  * tkFrame.c --
  3.  *
  4.  *    This module implements "frame" widgets for the Tk
  5.  *    toolkit.  Frames are windows with a background color
  6.  *    and possibly a 3-D effect, but no other attributes.
  7.  *
  8.  * Copyright (c) 1990-1993 The Regents of the University of California.
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and its documentation for any purpose, provided that the
  14.  * above copyright notice and the following two paragraphs appear in
  15.  * all copies of this software.
  16.  * 
  17.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  18.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  19.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  20.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  21.  *
  22.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  23.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  24.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  25.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  26.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  27.  */
  28.  
  29. #ifndef lint
  30. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkFrame.c,v 1.31 93/06/16 17:15:03 ouster Exp $ SPRITE (Berkeley)";
  31. #endif
  32.  
  33. #include "default.h"
  34. #include "tkConfig.h"
  35. #include "tk.h"
  36.  
  37. /*
  38.  * A data structure of the following type is kept for each
  39.  * frame that currently exists for this process:
  40.  */
  41.  
  42. typedef struct {
  43.     Tk_Window tkwin;        /* Window that embodies the frame.  NULL
  44.                  * means that the window has been destroyed
  45.                  * but the data structures haven't yet been
  46.                  * cleaned up.*/
  47.     Display *display;        /* Display containing widget.  Used, among
  48.                  * other things, so that resources can be
  49.                  * freed even after tkwin has gone away. */
  50.     Tcl_Interp *interp;        /* Interpreter associated with
  51.                  * widget.  Used to delete widget
  52.                  * command.  */
  53.     Tk_Uid screenName;        /* If this window isn't a toplevel window
  54.                  * then this is NULL;  otherwise it gives
  55.                  * the name of the screen on which window
  56.                  * is displayed. */
  57.     Tk_3DBorder border;        /* Structure used to draw 3-D border and
  58.                  * background. */
  59.     int borderWidth;        /* Width of 3-D border (if any). */
  60.     int relief;            /* 3-d effect: TK_RELIEF_RAISED etc. */
  61.     int width;            /* Width to request for window.  <= 0 means
  62.                  * don't request any size. */
  63.     int height;            /* Height to request for window.  <= 0 means
  64.                  * don't request any size. */
  65.     char *geometry;        /* Geometry that user requested.  NULL
  66.                  * means use width and height instead. 
  67.                  * Malloc'ed. */
  68.     Cursor cursor;        /* Current cursor for window, or None. */
  69.     int flags;            /* Various flags;  see below for
  70.                  * definitions. */
  71. } Frame;
  72.  
  73. /*
  74.  * Flag bits for frames:
  75.  *
  76.  * REDRAW_PENDING:        Non-zero means a DoWhenIdle handler
  77.  *                has already been queued to redraw
  78.  *                this window.
  79.  * CLEAR_NEEDED;        Need to clear the window when redrawing.
  80.  */
  81.  
  82. #define REDRAW_PENDING        1
  83. #define CLEAR_NEEDED        2
  84.  
  85. static Tk_ConfigSpec configSpecs[] = {
  86.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  87.     DEF_FRAME_BG_COLOR, Tk_Offset(Frame, border), TK_CONFIG_COLOR_ONLY},
  88.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  89.     DEF_FRAME_BG_MONO, Tk_Offset(Frame, border), TK_CONFIG_MONO_ONLY},
  90.     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
  91.     (char *) NULL, 0, 0},
  92.     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
  93.     (char *) NULL, 0, 0},
  94.     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  95.     DEF_FRAME_BORDER_WIDTH, Tk_Offset(Frame, borderWidth), 0},
  96.     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
  97.     DEF_FRAME_CURSOR, Tk_Offset(Frame, cursor), TK_CONFIG_NULL_OK},
  98.     {TK_CONFIG_STRING, "-geometry", "geometry", "Geometry",
  99.     DEF_FRAME_GEOMETRY, Tk_Offset(Frame, geometry), TK_CONFIG_NULL_OK},
  100.     {TK_CONFIG_PIXELS, "-height", "height", "Height",
  101.     DEF_FRAME_HEIGHT, Tk_Offset(Frame, height), 0},
  102.     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
  103.     DEF_FRAME_RELIEF, Tk_Offset(Frame, relief), 0},
  104.     {TK_CONFIG_PIXELS, "-width", "width", "Width",
  105.     DEF_FRAME_WIDTH, Tk_Offset(Frame, width), 0},
  106.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  107.     (char *) NULL, 0, 0}
  108. };
  109.  
  110. /*
  111.  * Forward declarations for procedures defined later in this file:
  112.  */
  113.  
  114. static int    ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp,
  115.             Frame *framePtr, int argc, char **argv, int flags));
  116. static void    DestroyFrame _ANSI_ARGS_((ClientData clientData));
  117. static void    DisplayFrame _ANSI_ARGS_((ClientData clientData));
  118. static void    FrameEventProc _ANSI_ARGS_((ClientData clientData,
  119.             XEvent *eventPtr));
  120. static int    FrameWidgetCmd _ANSI_ARGS_((ClientData clientData,
  121.             Tcl_Interp *interp, int argc, char **argv));
  122. static void    MapFrame _ANSI_ARGS_((ClientData clientData));
  123.  
  124. /*
  125.  *--------------------------------------------------------------
  126.  *
  127.  * Tk_FrameCmd --
  128.  *
  129.  *    This procedure is invoked to process the "frame" and
  130.  *    "toplevel" Tcl commands.  See the user documentation for
  131.  *    details on what it does.
  132.  *
  133.  * Results:
  134.  *    A standard Tcl result.
  135.  *
  136.  * Side effects:
  137.  *    See the user documentation.
  138.  *
  139.  *--------------------------------------------------------------
  140.  */
  141.  
  142. int
  143. Tk_FrameCmd(clientData, interp, argc, argv)
  144.     ClientData clientData;    /* Main window associated with
  145.                  * interpreter. */
  146.     Tcl_Interp *interp;        /* Current interpreter. */
  147.     int argc;            /* Number of arguments. */
  148.     char **argv;        /* Argument strings. */
  149. {
  150.     Tk_Window tkwin = (Tk_Window) clientData;
  151.     Tk_Window new;
  152.     register Frame *framePtr;
  153.     Tk_Uid screenUid;
  154.     char *className, *screen;
  155.     int src, dst;
  156.  
  157.     if (argc < 2) {
  158.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  159.         argv[0], " pathName ?options?\"", (char *) NULL);
  160.     return TCL_ERROR;
  161.     }
  162.  
  163.     /*
  164.      * The code below is a special hack that extracts a few key
  165.      * options from the argument list now, rather than letting
  166.      * ConfigureFrame do it.  This is necessary because we have
  167.      * to know the window's screen (if it's top-level) and its
  168.      * class before creating the window.
  169.      */
  170.  
  171.     screen = NULL;
  172.     className = (argv[0][0] == 't') ? "Toplevel" : "Frame";
  173.     for (src = 2, dst = 2; src < argc;  src += 2) {
  174.     char c;
  175.  
  176.     c = argv[src][1];
  177.     if ((c == 'c')
  178.         && (strncmp(argv[src], "-class", strlen(argv[src])) == 0)) {
  179.         className = argv[src+1];
  180.     } else if ((argv[0][0] == 't') && (c == 's')
  181.         && (strncmp(argv[src], "-screen", strlen(argv[src])) == 0)) {
  182.         screen = argv[src+1];
  183.     } else {
  184.         argv[dst] = argv[src];
  185.         argv[dst+1] = argv[src+1];
  186.         dst += 2;
  187.     }
  188.     }
  189.     argc -= src-dst;
  190.  
  191.     /*
  192.      * Provide a default screen for top-level windows (same as screen
  193.      * of parent window).
  194.      */
  195.  
  196.     if ((argv[0][0] == 't') && (screen == NULL)) {
  197.     screen = "";
  198.     }
  199.     if (screen != NULL) {
  200.     screenUid = Tk_GetUid(screen);
  201.     } else {
  202.     screenUid = NULL;
  203.     }
  204.  
  205.     /*
  206.      * Create the window.
  207.      */
  208.  
  209.     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenUid);
  210.     if (new == NULL) {
  211.     return TCL_ERROR;
  212.     }
  213.  
  214.     Tk_SetClass(new, className);
  215.     framePtr = (Frame *) ckalloc(sizeof(Frame));
  216.     framePtr->tkwin = new;
  217.     framePtr->display = Tk_Display(new);
  218.     framePtr->interp = interp;
  219.     framePtr->screenName = screenUid;
  220.     framePtr->flags = 0;
  221.     Tk_CreateEventHandler(framePtr->tkwin, ExposureMask|StructureNotifyMask,
  222.         FrameEventProc, (ClientData) framePtr);
  223.     Tcl_CreateCommand(interp, Tk_PathName(framePtr->tkwin),
  224.         FrameWidgetCmd, (ClientData) framePtr, (void (*)()) NULL);
  225.  
  226.     if (ConfigureFrame(interp, framePtr, argc-2, argv+2, 0) != TCL_OK) {
  227.     Tk_DestroyWindow(framePtr->tkwin);
  228.     return TCL_ERROR;
  229.     }
  230.     if (screenUid != NULL) {
  231.     Tk_DoWhenIdle(MapFrame, (ClientData) framePtr);
  232.     }
  233.     interp->result = Tk_PathName(framePtr->tkwin);
  234.     return TCL_OK;
  235. }
  236.  
  237. /*
  238.  *--------------------------------------------------------------
  239.  *
  240.  * FrameWidgetCmd --
  241.  *
  242.  *    This procedure is invoked to process the Tcl command
  243.  *    that corresponds to a frame widget.  See the user
  244.  *    documentation for details on what it does.
  245.  *
  246.  * Results:
  247.  *    A standard Tcl result.
  248.  *
  249.  * Side effects:
  250.  *    See the user documentation.
  251.  *
  252.  *--------------------------------------------------------------
  253.  */
  254.  
  255. static int
  256. FrameWidgetCmd(clientData, interp, argc, argv)
  257.     ClientData clientData;    /* Information about frame widget. */
  258.     Tcl_Interp *interp;        /* Current interpreter. */
  259.     int argc;            /* Number of arguments. */
  260.     char **argv;        /* Argument strings. */
  261. {
  262.     register Frame *framePtr = (Frame *) clientData;
  263.     int result = TCL_OK;
  264.     int length;
  265.     char c;
  266.  
  267.     if (argc < 2) {
  268.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  269.         argv[0], " option ?arg arg ...?\"", (char *) NULL);
  270.     return TCL_ERROR;
  271.     }
  272.     Tk_Preserve((ClientData) framePtr);
  273.     c = argv[1][0];
  274.     length = strlen(argv[1]);
  275.     if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
  276.     if (argc == 2) {
  277.         result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs,
  278.             (char *) framePtr, (char *) NULL, 0);
  279.     } else if (argc == 3) {
  280.         result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs,
  281.             (char *) framePtr, argv[2], 0);
  282.     } else {
  283.         result = ConfigureFrame(interp, framePtr, argc-2, argv+2,
  284.             TK_CONFIG_ARGV_ONLY);
  285.     }
  286.     } else {
  287.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  288.         "\":  must be configure", (char *) NULL);
  289.     result = TCL_ERROR;
  290.     }
  291.     Tk_Release((ClientData) framePtr);
  292.     return result;
  293. }
  294.  
  295. /*
  296.  *----------------------------------------------------------------------
  297.  *
  298.  * DestroyFrame --
  299.  *
  300.  *    This procedure is invoked by Tk_EventuallyFree or Tk_Release
  301.  *    to clean up the internal structure of a frame at a safe time
  302.  *    (when no-one is using it anymore).
  303.  *
  304.  * Results:
  305.  *    None.
  306.  *
  307.  * Side effects:
  308.  *    Everything associated with the frame is freed up.
  309.  *
  310.  *----------------------------------------------------------------------
  311.  */
  312.  
  313. static void
  314. DestroyFrame(clientData)
  315.     ClientData clientData;    /* Info about frame widget. */
  316. {
  317.     register Frame *framePtr = (Frame *) clientData;
  318.  
  319.     Tk_FreeOptions(configSpecs, (char *) framePtr, framePtr->display, 0);
  320.     ckfree((char *) framePtr);
  321. }
  322.  
  323. /*
  324.  *----------------------------------------------------------------------
  325.  *
  326.  * ConfigureFrame --
  327.  *
  328.  *    This procedure is called to process an argv/argc list, plus
  329.  *    the Tk option database, in order to configure (or
  330.  *    reconfigure) a frame widget.
  331.  *
  332.  * Results:
  333.  *    The return value is a standard Tcl result.  If TCL_ERROR is
  334.  *    returned, then interp->result contains an error message.
  335.  *
  336.  * Side effects:
  337.  *    Configuration information, such as text string, colors, font,
  338.  *    etc. get set for framePtr;  old resources get freed, if there
  339.  *    were any.
  340.  *
  341.  *----------------------------------------------------------------------
  342.  */
  343.  
  344. static int
  345. ConfigureFrame(interp, framePtr, argc, argv, flags)
  346.     Tcl_Interp *interp;        /* Used for error reporting. */
  347.     register Frame *framePtr;    /* Information about widget;  may or may
  348.                  * not already have values for some fields. */
  349.     int argc;            /* Number of valid entries in argv. */
  350.     char **argv;        /* Arguments. */
  351.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  352. {
  353.     if (Tk_ConfigureWidget(interp, framePtr->tkwin, configSpecs,
  354.         argc, argv, (char *) framePtr, flags) != TCL_OK) {
  355.     return TCL_ERROR;
  356.     }
  357.  
  358.     Tk_SetBackgroundFromBorder(framePtr->tkwin, framePtr->border);
  359.     Tk_SetInternalBorder(framePtr->tkwin, framePtr->borderWidth);
  360.     if (framePtr->geometry != NULL) {
  361.     int height, width;
  362.  
  363.     if (sscanf(framePtr->geometry, "%dx%d", &width, &height) != 2) {
  364.         Tcl_AppendResult(interp, "bad geometry \"", framePtr->geometry,
  365.             "\": expected widthxheight", (char *) NULL);
  366.         return TCL_ERROR;
  367.     }
  368.     Tk_GeometryRequest(framePtr->tkwin, width, height);
  369.     } else if ((framePtr->width > 0) && (framePtr->height > 0)) {
  370.     Tk_GeometryRequest(framePtr->tkwin, framePtr->width,
  371.         framePtr->height);
  372.     }
  373.  
  374.     if (Tk_IsMapped(framePtr->tkwin)
  375.         && !(framePtr->flags & REDRAW_PENDING)) {
  376.     Tk_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  377.     framePtr->flags |= REDRAW_PENDING|CLEAR_NEEDED;
  378.     }
  379.     return TCL_OK;
  380. }
  381.  
  382. /*
  383.  *----------------------------------------------------------------------
  384.  *
  385.  * DisplayFrame --
  386.  *
  387.  *    This procedure is invoked to display a frame widget.
  388.  *
  389.  * Results:
  390.  *    None.
  391.  *
  392.  * Side effects:
  393.  *    Commands are output to X to display the frame in its
  394.  *    current mode.
  395.  *
  396.  *----------------------------------------------------------------------
  397.  */
  398.  
  399. static void
  400. DisplayFrame(clientData)
  401.     ClientData clientData;    /* Information about widget. */
  402. {
  403.     register Frame *framePtr = (Frame *) clientData;
  404.     register Tk_Window tkwin = framePtr->tkwin;
  405.  
  406.     framePtr->flags &= ~REDRAW_PENDING;
  407.     if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  408.     return;
  409.     }
  410.  
  411.     if (framePtr->flags & CLEAR_NEEDED) {
  412.     XClearWindow(framePtr->display, Tk_WindowId(tkwin));
  413.     framePtr->flags &= ~CLEAR_NEEDED;
  414.     }
  415.     if ((framePtr->border != NULL)
  416.         && (framePtr->relief != TK_RELIEF_FLAT)) {
  417.     Tk_Draw3DRectangle(framePtr->display, Tk_WindowId(tkwin),
  418.         framePtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin),
  419.         framePtr->borderWidth, framePtr->relief);
  420.     }
  421. }
  422.  
  423. /*
  424.  *--------------------------------------------------------------
  425.  *
  426.  * FrameEventProc --
  427.  *
  428.  *    This procedure is invoked by the Tk dispatcher on
  429.  *    structure changes to a frame.  For frames with 3D
  430.  *    borders, this procedure is also invoked for exposures.
  431.  *
  432.  * Results:
  433.  *    None.
  434.  *
  435.  * Side effects:
  436.  *    When the window gets deleted, internal structures get
  437.  *    cleaned up.  When it gets exposed, it is redisplayed.
  438.  *
  439.  *--------------------------------------------------------------
  440.  */
  441.  
  442. static void
  443. FrameEventProc(clientData, eventPtr)
  444.     ClientData clientData;    /* Information about window. */
  445.     register XEvent *eventPtr;    /* Information about event. */
  446. {
  447.     register Frame *framePtr = (Frame *) clientData;
  448.  
  449.     if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
  450.     if ((framePtr->relief != TK_RELIEF_FLAT) && (framePtr->tkwin != NULL)
  451.         && !(framePtr->flags & REDRAW_PENDING)) {
  452.         Tk_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  453.         framePtr->flags |= REDRAW_PENDING;
  454.     }
  455.     } else if (eventPtr->type == DestroyNotify) {
  456.     Tcl_DeleteCommand(framePtr->interp, Tk_PathName(framePtr->tkwin));
  457.     framePtr->tkwin = NULL;
  458.     if (framePtr->flags & REDRAW_PENDING) {
  459.         Tk_CancelIdleCall(DisplayFrame, (ClientData) framePtr);
  460.     }
  461.     Tk_CancelIdleCall(MapFrame, (ClientData) framePtr);
  462.     Tk_EventuallyFree((ClientData) framePtr, DestroyFrame);
  463.     }
  464. }
  465.  
  466. /*
  467.  *----------------------------------------------------------------------
  468.  *
  469.  * MapFrame --
  470.  *
  471.  *    This procedure is invoked as a when-idle handler to map a
  472.  *    newly-created top-level frame.
  473.  *
  474.  * Results:
  475.  *    None.
  476.  *
  477.  * Side effects:
  478.  *    The frame given by the clientData argument is mapped.
  479.  *
  480.  *----------------------------------------------------------------------
  481.  */
  482.  
  483. static void
  484. MapFrame(clientData)
  485.     ClientData clientData;        /* Pointer to frame structure. */
  486. {
  487.     Frame *framePtr = (Frame *) clientData;
  488.  
  489.     /*
  490.      * Wait for all other background events to be processed before
  491.      * mapping window.  This ensures that the window's correct geometry
  492.      * will have been determined before it is first mapped, so that the
  493.      * window manager doesn't get a false idea of its desired geometry.
  494.      */
  495.  
  496.     Tk_Preserve((ClientData) framePtr);
  497.     while (1) {
  498.     if (Tk_DoOneEvent(TK_IDLE_EVENTS) == 0) {
  499.         break;
  500.     }
  501.  
  502.     /*
  503.      * After each event, make sure that the window still exists
  504.      * and quit if the window has been destroyed.
  505.      */
  506.  
  507.     if (framePtr->tkwin == NULL) {
  508.         Tk_Release((ClientData) framePtr);
  509.         return;
  510.     }
  511.     }
  512.     Tk_MapWindow(framePtr->tkwin);
  513.     Tk_Release((ClientData) framePtr);
  514. }
  515.