/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tk3d.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tk3d.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.42  
changed lines
  Added in v.220

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25