]>
Commit | Line | Data |
---|---|---|
6a5fa4e0 MG |
1 | /* |
2 | * tkConfig.c -- | |
3 | * | |
4 | * This file contains the Tk_ConfigureWidget procedure. | |
5 | * | |
6 | * Copyright 1990-1992 Regents of the University of California. | |
7 | * Permission to use, copy, modify, and distribute this | |
8 | * software and its documentation for any purpose and without | |
9 | * fee is hereby granted, provided that the above copyright | |
10 | * notice appear in all copies. The University of California | |
11 | * makes no representations about the suitability of this | |
12 | * software for any purpose. It is provided "as is" without | |
13 | * express or implied warranty. | |
14 | */ | |
15 | ||
16 | #ifndef lint | |
17 | static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkConfig.c,v 1.28 92/07/25 15:52:26 ouster Exp $ SPRITE (Berkeley)"; | |
18 | #endif | |
19 | ||
20 | #include "tkconfig.h" | |
21 | #include "tk.h" | |
22 | ||
23 | /* | |
24 | * Values for "flags" field of Tk_ConfigSpec structures. Be sure | |
25 | * to coordinate these values with those defined in tk.h | |
26 | * (TK_CONFIG_COLOR_ONLY, etc.). There must not be overlap! | |
27 | * | |
28 | * INIT - Non-zero means (char *) things have been | |
29 | * converted to Tk_Uid's. | |
30 | */ | |
31 | ||
32 | #define INIT 0x20 | |
33 | ||
34 | /* | |
35 | * Forward declarations for procedures defined later in this file: | |
36 | */ | |
37 | ||
38 | static int DoConfig _ANSI_ARGS_((Tcl_Interp *interp, | |
39 | Tk_Window tkwin, Tk_ConfigSpec *specPtr, | |
40 | Tk_Uid value, int valueIsUid, char *widgRec)); | |
41 | static Tk_ConfigSpec * FindConfigSpec _ANSI_ARGS_ ((Tcl_Interp *interp, | |
42 | Tk_ConfigSpec *specs, char *argvName, | |
43 | int needFlags, int hateFlags)); | |
44 | static char * FormatConfigInfo _ANSI_ARGS_ ((Tk_Window tkwin, | |
45 | Tk_ConfigSpec *specPtr, char *widgRec)); | |
46 | \f | |
47 | /* | |
48 | *-------------------------------------------------------------- | |
49 | * | |
50 | * Tk_ConfigureWidget -- | |
51 | * | |
52 | * Process command-line options and database options to | |
53 | * fill in fields of a widget record with resources and | |
54 | * other parameters. | |
55 | * | |
56 | * Results: | |
57 | * A standard Tcl return value. In case of an error, | |
58 | * interp->result will hold an error message. | |
59 | * | |
60 | * Side effects: | |
61 | * The fields of widgRec get filled in with information | |
62 | * from argc/argv and the option database. Old information | |
63 | * in widgRec's fields gets recycled. | |
64 | * | |
65 | *-------------------------------------------------------------- | |
66 | */ | |
67 | ||
68 | int | |
69 | Tk_ConfigureWidget(interp, tkwin, specs, argc, argv, widgRec, flags) | |
70 | Tcl_Interp *interp; /* Interpreter for error reporting. */ | |
71 | Tk_Window tkwin; /* Window containing widget (needed to | |
72 | * set up X resources). */ | |
73 | Tk_ConfigSpec *specs; /* Describes legal options. */ | |
74 | int argc; /* Number of elements in argv. */ | |
75 | char **argv; /* Command-line options. */ | |
76 | char *widgRec; /* Record whose fields are to be | |
77 | * modified. Values must be properly | |
78 | * initialized. */ | |
79 | int flags; /* Used to specify additional flags | |
80 | * that must be present in config specs | |
81 | * for them to be considered. Also, | |
82 | * may have TK_CONFIG_ARGV_ONLY set. */ | |
83 | { | |
84 | register Tk_ConfigSpec *specPtr; | |
85 | Tk_Uid value; /* Value of option from database. */ | |
86 | int needFlags; /* Specs must contain this set of flags | |
87 | * or else they are not considered. */ | |
88 | int hateFlags; /* If a spec contains any bits here, it's | |
89 | * not considered. */ | |
90 | ||
91 | needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); | |
92 | if (Tk_DefaultDepth(Tk_Screen(tkwin)) == 1) { | |
93 | hateFlags = TK_CONFIG_COLOR_ONLY; | |
94 | } else { | |
95 | hateFlags = TK_CONFIG_MONO_ONLY; | |
96 | } | |
97 | ||
98 | /* | |
99 | * Pass one: scan through all the option specs, replacing strings | |
100 | * with Tk_Uids (if this hasn't been done already) and clearing | |
101 | * the TK_CONFIG_OPTION_SPECIFIED flags. | |
102 | */ | |
103 | ||
104 | for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { | |
105 | if (!(specPtr->specFlags & INIT) && (specPtr->argvName != NULL)) { | |
106 | if (specPtr->dbName != NULL) { | |
107 | specPtr->dbName = Tk_GetUid(specPtr->dbName); | |
108 | } | |
109 | if (specPtr->dbClass != NULL) { | |
110 | specPtr->dbClass = Tk_GetUid(specPtr->dbClass); | |
111 | } | |
112 | if (specPtr->defValue != NULL) { | |
113 | specPtr->defValue = Tk_GetUid(specPtr->defValue); | |
114 | } | |
115 | } | |
116 | specPtr->specFlags = (specPtr->specFlags & ~TK_CONFIG_OPTION_SPECIFIED) | |
117 | | INIT; | |
118 | } | |
119 | ||
120 | /* | |
121 | * Pass two: scan through all of the arguments, processing those | |
122 | * that match entries in the specs. | |
123 | */ | |
124 | ||
125 | for ( ; argc > 0; argc -= 2, argv += 2) { | |
126 | specPtr = FindConfigSpec(interp, specs, *argv, needFlags, hateFlags); | |
127 | if (specPtr == NULL) { | |
128 | return TCL_ERROR; | |
129 | } | |
130 | ||
131 | /* | |
132 | * Process the entry. | |
133 | */ | |
134 | ||
135 | if (argc < 2) { | |
136 | Tcl_AppendResult(interp, "value for \"", *argv, | |
137 | "\" missing", (char *) NULL); | |
138 | return TCL_ERROR; | |
139 | } | |
140 | if (DoConfig(interp, tkwin, specPtr, argv[1], 0, widgRec) != TCL_OK) { | |
141 | char msg[100]; | |
142 | ||
143 | sprintf(msg, "\n (processing \"%.40s\" option)", | |
144 | specPtr->argvName); | |
145 | Tcl_AddErrorInfo(interp, msg); | |
146 | return TCL_ERROR; | |
147 | } | |
148 | specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED; | |
149 | } | |
150 | ||
151 | /* | |
152 | * Pass three: scan through all of the specs again; if no | |
153 | * command-line argument matched a spec, then check for info | |
154 | * in the option database. If there was nothing in the | |
155 | * database, then use the default. | |
156 | */ | |
157 | ||
158 | if (!(flags & TK_CONFIG_ARGV_ONLY)) { | |
159 | for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { | |
160 | if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED) | |
161 | || (specPtr->argvName == NULL) | |
162 | || (specPtr->type == TK_CONFIG_SYNONYM)) { | |
163 | continue; | |
164 | } | |
165 | if (((specPtr->specFlags & needFlags) != needFlags) | |
166 | || (specPtr->specFlags & hateFlags)) { | |
167 | continue; | |
168 | } | |
169 | value = NULL; | |
170 | if (specPtr->dbName != NULL) { | |
171 | value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass); | |
172 | } | |
173 | if (value != NULL) { | |
174 | if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) != | |
175 | TCL_OK) { | |
176 | char msg[200]; | |
177 | ||
178 | sprintf(msg, "\n (%s \"%.50s\" in widget \"%.50s\")", | |
179 | "database entry for", | |
180 | specPtr->dbName, Tk_PathName(tkwin)); | |
181 | Tcl_AddErrorInfo(interp, msg); | |
182 | return TCL_ERROR; | |
183 | } | |
184 | } else { | |
185 | value = specPtr->defValue; | |
186 | if ((value != NULL) && !(specPtr->specFlags | |
187 | & TK_CONFIG_DONT_SET_DEFAULT)) { | |
188 | if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) != | |
189 | TCL_OK) { | |
190 | char msg[200]; | |
191 | ||
192 | sprintf(msg, | |
193 | "\n (%s \"%.50s\" in widget \"%.50s\")", | |
194 | "default value for", | |
195 | specPtr->dbName, Tk_PathName(tkwin)); | |
196 | Tcl_AddErrorInfo(interp, msg); | |
197 | return TCL_ERROR; | |
198 | } | |
199 | } | |
200 | } | |
201 | } | |
202 | } | |
203 | ||
204 | return TCL_OK; | |
205 | } | |
206 | \f | |
207 | /* | |
208 | *-------------------------------------------------------------- | |
209 | * | |
210 | * FindConfigSpec -- | |
211 | * | |
212 | * Search through a table of configuration specs, looking for | |
213 | * one that matches a given argvName. | |
214 | * | |
215 | * Results: | |
216 | * The return value is a pointer to the matching entry, or NULL | |
217 | * if nothing matched. In that case an error message is left | |
218 | * in interp->result. | |
219 | * | |
220 | * Side effects: | |
221 | * None. | |
222 | * | |
223 | *-------------------------------------------------------------- | |
224 | */ | |
225 | ||
226 | static Tk_ConfigSpec * | |
227 | FindConfigSpec(interp, specs, argvName, needFlags, hateFlags) | |
228 | Tcl_Interp *interp; /* Used for reporting errors. */ | |
229 | Tk_ConfigSpec *specs; /* Pointer to table of configuration | |
230 | * specifications for a widget. */ | |
231 | char *argvName; /* Name (suitable for use in a "config" | |
232 | * command) identifying particular option. */ | |
233 | int needFlags; /* Flags that must be present in matching | |
234 | * entry. */ | |
235 | int hateFlags; /* Flags that must NOT be present in | |
236 | * matching entry. */ | |
237 | { | |
238 | register Tk_ConfigSpec *specPtr; | |
239 | register char c; /* First character of current argument. */ | |
240 | Tk_ConfigSpec *matchPtr; /* Matching spec, or NULL. */ | |
241 | int length; | |
242 | ||
243 | c = argvName[1]; | |
244 | length = strlen(argvName); | |
245 | matchPtr = NULL; | |
246 | for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { | |
247 | if (specPtr->argvName == NULL) { | |
248 | continue; | |
249 | } | |
250 | if ((specPtr->argvName[1] != c) | |
251 | || (strncmp(specPtr->argvName, argvName, length) != 0)) { | |
252 | continue; | |
253 | } | |
254 | if (((specPtr->specFlags & needFlags) != needFlags) | |
255 | || (specPtr->specFlags & hateFlags)) { | |
256 | continue; | |
257 | } | |
258 | if (specPtr->argvName[length] == 0) { | |
259 | matchPtr = specPtr; | |
260 | goto gotMatch; | |
261 | } | |
262 | if (matchPtr != NULL) { | |
263 | Tcl_AppendResult(interp, "ambiguous option \"", argvName, | |
264 | "\"", (char *) NULL); | |
265 | return (Tk_ConfigSpec *) NULL; | |
266 | } | |
267 | matchPtr = specPtr; | |
268 | } | |
269 | ||
270 | if (matchPtr == NULL) { | |
271 | Tcl_AppendResult(interp, "unknown option \"", argvName, | |
272 | "\"", (char *) NULL); | |
273 | return (Tk_ConfigSpec *) NULL; | |
274 | } | |
275 | ||
276 | /* | |
277 | * Found a matching entry. If it's a synonym, then find the | |
278 | * entry that it's a synonym for. | |
279 | */ | |
280 | ||
281 | gotMatch: | |
282 | specPtr = matchPtr; | |
283 | if (specPtr->type == TK_CONFIG_SYNONYM) { | |
284 | for (specPtr = specs; ; specPtr++) { | |
285 | if (specPtr->type == TK_CONFIG_END) { | |
286 | Tcl_AppendResult(interp, | |
287 | "couldn't find synonym for option \"", | |
288 | argvName, "\"", (char *) NULL); | |
289 | return (Tk_ConfigSpec *) NULL; | |
290 | } | |
291 | if ((specPtr->dbName == matchPtr->dbName) | |
292 | && (specPtr->type != TK_CONFIG_SYNONYM) | |
293 | && ((specPtr->specFlags & needFlags) == needFlags) | |
294 | && !(specPtr->specFlags & hateFlags)) { | |
295 | break; | |
296 | } | |
297 | } | |
298 | } | |
299 | return specPtr; | |
300 | } | |
301 | \f | |
302 | /* | |
303 | *-------------------------------------------------------------- | |
304 | * | |
305 | * DoConfig -- | |
306 | * | |
307 | * This procedure applies a single configuration option | |
308 | * to a widget record. | |
309 | * | |
310 | * Results: | |
311 | * A standard Tcl return value. | |
312 | * | |
313 | * Side effects: | |
314 | * WidgRec is modified as indicated by specPtr and value. | |
315 | * The old value is recycled, if that is appropriate for | |
316 | * the value type. | |
317 | * | |
318 | *-------------------------------------------------------------- | |
319 | */ | |
320 | ||
321 | static int | |
322 | DoConfig(interp, tkwin, specPtr, value, valueIsUid, widgRec) | |
323 | Tcl_Interp *interp; /* Interpreter for error reporting. */ | |
324 | Tk_Window tkwin; /* Window containing widget (needed to | |
325 | * set up X resources). */ | |
326 | Tk_ConfigSpec *specPtr; /* Specifier to apply. */ | |
327 | char *value; /* Value to use to fill in widgRec. */ | |
328 | int valueIsUid; /* Non-zero means value is a Tk_Uid; | |
329 | * zero means it's an ordinary string. */ | |
330 | char *widgRec; /* Record whose fields are to be | |
331 | * modified. Values must be properly | |
332 | * initialized. */ | |
333 | { | |
334 | char *ptr; | |
335 | Tk_Uid uid; | |
336 | int nullValue; | |
337 | ||
338 | nullValue = 0; | |
339 | if ((*value == 0) && (specPtr->specFlags & TK_CONFIG_NULL_OK)) { | |
340 | nullValue = 1; | |
341 | } | |
342 | ||
343 | do { | |
344 | ptr = widgRec + specPtr->offset; | |
345 | switch (specPtr->type) { | |
346 | case TK_CONFIG_BOOLEAN: | |
347 | if (Tcl_GetBoolean(interp, value, (int *) ptr) != TCL_OK) { | |
348 | return TCL_ERROR; | |
349 | } | |
350 | break; | |
351 | case TK_CONFIG_INT: | |
352 | if (Tcl_GetInt(interp, value, (int *) ptr) != TCL_OK) { | |
353 | return TCL_ERROR; | |
354 | } | |
355 | break; | |
356 | case TK_CONFIG_DOUBLE: | |
357 | if (Tcl_GetDouble(interp, value, (double *) ptr) != TCL_OK) { | |
358 | return TCL_ERROR; | |
359 | } | |
360 | break; | |
361 | case TK_CONFIG_STRING: { | |
362 | char *old, *new; | |
363 | ||
364 | if (nullValue) { | |
365 | new = NULL; | |
366 | } else { | |
367 | new = (char *) ckalloc((unsigned) (strlen(value) + 1)); | |
368 | strcpy(new, value); | |
369 | } | |
370 | old = *((char **) ptr); | |
371 | if (old != NULL) { | |
372 | ckfree(old); | |
373 | } | |
374 | *((char **) ptr) = new; | |
375 | break; | |
376 | } | |
377 | case TK_CONFIG_UID: | |
378 | if (nullValue) { | |
379 | *((Tk_Uid *) ptr) = NULL; | |
380 | } else { | |
381 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
382 | *((Tk_Uid *) ptr) = uid; | |
383 | } | |
384 | break; | |
385 | case TK_CONFIG_COLOR: { | |
386 | XColor *newPtr, *oldPtr; | |
387 | ||
388 | if (nullValue) { | |
389 | newPtr = NULL; | |
390 | } else { | |
391 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
392 | newPtr = Tk_GetColor(interp, tkwin, (Colormap) None, uid); | |
393 | if (newPtr == NULL) { | |
394 | return TCL_ERROR; | |
395 | } | |
396 | } | |
397 | oldPtr = *((XColor **) ptr); | |
398 | if (oldPtr != NULL) { | |
399 | Tk_FreeColor(oldPtr); | |
400 | } | |
401 | *((XColor **) ptr) = newPtr; | |
402 | break; | |
403 | } | |
404 | case TK_CONFIG_FONT: { | |
405 | XFontStruct *newPtr, *oldPtr; | |
406 | ||
407 | if (nullValue) { | |
408 | newPtr = NULL; | |
409 | } else { | |
410 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
411 | newPtr = Tk_GetFontStruct(interp, tkwin, uid); | |
412 | if (newPtr == NULL) { | |
413 | return TCL_ERROR; | |
414 | } | |
415 | } | |
416 | oldPtr = *((XFontStruct **) ptr); | |
417 | if (oldPtr != NULL) { | |
418 | Tk_FreeFontStruct(oldPtr); | |
419 | } | |
420 | *((XFontStruct **) ptr) = newPtr; | |
421 | break; | |
422 | } | |
423 | case TK_CONFIG_BITMAP: { | |
424 | Pixmap new, old; | |
425 | ||
426 | if (nullValue) { | |
427 | new = None; | |
428 | } else { | |
429 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
430 | new = Tk_GetBitmap(interp, tkwin, uid); | |
431 | if (new == None) { | |
432 | return TCL_ERROR; | |
433 | } | |
434 | } | |
435 | old = *((Pixmap *) ptr); | |
436 | if (old != None) { | |
437 | Tk_FreeBitmap(old); | |
438 | } | |
439 | *((Pixmap *) ptr) = new; | |
440 | break; | |
441 | } | |
442 | #if defined(USE_XPM3) | |
443 | case TK_CONFIG_PIXMAP: { | |
444 | Pixmap new, old; | |
445 | ||
446 | if (nullValue) { | |
447 | new = None; | |
448 | } else { | |
449 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
450 | new = Tk_GetPixmap(interp, tkwin, uid); | |
451 | if (new == None) { | |
452 | return TCL_ERROR; | |
453 | } | |
454 | } | |
455 | old = *((Pixmap *) ptr); | |
456 | if (old != None) { | |
457 | Tk_FreePixmap(old); | |
458 | } | |
459 | *((Pixmap *) ptr) = new; | |
460 | break; | |
461 | } | |
462 | #endif | |
463 | case TK_CONFIG_BORDER: { | |
464 | Tk_3DBorder new, old; | |
465 | ||
466 | if (nullValue) { | |
467 | new = NULL; | |
468 | } else { | |
469 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
470 | new = Tk_Get3DBorder(interp, tkwin, (Colormap) None, uid); | |
471 | if (new == NULL) { | |
472 | return TCL_ERROR; | |
473 | } | |
474 | } | |
475 | old = *((Tk_3DBorder *) ptr); | |
476 | if (old != NULL) { | |
477 | Tk_Free3DBorder(old); | |
478 | } | |
479 | *((Tk_3DBorder *) ptr) = new; | |
480 | break; | |
481 | } | |
482 | case TK_CONFIG_RELIEF: | |
483 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
484 | if (Tk_GetRelief(interp, uid, (int *) ptr) != TCL_OK) { | |
485 | return TCL_ERROR; | |
486 | } | |
487 | break; | |
488 | case TK_CONFIG_CURSOR: | |
489 | case TK_CONFIG_ACTIVE_CURSOR: { | |
490 | Cursor new, old; | |
491 | ||
492 | if (nullValue) { | |
493 | new = None; | |
494 | } else { | |
495 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
496 | new = Tk_GetCursor(interp, tkwin, uid); | |
497 | if (new == None) { | |
498 | return TCL_ERROR; | |
499 | } | |
500 | } | |
501 | old = *((Cursor *) ptr); | |
502 | if (old != None) { | |
503 | Tk_FreeCursor(old); | |
504 | } | |
505 | *((Cursor *) ptr) = new; | |
506 | if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) { | |
507 | Tk_DefineCursor(tkwin, new); | |
508 | } | |
509 | break; | |
510 | } | |
511 | case TK_CONFIG_JUSTIFY: | |
512 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
513 | if (Tk_GetJustify(interp, uid, (Tk_Justify *) ptr) != TCL_OK) { | |
514 | return TCL_ERROR; | |
515 | } | |
516 | break; | |
517 | case TK_CONFIG_ANCHOR: | |
518 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
519 | if (Tk_GetAnchor(interp, uid, (Tk_Anchor *) ptr) != TCL_OK) { | |
520 | return TCL_ERROR; | |
521 | } | |
522 | break; | |
523 | case TK_CONFIG_CAP_STYLE: | |
524 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
525 | if (Tk_GetCapStyle(interp, uid, (int *) ptr) != TCL_OK) { | |
526 | return TCL_ERROR; | |
527 | } | |
528 | break; | |
529 | case TK_CONFIG_JOIN_STYLE: | |
530 | uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); | |
531 | if (Tk_GetJoinStyle(interp, uid, (int *) ptr) != TCL_OK) { | |
532 | return TCL_ERROR; | |
533 | } | |
534 | break; | |
535 | case TK_CONFIG_PIXELS: | |
536 | if (Tk_GetPixels(interp, tkwin, value, (int *) ptr) | |
537 | != TCL_OK) { | |
538 | return TCL_ERROR; | |
539 | } | |
540 | break; | |
541 | case TK_CONFIG_MM: | |
542 | if (Tk_GetScreenMM(interp, tkwin, value, (double *) ptr) | |
543 | != TCL_OK) { | |
544 | return TCL_ERROR; | |
545 | } | |
546 | break; | |
547 | case TK_CONFIG_WINDOW: { | |
548 | Tk_Window tkwin2; | |
549 | ||
550 | if (nullValue) { | |
551 | tkwin2 = NULL; | |
552 | } else { | |
553 | tkwin2 = Tk_NameToWindow(interp, value, tkwin); | |
554 | if (tkwin2 == NULL) { | |
555 | return TCL_ERROR; | |
556 | } | |
557 | } | |
558 | *((Tk_Window *) ptr) = tkwin2; | |
559 | break; | |
560 | } | |
561 | case TK_CONFIG_CUSTOM: | |
562 | if ((*specPtr->customPtr->parseProc)( | |
563 | specPtr->customPtr->clientData, interp, tkwin, | |
564 | value, widgRec, specPtr->offset) != TCL_OK) { | |
565 | return TCL_ERROR; | |
566 | } | |
567 | break; | |
568 | default: { | |
569 | sprintf(interp->result, "bad config table: unknown type %d", | |
570 | specPtr->type); | |
571 | return TCL_ERROR; | |
572 | } | |
573 | } | |
574 | specPtr++; | |
575 | } while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END)); | |
576 | return TCL_OK; | |
577 | } | |
578 | \f | |
579 | /* | |
580 | *-------------------------------------------------------------- | |
581 | * | |
582 | * Tk_ConfigureInfo -- | |
583 | * | |
584 | * Return information about the configuration options | |
585 | * for a window, and their current values. | |
586 | * | |
587 | * Results: | |
588 | * Always returns TCL_OK. Interp->result will be modified | |
589 | * hold a description of either a single configuration option | |
590 | * available for "widgRec" via "specs", or all the configuration | |
591 | * options available. In the "all" case, the result will | |
592 | * available for "widgRec" via "specs". The result will | |
593 | * be a list, each of whose entries describes one option. | |
594 | * Each entry will itself be a list containing the option's | |
595 | * name for use on command lines, database name, database | |
596 | * class, default value, and current value (empty string | |
597 | * if none). For options that are synonyms, the list will | |
598 | * contain only two values: name and synonym name. If the | |
599 | * "name" argument is non-NULL, then the only information | |
600 | * returned is that for the named argument (i.e. the corresponding | |
601 | * entry in the overall list is returned). | |
602 | * | |
603 | * Side effects: | |
604 | * None. | |
605 | * | |
606 | *-------------------------------------------------------------- | |
607 | */ | |
608 | ||
609 | int | |
610 | Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags) | |
611 | Tcl_Interp *interp; /* Interpreter for error reporting. */ | |
612 | Tk_Window tkwin; /* Window corresponding to widgRec. */ | |
613 | Tk_ConfigSpec *specs; /* Describes legal options. */ | |
614 | char *widgRec; /* Record whose fields contain current | |
615 | * values for options. */ | |
616 | char *argvName; /* If non-NULL, indicates a single option | |
617 | * whose info is to be returned. Otherwise | |
618 | * info is returned for all options. */ | |
619 | int flags; /* Used to specify additional flags | |
620 | * that must be present in config specs | |
621 | * for them to be considered. */ | |
622 | { | |
623 | register Tk_ConfigSpec *specPtr; | |
624 | int needFlags, hateFlags; | |
625 | char *list; | |
626 | char *leader = "{"; | |
627 | ||
628 | needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); | |
629 | if (Tk_DefaultDepth(Tk_Screen(tkwin)) == 1) { | |
630 | hateFlags = TK_CONFIG_COLOR_ONLY; | |
631 | } else { | |
632 | hateFlags = TK_CONFIG_MONO_ONLY; | |
633 | } | |
634 | ||
635 | /* | |
636 | * If information is only wanted for a single configuration | |
637 | * spec, then handle that one spec specially. | |
638 | */ | |
639 | ||
640 | Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); | |
641 | if (argvName != NULL) { | |
642 | specPtr = FindConfigSpec(interp, specs, argvName, needFlags, | |
643 | hateFlags); | |
644 | if (specPtr == NULL) { | |
645 | return TCL_ERROR; | |
646 | } | |
647 | interp->result = FormatConfigInfo(tkwin, specPtr, widgRec); | |
648 | interp->freeProc = TCL_DYNAMIC; | |
649 | return TCL_OK; | |
650 | } | |
651 | ||
652 | /* | |
653 | * Loop through all the specs, creating a big list with all | |
654 | * their information. | |
655 | */ | |
656 | ||
657 | for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { | |
658 | if ((argvName != NULL) && (specPtr->argvName != argvName)) { | |
659 | continue; | |
660 | } | |
661 | if (((specPtr->specFlags & needFlags) != needFlags) | |
662 | || (specPtr->specFlags & hateFlags)) { | |
663 | continue; | |
664 | } | |
665 | if (specPtr->argvName == NULL) { | |
666 | continue; | |
667 | } | |
668 | list = FormatConfigInfo(tkwin, specPtr, widgRec); | |
669 | Tcl_AppendResult(interp, leader, list, "}", (char *) NULL); | |
670 | ckfree(list); | |
671 | leader = " {"; | |
672 | } | |
673 | return TCL_OK; | |
674 | } | |
675 | \f | |
676 | /* | |
677 | *-------------------------------------------------------------- | |
678 | * | |
679 | * FormatConfigInfo -- | |
680 | * | |
681 | * Create a valid Tcl list holding the configuration information | |
682 | * for a single configuration option. | |
683 | * | |
684 | * Results: | |
685 | * A Tcl list, dynamically allocated. The caller is expected to | |
686 | * arrange for this list to be freed eventually. | |
687 | * | |
688 | * Side effects: | |
689 | * Memory is allocated. | |
690 | * | |
691 | *-------------------------------------------------------------- | |
692 | */ | |
693 | ||
694 | static char * | |
695 | FormatConfigInfo(tkwin, specPtr, widgRec) | |
696 | Tk_Window tkwin; /* Window corresponding to widget. */ | |
697 | register Tk_ConfigSpec *specPtr; /* Pointer to information describing | |
698 | * option. */ | |
699 | char *widgRec; /* Pointer to record holding current | |
700 | * values of info for widget. */ | |
701 | { | |
702 | char *argv[6], *ptr, *result; | |
703 | char buffer[200]; | |
704 | Tcl_FreeProc *freeProc = (Tcl_FreeProc *) NULL; | |
705 | ||
706 | argv[0] = specPtr->argvName; | |
707 | argv[1] = specPtr->dbName; | |
708 | argv[2] = specPtr->dbClass; | |
709 | argv[3] = specPtr->defValue; | |
710 | if (specPtr->type == TK_CONFIG_SYNONYM) { | |
711 | return Tcl_Merge(2, argv); | |
712 | } | |
713 | ptr = widgRec + specPtr->offset; | |
714 | argv[4] = ""; | |
715 | switch (specPtr->type) { | |
716 | case TK_CONFIG_BOOLEAN: | |
717 | if (*((int *) ptr) == 0) { | |
718 | argv[4] = "false"; | |
719 | } else { | |
720 | argv[4] = "true"; | |
721 | } | |
722 | break; | |
723 | case TK_CONFIG_INT: | |
724 | sprintf(buffer, "%d", *((int *) ptr)); | |
725 | argv[4] = buffer; | |
726 | break; | |
727 | case TK_CONFIG_DOUBLE: | |
728 | sprintf(buffer, "%g", *((double *) ptr)); | |
729 | argv[4] = buffer; | |
730 | break; | |
731 | case TK_CONFIG_STRING: | |
732 | argv[4] = (*(char **) ptr); | |
733 | break; | |
734 | case TK_CONFIG_UID: { | |
735 | Tk_Uid uid = *((Tk_Uid *) ptr); | |
736 | if (uid != NULL) { | |
737 | argv[4] = uid; | |
738 | } | |
739 | break; | |
740 | } | |
741 | case TK_CONFIG_COLOR: { | |
742 | XColor *colorPtr = *((XColor **) ptr); | |
743 | if (colorPtr != NULL) { | |
744 | argv[4] = Tk_NameOfColor(colorPtr); | |
745 | } | |
746 | break; | |
747 | } | |
748 | case TK_CONFIG_FONT: { | |
749 | XFontStruct *fontStructPtr = *((XFontStruct **) ptr); | |
750 | if (fontStructPtr != NULL) { | |
751 | argv[4] = Tk_NameOfFontStruct(fontStructPtr); | |
752 | } | |
753 | break; | |
754 | } | |
755 | case TK_CONFIG_BITMAP: { | |
756 | Pixmap pixmap = *((Pixmap *) ptr); | |
757 | if (pixmap != None) { | |
758 | argv[4] = Tk_NameOfBitmap(pixmap); | |
759 | } | |
760 | break; | |
761 | } | |
762 | #if defined(USE_XPM3) | |
763 | case TK_CONFIG_PIXMAP: { | |
764 | Pixmap pixmap = *((Pixmap *) ptr); | |
765 | if (pixmap != None) { | |
766 | argv[4] = Tk_NameOfPixmap(pixmap); | |
767 | } | |
768 | break; | |
769 | } | |
770 | #endif | |
771 | case TK_CONFIG_BORDER: { | |
772 | Tk_3DBorder border = *((Tk_3DBorder *) ptr); | |
773 | if (border != NULL) { | |
774 | argv[4] = Tk_NameOf3DBorder(border); | |
775 | } | |
776 | break; | |
777 | } | |
778 | case TK_CONFIG_RELIEF: | |
779 | argv[4] = Tk_NameOfRelief(*((int *) ptr)); | |
780 | break; | |
781 | case TK_CONFIG_CURSOR: | |
782 | case TK_CONFIG_ACTIVE_CURSOR: { | |
783 | Cursor cursor = *((Cursor *) ptr); | |
784 | if (cursor != None) { | |
785 | argv[4] = Tk_NameOfCursor(cursor); | |
786 | } | |
787 | break; | |
788 | } | |
789 | case TK_CONFIG_JUSTIFY: | |
790 | argv[4] = Tk_NameOfJustify(*((Tk_Justify *) ptr)); | |
791 | break; | |
792 | case TK_CONFIG_ANCHOR: | |
793 | argv[4] = Tk_NameOfAnchor(*((Tk_Anchor *) ptr)); | |
794 | break; | |
795 | case TK_CONFIG_CAP_STYLE: | |
796 | argv[4] = Tk_NameOfCapStyle(*((int *) ptr)); | |
797 | break; | |
798 | case TK_CONFIG_JOIN_STYLE: | |
799 | argv[4] = Tk_NameOfJoinStyle(*((int *) ptr)); | |
800 | break; | |
801 | case TK_CONFIG_PIXELS: | |
802 | sprintf(buffer, "%d", *((int *) ptr)); | |
803 | argv[4] = buffer; | |
804 | break; | |
805 | case TK_CONFIG_MM: | |
806 | sprintf(buffer, "%gm", *((int *) ptr)); | |
807 | argv[4] = buffer; | |
808 | break; | |
809 | case TK_CONFIG_WINDOW: { | |
810 | Tk_Window tkwin; | |
811 | ||
812 | tkwin = *((Tk_Window *) ptr); | |
813 | if (tkwin != NULL) { | |
814 | argv[4] = Tk_PathName(tkwin); | |
815 | } | |
816 | break; | |
817 | } | |
818 | case TK_CONFIG_CUSTOM: | |
819 | argv[4] = (*specPtr->customPtr->printProc)( | |
820 | specPtr->customPtr->clientData, tkwin, widgRec, | |
821 | specPtr->offset, &freeProc); | |
822 | break; | |
823 | default: | |
824 | argv[4] = "?? unknown type ??"; | |
825 | } | |
826 | if (argv[1] == NULL) { | |
827 | argv[1] = ""; | |
828 | } | |
829 | if (argv[2] == NULL) { | |
830 | argv[2] = ""; | |
831 | } | |
832 | if (argv[3] == NULL) { | |
833 | argv[3] = ""; | |
834 | } | |
835 | if (argv[4] == NULL) { | |
836 | argv[4] = ""; | |
837 | } | |
838 | result = Tcl_Merge(5, argv); | |
839 | if (freeProc != NULL) { | |
840 | if (freeProc == (Tcl_FreeProc *) free) { | |
841 | ckfree(argv[4]); | |
842 | } else { | |
843 | (*freeProc)(argv[4]); | |
844 | } | |
845 | } | |
846 | return result; | |
847 | } |