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

Contents of /projs/trunk/shared_source/tk_base/tk3d.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (show annotations) (download)
Fri Oct 14 01:50:00 2016 UTC (8 years, 1 month ago) by dashley
File MIME type: text/plain
File size: 41874 byte(s)
Move shared source code to commonize.
1 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tk3d.c,v 1.1.1.1 2001/06/13 04:53:30 dtashley Exp $ */
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
1402 /* $History: tk3d.c $
1403 *
1404 * ***************** Version 1 *****************
1405 * User: Dtashley Date: 1/02/01 Time: 2:32a
1406 * Created in $/IjuScripter, IjuConsole/Source/Tk Base
1407 * Initial check-in.
1408 */
1409
1410 /* End of TK3D.C */

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25