4 * This file contains the Tk_ConfigureWidget function. THIS FILE IS HERE
5 * FOR BACKWARD COMPATIBILITY; THE NEW CONFIGURATION PACKAGE SHOULD BE
6 * USED FOR NEW PROJECTS.
8 * Copyright (c) 1990-1994 The Regents of the University of California.
9 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11 * See the file "license.terms" for information on usage and redistribution of
12 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 * Values for "flags" field of Tk_ConfigSpec structures. Be sure to coordinate
19 * these values with those defined in tk.h (TK_CONFIG_COLOR_ONLY, etc.) There
20 * must not be overlap!
22 * INIT - Non-zero means (char *) things have been converted to
29 * Forward declarations for functions defined later in this file:
32 static int DoConfig(Tcl_Interp *interp, Tk_Window tkwin,
33 Tk_ConfigSpec *specPtr, Tk_Uid value,
34 int valueIsUid, char *widgRec);
35 static Tk_ConfigSpec * FindConfigSpec(Tcl_Interp *interp,
36 Tk_ConfigSpec *specs, const char *argvName,
37 int needFlags, int hateFlags);
38 static char * FormatConfigInfo(Tcl_Interp *interp, Tk_Window tkwin,
39 const Tk_ConfigSpec *specPtr, char *widgRec);
40 static const char * FormatConfigValue(Tcl_Interp *interp, Tk_Window tkwin,
41 const Tk_ConfigSpec *specPtr, char *widgRec,
42 char *buffer, Tcl_FreeProc **freeProcPtr);
43 static Tk_ConfigSpec * GetCachedSpecs(Tcl_Interp *interp,
44 const Tk_ConfigSpec *staticSpecs);
45 static void DeleteSpecCacheTable(ClientData clientData,
49 *--------------------------------------------------------------
51 * Tk_ConfigureWidget --
53 * Process command-line options and database options to fill in fields of
54 * a widget record with resources and other parameters.
57 * A standard Tcl return value. In case of an error, the interp's result
58 * will hold an error message.
61 * The fields of widgRec get filled in with information from argc/argv
62 * and the option database. Old information in widgRec's fields gets
63 * recycled. A copy of the spec-table is taken with (some of) the char*
64 * fields converted into Tk_Uid fields; this copy will be released when
65 * the interpreter terminates.
67 *--------------------------------------------------------------
72 Tcl_Interp *interp, /* Interpreter for error reporting. */
73 Tk_Window tkwin, /* Window containing widget (needed to set up
75 const Tk_ConfigSpec *specs, /* Describes legal options. */
76 int argc, /* Number of elements in argv. */
77 const char **argv, /* Command-line options. */
78 char *widgRec, /* Record whose fields are to be modified.
79 * Values must be properly initialized. */
80 int flags) /* Used to specify additional flags that must
81 * be present in config specs for them to be
82 * considered. Also, may have
83 * TK_CONFIG_ARGV_ONLY set. */
85 Tk_ConfigSpec *specPtr, *staticSpecs;
86 Tk_Uid value; /* Value of option from database. */
87 int needFlags; /* Specs must contain this set of flags or
88 * else they are not considered. */
89 int hateFlags; /* If a spec contains any bits here, it's not
94 * Either we're not really in Tk, or the main window was destroyed and
95 * we're on our way out of the application
98 Tcl_SetObjResult(interp, Tcl_NewStringObj("NULL main window", -1));
99 Tcl_SetErrorCode(interp, "TK", "NO_MAIN_WINDOW", NULL);
103 needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
104 if (Tk_Depth(tkwin) <= 1) {
105 hateFlags = TK_CONFIG_COLOR_ONLY;
107 hateFlags = TK_CONFIG_MONO_ONLY;
111 * Get the build of the config for this interpreter.
114 staticSpecs = GetCachedSpecs(interp, specs);
116 for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) {
117 specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED;
121 * Pass one: scan through all of the arguments, processing those that
122 * match entries in the specs.
125 for ( ; argc > 0; argc -= 2, argv += 2) {
128 if (flags & TK_CONFIG_OBJS) {
129 arg = Tcl_GetString((Tcl_Obj *) *argv);
133 specPtr = FindConfigSpec(interp, staticSpecs, arg, needFlags, hateFlags);
134 if (specPtr == NULL) {
143 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
144 "value for \"%s\" missing", arg));
145 Tcl_SetErrorCode(interp, "TK", "VALUE_MISSING", NULL);
148 if (flags & TK_CONFIG_OBJS) {
149 arg = Tcl_GetString((Tcl_Obj *) argv[1]);
153 if (DoConfig(interp, tkwin, specPtr, arg, 0, widgRec) != TCL_OK) {
154 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
155 "\n (processing \"%.40s\" option)",specPtr->argvName));
158 if (!(flags & TK_CONFIG_ARGV_ONLY)) {
159 specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED;
164 * Pass two: scan through all of the specs again; if no command-line
165 * argument matched a spec, then check for info in the option database.
166 * If there was nothing in the database, then use the default.
169 if (!(flags & TK_CONFIG_ARGV_ONLY)) {
170 for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) {
171 if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED)
172 || (specPtr->argvName == NULL)
173 || (specPtr->type == TK_CONFIG_SYNONYM)) {
176 if (((specPtr->specFlags & needFlags) != needFlags)
177 || (specPtr->specFlags & hateFlags)) {
181 if (specPtr->dbName != NULL) {
182 value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass);
185 if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
187 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
188 "\n (%s \"%.50s\" in widget \"%.50s\")",
189 "database entry for", specPtr->dbName,
190 Tk_PathName(tkwin)));
194 if (specPtr->defValue != NULL) {
195 value = Tk_GetUid(specPtr->defValue);
199 if ((value != NULL) && !(specPtr->specFlags
200 & TK_CONFIG_DONT_SET_DEFAULT)) {
201 if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
203 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
204 "\n (%s \"%.50s\" in widget \"%.50s\")",
205 "default value for", specPtr->dbName,
206 Tk_PathName(tkwin)));
218 *--------------------------------------------------------------
222 * Search through a table of configuration specs, looking for one that
223 * matches a given argvName.
226 * The return value is a pointer to the matching entry, or NULL if
227 * nothing matched. In that case an error message is left in the interp's
233 *--------------------------------------------------------------
236 static Tk_ConfigSpec *
238 Tcl_Interp *interp, /* Used for reporting errors. */
239 Tk_ConfigSpec *specs, /* Pointer to table of configuration
240 * specifications for a widget. */
241 const char *argvName, /* Name (suitable for use in a "config"
242 * command) identifying particular option. */
243 int needFlags, /* Flags that must be present in matching
245 int hateFlags) /* Flags that must NOT be present in matching
248 Tk_ConfigSpec *specPtr;
249 char c; /* First character of current argument. */
250 Tk_ConfigSpec *matchPtr; /* Matching spec, or NULL. */
254 length = strlen(argvName);
256 for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
257 if (specPtr->argvName == NULL) {
260 if ((specPtr->argvName[1] != c)
261 || (strncmp(specPtr->argvName, argvName, length) != 0)) {
264 if (((specPtr->specFlags & needFlags) != needFlags)
265 || (specPtr->specFlags & hateFlags)) {
268 if (specPtr->argvName[length] == 0) {
272 if (matchPtr != NULL) {
273 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
274 "ambiguous option \"%s\"", argvName));
275 Tcl_SetErrorCode(interp, "TK", "LOOKUP", "OPTION", argvName,NULL);
281 if (matchPtr == NULL) {
282 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
283 "unknown option \"%s\"", argvName));
284 Tcl_SetErrorCode(interp, "TK", "LOOKUP", "OPTION", argvName, NULL);
289 * Found a matching entry. If it's a synonym, then find the entry that
290 * it's a synonym for.
295 if (specPtr->type == TK_CONFIG_SYNONYM) {
296 for (specPtr = specs; ; specPtr++) {
297 if (specPtr->type == TK_CONFIG_END) {
298 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
299 "couldn't find synonym for option \"%s\"",
301 Tcl_SetErrorCode(interp, "TK", "LOOKUP", "OPTION", argvName,
305 if ((specPtr->dbName == matchPtr->dbName)
306 && (specPtr->type != TK_CONFIG_SYNONYM)
307 && ((specPtr->specFlags & needFlags) == needFlags)
308 && !(specPtr->specFlags & hateFlags)) {
317 *--------------------------------------------------------------
321 * This function applies a single configuration option to a widget
325 * A standard Tcl return value.
328 * WidgRec is modified as indicated by specPtr and value. The old value
329 * is recycled, if that is appropriate for the value type.
331 *--------------------------------------------------------------
336 Tcl_Interp *interp, /* Interpreter for error reporting. */
337 Tk_Window tkwin, /* Window containing widget (needed to set up
339 Tk_ConfigSpec *specPtr, /* Specifier to apply. */
340 Tk_Uid value, /* Value to use to fill in widgRec. */
341 int valueIsUid, /* Non-zero means value is a Tk_Uid; zero
342 * means it's an ordinary string. */
343 char *widgRec) /* Record whose fields are to be modified.
344 * Values must be properly initialized. */
351 if ((*value == 0) && (specPtr->specFlags & TK_CONFIG_NULL_OK)) {
356 ptr = widgRec + specPtr->offset;
357 switch (specPtr->type) {
358 case TK_CONFIG_BOOLEAN:
359 if (Tcl_GetBoolean(interp, value, (int *) ptr) != TCL_OK) {
364 if (Tcl_GetInt(interp, value, (int *) ptr) != TCL_OK) {
368 case TK_CONFIG_DOUBLE:
369 if (Tcl_GetDouble(interp, value, (double *) ptr) != TCL_OK) {
373 case TK_CONFIG_STRING: {
374 char *oldStr, *newStr;
379 newStr = (char *)ckalloc(strlen(value) + 1);
380 strcpy(newStr, value);
382 oldStr = *((char **) ptr);
383 if (oldStr != NULL) {
386 *((char **) ptr) = newStr;
391 *((Tk_Uid *) ptr) = NULL;
393 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
394 *((Tk_Uid *) ptr) = uid;
397 case TK_CONFIG_COLOR: {
398 XColor *newPtr, *oldPtr;
403 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
404 newPtr = Tk_GetColor(interp, tkwin, uid);
405 if (newPtr == NULL) {
409 oldPtr = *((XColor **) ptr);
410 if (oldPtr != NULL) {
411 Tk_FreeColor(oldPtr);
413 *((XColor **) ptr) = newPtr;
416 case TK_CONFIG_FONT: {
422 newFont = Tk_GetFont(interp, tkwin, value);
423 if (newFont == NULL) {
427 Tk_FreeFont(*((Tk_Font *) ptr));
428 *((Tk_Font *) ptr) = newFont;
431 case TK_CONFIG_BITMAP: {
432 Pixmap newBmp, oldBmp;
437 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
438 newBmp = Tk_GetBitmap(interp, tkwin, uid);
439 if (newBmp == None) {
443 oldBmp = *((Pixmap *) ptr);
444 if (oldBmp != None) {
445 Tk_FreeBitmap(Tk_Display(tkwin), oldBmp);
447 *((Pixmap *) ptr) = newBmp;
450 case TK_CONFIG_BORDER: {
451 Tk_3DBorder newBorder, oldBorder;
456 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
457 newBorder = Tk_Get3DBorder(interp, tkwin, uid);
458 if (newBorder == NULL) {
462 oldBorder = *((Tk_3DBorder *) ptr);
463 if (oldBorder != NULL) {
464 Tk_Free3DBorder(oldBorder);
466 *((Tk_3DBorder *) ptr) = newBorder;
469 case TK_CONFIG_RELIEF:
470 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
471 if (Tk_GetRelief(interp, uid, (int *) ptr) != TCL_OK) {
475 case TK_CONFIG_CURSOR:
476 case TK_CONFIG_ACTIVE_CURSOR: {
477 Tk_Cursor newCursor, oldCursor;
482 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
483 newCursor = Tk_GetCursor(interp, tkwin, uid);
484 if (newCursor == NULL) {
488 oldCursor = *((Tk_Cursor *) ptr);
489 if (oldCursor != NULL) {
490 Tk_FreeCursor(Tk_Display(tkwin), oldCursor);
492 *((Tk_Cursor *) ptr) = newCursor;
493 if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) {
494 Tk_DefineCursor(tkwin, newCursor);
498 case TK_CONFIG_JUSTIFY:
499 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
500 if (Tk_GetJustify(interp, uid, (Tk_Justify *) ptr) != TCL_OK) {
504 case TK_CONFIG_ANCHOR:
505 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
506 if (Tk_GetAnchor(interp, uid, (Tk_Anchor *) ptr) != TCL_OK) {
510 case TK_CONFIG_CAP_STYLE:
511 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
512 if (Tk_GetCapStyle(interp, uid, (int *) ptr) != TCL_OK) {
516 case TK_CONFIG_JOIN_STYLE:
517 uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
518 if (Tk_GetJoinStyle(interp, uid, (int *) ptr) != TCL_OK) {
522 case TK_CONFIG_PIXELS:
523 if (Tk_GetPixels(interp, tkwin, value, (int *) ptr)
529 if (Tk_GetScreenMM(interp, tkwin, value, (double*)ptr) != TCL_OK) {
533 case TK_CONFIG_WINDOW: {
539 tkwin2 = Tk_NameToWindow(interp, value, tkwin);
540 if (tkwin2 == NULL) {
544 *((Tk_Window *) ptr) = tkwin2;
547 case TK_CONFIG_CUSTOM:
548 if (specPtr->customPtr->parseProc(specPtr->customPtr->clientData,
549 interp, tkwin, value, widgRec, specPtr->offset)!=TCL_OK) {
554 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
555 "bad config table: unknown type %d", specPtr->type));
556 Tcl_SetErrorCode(interp, "TK", "BAD_CONFIG", NULL);
560 } while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END));
565 *--------------------------------------------------------------
567 * Tk_ConfigureInfo --
569 * Return information about the configuration options for a window, and
570 * their current values.
573 * Always returns TCL_OK. The interp's result will be modified hold a
574 * description of either a single configuration option available for
575 * "widgRec" via "specs", or all the configuration options available. In
576 * the "all" case, the result will available for "widgRec" via "specs".
577 * The result will be a list, each of whose entries describes one option.
578 * Each entry will itself be a list containing the option's name for use
579 * on command lines, database name, database class, default value, and
580 * current value (empty string if none). For options that are synonyms,
581 * the list will contain only two values: name and synonym name. If the
582 * "name" argument is non-NULL, then the only information returned is
583 * that for the named argument (i.e. the corresponding entry in the
584 * overall list is returned).
589 *--------------------------------------------------------------
594 Tcl_Interp *interp, /* Interpreter for error reporting. */
595 Tk_Window tkwin, /* Window corresponding to widgRec. */
596 const Tk_ConfigSpec *specs, /* Describes legal options. */
597 char *widgRec, /* Record whose fields contain current values
599 const char *argvName, /* If non-NULL, indicates a single option
600 * whose info is to be returned. Otherwise
601 * info is returned for all options. */
602 int flags) /* Used to specify additional flags that must
603 * be present in config specs for them to be
606 Tk_ConfigSpec *specPtr, *staticSpecs;
607 int needFlags, hateFlags;
609 const char *leader = "{";
611 needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
612 if (Tk_Depth(tkwin) <= 1) {
613 hateFlags = TK_CONFIG_COLOR_ONLY;
615 hateFlags = TK_CONFIG_MONO_ONLY;
619 * Get the build of the config for this interpreter.
622 staticSpecs = GetCachedSpecs(interp, specs);
625 * If information is only wanted for a single configuration spec, then
626 * handle that one spec specially.
629 Tcl_ResetResult(interp);
630 if (argvName != NULL) {
631 specPtr = FindConfigSpec(interp, staticSpecs, argvName, needFlags,
633 if (specPtr == NULL) {
636 list = FormatConfigInfo(interp, tkwin, specPtr, widgRec);
637 Tcl_SetObjResult(interp, Tcl_NewStringObj(list, -1));
643 * Loop through all the specs, creating a big list with all their
647 for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) {
648 if ((argvName != NULL) && (specPtr->argvName != argvName)) {
651 if (((specPtr->specFlags & needFlags) != needFlags)
652 || (specPtr->specFlags & hateFlags)) {
655 if (specPtr->argvName == NULL) {
658 list = FormatConfigInfo(interp, tkwin, specPtr, widgRec);
659 Tcl_AppendResult(interp, leader, list, "}", NULL);
667 *--------------------------------------------------------------
669 * FormatConfigInfo --
671 * Create a valid Tcl list holding the configuration information for a
672 * single configuration option.
675 * A Tcl list, dynamically allocated. The caller is expected to arrange
676 * for this list to be freed eventually.
679 * Memory is allocated.
681 *--------------------------------------------------------------
686 Tcl_Interp *interp, /* Interpreter to use for things like
687 * floating-point precision. */
688 Tk_Window tkwin, /* Window corresponding to widget. */
689 const Tk_ConfigSpec *specPtr,
690 /* Pointer to information describing
692 char *widgRec) /* Pointer to record holding current values of
693 * info for widget. */
698 Tcl_FreeProc *freeProc = NULL;
700 argv[0] = specPtr->argvName;
701 argv[1] = specPtr->dbName;
702 argv[2] = specPtr->dbClass;
703 argv[3] = specPtr->defValue;
704 if (specPtr->type == TK_CONFIG_SYNONYM) {
705 return Tcl_Merge(2, argv);
707 argv[4] = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer,
709 if (argv[1] == NULL) {
712 if (argv[2] == NULL) {
715 if (argv[3] == NULL) {
718 if (argv[4] == NULL) {
721 result = Tcl_Merge(5, argv);
722 if (freeProc != NULL) {
723 if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) {
724 ckfree((char *) argv[4]);
726 freeProc((char *) argv[4]);
733 *----------------------------------------------------------------------
735 * FormatConfigValue --
737 * This function formats the current value of a configuration option.
740 * The return value is the formatted value of the option given by specPtr
741 * and widgRec. If the value is static, so that it need not be freed,
742 * *freeProcPtr will be set to NULL; otherwise *freeProcPtr will be set
743 * to the address of a function to free the result, and the caller must
744 * invoke this function when it is finished with the result.
749 *----------------------------------------------------------------------
754 Tcl_Interp *interp, /* Interpreter for use in real conversions. */
755 Tk_Window tkwin, /* Window corresponding to widget. */
756 const Tk_ConfigSpec *specPtr, /* Pointer to information describing option.
757 * Must not point to a synonym option. */
758 char *widgRec, /* Pointer to record holding current values of
759 * info for widget. */
760 char *buffer, /* Static buffer to use for small values.
761 * Must have at least 200 bytes of storage. */
762 Tcl_FreeProc **freeProcPtr) /* Pointer to word to fill in with address of
763 * function to free the result, or NULL if
764 * result is static. */
766 const char *ptr, *result;
769 ptr = widgRec + specPtr->offset;
771 switch (specPtr->type) {
772 case TK_CONFIG_BOOLEAN:
773 if (*((int *) ptr) == 0) {
780 sprintf(buffer, "%d", *((int *) ptr));
783 case TK_CONFIG_DOUBLE:
784 Tcl_PrintDouble(interp, *((double *) ptr), buffer);
787 case TK_CONFIG_STRING:
788 result = (*(char **) ptr);
789 if (result == NULL) {
793 case TK_CONFIG_UID: {
794 Tk_Uid uid = *((Tk_Uid *) ptr);
801 case TK_CONFIG_COLOR: {
802 XColor *colorPtr = *((XColor **) ptr);
804 if (colorPtr != NULL) {
805 result = Tk_NameOfColor(colorPtr);
809 case TK_CONFIG_FONT: {
810 Tk_Font tkfont = *((Tk_Font *) ptr);
812 if (tkfont != NULL) {
813 result = Tk_NameOfFont(tkfont);
817 case TK_CONFIG_BITMAP: {
818 Pixmap pixmap = *((Pixmap *) ptr);
820 if (pixmap != None) {
821 result = Tk_NameOfBitmap(Tk_Display(tkwin), pixmap);
825 case TK_CONFIG_BORDER: {
826 Tk_3DBorder border = *((Tk_3DBorder *) ptr);
828 if (border != NULL) {
829 result = Tk_NameOf3DBorder(border);
833 case TK_CONFIG_RELIEF:
834 result = Tk_NameOfRelief(*((int *) ptr));
836 case TK_CONFIG_CURSOR:
837 case TK_CONFIG_ACTIVE_CURSOR: {
838 Tk_Cursor cursor = *((Tk_Cursor *) ptr);
840 if (cursor != NULL) {
841 result = Tk_NameOfCursor(Tk_Display(tkwin), cursor);
845 case TK_CONFIG_JUSTIFY:
846 result = Tk_NameOfJustify(*((Tk_Justify *) ptr));
848 case TK_CONFIG_ANCHOR:
849 result = Tk_NameOfAnchor(*((Tk_Anchor *) ptr));
851 case TK_CONFIG_CAP_STYLE:
852 result = Tk_NameOfCapStyle(*((int *) ptr));
854 case TK_CONFIG_JOIN_STYLE:
855 result = Tk_NameOfJoinStyle(*((int *) ptr));
857 case TK_CONFIG_PIXELS:
858 sprintf(buffer, "%d", *((int *) ptr));
862 Tcl_PrintDouble(interp, *((double *) ptr), buffer);
865 case TK_CONFIG_WINDOW: {
866 tkwin = *((Tk_Window *) ptr);
868 result = Tk_PathName(tkwin);
872 case TK_CONFIG_CUSTOM:
873 result = specPtr->customPtr->printProc(specPtr->customPtr->clientData,
874 tkwin, widgRec, specPtr->offset, freeProcPtr);
877 result = "?? unknown type ??";
883 *----------------------------------------------------------------------
885 * Tk_ConfigureValue --
887 * This function returns the current value of a configuration option for
891 * The return value is a standard Tcl completion code (TCL_OK or
892 * TCL_ERROR). The interp's result will be set to hold either the value
893 * of the option given by argvName (if TCL_OK is returned) or an error
894 * message (if TCL_ERROR is returned).
899 *----------------------------------------------------------------------
904 Tcl_Interp *interp, /* Interpreter for error reporting. */
905 Tk_Window tkwin, /* Window corresponding to widgRec. */
906 const Tk_ConfigSpec *specs, /* Describes legal options. */
907 char *widgRec, /* Record whose fields contain current values
909 const char *argvName, /* Gives the command-line name for the option
910 * whose value is to be returned. */
911 int flags) /* Used to specify additional flags that must
912 * be present in config specs for them to be
915 Tk_ConfigSpec *specPtr;
916 int needFlags, hateFlags;
917 Tcl_FreeProc *freeProc;
921 needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
922 if (Tk_Depth(tkwin) <= 1) {
923 hateFlags = TK_CONFIG_COLOR_ONLY;
925 hateFlags = TK_CONFIG_MONO_ONLY;
929 * Get the build of the config for this interpreter.
932 specPtr = GetCachedSpecs(interp, specs);
934 specPtr = FindConfigSpec(interp, specPtr, argvName, needFlags, hateFlags);
935 if (specPtr == NULL) {
938 result = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer,
940 Tcl_SetObjResult(interp, Tcl_NewStringObj(result, -1));
941 if (freeProc != NULL) {
942 if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) {
943 ckfree((char *) result);
945 freeProc((char *) result);
952 *----------------------------------------------------------------------
956 * Free up all resources associated with configuration options.
962 * Any resource in widgRec that is controlled by a configuration option
963 * (e.g. a Tk_3DBorder or XColor) is freed in the appropriate fashion.
966 * Since this is not looking anything up, this uses the static version of
969 *----------------------------------------------------------------------
974 const Tk_ConfigSpec *specs, /* Describes legal options. */
975 char *widgRec, /* Record whose fields contain current values
977 Display *display, /* X display; needed for freeing some
979 int needFlags) /* Used to specify additional flags that must
980 * be present in config specs for them to be
983 const Tk_ConfigSpec *specPtr;
986 for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
987 if ((specPtr->specFlags & needFlags) != needFlags) {
990 ptr = widgRec + specPtr->offset;
991 switch (specPtr->type) {
992 case TK_CONFIG_STRING:
993 if (*((char **) ptr) != NULL) {
994 ckfree(*((char **) ptr));
995 *((char **) ptr) = NULL;
998 case TK_CONFIG_COLOR:
999 if (*((XColor **) ptr) != NULL) {
1000 Tk_FreeColor(*((XColor **) ptr));
1001 *((XColor **) ptr) = NULL;
1004 case TK_CONFIG_FONT:
1005 Tk_FreeFont(*((Tk_Font *) ptr));
1006 *((Tk_Font *) ptr) = NULL;
1008 case TK_CONFIG_BITMAP:
1009 if (*((Pixmap *) ptr) != None) {
1010 Tk_FreeBitmap(display, *((Pixmap *) ptr));
1011 *((Pixmap *) ptr) = None;
1014 case TK_CONFIG_BORDER:
1015 if (*((Tk_3DBorder *) ptr) != NULL) {
1016 Tk_Free3DBorder(*((Tk_3DBorder *) ptr));
1017 *((Tk_3DBorder *) ptr) = NULL;
1020 case TK_CONFIG_CURSOR:
1021 case TK_CONFIG_ACTIVE_CURSOR:
1022 if (*((Tk_Cursor *) ptr) != NULL) {
1023 Tk_FreeCursor(display, *((Tk_Cursor *) ptr));
1024 *((Tk_Cursor *) ptr) = NULL;
1031 *--------------------------------------------------------------
1035 * Returns a writable per-interpreter (and hence thread-local) copy of
1036 * the given spec-table with (some of) the char* fields converted into
1037 * Tk_Uid fields; this copy will be released when the interpreter
1038 * terminates (during AssocData cleanup).
1041 * A pointer to the copied table.
1044 * The conversion to Tk_Uid is only done the first time, when the table
1045 * copy is taken. After that, the table is assumed to have Tk_Uids where
1046 * they are needed. The time of deletion of the caches isn't very
1047 * important unless you've got a lot of code that uses Tk_ConfigureWidget
1048 * (or *Info or *Value} when the interpreter is being deleted.
1050 *--------------------------------------------------------------
1053 static Tk_ConfigSpec *
1055 Tcl_Interp *interp, /* Interpreter in which to store the cache. */
1056 const Tk_ConfigSpec *staticSpecs)
1057 /* Value to cache a copy of; it is also used
1058 * as a key into the cache. */
1060 Tk_ConfigSpec *cachedSpecs;
1061 Tcl_HashTable *specCacheTablePtr;
1062 Tcl_HashEntry *entryPtr;
1066 * Get (or allocate if it doesn't exist) the hash table that the writable
1067 * copies of the widget specs are stored in. In effect, this is
1068 * self-initializing code.
1071 specCacheTablePtr = (Tcl_HashTable *)
1072 Tcl_GetAssocData(interp, "tkConfigSpec.threadTable", NULL);
1073 if (specCacheTablePtr == NULL) {
1074 specCacheTablePtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
1075 Tcl_InitHashTable(specCacheTablePtr, TCL_ONE_WORD_KEYS);
1076 Tcl_SetAssocData(interp, "tkConfigSpec.threadTable",
1077 DeleteSpecCacheTable, specCacheTablePtr);
1081 * Look up or create the hash entry that the constant specs are mapped to,
1082 * which will have the writable specs as its associated value.
1085 entryPtr = Tcl_CreateHashEntry(specCacheTablePtr, (char *) staticSpecs,
1088 size_t entrySpace = sizeof(Tk_ConfigSpec);
1089 const Tk_ConfigSpec *staticSpecPtr;
1090 Tk_ConfigSpec *specPtr;
1093 * OK, no working copy in this interpreter so copy. Need to work out
1094 * how much space to allocate first.
1097 for (staticSpecPtr=staticSpecs; staticSpecPtr->type!=TK_CONFIG_END;
1099 entrySpace += sizeof(Tk_ConfigSpec);
1103 * Now allocate our working copy's space and copy over the contents
1107 cachedSpecs = (Tk_ConfigSpec *)ckalloc(entrySpace);
1108 memcpy(cachedSpecs, staticSpecs, entrySpace);
1109 Tcl_SetHashValue(entryPtr, cachedSpecs);
1112 * Finally, go through and replace database names, database classes
1113 * and default values with Tk_Uids. This is the bit that has to be
1117 for (specPtr=cachedSpecs; specPtr->type!=TK_CONFIG_END; specPtr++) {
1118 if (specPtr->argvName != NULL) {
1119 if (specPtr->dbName != NULL) {
1120 specPtr->dbName = Tk_GetUid(specPtr->dbName);
1122 if (specPtr->dbClass != NULL) {
1123 specPtr->dbClass = Tk_GetUid(specPtr->dbClass);
1125 if (specPtr->defValue != NULL) {
1126 specPtr->defValue = Tk_GetUid(specPtr->defValue);
1131 cachedSpecs = (Tk_ConfigSpec *)Tcl_GetHashValue(entryPtr);
1138 *--------------------------------------------------------------
1140 * DeleteSpecCacheTable --
1142 * Delete the per-interpreter copy of all the Tk_ConfigSpec tables which
1143 * were stored in the interpreter's assoc-data store.
1149 * None (does *not* use any Tk API).
1151 *--------------------------------------------------------------
1155 DeleteSpecCacheTable(
1156 ClientData clientData,
1157 TCL_UNUSED(Tcl_Interp *))
1159 Tcl_HashTable *tablePtr = (Tcl_HashTable *)clientData;
1160 Tcl_HashEntry *entryPtr;
1161 Tcl_HashSearch search;
1163 for (entryPtr = Tcl_FirstHashEntry(tablePtr,&search); entryPtr != NULL;
1164 entryPtr = Tcl_NextHashEntry(&search)) {
1166 * Someone else deallocates the Tk_Uids themselves.
1169 ckfree(Tcl_GetHashValue(entryPtr));
1171 Tcl_DeleteHashTable(tablePtr);