1 /*
2  * tixUtils.c --
3  *
4  *	This file contains some utility functions for Tix, such as the
5  *	subcommand handling functions and option handling functions.
6  *
7  * Copyright (c) 1993-1999 Ioi Kim Lam.
8  * Copyright (c) 2000-2001 Tix Project Group.
9  *
10  * See the file "license.terms" for information on usage and redistribution
11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12  *
13  * $Id: tixUtils.c,v 1.13 2008/02/28 04:29:17 hobbs Exp $
14  */
15 
16 #include <tcl.h>
17 #include <tixPort.h>
18 #include <tixInt.h>
19 
20 /*
21  * Forward declarations for procedures defined later in this file:
22  */
23 
24 static int	ReliefParseProc(ClientData clientData,
25 	Tcl_Interp *interp, Tk_Window tkwin, CONST84 char *value,
26 	char *widRec, int offset);
27 static char *	ReliefPrintProc(ClientData clientData,
28 	Tk_Window tkwin, char *widRec, int offset,
29 	Tix_FreeProc **freeProcPtr);
30 
31 #define WRONG_ARGC 1
32 #define NO_MATCH   2
33 
34 
35 /*----------------------------------------------------------------------
36  * Tix_HandleSubCmds --
37  *
38  *	This function makes it easier to write major-minor style TCL
39  *	commands.  It matches the minor command (sub-command) names
40  *	with names defined in the cmdInfo structure and call the
41  *	appropriate sub-command functions for you. This function will
42  *	automatically generate error messages when the user calls an
43  *	invalid sub-command or calls a sub-command with incorrect
44  *	number of arguments.
45  *
46  *----------------------------------------------------------------------
47  */
48 
Tix_HandleSubCmds(cmdInfo,subCmdInfo,clientData,interp,argc,argv)49 int Tix_HandleSubCmds(cmdInfo, subCmdInfo, clientData, interp, argc, argv)
50     Tix_CmdInfo * cmdInfo;
51     Tix_SubCmdInfo * subCmdInfo;
52     ClientData clientData;	/* Main window associated with
53 				 * interpreter. */
54     Tcl_Interp *interp;		/* Current interpreter. */
55     int argc;			/* Number of arguments. */
56     CONST84 char **argv;	/* Argument strings. */
57 {
58 
59     int i;
60     int error = NO_MATCH;
61     unsigned int len;
62     Tix_SubCmdInfo * s;
63 
64     /*
65      * First check if the number of arguments to the major command
66      * is correct
67      */
68     argc -= 1;
69     if (argc < cmdInfo->minargc ||
70 	(cmdInfo->maxargc != TIX_VAR_ARGS && argc > cmdInfo->maxargc)) {
71 
72 	Tcl_AppendResult(interp, "wrong # args: should be \"",
73 	    argv[0], " ", cmdInfo->info, "\".", (char *) NULL);
74 
75 	return TCL_ERROR;
76     }
77 
78     /*
79      * Now try to match the subcommands with argv[1]
80      */
81     argc -= 1;
82     len = strlen(argv[1]);
83 
84     for (i = 0, s = subCmdInfo; i < cmdInfo->numSubCmds; i++, s++) {
85 	if (s->name == TIX_DEFAULT_SUBCMD) {
86 	    if (s->checkArgvProc) {
87 	      if (!((*s->checkArgvProc)(clientData, interp, argc+1, argv+1))) {
88 		    /* Some improper argv in the arguments of the default
89 		     * subcommand
90 		     */
91 		    break;
92 		}
93 	    }
94 	    return (*s->proc)(clientData, interp, argc+1, argv+1);
95 	}
96 
97 	if (s->namelen == TIX_DEFAULT_LEN) {
98 	    s->namelen = strlen(s->name);
99 	}
100 	if (s->name[0] == argv[1][0] && strncmp(argv[1],s->name,len)==0) {
101 	    if (argc < s->minargc) {
102 		error = WRONG_ARGC;
103 		break;
104 	    }
105 
106 	    if (s->maxargc != TIX_VAR_ARGS &&
107 		argc > s->maxargc) {
108 		error = WRONG_ARGC;
109 		break;
110 	    }
111 
112 	    /*
113 	     * Here we have a matched argc and command name --> go for it!
114 	     */
115 	    return (*s->proc)(clientData, interp, argc, argv+2);
116 	}
117     }
118 
119     if (error == WRONG_ARGC) {
120 	/*
121 	 * got a match but incorrect number of arguments
122 	 */
123 	Tcl_AppendResult(interp, "wrong # args: should be \"",
124 	    argv[0], " ", argv[1], " ", s->info, "\"", (char *) NULL);
125     } else {
126 	int max;
127 
128 	/*
129 	 * no match: let print out all the options
130 	 */
131 	Tcl_AppendResult(interp, "unknown option \"",
132 	    argv[1], "\".",  (char *) NULL);
133 
134 	if (cmdInfo->numSubCmds == 0) {
135 	    max = 0;
136 	} else {
137 	    if (subCmdInfo[cmdInfo->numSubCmds-1].name == TIX_DEFAULT_SUBCMD) {
138 		max = cmdInfo->numSubCmds-1;
139 	    } else {
140 		max = cmdInfo->numSubCmds;
141 	    }
142 	}
143 
144 	if (max == 0) {
145 	    Tcl_AppendResult(interp,
146 		" This command does not take any options.",
147 		(char *) NULL);
148 	} else if (max == 1) {
149 	    Tcl_AppendResult(interp,
150 		" Must be ", subCmdInfo->name, ".", (char *)NULL);
151 	} else {
152 	    Tcl_AppendResult(interp, " Must be ", (char *) NULL);
153 
154 	    for (i = 0, s = subCmdInfo; i < max; i++, s++) {
155 		if (i == max-1) {
156 		    Tcl_AppendResult(interp,"or ",s->name, ".", (char *) NULL);
157 		} else if (i == max-2) {
158 		    Tcl_AppendResult(interp, s->name, " ", (char *) NULL);
159 		} else {
160 		    Tcl_AppendResult(interp, s->name, ", ", (char *) NULL);
161 		}
162 	    }
163 	}
164     }
165     return TCL_ERROR;
166 }
167 
168 /*----------------------------------------------------------------------
169  * Tix_Exit --
170  *
171  *	Call the "exit" tcl command so that things can be cleaned up
172  *	before calling the unix exit(2);
173  *
174  *----------------------------------------------------------------------
175  */
Tix_Exit(interp,code)176 void Tix_Exit(interp, code)
177     Tcl_Interp* interp;
178     int code;
179 {
180     const char *str;
181     if (code != 0 && interp && ((str = Tcl_GetStringResult(interp)) != NULL)) {
182 	fprintf(stderr, "%s\n", str);
183 	fprintf(stderr, "%s\n",
184 	    Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY));
185     }
186 
187     if (interp) {
188 	Tcl_EvalEx(interp, "exit", -1, TCL_GLOBAL_ONLY);
189     }
190     exit(code);
191 }
192 
193 /*----------------------------------------------------------------------
194  * Tix_CreateCommands --
195  *
196  *
197  *	Creates a list of commands stored in the array "commands"
198  *----------------------------------------------------------------------
199  */
200 
201 static int initialized = 0;
202 
Tix_CreateCommands(interp,commands,clientData,deleteProc)203 void Tix_CreateCommands(interp, commands, clientData, deleteProc)
204     Tcl_Interp *interp;
205     Tix_TclCmd *commands;
206     ClientData clientData;
207     Tcl_CmdDeleteProc *deleteProc;
208 {
209     Tix_TclCmd * cmdPtr;
210 
211     if (!initialized) {
212 	Tcl_CmdInfo cmdInfo;
213 
214 	initialized = 1;
215 	if (!Tcl_GetCommandInfo(interp,"image", (Tcl_CmdInfo *) &cmdInfo)) {
216 	    Tcl_Panic("cannot find the \"image\" command");
217 	} else if (cmdInfo.isNativeObjectProc == 1) {
218 	    initialized = 2; /* we use objects */
219 	}
220     }
221     for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
222 	Tcl_CreateCommand(interp, cmdPtr->name,
223 	     cmdPtr->cmdProc, clientData, deleteProc);
224     }
225 }
226 
227 /*
228  *----------------------------------------------------------------------
229  * Tix_GetAnchorGC --
230  *
231  *	Get the GC for drawing the anchor dotted lines around anchor
232  *	elements.
233  *
234  * Results:
235  *	Returns a GC that can be passed to Tix_DrawAnchorLines for
236  *	drawing an anchor line for the given background color.
237  *
238  * Side effects:
239  *	None.
240  *----------------------------------------------------------------------
241  */
242 
243 GC
Tix_GetAnchorGC(tkwin,bgColor)244 Tix_GetAnchorGC(tkwin, bgColor)
245 	Tk_Window tkwin;
246 	XColor *bgColor;
247 {
248     XGCValues gcValues;
249     XColor valueKey;
250     XColor * anchorColor;
251     int r, g, b;
252     int max;
253 
254     /*
255      * Get the best color to draw the dotted lines on the given background
256      * color.
257      */
258 
259     r = bgColor->red;
260     g = bgColor->green;
261     b = bgColor->blue;
262 
263     r = (65535 - r) & 0xffff;
264     g = (65535 - g) & 0xffff;
265     b = (65535 - b) & 0xffff;
266 
267     max = r;
268     if (max < g) {
269 	max = g;
270     }
271     if (max < b) {
272 	max = b;
273     }
274 
275     max = max / 256;
276     if (max > 96) {
277 	/*
278 	 * scale color up
279 	 */
280 
281 	r = (r * 255) / max;
282 	g = (g * 255) / max;
283 	b = (b * 255) / max;
284     } else {
285 	/*
286 	 * scale color down
287 	 */
288 	int min = r;
289 	if (min > g) {
290 	    min = g;
291 	}
292 	if (min > b) {
293 	    min = b;
294 	}
295 	r = r - min;
296 	g = g - min;
297 	b = b - min;
298     }
299 
300     valueKey.red   = r;
301     valueKey.green = g;
302     valueKey.blue  = b;
303 
304     anchorColor = Tk_GetColorByValue(tkwin, &valueKey);
305 
306     gcValues.foreground		= anchorColor->pixel;
307     gcValues.graphics_exposures = False;
308     gcValues.subwindow_mode	= IncludeInferiors;
309 
310     return Tk_GetGC(tkwin, GCForeground|GCGraphicsExposures|GCSubwindowMode,
311 	    &gcValues);
312 }
313 
314 /*
315  *----------------------------------------------------------------------
316  * Tix_DrawAnchorLines --
317  *
318  *	Draw dotted anchor lines around anchor elements. The exact
319  *	behavior is defined in the platform-specific
320  *	TixpDrawAnchorLines function.
321  *
322  * Results:
323  *	None.
324  *
325  * Side effects:
326  *	None.
327  *----------------------------------------------------------------------
328  */
329 
330 void
Tix_DrawAnchorLines(display,drawable,gc,x,y,w,h)331 Tix_DrawAnchorLines(display, drawable, gc, x, y, w, h)
332     Display *display;
333     Drawable drawable;
334     GC gc;
335     int x;
336     int y;
337     int w;
338     int h;
339 {
340     TixpDrawAnchorLines(display, drawable, gc, x, y, w, h);
341 }
342 
343 /*----------------------------------------------------------------------
344  * Tix_CreateSubWindow --
345  *
346  *	Creates a subwindow for a widget (usually used to draw headers,
347  *	e.g, HList and Grid widgets)
348  *----------------------------------------------------------------------
349  */
350 
351 Tk_Window
Tix_CreateSubWindow(interp,tkwin,subPath)352 Tix_CreateSubWindow(interp, tkwin, subPath)
353     Tcl_Interp * interp;
354     Tk_Window tkwin;
355     CONST84 char * subPath;
356 {
357     Tcl_DString dString;
358     Tk_Window subwin;
359 
360     Tcl_DStringInit(&dString);
361     Tcl_DStringAppend(&dString, Tk_PathName(tkwin),
362 	    (int) strlen(Tk_PathName(tkwin)));
363     Tcl_DStringAppend(&dString, ".tixsw:", 7);
364     Tcl_DStringAppend(&dString, subPath, (int) strlen(subPath));
365 
366     subwin = Tk_CreateWindowFromPath(interp, tkwin, dString.string,
367 	(char *) NULL);
368 
369     Tcl_DStringFree(&dString);
370 
371     return subwin;
372 }
373 static int
ErrorProc(clientData,errorEventPtr)374 ErrorProc(clientData, errorEventPtr)
375     ClientData clientData;
376     XErrorEvent *errorEventPtr;		/* unused */
377 {
378     int * badAllocPtr = (int*) clientData;
379 
380     * badAllocPtr = 1;
381     return 0;				/* return 0 means error has been
382 					 * handled properly */
383 }
384 
385 /*
386  *----------------------------------------------------------------------
387  * Tix_GetRenderBuffer --
388  *
389  *	Returns a drawable for rendering a widget. If there is
390  *	sufficient graphics resource, a pixmap is returned so that
391  *	double-buffering can be done. However, if resource is
392  *	insufficient, then the windowId is returned. In the second
393  *	case happens, the caller of this function has two choices: (1)
394  *	draw to the window directly (which may lead to flickering on
395  *	the screen) or (2) try to allocate smaller pixmaps.
396  *
397  * Results:
398  *	An allocated pixmap of the same depth as the window, or the
399  *	window itself.
400  *
401  * Side effects:
402  *	A pixmap may be allocated. The caller should call
403  *	Tk_FreePixmap() to free the pixmap returned by this function.
404  *
405  *----------------------------------------------------------------------
406  */
407 
408 /*
409  * Uncomment this if you want to use single-buffer mode drawing to
410  * debug paintings.
411  */
412 
413 /* #define PAINT_DEBUG 1 */
414 
415 Drawable
Tix_GetRenderBuffer(display,windowId,width,height,depth)416 Tix_GetRenderBuffer(display, windowId, width, height, depth)
417     Display *display;		/* Display of the windowId */
418     Window windowId;		/* Window to draw into */
419     int width;			/* width of the drawing region */
420     int height;			/* height of the drawing region */
421     int depth;			/* Depth of the window. TODO remove this arg*/
422 {
423 #ifdef PAINT_DEBUG
424     return windowId;
425 #else
426     Tk_ErrorHandler handler;
427     Pixmap pixmap;
428     int badAlloc = 0;
429 
430     handler= Tk_CreateErrorHandler(display, BadAlloc,
431 	-1, -1, (Tk_ErrorProc *) ErrorProc, (ClientData) &badAlloc);
432     pixmap = Tk_GetPixmap(display, windowId, width, height, depth);
433 
434 #if !defined(__WIN32__) && !defined(MAC_TCL) && !defined(MAC_OSX_TK) /* UNIX */
435     /*
436      * This XSync call is necessary because X may delay the delivery of the
437      * error message. This will make our graphics a bit slower, though,
438      * especially over slow lines
439      */
440     XSync(display, 0);
441 #endif
442     /* If ErrorProc() is eevr called, it is called before XSync returns */
443 
444     Tk_DeleteErrorHandler(handler);
445 
446     if (!badAlloc) {
447 	return pixmap;
448     } else {
449 	return windowId;
450     }
451 #endif
452 }
453 
454 /*
455  *----------------------------------------------------------------------
456  *
457  * Tix_GlobalVarEval --
458  *
459  *	Given a variable number of string arguments, concatenate them
460  *	all together and execute the result as a Tcl command in the global
461  *	scope.
462  *
463  * Results:
464  *	A standard Tcl return result.  An error message or other
465  *	result may be left in the interp's result.
466  *
467  * Side effects:
468  *	Depends on what was done by the command.
469  *
470  *----------------------------------------------------------------------
471  */
472 	/* VARARGS2 */ /* ARGSUSED */
473 int
TCL_VARARGS_DEF(Tcl_Interp *,arg1)474 Tix_GlobalVarEval TCL_VARARGS_DEF(Tcl_Interp *,arg1)
475 {
476     va_list argList;
477     Tcl_DString buf;
478     char *string;
479     Tcl_Interp *interp;
480     int result;
481 
482     /*
483      * Copy the strings one after the other into a single larger
484      * string.	Use stack-allocated space for small commands, but if
485      * the command gets too large than call ckalloc to create the
486      * space.
487      */
488 
489     interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
490     Tcl_DStringInit(&buf);
491     while (1) {
492 	string = va_arg(argList, char *);
493 	if (string == NULL) {
494 	    break;
495 	}
496 	Tcl_DStringAppend(&buf, string, -1);
497     }
498     va_end(argList);
499 
500     result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf),
501 	    Tcl_DStringLength(&buf), TCL_GLOBAL_ONLY);
502     Tcl_DStringFree(&buf);
503     return result;
504 }
505 
506 /*----------------------------------------------------------------------
507  * TixGetHashTable --
508  *
509  *	This functions makes it possible to keep one hash table per
510  *	interpreter. This way, Tix classes can be used in multiple
511  *	interpreters.
512  *
513  *----------------------------------------------------------------------
514  */
515 
516 static void		DeleteHashTableProc _ANSI_ARGS_((ClientData clientData,
517 			    Tcl_Interp * interp));
518 static void
DeleteHashTableProc(clientData,interp)519 DeleteHashTableProc(clientData, interp)
520     ClientData clientData;
521     Tcl_Interp * interp;
522 {
523     Tcl_HashTable * htPtr = (Tcl_HashTable *)clientData;
524     Tcl_HashSearch hashSearch;
525     Tcl_HashEntry * hashPtr;
526 
527     for (hashPtr = Tcl_FirstHashEntry(htPtr, &hashSearch);
528 	    hashPtr;
529 	    hashPtr = Tcl_NextHashEntry(&hashSearch)) {
530 	Tcl_DeleteHashEntry(hashPtr);
531     }
532 
533     Tcl_DeleteHashTable(htPtr);
534     ckfree((char*)htPtr);
535 }
536 
537 /*
538  *----------------------------------------------------------------------
539  * TixGetHashTable() --
540  *
541  *	Returns a named hashtable to be used for the given
542  *	interpreter. Creates the hashtable if it doesn't exist yet. It
543  *	uses Tcl_GetAssocData to make sure that the hashtable is not
544  *	shared by different interpreters.
545  *
546  * Results:
547  *	Pointer to the hashtable.
548  *
549  * Side effects:
550  *	The hashtable is created if it doesn't exist yet.
551  *
552  *----------------------------------------------------------------------
553  */
554 
555 Tcl_HashTable *
TixGetHashTable(interp,name,deleteProc,keyType)556 TixGetHashTable(interp, name, deleteProc, keyType)
557     Tcl_Interp * interp;
558     char * name;
559     Tcl_InterpDeleteProc *deleteProc;
560     int keyType;
561 {
562     Tcl_HashTable * htPtr;
563 
564     htPtr = (Tcl_HashTable*)Tcl_GetAssocData(interp, name, NULL);
565 
566     if (htPtr == NULL) {
567 	htPtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
568 	Tcl_InitHashTable(htPtr, keyType);
569 	Tcl_SetAssocData(interp, name, NULL, (ClientData)htPtr);
570 
571 	if (deleteProc) {
572 	    Tcl_CallWhenDeleted(interp, deleteProc, (ClientData)htPtr);
573 	} else {
574 	    Tcl_CallWhenDeleted(interp, DeleteHashTableProc,
575 		    (ClientData)htPtr);
576 	}
577     }
578 
579     return htPtr;
580 }
581 
582 /*----------------------------------------------------------------------
583  *
584  *		 The Tix Customed Config Options
585  *
586  *----------------------------------------------------------------------
587  */
588 
589 /*----------------------------------------------------------------------
590  *  ReliefParseProc --
591  *
592  *	Parse the text string and store the Tix_Relief information
593  *	inside the widget record.
594  *----------------------------------------------------------------------
595  */
596 static int
ReliefParseProc(clientData,interp,tkwin,value,widRec,offset)597 ReliefParseProc(clientData, interp, tkwin, value, widRec,offset)
598     ClientData clientData;
599     Tcl_Interp *interp;
600     Tk_Window tkwin;
601     CONST84 char *value;
602     char *widRec;	/* Must point to a valid Tix_DItem struct */
603     int offset;
604 {
605     Tix_Relief * ptr = (Tix_Relief *)(widRec + offset);
606     Tix_Relief	 newVal;
607 
608     if (value != NULL) {
609 	size_t len = strlen(value);
610 
611 	if (strncmp(value, "raised", len) == 0) {
612 	    newVal = TIX_RELIEF_RAISED;
613 	} else if (strncmp(value, "flat", len) == 0) {
614 	    newVal = TIX_RELIEF_FLAT;
615 	} else if (strncmp(value, "sunken", len) == 0) {
616 	    newVal = TIX_RELIEF_SUNKEN;
617 	} else if (strncmp(value, "groove", len) == 0) {
618 	    newVal = TIX_RELIEF_GROOVE;
619 	} else if (strncmp(value, "ridge", len) == 0) {
620 	    newVal = TIX_RELIEF_RIDGE;
621 	} else if (strncmp(value, "solid", len) == 0) {
622 	    newVal = TIX_RELIEF_SOLID;
623 	} else {
624 	    goto error;
625 	}
626     } else {
627 	value = "";
628 	goto error;
629     }
630 
631     *ptr = newVal;
632     return TCL_OK;
633 
634   error:
635     Tcl_AppendResult(interp, "bad relief type \"", value,
636 	"\":  must be flat, groove, raised, ridge, solid or sunken", NULL);
637     return TCL_ERROR;
638 }
639 
640 static char *
ReliefPrintProc(clientData,tkwin,widRec,offset,freeProcPtr)641 ReliefPrintProc(clientData, tkwin, widRec,offset, freeProcPtr)
642     ClientData clientData;
643     Tk_Window tkwin;
644     char *widRec;
645     int offset;
646     Tix_FreeProc **freeProcPtr;
647 {
648     Tix_Relief *ptr = (Tix_Relief*)(widRec+offset);
649 
650     switch (*ptr) {
651       case TIX_RELIEF_RAISED:
652 	return "raised";
653       case TIX_RELIEF_FLAT:
654 	return "flat";
655       case TIX_RELIEF_SUNKEN:
656 	return "sunken";
657       case TIX_RELIEF_GROOVE:
658 	return "groove";
659       case TIX_RELIEF_RIDGE:
660 	return "ridge";
661       case TIX_RELIEF_SOLID:
662 	return "solid";
663       default:
664 	return "unknown";
665     }
666 }
667 /*
668  * The global data structures to use in widget configSpecs arrays
669  *
670  * These are declared in <tix.h>
671  */
672 
673 Tk_CustomOption tixConfigRelief = {
674     ReliefParseProc, ReliefPrintProc, 0,
675 };
676 
677 /* Tix_SetRcFileName --
678  *
679  *	Sets a user-specific startup file in a way that's compatible with
680  *	different versions of Tclsh
681  */
Tix_SetRcFileName(interp,rcFileName)682 void Tix_SetRcFileName(interp, rcFileName)
683     Tcl_Interp * interp;
684     CONST84 char * rcFileName;
685 {
686     /*
687      * Starting from TCL 7.5, the symbol tcl_rcFileName is no longer
688      * exported by libtcl.a. Instead, this variable must be set using
689      * a TCL global variable
690      */
691     Tcl_SetVar(interp, "tcl_rcFileName", rcFileName, TCL_GLOBAL_ONLY);
692 }
693 
694 /*
695  * The TkComputeTextGeometry function is no longer supported in Tk 8.0+
696  */
697 
698 /*
699  *----------------------------------------------------------------------
700  *
701  * TixComputeTextGeometry --
702  *
703  *	This procedure computes the amount of screen space needed to
704  *	display a multi-line string of text.
705  *
706  * Results:
707  *	There is no return value.  The dimensions of the screen area
708  *	needed to display the text are returned in *widthPtr, and *heightPtr.
709  *
710  * Side effects:
711  *	None.
712  *
713  *----------------------------------------------------------------------
714  */
715 
716 void
TixComputeTextGeometry(font,string,numChars,wrapLength,widthPtr,heightPtr)717 TixComputeTextGeometry(font, string, numChars, wrapLength,
718 	widthPtr, heightPtr)
719     TixFont font;		/* Font that will be used to display text. */
720     CONST84 char *string;	/* String whose dimensions are to be
721 				 * computed. */
722     int numChars;		/* Number of characters to consider from
723 				 * string. -1 means the entire size of
724 				 * the text string */
725     int wrapLength;		/* Longest permissible line length, in
726 				 * pixels.  <= 0 means no automatic wrapping:
727 				 * just let lines get as long as needed. */
728     int *widthPtr;		/* Store width of string here. */
729     int *heightPtr;		/* Store height of string here. */
730 {
731     Tk_TextLayout textLayout;
732 
733     /*
734      * The justification itself doesn't affect the geometry (size) of
735      * the text string. We pass TK_JUSTIFY_LEFT.
736      */
737 
738     textLayout = Tk_ComputeTextLayout(font,
739 	string, numChars, wrapLength, TK_JUSTIFY_LEFT, 0,
740 	widthPtr, heightPtr);
741     Tk_FreeTextLayout(textLayout);
742 }
743 
744 /*
745  *----------------------------------------------------------------------
746  *
747  * TixDisplayText --
748  *
749  *	Display a text string on one or more lines.
750  *
751  * Results:
752  *	None.
753  *
754  * Side effects:
755  *	The text given by "string" gets displayed at the given location
756  *	in the given drawable with the given font etc.
757  *
758  *----------------------------------------------------------------------
759  */
760 
761 void
TixDisplayText(display,drawable,font,string,numChars,x,y,length,justify,underline,gc)762 TixDisplayText(display, drawable, font, string, numChars, x, y,
763 	length, justify, underline, gc)
764     Display *display;		/* X display to use for drawing text. */
765     Drawable drawable;		/* Window or pixmap in which to draw the
766 				 * text. */
767     TixFont font;		/* Font that determines geometry of text
768 				 * (should be same as font in gc). */
769     CONST84 char *string;	/* String to display;  may contain embedded
770 				 * newlines. */
771     int numChars;		/* Number of characters to use from string. */
772     int x, y;			/* Pixel coordinates within drawable of
773 				 * upper left corner of display area. */
774     int length;			/* Line length in pixels;  used to compute
775 				 * word wrap points and also for
776 				 * justification. Must be > 0. */
777     Tk_Justify justify;		/* How to justify lines. */
778     int underline;		/* Index of character to underline, or < 0
779 				 * for no underlining. */
780     GC gc;			/* Graphics context to use for drawing text. */
781 {
782     Tk_TextLayout textLayout;
783     int dummyx, dummyy;
784 
785     textLayout = Tk_ComputeTextLayout(font,
786 	string, numChars, length, justify, 0,
787 	&dummyx, &dummyy);
788 
789     Tk_DrawTextLayout(display, drawable, gc, textLayout,
790 	    x, y, 0, -1);
791     Tk_UnderlineTextLayout(display, drawable, gc,
792 	    textLayout, x, y, underline);
793 
794     Tk_FreeTextLayout(textLayout);
795 }
796 
797 /*
798  *----------------------------------------------------------------------
799  * Tix_ZAlloc --
800  *
801  *	Allocate the memory block with ckalloc and zeros it.
802  *
803  * Results:
804  *	Same as ckalloc() except the new memory block is filled with
805  *	zero. Returns NULL if memory allocation fails.
806  *
807  * Side effects:
808  *	None.
809  *----------------------------------------------------------------------
810  */
811 
Tix_ZAlloc(nbytes)812 char * Tix_ZAlloc(nbytes)
813     unsigned int nbytes;	/* size of memory block to alloc, in
814 				 * number of bytes.*/
815 {
816     char * ptr = (char*)ckalloc(nbytes);
817     if (ptr) {
818 	memset(ptr, 0, nbytes);
819     }
820     return ptr;
821 }
822