tkOldConfig.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:33k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkOldConfig.c --
  3.  *
  4.  * This file contains the Tk_ConfigureWidget procedure. THIS FILE
  5.  * IS HERE FOR BACKWARD COMPATIBILITY; THE NEW CONFIGURATION
  6.  * PACKAGE SHOULD BE USED FOR NEW PROJECTS.
  7.  *
  8.  * Copyright (c) 1990-1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tkOldConfig.c,v 1.12.2.3 2005/12/05 22:42:42 hobbs Exp $
  15.  */
  16. #include "tkPort.h"
  17. #include "tk.h"
  18. /*
  19.  * Values for "flags" field of Tk_ConfigSpec structures.  Be sure
  20.  * to coordinate these values with those defined in tk.h
  21.  * (TK_CONFIG_COLOR_ONLY, etc.).  There must not be overlap!
  22.  *
  23.  * INIT - Non-zero means (char *) things have been
  24.  * converted to Tk_Uid's.
  25.  */
  26. #define INIT 0x20
  27. /*
  28.  * Forward declarations for procedures defined later in this file:
  29.  */
  30. static int DoConfig _ANSI_ARGS_((Tcl_Interp *interp,
  31.     Tk_Window tkwin, Tk_ConfigSpec *specPtr,
  32.     Tk_Uid value, int valueIsUid, char *widgRec));
  33. static Tk_ConfigSpec * FindConfigSpec _ANSI_ARGS_((Tcl_Interp *interp,
  34.     Tk_ConfigSpec *specs, CONST char *argvName,
  35.     int needFlags, int hateFlags));
  36. static char * FormatConfigInfo _ANSI_ARGS_((Tcl_Interp *interp,
  37.     Tk_Window tkwin, Tk_ConfigSpec *specPtr,
  38.     char *widgRec));
  39. static CONST char * FormatConfigValue _ANSI_ARGS_((Tcl_Interp *interp,
  40.     Tk_Window tkwin, Tk_ConfigSpec *specPtr,
  41.     char *widgRec, char *buffer,
  42.     Tcl_FreeProc **freeProcPtr));
  43. static Tk_ConfigSpec * GetCachedSpecs _ANSI_ARGS_((Tcl_Interp *interp,
  44.     const Tk_ConfigSpec *staticSpecs));
  45. static void DeleteSpecCacheTable _ANSI_ARGS_((
  46.     ClientData clientData, Tcl_Interp *interp));
  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.  * the interp's result will hold an error message.
  59.  *
  60.  * Side effects:
  61.  * The fields of widgRec get filled in with information from
  62.  * argc/argv and the option database.  Old information in
  63.  * widgRec's fields gets recycled. A copy of the spec-table is
  64.  * taken with (some of) the char* *fields converted into Tk_Uid
  65.  * fields; this copy will be released when *the interpreter
  66.  * terminates.
  67.  *
  68.  *--------------------------------------------------------------
  69.  */
  70. int
  71. Tk_ConfigureWidget(interp, tkwin, origSpecs, argc, argv, widgRec, flags)
  72.     Tcl_Interp *interp; /* Interpreter for error reporting. */
  73.     Tk_Window tkwin; /* Window containing widget (needed to
  74.  * set up X resources). */
  75.     Tk_ConfigSpec *origSpecs; /* 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
  79.  * modified.  Values must be properly
  80.  * initialized. */
  81.     int flags; /* Used to specify additional flags
  82.  * that must be present in config specs
  83.  * for them to be considered.  Also,
  84.  * may have TK_CONFIG_ARGV_ONLY set. */
  85. {
  86.     register Tk_ConfigSpec *specs, *specPtr, *origSpecPtr;
  87.     Tk_Uid value; /* Value of option from database. */
  88.     int needFlags; /* Specs must contain this set of flags
  89.  * or else they are not considered. */
  90.     int hateFlags; /* If a spec contains any bits here, it's
  91.  * not considered. */
  92.     if (tkwin == NULL) {
  93. /*
  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
  96.  */
  97. Tcl_AppendResult(interp, "NULL main window", (char *)NULL);
  98. return TCL_ERROR;
  99.     }
  100.     needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
  101.     if (Tk_Depth(tkwin) <= 1) {
  102. hateFlags = TK_CONFIG_COLOR_ONLY;
  103.     } else {
  104. hateFlags = TK_CONFIG_MONO_ONLY;
  105.     }
  106.     /*
  107.      * Get the build of the config for this interpreter and reset any
  108.      * indication of changed options.
  109.      */
  110.     specs = GetCachedSpecs(interp, origSpecs);
  111.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  112. specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED;
  113.     }
  114.     /*
  115.      * Pass one:  scan through all of the arguments, processing those
  116.      * that match entries in the specs.
  117.      */
  118.     for ( ; argc > 0; argc -= 2, argv += 2) {
  119. CONST char *arg;
  120. if (flags & TK_CONFIG_OBJS) {
  121.     arg = Tcl_GetStringFromObj((Tcl_Obj *) *argv, NULL);
  122. } else {
  123.     arg = *argv;
  124. }
  125. specPtr = FindConfigSpec(interp, specs, arg, needFlags, hateFlags);
  126. if (specPtr == NULL) {
  127.     return TCL_ERROR;
  128. }
  129. /*
  130.  * Process the entry.
  131.  */
  132. if (argc < 2) {
  133.     Tcl_AppendResult(interp, "value for "", arg,
  134.     "" missing", (char *) NULL);
  135.     return TCL_ERROR;
  136. }
  137. if (flags & TK_CONFIG_OBJS) {
  138.     arg = Tcl_GetString((Tcl_Obj *) argv[1]);
  139. } else {
  140.     arg = argv[1];
  141. }
  142. if (DoConfig(interp, tkwin, specPtr, arg, 0, widgRec) != TCL_OK) {
  143.     char msg[100];
  144.     sprintf(msg, "n    (processing "%.40s" option)",
  145.     specPtr->argvName);
  146.     Tcl_AddErrorInfo(interp, msg);
  147.     return TCL_ERROR;
  148. }
  149. specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED;
  150.     }
  151.     /*
  152.      * Thread Unsafe!  For compatibility through 8.4.x, we set the original
  153.      * specPtr flags to indicate changed options.  This has been removed
  154.      * from 8.5.  Switch to Tcl_Obj-based options instead. [Bug 749908]
  155.      */
  156.     for (origSpecPtr = origSpecs, specPtr = specs;
  157.  specPtr->type != TK_CONFIG_END; origSpecPtr++, specPtr++) {
  158. origSpecPtr->specFlags = specPtr->specFlags;
  159.     }
  160.     /*
  161.      * Pass two:  scan through all of the specs again;  if no
  162.      * command-line argument matched a spec, then check for info
  163.      * in the option database.  If there was nothing in the
  164.      * database, then use the default.
  165.      */
  166.     if (!(flags & TK_CONFIG_ARGV_ONLY)) {
  167. for (specPtr=specs; specPtr->type!=TK_CONFIG_END; specPtr++) {
  168.     if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED)
  169.     || (specPtr->argvName == NULL)
  170.     || (specPtr->type == TK_CONFIG_SYNONYM)) {
  171. continue;
  172.     }
  173.     if (((specPtr->specFlags & needFlags) != needFlags)
  174.     || (specPtr->specFlags & hateFlags)) {
  175. continue;
  176.     }
  177.     value = NULL;
  178.     if (specPtr->dbName != NULL) {
  179. value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass);
  180.     }
  181.     if (value != NULL) {
  182. if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
  183. TCL_OK) {
  184.     char msg[200];
  185.     sprintf(msg, "n    (%s "%.50s" in widget "%.50s")",
  186.     "database entry for",
  187.     specPtr->dbName, Tk_PathName(tkwin));
  188.     Tcl_AddErrorInfo(interp, msg);
  189.     return TCL_ERROR;
  190. }
  191.     } else {
  192. if (specPtr->defValue != NULL) {
  193.     value = Tk_GetUid(specPtr->defValue);
  194. } else {
  195.     value = NULL;
  196. }
  197. if ((value != NULL) && !(specPtr->specFlags
  198. & TK_CONFIG_DONT_SET_DEFAULT)) {
  199.     if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
  200.     TCL_OK) {
  201. char msg[200];
  202. sprintf(msg,
  203. "n    (%s "%.50s" in widget "%.50s")",
  204. "default value for",
  205. specPtr->dbName, Tk_PathName(tkwin));
  206. Tcl_AddErrorInfo(interp, msg);
  207. return TCL_ERROR;
  208.     }
  209. }
  210.     }
  211. }
  212.     }
  213.     return TCL_OK;
  214. }
  215. /*
  216.  *--------------------------------------------------------------
  217.  *
  218.  * FindConfigSpec --
  219.  *
  220.  * Search through a table of configuration specs, looking for
  221.  * one that matches a given argvName.
  222.  *
  223.  * Results:
  224.  * The return value is a pointer to the matching entry, or NULL
  225.  * if nothing matched.  In that case an error message is left
  226.  * in the interp's result.
  227.  *
  228.  * Side effects:
  229.  * None.
  230.  *
  231.  *--------------------------------------------------------------
  232.  */
  233. static Tk_ConfigSpec *
  234. FindConfigSpec(interp, specs, argvName, needFlags, hateFlags)
  235.     Tcl_Interp *interp; /* Used for reporting errors. */
  236.     Tk_ConfigSpec *specs; /* Pointer to table of configuration
  237.  * specifications for a widget. */
  238.     CONST char *argvName; /* Name (suitable for use in a "config"
  239.  * command) identifying particular option. */
  240.     int needFlags; /* Flags that must be present in matching
  241.  * entry. */
  242.     int hateFlags; /* Flags that must NOT be present in
  243.  * matching entry. */
  244. {
  245.     register Tk_ConfigSpec *specPtr;
  246.     register char c; /* First character of current argument. */
  247.     Tk_ConfigSpec *matchPtr; /* Matching spec, or NULL. */
  248.     size_t length;
  249.     c = argvName[1];
  250.     length = strlen(argvName);
  251.     matchPtr = NULL;
  252.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  253. if (specPtr->argvName == NULL) {
  254.     continue;
  255. }
  256. if ((specPtr->argvName[1] != c)
  257. || (strncmp(specPtr->argvName, argvName, length) != 0)) {
  258.     continue;
  259. }
  260. if (((specPtr->specFlags & needFlags) != needFlags)
  261. || (specPtr->specFlags & hateFlags)) {
  262.     continue;
  263. }
  264. if (specPtr->argvName[length] == 0) {
  265.     matchPtr = specPtr;
  266.     goto gotMatch;
  267. }
  268. if (matchPtr != NULL) {
  269.     Tcl_AppendResult(interp, "ambiguous option "", argvName,
  270.     """, (char *) NULL);
  271.     return (Tk_ConfigSpec *) NULL;
  272. }
  273. matchPtr = specPtr;
  274.     }
  275.     if (matchPtr == NULL) {
  276. Tcl_AppendResult(interp, "unknown option "", argvName,
  277. """, (char *) NULL);
  278. return (Tk_ConfigSpec *) NULL;
  279.     }
  280.     /*
  281.      * Found a matching entry.  If it's a synonym, then find the
  282.      * entry that it's a synonym for.
  283.      */
  284.     gotMatch:
  285.     specPtr = matchPtr;
  286.     if (specPtr->type == TK_CONFIG_SYNONYM) {
  287. for (specPtr = specs; ; specPtr++) {
  288.     if (specPtr->type == TK_CONFIG_END) {
  289. Tcl_AppendResult(interp,
  290. "couldn't find synonym for option "",
  291. argvName, """, (char *) NULL);
  292. return (Tk_ConfigSpec *) NULL;
  293.     }
  294.     if ((specPtr->dbName == matchPtr->dbName) 
  295.     && (specPtr->type != TK_CONFIG_SYNONYM)
  296.     && ((specPtr->specFlags & needFlags) == needFlags)
  297.     && !(specPtr->specFlags & hateFlags)) {
  298. break;
  299.     }
  300. }
  301.     }
  302.     return specPtr;
  303. }
  304. /*
  305.  *--------------------------------------------------------------
  306.  *
  307.  * DoConfig --
  308.  *
  309.  * This procedure applies a single configuration option
  310.  * to a widget record.
  311.  *
  312.  * Results:
  313.  * A standard Tcl return value.
  314.  *
  315.  * Side effects:
  316.  * WidgRec is modified as indicated by specPtr and value.
  317.  * The old value is recycled, if that is appropriate for
  318.  * the value type.
  319.  *
  320.  *--------------------------------------------------------------
  321.  */
  322. static int
  323. DoConfig(interp, tkwin, specPtr, value, valueIsUid, widgRec)
  324.     Tcl_Interp *interp; /* Interpreter for error reporting. */
  325.     Tk_Window tkwin; /* Window containing widget (needed to
  326.  * set up X resources). */
  327.     Tk_ConfigSpec *specPtr; /* Specifier to apply. */
  328.     Tk_Uid value; /* Value to use to fill in widgRec. */
  329.     int valueIsUid; /* Non-zero means value is a Tk_Uid;
  330.  * zero means it's an ordinary string. */
  331.     char *widgRec; /* Record whose fields are to be
  332.  * modified.  Values must be properly
  333.  * initialized. */
  334. {
  335.     char *ptr;
  336.     Tk_Uid uid;
  337.     int nullValue;
  338.     nullValue = 0;
  339.     if ((*value == 0) && (specPtr->specFlags & TK_CONFIG_NULL_OK)) {
  340. nullValue = 1;
  341.     }
  342.     do {
  343. ptr = widgRec + specPtr->offset;
  344. switch (specPtr->type) {
  345.     case TK_CONFIG_BOOLEAN:
  346. if (Tcl_GetBoolean(interp, value, (int *) ptr) != TCL_OK) {
  347.     return TCL_ERROR;
  348. }
  349. break;
  350.     case TK_CONFIG_INT:
  351. if (Tcl_GetInt(interp, value, (int *) ptr) != TCL_OK) {
  352.     return TCL_ERROR;
  353. }
  354. break;
  355.     case TK_CONFIG_DOUBLE:
  356. if (Tcl_GetDouble(interp, value, (double *) ptr) != TCL_OK) {
  357.     return TCL_ERROR;
  358. }
  359. break;
  360.     case TK_CONFIG_STRING: {
  361. char *old, *new;
  362. if (nullValue) {
  363.     new = NULL;
  364. } else {
  365.     new = (char *) ckalloc((unsigned) (strlen(value) + 1));
  366.     strcpy(new, value);
  367. }
  368. old = *((char **) ptr);
  369. if (old != NULL) {
  370.     ckfree(old);
  371. }
  372. *((char **) ptr) = new;
  373. break;
  374.     }
  375.     case TK_CONFIG_UID:
  376. if (nullValue) {
  377.     *((Tk_Uid *) ptr) = NULL;
  378. } else {
  379.     uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  380.     *((Tk_Uid *) ptr) = uid;
  381. }
  382. break;
  383.     case TK_CONFIG_COLOR: {
  384. XColor *newPtr, *oldPtr;
  385. if (nullValue) {
  386.     newPtr = NULL;
  387. } else {
  388.     uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  389.     newPtr = Tk_GetColor(interp, tkwin, uid);
  390.     if (newPtr == NULL) {
  391. return TCL_ERROR;
  392.     }
  393. }
  394. oldPtr = *((XColor **) ptr);
  395. if (oldPtr != NULL) {
  396.     Tk_FreeColor(oldPtr);
  397. }
  398. *((XColor **) ptr) = newPtr;
  399. break;
  400.     }
  401.     case TK_CONFIG_FONT: {
  402. Tk_Font new;
  403. if (nullValue) {
  404.     new = NULL;
  405. } else {
  406.     new = Tk_GetFont(interp, tkwin, value);
  407.     if (new == NULL) {
  408. return TCL_ERROR;
  409.     }
  410. }
  411. Tk_FreeFont(*((Tk_Font *) ptr));
  412. *((Tk_Font *) ptr) = new;
  413. break;
  414.     }
  415.     case TK_CONFIG_BITMAP: {
  416. Pixmap new, old;
  417. if (nullValue) {
  418.     new = None;
  419.         } else {
  420.     uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  421.     new = Tk_GetBitmap(interp, tkwin, uid);
  422.     if (new == None) {
  423. return TCL_ERROR;
  424.     }
  425. }
  426. old = *((Pixmap *) ptr);
  427. if (old != None) {
  428.     Tk_FreeBitmap(Tk_Display(tkwin), old);
  429. }
  430. *((Pixmap *) ptr) = new;
  431. break;
  432.     }
  433.     case TK_CONFIG_BORDER: {
  434. Tk_3DBorder new, old;
  435. if (nullValue) {
  436.     new = NULL;
  437. } else {
  438.     uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  439.     new = Tk_Get3DBorder(interp, tkwin, uid);
  440.     if (new == NULL) {
  441. return TCL_ERROR;
  442.     }
  443. }
  444. old = *((Tk_3DBorder *) ptr);
  445. if (old != NULL) {
  446.     Tk_Free3DBorder(old);
  447. }
  448. *((Tk_3DBorder *) ptr) = new;
  449. break;
  450.     }
  451.     case TK_CONFIG_RELIEF:
  452. uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  453. if (Tk_GetRelief(interp, uid, (int *) ptr) != TCL_OK) {
  454.     return TCL_ERROR;
  455. }
  456. break;
  457.     case TK_CONFIG_CURSOR:
  458.     case TK_CONFIG_ACTIVE_CURSOR: {
  459. Tk_Cursor new, old;
  460. if (nullValue) {
  461.     new = None;
  462. } else {
  463.     uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  464.     new = Tk_GetCursor(interp, tkwin, uid);
  465.     if (new == None) {
  466. return TCL_ERROR;
  467.     }
  468. }
  469. old = *((Tk_Cursor *) ptr);
  470. if (old != None) {
  471.     Tk_FreeCursor(Tk_Display(tkwin), old);
  472. }
  473. *((Tk_Cursor *) ptr) = new;
  474. if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) {
  475.     Tk_DefineCursor(tkwin, new);
  476. }
  477. break;
  478.     }
  479.     case TK_CONFIG_JUSTIFY:
  480. uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  481. if (Tk_GetJustify(interp, uid, (Tk_Justify *) ptr) != TCL_OK) {
  482.     return TCL_ERROR;
  483. }
  484. break;
  485.     case TK_CONFIG_ANCHOR:
  486. uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  487. if (Tk_GetAnchor(interp, uid, (Tk_Anchor *) ptr) != TCL_OK) {
  488.     return TCL_ERROR;
  489. }
  490. break;
  491.     case TK_CONFIG_CAP_STYLE:
  492. uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  493. if (Tk_GetCapStyle(interp, uid, (int *) ptr) != TCL_OK) {
  494.     return TCL_ERROR;
  495. }
  496. break;
  497.     case TK_CONFIG_JOIN_STYLE:
  498. uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  499. if (Tk_GetJoinStyle(interp, uid, (int *) ptr) != TCL_OK) {
  500.     return TCL_ERROR;
  501. }
  502. break;
  503.     case TK_CONFIG_PIXELS:
  504. if (Tk_GetPixels(interp, tkwin, value, (int *) ptr)
  505. != TCL_OK) {
  506.     return TCL_ERROR;
  507. }
  508. break;
  509.     case TK_CONFIG_MM:
  510. if (Tk_GetScreenMM(interp, tkwin, value, (double *) ptr)
  511. != TCL_OK) {
  512.     return TCL_ERROR;
  513. }
  514. break;
  515.     case TK_CONFIG_WINDOW: {
  516. Tk_Window tkwin2;
  517. if (nullValue) {
  518.     tkwin2 = NULL;
  519. } else {
  520.     tkwin2 = Tk_NameToWindow(interp, value, tkwin);
  521.     if (tkwin2 == NULL) {
  522. return TCL_ERROR;
  523.     }
  524. }
  525. *((Tk_Window *) ptr) = tkwin2;
  526. break;
  527.     }
  528.     case TK_CONFIG_CUSTOM:
  529. if ((*specPtr->customPtr->parseProc)(
  530. specPtr->customPtr->clientData, interp, tkwin,
  531. value, widgRec, specPtr->offset) != TCL_OK) {
  532.     return TCL_ERROR;
  533. }
  534. break;
  535.     default: {
  536. char buf[64 + TCL_INTEGER_SPACE];
  537. sprintf(buf, "bad config table: unknown type %d",
  538. specPtr->type);
  539. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  540. return TCL_ERROR;
  541.     }
  542. }
  543. specPtr++;
  544.     } while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END));
  545.     return TCL_OK;
  546. }
  547. /*
  548.  *--------------------------------------------------------------
  549.  *
  550.  * Tk_ConfigureInfo --
  551.  *
  552.  * Return information about the configuration options
  553.  * for a window, and their current values.
  554.  *
  555.  * Results:
  556.  * Always returns TCL_OK.  The interp's result will be modified
  557.  * hold a description of either a single configuration option
  558.  * available for "widgRec" via "specs", or all the configuration
  559.  * options available.  In the "all" case, the result will
  560.  * available for "widgRec" via "specs".  The result will
  561.  * be a list, each of whose entries describes one option.
  562.  * Each entry will itself be a list containing the option's
  563.  * name for use on command lines, database name, database
  564.  * class, default value, and current value (empty string
  565.  * if none).  For options that are synonyms, the list will
  566.  * contain only two values:  name and synonym name.  If the
  567.  * "name" argument is non-NULL, then the only information
  568.  * returned is that for the named argument (i.e. the corresponding
  569.  * entry in the overall list is returned).
  570.  *
  571.  * Side effects:
  572.  * None.
  573.  *
  574.  *--------------------------------------------------------------
  575.  */
  576. int
  577. Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags)
  578.     Tcl_Interp *interp; /* Interpreter for error reporting. */
  579.     Tk_Window tkwin; /* Window corresponding to widgRec. */
  580.     Tk_ConfigSpec *specs; /* Describes legal options. */
  581.     char *widgRec; /* Record whose fields contain current
  582.  * values for options. */
  583.     CONST char *argvName; /* If non-NULL, indicates a single option
  584.  * whose info is to be returned.  Otherwise
  585.  * info is returned for all options. */
  586.     int flags; /* Used to specify additional flags
  587.  * that must be present in config specs
  588.  * for them to be considered. */
  589. {
  590.     register Tk_ConfigSpec *specPtr;
  591.     int needFlags, hateFlags;
  592.     char *list;
  593.     char *leader = "{";
  594.     needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
  595.     if (Tk_Depth(tkwin) <= 1) {
  596. hateFlags = TK_CONFIG_COLOR_ONLY;
  597.     } else {
  598. hateFlags = TK_CONFIG_MONO_ONLY;
  599.     }
  600.     /*
  601.      * Get the build of the config for this interpreter.
  602.      */
  603.     specs = GetCachedSpecs(interp, specs);
  604.     /*
  605.      * If information is only wanted for a single configuration
  606.      * spec, then handle that one spec specially.
  607.      */
  608.     Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
  609.     if (argvName != NULL) {
  610. specPtr = FindConfigSpec(interp, specs, argvName, needFlags,hateFlags);
  611. if (specPtr == NULL) {
  612.     return TCL_ERROR;
  613. }
  614. Tcl_SetResult(interp,
  615. FormatConfigInfo(interp, tkwin, specPtr, widgRec),
  616. TCL_DYNAMIC);
  617. return TCL_OK;
  618.     }
  619.     /*
  620.      * Loop through all the specs, creating a big list with all
  621.      * their information.
  622.      */
  623.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  624. if ((argvName != NULL) && (specPtr->argvName != argvName)) {
  625.     continue;
  626. }
  627. if (((specPtr->specFlags & needFlags) != needFlags)
  628. || (specPtr->specFlags & hateFlags)) {
  629.     continue;
  630. }
  631. if (specPtr->argvName == NULL) {
  632.     continue;
  633. }
  634. list = FormatConfigInfo(interp, tkwin, specPtr, widgRec);
  635. Tcl_AppendResult(interp, leader, list, "}", (char *) NULL);
  636. ckfree(list);
  637. leader = " {";
  638.     }
  639.     return TCL_OK;
  640. }
  641. /*
  642.  *--------------------------------------------------------------
  643.  *
  644.  * FormatConfigInfo --
  645.  *
  646.  * Create a valid Tcl list holding the configuration information
  647.  * for a single configuration option.
  648.  *
  649.  * Results:
  650.  * A Tcl list, dynamically allocated.  The caller is expected to
  651.  * arrange for this list to be freed eventually.
  652.  *
  653.  * Side effects:
  654.  * Memory is allocated.
  655.  *
  656.  *--------------------------------------------------------------
  657.  */
  658. static char *
  659. FormatConfigInfo(interp, tkwin, specPtr, widgRec)
  660.     Tcl_Interp *interp; /* Interpreter to use for things
  661.  * like floating-point precision. */
  662.     Tk_Window tkwin; /* Window corresponding to widget. */
  663.     register Tk_ConfigSpec *specPtr; /* Pointer to information describing
  664.  * option. */
  665.     char *widgRec; /* Pointer to record holding current
  666.  * values of info for widget. */
  667. {
  668.     CONST char *argv[6];
  669.     char *result;
  670.     char buffer[200];
  671.     Tcl_FreeProc *freeProc = (Tcl_FreeProc *) NULL;
  672.     argv[0] = specPtr->argvName;
  673.     argv[1] = specPtr->dbName;
  674.     argv[2] = specPtr->dbClass;
  675.     argv[3] = specPtr->defValue;
  676.     if (specPtr->type == TK_CONFIG_SYNONYM) {
  677. return Tcl_Merge(2, argv);
  678.     }
  679.     argv[4] = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer,
  680.     &freeProc);
  681.     if (argv[1] == NULL) {
  682. argv[1] = "";
  683.     }
  684.     if (argv[2] == NULL) {
  685. argv[2] = "";
  686.     }
  687.     if (argv[3] == NULL) {
  688. argv[3] = "";
  689.     }
  690.     if (argv[4] == NULL) {
  691. argv[4] = "";
  692.     }
  693.     result = Tcl_Merge(5, argv);
  694.     if (freeProc != NULL) {
  695. if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) {
  696.     ckfree((char *)argv[4]);
  697. } else {
  698.     (*freeProc)((char *)argv[4]);
  699. }
  700.     }
  701.     return result;
  702. }
  703. /*
  704.  *----------------------------------------------------------------------
  705.  *
  706.  * FormatConfigValue --
  707.  *
  708.  * This procedure formats the current value of a configuration
  709.  * option.
  710.  *
  711.  * Results:
  712.  * The return value is the formatted value of the option given
  713.  * by specPtr and widgRec.  If the value is static, so that it
  714.  * need not be freed, *freeProcPtr will be set to NULL;  otherwise
  715.  * *freeProcPtr will be set to the address of a procedure to
  716.  * free the result, and the caller must invoke this procedure
  717.  * when it is finished with the result.
  718.  *
  719.  * Side effects:
  720.  * None.
  721.  *
  722.  *----------------------------------------------------------------------
  723.  */
  724. static CONST char *
  725. FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, freeProcPtr)
  726.     Tcl_Interp *interp; /* Interpreter for use in real conversions. */
  727.     Tk_Window tkwin; /* Window corresponding to widget. */
  728.     Tk_ConfigSpec *specPtr; /* Pointer to information describing option.
  729.  * Must not point to a synonym option. */
  730.     char *widgRec; /* Pointer to record holding current
  731.  * values of info for widget. */
  732.     char *buffer; /* Static buffer to use for small values.
  733.  * Must have at least 200 bytes of storage. */
  734.     Tcl_FreeProc **freeProcPtr; /* Pointer to word to fill in with address
  735.  * of procedure to free the result, or NULL
  736.  * if result is static. */
  737. {
  738.     CONST char *ptr, *result;
  739.     *freeProcPtr = NULL;
  740.     ptr = widgRec + specPtr->offset;
  741.     result = "";
  742.     switch (specPtr->type) {
  743. case TK_CONFIG_BOOLEAN:
  744.     if (*((int *) ptr) == 0) {
  745. result = "0";
  746.     } else {
  747. result = "1";
  748.     }
  749.     break;
  750. case TK_CONFIG_INT:
  751.     sprintf(buffer, "%d", *((int *) ptr));
  752.     result = buffer;
  753.     break;
  754. case TK_CONFIG_DOUBLE:
  755.     Tcl_PrintDouble(interp, *((double *) ptr), buffer);
  756.     result = buffer;
  757.     break;
  758. case TK_CONFIG_STRING:
  759.     result = (*(char **) ptr);
  760.     if (result == NULL) {
  761. result = "";
  762.     }
  763.     break;
  764. case TK_CONFIG_UID: {
  765.     Tk_Uid uid = *((Tk_Uid *) ptr);
  766.     if (uid != NULL) {
  767. result = uid;
  768.     }
  769.     break;
  770. }
  771. case TK_CONFIG_COLOR: {
  772.     XColor *colorPtr = *((XColor **) ptr);
  773.     if (colorPtr != NULL) {
  774. result = Tk_NameOfColor(colorPtr);
  775.     }
  776.     break;
  777. }
  778. case TK_CONFIG_FONT: {
  779.     Tk_Font tkfont = *((Tk_Font *) ptr);
  780.     if (tkfont != NULL) {
  781. result = Tk_NameOfFont(tkfont);
  782.     }
  783.     break;
  784. }
  785. case TK_CONFIG_BITMAP: {
  786.     Pixmap pixmap = *((Pixmap *) ptr);
  787.     if (pixmap != None) {
  788. result = Tk_NameOfBitmap(Tk_Display(tkwin), pixmap);
  789.     }
  790.     break;
  791. }
  792. case TK_CONFIG_BORDER: {
  793.     Tk_3DBorder border = *((Tk_3DBorder *) ptr);
  794.     if (border != NULL) {
  795. result = Tk_NameOf3DBorder(border);
  796.     }
  797.     break;
  798. }
  799. case TK_CONFIG_RELIEF:
  800.     result = Tk_NameOfRelief(*((int *) ptr));
  801.     break;
  802. case TK_CONFIG_CURSOR:
  803. case TK_CONFIG_ACTIVE_CURSOR: {
  804.     Tk_Cursor cursor = *((Tk_Cursor *) ptr);
  805.     if (cursor != None) {
  806. result = Tk_NameOfCursor(Tk_Display(tkwin), cursor);
  807.     }
  808.     break;
  809. }
  810. case TK_CONFIG_JUSTIFY:
  811.     result = Tk_NameOfJustify(*((Tk_Justify *) ptr));
  812.     break;
  813. case TK_CONFIG_ANCHOR:
  814.     result = Tk_NameOfAnchor(*((Tk_Anchor *) ptr));
  815.     break;
  816. case TK_CONFIG_CAP_STYLE:
  817.     result = Tk_NameOfCapStyle(*((int *) ptr));
  818.     break;
  819. case TK_CONFIG_JOIN_STYLE:
  820.     result = Tk_NameOfJoinStyle(*((int *) ptr));
  821.     break;
  822. case TK_CONFIG_PIXELS:
  823.     sprintf(buffer, "%d", *((int *) ptr));
  824.     result = buffer;
  825.     break;
  826. case TK_CONFIG_MM:
  827.     Tcl_PrintDouble(interp, *((double *) ptr), buffer);
  828.     result = buffer;
  829.     break;
  830. case TK_CONFIG_WINDOW: {
  831.     Tk_Window tkwin;
  832.     tkwin = *((Tk_Window *) ptr);
  833.     if (tkwin != NULL) {
  834. result = Tk_PathName(tkwin);
  835.     }
  836.     break;
  837. }
  838. case TK_CONFIG_CUSTOM:
  839.     result = (*specPtr->customPtr->printProc)(
  840.     specPtr->customPtr->clientData, tkwin, widgRec,
  841.     specPtr->offset, freeProcPtr);
  842.     break;
  843. default: 
  844.     result = "?? unknown type ??";
  845.     }
  846.     return result;
  847. }
  848. /*
  849.  *----------------------------------------------------------------------
  850.  *
  851.  * Tk_ConfigureValue --
  852.  *
  853.  * This procedure returns the current value of a configuration
  854.  * option for a widget.
  855.  *
  856.  * Results:
  857.  * The return value is a standard Tcl completion code (TCL_OK or
  858.  * TCL_ERROR).  The interp's result will be set to hold either the value
  859.  * of the option given by argvName (if TCL_OK is returned) or
  860.  * an error message (if TCL_ERROR is returned).
  861.  *
  862.  * Side effects:
  863.  * None.
  864.  *
  865.  *----------------------------------------------------------------------
  866.  */
  867. int
  868. Tk_ConfigureValue(interp, tkwin, specs, widgRec, argvName, flags)
  869.     Tcl_Interp *interp; /* Interpreter for error reporting. */
  870.     Tk_Window tkwin; /* Window corresponding to widgRec. */
  871.     Tk_ConfigSpec *specs; /* Describes legal options. */
  872.     char *widgRec; /* Record whose fields contain current
  873.  * values for options. */
  874.     CONST char *argvName; /* Gives the command-line name for the
  875.  * option whose value is to be returned. */
  876.     int flags; /* Used to specify additional flags
  877.  * that must be present in config specs
  878.  * for them to be considered. */
  879. {
  880.     Tk_ConfigSpec *specPtr;
  881.     int needFlags, hateFlags;
  882.     Tcl_FreeProc *freeProc;
  883.     CONST char *result;
  884.     char buffer[200];
  885.     needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
  886.     if (Tk_Depth(tkwin) <= 1) {
  887. hateFlags = TK_CONFIG_COLOR_ONLY;
  888.     } else {
  889. hateFlags = TK_CONFIG_MONO_ONLY;
  890.     }
  891.     /*
  892.      * Get the build of the config for this interpreter.
  893.      */
  894.     specs = GetCachedSpecs(interp, specs);
  895.     specPtr = FindConfigSpec(interp, specs, argvName, needFlags, hateFlags);
  896.     if (specPtr == NULL) {
  897. return TCL_ERROR;
  898.     }
  899.     result = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, &freeProc);
  900.     Tcl_SetResult(interp, (char *) result, TCL_VOLATILE);
  901.     if (freeProc != NULL) {
  902. if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) {
  903.     ckfree((char *)result);
  904. } else {
  905.     (*freeProc)((char *)result);
  906. }
  907.     }
  908.     return TCL_OK;
  909. }
  910. /*
  911.  *----------------------------------------------------------------------
  912.  *
  913.  * Tk_FreeOptions --
  914.  *
  915.  * Free up all resources associated with configuration options.
  916.  *
  917.  * Results:
  918.  * None.
  919.  *
  920.  * Side effects:
  921.  * Any resource in widgRec that is controlled by a configuration
  922.  * option (e.g. a Tk_3DBorder or XColor) is freed in the appropriate
  923.  * fashion.
  924.  *
  925.  *----------------------------------------------------------------------
  926.  */
  927. /* ARGSUSED */
  928. void
  929. Tk_FreeOptions(specs, widgRec, display, needFlags)
  930.     Tk_ConfigSpec *specs; /* Describes legal options. */
  931.     char *widgRec; /* Record whose fields contain current
  932.  * values for options. */
  933.     Display *display; /* X display; needed for freeing some
  934.  * resources. */
  935.     int needFlags; /* Used to specify additional flags
  936.  * that must be present in config specs
  937.  * for them to be considered. */
  938. {
  939.     register Tk_ConfigSpec *specPtr;
  940.     char *ptr;
  941.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  942. if ((specPtr->specFlags & needFlags) != needFlags) {
  943.     continue;
  944. }
  945. ptr = widgRec + specPtr->offset;
  946. switch (specPtr->type) {
  947.     case TK_CONFIG_STRING:
  948. if (*((char **) ptr) != NULL) {
  949.     ckfree(*((char **) ptr));
  950.     *((char **) ptr) = NULL;
  951. }
  952. break;
  953.     case TK_CONFIG_COLOR:
  954. if (*((XColor **) ptr) != NULL) {
  955.     Tk_FreeColor(*((XColor **) ptr));
  956.     *((XColor **) ptr) = NULL;
  957. }
  958. break;
  959.     case TK_CONFIG_FONT:
  960. Tk_FreeFont(*((Tk_Font *) ptr));
  961. *((Tk_Font *) ptr) = NULL;
  962. break;
  963.     case TK_CONFIG_BITMAP:
  964. if (*((Pixmap *) ptr) != None) {
  965.     Tk_FreeBitmap(display, *((Pixmap *) ptr));
  966.     *((Pixmap *) ptr) = None;
  967. }
  968. break;
  969.     case TK_CONFIG_BORDER:
  970. if (*((Tk_3DBorder *) ptr) != NULL) {
  971.     Tk_Free3DBorder(*((Tk_3DBorder *) ptr));
  972.     *((Tk_3DBorder *) ptr) = NULL;
  973. }
  974. break;
  975.     case TK_CONFIG_CURSOR:
  976.     case TK_CONFIG_ACTIVE_CURSOR:
  977. if (*((Tk_Cursor *) ptr) != None) {
  978.     Tk_FreeCursor(display, *((Tk_Cursor *) ptr));
  979.     *((Tk_Cursor *) ptr) = None;
  980. }
  981. }
  982.     }
  983. }
  984. /*
  985.  *--------------------------------------------------------------
  986.  *
  987.  * GetCachedSpecs --
  988.  *
  989.  *Returns a writable per-interpreter (and hence thread-local) copy of
  990.  *the given spec-table with (some of) the char* fields converted into
  991.  *Tk_Uid fields; this copy will be released when the interpreter
  992.  *terminates (during AssocData cleanup).
  993.  *
  994.  * Results:
  995.  *A pointer to the copied table.
  996.  *
  997.  * Notes:
  998.  *The conversion to Tk_Uid is only done the first time, when the table
  999.  *copy is taken. After that, the table is assumed to have Tk_Uids where
  1000.  *they are needed. The time of deletion of the caches isn't very
  1001.  *important unless you've got a lot of code that uses Tk_ConfigureWidget
  1002.  *(or *Info or *Value} when the interpreter is being deleted.
  1003.  *
  1004.  *--------------------------------------------------------------
  1005.  */
  1006. static Tk_ConfigSpec *
  1007. GetCachedSpecs(interp, staticSpecs)
  1008.     Tcl_Interp *interp; /* Interpreter in which to store the cache. */
  1009.     const Tk_ConfigSpec *staticSpecs;
  1010. /* Value to cache a copy of; it is also used
  1011.  * as a key into the cache. */
  1012. {
  1013.     Tk_ConfigSpec *cachedSpecs;
  1014.     Tcl_HashTable *specCacheTablePtr;
  1015.     Tcl_HashEntry *entryPtr;
  1016.     int isNew;
  1017.     /*
  1018.      * Get (or allocate if it doesn't exist) the hash table that the writable
  1019.      * copies of the widget specs are stored in. In effect, this is
  1020.      * self-initializing code.
  1021.      */
  1022.     specCacheTablePtr = (Tcl_HashTable *)
  1023.     Tcl_GetAssocData(interp, "tkConfigSpec.threadTable", NULL);
  1024.     if (specCacheTablePtr == NULL) {
  1025. specCacheTablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  1026. Tcl_InitHashTable(specCacheTablePtr, TCL_ONE_WORD_KEYS);
  1027. Tcl_SetAssocData(interp, "tkConfigSpec.threadTable",
  1028. DeleteSpecCacheTable, (ClientData) specCacheTablePtr);
  1029.     }
  1030.     /*
  1031.      * Look up or create the hash entry that the constant specs are mapped to,
  1032.      * which will have the writable specs as its associated value.
  1033.      */
  1034.     entryPtr = Tcl_CreateHashEntry(specCacheTablePtr, (char *) staticSpecs,
  1035.     &isNew);
  1036.     if (isNew) {
  1037. unsigned int entrySpace = sizeof(Tk_ConfigSpec);
  1038. const Tk_ConfigSpec *staticSpecPtr;
  1039. Tk_ConfigSpec *specPtr;
  1040. /*
  1041.  * OK, no working copy in this interpreter so copy. Need to work out
  1042.  * how much space to allocate first.
  1043.  */
  1044. for (staticSpecPtr=staticSpecs; staticSpecPtr->type!=TK_CONFIG_END;
  1045. staticSpecPtr++) {
  1046.     entrySpace += sizeof(Tk_ConfigSpec);
  1047. }
  1048. /*
  1049.  * Now allocate our working copy's space and copy over the contents
  1050.  * from the master copy.
  1051.  */
  1052. cachedSpecs = (Tk_ConfigSpec *) ckalloc(entrySpace);
  1053. memcpy((void *) cachedSpecs, (void *) staticSpecs, entrySpace);
  1054. Tcl_SetHashValue(entryPtr, (ClientData) cachedSpecs);
  1055. /*
  1056.  * Finally, go through and replace database names, database classes
  1057.  * and default values with Tk_Uids. This is the bit that has to be
  1058.  * per-thread.
  1059.  */
  1060. for (specPtr=cachedSpecs; specPtr->type!=TK_CONFIG_END; specPtr++) {
  1061.     if (specPtr->argvName != NULL) {
  1062. if (specPtr->dbName != NULL) {
  1063.     specPtr->dbName = Tk_GetUid(specPtr->dbName);
  1064. }
  1065. if (specPtr->dbClass != NULL) {
  1066.     specPtr->dbClass = Tk_GetUid(specPtr->dbClass);
  1067. }
  1068. if (specPtr->defValue != NULL) {
  1069.     specPtr->defValue = Tk_GetUid(specPtr->defValue);
  1070. }
  1071.     }
  1072. }
  1073.     } else {
  1074. cachedSpecs = (Tk_ConfigSpec *) Tcl_GetHashValue(entryPtr);
  1075.     }
  1076.     return cachedSpecs;
  1077. }
  1078. /*
  1079.  *--------------------------------------------------------------
  1080.  *
  1081.  * DeleteSpecCacheTable --
  1082.  *
  1083.  * Delete the per-interpreter copy of all the Tk_ConfigSpec tables which
  1084.  * were stored in the interpreter's assoc-data store.
  1085.  *
  1086.  * Results:
  1087.  * None
  1088.  *
  1089.  * Side effects:
  1090.  * None
  1091.  *
  1092.  *--------------------------------------------------------------
  1093.  */
  1094. static void
  1095. DeleteSpecCacheTable(clientData, interp)
  1096.     ClientData clientData;
  1097.     Tcl_Interp *interp;
  1098. {
  1099.     Tcl_HashTable *tablePtr = (Tcl_HashTable *) clientData;
  1100.     Tcl_HashEntry *entryPtr;
  1101.     Tcl_HashSearch search;
  1102.     for (entryPtr = Tcl_FirstHashEntry(tablePtr,&search); entryPtr != NULL;
  1103.     entryPtr = Tcl_NextHashEntry(&search)) {
  1104. /*
  1105.  * Someone else deallocates the Tk_Uids themselves.
  1106.  */
  1107. ckfree((char *) Tcl_GetHashValue(entryPtr));
  1108.     }
  1109.     Tcl_DeleteHashTable(tablePtr);
  1110.     ckfree((char *) tablePtr);
  1111. }