4 * This file contains the Tk_ConfigureWidget procedure.
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.
17 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkConfig.c,v 1.28 92/07/25 15:52:26 ouster Exp $ SPRITE (Berkeley)";
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!
28 * INIT - Non-zero means (char *) things have been
29 * converted to Tk_Uid's.
35 * Forward declarations for procedures defined later in this file:
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
));
48 *--------------------------------------------------------------
50 * Tk_ConfigureWidget --
52 * Process command-line options and database options to
53 * fill in fields of a widget record with resources and
57 * A standard Tcl return value. In case of an error,
58 * interp->result will hold an error message.
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.
65 *--------------------------------------------------------------
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
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. */
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
91 needFlags
= flags
& ~(TK_CONFIG_USER_BIT
- 1);
92 if (Tk_DefaultDepth(Tk_Screen(tkwin
)) == 1) {
93 hateFlags
= TK_CONFIG_COLOR_ONLY
;
95 hateFlags
= TK_CONFIG_MONO_ONLY
;
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.
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
);
109 if (specPtr
->dbClass
!= NULL
) {
110 specPtr
->dbClass
= Tk_GetUid(specPtr
->dbClass
);
112 if (specPtr
->defValue
!= NULL
) {
113 specPtr
->defValue
= Tk_GetUid(specPtr
->defValue
);
116 specPtr
->specFlags
= (specPtr
->specFlags
& ~TK_CONFIG_OPTION_SPECIFIED
)
121 * Pass two: scan through all of the arguments, processing those
122 * that match entries in the specs.
125 for ( ; argc
> 0; argc
-= 2, argv
+= 2) {
126 specPtr
= FindConfigSpec(interp
, specs
, *argv
, needFlags
, hateFlags
);
127 if (specPtr
== NULL
) {
136 Tcl_AppendResult(interp
, "value for \"", *argv
,
137 "\" missing", (char *) NULL
);
140 if (DoConfig(interp
, tkwin
, specPtr
, argv
[1], 0, widgRec
) != TCL_OK
) {
143 sprintf(msg
, "\n (processing \"%.40s\" option)",
145 Tcl_AddErrorInfo(interp
, msg
);
148 specPtr
->specFlags
|= TK_CONFIG_OPTION_SPECIFIED
;
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.
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
)) {
165 if (((specPtr
->specFlags
& needFlags
) != needFlags
)
166 || (specPtr
->specFlags
& hateFlags
)) {
170 if (specPtr
->dbName
!= NULL
) {
171 value
= Tk_GetOption(tkwin
, specPtr
->dbName
, specPtr
->dbClass
);
174 if (DoConfig(interp
, tkwin
, specPtr
, value
, 1, widgRec
) !=
178 sprintf(msg
, "\n (%s \"%.50s\" in widget \"%.50s\")",
179 "database entry for",
180 specPtr
->dbName
, Tk_PathName(tkwin
));
181 Tcl_AddErrorInfo(interp
, msg
);
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
) !=
193 "\n (%s \"%.50s\" in widget \"%.50s\")",
195 specPtr
->dbName
, Tk_PathName(tkwin
));
196 Tcl_AddErrorInfo(interp
, msg
);
208 *--------------------------------------------------------------
212 * Search through a table of configuration specs, looking for
213 * one that matches a given argvName.
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
223 *--------------------------------------------------------------
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
235 int hateFlags
; /* Flags that must NOT be present in
238 register Tk_ConfigSpec
*specPtr
;
239 register char c
; /* First character of current argument. */
240 Tk_ConfigSpec
*matchPtr
; /* Matching spec, or NULL. */
244 length
= strlen(argvName
);
246 for (specPtr
= specs
; specPtr
->type
!= TK_CONFIG_END
; specPtr
++) {
247 if (specPtr
->argvName
== NULL
) {
250 if ((specPtr
->argvName
[1] != c
)
251 || (strncmp(specPtr
->argvName
, argvName
, length
) != 0)) {
254 if (((specPtr
->specFlags
& needFlags
) != needFlags
)
255 || (specPtr
->specFlags
& hateFlags
)) {
258 if (specPtr
->argvName
[length
] == 0) {
262 if (matchPtr
!= NULL
) {
263 Tcl_AppendResult(interp
, "ambiguous option \"", argvName
,
264 "\"", (char *) NULL
);
265 return (Tk_ConfigSpec
*) NULL
;
270 if (matchPtr
== NULL
) {
271 Tcl_AppendResult(interp
, "unknown option \"", argvName
,
272 "\"", (char *) NULL
);
273 return (Tk_ConfigSpec
*) NULL
;
277 * Found a matching entry. If it's a synonym, then find the
278 * entry that it's a synonym for.
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
;
291 if ((specPtr
->dbName
== matchPtr
->dbName
)
292 && (specPtr
->type
!= TK_CONFIG_SYNONYM
)
293 && ((specPtr
->specFlags
& needFlags
) == needFlags
)
294 && !(specPtr
->specFlags
& hateFlags
)) {
303 *--------------------------------------------------------------
307 * This procedure applies a single configuration option
308 * to a widget record.
311 * A standard Tcl return value.
314 * WidgRec is modified as indicated by specPtr and value.
315 * The old value is recycled, if that is appropriate for
318 *--------------------------------------------------------------
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
339 if ((*value
== 0) && (specPtr
->specFlags
& TK_CONFIG_NULL_OK
)) {
344 ptr
= widgRec
+ specPtr
->offset
;
345 switch (specPtr
->type
) {
346 case TK_CONFIG_BOOLEAN
:
347 if (Tcl_GetBoolean(interp
, value
, (int *) ptr
) != TCL_OK
) {
352 if (Tcl_GetInt(interp
, value
, (int *) ptr
) != TCL_OK
) {
356 case TK_CONFIG_DOUBLE
:
357 if (Tcl_GetDouble(interp
, value
, (double *) ptr
) != TCL_OK
) {
361 case TK_CONFIG_STRING
: {
367 new = (char *) ckalloc((unsigned) (strlen(value
) + 1));
370 old
= *((char **) ptr
);
374 *((char **) ptr
) = new;
379 *((Tk_Uid
*) ptr
) = NULL
;
381 uid
= valueIsUid
? (Tk_Uid
) value
: Tk_GetUid(value
);
382 *((Tk_Uid
*) ptr
) = uid
;
385 case TK_CONFIG_COLOR
: {
386 XColor
*newPtr
, *oldPtr
;
391 uid
= valueIsUid
? (Tk_Uid
) value
: Tk_GetUid(value
);
392 newPtr
= Tk_GetColor(interp
, tkwin
, (Colormap
) None
, uid
);
393 if (newPtr
== NULL
) {
397 oldPtr
= *((XColor
**) ptr
);
398 if (oldPtr
!= NULL
) {
399 Tk_FreeColor(oldPtr
);
401 *((XColor
**) ptr
) = newPtr
;
404 case TK_CONFIG_FONT
: {
405 XFontStruct
*newPtr
, *oldPtr
;
410 uid
= valueIsUid
? (Tk_Uid
) value
: Tk_GetUid(value
);
411 newPtr
= Tk_GetFontStruct(interp
, tkwin
, uid
);
412 if (newPtr
== NULL
) {
416 oldPtr
= *((XFontStruct
**) ptr
);
417 if (oldPtr
!= NULL
) {
418 Tk_FreeFontStruct(oldPtr
);
420 *((XFontStruct
**) ptr
) = newPtr
;
423 case TK_CONFIG_BITMAP
: {
429 uid
= valueIsUid
? (Tk_Uid
) value
: Tk_GetUid(value
);
430 new = Tk_GetBitmap(interp
, tkwin
, uid
);
435 old
= *((Pixmap
*) ptr
);
439 *((Pixmap
*) ptr
) = new;
442 #if defined(USE_XPM3)
443 case TK_CONFIG_PIXMAP
: {
449 uid
= valueIsUid
? (Tk_Uid
) value
: Tk_GetUid(value
);
450 new = Tk_GetPixmap(interp
, tkwin
, uid
);
455 old
= *((Pixmap
*) ptr
);
459 *((Pixmap
*) ptr
) = new;
463 case TK_CONFIG_BORDER
: {
464 Tk_3DBorder
new, old
;
469 uid
= valueIsUid
? (Tk_Uid
) value
: Tk_GetUid(value
);
470 new = Tk_Get3DBorder(interp
, tkwin
, (Colormap
) None
, uid
);
475 old
= *((Tk_3DBorder
*) ptr
);
477 Tk_Free3DBorder(old
);
479 *((Tk_3DBorder
*) ptr
) = new;
482 case TK_CONFIG_RELIEF
:
483 uid
= valueIsUid
? (Tk_Uid
) value
: Tk_GetUid(value
);
484 if (Tk_GetRelief(interp
, uid
, (int *) ptr
) != TCL_OK
) {
488 case TK_CONFIG_CURSOR
:
489 case TK_CONFIG_ACTIVE_CURSOR
: {
495 uid
= valueIsUid
? (Tk_Uid
) value
: Tk_GetUid(value
);
496 new = Tk_GetCursor(interp
, tkwin
, uid
);
501 old
= *((Cursor
*) ptr
);
505 *((Cursor
*) ptr
) = new;
506 if (specPtr
->type
== TK_CONFIG_ACTIVE_CURSOR
) {
507 Tk_DefineCursor(tkwin
, new);
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
) {
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
) {
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
) {
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
) {
535 case TK_CONFIG_PIXELS
:
536 if (Tk_GetPixels(interp
, tkwin
, value
, (int *) ptr
)
542 if (Tk_GetScreenMM(interp
, tkwin
, value
, (double *) ptr
)
547 case TK_CONFIG_WINDOW
: {
553 tkwin2
= Tk_NameToWindow(interp
, value
, tkwin
);
554 if (tkwin2
== NULL
) {
558 *((Tk_Window
*) ptr
) = tkwin2
;
561 case TK_CONFIG_CUSTOM
:
562 if ((*specPtr
->customPtr
->parseProc
)(
563 specPtr
->customPtr
->clientData
, interp
, tkwin
,
564 value
, widgRec
, specPtr
->offset
) != TCL_OK
) {
569 sprintf(interp
->result
, "bad config table: unknown type %d",
575 } while ((specPtr
->argvName
== NULL
) && (specPtr
->type
!= TK_CONFIG_END
));
580 *--------------------------------------------------------------
582 * Tk_ConfigureInfo --
584 * Return information about the configuration options
585 * for a window, and their current values.
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).
606 *--------------------------------------------------------------
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. */
623 register Tk_ConfigSpec
*specPtr
;
624 int needFlags
, hateFlags
;
628 needFlags
= flags
& ~(TK_CONFIG_USER_BIT
- 1);
629 if (Tk_DefaultDepth(Tk_Screen(tkwin
)) == 1) {
630 hateFlags
= TK_CONFIG_COLOR_ONLY
;
632 hateFlags
= TK_CONFIG_MONO_ONLY
;
636 * If information is only wanted for a single configuration
637 * spec, then handle that one spec specially.
640 Tcl_SetResult(interp
, (char *) NULL
, TCL_STATIC
);
641 if (argvName
!= NULL
) {
642 specPtr
= FindConfigSpec(interp
, specs
, argvName
, needFlags
,
644 if (specPtr
== NULL
) {
647 interp
->result
= FormatConfigInfo(tkwin
, specPtr
, widgRec
);
648 interp
->freeProc
= TCL_DYNAMIC
;
653 * Loop through all the specs, creating a big list with all
657 for (specPtr
= specs
; specPtr
->type
!= TK_CONFIG_END
; specPtr
++) {
658 if ((argvName
!= NULL
) && (specPtr
->argvName
!= argvName
)) {
661 if (((specPtr
->specFlags
& needFlags
) != needFlags
)
662 || (specPtr
->specFlags
& hateFlags
)) {
665 if (specPtr
->argvName
== NULL
) {
668 list
= FormatConfigInfo(tkwin
, specPtr
, widgRec
);
669 Tcl_AppendResult(interp
, leader
, list
, "}", (char *) NULL
);
677 *--------------------------------------------------------------
679 * FormatConfigInfo --
681 * Create a valid Tcl list holding the configuration information
682 * for a single configuration option.
685 * A Tcl list, dynamically allocated. The caller is expected to
686 * arrange for this list to be freed eventually.
689 * Memory is allocated.
691 *--------------------------------------------------------------
695 FormatConfigInfo(tkwin
, specPtr
, widgRec
)
696 Tk_Window tkwin
; /* Window corresponding to widget. */
697 register Tk_ConfigSpec
*specPtr
; /* Pointer to information describing
699 char *widgRec
; /* Pointer to record holding current
700 * values of info for widget. */
702 char *argv
[6], *ptr
, *result
;
704 Tcl_FreeProc
*freeProc
= (Tcl_FreeProc
*) NULL
;
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
);
713 ptr
= widgRec
+ specPtr
->offset
;
715 switch (specPtr
->type
) {
716 case TK_CONFIG_BOOLEAN
:
717 if (*((int *) ptr
) == 0) {
724 sprintf(buffer
, "%d", *((int *) ptr
));
727 case TK_CONFIG_DOUBLE
:
728 sprintf(buffer
, "%g", *((double *) ptr
));
731 case TK_CONFIG_STRING
:
732 argv
[4] = (*(char **) ptr
);
734 case TK_CONFIG_UID
: {
735 Tk_Uid uid
= *((Tk_Uid
*) ptr
);
741 case TK_CONFIG_COLOR
: {
742 XColor
*colorPtr
= *((XColor
**) ptr
);
743 if (colorPtr
!= NULL
) {
744 argv
[4] = Tk_NameOfColor(colorPtr
);
748 case TK_CONFIG_FONT
: {
749 XFontStruct
*fontStructPtr
= *((XFontStruct
**) ptr
);
750 if (fontStructPtr
!= NULL
) {
751 argv
[4] = Tk_NameOfFontStruct(fontStructPtr
);
755 case TK_CONFIG_BITMAP
: {
756 Pixmap pixmap
= *((Pixmap
*) ptr
);
757 if (pixmap
!= None
) {
758 argv
[4] = Tk_NameOfBitmap(pixmap
);
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
);
771 case TK_CONFIG_BORDER
: {
772 Tk_3DBorder border
= *((Tk_3DBorder
*) ptr
);
773 if (border
!= NULL
) {
774 argv
[4] = Tk_NameOf3DBorder(border
);
778 case TK_CONFIG_RELIEF
:
779 argv
[4] = Tk_NameOfRelief(*((int *) ptr
));
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
);
789 case TK_CONFIG_JUSTIFY
:
790 argv
[4] = Tk_NameOfJustify(*((Tk_Justify
*) ptr
));
792 case TK_CONFIG_ANCHOR
:
793 argv
[4] = Tk_NameOfAnchor(*((Tk_Anchor
*) ptr
));
795 case TK_CONFIG_CAP_STYLE
:
796 argv
[4] = Tk_NameOfCapStyle(*((int *) ptr
));
798 case TK_CONFIG_JOIN_STYLE
:
799 argv
[4] = Tk_NameOfJoinStyle(*((int *) ptr
));
801 case TK_CONFIG_PIXELS
:
802 sprintf(buffer
, "%d", *((int *) ptr
));
806 sprintf(buffer
, "%gm", *((int *) ptr
));
809 case TK_CONFIG_WINDOW
: {
812 tkwin
= *((Tk_Window
*) ptr
);
814 argv
[4] = Tk_PathName(tkwin
);
818 case TK_CONFIG_CUSTOM
:
819 argv
[4] = (*specPtr
->customPtr
->printProc
)(
820 specPtr
->customPtr
->clientData
, tkwin
, widgRec
,
821 specPtr
->offset
, &freeProc
);
824 argv
[4] = "?? unknown type ??";
826 if (argv
[1] == NULL
) {
829 if (argv
[2] == NULL
) {
832 if (argv
[3] == NULL
) {
835 if (argv
[4] == NULL
) {
838 result
= Tcl_Merge(5, argv
);
839 if (freeProc
!= NULL
) {
840 if (freeProc
== (Tcl_FreeProc
*) free
) {
843 (*freeProc
)(argv
[4]);