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

Annotation of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tk3d.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (hide annotations) (download)
Sat Nov 5 10:54:17 2016 UTC (7 years, 8 months ago) by dashley
File MIME type: text/plain
File size: 41560 byte(s)
License and property (keyword) changes.
1 dashley 69 /* $Header$ */
2 dashley 25
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 dashley 69 /* End of tk3d.c */

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25