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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkUtil.c --
  3.  *
  4.  * This file contains miscellaneous utility procedures that
  5.  * are used by the rest of Tk, such as a procedure for drawing
  6.  * a focus highlight.
  7.  *
  8.  * Copyright (c) 1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tkUtil.c,v 1.12.2.1 2004/10/27 00:37:38 davygrvy Exp $
  15.  */
  16. #include "tkInt.h"
  17. #include "tkPort.h"
  18. /*
  19.  * The structure below defines the implementation of the "statekey"
  20.  * Tcl object, used for quickly finding a mapping in a TkStateMap.
  21.  */
  22. Tcl_ObjType tkStateKeyObjType = {
  23.     "statekey", /* name */
  24.     (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */
  25.     (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */
  26.     (Tcl_UpdateStringProc *) NULL, /* updateStringProc */
  27.     (Tcl_SetFromAnyProc *) NULL /* setFromAnyProc */
  28. };
  29. /*
  30.  *--------------------------------------------------------------
  31.  *
  32.  * TkStateParseProc --
  33.  *
  34.  * This procedure is invoked during option processing to handle
  35.  * the "-state" and "-default" options.
  36.  *
  37.  * Results:
  38.  * A standard Tcl return value.
  39.  *
  40.  * Side effects:
  41.  * The state for a given item gets replaced by the state
  42.  * indicated in the value argument.
  43.  *
  44.  *--------------------------------------------------------------
  45.  */
  46. int
  47. TkStateParseProc(clientData, interp, tkwin, value, widgRec, offset)
  48.     ClientData clientData; /* some flags.*/
  49.     Tcl_Interp *interp; /* Used for reporting errors. */
  50.     Tk_Window tkwin; /* Window containing canvas widget. */
  51.     CONST char *value; /* Value of option. */
  52.     char *widgRec; /* Pointer to record for item. */
  53.     int offset; /* Offset into item. */
  54. {
  55.     int c;
  56.     int flags = (int)clientData;
  57.     size_t length;
  58.     register Tk_State *statePtr = (Tk_State *) (widgRec + offset);
  59.     if(value == NULL || *value == 0) {
  60. *statePtr = TK_STATE_NULL;
  61. return TCL_OK;
  62.     }
  63.     c = value[0];
  64.     length = strlen(value);
  65.     if ((c == 'n') && (strncmp(value, "normal", length) == 0)) {
  66. *statePtr = TK_STATE_NORMAL;
  67. return TCL_OK;
  68.     }
  69.     if ((c == 'd') && (strncmp(value, "disabled", length) == 0)) {
  70. *statePtr = TK_STATE_DISABLED;
  71. return TCL_OK;
  72.     }
  73.     if ((c == 'a') && (flags&1) && (strncmp(value, "active", length) == 0)) {
  74. *statePtr = TK_STATE_ACTIVE;
  75. return TCL_OK;
  76.     }
  77.     if ((c == 'h') && (flags&2) && (strncmp(value, "hidden", length) == 0)) {
  78. *statePtr = TK_STATE_HIDDEN;
  79. return TCL_OK;
  80.     }
  81.     Tcl_AppendResult(interp, "bad ", (flags&4)?"-default" : "state",
  82.     " value "", value, "": must be normal",
  83.     (char *) NULL);
  84.     if (flags&1) {
  85. Tcl_AppendResult(interp, ", active",(char *) NULL);
  86.     }
  87.     if (flags&2) {
  88. Tcl_AppendResult(interp, ", hidden",(char *) NULL);
  89.     }
  90.     if (flags&3) {
  91. Tcl_AppendResult(interp, ",",(char *) NULL);
  92.     }
  93.     Tcl_AppendResult(interp, " or disabled",(char *) NULL);
  94.     *statePtr = TK_STATE_NORMAL;
  95.     return TCL_ERROR;
  96. }
  97. /*
  98.  *--------------------------------------------------------------
  99.  *
  100.  * TkStatePrintProc --
  101.  *
  102.  * This procedure is invoked by the Tk configuration code
  103.  * to produce a printable string for the "-state"
  104.  * configuration option.
  105.  *
  106.  * Results:
  107.  * The return value is a string describing the state for
  108.  * the item referred to by "widgRec".  In addition, *freeProcPtr
  109.  * is filled in with the address of a procedure to call to free
  110.  * the result string when it's no longer needed (or NULL to
  111.  * indicate that the string doesn't need to be freed).
  112.  *
  113.  * Side effects:
  114.  * None.
  115.  *
  116.  *--------------------------------------------------------------
  117.  */
  118. char *
  119. TkStatePrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
  120.     ClientData clientData; /* Ignored. */
  121.     Tk_Window tkwin; /* Window containing canvas widget. */
  122.     char *widgRec; /* Pointer to record for item. */
  123.     int offset; /* Offset into item. */
  124.     Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
  125.  * information about how to reclaim
  126.  * storage for return string. */
  127. {
  128.     register Tk_State *statePtr = (Tk_State *) (widgRec + offset);
  129.     if (*statePtr==TK_STATE_NORMAL) {
  130. return "normal";
  131.     } else if (*statePtr==TK_STATE_DISABLED) {
  132. return "disabled";
  133.     } else if (*statePtr==TK_STATE_HIDDEN) {
  134. return "hidden";
  135.     } else if (*statePtr==TK_STATE_ACTIVE) {
  136. return "active";
  137.     } else {
  138. return "";
  139.     }
  140. }
  141. /*
  142.  *--------------------------------------------------------------
  143.  *
  144.  * TkOrientParseProc --
  145.  *
  146.  * This procedure is invoked during option processing to handle
  147.  * the "-orient" option.
  148.  *
  149.  * Results:
  150.  * A standard Tcl return value.
  151.  *
  152.  * Side effects:
  153.  * The orientation for a given item gets replaced by the orientation
  154.  * indicated in the value argument.
  155.  *
  156.  *--------------------------------------------------------------
  157.  */
  158. int
  159. TkOrientParseProc(clientData, interp, tkwin, value, widgRec, offset)
  160.     ClientData clientData; /* some flags.*/
  161.     Tcl_Interp *interp; /* Used for reporting errors. */
  162.     Tk_Window tkwin; /* Window containing canvas widget. */
  163.     CONST char *value; /* Value of option. */
  164.     char *widgRec; /* Pointer to record for item. */
  165.     int offset; /* Offset into item. */
  166. {
  167.     int c;
  168.     size_t length;
  169.     register int *orientPtr = (int *) (widgRec + offset);
  170.     if(value == NULL || *value == 0) {
  171. *orientPtr = 0;
  172. return TCL_OK;
  173.     }
  174.     c = value[0];
  175.     length = strlen(value);
  176.     if ((c == 'h') && (strncmp(value, "horizontal", length) == 0)) {
  177. *orientPtr = 0;
  178. return TCL_OK;
  179.     }
  180.     if ((c == 'v') && (strncmp(value, "vertical", length) == 0)) {
  181. *orientPtr = 1;
  182. return TCL_OK;
  183.     }
  184.     Tcl_AppendResult(interp, "bad orientation "", value,
  185.     "": must be vertical or horizontal",
  186.     (char *) NULL);
  187.     *orientPtr = 0;
  188.     return TCL_ERROR;
  189. }
  190. /*
  191.  *--------------------------------------------------------------
  192.  *
  193.  * TkOrientPrintProc --
  194.  *
  195.  * This procedure is invoked by the Tk configuration code
  196.  * to produce a printable string for the "-orient"
  197.  * configuration option.
  198.  *
  199.  * Results:
  200.  * The return value is a string describing the orientation for
  201.  * the item referred to by "widgRec".  In addition, *freeProcPtr
  202.  * is filled in with the address of a procedure to call to free
  203.  * the result string when it's no longer needed (or NULL to
  204.  * indicate that the string doesn't need to be freed).
  205.  *
  206.  * Side effects:
  207.  * None.
  208.  *
  209.  *--------------------------------------------------------------
  210.  */
  211. char *
  212. TkOrientPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
  213.     ClientData clientData; /* Ignored. */
  214.     Tk_Window tkwin; /* Window containing canvas widget. */
  215.     char *widgRec; /* Pointer to record for item. */
  216.     int offset; /* Offset into item. */
  217.     Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
  218.  * information about how to reclaim
  219.  * storage for return string. */
  220. {
  221.     register int *statePtr = (int *) (widgRec + offset);
  222.     if (*statePtr) {
  223. return "vertical";
  224.     } else {
  225. return "horizontal";
  226.     }
  227. }
  228. /*
  229.  *----------------------------------------------------------------------
  230.  *
  231.  * TkOffsetParseProc --
  232.  *
  233.  * Converts the offset of a stipple or tile into the Tk_TSOffset structure.
  234.  *
  235.  *----------------------------------------------------------------------
  236.  */
  237. int
  238. TkOffsetParseProc(clientData, interp, tkwin, value, widgRec, offset)
  239.     ClientData clientData; /* not used */
  240.     Tcl_Interp *interp; /* Interpreter to send results back to */
  241.     Tk_Window tkwin; /* Window on same display as tile */
  242.     CONST char *value; /* Name of image */
  243.     char *widgRec; /* Widget structure record */
  244.     int offset; /* Offset of tile in record */
  245. {
  246.     Tk_TSOffset *offsetPtr = (Tk_TSOffset *)(widgRec + offset);
  247.     Tk_TSOffset tsoffset;
  248.     CONST char *q, *p;
  249.     int result;
  250.     if ((value == NULL) || (*value == 0)) {
  251. tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE;
  252. goto goodTSOffset;
  253.     }
  254.     tsoffset.flags = 0;
  255.     p = value;
  256.     switch(value[0]) {
  257. case '#':
  258.     if (((int)clientData) & TK_OFFSET_RELATIVE) {
  259. tsoffset.flags = TK_OFFSET_RELATIVE;
  260. p++; break;
  261.     }
  262.     goto badTSOffset;
  263. case 'e':
  264.     switch(value[1]) {
  265. case '':
  266.     tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_MIDDLE;
  267.     goto goodTSOffset;
  268. case 'n':
  269.     if (value[2]!='d' || value[3]!='') {goto badTSOffset;}
  270.     tsoffset.flags = INT_MAX;
  271.     goto goodTSOffset;
  272.     }
  273. case 'w':
  274.     if (value[1] != '') {goto badTSOffset;}
  275.     tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_MIDDLE;
  276.     goto goodTSOffset;
  277. case 'n':
  278.     if ((value[1] != '') && (value[2] != '')) {
  279. goto badTSOffset;
  280.     }
  281.     switch(value[1]) {
  282. case '': tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_TOP;
  283.    goto goodTSOffset;
  284. case 'w': tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_TOP;
  285.    goto goodTSOffset;
  286. case 'e': tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_TOP;
  287.    goto goodTSOffset;
  288.     }
  289.     goto badTSOffset;
  290. case 's':
  291.     if ((value[1] != '') && (value[2] != '')) {
  292. goto badTSOffset;
  293.     }
  294.     switch(value[1]) {
  295. case '': tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_BOTTOM;
  296.    goto goodTSOffset;
  297. case 'w': tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_BOTTOM;
  298.    goto goodTSOffset;
  299. case 'e': tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_BOTTOM;
  300.    goto goodTSOffset;
  301.     }
  302.     goto badTSOffset;
  303. case 'c':
  304.     if (strncmp(value, "center", strlen(value)) != 0) {
  305. goto badTSOffset;
  306.     }
  307.     tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE;
  308.     goto goodTSOffset;
  309.     }
  310.     if ((q = strchr(p,',')) == NULL) {
  311. if (((int)clientData) & TK_OFFSET_INDEX) {
  312.     if (Tcl_GetInt(interp, (char *) p, &tsoffset.flags) != TCL_OK) {
  313. Tcl_ResetResult(interp);
  314. goto badTSOffset;
  315.     }
  316.     tsoffset.flags |= TK_OFFSET_INDEX;
  317.     goto goodTSOffset;
  318. }
  319. goto badTSOffset;
  320.     }
  321.     *((char *) q) = 0;
  322.     result = Tk_GetPixels(interp, tkwin, (char *) p, &tsoffset.xoffset);
  323.     *((char *) q) = ',';
  324.     if (result != TCL_OK) {
  325. return TCL_ERROR;
  326.     }
  327.     if (Tk_GetPixels(interp, tkwin, (char *) q+1, &tsoffset.yoffset) != TCL_OK) {
  328. return TCL_ERROR;
  329.     }
  330. goodTSOffset:
  331.     /* below is a hack to allow the stipple/tile offset to be stored
  332.      * in the internal tile structure. Most of the times, offsetPtr
  333.      * is a pointer to an already existing tile structure. However
  334.      * if this structure is not already created, we must do it
  335.      * with Tk_GetTile()!!!!;
  336.      */
  337.     memcpy(offsetPtr,&tsoffset, sizeof(Tk_TSOffset));
  338.     return TCL_OK;
  339. badTSOffset:
  340.     Tcl_AppendResult(interp, "bad offset "", value,
  341.     "": expected "x,y"", (char *) NULL);
  342.     if (((int) clientData) & TK_OFFSET_RELATIVE) {
  343. Tcl_AppendResult(interp, ", "#x,y"", (char *) NULL);
  344.     }
  345.     if (((int) clientData) & TK_OFFSET_INDEX) {
  346. Tcl_AppendResult(interp, ", <index>", (char *) NULL);
  347.     }
  348.     Tcl_AppendResult(interp, ", n, ne, e, se, s, sw, w, nw, or center",
  349.     (char *) NULL);
  350.     return TCL_ERROR;
  351. }
  352. /*
  353.  *----------------------------------------------------------------------
  354.  *
  355.  * TkOffsetPrintProc --
  356.  *
  357.  * Returns the offset of the tile.
  358.  *
  359.  * Results:
  360.  * The offset of the tile is returned.
  361.  *
  362.  *----------------------------------------------------------------------
  363.  */
  364. char *
  365. TkOffsetPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
  366.     ClientData clientData; /* not used */
  367.     Tk_Window tkwin; /* not used */
  368.     char *widgRec; /* Widget structure record */
  369.     int offset; /* Offset of tile in record */
  370.     Tcl_FreeProc **freeProcPtr; /* not used */
  371. {
  372.     Tk_TSOffset *offsetPtr = (Tk_TSOffset *)(widgRec + offset);
  373.     char *p, *q;
  374.     if ((offsetPtr->flags) & TK_OFFSET_INDEX) {
  375. if ((offsetPtr->flags) >= INT_MAX) {
  376.     return "end";
  377. }
  378. p = (char *) ckalloc(32);
  379. sprintf(p, "%d",(offsetPtr->flags & (~TK_OFFSET_INDEX)));
  380. *freeProcPtr = TCL_DYNAMIC;
  381. return p;
  382.     }
  383.     if ((offsetPtr->flags) & TK_OFFSET_TOP) {
  384. if ((offsetPtr->flags) & TK_OFFSET_LEFT) {
  385.     return "nw";
  386. } else if ((offsetPtr->flags) & TK_OFFSET_CENTER) {
  387.     return "n";
  388. } else if ((offsetPtr->flags) & TK_OFFSET_RIGHT) {
  389.     return "ne";
  390. }
  391.     } else if ((offsetPtr->flags) & TK_OFFSET_MIDDLE) {
  392. if ((offsetPtr->flags) & TK_OFFSET_LEFT) {
  393.     return "w";
  394. } else if ((offsetPtr->flags) & TK_OFFSET_CENTER) {
  395.     return "center";
  396. } else if ((offsetPtr->flags) & TK_OFFSET_RIGHT) {
  397.     return "e";
  398. }
  399.     } else if ((offsetPtr->flags) & TK_OFFSET_BOTTOM) {
  400. if ((offsetPtr->flags) & TK_OFFSET_LEFT) {
  401.     return "sw";
  402. } else if ((offsetPtr->flags) & TK_OFFSET_CENTER) {
  403.     return "s";
  404. } else if ((offsetPtr->flags) & TK_OFFSET_RIGHT) {
  405.     return "se";
  406. }
  407.     } 
  408.     q = p = (char *) ckalloc(32);
  409.     if ((offsetPtr->flags) & TK_OFFSET_RELATIVE) {
  410. *q++ = '#';
  411.     }
  412.     sprintf(q, "%d,%d",offsetPtr->xoffset, offsetPtr->yoffset);
  413.     *freeProcPtr = TCL_DYNAMIC;
  414.     return p;
  415. }
  416. /*
  417.  *----------------------------------------------------------------------
  418.  *
  419.  * TkPixelParseProc --
  420.  *
  421.  * Converts the name of an image into a tile.
  422.  *
  423.  *----------------------------------------------------------------------
  424.  */
  425. int
  426. TkPixelParseProc(clientData, interp, tkwin, value, widgRec, offset)
  427.     ClientData clientData; /* if non-NULL, negative values are
  428.  * allowed as well */
  429.     Tcl_Interp *interp; /* Interpreter to send results back to */
  430.     Tk_Window tkwin; /* Window on same display as tile */
  431.     CONST char *value; /* Name of image */
  432.     char *widgRec; /* Widget structure record */
  433.     int offset; /* Offset of tile in record */
  434. {
  435.     double *doublePtr = (double *)(widgRec + offset);
  436.     int result;
  437.     result = TkGetDoublePixels(interp, tkwin, value, doublePtr);
  438.     if ((result == TCL_OK) && (clientData == NULL) && (*doublePtr < 0.0)) {
  439. Tcl_AppendResult(interp, "bad screen distance "", value,
  440. """, (char *) NULL);
  441. return TCL_ERROR;
  442.     }
  443.     return result;
  444. }
  445. /*
  446.  *----------------------------------------------------------------------
  447.  *
  448.  * TkPixelPrintProc --
  449.  *
  450.  * Returns the name of the tile.
  451.  *
  452.  * Results:
  453.  * The name of the tile is returned.
  454.  *
  455.  *----------------------------------------------------------------------
  456.  */
  457. char *
  458. TkPixelPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
  459.     ClientData clientData; /* not used */
  460.     Tk_Window tkwin; /* not used */
  461.     char *widgRec; /* Widget structure record */
  462.     int offset; /* Offset of tile in record */
  463.     Tcl_FreeProc **freeProcPtr; /* not used */
  464. {
  465.     double *doublePtr = (double *)(widgRec + offset);
  466.     char *p;
  467.     p = (char *) ckalloc(24);
  468.     Tcl_PrintDouble((Tcl_Interp *) NULL, *doublePtr, p);
  469.     *freeProcPtr = TCL_DYNAMIC;
  470.     return p;
  471. }
  472. /*
  473.  *----------------------------------------------------------------------
  474.  *
  475.  * TkDrawInsetFocusHighlight --
  476.  *
  477.  * This procedure draws a rectangular ring around the outside of
  478.  * a widget to indicate that it has received the input focus.  It
  479.  * takes an additional padding argument that specifies how much
  480.  * padding is present outside th widget.
  481.  *
  482.  * Results:
  483.  * None.
  484.  *
  485.  * Side effects:
  486.  * A rectangle "width" pixels wide is drawn in "drawable",
  487.  * corresponding to the outer area of "tkwin".
  488.  *
  489.  *----------------------------------------------------------------------
  490.  */
  491. void
  492. TkDrawInsetFocusHighlight(tkwin, gc, width, drawable, padding)
  493.     Tk_Window tkwin; /* Window whose focus highlight ring is
  494.  * to be drawn. */
  495.     GC gc; /* Graphics context to use for drawing
  496.  * the highlight ring. */
  497.     int width; /* Width of the highlight ring, in pixels. */
  498.     Drawable drawable; /* Where to draw the ring (typically a
  499.  * pixmap for double buffering). */
  500.     int padding; /* Width of padding outside of widget. */
  501. {
  502.     XRectangle rects[4];
  503.     rects[0].x = padding;
  504.     rects[0].y = padding;
  505.     rects[0].width = Tk_Width(tkwin) - (2 * padding);
  506.     rects[0].height = width;
  507.     rects[1].x = padding;
  508.     rects[1].y = Tk_Height(tkwin) - width - padding;
  509.     rects[1].width = Tk_Width(tkwin) - (2 * padding);
  510.     rects[1].height = width;
  511.     rects[2].x = padding;
  512.     rects[2].y = width + padding;
  513.     rects[2].width = width;
  514.     rects[2].height = Tk_Height(tkwin) - 2*width - 2*padding;
  515.     rects[3].x = Tk_Width(tkwin) - width - padding;
  516.     rects[3].y = rects[2].y;
  517.     rects[3].width = width;
  518.     rects[3].height = rects[2].height;
  519.     XFillRectangles(Tk_Display(tkwin), drawable, gc, rects, 4);
  520. }
  521. /*
  522.  *----------------------------------------------------------------------
  523.  *
  524.  * Tk_DrawFocusHighlight --
  525.  *
  526.  * This procedure draws a rectangular ring around the outside of
  527.  * a widget to indicate that it has received the input focus.
  528.  *
  529.  *      This function is now deprecated.  Use TkpDrawHighlightBorder instead,
  530.  *      since this function does not handle drawing the Focus ring properly
  531.  *      on the Macintosh - you need to know the background GC as well 
  532.  *      as the foreground since the Mac focus ring separated from the widget
  533.  *      by a 1 pixel border.
  534.  *
  535.  * Results:
  536.  * None.
  537.  *
  538.  * Side effects:
  539.  * A rectangle "width" pixels wide is drawn in "drawable",
  540.  * corresponding to the outer area of "tkwin".
  541.  *
  542.  *----------------------------------------------------------------------
  543.  */
  544. void
  545. Tk_DrawFocusHighlight(tkwin, gc, width, drawable)
  546.     Tk_Window tkwin; /* Window whose focus highlight ring is
  547.  * to be drawn. */
  548.     GC gc; /* Graphics context to use for drawing
  549.  * the highlight ring. */
  550.     int width; /* Width of the highlight ring, in pixels. */
  551.     Drawable drawable; /* Where to draw the ring (typically a
  552.  * pixmap for double buffering). */
  553. {
  554.     TkDrawInsetFocusHighlight(tkwin, gc, width, drawable, 0);
  555. }
  556. /*
  557.  *----------------------------------------------------------------------
  558.  *
  559.  * Tk_GetScrollInfo --
  560.  *
  561.  * This procedure is invoked to parse "xview" and "yview"
  562.  * scrolling commands for widgets using the new scrolling
  563.  * command syntax ("moveto" or "scroll" options).
  564.  *
  565.  * Results:
  566.  * The return value is either TK_SCROLL_MOVETO, TK_SCROLL_PAGES,
  567.  * TK_SCROLL_UNITS, or TK_SCROLL_ERROR.  This indicates whether
  568.  * the command was successfully parsed and what form the command
  569.  * took.  If TK_SCROLL_MOVETO, *dblPtr is filled in with the
  570.  * desired position;  if TK_SCROLL_PAGES or TK_SCROLL_UNITS,
  571.  * *intPtr is filled in with the number of lines to move (may be
  572.  * negative);  if TK_SCROLL_ERROR, the interp's result contains an
  573.  * error message.
  574.  *
  575.  * Side effects:
  576.  * None.
  577.  *
  578.  *----------------------------------------------------------------------
  579.  */
  580. int
  581. Tk_GetScrollInfo(interp, argc, argv, dblPtr, intPtr)
  582.     Tcl_Interp *interp; /* Used for error reporting. */
  583.     int argc; /* # arguments for command. */
  584.     CONST char **argv; /* Arguments for command. */
  585.     double *dblPtr; /* Filled in with argument "moveto"
  586.  * option, if any. */
  587.     int *intPtr; /* Filled in with number of pages
  588.  * or lines to scroll, if any. */
  589. {
  590.     int c;
  591.     size_t length;
  592.     length = strlen(argv[2]);
  593.     c = argv[2][0];
  594.     if ((c == 'm') && (strncmp(argv[2], "moveto", length) == 0)) {
  595. if (argc != 4) {
  596.     Tcl_AppendResult(interp, "wrong # args: should be "",
  597.     argv[0], " ", argv[1], " moveto fraction"",
  598.     (char *) NULL);
  599.     return TK_SCROLL_ERROR;
  600. }
  601. if (Tcl_GetDouble(interp, argv[3], dblPtr) != TCL_OK) {
  602.     return TK_SCROLL_ERROR;
  603. }
  604. return TK_SCROLL_MOVETO;
  605.     } else if ((c == 's')
  606.     && (strncmp(argv[2], "scroll", length) == 0)) {
  607. if (argc != 5) {
  608.     Tcl_AppendResult(interp, "wrong # args: should be "",
  609.     argv[0], " ", argv[1], " scroll number units|pages"",
  610.     (char *) NULL);
  611.     return TK_SCROLL_ERROR;
  612. }
  613. if (Tcl_GetInt(interp, argv[3], intPtr) != TCL_OK) {
  614.     return TK_SCROLL_ERROR;
  615. }
  616. length = strlen(argv[4]);
  617. c = argv[4][0];
  618. if ((c == 'p') && (strncmp(argv[4], "pages", length) == 0)) {
  619.     return TK_SCROLL_PAGES;
  620. } else if ((c == 'u')
  621. && (strncmp(argv[4], "units", length) == 0)) {
  622.     return TK_SCROLL_UNITS;
  623. } else {
  624.     Tcl_AppendResult(interp, "bad argument "", argv[4],
  625.     "": must be units or pages", (char *) NULL);
  626.     return TK_SCROLL_ERROR;
  627. }
  628.     }
  629.     Tcl_AppendResult(interp, "unknown option "", argv[2],
  630.     "": must be moveto or scroll", (char *) NULL);
  631.     return TK_SCROLL_ERROR;
  632. }
  633. /*
  634.  *----------------------------------------------------------------------
  635.  *
  636.  * Tk_GetScrollInfoObj --
  637.  *
  638.  * This procedure is invoked to parse "xview" and "yview"
  639.  * scrolling commands for widgets using the new scrolling
  640.  * command syntax ("moveto" or "scroll" options).
  641.  *
  642.  * Results:
  643.  * The return value is either TK_SCROLL_MOVETO, TK_SCROLL_PAGES,
  644.  * TK_SCROLL_UNITS, or TK_SCROLL_ERROR.  This indicates whether
  645.  * the command was successfully parsed and what form the command
  646.  * took.  If TK_SCROLL_MOVETO, *dblPtr is filled in with the
  647.  * desired position;  if TK_SCROLL_PAGES or TK_SCROLL_UNITS,
  648.  * *intPtr is filled in with the number of lines to move (may be
  649.  * negative);  if TK_SCROLL_ERROR, the interp's result contains an
  650.  * error message.
  651.  *
  652.  * Side effects:
  653.  * None.
  654.  *
  655.  *----------------------------------------------------------------------
  656.  */
  657. int
  658. Tk_GetScrollInfoObj(interp, objc, objv, dblPtr, intPtr)
  659.     Tcl_Interp *interp; /* Used for error reporting. */
  660.     int objc; /* # arguments for command. */
  661.     Tcl_Obj *CONST objv[]; /* Arguments for command. */
  662.     double *dblPtr; /* Filled in with argument "moveto"
  663.  * option, if any. */
  664.     int *intPtr; /* Filled in with number of pages
  665.  * or lines to scroll, if any. */
  666. {
  667.     int c;
  668.     size_t length;
  669.     char *arg2, *arg4;
  670.     arg2 = Tcl_GetString(objv[2]);
  671.     length = strlen(arg2);
  672.     c = arg2[0];
  673.     if ((c == 'm') && (strncmp(arg2, "moveto", length) == 0)) {
  674. if (objc != 4) {
  675.     Tcl_WrongNumArgs(interp, 2, objv, "moveto fraction");
  676.     return TK_SCROLL_ERROR;
  677. }
  678. if (Tcl_GetDoubleFromObj(interp, objv[3], dblPtr) != TCL_OK) {
  679.     return TK_SCROLL_ERROR;
  680. }
  681. return TK_SCROLL_MOVETO;
  682.     } else if ((c == 's')
  683.     && (strncmp(arg2, "scroll", length) == 0)) {
  684. if (objc != 5) {
  685.     Tcl_WrongNumArgs(interp, 2, objv, "scroll number units|pages");
  686.     return TK_SCROLL_ERROR;
  687. }
  688. if (Tcl_GetIntFromObj(interp, objv[3], intPtr) != TCL_OK) {
  689.     return TK_SCROLL_ERROR;
  690. }
  691. arg4 = Tcl_GetString(objv[4]);
  692. length = (strlen(arg4));
  693. c = arg4[0];
  694. if ((c == 'p') && (strncmp(arg4, "pages", length) == 0)) {
  695.     return TK_SCROLL_PAGES;
  696. } else if ((c == 'u')
  697. && (strncmp(arg4, "units", length) == 0)) {
  698.     return TK_SCROLL_UNITS;
  699. } else {
  700.     Tcl_AppendResult(interp, "bad argument "", arg4,
  701.     "": must be units or pages", (char *) NULL);
  702.     return TK_SCROLL_ERROR;
  703. }
  704.     }
  705.     Tcl_AppendResult(interp, "unknown option "", arg2,
  706.     "": must be moveto or scroll", (char *) NULL);
  707.     return TK_SCROLL_ERROR;
  708. }
  709. /*
  710.  *---------------------------------------------------------------------------
  711.  *
  712.  * TkComputeAnchor --
  713.  *
  714.  * Determine where to place a rectangle so that it will be properly
  715.  * anchored with respect to the given window.  Used by widgets
  716.  * to align a box of text inside a window.  When anchoring with
  717.  * respect to one of the sides, the rectangle be placed inside of
  718.  * the internal border of the window.
  719.  *
  720.  * Results:
  721.  * *xPtr and *yPtr set to the upper-left corner of the rectangle
  722.  * anchored in the window.
  723.  *
  724.  * Side effects:
  725.  * None.
  726.  *
  727.  *---------------------------------------------------------------------------
  728.  */
  729. void
  730. TkComputeAnchor(anchor, tkwin, padX, padY, innerWidth, innerHeight, xPtr, yPtr)
  731.     Tk_Anchor anchor; /* Desired anchor. */
  732.     Tk_Window tkwin; /* Anchored with respect to this window. */
  733.     int padX, padY; /* Use this extra padding inside window, in
  734.  * addition to the internal border. */
  735.     int innerWidth, innerHeight;/* Size of rectangle to anchor in window. */
  736.     int *xPtr, *yPtr; /* Returns upper-left corner of anchored
  737.  * rectangle. */
  738. {
  739.     switch (anchor) {
  740. case TK_ANCHOR_NW:
  741. case TK_ANCHOR_W:
  742. case TK_ANCHOR_SW:
  743.     *xPtr = Tk_InternalBorderLeft(tkwin) + padX;
  744.     break;
  745. case TK_ANCHOR_N:
  746. case TK_ANCHOR_CENTER:
  747. case TK_ANCHOR_S:
  748.     *xPtr = (Tk_Width(tkwin) - innerWidth) / 2;
  749.     break;
  750. default:
  751.     *xPtr = Tk_Width(tkwin) - (Tk_InternalBorderRight(tkwin) + padX)
  752.     - innerWidth;
  753.     break;
  754.     }
  755.     switch (anchor) {
  756. case TK_ANCHOR_NW:
  757. case TK_ANCHOR_N:
  758. case TK_ANCHOR_NE:
  759.     *yPtr = Tk_InternalBorderTop(tkwin) + padY;
  760.     break;
  761. case TK_ANCHOR_W:
  762. case TK_ANCHOR_CENTER:
  763. case TK_ANCHOR_E:
  764.     *yPtr = (Tk_Height(tkwin) - innerHeight) / 2;
  765.     break;
  766. default:
  767.     *yPtr = Tk_Height(tkwin) - Tk_InternalBorderBottom(tkwin) - padY
  768.     - innerHeight;
  769.     break;
  770.     }
  771. }
  772. /*
  773.  *---------------------------------------------------------------------------
  774.  *
  775.  * TkFindStateString --
  776.  *
  777.  * Given a lookup table, map a number to a string in the table.
  778.  *
  779.  * Results:
  780.  * If numKey was equal to the numeric key of one of the elements
  781.  * in the table, returns the string key of that element.
  782.  * Returns NULL if numKey was not equal to any of the numeric keys
  783.  * in the table.
  784.  *
  785.  * Side effects.
  786.  * None.
  787.  *
  788.  *---------------------------------------------------------------------------
  789.  */
  790. char *
  791. TkFindStateString(mapPtr, numKey)
  792.     CONST TkStateMap *mapPtr; /* The state table. */
  793.     int numKey; /* The key to try to find in the table. */
  794. {
  795.     for ( ; mapPtr->strKey != NULL; mapPtr++) {
  796. if (numKey == mapPtr->numKey) {
  797.     return mapPtr->strKey;
  798. }
  799.     }
  800.     return NULL;
  801. }
  802. /*
  803.  *---------------------------------------------------------------------------
  804.  *
  805.  * TkFindStateNum --
  806.  *
  807.  * Given a lookup table, map a string to a number in the table.
  808.  *
  809.  * Results:
  810.  * If strKey was equal to the string keys of one of the elements
  811.  * in the table, returns the numeric key of that element.
  812.  * Returns the numKey associated with the last element (the NULL
  813.  * string one) in the table if strKey was not equal to any of the
  814.  * string keys in the table.  In that case, an error message is
  815.  * also left in the interp's result (if interp is not NULL).
  816.  *
  817.  * Side effects.
  818.  * None.
  819.  *
  820.  *---------------------------------------------------------------------------
  821.  */
  822. int
  823. TkFindStateNum(interp, option, mapPtr, strKey)
  824.     Tcl_Interp *interp; /* Interp for error reporting. */
  825.     CONST char *option; /* String to use when constructing error. */
  826.     CONST TkStateMap *mapPtr; /* Lookup table. */
  827.     CONST char *strKey; /* String to try to find in lookup table. */
  828. {
  829.     CONST TkStateMap *mPtr;
  830.     for (mPtr = mapPtr; mPtr->strKey != NULL; mPtr++) {
  831. if (strcmp(strKey, mPtr->strKey) == 0) {
  832.     return mPtr->numKey;
  833. }
  834.     }
  835.     if (interp != NULL) {
  836. mPtr = mapPtr;
  837. Tcl_AppendResult(interp, "bad ", option, " value "", strKey,
  838. "": must be ", mPtr->strKey, (char *) NULL);
  839. for (mPtr++; mPtr->strKey != NULL; mPtr++) {
  840.     Tcl_AppendResult(interp, 
  841.     ((mPtr[1].strKey != NULL) ? ", " : ", or "), 
  842.     mPtr->strKey, (char *) NULL);
  843. }
  844.     }
  845.     return mPtr->numKey;
  846. }
  847. int
  848. TkFindStateNumObj(interp, optionPtr, mapPtr, keyPtr)
  849.     Tcl_Interp *interp; /* Interp for error reporting. */
  850.     Tcl_Obj *optionPtr; /* String to use when constructing error. */
  851.     CONST TkStateMap *mapPtr; /* Lookup table. */
  852.     Tcl_Obj *keyPtr; /* String key to find in lookup table. */
  853. {
  854.     CONST TkStateMap *mPtr;
  855.     CONST char *key;
  856.     CONST Tcl_ObjType *typePtr;
  857.     if ((keyPtr->typePtr == &tkStateKeyObjType)
  858.     && (keyPtr->internalRep.twoPtrValue.ptr1 == (VOID *) mapPtr)) {
  859. return (int) keyPtr->internalRep.twoPtrValue.ptr2;
  860.     }
  861.     key = Tcl_GetStringFromObj(keyPtr, NULL);
  862.     for (mPtr = mapPtr; mPtr->strKey != NULL; mPtr++) {
  863. if (strcmp(key, mPtr->strKey) == 0) {
  864.     typePtr = keyPtr->typePtr;
  865.     if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
  866. (*typePtr->freeIntRepProc)(keyPtr);
  867.     }
  868.     keyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) mapPtr;
  869.     keyPtr->internalRep.twoPtrValue.ptr2 = (VOID *) mPtr->numKey;
  870.     keyPtr->typePtr = &tkStateKeyObjType;     
  871.     return mPtr->numKey;
  872. }
  873.     }
  874.     if (interp != NULL) {
  875. mPtr = mapPtr;
  876. Tcl_AppendResult(interp, "bad ",
  877. Tcl_GetStringFromObj(optionPtr, NULL), " value "", key,
  878. "": must be ", mPtr->strKey, (char *) NULL);
  879. for (mPtr++; mPtr->strKey != NULL; mPtr++) {
  880.     Tcl_AppendResult(interp, 
  881. ((mPtr[1].strKey != NULL) ? ", " : ", or "), 
  882. mPtr->strKey, (char *) NULL);
  883. }
  884.     }
  885.     return mPtr->numKey;
  886. }
  887. /*
  888.  * For each exit handler created with a call to TkCreateExitHandler
  889.  * there is a structure of the following type:
  890.  */
  891. typedef struct ExitHandler {
  892.     Tcl_ExitProc *proc; /* Procedure to call when process exits. */
  893.     ClientData clientData; /* One word of information to pass to proc. */
  894.     struct ExitHandler *nextPtr;/* Next in list of all exit handlers for
  895.  * this application, or NULL for end of list. */
  896. } ExitHandler;
  897. /*
  898.  * There is both per-process and per-thread exit handlers.
  899.  * The first list is controlled by a mutex.  The other is in
  900.  * thread local storage.
  901.  */
  902. static ExitHandler *firstExitPtr = NULL;
  903. /* First in list of all exit handlers for
  904.  * application. */
  905. TCL_DECLARE_MUTEX(exitMutex)
  906. /*
  907.  *---------------------------------------------------------------------------
  908.  *
  909.  * TkCreateExitHandler --
  910.  *
  911.  * Same as Tcl_CreateExitHandler, but private to Tk.
  912.  *
  913.  * Results:
  914.  * None.
  915.  *
  916.  * Side effects.
  917.  * Sets a handler with Tcl_CreateExitHandler if this is the first call.
  918.  *
  919.  *---------------------------------------------------------------------------
  920.  */
  921. void
  922. TkCreateExitHandler (proc, clientData)
  923.     Tcl_ExitProc *proc; /* Procedure to invoke. */
  924.     ClientData clientData; /* Arbitrary value to pass to proc. */
  925. {
  926.     ExitHandler *exitPtr;
  927.     exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler));
  928.     exitPtr->proc = proc;
  929.     exitPtr->clientData = clientData;
  930.     Tcl_MutexLock(&exitMutex);
  931.     if (firstExitPtr == NULL) {
  932. Tcl_CreateExitHandler(TkFinalize, NULL);
  933.     }
  934.     exitPtr->nextPtr = firstExitPtr;
  935.     firstExitPtr = exitPtr;
  936.     Tcl_MutexUnlock(&exitMutex);
  937. }
  938. /*
  939.  *---------------------------------------------------------------------------
  940.  *
  941.  * TkDeleteExitHandler --
  942.  *
  943.  * Same as Tcl_DeleteExitHandler, but private to Tk.
  944.  *
  945.  * Results:
  946.  * None.
  947.  *
  948.  * Side effects.
  949.  * None.
  950.  *
  951.  *---------------------------------------------------------------------------
  952.  */
  953. void
  954. TkDeleteExitHandler (proc, clientData)
  955.     Tcl_ExitProc *proc; /* Procedure that was previously registered. */
  956.     ClientData clientData; /* Arbitrary value to pass to proc. */
  957. {
  958.     ExitHandler *exitPtr, *prevPtr;
  959.     Tcl_MutexLock(&exitMutex);
  960.     for (prevPtr = NULL, exitPtr = firstExitPtr; exitPtr != NULL;
  961.     prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
  962. if ((exitPtr->proc == proc)
  963. && (exitPtr->clientData == clientData)) {
  964.     if (prevPtr == NULL) {
  965. firstExitPtr = exitPtr->nextPtr;
  966.     } else {
  967. prevPtr->nextPtr = exitPtr->nextPtr;
  968.     }
  969.     ckfree((char *) exitPtr);
  970.     break;
  971. }
  972.     }
  973.     Tcl_MutexUnlock(&exitMutex);
  974.     return;
  975. }
  976. /*
  977.  *---------------------------------------------------------------------------
  978.  *
  979.  * TkFinalize --
  980.  *
  981.  * Runs our private exit handlers and removes itself from Tcl. This is
  982.  * benificial should we want to protect from dangling pointers should
  983.  * the Tk shared library be unloaded prior to Tcl which can happen on
  984.  * windows should the process be forcefully exiting from an exception
  985.  * handler.
  986.  *
  987.  * Results:
  988.  * None.
  989.  *
  990.  * Side effects.
  991.  * None.
  992.  *
  993.  *---------------------------------------------------------------------------
  994.  */
  995. void
  996. TkFinalize (clientData)
  997.     ClientData clientData; /* Arbitrary value to pass to proc. */
  998. {
  999.     ExitHandler *exitPtr;
  1000.     Tcl_DeleteExitHandler(TkFinalize, NULL);
  1001.     Tcl_MutexLock(&exitMutex);
  1002.     for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) {
  1003. /*
  1004.  * Be careful to remove the handler from the list before
  1005.  * invoking its callback.  This protects us against
  1006.  * double-freeing if the callback should call
  1007.  * Tcl_DeleteExitHandler on itself.
  1008.  */
  1009. firstExitPtr = exitPtr->nextPtr;
  1010. Tcl_MutexUnlock(&exitMutex);
  1011. (*exitPtr->proc)(exitPtr->clientData);
  1012. ckfree((char *) exitPtr);
  1013. Tcl_MutexLock(&exitMutex);
  1014.     }    
  1015.     firstExitPtr = NULL;
  1016.     Tcl_MutexUnlock(&exitMutex);
  1017. }