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