1 
2 /*	$Id: tixUtils.c,v 1.3 2000/10/12 04:06:58 idiscovery Exp $	*/
3 
4 /*
5  * tixUtils.c --
6  *
7  *	This file contains some utility functions for Tix, such as the
8  *	subcommand handling functions and option handling functions.
9  *
10  * Copyright (c) 1996, Expert Interface Technologies
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  */
16 #include "tixPort.h"
17 #include "tixInt.h"
18 
19 /*
20  * Forward declarations for procedures defined later in this file:
21  */
22 
23 static void		Prompt _ANSI_ARGS_((Tcl_Interp *interp, int partial));
24 static void		StdinProc _ANSI_ARGS_((ClientData clientData,
25 			    int mask));
26 static int		 ReliefParseProc _ANSI_ARGS_((ClientData clientData,
27 			    Tcl_Interp *interp,
28 			    Tk_Window tkwin,
29 			    Tcl_Obj * avalue,
30 			    char *widRec,
31 			    int offset));
32 static Tcl_Obj *		 ReliefPrintProc _ANSI_ARGS_((ClientData clientData,
33 			    Tk_Window tkwin,
34 			    char *widRec,
35 			    int offset,
36 			    Tcl_FreeProc **freeProcPtr));
37 /*
38  * Global vars used in this file
39  */
40 static Tcl_DString command;	/* Used to assemble lines of terminal input
41 				 * into Tcl commands. */
42 
43 
44 #define WRONG_ARGC 1
45 #define NO_MATCH   2
46 
47 
48 #ifndef _LANG
49 /*----------------------------------------------------------------------
50  * TixSaveInterpState --
51  *
52  *	Save the current application-visible state of the interpreter.
53  *	This can later be restored by the TixSaveInterpState() function.
54  *	These two functions are useful if you want to evaluate a Tcl
55  *	command, which may cause errors, inside a command function.
56  *
57  *	Each TixSaveInterpState() call much be matched by one
58  *	TixRestoreInterpState() call with the same statePtr. statePtr
59  *	should be allocated by the calling function, usually
60  *	as a variable on the stack.
61  *----------------------------------------------------------------------
62  */
63 
64 void
TixSaveInterpState(interp,statePtr)65 TixSaveInterpState(interp, statePtr)
66     Tcl_Interp * interp;
67     TixInterpState * statePtr;
68 {
69     char * p;
70     if (interp->result) {
71 	statePtr->result = tixStrDup(interp->result);
72     } else {
73 	statePtr->result = NULL;
74     }
75 
76     p = Tcl_GetVar2(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY);
77     if (p) {
78 	statePtr->errorInfo = tixStrDup(p);
79     } else {
80 	statePtr->errorInfo = NULL;
81     }
82 
83     p = Tcl_GetVar2(interp, "errorCode", NULL, TCL_GLOBAL_ONLY);
84     if (p) {
85 	statePtr->errorCode = tixStrDup(p);
86     } else {
87 	statePtr->errorCode = NULL;
88     }
89 }
90 
91 /*----------------------------------------------------------------------
92  * TixRestoreInterpState --
93  *
94  *	See TixSaveInterpState above.
95  *----------------------------------------------------------------------
96  */
97 
98 void
TixRestoreInterpState(interp,statePtr)99 TixRestoreInterpState(interp, statePtr)
100     Tcl_Interp * interp;
101     TixInterpState * statePtr;
102 {
103     if (statePtr->result) {
104 	Tcl_SetResult(interp, statePtr->result, TCL_DYNAMIC);
105     }
106     if (statePtr->errorInfo) {
107 	Tcl_SetVar2(interp, "errorInfo", NULL, statePtr->errorInfo,
108 		TCL_GLOBAL_ONLY);
109 	ckfree((char*)statePtr->errorInfo);
110     } else {
111 	Tcl_UnsetVar2(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY);
112     }
113     if (statePtr->errorCode) {
114 	Tcl_SetVar2(interp, "errorCode", NULL, statePtr->errorCode,
115 		TCL_GLOBAL_ONLY);
116 	ckfree((char*)statePtr->errorCode);
117     } else {
118 	Tcl_UnsetVar2(interp, "errorCode", NULL, TCL_GLOBAL_ONLY);
119     }
120 }
121 #endif
122 
123 /*----------------------------------------------------------------------
124  * Tix_HandleSubCmds --
125  *
126  *	This function makes it easier to write major-minor style TCL
127  *	commands.  It matches the minor command (sub-command) names
128  *	with names defined in the cmdInfo structure and call the
129  *	appropriate sub-command functions for you. This function will
130  *	automatically generate error messages when the user calls an
131  *	invalid sub-command or calls a sub-command with incorrect
132  *	number of arguments.
133  *
134  *----------------------------------------------------------------------
135  */
136 
Tix_HandleSubCmds(cmdInfo,subCmdInfo,clientData,interp,argc,argv)137 int Tix_HandleSubCmds(cmdInfo, subCmdInfo, clientData, interp, argc, argv)
138     Tix_CmdInfo * cmdInfo;
139     Tix_SubCmdInfo * subCmdInfo;
140     ClientData clientData;	/* Main window associated with
141 				 * interpreter. */
142     Tcl_Interp *interp;		/* Current interpreter. */
143     int argc;			/* Number of arguments. */
144     char **argv;		/* Argument strings. */
145 {
146 
147     int i;
148     int len;
149     int error = NO_MATCH;
150     Tix_SubCmdInfo * s;
151 
152     /*
153      * First check if the number of arguments to the major command
154      * is correct
155      */
156     argc -= 1;
157     if (argc < cmdInfo->minargc ||
158 	(cmdInfo->maxargc != TIX_VAR_ARGS && argc > cmdInfo->maxargc)) {
159 
160 	Tcl_AppendResult(interp, "wrong # args: should be \"",
161 	    argv[0], " ", cmdInfo->info, "\".", (char *) NULL);
162 
163 	return TCL_ERROR;
164     }
165 
166     /*
167      * Now try to match the subcommands with argv[1]
168      */
169     argc -= 1;
170     len = strlen(argv[1]);
171 
172     for (i = 0, s = subCmdInfo; i < cmdInfo->numSubCmds; i++, s++) {
173 	if (s->name == TIX_DEFAULT_SUBCMD) {
174 	    if (s->checkArgvProc) {
175 	      if (!((*s->checkArgvProc)(clientData, interp, argc+1, argv+1))) {
176 		    /* Some improper argv in the arguments of the default
177 		     * subcommand
178 		     */
179 		    break;
180 		}
181 	    }
182 	    return (*s->proc)(clientData, interp, argc+1, argv+1);
183 	}
184 
185 	if (s->namelen == TIX_DEFAULT_LEN) {
186 	    s->namelen = strlen(s->name);
187 	}
188 	if (s->name[0] == argv[1][0] && strncmp(argv[1],s->name,len)==0) {
189 	    if (argc < s->minargc) {
190 		error = WRONG_ARGC;
191 		break;
192 	    }
193 
194 	    if (s->maxargc != TIX_VAR_ARGS &&
195 		argc > s->maxargc) {
196 		error = WRONG_ARGC;
197 		break;
198 	    }
199 
200 	    /*
201 	     * Here we have a matched argc and command name --> go for it!
202 	     */
203 	    return (*s->proc)(clientData, interp, argc, argv+2);
204 	}
205     }
206 
207     if (error == WRONG_ARGC) {
208 	/*
209 	 * got a match but incorrect number of arguments
210 	 */
211 	Tcl_AppendResult(interp, "wrong # args: should be \"",
212 	    argv[0], " ", argv[1], " ", s->info, "\"", (char *) NULL);
213     } else {
214 	int max;
215 
216 	/*
217 	 * no match: let print out all the options
218 	 */
219 	Tcl_AppendResult(interp, "unknown option \"",
220 	    argv[1], "\".",  (char *) NULL);
221 
222 	if (cmdInfo->numSubCmds == 0) {
223 	    max = 0;
224 	} else {
225 	    if (subCmdInfo[cmdInfo->numSubCmds-1].name == TIX_DEFAULT_SUBCMD) {
226 		max = cmdInfo->numSubCmds-1;
227 	    } else {
228 		max = cmdInfo->numSubCmds;
229 	    }
230 	}
231 
232 	if (max == 0) {
233 	    Tcl_AppendResult(interp,
234 		" This command does not take any options.",
235 		(char *) NULL);
236 	} else if (max == 1) {
237 	    Tcl_AppendResult(interp,
238 		" Must be ", subCmdInfo->name, ".", (char *)NULL);
239 	} else {
240 	    Tcl_AppendResult(interp, " Must be ", (char *) NULL);
241 
242 	    for (i = 0, s = subCmdInfo; i < max; i++, s++) {
243 		if (i == max-1) {
244 		    Tcl_AppendResult(interp,"or ",s->name, ".", (char *) NULL);
245 		} else if (i == max-2) {
246 		    Tcl_AppendResult(interp, s->name, " ", (char *) NULL);
247 		} else {
248 		    Tcl_AppendResult(interp, s->name, ", ", (char *) NULL);
249 		}
250 	    }
251 	}
252     }
253     return TCL_ERROR;
254 }
255 
256 #ifndef _LANG
257 
258 /*----------------------------------------------------------------------
259  * Tix_Exit --
260  *
261  *	Call the "exit" tcl command so that things can be cleaned up
262  *	before calling the unix exit(2);
263  *
264  *----------------------------------------------------------------------
265  */
Tix_Exit(interp,code)266 void Tix_Exit(interp, code)
267     Tcl_Interp* interp;
268     int code;
269 {
270     if (code != 0 && interp && interp->result != 0) {
271 	fprintf(stderr, "%s\n", interp->result);
272 	fprintf(stderr, "%s\n",
273 	    Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY));
274     }
275 
276     if (interp) {
277 	Tcl_GlobalEval(interp, tixStrDup("exit"));
278     }
279     exit(code);
280 }
281 
282 /*
283  *----------------------------------------------------------------------
284  *
285  * Tix_LoadTclLibrary --
286  *
287  *	Loads in a TCL library for an application according to
288  *	the library settings.
289  *
290  * Results:
291  *	TCL_OK or TCL_ERROR
292  *
293  * envName	the environment variable that indicates the library
294  * tclName	the TCL variable that points to the TCL library.
295  * initFile	the file to load in during initialization.
296  * defDir	the default directory to search if the user hasn't set
297  *		the environment variable.
298  * appName	the name of the application.
299  *----------------------------------------------------------------------
300  */
301 
302 /* Some compilers can't handle multi-line character strings very well ...
303  * So I just using this big lump of mess here.
304  */
305 
306 static char _format[] = "lappend auto_path $%s \nif [file exists $%s/%s] {\nsource $%s/%s\n} else {\nset msg \"\ncan't find $%s/%s;\\nperhaps you \"\nappend msg \"need to install %s\\nor set your %s \"\nappend msg \"environment variable?\"\nerror $msg\n}";
307 
308 int
Tix_LoadTclLibrary(interp,envName,tclName,initFile,defDir,appName)309 Tix_LoadTclLibrary(interp, envName, tclName, initFile, defDir, appName)
310     Tcl_Interp *interp;
311     char *envName;
312     char *tclName;
313     char *initFile;
314     char *defDir;
315     char *appName;
316 {
317     char * libDir, *initCmd;
318     size_t size;
319     int code;
320     char *format;
321     format = _format;
322 
323     libDir = getenv(envName);
324     if (libDir == NULL) {
325 	libDir = defDir;
326     }
327 
328     /*
329      * This size should be big enough.
330      */
331 
332     size = strlen(format) + strlen(tclName)*4 + strlen(initFile)*3
333 	+ strlen(appName) + strlen(envName) + 100;
334     initCmd = ckalloc(sizeof(char) * size);
335 
336     Tcl_SetVar(interp, tclName, libDir, TCL_GLOBAL_ONLY);
337 
338     sprintf(initCmd, format,
339 	tclName,
340 	tclName, initFile,
341 	tclName, initFile,
342 	tclName, initFile,
343 	appName, envName
344     );
345 
346     code =  Tcl_GlobalEval(interp, initCmd);
347     ckfree(initCmd);
348     return code;
349 }
350 
351 /*----------------------------------------------------------------------
352  * Tix_CreateCommands --
353  *
354  *
355  *	Creates a list of commands stored in the array "commands"
356  *----------------------------------------------------------------------
357  */
358 
359 static int initialized = 0;
360 
Tix_CreateCommands(interp,commands,clientData,deleteProc)361 void Tix_CreateCommands(interp, commands, clientData, deleteProc)
362     Tcl_Interp *interp;
363     Tix_TclCmd *commands;
364     ClientData clientData;
365     Tcl_CmdDeleteProc *deleteProc;
366 {
367     Tix_TclCmd * cmdPtr;
368 
369     if (!initialized) {
370 	char *version = Tcl_PkgRequire(interp, "Tcl", NULL, 0);
371 	initialized = 1;
372 	if (version[0] == '8') {
373 	    struct CmdInfo {
374 		int isNativeObjectProc;
375 		Tcl_ObjCmdProc *objProc;
376 		ClientData objClientData;
377 		VOID *dummy[10]; /* worst case space that could be written
378 				  * by Tcl_GetCommandInfo() */
379 	    } cmdInfo;
380 	    if (!Tcl_GetCommandInfo(interp,"image", (Tcl_CmdInfo *) &cmdInfo)) {
381 		panic("cannot find the \"image\" command");
382 	    } else if (cmdInfo.isNativeObjectProc == 1) {
383 		initialized = 2; /* we use objects */
384 	    }
385 	}
386     }
387     for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
388 	Tcl_CreateCommand(interp, cmdPtr->name,
389 	     cmdPtr->cmdProc, clientData, deleteProc);
390     }
391 }
392 
393 #endif
394 
395 
396 /*----------------------------------------------------------------------
397  * Tix_DrawAnchorLines --
398  *
399  * 	Draw dotted anchor lines around anchor elements
400  *----------------------------------------------------------------------
401  */
402 
Tix_DrawAnchorLines(display,drawable,gc,x,y,w,h)403 void Tix_DrawAnchorLines(display, drawable, gc, x, y, w, h)
404     Display *display;
405     Drawable drawable;
406     GC gc;
407     int x;
408     int y;
409     int w;
410     int h;
411 {
412     TixpDrawAnchorLines(display, drawable, gc, x, y, w, h);
413 }
414 
415 /*----------------------------------------------------------------------
416  * Tix_CreateSubWindow --
417  *
418  *	Creates a subwindow for a widget (usually used to draw headers,
419  *	e.g, HList and Grid widgets)
420  *----------------------------------------------------------------------
421  */
422 
423 Tk_Window
Tix_CreateSubWindow(interp,tkwin,subPath)424 Tix_CreateSubWindow(interp, tkwin, subPath)
425     Tcl_Interp * interp;
426     Tk_Window tkwin;
427     char * subPath;
428 {
429     Tcl_DString dString;
430     Tk_Window subwin;
431 
432     Tcl_DStringInit(&dString);
433     Tcl_DStringAppend(&dString, Tk_PathName(tkwin),
434 	strlen(Tk_PathName(tkwin)));
435     Tcl_DStringAppend(&dString, ".tixsw:", 7);
436     Tcl_DStringAppend(&dString, subPath, strlen(subPath));
437 
438     subwin = Tk_CreateWindowFromPath(interp, tkwin, Tcl_DStringValue(&dString),
439 	(char *) NULL);
440 
441     Tcl_DStringFree(&dString);
442 
443     return subwin;
444 }
445 
446 /*----------------------------------------------------------------------
447  * Tix_GetRenderBuffer --
448  *
449  *	Returns a drawable for rendering a widget. If there is sufficient
450  *	resource, a pixmap is returned so that double-buffering can
451  *	be done. However, if resource is insufficient, then the
452  *	windowId is returned. In the second case happens, the caller
453  *	of this function has two choices: (1) draw to the window directly
454  *	(which may lead to flashing on the screen) or (2) try to allocate
455  *	smaller pixmaps.
456  *----------------------------------------------------------------------
457  */
458 
459 static int
ErrorProc(clientData,errorEventPtr)460 ErrorProc(clientData, errorEventPtr)
461     ClientData clientData;
462     XErrorEvent *errorEventPtr;		/* unused */
463 {
464     int * badAllocPtr = (int*) clientData;
465 
466     * badAllocPtr = 1;
467     return 0;				/* return 0 means error has been
468 					 * handled properly */
469 }
470 
Tix_GetRenderBuffer(display,windowId,width,height,depth)471 Drawable Tix_GetRenderBuffer(display, windowId, width, height, depth)
472     Display *display;
473     Window windowId;
474     int width;
475     int height;
476     int depth;
477 {
478     Tk_ErrorHandler handler;
479     Pixmap pixmap;
480     int badAlloc = 0;
481 
482     handler= Tk_CreateErrorHandler(display, BadAlloc,
483 	-1, -1, (Tk_ErrorProc *) ErrorProc, (ClientData) &badAlloc);
484     pixmap = Tk_GetPixmap(display, windowId, width, height, depth);
485 
486 #ifndef _WINDOWS
487     /*
488      * This XSync call is necessary because X may delay the delivery of the
489      * error message. This will make our graphics a bit slower, though,
490      * especially over slow lines
491      */
492     XSync(display, 0);
493 #endif
494     /* If ErrorProc() is eevr called, it is called before XSync returns */
495 
496     Tk_DeleteErrorHandler(handler);
497 
498     if (!badAlloc) {
499 	return pixmap;
500     } else {
501 	return windowId;
502     }
503 }
504 
505 #ifndef _LANG
506 /*
507  *----------------------------------------------------------------------
508  *
509  * Tix_GlobalVarEval --
510  *
511  *	Given a variable number of string arguments, concatenate them
512  *	all together and execute the result as a Tcl command in the global
513  *	scope.
514  *
515  * Results:
516  *	A standard Tcl return result.  An error message or other
517  *	result may be left in interp->result.
518  *
519  * Side effects:
520  *	Depends on what was done by the command.
521  *
522  *----------------------------------------------------------------------
523  */
524 	/* VARARGS2 */ /* ARGSUSED */
525 int
526 #ifdef TCL_VARARGS_DEF
TCL_VARARGS_DEF(Tcl_Interp *,arg1)527 Tix_GlobalVarEval TCL_VARARGS_DEF(Tcl_Interp *,arg1)
528 #else
529 #ifndef lint
530 Tix_GlobalVarEval(va_alist)
531 #else
532 Tix_GlobalVarEval(iPtr, p, va_alist)
533     Tcl_Interp *iPtr;		/* Interpreter in which to execute command. */
534     char *p;			/* One or more strings to concatenate,
535 				 * terminated with a NULL string. */
536 #endif
537     va_dcl
538 #endif
539 {
540     va_list argList;
541     Tcl_DString buf;
542     char *string;
543     Tcl_Interp *interp;
544     int result;
545 
546 #ifdef TCL_VARARGS_DEF
547     /*
548      * Copy the strings one after the other into a single larger
549      * string.  Use stack-allocated space for small commands, but if
550      * the command gets too large than call ckalloc to create the
551      * space.
552      */
553 
554     interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
555     Tcl_DStringInit(&buf);
556     while (1) {
557 	string = va_arg(argList, char *);
558 	if (string == NULL) {
559 	    break;
560 	}
561 	Tcl_DStringAppend(&buf, string, -1);
562     }
563     va_end(argList);
564 
565     result = Tcl_GlobalEval(interp, Tcl_DStringValue(&buf));
566     Tcl_DStringFree(&buf);
567     return result;
568 #else
569     va_start(argList);
570     interp = va_arg(argList, Tcl_Interp *);
571     Tcl_DStringInit(&buf);
572     while (1) {
573 	string = va_arg(argList, char *);
574 	if (string == NULL) {
575 	    break;
576 	}
577 	Tcl_DStringAppend(&buf, string, -1);
578     }
579     va_end(argList);
580 
581     result = Tcl_GlobalEval(interp, Tcl_DStringValue(&buf));
582     Tcl_DStringFree(&buf);
583     return result;
584 #endif
585 }
586 #endif
587 
588 /*----------------------------------------------------------------------
589  * TixGetHashTable --
590  *
591  *	This functions makes it possible to keep one hash table per
592  *	interpreter. This way, Tix classes can be used in multiple
593  *	interpreters.
594  *
595  *----------------------------------------------------------------------
596  */
597 
598 #ifdef TK_4_1_OR_LATER
599 
600 static void		DeleteHashTableProc _ANSI_ARGS_((ClientData clientData,
601 			    Tcl_Interp * interp));
602 static void
DeleteHashTableProc(clientData,interp)603 DeleteHashTableProc(clientData, interp)
604     ClientData clientData;
605     Tcl_Interp * interp;
606 {
607     Tcl_HashTable * htPtr = (Tcl_HashTable *)clientData;
608     Tcl_HashSearch hashSearch;
609     Tcl_HashEntry * hashPtr;
610 
611     for (hashPtr = Tcl_FirstHashEntry(htPtr, &hashSearch);
612 	    hashPtr;
613 	    hashPtr = Tcl_NextHashEntry(&hashSearch)) {
614 	Tcl_DeleteHashEntry(hashPtr);
615     }
616 
617     Tcl_DeleteHashTable(htPtr);
618     ckfree((char*)htPtr);
619 }
620 
621 Tcl_HashTable *
TixGetHashTable(interp,name,deleteProc)622 TixGetHashTable(interp, name, deleteProc)
623     Tcl_Interp * interp;
624     char * name;
625     Tcl_InterpDeleteProc *deleteProc;
626 {
627     Tcl_HashTable * htPtr;
628 
629     htPtr = (Tcl_HashTable*)Tcl_GetAssocData(interp, name, NULL);
630     if (htPtr == NULL) {
631 	htPtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
632 	Tcl_InitHashTable(htPtr, TCL_STRING_KEYS);
633 	Tcl_SetAssocData(interp, name, NULL, (ClientData)htPtr);
634 	if (deleteProc) {
635 	    Tcl_CallWhenDeleted(interp, deleteProc, (ClientData)htPtr);
636 	} else {
637 	    Tcl_CallWhenDeleted(interp, DeleteHashTableProc,
638 		    (ClientData)htPtr);
639 	}
640     }
641 
642     return htPtr;
643 }
644 
645 #else
646 
647 Tcl_HashTable *
TixGetHashTable(interp,name)648 TixGetHashTable(interp, name)
649     Tcl_Interp * interp;	/* Current interpreter. */
650     char * name;		/* Textual name of the hash table. */
651 {
652     static int inited = 0;
653     static Tcl_HashTable classTable;
654     static Tcl_HashTable methodTable;
655     static Tcl_HashTable specTable;
656 
657     if (!inited) {
658 	Tcl_InitHashTable(&classTable, TCL_STRING_KEYS);
659 	Tcl_InitHashTable(&methodTable, TCL_STRING_KEYS);
660 	Tcl_InitHashTable(&specTable, TCL_STRING_KEYS);
661 	inited = 1;
662     }
663 
664     if (strcmp(name, "tixClassTab") == 0) {
665 	return &classTable;
666     } else if (strcmp(name, "tixSpecTab") == 0) {
667 	return &specTable;
668     } else if (strcmp(name, "tixMethodTab") == 0) {
669 	return &methodTable;
670     } else {
671 	panic("Unknown hash table %s", name);
672     }
673 }
674 #endif
675 
676 /*----------------------------------------------------------------------
677  *
678  *		 The Tix Customed Config Options
679  *
680  *----------------------------------------------------------------------
681  */
682 
683 /*----------------------------------------------------------------------
684  *  ReliefParseProc --
685  *
686  *	Parse the text string and store the Tix_Relief information
687  *	inside the widget record.
688  *----------------------------------------------------------------------
689  */
ReliefParseProc(clientData,interp,tkwin,avalue,widRec,offset)690 static int ReliefParseProc(clientData, interp, tkwin, avalue, widRec,offset)
691     ClientData clientData;
692     Tcl_Interp *interp;
693     Tk_Window tkwin;
694     Tcl_Obj * avalue;
695     char *widRec;		/* Must point to a valid Tix_DItem struct */
696     int offset;
697 {
698     Tix_Relief * ptr = (Tix_Relief *)(widRec + offset);
699     Tix_Relief   newVal;
700     char *value = Tcl_GetString(avalue);
701 
702     if (value != NULL) {
703 	size_t len = strlen(value);
704 
705 	if (strncmp(value, "raised", len) == 0) {
706 	    newVal = TIX_RELIEF_RAISED;
707 	} else if (strncmp(value, "flat", len) == 0) {
708 	    newVal = TIX_RELIEF_FLAT;
709 	} else if (strncmp(value, "sunken", len) == 0) {
710 	    newVal = TIX_RELIEF_SUNKEN;
711 	} else if (strncmp(value, "groove", len) == 0) {
712 	    newVal = TIX_RELIEF_GROOVE;
713 	} else if (strncmp(value, "ridge", len) == 0) {
714 	    newVal = TIX_RELIEF_RIDGE;
715 	} else if (strncmp(value, "solid", len) == 0) {
716 	    newVal = TIX_RELIEF_SOLID;
717 	} else {
718 	    goto error;
719 	}
720     } else {
721 	value = "";
722 	goto error;
723     }
724 
725     *ptr = newVal;
726     return TCL_OK;
727 
728   error:
729     Tcl_AppendResult(interp, "bad relief type \"", value,
730 	"\":  must be flat, groove, raised, ridge, solid or sunken", NULL);
731     return TCL_ERROR;
732 }
733 
734 static Tcl_Obj *
ReliefPrintProc(clientData,tkwin,widRec,offset,freeProcPtr)735 ReliefPrintProc(clientData, tkwin, widRec,offset, freeProcPtr)
736     ClientData clientData;
737     Tk_Window tkwin;
738     char *widRec;
739     int offset;
740     Tix_FreeProc **freeProcPtr;
741 {
742     Tix_Relief *ptr = (Tix_Relief*)(widRec+offset);
743     Tcl_Obj * result = NULL;
744 
745     switch (*ptr) {
746       case TIX_RELIEF_RAISED:
747 	LangSetString(&result,"raised");
748         break;
749       case TIX_RELIEF_FLAT:
750 	LangSetString(&result,"flat");
751         break;
752       case TIX_RELIEF_SUNKEN:
753 	LangSetString(&result,"sunken");
754         break;
755       case TIX_RELIEF_GROOVE:
756 	LangSetString(&result,"groove");
757         break;
758       case TIX_RELIEF_RIDGE:
759 	LangSetString(&result,"ridge");
760         break;
761       case TIX_RELIEF_SOLID:
762 	LangSetString(&result,"solid");
763         break;
764       default:
765 	LangSetString(&result,"unknown");
766         break;
767     }
768     return result;
769 }
770 /*
771  * The global data structures to use in widget configSpecs arrays
772  *
773  * These are declared in <tix.h>
774  */
775 #ifndef _LANG
776 Tk_CustomOption tixConfigRelief = {
777     ReliefParseProc, ReliefPrintProc, 0,
778 };
779 #endif
780 
781 /* Tix_SetRcFileName --
782  *
783  *	Sets a user-specific startup file in a way that's compatible with
784  *	different versions of Tclsh
785  */
786 #ifndef _LANG
Tix_SetRcFileName(interp,rcFileName)787 void Tix_SetRcFileName(interp, rcFileName)
788     Tcl_Interp * interp;
789     char * rcFileName;
790 {
791 #ifdef TCL_7_5_OR_LATER
792     /*
793      * Starting from TCL 7.5, the symbol tcl_rcFileName is no longer
794      * exported by libtcl.a. Instead, this variable must be set using
795      * a TCL global variable
796      */
797     Tcl_SetVar(interp, "tcl_rcFileName", rcFileName, TCL_GLOBAL_ONLY);
798 #else
799     tcl_RcFileName = rcFileName;
800 #endif
801 }
802 #endif
803 
804 #if (TK_MAJOR_VERSION > 4)
805 
806 /*
807  * The TkComputeTextGeometry function is no longer supported in Tk 8.0+
808  */
809 
810 /*
811  *----------------------------------------------------------------------
812  *
813  * TixComputeTextGeometry --
814  *
815  *	This procedure computes the amount of screen space needed to
816  *	display a multi-line string of text.
817  *
818  * Results:
819  *	There is no return value.  The dimensions of the screen area
820  *	needed to display the text are returned in *widthPtr, and *heightPtr.
821  *
822  * Side effects:
823  *	None.
824  *
825  *----------------------------------------------------------------------
826  */
827 
828 void
TixComputeTextGeometry(font,string,numChars,wrapLength,widthPtr,heightPtr)829 TixComputeTextGeometry(font, string, numChars, wrapLength,
830 	widthPtr, heightPtr)
831     TixFont font;		/* Font that will be used to display text. */
832     char *string;		/* String whose dimensions are to be
833 				 * computed. */
834     int numChars;		/* Number of characters to consider from
835 				 * string. */
836     int wrapLength;		/* Longest permissible line length, in
837 				 * pixels.  <= 0 means no automatic wrapping:
838 				 * just let lines get as long as needed. */
839     int *widthPtr;		/* Store width of string here. */
840     int *heightPtr;		/* Store height of string here. */
841 {
842     Tk_TextLayout textLayout;
843 
844     /*
845      * The justification itself doesn't affect the geometry (size) of
846      * the text string. We pass TK_JUSTIFY_LEFT.
847      */
848 
849     textLayout = Tk_ComputeTextLayout(font,
850 	string, -1, wrapLength, TK_JUSTIFY_LEFT, 0,
851 	widthPtr, heightPtr);
852     Tk_FreeTextLayout(textLayout);
853 }
854 
855 /*
856  *----------------------------------------------------------------------
857  *
858  * TixDisplayText --
859  *
860  *	Display a text string on one or more lines.
861  *
862  * Results:
863  *	None.
864  *
865  * Side effects:
866  *	The text given by "string" gets displayed at the given location
867  *	in the given drawable with the given font etc.
868  *
869  *----------------------------------------------------------------------
870  */
871 
872 void
TixDisplayText(display,drawable,font,string,numChars,x,y,length,justify,underline,gc)873 TixDisplayText(display, drawable, font, string, numChars, x, y,
874 	length, justify, underline, gc)
875     Display *display;		/* X display to use for drawing text. */
876     Drawable drawable;		/* Window or pixmap in which to draw the
877 				 * text. */
878     TixFont font;		/* Font that determines geometry of text
879 				 * (should be same as font in gc). */
880     char *string;		/* String to display;  may contain embedded
881 				 * newlines. */
882     int numChars;		/* Number of characters to use from string. */
883     int x, y;			/* Pixel coordinates within drawable of
884 				 * upper left corner of display area. */
885     int length;			/* Line length in pixels;  used to compute
886 				 * word wrap points and also for
887 				 * justification.   Must be > 0. */
888     Tk_Justify justify;		/* How to justify lines. */
889     int underline;		/* Index of character to underline, or < 0
890 				 * for no underlining. */
891     GC gc;			/* Graphics context to use for drawing text. */
892 {
893     Tk_TextLayout textLayout;
894     int width;
895     int height;
896 
897     /* FIXME: Needs attention?
898         - incoming numChars is not used, possibly due to confusion
899           as to whether it is bytes or chars
900      */
901 
902     textLayout = Tk_ComputeTextLayout(font,
903 	string, -1, length, justify, 0,
904 	&width, &height);
905 
906     switch (justify) {
907         case TK_JUSTIFY_RIGHT:
908 	    x += length-width;
909 	    break;
910         case TK_JUSTIFY_CENTER:
911 	    x += (length-width)/2;
912 	    break;
913 	default:
914 	case TK_JUSTIFY_LEFT:
915 	    break;
916     }
917 
918     Tk_DrawTextLayout(display, drawable, gc, textLayout,
919 	    x, y, 0, -1);
920     Tk_UnderlineTextLayout(display, drawable, gc,
921 	    textLayout, x, y, underline);
922 
923     Tk_FreeTextLayout(textLayout);
924 }
925 #endif
926 
927 #if TK_MAJOR_VERSION < 8
928 
929 /*
930  * Procedure types defined by Tcl:
931  */
932 
933 typedef void (Tcl_FreeInternalRepProc) _ANSI_ARGS_((struct Tcl_Obj *objPtr));
934 typedef void (Tcl_DupInternalRepProc) _ANSI_ARGS_((struct Tcl_Obj *srcPtr,
935         struct Tcl_Obj *dupPtr));
936 typedef void (Tcl_UpdateStringProc) _ANSI_ARGS_((struct Tcl_Obj *objPtr));
937 typedef int (Tcl_SetFromAnyProc) _ANSI_ARGS_((Tcl_Interp *interp,
938 	struct Tcl_Obj *objPtr));
939 typedef int (Tcl_ObjCmdProc) _ANSI_ARGS_((ClientData clientData,
940 	Tcl_Interp *interp, int objc, struct Tcl_Obj *CONST objv[]));
941 
942 /*
943  * The following structure represents a type of object, which is a
944  * particular internal representation for an object plus a set of
945  * procedures that provide standard operations on objects of that type.
946  */
947 
948 typedef struct Tcl_ObjType {
949     char *name;			/* Name of the type, e.g. "int". */
950     Tcl_FreeInternalRepProc *freeIntRepProc;
951 				/* Called to free any storage for the type's
952 				 * internal rep. NULL if the internal rep
953 				 * does not need freeing. */
954     Tcl_DupInternalRepProc *dupIntRepProc;
955     				/* Called to create a new object as a copy
956 				 * of an existing object. */
957     Tcl_UpdateStringProc *updateStringProc;
958     				/* Called to update the string rep from the
959 				 * type's internal representation. */
960     Tcl_SetFromAnyProc *setFromAnyProc;
961     				/* Called to convert the object's internal
962 				 * rep to this type. Frees the internal rep
963 				 * of the old type. Returns TCL_ERROR on
964 				 * failure. */
965 } Tcl_ObjType;
966 
967 /*
968  * One of the following structures exists for each object in the Tcl
969  * system.  An object stores a value as either a string, some internal
970  * representation, or both.
971  */
972 
973 typedef struct Tcl_Obj {
974     int refCount;		/* When 0 the object will be freed. */
975     char *bytes;		/* This points to the first byte of the
976 				 * object's string representation. The
977 				 * array must be followed by a null byte
978 				 * (i.e., at offset length) but may also
979 				 * contain embedded null characters. The
980 				 * array's storage is allocated by
981 				 * ckalloc. NULL indicates the string
982 				 * rep is empty or invalid and must be
983 				 * regenerated from the internal rep.
984 				 * Clients should use Tcl_GetStringFromObj
985 				 * to get a pointer to the byte array
986 				 * as a readonly value.  */
987     int length;			/* The number of bytes at *bytes, not
988 				 * including the terminating null. */
989     Tcl_ObjType *typePtr;	/* Denotes the object's type. Always
990 				 * corresponds to the type of the object's
991 				 * internal rep. NULL indicates the object
992 				 * has no internal rep (has no type). */
993     union {			/* The internal representation: */
994 	long longValue;		/*   - an long integer value */
995 	double doubleValue;	/*   - a double-precision floating value */
996 	VOID *otherValuePtr;	/*   - another, type-specific value */
997 	struct {		/*   - internal rep as two pointers */
998 	    VOID *ptr1;
999 	    VOID *ptr2;
1000 	} twoPtrValue;
1001     } internalRep;
1002 } Tcl_Obj;
1003 
1004 #endif
1005 
1006 /*
1007  *----------------------------------------------------------------------
1008  *
1009  * TixGetStringFromObj --
1010  *
1011  *	Returns the string representation's byte array pointer and length
1012  *	for an object.
1013  *
1014  * Results:
1015  *	Returns a pointer to the string representation of objPtr.  If
1016  *	lengthPtr isn't NULL, the length of the string representation is
1017  *	stored at *lengthPtr. The byte array referenced by the returned
1018  *	pointer must not be modified by the caller. Furthermore, the
1019  *	caller must copy the bytes if they need to retain them since the
1020  *	object's string rep can change as a result of other operations.
1021  *      REMARK: This function reacts a little bit different than
1022  *	Tcl_GetStringFromObj():
1023  *	- objPtr is allowed to be NULL. In that case the NULL pointer
1024  *	  will be returned, and the length will be reported to be 0;
1025  *	In the Img code there is never a distinction between en empty
1026  *	string and a NULL pointer, while the latter is easier to check
1027  *	for. That's the reason for this difference.
1028  *
1029  * Side effects:
1030  *	May call the object's updateStringProc to update the string
1031  *	representation from the internal representation.
1032  *
1033  *----------------------------------------------------------------------
1034  */
1035 
1036 
1037 char *
TixGetStringFromObj(objPtr,lengthPtr)1038 TixGetStringFromObj(objPtr, lengthPtr)
1039     char *objPtr;		/* Object whose string rep byte pointer
1040 				 * should be returned, or NULL */
1041     register int *lengthPtr;	/* If non-NULL, the location where the
1042 				 * string rep's byte array length should be
1043 				 * stored. If NULL, no length is stored. */
1044 {
1045     Tcl_Obj *obj = (Tcl_Obj *) objPtr;
1046     int length;
1047     if (!lengthPtr)
1048       lengthPtr = &length;
1049     if (!obj) {
1050 	if (lengthPtr != NULL) {
1051 	    *lengthPtr = 0;
1052 	}
1053 	return (char *) NULL;
1054     }
1055 #ifdef _LANG
1056     objPtr = Tcl_GetStringFromObj(obj,lengthPtr);
1057     if (*lengthPtr)
1058      return NULL;
1059     return objPtr;
1060 #else
1061     if (initialized & 2) {
1062 	if (obj->bytes != NULL) {
1063 	    if (lengthPtr != NULL) {
1064 		*lengthPtr = obj->length;
1065 	    }
1066 	    return (obj->length) ? obj->bytes : (char *) NULL;
1067 	}
1068 
1069 	if (obj->typePtr == NULL) {
1070 	    if (lengthPtr != NULL) {
1071 		*lengthPtr = 0;
1072 	    }
1073 	    return "";
1074 	}
1075 
1076 	obj->typePtr->updateStringProc(obj);
1077 	if (lengthPtr != NULL) {
1078 	    *lengthPtr = obj->length;
1079 	}
1080 	return (obj->length) ? obj->bytes : (char *) NULL;
1081     } else {
1082 	if (lengthPtr != NULL) {
1083 	    *lengthPtr = objPtr ? strlen(objPtr) : 0;
1084 	}
1085 	return objPtr;
1086     }
1087 #endif /* _LANG */
1088 }
1089 
1090 /*----------------------------------------------------------------------
1091  * TixStartSubRegionDraw --
1092  *
1093  *	Limits the subsequent drawing operations into the prescribed
1094  *	rectangle region. This takes effect up to a matching
1095  *	TixEndSubRegionDraw() call.
1096  *
1097  * Return value:
1098  *	none.
1099  *----------------------------------------------------------------------
1100  */
1101 
1102 void
TixpStartSubRegionDraw(ddPtr,drawable,gc,subRegPtr,origX,origY,x,y,width,height,needWidth,needHeight)1103 TixpStartSubRegionDraw(ddPtr, drawable, gc, subRegPtr, origX, origY,
1104 	x, y, width, height, needWidth, needHeight)
1105     Tix_DispData *ddPtr;
1106     Drawable drawable;
1107     GC gc;
1108     TixpSubRegion * subRegPtr;
1109     int origX;
1110     int origY;
1111     int x;
1112     int y;
1113     int width;
1114     int height;
1115     int needWidth;
1116     int needHeight;
1117 {
1118     Display *display = ddPtr->display;
1119     int depth;
1120 
1121     if ((width < needWidth) || (height < needHeight)) {
1122 	subRegPtr->origX  = origX;
1123 	subRegPtr->origY  = origY;
1124 	subRegPtr->x	  = x;
1125 	subRegPtr->y	  = y;
1126 	subRegPtr->width  = width;
1127 	subRegPtr->height = height;
1128 
1129 	/*
1130 	 * Find out the depth of the drawable and create a pixmap of
1131 	 * the same depth.
1132 	 */
1133         depth = Tk_Depth(ddPtr->tkwin);
1134 
1135 	subRegPtr->pixmap = Tk_GetPixmap(display, drawable, width, height,
1136 		depth);
1137 
1138 	if (subRegPtr->pixmap != None) {
1139 	    /*
1140 	     * It could be None if we have somehow exhausted the Windows
1141 	     * GDI resources.
1142 	     */
1143 	    XCopyArea(display, drawable, subRegPtr->pixmap, gc, x, y,
1144 		    width, height, 0, 0);
1145 	}
1146     } else {
1147 	subRegPtr->pixmap = None;
1148     }
1149 }
1150 
1151 /*----------------------------------------------------------------------
1152  * TixpEndSubRegionDraw --
1153  *
1154  *
1155  *----------------------------------------------------------------------
1156  */
1157 void
TixpEndSubRegionDraw(display,drawable,gc,subRegPtr)1158 TixpEndSubRegionDraw(display, drawable, gc, subRegPtr)
1159     Display *display;
1160     Drawable drawable;
1161     GC gc;
1162     TixpSubRegion * subRegPtr;
1163 {
1164     if (subRegPtr->pixmap != None) {
1165 	XCopyArea(display, subRegPtr->pixmap, drawable, gc, 0, 0,
1166 		subRegPtr->width, subRegPtr->height,
1167 		subRegPtr->x, subRegPtr->y);
1168 	Tk_FreePixmap(display, subRegPtr->pixmap);
1169 	subRegPtr->pixmap = None;
1170     }
1171 }
1172 
1173 /*
1174  *----------------------------------------------------------------------
1175  *
1176  * TixpSubRegDisplayText --
1177  *
1178  *	Display a text string on one or more lines in a sub region.
1179  *
1180  * Results:
1181  *	See TkDisplayText
1182  *
1183  * Side effects:
1184  *	See TkDisplayText
1185  *
1186  *----------------------------------------------------------------------
1187  */
1188 
1189 void
TixpSubRegDisplayText(display,drawable,gc,subRegPtr,font,string,numChars,x,y,length,justify,underline)1190 TixpSubRegDisplayText(display, drawable, gc, subRegPtr, font, string,
1191 	numChars, x, y,	length, justify, underline)
1192     Display *display;		/* X display to use for drawing text. */
1193     Drawable drawable;		/* Window or pixmap in which to draw the
1194 				 * text. */
1195     GC gc;			/* Graphics context to use for drawing text. */
1196     TixpSubRegion * subRegPtr;	/* Information about the subregion */
1197     TixFont font;		/* Font that determines geometry of text
1198 				 * (should be same as font in gc). */
1199     char *string;		/* String to display;  may contain embedded
1200 				 * newlines. */
1201     int numChars;		/* Number of characters to use from string. */
1202     int x, y;			/* Pixel coordinates within drawable of
1203 				 * upper left corner of display area. */
1204     int length;			/* Line length in pixels;  used to compute
1205 				 * word wrap points and also for
1206 				 * justification.   Must be > 0. */
1207     Tk_Justify justify;		/* How to justify lines. */
1208     int underline;		/* Index of character to underline, or < 0
1209 				 * for no underlining. */
1210 {
1211     if (subRegPtr->pixmap != None) {
1212 	TixDisplayText(display, subRegPtr->pixmap, font, string,
1213 		numChars, x - subRegPtr->x, y - subRegPtr->y,
1214 		length, justify, underline, gc);
1215     } else {
1216 	TixDisplayText(display, drawable, font, string,
1217 		numChars, x, y,	length, justify, underline, gc);
1218     }
1219 }
1220 
1221 /*----------------------------------------------------------------------
1222  * TixpSubRegFillRectangle --
1223  *
1224  *
1225  *----------------------------------------------------------------------
1226  */
1227 
1228 void
TixpSubRegFillRectangle(display,drawable,gc,subRegPtr,x,y,width,height)1229 TixpSubRegFillRectangle(display, drawable, gc, subRegPtr, x, y, width, height)
1230     Display *display;		/* X display to use for drawing rectangle. */
1231     Drawable drawable;		/* Window or pixmap in which to draw the
1232 				 * rectangle. */
1233     GC gc;			/* Graphics context to use for drawing. */
1234     TixpSubRegion * subRegPtr;	/* Information about the subregion */
1235     int x, y;			/* Pixel coordinates within drawable of
1236 				 * upper left corner of display area. */
1237     int width, height;		/* Size of the rectangle. */
1238 {
1239     if (subRegPtr->pixmap != None) {
1240 	XFillRectangle(display, subRegPtr->pixmap, gc,
1241 		x - subRegPtr->x, y - subRegPtr->x, width, height);
1242     } else {
1243 	XFillRectangle(display, drawable, gc, x, y, width, height);
1244     }
1245 }
1246 
1247 /*----------------------------------------------------------------------
1248  * TixpSubRegDrawImage	--
1249  *
1250  *	Draws a Tk image in a subregion.
1251  *----------------------------------------------------------------------
1252  */
1253 
1254 void
TixpSubRegDrawImage(subRegPtr,image,imageX,imageY,width,height,drawable,drawableX,drawableY)1255 TixpSubRegDrawImage(subRegPtr, image, imageX, imageY, width, height,
1256 	drawable, drawableX, drawableY)
1257     TixpSubRegion * subRegPtr;
1258     Tk_Image image;
1259     int imageX;
1260     int imageY;
1261     int width;
1262     int height;
1263     Drawable drawable;
1264     int drawableX;
1265     int drawableY;
1266 {
1267     if (subRegPtr->pixmap != None) {
1268 	Tk_RedrawImage(image, imageX, imageY, width, height, subRegPtr->pixmap,
1269 	        drawableX - subRegPtr->x, drawableY - subRegPtr->y);
1270     } else {
1271 	Tk_RedrawImage(image, imageX, imageY, width, height, drawable,
1272 	        drawableX, drawableY);
1273     }
1274 }
1275 
1276 void
TixpSubRegDrawBitmap(display,drawable,gc,subRegPtr,bitmap,src_x,src_y,width,height,dest_x,dest_y,plane)1277 TixpSubRegDrawBitmap(display, drawable, gc, subRegPtr, bitmap, src_x, src_y,
1278 	width, height, dest_x, dest_y, plane)
1279     Display *display;
1280     Drawable drawable;
1281     GC gc;
1282     TixpSubRegion * subRegPtr;
1283     Pixmap bitmap;
1284     int src_x, src_y;
1285     int width, height;
1286     int dest_x, dest_y;
1287     unsigned long plane;
1288 {
1289     XSetClipOrigin(display, gc, dest_x, dest_y);
1290     if (subRegPtr->pixmap != None) {
1291 	XCopyPlane(display, bitmap, subRegPtr->pixmap, gc, src_x, src_y,
1292 		width, height, dest_x - subRegPtr->x, dest_y - subRegPtr->y,
1293 		plane);
1294     } else {
1295 	XCopyPlane(display, bitmap, drawable, gc, src_x, src_y, width, height,
1296 	        dest_x, dest_y, plane);
1297     }
1298     XSetClipOrigin(display, gc, 0, 0);
1299 }
1300 
1301