/* * tkOldConfig.c -- * * This file contains the Tk_ConfigureWidget function. THIS FILE IS HERE * FOR BACKWARD COMPATIBILITY; THE NEW CONFIGURATION PACKAGE SHOULD BE * USED FOR NEW PROJECTS. * * Copyright © 1990-1994 The Regents of the University of California. * Copyright © 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkInt.h" /* * Values for "flags" field of Tk_ConfigSpec structures. Be sure to coordinate * these values with those defined in tk.h (TK_CONFIG_COLOR_ONLY, etc.) There * must not be overlap! */ #ifndef TK_CONFIG_OPTION_SPECIFIED # define TK_CONFIG_OPTION_SPECIFIED (1 << 4) #endif #ifdef _WIN32 #include "tkWinInt.h" #endif /* * Forward declarations for functions defined later in this file: */ static int DoConfig(Tcl_Interp *interp, Tk_Window tkwin, Tk_ConfigSpec *specPtr, Tcl_Obj *value, void *widgRec); static Tk_ConfigSpec * FindConfigSpec(Tcl_Interp *interp, Tk_ConfigSpec *specs, const char *argvName, int needFlags, int hateFlags); static char * FormatConfigInfo(Tcl_Interp *interp, Tk_Window tkwin, const Tk_ConfigSpec *specPtr, void *widgRec); static const char * FormatConfigValue(Tcl_Interp *interp, Tk_Window tkwin, const Tk_ConfigSpec *specPtr, void *widgRec, char *buffer, Tcl_FreeProc **freeProcPtr); static Tk_ConfigSpec * GetCachedSpecs(Tcl_Interp *interp, const Tk_ConfigSpec *staticSpecs); static void DeleteSpecCacheTable(void *clientData, Tcl_Interp *interp); /* *-------------------------------------------------------------- * * Tk_ConfigureWidget -- * * Process command-line options and database options to fill in fields of * a widget record with resources and other parameters. * * Results: * A standard Tcl return value. In case of an error, the interp's result * will hold an error message. * * Side effects: * The fields of widgRec get filled in with information from objc/objv * and the option database. Old information in widgRec's fields gets * recycled. A copy of the spec-table is taken with (some of) the char* * fields converted into Tk_Uid fields; this copy will be released when * the interpreter terminates. * *-------------------------------------------------------------- */ int Tk_ConfigureWidget( Tcl_Interp *interp, /* Interpreter for error reporting. */ Tk_Window tkwin, /* Window containing widget (needed to set up * X resources). */ const Tk_ConfigSpec *specs, /* Describes legal options. */ Tcl_Size objc, /* Number of elements in objv. */ Tcl_Obj *const *objv, /* Command-line options. */ void *widgRec, /* Record whose fields are to be modified. * Values must be properly initialized. */ int flags) /* Used to specify additional flags that must * be present in config specs for them to be * considered. Also, may have * TK_CONFIG_ARGV_ONLY set. */ { Tk_ConfigSpec *specPtr, *staticSpecs; Tk_Uid value; /* Value of option from database. */ int needFlags; /* Specs must contain this set of flags or * else they are not considered. */ int hateFlags; /* If a spec contains any bits here, it's not * considered. */ if (tkwin == NULL) { /* * Either we're not really in Tk, or the main window was destroyed and * we're on our way out of the application */ Tcl_SetObjResult(interp, Tcl_NewStringObj("NULL main window", TCL_INDEX_NONE)); Tcl_SetErrorCode(interp, "TK", "NO_MAIN_WINDOW", (char *)NULL); return TCL_ERROR; } needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); if (Tk_Depth(tkwin) <= 1) { hateFlags = TK_CONFIG_COLOR_ONLY; } else { hateFlags = TK_CONFIG_MONO_ONLY; } /* * Get the build of the config for this interpreter. */ staticSpecs = GetCachedSpecs(interp, specs); for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) { specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED; } /* * Pass one: scan through all of the arguments, processing those that * match entries in the specs. */ for ( ; objc > 0; objc -= 2, objv += 2) { const char *arg; arg = Tcl_GetString(*objv); specPtr = FindConfigSpec(interp, staticSpecs, arg, needFlags, hateFlags); if (specPtr == NULL) { return TCL_ERROR; } /* * Process the entry. */ if (objc < 2) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "value for \"%s\" missing", arg)); Tcl_SetErrorCode(interp, "TK", "VALUE_MISSING", (char *)NULL); return TCL_ERROR; } if (DoConfig(interp, tkwin, specPtr, objv[1], widgRec) != TCL_OK) { Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (processing \"%.40s\" option)",specPtr->argvName)); return TCL_ERROR; } if (!(flags & TK_CONFIG_ARGV_ONLY)) { specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED; } } /* * Pass two: scan through all of the specs again; if no command-line * argument matched a spec, then check for info in the option database. * If there was nothing in the database, then use the default. */ if (!(flags & TK_CONFIG_ARGV_ONLY)) { for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) { if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED) || (specPtr->argvName == NULL) || (specPtr->type == TK_CONFIG_SYNONYM)) { continue; } if (((specPtr->specFlags & needFlags) != needFlags) || (specPtr->specFlags & hateFlags)) { continue; } value = NULL; if (specPtr->dbName != NULL) { value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass); } if (value != NULL) { Tcl_Obj *arg = Tcl_NewStringObj(value, TCL_INDEX_NONE); Tcl_IncrRefCount(arg); if (DoConfig(interp, tkwin, specPtr, arg, widgRec) != TCL_OK) { Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (%s \"%.50s\" in widget \"%.50s\")", "database entry for", specPtr->dbName, Tk_PathName(tkwin))); Tcl_DecrRefCount(arg); return TCL_ERROR; } Tcl_DecrRefCount(arg); } else { if ((specPtr->defValue != NULL) && !(specPtr->specFlags & TK_CONFIG_DONT_SET_DEFAULT)) { Tcl_Obj *arg = Tcl_NewStringObj(specPtr->defValue, TCL_INDEX_NONE); Tcl_IncrRefCount(arg); if (DoConfig(interp, tkwin, specPtr, arg, widgRec) != TCL_OK) { Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (%s \"%.50s\" in widget \"%.50s\")", "default value for", specPtr->dbName, Tk_PathName(tkwin))); Tcl_DecrRefCount(arg); return TCL_ERROR; } Tcl_DecrRefCount(arg); } } } } return TCL_OK; } /* *-------------------------------------------------------------- * * FindConfigSpec -- * * Search through a table of configuration specs, looking for one that * matches a given argvName. * * Results: * The return value is a pointer to the matching entry, or NULL if * nothing matched. In that case an error message is left in the interp's * result. * * Side effects: * None. * *-------------------------------------------------------------- */ static Tk_ConfigSpec * FindConfigSpec( Tcl_Interp *interp, /* Used for reporting errors. */ Tk_ConfigSpec *specs, /* Pointer to table of configuration * specifications for a widget. */ const char *argvName, /* Name (suitable for use in a "config" * command) identifying particular option. */ int needFlags, /* Flags that must be present in matching * entry. */ int hateFlags) /* Flags that must NOT be present in matching * entry. */ { Tk_ConfigSpec *specPtr; char c; /* First character of current argument. */ Tk_ConfigSpec *matchPtr; /* Matching spec, or NULL. */ size_t length; c = argvName[1]; length = strlen(argvName); matchPtr = NULL; for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { if (specPtr->argvName == NULL) { continue; } if ((specPtr->argvName[1] != c) || (strncmp(specPtr->argvName, argvName, length) != 0)) { continue; } if (((specPtr->specFlags & needFlags) != needFlags) || (specPtr->specFlags & hateFlags)) { continue; } if (specPtr->argvName[length] == 0) { matchPtr = specPtr; goto gotMatch; } if (matchPtr != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "ambiguous option \"%s\"", argvName)); Tcl_SetErrorCode(interp, "TK", "LOOKUP", "OPTION", argvName, (char *)NULL); return NULL; } matchPtr = specPtr; } if (matchPtr == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "unknown option \"%s\"", argvName)); Tcl_SetErrorCode(interp, "TK", "LOOKUP", "OPTION", argvName, (char *)NULL); return NULL; } /* * Found a matching entry. If it's a synonym, then find the entry that * it's a synonym for. */ gotMatch: specPtr = matchPtr; if (specPtr->type == TK_CONFIG_SYNONYM) { for (specPtr = specs; ; specPtr++) { if (specPtr->type == TK_CONFIG_END) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "couldn't find synonym for option \"%s\"", argvName)); Tcl_SetErrorCode(interp, "TK", "LOOKUP", "OPTION", argvName, (char *)NULL); return NULL; } if ((specPtr->dbName == matchPtr->dbName) && (specPtr->type != TK_CONFIG_SYNONYM) && ((specPtr->specFlags & needFlags) == needFlags) && !(specPtr->specFlags & hateFlags)) { break; } } } return specPtr; } /* *-------------------------------------------------------------- * * DoConfig -- * * This function applies a single configuration option to a widget * record. * * Results: * A standard Tcl return value. * * Side effects: * WidgRec is modified as indicated by specPtr and value. The old value * is recycled, if that is appropriate for the value type. * *-------------------------------------------------------------- */ static int DoConfig( Tcl_Interp *interp, /* Interpreter for error reporting. */ Tk_Window tkwin, /* Window containing widget (needed to set up * X resources). */ Tk_ConfigSpec *specPtr, /* Specifier to apply. */ Tcl_Obj *arg, /* Value to use to fill in widgRec. */ void *widgRec) /* Record whose fields are to be modified. * Values must be properly initialized. */ { void *ptr; int nullValue = 0; const char *value = Tcl_GetString(arg); if ((*value == 0) && (specPtr->specFlags & (TK_CONFIG_NULL_OK|TCL_NULL_OK|1))) { nullValue = 1; } if ((specPtr->specFlags & TK_CONFIG_OBJS) && (specPtr->type != TK_CONFIG_STRING) && (specPtr->type != TK_CONFIG_PIXELS)) { /* Prevent surprises for other options than TK_CONFIG_(STRING|PIXELS) */ Tcl_AppendResult(interp, "TK_CONFIG_OBJS not supported", (char *)NULL); return TCL_ERROR; } do { if (specPtr->offset < 0) { break; } ptr = (char *)widgRec + specPtr->offset; switch (specPtr->type) { case TK_CONFIG_BOOLEAN: if (Tcl_GetBooleanFromObj(interp, arg, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_INT: if (Tcl_GetIntFromObj(interp, arg, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_DOUBLE: if (Tcl_GetDoubleFromObj(interp, arg, (double *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_STRING: { char *oldStr, *newStr; if (nullValue) { newStr = NULL; } else if (specPtr->specFlags & TK_CONFIG_OBJS) { Tcl_IncrRefCount(arg); newStr = (char *)arg; } else { newStr = (char *)ckalloc(strlen(value) + 1); strcpy(newStr, value); } oldStr = *((char **)ptr); if (oldStr != NULL) { if (specPtr->specFlags & TK_CONFIG_OBJS) { Tcl_DecrRefCount((Tcl_Obj *)oldStr); } else { ckfree(oldStr); } } *((char **)ptr) = newStr; break; } case TK_CONFIG_UID: if (nullValue) { *((Tk_Uid *)ptr) = NULL; } else { *((Tk_Uid *)ptr) = Tk_GetUid(value); } break; case TK_CONFIG_COLOR: { XColor *newPtr, *oldPtr; if (nullValue) { newPtr = NULL; } else { newPtr = Tk_AllocColorFromObj(interp, tkwin, arg); if (newPtr == NULL) { return TCL_ERROR; } } oldPtr = *((XColor **)ptr); if (oldPtr != NULL) { Tk_FreeColor(oldPtr); } *((XColor **)ptr) = newPtr; break; } case TK_CONFIG_FONT: { Tk_Font newFont; if (nullValue) { newFont = NULL; } else { newFont = Tk_AllocFontFromObj(interp, tkwin, arg); if (newFont == NULL) { return TCL_ERROR; } } Tk_FreeFont(*((Tk_Font *)ptr)); *((Tk_Font *)ptr) = newFont; break; } case TK_CONFIG_BITMAP: { Pixmap newBmp, oldBmp; if (nullValue) { newBmp = None; } else { newBmp = Tk_AllocBitmapFromObj(interp, tkwin, arg); if (newBmp == None) { return TCL_ERROR; } } oldBmp = *((Pixmap *)ptr); if (oldBmp != None) { Tk_FreeBitmap(Tk_Display(tkwin), oldBmp); } *((Pixmap *)ptr) = newBmp; break; } case TK_CONFIG_BORDER: { Tk_3DBorder newBorder, oldBorder; if (nullValue) { newBorder = NULL; } else { newBorder = Tk_Alloc3DBorderFromObj(interp, tkwin, arg); if (newBorder == NULL) { return TCL_ERROR; } } oldBorder = *((Tk_3DBorder *)ptr); if (oldBorder != NULL) { Tk_Free3DBorder(oldBorder); } *((Tk_3DBorder *)ptr) = newBorder; break; } case TK_CONFIG_RELIEF: if (Tk_GetReliefFromObj(interp, arg, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_CURSOR: case TK_CONFIG_ACTIVE_CURSOR: { Tk_Cursor newCursor, oldCursor; if (nullValue) { newCursor = NULL; } else { newCursor = Tk_AllocCursorFromObj(interp, tkwin, arg); if (newCursor == NULL) { return TCL_ERROR; } } oldCursor = *((Tk_Cursor *)ptr); if (oldCursor != NULL) { Tk_FreeCursor(Tk_Display(tkwin), oldCursor); } *((Tk_Cursor *)ptr) = newCursor; if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) { Tk_DefineCursor(tkwin, newCursor); } break; } case TK_CONFIG_JUSTIFY: if (Tk_GetJustifyFromObj(interp, arg, (Tk_Justify *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_ANCHOR: if (Tk_GetAnchorFromObj(interp, arg, (Tk_Anchor *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_CAP_STYLE: if (Tk_GetCapStyle(interp, value, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_JOIN_STYLE: if (Tk_GetJoinStyle(interp, value, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_PIXELS: if (specPtr->specFlags & TK_CONFIG_OBJS) { int dummy; if (nullValue) { if (*(Tcl_Obj **)ptr != NULL) { Tcl_DecrRefCount(*(Tcl_Obj **)ptr); *(Tcl_Obj **)ptr = NULL; } } else if (Tk_GetPixelsFromObj(interp, tkwin, arg, &dummy) != TCL_OK) { return TCL_ERROR; } else { Tcl_IncrRefCount(arg); if (*(Tcl_Obj **)ptr != NULL) { Tcl_DecrRefCount(*(Tcl_Obj **)ptr); } *(Tcl_Obj **)ptr = arg; } } else if (nullValue) { *(int *)ptr = INT_MIN; } else if (Tk_GetPixelsFromObj(interp, tkwin, arg, (int *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_MM: if (Tk_GetScreenMM(interp, tkwin, value, (double *)ptr) != TCL_OK) { return TCL_ERROR; } break; case TK_CONFIG_WINDOW: { Tk_Window tkwin2; if (nullValue) { tkwin2 = NULL; } else { tkwin2 = Tk_NameToWindow(interp, value, tkwin); if (tkwin2 == NULL) { return TCL_ERROR; } } *((Tk_Window *)ptr) = tkwin2; break; } case TK_CONFIG_CUSTOM: if (specPtr->customPtr->parseProc(specPtr->customPtr->clientData, interp, tkwin, value, (char *)widgRec, specPtr->offset)!=TCL_OK) { return TCL_ERROR; } break; default: Tcl_SetObjResult(interp, Tcl_ObjPrintf( "bad config table: unknown type %d", specPtr->type)); Tcl_SetErrorCode(interp, "TK", "BAD_CONFIG", (char *)NULL); return TCL_ERROR; } specPtr++; } while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END)); return TCL_OK; } /* *-------------------------------------------------------------- * * Tk_ConfigureInfo -- * * Return information about the configuration options for a window, and * their current values. * * Results: * Always returns TCL_OK. The interp's result will be modified hold a * description of either a single configuration option available for * "widgRec" via "specs", or all the configuration options available. In * the "all" case, the result will available for "widgRec" via "specs". * The result will be a list, each of whose entries describes one option. * Each entry will itself be a list containing the option's name for use * on command lines, database name, database class, default value, and * current value (empty string if none). For options that are synonyms, * the list will contain only two values: name and synonym name. If the * "name" argument is non-NULL, then the only information returned is * that for the named argument (i.e. the corresponding entry in the * overall list is returned). * * Side effects: * None. * *-------------------------------------------------------------- */ int Tk_ConfigureInfo( Tcl_Interp *interp, /* Interpreter for error reporting. */ Tk_Window tkwin, /* Window corresponding to widgRec. */ const Tk_ConfigSpec *specs, /* Describes legal options. */ void *widgRec, /* Record whose fields contain current values * for options. */ const char *argvName, /* If non-NULL, indicates a single option * whose info is to be returned. Otherwise * info is returned for all options. */ int flags) /* Used to specify additional flags that must * be present in config specs for them to be * considered. */ { Tk_ConfigSpec *specPtr, *staticSpecs; int needFlags, hateFlags; char *list; const char *leader = "{"; needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); if (Tk_Depth(tkwin) <= 1) { hateFlags = TK_CONFIG_COLOR_ONLY; } else { hateFlags = TK_CONFIG_MONO_ONLY; } /* * Get the build of the config for this interpreter. */ staticSpecs = GetCachedSpecs(interp, specs); /* * If information is only wanted for a single configuration spec, then * handle that one spec specially. */ Tcl_ResetResult(interp); if (argvName != NULL) { specPtr = FindConfigSpec(interp, staticSpecs, argvName, needFlags, hateFlags); if (specPtr == NULL) { return TCL_ERROR; } list = FormatConfigInfo(interp, tkwin, specPtr, widgRec); Tcl_SetObjResult(interp, Tcl_NewStringObj(list, TCL_INDEX_NONE)); ckfree(list); return TCL_OK; } /* * Loop through all the specs, creating a big list with all their * information. */ for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) { if ((argvName != NULL) && (specPtr->argvName != argvName)) { continue; } if (((specPtr->specFlags & needFlags) != needFlags) || (specPtr->specFlags & hateFlags)) { continue; } if ((specPtr->argvName == NULL) || (specPtr->offset < 0)) { continue; } list = FormatConfigInfo(interp, tkwin, specPtr, widgRec); Tcl_AppendResult(interp, leader, list, "}", (char *)NULL); ckfree(list); leader = " {"; } return TCL_OK; } /* *-------------------------------------------------------------- * * FormatConfigInfo -- * * Create a valid Tcl list holding the configuration information for a * single configuration option. * * Results: * A Tcl list, dynamically allocated. The caller is expected to arrange * for this list to be freed eventually. * * Side effects: * Memory is allocated. * *-------------------------------------------------------------- */ static char * FormatConfigInfo( Tcl_Interp *interp, /* Interpreter to use for things like * floating-point precision. */ Tk_Window tkwin, /* Window corresponding to widget. */ const Tk_ConfigSpec *specPtr, /* Pointer to information describing * option. */ void *widgRec) /* Pointer to record holding current values of * info for widget. */ { const char *argv[6]; char *result; char buffer[200]; Tcl_FreeProc *freeProc = NULL; argv[0] = specPtr->argvName; argv[1] = specPtr->dbName; argv[2] = specPtr->dbClass; argv[3] = specPtr->defValue; if (specPtr->type == TK_CONFIG_SYNONYM) { return Tcl_Merge(2, argv); } argv[4] = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, &freeProc); if (argv[1] == NULL) { argv[1] = ""; } if (argv[2] == NULL) { argv[2] = ""; } if (argv[3] == NULL) { argv[3] = ""; } if (argv[4] == NULL) { argv[4] = ""; } result = Tcl_Merge(5, argv); if (freeProc != NULL) { if (freeProc == TCL_DYNAMIC) { ckfree((char *)argv[4]); } else { freeProc((char *)argv[4]); } } return result; } /* *---------------------------------------------------------------------- * * FormatConfigValue -- * * This function formats the current value of a configuration option. * * Results: * The return value is the formatted value of the option given by specPtr * and widgRec. If the value is static, so that it need not be freed, * *freeProcPtr will be set to NULL; otherwise *freeProcPtr will be set * to the address of a function to free the result, and the caller must * invoke this function when it is finished with the result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static const char * FormatConfigValue( Tcl_Interp *interp, /* Interpreter for use in real conversions. */ Tk_Window tkwin, /* Window corresponding to widget. */ const Tk_ConfigSpec *specPtr, /* Pointer to information describing option. * Must not point to a synonym option. */ void *widgRec, /* Pointer to record holding current values of * info for widget. */ char *buffer, /* Static buffer to use for small values. * Must have at least 200 bytes of storage. */ Tcl_FreeProc **freeProcPtr) /* Pointer to word to fill in with address of * function to free the result, or NULL if * result is static. */ { void *ptr; const char *result; *freeProcPtr = NULL; if (specPtr->offset < 0) { return NULL; } ptr = (char *)widgRec + specPtr->offset; result = ""; if (specPtr->specFlags & TK_CONFIG_OBJS) { if (*(Tcl_Obj **)ptr != NULL) { result = Tcl_GetString(*(Tcl_Obj **)ptr); } return result; } switch (specPtr->type) { case TK_CONFIG_BOOLEAN: if (*((int *)ptr) == 0) { result = "0"; } else { result = "1"; } break; case TK_CONFIG_INT: snprintf(buffer, 200, "%d", *((int *)ptr)); result = buffer; break; case TK_CONFIG_DOUBLE: Tcl_PrintDouble(interp, *((double *)ptr), buffer); result = buffer; break; case TK_CONFIG_STRING: result = *(char **)ptr; if (result == NULL) { result = ""; } break; case TK_CONFIG_UID: { Tk_Uid uid = *((Tk_Uid *)ptr); if (uid != NULL) { result = uid; } break; } case TK_CONFIG_COLOR: { XColor *colorPtr = *((XColor **)ptr); if (colorPtr != NULL) { result = Tk_NameOfColor(colorPtr); } break; } case TK_CONFIG_FONT: { Tk_Font tkfont = *((Tk_Font *)ptr); if (tkfont != NULL) { result = Tk_NameOfFont(tkfont); } break; } case TK_CONFIG_BITMAP: { Pixmap pixmap = *((Pixmap *)ptr); if (pixmap != None) { result = Tk_NameOfBitmap(Tk_Display(tkwin), pixmap); } break; } case TK_CONFIG_BORDER: { Tk_3DBorder border = *((Tk_3DBorder *)ptr); if (border != NULL) { result = Tk_NameOf3DBorder(border); } break; } case TK_CONFIG_RELIEF: result = Tk_NameOfRelief(*((int *)ptr)); break; case TK_CONFIG_CURSOR: case TK_CONFIG_ACTIVE_CURSOR: { Tk_Cursor cursor = *((Tk_Cursor *)ptr); if (cursor != NULL) { result = Tk_NameOfCursor(Tk_Display(tkwin), cursor); } break; } case TK_CONFIG_JUSTIFY: result = Tk_NameOfJustify(*((Tk_Justify *)ptr)); break; case TK_CONFIG_ANCHOR: result = Tk_NameOfAnchor(*((Tk_Anchor *)ptr)); break; case TK_CONFIG_CAP_STYLE: result = Tk_NameOfCapStyle(*((int *)ptr)); break; case TK_CONFIG_JOIN_STYLE: result = Tk_NameOfJoinStyle(*((int *)ptr)); break; case TK_CONFIG_PIXELS: if ((*(int *)ptr != INT_MIN) || !(specPtr->specFlags & (TK_CONFIG_NULL_OK|TCL_NULL_OK|1))) { snprintf(buffer, 200, "%d", *((int *)ptr)); result = buffer; } break; case TK_CONFIG_MM: Tcl_PrintDouble(interp, *((double *)ptr), buffer); result = buffer; break; case TK_CONFIG_WINDOW: { tkwin = *((Tk_Window *)ptr); if (tkwin != NULL) { result = Tk_PathName(tkwin); } break; } case TK_CONFIG_CUSTOM: result = specPtr->customPtr->printProc(specPtr->customPtr->clientData, tkwin, (char *)widgRec, specPtr->offset, freeProcPtr); break; default: result = "?? unknown type ??"; } return result; } /* *---------------------------------------------------------------------- * * Tk_ConfigureValue -- * * This function returns the current value of a configuration option for * a widget. * * Results: * The return value is a standard Tcl completion code (TCL_OK or * TCL_ERROR). The interp's result will be set to hold either the value * of the option given by argvName (if TCL_OK is returned) or an error * message (if TCL_ERROR is returned). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tk_ConfigureValue( Tcl_Interp *interp, /* Interpreter for error reporting. */ Tk_Window tkwin, /* Window corresponding to widgRec. */ const Tk_ConfigSpec *specs, /* Describes legal options. */ void *widgRec, /* Record whose fields contain current values * for options. */ const char *argvName, /* Gives the command-line name for the option * whose value is to be returned. */ int flags) /* Used to specify additional flags that must * be present in config specs for them to be * considered. */ { Tk_ConfigSpec *specPtr; int needFlags, hateFlags; Tcl_FreeProc *freeProc; const char *result; char buffer[200]; needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); if (Tk_Depth(tkwin) <= 1) { hateFlags = TK_CONFIG_COLOR_ONLY; } else { hateFlags = TK_CONFIG_MONO_ONLY; } /* * Get the build of the config for this interpreter. */ specPtr = GetCachedSpecs(interp, specs); specPtr = FindConfigSpec(interp, specPtr, argvName, needFlags, hateFlags); if (specPtr == NULL) { return TCL_ERROR; } result = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, &freeProc); Tcl_SetObjResult(interp, Tcl_NewStringObj(result, TCL_INDEX_NONE)); if (freeProc != NULL) { if (freeProc == TCL_DYNAMIC) { ckfree((char *)result); } else { freeProc((char *)result); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tk_FreeOptions -- * * Free up all resources associated with configuration options. * * Results: * None. * * Side effects: * Any resource in widgRec that is controlled by a configuration option * (e.g. a Tk_3DBorder or XColor) is freed in the appropriate fashion. * * Notes: * Since this is not looking anything up, this uses the static version of * the config specs. * *---------------------------------------------------------------------- */ void Tk_FreeOptions( const Tk_ConfigSpec *specs, /* Describes legal options. */ void *widgRec, /* Record whose fields contain current values * for options. */ Display *display, /* X display; needed for freeing some * resources. */ int needFlags) /* Used to specify additional flags that must * be present in config specs for them to be * considered. */ { const Tk_ConfigSpec *specPtr; char *ptr; for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { if ((specPtr->specFlags & needFlags) != needFlags) { continue; } if (specPtr->offset < 0) { continue; } ptr = (char *)widgRec + specPtr->offset; if ((specPtr->specFlags & TK_CONFIG_OBJS) && (*(Tcl_Obj **)ptr != NULL)) { Tcl_DecrRefCount(*(Tcl_Obj **)ptr); *(Tcl_Obj **)ptr = NULL; continue; } switch (specPtr->type) { case TK_CONFIG_STRING: if (*((char **)ptr) != NULL) { ckfree(*((char **)ptr)); *((char **)ptr) = NULL; } break; case TK_CONFIG_COLOR: if (*((XColor **)ptr) != NULL) { Tk_FreeColor(*((XColor **)ptr)); *((XColor **)ptr) = NULL; } break; case TK_CONFIG_FONT: Tk_FreeFont(*((Tk_Font *)ptr)); *((Tk_Font *)ptr) = NULL; break; case TK_CONFIG_BITMAP: if (*((Pixmap *)ptr) != None) { Tk_FreeBitmap(display, *((Pixmap *)ptr)); *((Pixmap *)ptr) = None; } break; case TK_CONFIG_BORDER: if (*((Tk_3DBorder *)ptr) != NULL) { Tk_Free3DBorder(*((Tk_3DBorder *)ptr)); *((Tk_3DBorder *)ptr) = NULL; } break; case TK_CONFIG_CURSOR: case TK_CONFIG_ACTIVE_CURSOR: if (*((Tk_Cursor *)ptr) != NULL) { Tk_FreeCursor(display, *((Tk_Cursor *)ptr)); *((Tk_Cursor *)ptr) = NULL; } } } } /* *-------------------------------------------------------------- * * GetCachedSpecs -- * * Returns a writable per-interpreter (and hence thread-local) copy of * the given spec-table with (some of) the char* fields converted into * Tk_Uid fields; this copy will be released when the interpreter * terminates (during AssocData cleanup). * * Results: * A pointer to the copied table. * * Notes: * The conversion to Tk_Uid is only done the first time, when the table * copy is taken. After that, the table is assumed to have Tk_Uids where * they are needed. The time of deletion of the caches isn't very * important unless you've got a lot of code that uses Tk_ConfigureWidget * (or *Info or *Value} when the interpreter is being deleted. * *-------------------------------------------------------------- */ static Tk_ConfigSpec * GetCachedSpecs( Tcl_Interp *interp, /* Interpreter in which to store the cache. */ const Tk_ConfigSpec *staticSpecs) /* Value to cache a copy of; it is also used * as a key into the cache. */ { Tk_ConfigSpec *cachedSpecs; Tcl_HashTable *specCacheTablePtr; Tcl_HashEntry *entryPtr; int isNew; /* * Get (or allocate if it doesn't exist) the hash table that the writable * copies of the widget specs are stored in. In effect, this is * self-initializing code. */ specCacheTablePtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tkConfigSpec.threadTable", NULL); if (specCacheTablePtr == NULL) { specCacheTablePtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(specCacheTablePtr, TCL_ONE_WORD_KEYS); Tcl_SetAssocData(interp, "tkConfigSpec.threadTable", DeleteSpecCacheTable, specCacheTablePtr); } /* * Look up or create the hash entry that the constant specs are mapped to, * which will have the writable specs as its associated value. */ entryPtr = Tcl_CreateHashEntry(specCacheTablePtr, (char *) staticSpecs, &isNew); if (isNew) { size_t entrySpace = sizeof(Tk_ConfigSpec); const Tk_ConfigSpec *staticSpecPtr; Tk_ConfigSpec *specPtr; /* * OK, no working copy in this interpreter so copy. Need to work out * how much space to allocate first. */ for (staticSpecPtr=staticSpecs; staticSpecPtr->type!=TK_CONFIG_END; staticSpecPtr++) { entrySpace += sizeof(Tk_ConfigSpec); } /* * Now allocate our working copy's space and copy over the contents * from the origin. */ cachedSpecs = (Tk_ConfigSpec *)ckalloc(entrySpace); memcpy(cachedSpecs, staticSpecs, entrySpace); Tcl_SetHashValue(entryPtr, cachedSpecs); /* * Finally, go through and replace database names, database classes * and default values with Tk_Uids. This is the bit that has to be * per-thread. */ for (specPtr=cachedSpecs; specPtr->type!=TK_CONFIG_END; specPtr++) { if (specPtr->argvName != NULL) { if (specPtr->dbName != NULL) { specPtr->dbName = Tk_GetUid(specPtr->dbName); } if (specPtr->dbClass != NULL) { specPtr->dbClass = Tk_GetUid(specPtr->dbClass); } if (specPtr->defValue != NULL) { specPtr->defValue = Tk_GetUid(specPtr->defValue); } } } } else { cachedSpecs = (Tk_ConfigSpec *)Tcl_GetHashValue(entryPtr); } return cachedSpecs; } /* *-------------------------------------------------------------- * * DeleteSpecCacheTable -- * * Delete the per-interpreter copy of all the Tk_ConfigSpec tables which * were stored in the interpreter's assoc-data store. * * Results: * None * * Side effects: * None (does *not* use any Tk API). * *-------------------------------------------------------------- */ static void DeleteSpecCacheTable( void *clientData, TCL_UNUSED(Tcl_Interp *)) { Tcl_HashTable *tablePtr = (Tcl_HashTable *)clientData; Tcl_HashEntry *entryPtr; Tcl_HashSearch search; for (entryPtr = Tcl_FirstHashEntry(tablePtr,&search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { /* * Someone else deallocates the Tk_Uids themselves. */ ckfree(Tcl_GetHashValue(entryPtr)); } Tcl_DeleteHashTable(tablePtr); ckfree(tablePtr); } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */