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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tk3d.c --
  3.  *
  4.  * This module provides procedures to draw borders in
  5.  * the three-dimensional Motif style.
  6.  *
  7.  * Copyright (c) 1990-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * RCS: @(#) $Id: tk3d.c,v 1.13 2002/08/05 04:30:38 dgp Exp $
  14.  */
  15. #include "tk3d.h"
  16. /*
  17.  * The following table defines the string values for reliefs, which are
  18.  * used by Tk_GetReliefFromObj.
  19.  */
  20. static CONST char *reliefStrings[] = {"flat", "groove", "raised",
  21.     "ridge", "solid", "sunken", 
  22.     (char *) NULL};
  23. /*
  24.  * Forward declarations for procedures defined in this file:
  25.  */
  26. static void BorderInit _ANSI_ARGS_((TkDisplay *dispPtr));
  27. static void DupBorderObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,
  28.     Tcl_Obj *dupObjPtr));
  29. static void FreeBorderObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));
  30. static int Intersect _ANSI_ARGS_((XPoint *a1Ptr, XPoint *a2Ptr,
  31.     XPoint *b1Ptr, XPoint *b2Ptr, XPoint *iPtr));
  32. static void InitBorderObj _ANSI_ARGS_((Tcl_Obj *objPtr));
  33. static void ShiftLine _ANSI_ARGS_((XPoint *p1Ptr, XPoint *p2Ptr,
  34.     int distance, XPoint *p3Ptr));
  35. /*
  36.  * The following structure defines the implementation of the "border" Tcl
  37.  * object, used for drawing. The border object remembers the hash table entry
  38.  * associated with a border. The actual allocation and deallocation of the
  39.  * border should be done by the configuration package when the border option
  40.  * is set.
  41.  */
  42. Tcl_ObjType tkBorderObjType = {
  43.     "border", /* name */
  44.     FreeBorderObjProc, /* freeIntRepProc */
  45.     DupBorderObjProc, /* dupIntRepProc */
  46.     NULL, /* updateStringProc */
  47.     NULL /* setFromAnyProc */
  48. };
  49. /*
  50.  *----------------------------------------------------------------------
  51.  *
  52.  * Tk_Alloc3DBorderFromObj --
  53.  *
  54.  * Given a Tcl_Obj *, map the value to a corresponding
  55.  * Tk_3DBorder structure based on the tkwin given.
  56.  *
  57.  * Results:
  58.  * The return value is a token for a data structure describing a
  59.  * 3-D border.  This token may be passed to procedures such as
  60.  * Tk_Draw3DRectangle and Tk_Free3DBorder.  If an error prevented
  61.  * the border from being created then NULL is returned and an error
  62.  * message will be left in the interp's result.
  63.  *
  64.  * Side effects:
  65.  * The border is added to an internal database with a reference
  66.  * count. For each call to this procedure, there should eventually
  67.  * be a call to FreeBorderObjProc so that the database is
  68.  * cleaned up when borders aren't in use anymore.
  69.  *
  70.  *----------------------------------------------------------------------
  71.  */
  72. Tk_3DBorder
  73. Tk_Alloc3DBorderFromObj(interp, tkwin, objPtr)
  74.     Tcl_Interp *interp; /* Interp for error results. */
  75.     Tk_Window tkwin; /* Need the screen the border is used on.*/
  76.     Tcl_Obj *objPtr; /* Object giving name of color for window
  77.  * background. */
  78. {
  79.     TkBorder *borderPtr;
  80.     if (objPtr->typePtr != &tkBorderObjType) {
  81. InitBorderObj(objPtr);
  82.     }
  83.     borderPtr = (TkBorder *) objPtr->internalRep.twoPtrValue.ptr1;
  84.     /*
  85.      * If the object currently points to a TkBorder, see if it's the
  86.      * one we want.  If so, increment its reference count and return.
  87.      */
  88.     if (borderPtr != NULL) {
  89. if (borderPtr->resourceRefCount == 0) {
  90.     /*
  91.      * This is a stale reference: it refers to a border that's
  92.      * no longer in use.  Clear the reference.
  93.      */
  94.     FreeBorderObjProc(objPtr);
  95.     borderPtr = NULL;
  96. } else if ((Tk_Screen(tkwin) == borderPtr->screen)
  97. && (Tk_Colormap(tkwin) == borderPtr->colormap)) {
  98.     borderPtr->resourceRefCount++;
  99.     return (Tk_3DBorder) borderPtr;
  100. }
  101.     }
  102.     /*
  103.      * The object didn't point to the border that we wanted.  Search
  104.      * the list of borders with the same name to see if one of the
  105.      * others is the right one.
  106.      */
  107.     /*
  108.      * If the cached value is NULL, either the object type was not a
  109.      * color going in, or the object is a color type but had
  110.      * previously been freed.
  111.      *
  112.      * If the value is not NULL, the internal rep is the value
  113.      * of the color the last time this object was accessed. Check
  114.      * the screen and colormap of the last access, and if they
  115.      * match, we are done.
  116.      */
  117.     if (borderPtr != NULL) {
  118. TkBorder *firstBorderPtr = 
  119. (TkBorder *) Tcl_GetHashValue(borderPtr->hashPtr);
  120. FreeBorderObjProc(objPtr);
  121. for (borderPtr = firstBorderPtr ; borderPtr != NULL;
  122. borderPtr = borderPtr->nextPtr) {
  123.     if ((Tk_Screen(tkwin) == borderPtr->screen)
  124. && (Tk_Colormap(tkwin) == borderPtr->colormap)) {
  125. borderPtr->resourceRefCount++;
  126. borderPtr->objRefCount++;
  127. objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) borderPtr;
  128. return (Tk_3DBorder) borderPtr;
  129.     }
  130. }
  131.     }
  132.     /*
  133.      * Still no luck.  Call Tk_Get3DBorder to allocate a new border.
  134.      */
  135.     borderPtr = (TkBorder *) Tk_Get3DBorder(interp, tkwin,
  136.     Tcl_GetString(objPtr));
  137.     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) borderPtr;
  138.     if (borderPtr != NULL) {
  139. borderPtr->objRefCount++;
  140.     }
  141.     return (Tk_3DBorder) borderPtr;
  142. }
  143. /*
  144.  *--------------------------------------------------------------
  145.  *
  146.  * Tk_Get3DBorder --
  147.  *
  148.  * Create a data structure for displaying a 3-D border.
  149.  *
  150.  * Results:
  151.  * The return value is a token for a data structure describing a
  152.  * 3-D border.  This token may be passed to procedures such as
  153.  * Tk_Draw3DRectangle and Tk_Free3DBorder.  If an error prevented
  154.  * the border from being created then NULL is returned and an error
  155.  * message will be left in the interp's result.
  156.  *
  157.  * Side effects:
  158.  * Data structures, graphics contexts, etc. are allocated.
  159.  * It is the caller's responsibility to eventually call
  160.  * Tk_Free3DBorder to release the resources.
  161.  *
  162.  *--------------------------------------------------------------
  163.  */
  164. Tk_3DBorder
  165. Tk_Get3DBorder(interp, tkwin, colorName)
  166.     Tcl_Interp *interp; /* Place to store an error message. */
  167.     Tk_Window tkwin; /* Token for window in which border will
  168.  * be drawn. */
  169.     Tk_Uid colorName; /* String giving name of color
  170.  * for window background. */
  171. {
  172.     Tcl_HashEntry *hashPtr;
  173.     TkBorder *borderPtr, *existingBorderPtr;
  174.     int new;
  175.     XGCValues gcValues;
  176.     XColor *bgColorPtr;
  177.     TkDisplay *dispPtr;
  178.     dispPtr = ((TkWindow *) tkwin)->dispPtr;
  179.     if (!dispPtr->borderInit) {
  180. BorderInit(dispPtr);
  181.     }
  182.     hashPtr = Tcl_CreateHashEntry(&dispPtr->borderTable, colorName, &new);
  183.     if (!new) {
  184. existingBorderPtr = (TkBorder *) Tcl_GetHashValue(hashPtr);
  185. for (borderPtr = existingBorderPtr; borderPtr != NULL;
  186. borderPtr = borderPtr->nextPtr) {
  187.     if ((Tk_Screen(tkwin) == borderPtr->screen)
  188.     && (Tk_Colormap(tkwin) == borderPtr->colormap)) {
  189. borderPtr->resourceRefCount++;
  190. return (Tk_3DBorder) borderPtr;
  191.     }
  192. }
  193.     } else {
  194. existingBorderPtr = NULL;
  195.     }
  196.     /*
  197.      * No satisfactory border exists yet.  Initialize a new one.
  198.      */
  199.     bgColorPtr = Tk_GetColor(interp, tkwin, colorName);
  200.     if (bgColorPtr == NULL) {
  201. if (new) {
  202.     Tcl_DeleteHashEntry(hashPtr);
  203. }
  204. return NULL;
  205.     }
  206.     borderPtr = TkpGetBorder();
  207.     borderPtr->screen = Tk_Screen(tkwin);
  208.     borderPtr->visual = Tk_Visual(tkwin);
  209.     borderPtr->depth = Tk_Depth(tkwin);
  210.     borderPtr->colormap = Tk_Colormap(tkwin);
  211.     borderPtr->resourceRefCount = 1;
  212.     borderPtr->objRefCount = 0;
  213.     borderPtr->bgColorPtr = bgColorPtr;
  214.     borderPtr->darkColorPtr = NULL;
  215.     borderPtr->lightColorPtr = NULL;
  216.     borderPtr->shadow = None;
  217.     borderPtr->bgGC = None;
  218.     borderPtr->darkGC = None;
  219.     borderPtr->lightGC = None;
  220.     borderPtr->hashPtr = hashPtr;
  221.     borderPtr->nextPtr = existingBorderPtr;
  222.     Tcl_SetHashValue(hashPtr, borderPtr);
  223.     /*
  224.      * Create the information for displaying the background color,
  225.      * but delay the allocation of shadows until they are actually
  226.      * needed for drawing.
  227.      */
  228.     gcValues.foreground = borderPtr->bgColorPtr->pixel;
  229.     borderPtr->bgGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  230.     return (Tk_3DBorder) borderPtr;
  231. }
  232. /*
  233.  *--------------------------------------------------------------
  234.  *
  235.  * Tk_Draw3DRectangle --
  236.  *
  237.  * Draw a 3-D border at a given place in a given window.
  238.  *
  239.  * Results:
  240.  * None.
  241.  *
  242.  * Side effects:
  243.  * A 3-D border will be drawn in the indicated drawable.
  244.  * The outside edges of the border will be determined by x,
  245.  * y, width, and height.  The inside edges of the border
  246.  * will be determined by the borderWidth argument.
  247.  *
  248.  *--------------------------------------------------------------
  249.  */
  250. void
  251. Tk_Draw3DRectangle(tkwin, drawable, border, x, y, width, height,
  252. borderWidth, relief)
  253.     Tk_Window tkwin; /* Window for which border was allocated. */
  254.     Drawable drawable; /* X window or pixmap in which to draw. */
  255.     Tk_3DBorder border; /* Token for border to draw. */
  256.     int x, y, width, height; /* Outside area of region in
  257.  * which border will be drawn. */
  258.     int borderWidth; /* Desired width for border, in
  259.  * pixels. */
  260.     int relief; /* Type of relief: TK_RELIEF_RAISED,
  261.  * TK_RELIEF_SUNKEN, TK_RELIEF_GROOVE, etc. */
  262. {
  263.     if (width < 2*borderWidth) {
  264. borderWidth = width/2;
  265.     }
  266.     if (height < 2*borderWidth) {
  267. borderWidth = height/2;
  268.     }
  269.     Tk_3DVerticalBevel(tkwin, drawable, border, x, y, borderWidth, height,
  270.     1, relief);
  271.     Tk_3DVerticalBevel(tkwin, drawable, border, x+width-borderWidth, y,
  272.     borderWidth, height, 0, relief);
  273.     Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, borderWidth,
  274.     1, 1, 1, relief);
  275.     Tk_3DHorizontalBevel(tkwin, drawable, border, x, y+height-borderWidth,
  276.     width, borderWidth, 0, 0, 0, relief);
  277. }
  278. /*
  279.  *--------------------------------------------------------------
  280.  *
  281.  * Tk_NameOf3DBorder --
  282.  *
  283.  * Given a border, return a textual string identifying the
  284.  * border's color.
  285.  *
  286.  * Results:
  287.  * The return value is the string that was used to create
  288.  * the border.
  289.  *
  290.  * Side effects:
  291.  * None.
  292.  *
  293.  *--------------------------------------------------------------
  294.  */
  295. CONST char *
  296. Tk_NameOf3DBorder(border)
  297.     Tk_3DBorder border; /* Token for border. */
  298. {
  299.     TkBorder *borderPtr = (TkBorder *) border;
  300.     return borderPtr->hashPtr->key.string;
  301. }
  302. /*
  303.  *--------------------------------------------------------------------
  304.  *
  305.  * Tk_3DBorderColor --
  306.  *
  307.  * Given a 3D border, return the X color used for the "flat"
  308.  * surfaces.
  309.  *
  310.  * Results:
  311.  * Returns the color used drawing flat surfaces with the border.
  312.  *
  313.  * Side effects:
  314.  * None.
  315.  *
  316.  *--------------------------------------------------------------------
  317.  */
  318. XColor *
  319. Tk_3DBorderColor(border)
  320.     Tk_3DBorder border; /* Border whose color is wanted. */
  321. {
  322.     return(((TkBorder *) border)->bgColorPtr);
  323. }
  324. /*
  325.  *--------------------------------------------------------------------
  326.  *
  327.  * Tk_3DBorderGC --
  328.  *
  329.  * Given a 3D border, returns one of the graphics contexts used to
  330.  * draw the border.
  331.  *
  332.  * Results:
  333.  * Returns the graphics context given by the "which" argument.
  334.  *
  335.  * Side effects:
  336.  * None.
  337.  *
  338.  *--------------------------------------------------------------------
  339.  */
  340. GC
  341. Tk_3DBorderGC(tkwin, border, which)
  342.     Tk_Window tkwin; /* Window for which border was allocated. */
  343.     Tk_3DBorder border; /* Border whose GC is wanted. */
  344.     int which; /* Selects one of the border's 3 GC's:
  345.  * TK_3D_FLAT_GC, TK_3D_LIGHT_GC, or
  346.  * TK_3D_DARK_GC. */
  347. {
  348.     TkBorder * borderPtr = (TkBorder *) border;
  349.     if ((borderPtr->lightGC == None) && (which != TK_3D_FLAT_GC)) {
  350. TkpGetShadows(borderPtr, tkwin);
  351.     }
  352.     if (which == TK_3D_FLAT_GC) {
  353. return borderPtr->bgGC;
  354.     } else if (which == TK_3D_LIGHT_GC) {
  355. return borderPtr->lightGC;
  356.     } else if (which == TK_3D_DARK_GC){
  357. return borderPtr->darkGC;
  358.     }
  359.     panic("bogus "which" value in Tk_3DBorderGC");
  360.     /*
  361.      * The code below will never be executed, but it's needed to
  362.      * keep compilers happy.
  363.      */
  364.     return (GC) None;
  365. }
  366. /*
  367.  *--------------------------------------------------------------
  368.  *
  369.  * Tk_Free3DBorder --
  370.  *
  371.  * This procedure is called when a 3D border is no longer
  372.  * needed.  It frees the resources associated with the
  373.  * border.  After this call, the caller should never again
  374.  * use the "border" token.
  375.  *
  376.  * Results:
  377.  * None.
  378.  *
  379.  * Side effects:
  380.  * Resources are freed.
  381.  *
  382.  *--------------------------------------------------------------
  383.  */
  384. void
  385. Tk_Free3DBorder(border)
  386.     Tk_3DBorder border; /* Token for border to be released. */
  387. {
  388.     TkBorder *borderPtr = (TkBorder *) border;
  389.     Display *display = DisplayOfScreen(borderPtr->screen);
  390.     TkBorder *prevPtr;
  391.     borderPtr->resourceRefCount--;
  392.     if (borderPtr->resourceRefCount > 0) {
  393. return;
  394.     }
  395.     prevPtr = (TkBorder *) Tcl_GetHashValue(borderPtr->hashPtr);
  396.     TkpFreeBorder(borderPtr);
  397.     if (borderPtr->bgColorPtr != NULL) {
  398. Tk_FreeColor(borderPtr->bgColorPtr);
  399.     }
  400.     if (borderPtr->darkColorPtr != NULL) {
  401. Tk_FreeColor(borderPtr->darkColorPtr);
  402.     }
  403.     if (borderPtr->lightColorPtr != NULL) {
  404. Tk_FreeColor(borderPtr->lightColorPtr);
  405.     }
  406.     if (borderPtr->shadow != None) {
  407. Tk_FreeBitmap(display, borderPtr->shadow);
  408.     }
  409.     if (borderPtr->bgGC != None) {
  410. Tk_FreeGC(display, borderPtr->bgGC);
  411.     }
  412.     if (borderPtr->darkGC != None) {
  413. Tk_FreeGC(display, borderPtr->darkGC);
  414.     }
  415.     if (borderPtr->lightGC != None) {
  416. Tk_FreeGC(display, borderPtr->lightGC);
  417.     }
  418.     if (prevPtr == borderPtr) {
  419. if (borderPtr->nextPtr == NULL) {
  420.     Tcl_DeleteHashEntry(borderPtr->hashPtr);
  421. } else {
  422.     Tcl_SetHashValue(borderPtr->hashPtr, borderPtr->nextPtr);
  423. }
  424.     } else {
  425. while (prevPtr->nextPtr != borderPtr) {
  426.     prevPtr = prevPtr->nextPtr;
  427. }
  428. prevPtr->nextPtr = borderPtr->nextPtr;
  429.     }
  430.     if (borderPtr->objRefCount == 0) {
  431. ckfree((char *) borderPtr);
  432.     }
  433. }
  434. /*
  435.  *----------------------------------------------------------------------
  436.  *
  437.  * Tk_Free3DBorderFromObj --
  438.  *
  439.  * This procedure is called to release a border allocated by
  440.  * Tk_Alloc3DBorderFromObj. It does not throw away the Tcl_Obj *;
  441.  * it only gets rid of the hash table entry for this border
  442.  * and clears the cached value that is normally stored in the object.
  443.  *
  444.  * Results:
  445.  * None.
  446.  *
  447.  * Side effects:
  448.  * The reference count associated with the border represented by
  449.  * objPtr is decremented, and the border's resources are released 
  450.  * to X if there are no remaining uses for it.
  451.  *
  452.  *----------------------------------------------------------------------
  453.  */
  454. void
  455. Tk_Free3DBorderFromObj(tkwin, objPtr)
  456.     Tk_Window tkwin; /* The window this border lives in. Needed
  457.  * for the screen and colormap values. */
  458.     Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */
  459. {
  460.     Tk_Free3DBorder(Tk_Get3DBorderFromObj(tkwin, objPtr));
  461.     FreeBorderObjProc(objPtr);
  462. }
  463. /*
  464.  *---------------------------------------------------------------------------
  465.  *
  466.  * FreeBorderObjProc -- 
  467.  *
  468.  * This proc is called to release an object reference to a border.
  469.  * Called when the object's internal rep is released or when
  470.  * the cached borderPtr needs to be changed.
  471.  *
  472.  * Results:
  473.  * None.
  474.  *
  475.  * Side effects:
  476.  * The object reference count is decremented. When both it
  477.  * and the hash ref count go to zero, the border's resources
  478.  * are released.
  479.  *
  480.  *---------------------------------------------------------------------------
  481.  */
  482. static void
  483. FreeBorderObjProc(objPtr)
  484.     Tcl_Obj *objPtr; /* The object we are releasing. */
  485. {
  486.     TkBorder *borderPtr = (TkBorder *) objPtr->internalRep.twoPtrValue.ptr1;
  487.     if (borderPtr != NULL) {
  488. borderPtr->objRefCount--;
  489. if ((borderPtr->objRefCount == 0) 
  490. && (borderPtr->resourceRefCount == 0)) {
  491.     ckfree((char *) borderPtr);
  492. }
  493. objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL;
  494.     }
  495. }
  496. /*
  497.  *---------------------------------------------------------------------------
  498.  *
  499.  * DupBorderObjProc -- 
  500.  *
  501.  * When a cached border object is duplicated, this is called to
  502.  * update the internal reps.
  503.  *
  504.  * Results:
  505.  * None.
  506.  *
  507.  * Side effects:
  508.  * The border's objRefCount is incremented and the internal rep
  509.  * of the copy is set to point to it.
  510.  *
  511.  *---------------------------------------------------------------------------
  512.  */
  513. static void
  514. DupBorderObjProc(srcObjPtr, dupObjPtr)
  515.     Tcl_Obj *srcObjPtr; /* The object we are copying from. */
  516.     Tcl_Obj *dupObjPtr; /* The object we are copying to. */
  517. {
  518.     TkBorder *borderPtr = (TkBorder *) srcObjPtr->internalRep.twoPtrValue.ptr1;
  519.     
  520.     dupObjPtr->typePtr = srcObjPtr->typePtr;
  521.     dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) borderPtr;
  522.     if (borderPtr != NULL) {
  523. borderPtr->objRefCount++;
  524.     }
  525. }
  526. /*
  527.  *----------------------------------------------------------------------
  528.  *
  529.  * Tk_SetBackgroundFromBorder --
  530.  *
  531.  * Change the background of a window to one appropriate for a given
  532.  * 3-D border.
  533.  *
  534.  * Results:
  535.  * None.
  536.  *
  537.  * Side effects:
  538.  * Tkwin's background gets modified.
  539.  *
  540.  *----------------------------------------------------------------------
  541.  */
  542. void
  543. Tk_SetBackgroundFromBorder(tkwin, border)
  544.     Tk_Window tkwin; /* Window whose background is to be set. */
  545.     Tk_3DBorder border; /* Token for border. */
  546. {
  547.     register TkBorder *borderPtr = (TkBorder *) border;
  548.     Tk_SetWindowBackground(tkwin, borderPtr->bgColorPtr->pixel);
  549. }
  550. /*
  551.  *----------------------------------------------------------------------
  552.  *
  553.  * Tk_GetReliefFromObj --
  554.  *
  555.  * Return an integer value based on the value of the objPtr.
  556.  *
  557.  * Results:
  558.  * The return value is a standard Tcl result. If an error occurs during
  559.  * conversion, an error message is left in the interpreter's result
  560.  * unless "interp" is NULL.
  561.  *
  562.  * Side effects:
  563.  * The object gets converted by Tcl_GetIndexFromObj.
  564.  *
  565.  *----------------------------------------------------------------------
  566.  */
  567. int
  568. Tk_GetReliefFromObj(interp, objPtr, resultPtr)
  569.     Tcl_Interp *interp; /* Used for error reporting. */
  570.     Tcl_Obj *objPtr; /* The object we are trying to get the 
  571.  * value from. */
  572.     int *resultPtr; /* Where to place the answer. */
  573. {
  574.     return Tcl_GetIndexFromObj(interp, objPtr, reliefStrings, "relief", 0, 
  575.     resultPtr);
  576. }
  577. /*
  578.  *----------------------------------------------------------------------
  579.  *
  580.  * Tk_GetRelief --
  581.  *
  582.  * Parse a relief description and return the corresponding
  583.  * relief value, or an error.
  584.  *
  585.  * Results:
  586.  * A standard Tcl return value.  If all goes well then
  587.  * *reliefPtr is filled in with one of the values
  588.  * TK_RELIEF_RAISED, TK_RELIEF_FLAT, or TK_RELIEF_SUNKEN.
  589.  *
  590.  * Side effects:
  591.  * None.
  592.  *
  593.  *----------------------------------------------------------------------
  594.  */
  595. int
  596. Tk_GetRelief(interp, name, reliefPtr)
  597.     Tcl_Interp *interp; /* For error messages. */
  598.     CONST char *name; /* Name of a relief type. */
  599.     int *reliefPtr; /* Where to store converted relief. */
  600. {
  601.     char c;
  602.     size_t length;
  603.     c = name[0];
  604.     length = strlen(name);
  605.     if ((c == 'f') && (strncmp(name, "flat", length) == 0)) {
  606. *reliefPtr = TK_RELIEF_FLAT;
  607.     } else if ((c == 'g') && (strncmp(name, "groove", length) == 0)
  608.     && (length >= 2)) {
  609.         *reliefPtr = TK_RELIEF_GROOVE;
  610.     } else if ((c == 'r') && (strncmp(name, "raised", length) == 0)
  611.     && (length >= 2)) {
  612. *reliefPtr = TK_RELIEF_RAISED;
  613.     } else if ((c == 'r') && (strncmp(name, "ridge", length) == 0)) {
  614.         *reliefPtr = TK_RELIEF_RIDGE;
  615.     } else if ((c == 's') && (strncmp(name, "solid", length) == 0)) {
  616. *reliefPtr = TK_RELIEF_SOLID;
  617.     } else if ((c == 's') && (strncmp(name, "sunken", length) == 0)) {
  618. *reliefPtr = TK_RELIEF_SUNKEN;
  619.     } else {
  620. char buf[200];
  621. sprintf(buf, "bad relief type "%.50s": must be %s",
  622. name, "flat, groove, raised, ridge, solid, or sunken");
  623. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  624. return TCL_ERROR;
  625.     }
  626.     return TCL_OK;
  627. }
  628. /*
  629.  *--------------------------------------------------------------
  630.  *
  631.  * Tk_NameOfRelief --
  632.  *
  633.  * Given a relief value, produce a string describing that
  634.  * relief value.
  635.  *
  636.  * Results:
  637.  * The return value is a static string that is equivalent
  638.  * to relief.
  639.  *
  640.  * Side effects:
  641.  * None.
  642.  *
  643.  *--------------------------------------------------------------
  644.  */
  645. CONST char *
  646. Tk_NameOfRelief(relief)
  647.     int relief; /* One of TK_RELIEF_FLAT, TK_RELIEF_RAISED,
  648.  * or TK_RELIEF_SUNKEN. */
  649. {
  650.     if (relief == TK_RELIEF_FLAT) {
  651. return "flat";
  652.     } else if (relief == TK_RELIEF_SUNKEN) {
  653. return "sunken";
  654.     } else if (relief == TK_RELIEF_RAISED) {
  655. return "raised";
  656.     } else if (relief == TK_RELIEF_GROOVE) {
  657. return "groove";
  658.     } else if (relief == TK_RELIEF_RIDGE) {
  659. return "ridge";
  660.     } else if (relief == TK_RELIEF_SOLID) {
  661. return "solid";
  662.     } else if (relief == TK_RELIEF_NULL) {
  663. return "";
  664.     } else {
  665. return "unknown relief";
  666.     }
  667. }
  668. /*
  669.  *--------------------------------------------------------------
  670.  *
  671.  * Tk_Draw3DPolygon --
  672.  *
  673.  * Draw a border with 3-D appearance around the edge of a
  674.  * given polygon.
  675.  *
  676.  * Results:
  677.  * None.
  678.  *
  679.  * Side effects:
  680.  * Information is drawn in "drawable" in the form of a
  681.  * 3-D border borderWidth units width wide on the left
  682.  * of the trajectory given by pointPtr and numPoints (or
  683.  * -borderWidth units wide on the right side, if borderWidth
  684.  * is negative).
  685.  *
  686.  *--------------------------------------------------------------
  687.  */
  688. void
  689. Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  690. borderWidth, leftRelief)
  691.     Tk_Window tkwin; /* Window for which border was allocated. */
  692.     Drawable drawable; /* X window or pixmap in which to draw. */
  693.     Tk_3DBorder border; /* Token for border to draw. */
  694.     XPoint *pointPtr; /* Array of points describing
  695.  * polygon.  All points must be
  696.  * absolute (CoordModeOrigin). */
  697.     int numPoints; /* Number of points at *pointPtr. */
  698.     int borderWidth; /* Width of border, measured in
  699.  * pixels to the left of the polygon's
  700.  * trajectory.   May be negative. */
  701.     int leftRelief; /* TK_RELIEF_RAISED or
  702.  * TK_RELIEF_SUNKEN: indicates how
  703.  * stuff to left of trajectory looks
  704.  * relative to stuff on right. */
  705. {
  706.     XPoint poly[4], b1, b2, newB1, newB2;
  707.     XPoint perp, c, shift1, shift2; /* Used for handling parallel lines. */
  708.     register XPoint *p1Ptr, *p2Ptr;
  709.     TkBorder *borderPtr = (TkBorder *) border;
  710.     GC gc;
  711.     int i, lightOnLeft, dx, dy, parallel, pointsSeen;
  712.     Display *display = Tk_Display(tkwin);
  713.     if (borderPtr->lightGC == None) {
  714. TkpGetShadows(borderPtr, tkwin);
  715.     }
  716.     /*
  717.      * Handle grooves and ridges with recursive calls.
  718.      */
  719.     if ((leftRelief == TK_RELIEF_GROOVE) || (leftRelief == TK_RELIEF_RIDGE)) {
  720. int halfWidth;
  721. halfWidth = borderWidth/2;
  722. Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  723. halfWidth, (leftRelief == TK_RELIEF_GROOVE) ? TK_RELIEF_RAISED
  724. : TK_RELIEF_SUNKEN);
  725. Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  726. -halfWidth, (leftRelief == TK_RELIEF_GROOVE) ? TK_RELIEF_SUNKEN
  727. : TK_RELIEF_RAISED);
  728. return;
  729.     }
  730.     /*
  731.      * If the polygon is already closed, drop the last point from it
  732.      * (we'll close it automatically).
  733.      */
  734.     p1Ptr = &pointPtr[numPoints-1];
  735.     p2Ptr = &pointPtr[0];
  736.     if ((p1Ptr->x == p2Ptr->x) && (p1Ptr->y == p2Ptr->y)) {
  737. numPoints--;
  738.     }
  739.     /*
  740.      * The loop below is executed once for each vertex in the polgon.
  741.      * At the beginning of each iteration things look like this:
  742.      *
  743.      *          poly[1]       /
  744.      *             *        /
  745.      *             |      /
  746.      *             b1   * poly[0] (pointPtr[i-1])
  747.      *             |    |
  748.      *             |    |
  749.      *             |    |
  750.      *             |    |
  751.      *             |    |
  752.      *             |    | *p1Ptr            *p2Ptr
  753.      *             b2   *--------------------*
  754.      *             |
  755.      *             |
  756.      *             x-------------------------
  757.      *
  758.      * The job of this iteration is to do the following:
  759.      * (a) Compute x (the border corner corresponding to
  760.      *     pointPtr[i]) and put it in poly[2].  As part of
  761.      *    this, compute a new b1 and b2 value for the next
  762.      *    side of the polygon.
  763.      * (b) Put pointPtr[i] into poly[3].
  764.      * (c) Draw the polygon given by poly[0..3].
  765.      * (d) Advance poly[0], poly[1], b1, and b2 for the
  766.      *     next side of the polygon.
  767.      */
  768.     /*
  769.      * The above situation doesn't first come into existence until
  770.      * two points have been processed;  the first two points are
  771.      * used to "prime the pump", so some parts of the processing
  772.      * are ommitted for these points.  The variable "pointsSeen"
  773.      * keeps track of the priming process;  it has to be separate
  774.      * from i in order to be able to ignore duplicate points in the
  775.      * polygon.
  776.      */
  777.     pointsSeen = 0;
  778.     for (i = -2, p1Ptr = &pointPtr[numPoints-2], p2Ptr = p1Ptr+1;
  779.     i < numPoints; i++, p1Ptr = p2Ptr, p2Ptr++) {
  780. if ((i == -1) || (i == numPoints-1)) {
  781.     p2Ptr = pointPtr;
  782. }
  783. if ((p2Ptr->x == p1Ptr->x) && (p2Ptr->y == p1Ptr->y)) {
  784.     /*
  785.      * Ignore duplicate points (they'd cause core dumps in
  786.      * ShiftLine calls below).
  787.      */
  788.     continue;
  789. }
  790. ShiftLine(p1Ptr, p2Ptr, borderWidth, &newB1);
  791. newB2.x = newB1.x + (p2Ptr->x - p1Ptr->x);
  792. newB2.y = newB1.y + (p2Ptr->y - p1Ptr->y);
  793. poly[3] = *p1Ptr;
  794. parallel = 0;
  795. if (pointsSeen >= 1) {
  796.     parallel = Intersect(&newB1, &newB2, &b1, &b2, &poly[2]);
  797.     /*
  798.      * If two consecutive segments of the polygon are parallel,
  799.      * then things get more complex.  Consider the following
  800.      * diagram:
  801.      *
  802.      * poly[1]
  803.      *    *----b1-----------b2------a
  804.      *                                
  805.      *                                  
  806.      *         *---------*----------*    b
  807.      *        poly[0]  *p2Ptr   *p1Ptr  /
  808.      *                                /
  809.      *              --*--------*----c
  810.      *              newB1    newB2
  811.      *
  812.      * Instead of using x and *p1Ptr for poly[2] and poly[3], as
  813.      * in the original diagram, use a and b as above.  Then instead
  814.      * of using x and *p1Ptr for the new poly[0] and poly[1], use
  815.      * b and c as above.
  816.      *
  817.      * Do the computation in three stages:
  818.      * 1. Compute a point "perp" such that the line p1Ptr-perp
  819.      *    is perpendicular to p1Ptr-p2Ptr.
  820.      * 2. Compute the points a and c by intersecting the lines
  821.      *    b1-b2 and newB1-newB2 with p1Ptr-perp.
  822.      * 3. Compute b by shifting p1Ptr-perp to the right and
  823.      *    intersecting it with p1Ptr-p2Ptr.
  824.      */
  825.     if (parallel) {
  826. perp.x = p1Ptr->x + (p2Ptr->y - p1Ptr->y);
  827. perp.y = p1Ptr->y - (p2Ptr->x - p1Ptr->x);
  828. (void) Intersect(p1Ptr, &perp, &b1, &b2, &poly[2]);
  829. (void) Intersect(p1Ptr, &perp, &newB1, &newB2, &c);
  830. ShiftLine(p1Ptr, &perp, borderWidth, &shift1);
  831. shift2.x = shift1.x + (perp.x - p1Ptr->x);
  832. shift2.y = shift1.y + (perp.y - p1Ptr->y);
  833. (void) Intersect(p1Ptr, p2Ptr, &shift1, &shift2, &poly[3]);
  834.     }
  835. }
  836. if (pointsSeen >= 2) {
  837.     dx = poly[3].x - poly[0].x;
  838.     dy = poly[3].y - poly[0].y;
  839.     if (dx > 0) {
  840. lightOnLeft = (dy <= dx);
  841.     } else {
  842. lightOnLeft = (dy < dx);
  843.     }
  844.     if (lightOnLeft ^ (leftRelief == TK_RELIEF_RAISED)) {
  845. gc = borderPtr->lightGC;
  846.     } else {
  847. gc = borderPtr->darkGC;
  848.     }
  849.     XFillPolygon(display, drawable, gc, poly, 4, Convex,
  850.     CoordModeOrigin);
  851. }
  852. b1.x = newB1.x;
  853. b1.y = newB1.y;
  854. b2.x = newB2.x;
  855. b2.y = newB2.y;
  856. poly[0].x = poly[3].x;
  857. poly[0].y = poly[3].y;
  858. if (parallel) {
  859.     poly[1].x = c.x;
  860.     poly[1].y = c.y;
  861. } else if (pointsSeen >= 1) {
  862.     poly[1].x = poly[2].x;
  863.     poly[1].y = poly[2].y;
  864. }
  865. pointsSeen++;
  866.     }
  867. }
  868. /*
  869.  *----------------------------------------------------------------------
  870.  *
  871.  * Tk_Fill3DRectangle --
  872.  *
  873.  * Fill a rectangular area, supplying a 3D border if desired.
  874.  *
  875.  * Results:
  876.  * None.
  877.  *
  878.  * Side effects:
  879.  * Information gets drawn on the screen.
  880.  *
  881.  *----------------------------------------------------------------------
  882.  */
  883. void
  884. Tk_Fill3DRectangle(tkwin, drawable, border, x, y, width,
  885. height, borderWidth, relief)
  886.     Tk_Window tkwin; /* Window for which border was allocated. */
  887.     Drawable drawable; /* X window or pixmap in which to draw. */
  888.     Tk_3DBorder border; /* Token for border to draw. */
  889.     int x, y, width, height; /* Outside area of rectangular region. */
  890.     int borderWidth; /* Desired width for border, in
  891.  * pixels. Border will be *inside* region. */
  892.     int relief; /* Indicates 3D effect: TK_RELIEF_FLAT,
  893.  * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */
  894. {
  895.     register TkBorder *borderPtr = (TkBorder *) border;
  896.     int doubleBorder;
  897.     /*
  898.      * This code is slightly tricky because it only draws the background
  899.      * in areas not covered by the 3D border. This avoids flashing
  900.      * effects on the screen for the border region.
  901.      */
  902.   
  903.     if (relief == TK_RELIEF_FLAT) {
  904. borderWidth = 0;
  905.     } else {
  906. /*
  907.  * We need to make this extra check, otherwise we will leave
  908.  * garbage in thin frames [Bug: 3596]
  909.  */
  910. if (width < 2*borderWidth) {
  911.     borderWidth = width/2;
  912. }
  913. if (height < 2*borderWidth) {
  914.     borderWidth = height/2;
  915. }
  916.     }
  917.     doubleBorder = 2*borderWidth;
  918.     if ((width > doubleBorder) && (height > doubleBorder)) {
  919. XFillRectangle(Tk_Display(tkwin), drawable, borderPtr->bgGC,
  920. x + borderWidth, y + borderWidth,
  921. (unsigned int) (width - doubleBorder),
  922. (unsigned int) (height - doubleBorder));
  923.     }
  924.     if (borderWidth) {
  925. Tk_Draw3DRectangle(tkwin, drawable, border, x, y, width,
  926. height, borderWidth, relief);
  927.     }
  928. }
  929. /*
  930.  *----------------------------------------------------------------------
  931.  *
  932.  * Tk_Fill3DPolygon --
  933.  *
  934.  * Fill a polygonal area, supplying a 3D border if desired.
  935.  *
  936.  * Results:
  937.  * None.
  938.  *
  939.  * Side effects:
  940.  * Information gets drawn on the screen.
  941.  *
  942.  *----------------------------------------------------------------------
  943.  */
  944. void
  945. Tk_Fill3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  946. borderWidth, leftRelief)
  947.     Tk_Window tkwin; /* Window for which border was allocated. */
  948.     Drawable drawable; /* X window or pixmap in which to draw. */
  949.     Tk_3DBorder border; /* Token for border to draw. */
  950.     XPoint *pointPtr; /* Array of points describing
  951.  * polygon.  All points must be
  952.  * absolute (CoordModeOrigin). */
  953.     int numPoints; /* Number of points at *pointPtr. */
  954.     int borderWidth; /* Width of border, measured in
  955.  * pixels to the left of the polygon's
  956.  * trajectory.   May be negative. */
  957.     int leftRelief; /* Indicates 3D effect of left side of
  958.  * trajectory relative to right:
  959.  * TK_RELIEF_FLAT, TK_RELIEF_RAISED,
  960.  * or TK_RELIEF_SUNKEN. */
  961. {
  962.     register TkBorder *borderPtr = (TkBorder *) border;
  963.     XFillPolygon(Tk_Display(tkwin), drawable, borderPtr->bgGC,
  964.     pointPtr, numPoints, Complex, CoordModeOrigin);
  965.     if (leftRelief != TK_RELIEF_FLAT) {
  966. Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  967. borderWidth, leftRelief);
  968.     }
  969. }
  970. /*
  971.  *--------------------------------------------------------------
  972.  *
  973.  * BorderInit --
  974.  *
  975.  * Initialize the structures used for border management.
  976.  *
  977.  * Results:
  978.  * None.
  979.  *
  980.  * Side effects:
  981.  * Read the code.
  982.  *
  983.  *-------------------------------------------------------------
  984.  */
  985. static void
  986. BorderInit(dispPtr)
  987.      TkDisplay * dispPtr;     /* Used to access thread-specific data. */
  988. {
  989.     dispPtr->borderInit = 1;
  990.     Tcl_InitHashTable(&dispPtr->borderTable, TCL_STRING_KEYS);
  991. }
  992. /*
  993.  *--------------------------------------------------------------
  994.  *
  995.  * ShiftLine --
  996.  *
  997.  * Given two points on a line, compute a point on a
  998.  * new line that is parallel to the given line and
  999.  * a given distance away from it.
  1000.  *
  1001.  * Results:
  1002.  * None.
  1003.  *
  1004.  * Side effects:
  1005.  * None.
  1006.  *
  1007.  *--------------------------------------------------------------
  1008.  */
  1009. static void
  1010. ShiftLine(p1Ptr, p2Ptr, distance, p3Ptr)
  1011.     XPoint *p1Ptr; /* First point on line. */
  1012.     XPoint *p2Ptr; /* Second point on line. */
  1013.     int distance; /* New line is to be this many
  1014.  * units to the left of original
  1015.  * line, when looking from p1 to
  1016.  * p2.  May be negative. */
  1017.     XPoint *p3Ptr; /* Store coords of point on new
  1018.  * line here. */
  1019. {
  1020.     int dx, dy, dxNeg, dyNeg;
  1021.     /*
  1022.      * The table below is used for a quick approximation in
  1023.      * computing the new point.  An index into the table
  1024.      * is 128 times the slope of the original line (the slope
  1025.      * must always be between 0 and 1).  The value of the table
  1026.      * entry is 128 times the amount to displace the new line
  1027.      * in y for each unit of perpendicular distance.  In other
  1028.      * words, the table maps from the tangent of an angle to
  1029.      * the inverse of its cosine.  If the slope of the original
  1030.      * line is greater than 1, then the displacement is done in
  1031.      * x rather than in y.
  1032.      */
  1033.     static int shiftTable[129];
  1034.     /*
  1035.      * Initialize the table if this is the first time it is
  1036.      * used.
  1037.      */
  1038.     if (shiftTable[0] == 0) {
  1039. int i;
  1040. double tangent, cosine;
  1041. for (i = 0; i <= 128; i++) {
  1042.     tangent = i/128.0;
  1043.     cosine = 128/cos(atan(tangent)) + .5;
  1044.     shiftTable[i] = (int) cosine;
  1045. }
  1046.     }
  1047.     *p3Ptr = *p1Ptr;
  1048.     dx = p2Ptr->x - p1Ptr->x;
  1049.     dy = p2Ptr->y - p1Ptr->y;
  1050.     if (dy < 0) {
  1051. dyNeg = 1;
  1052. dy = -dy;
  1053.     } else {
  1054. dyNeg = 0;
  1055.     }
  1056.     if (dx < 0) {
  1057. dxNeg = 1;
  1058. dx = -dx;
  1059.     } else {
  1060. dxNeg = 0;
  1061.     }
  1062.     if (dy <= dx) {
  1063. dy = ((distance * shiftTable[(dy<<7)/dx]) + 64) >> 7;
  1064. if (!dxNeg) {
  1065.     dy = -dy;
  1066. }
  1067. p3Ptr->y += dy;
  1068.     } else {
  1069. dx = ((distance * shiftTable[(dx<<7)/dy]) + 64) >> 7;
  1070. if (dyNeg) {
  1071.     dx = -dx;
  1072. }
  1073. p3Ptr->x += dx;
  1074.     }
  1075. }
  1076. /*
  1077.  *--------------------------------------------------------------
  1078.  *
  1079.  * Intersect --
  1080.  *
  1081.  * Find the intersection point between two lines.
  1082.  *
  1083.  * Results:
  1084.  * Under normal conditions 0 is returned and the point
  1085.  * at *iPtr is filled in with the intersection between
  1086.  * the two lines.  If the two lines are parallel, then
  1087.  * -1 is returned and *iPtr isn't modified.
  1088.  *
  1089.  * Side effects:
  1090.  * None.
  1091.  *
  1092.  *--------------------------------------------------------------
  1093.  */
  1094. static int
  1095. Intersect(a1Ptr, a2Ptr, b1Ptr, b2Ptr, iPtr)
  1096.     XPoint *a1Ptr; /* First point of first line. */
  1097.     XPoint *a2Ptr; /* Second point of first line. */
  1098.     XPoint *b1Ptr; /* First point of second line. */
  1099.     XPoint *b2Ptr; /* Second point of second line. */
  1100.     XPoint *iPtr; /* Filled in with intersection point. */
  1101. {
  1102.     int dxadyb, dxbdya, dxadxb, dyadyb, p, q;
  1103.     /*
  1104.      * The code below is just a straightforward manipulation of two
  1105.      * equations of the form y = (x-x1)*(y2-y1)/(x2-x1) + y1 to solve
  1106.      * for the x-coordinate of intersection, then the y-coordinate.
  1107.      */
  1108.     dxadyb = (a2Ptr->x - a1Ptr->x)*(b2Ptr->y - b1Ptr->y);
  1109.     dxbdya = (b2Ptr->x - b1Ptr->x)*(a2Ptr->y - a1Ptr->y);
  1110.     dxadxb = (a2Ptr->x - a1Ptr->x)*(b2Ptr->x - b1Ptr->x);
  1111.     dyadyb = (a2Ptr->y - a1Ptr->y)*(b2Ptr->y - b1Ptr->y);
  1112.     if (dxadyb == dxbdya) {
  1113. return -1;
  1114.     }
  1115.     p = (a1Ptr->x*dxbdya - b1Ptr->x*dxadyb + (b1Ptr->y - a1Ptr->y)*dxadxb);
  1116.     q = dxbdya - dxadyb;
  1117.     if (q < 0) {
  1118. p = -p;
  1119. q = -q;
  1120.     }
  1121.     if (p < 0) {
  1122. iPtr->x = - ((-p + q/2)/q);
  1123.     } else {
  1124. iPtr->x = (p + q/2)/q;
  1125.     }
  1126.     p = (a1Ptr->y*dxadyb - b1Ptr->y*dxbdya + (b1Ptr->x - a1Ptr->x)*dyadyb);
  1127.     q = dxadyb - dxbdya;
  1128.     if (q < 0) {
  1129. p = -p;
  1130. q = -q;
  1131.     }
  1132.     if (p < 0) {
  1133. iPtr->y = - ((-p + q/2)/q);
  1134.     } else {
  1135. iPtr->y = (p + q/2)/q;
  1136.     }
  1137.     return 0;
  1138. }
  1139. /*
  1140.  *----------------------------------------------------------------------
  1141.  *
  1142.  * Tk_Get3DBorderFromObj --
  1143.  *
  1144.  * Returns the border referred to by a Tcl object.  The border must
  1145.  * already have been allocated via a call to Tk_Alloc3DBorderFromObj 
  1146.  * or Tk_Get3DBorder.
  1147.  *
  1148.  * Results:
  1149.  * Returns the Tk_3DBorder that matches the tkwin and the string rep
  1150.  * of the name of the border given in objPtr.
  1151.  *
  1152.  * Side effects:
  1153.  * If the object is not already a border, the conversion will free
  1154.  * any old internal representation. 
  1155.  *
  1156.  *----------------------------------------------------------------------
  1157.  */
  1158. Tk_3DBorder
  1159. Tk_Get3DBorderFromObj(tkwin, objPtr)
  1160.     Tk_Window tkwin;
  1161.     Tcl_Obj *objPtr; /* The object whose string value selects
  1162.  * a border. */
  1163. {
  1164.     TkBorder *borderPtr = NULL;
  1165.     Tcl_HashEntry *hashPtr;
  1166.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  1167.     if (objPtr->typePtr != &tkBorderObjType) {
  1168. InitBorderObj(objPtr);
  1169.     }
  1170.     /*
  1171.      * If we are lucky (and the user doesn't use too many different
  1172.      * displays, screens, or colormaps...) then the  TkBorder 
  1173.      * structure we need will be cached in the internal
  1174.      * representation of the Tcl_Obj.  Check it out...
  1175.      */
  1176.     borderPtr = (TkBorder *) objPtr->internalRep.twoPtrValue.ptr1;
  1177.     if ((borderPtr != NULL)
  1178.     && (borderPtr->resourceRefCount > 0)
  1179.     && (Tk_Screen(tkwin) == borderPtr->screen)
  1180.     && (Tk_Colormap(tkwin) == borderPtr->colormap)) {
  1181. /*
  1182.  * The object already points to the right border structure.
  1183.  * Just return it.
  1184.  */
  1185. return (Tk_3DBorder) borderPtr;
  1186.     }
  1187.     /*
  1188.      * If we make it here, it means we aren't so lucky.  Either there
  1189.      * was no cached TkBorder in the Tcl_Obj, or the TkBorder that was
  1190.      * there is for the wrong screen/colormap.  Either way, we have
  1191.      * to search for the right TkBorder.  For each color name, there is
  1192.      * linked list of TkBorder structures, one structure for each 
  1193.      * screen/colormap combination.  The head of the linked list is
  1194.      * recorded in a hash table (where the key is the color name)
  1195.      * attached to the TkDisplay structure.  Walk this list to find
  1196.      * the right TkBorder structure.
  1197.      */
  1198.     hashPtr = Tcl_FindHashEntry(&dispPtr->borderTable, Tcl_GetString(objPtr));
  1199.     if (hashPtr == NULL) {
  1200. goto error;
  1201.     }
  1202.     for (borderPtr = (TkBorder *) Tcl_GetHashValue(hashPtr);
  1203.     (borderPtr != NULL); borderPtr = borderPtr->nextPtr) {
  1204. if ((Tk_Screen(tkwin) == borderPtr->screen)
  1205. && (Tk_Colormap(tkwin) == borderPtr->colormap)) {
  1206.     FreeBorderObjProc(objPtr);
  1207.     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) borderPtr;
  1208.     borderPtr->objRefCount++;
  1209.     return (Tk_3DBorder) borderPtr;
  1210. }
  1211.     }
  1212.     error:
  1213.     panic("Tk_Get3DBorderFromObj called with non-existent border!");
  1214.     /*
  1215.      * The following code isn't reached; it's just there to please compilers.
  1216.      */
  1217.     return NULL;
  1218. }
  1219. /*
  1220.  *----------------------------------------------------------------------
  1221.  *
  1222.  * InitBorderObj --
  1223.  *
  1224.  * Attempt to generate a border internal form for the Tcl object
  1225.  * "objPtr".
  1226.  *
  1227.  * Results:
  1228.  * The return value is a standard Tcl result. If an error occurs during
  1229.  * conversion, an error message is left in the interpreter's result
  1230.  * unless "interp" is NULL.
  1231.  *
  1232.  * Side effects:
  1233.  * If no error occurs, a blank internal format for a border value
  1234.  * is intialized. The final form cannot be done without a Tk_Window.
  1235.  *
  1236.  *----------------------------------------------------------------------
  1237.  */
  1238. static void
  1239. InitBorderObj(objPtr)
  1240.     Tcl_Obj *objPtr; /* The object to convert. */
  1241. {
  1242.     Tcl_ObjType *typePtr;
  1243.     /*
  1244.      * Free the old internalRep before setting the new one. 
  1245.      */
  1246.     Tcl_GetString(objPtr);
  1247.     typePtr = objPtr->typePtr;
  1248.     if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
  1249. (*typePtr->freeIntRepProc)(objPtr);
  1250.     }
  1251.     objPtr->typePtr = &tkBorderObjType;
  1252.     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL;
  1253. }
  1254. /*
  1255.  *----------------------------------------------------------------------
  1256.  *
  1257.  * TkDebugBorder --
  1258.  *
  1259.  * This procedure returns debugging information about a border.
  1260.  *
  1261.  * Results:
  1262.  * The return value is a list with one sublist for each TkBorder
  1263.  * corresponding to "name".  Each sublist has two elements that
  1264.  * contain the resourceRefCount and objRefCount fields from the
  1265.  * TkBorder structure.
  1266.  *
  1267.  * Side effects:
  1268.  * None.
  1269.  *
  1270.  *----------------------------------------------------------------------
  1271.  */
  1272. Tcl_Obj *
  1273. TkDebugBorder(tkwin, name)
  1274.     Tk_Window tkwin; /* The window in which the border will be
  1275.  * used (not currently used). */
  1276.     char *name; /* Name of the desired color. */
  1277. {
  1278.     TkBorder *borderPtr;
  1279.     Tcl_HashEntry *hashPtr;
  1280.     Tcl_Obj *resultPtr, *objPtr;
  1281.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  1282.     resultPtr = Tcl_NewObj();
  1283.     hashPtr = Tcl_FindHashEntry(&dispPtr->borderTable, name);
  1284.     if (hashPtr != NULL) {
  1285. borderPtr = (TkBorder *) Tcl_GetHashValue(hashPtr);
  1286. if (borderPtr == NULL) {
  1287.     panic("TkDebugBorder found empty hash table entry");
  1288. }
  1289. for ( ; (borderPtr != NULL); borderPtr = borderPtr->nextPtr) {
  1290.     objPtr = Tcl_NewObj();
  1291.     Tcl_ListObjAppendElement(NULL, objPtr,
  1292.     Tcl_NewIntObj(borderPtr->resourceRefCount));
  1293.     Tcl_ListObjAppendElement(NULL, objPtr,
  1294.     Tcl_NewIntObj(borderPtr->objRefCount)); 
  1295.     Tcl_ListObjAppendElement(NULL, resultPtr, objPtr);
  1296. }
  1297.     }
  1298.     return resultPtr;
  1299. }