#include "tkInt.h"
#define INIT 0x20
static int DoConfig _ANSI_ARGS_((Tcl_Interp *interp,
Tk_Window tkwin, Tk_ConfigSpec *specPtr,
Tk_Uid value, int valueIsUid, char *widgRec));
static Tk_ConfigSpec * FindConfigSpec _ANSI_ARGS_((Tcl_Interp *interp,
Tk_ConfigSpec *specs, char *argvName,
int needFlags, int hateFlags));
static char * FormatConfigInfo _ANSI_ARGS_((Tcl_Interp *interp,
Tk_Window tkwin, Tk_ConfigSpec *specPtr,
char *widgRec));
static char * FormatConfigValue _ANSI_ARGS_((Tcl_Interp *interp,
Tk_Window tkwin, Tk_ConfigSpec *specPtr,
char *widgRec, char *buffer,
Tcl_FreeProc **freeProcPtr));
int
Tk_ConfigureWidget(interp, tkwin, specs, argc, argv, widgRec, flags)
Tcl_Interp *interp;
Tk_Window tkwin;
Tk_ConfigSpec *specs;
int argc;
char **argv;
char *widgRec;
int flags;
{
register Tk_ConfigSpec *specPtr;
Tk_Uid value;
int needFlags;
int hateFlags;
needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
if (Tk_Depth(tkwin) <= 1) {
hateFlags = TK_CONFIG_COLOR_ONLY;
} else {
hateFlags = TK_CONFIG_MONO_ONLY;
}
for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
if (!(specPtr->specFlags & INIT) && (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);
}
}
specPtr->specFlags = (specPtr->specFlags & ~TK_CONFIG_OPTION_SPECIFIED)
| INIT;
}
for ( ; argc > 0; argc -= 2, argv += 2) {
specPtr = FindConfigSpec(interp, specs, *argv, needFlags, hateFlags);
if (specPtr == NULL) {
return TCL_ERROR;
}
if (argc < 2) {
Tcl_AppendResult(interp, "value for \"", *argv,
"\" missing", (char *) NULL);
return TCL_ERROR;
}
if (DoConfig(interp, tkwin, specPtr, argv[1], 0, widgRec) != TCL_OK) {
char msg[100];
sprintf(msg, "\n (processing \"%.40s\" option)",
specPtr->argvName);
Tcl_AddErrorInfo(interp, msg);
return TCL_ERROR;
}
specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED;
}
if (!(flags & TK_CONFIG_ARGV_ONLY)) {
for (specPtr = specs; 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) {
if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
TCL_OK) {
char msg[200];
sprintf(msg, "\n (%s \"%.50s\" in widget \"%.50s\")",
"database entry for",
specPtr->dbName, Tk_PathName(tkwin));
Tcl_AddErrorInfo(interp, msg);
return TCL_ERROR;
}
} else {
value = specPtr->defValue;
if ((value != NULL) && !(specPtr->specFlags
& TK_CONFIG_DONT_SET_DEFAULT)) {
if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
TCL_OK) {
char msg[200];
sprintf(msg,
"\n (%s \"%.50s\" in widget \"%.50s\")",
"default value for",
specPtr->dbName, Tk_PathName(tkwin));
Tcl_AddErrorInfo(interp, msg);
return TCL_ERROR;
}
}
}
}
}
return TCL_OK;
}
static Tk_ConfigSpec *
FindConfigSpec(interp, specs, argvName, needFlags, hateFlags)
Tcl_Interp *interp;
Tk_ConfigSpec *specs;
char *argvName;
int needFlags;
int hateFlags;
{
register Tk_ConfigSpec *specPtr;
register char c;
Tk_ConfigSpec *matchPtr;
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_AppendResult(interp, "ambiguous option \"", argvName,
"\"", (char *) NULL);
return (Tk_ConfigSpec *) NULL;
}
matchPtr = specPtr;
}
if (matchPtr == NULL) {
Tcl_AppendResult(interp, "unknown option \"", argvName,
"\"", (char *) NULL);
return (Tk_ConfigSpec *) NULL;
}
gotMatch:
specPtr = matchPtr;
if (specPtr->type == TK_CONFIG_SYNONYM) {
for (specPtr = specs; ; specPtr++) {
if (specPtr->type == TK_CONFIG_END) {
Tcl_AppendResult(interp,
"couldn't find synonym for option \"",
argvName, "\"", (char *) NULL);
return (Tk_ConfigSpec *) NULL;
}
if ((specPtr->dbName == matchPtr->dbName)
&& (specPtr->type != TK_CONFIG_SYNONYM)
&& ((specPtr->specFlags & needFlags) == needFlags)
&& !(specPtr->specFlags & hateFlags)) {
break;
}
}
}
return specPtr;
}
static int
DoConfig(interp, tkwin, specPtr, value, valueIsUid, widgRec)
Tcl_Interp *interp;
Tk_Window tkwin;
Tk_ConfigSpec *specPtr;
char *value;
int valueIsUid;
char *widgRec;
{
char *ptr;
Tk_Uid uid;
int nullValue;
nullValue = 0;
if ((*value == 0) && (specPtr->specFlags & TK_CONFIG_NULL_OK)) {
nullValue = 1;
}
do {
ptr = widgRec + specPtr->offset;
switch (specPtr->type) {
case TK_CONFIG_BOOLEAN:
if (Tcl_GetBoolean(interp, value, (int *) ptr) != TCL_OK) {
return TCL_ERROR;
}
break;
case TK_CONFIG_INT:
if (Tcl_GetInt(interp, value, (int *) ptr) != TCL_OK) {
return TCL_ERROR;
}
break;
case TK_CONFIG_DOUBLE:
if (Tcl_GetDouble(interp, value, (double *) ptr) != TCL_OK) {
return TCL_ERROR;
}
break;
case TK_CONFIG_STRING: {
char *old, *new;
if (nullValue) {
new = NULL;
} else {
new = (char *) ckalloc((unsigned) (strlen(value) + 1));
strcpy(new, value);
}
old = *((char **) ptr);
if (old != NULL) {
ckfree(old);
}
*((char **) ptr) = new;
break;
}
case TK_CONFIG_UID:
if (nullValue) {
*((Tk_Uid *) ptr) = NULL;
} else {
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
*((Tk_Uid *) ptr) = uid;
}
break;
case TK_CONFIG_COLOR: {
XColor *newPtr, *oldPtr;
if (nullValue) {
newPtr = NULL;
} else {
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
newPtr = Tk_GetColor(interp, tkwin, uid);
if (newPtr == NULL) {
return TCL_ERROR;
}
}
oldPtr = *((XColor **) ptr);
if (oldPtr != NULL) {
Tk_FreeColor(oldPtr);
}
*((XColor **) ptr) = newPtr;
break;
}
case TK_CONFIG_FONT: {
XFontStruct *newPtr, *oldPtr;
if (nullValue) {
newPtr = NULL;
} else {
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
newPtr = Tk_GetFontStruct(interp, tkwin, uid);
if (newPtr == NULL) {
return TCL_ERROR;
}
}
oldPtr = *((XFontStruct **) ptr);
if (oldPtr != NULL) {
Tk_FreeFontStruct(oldPtr);
}
*((XFontStruct **) ptr) = newPtr;
break;
}
case TK_CONFIG_BITMAP: {
Pixmap new, old;
if (nullValue) {
new = None;
} else {
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
new = Tk_GetBitmap(interp, tkwin, uid);
if (new == None) {
return TCL_ERROR;
}
}
old = *((Pixmap *) ptr);
if (old != None) {
Tk_FreeBitmap(Tk_Display(tkwin), old);
}
*((Pixmap *) ptr) = new;
break;
}
case TK_CONFIG_BORDER: {
Tk_3DBorder new, old;
if (nullValue) {
new = NULL;
} else {
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
new = Tk_Get3DBorder(interp, tkwin, uid);
if (new == NULL) {
return TCL_ERROR;
}
}
old = *((Tk_3DBorder *) ptr);
if (old != NULL) {
Tk_Free3DBorder(old);
}
*((Tk_3DBorder *) ptr) = new;
break;
}
case TK_CONFIG_RELIEF:
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
if (Tk_GetRelief(interp, uid, (int *) ptr) != TCL_OK) {
return TCL_ERROR;
}
break;
case TK_CONFIG_CURSOR:
case TK_CONFIG_ACTIVE_CURSOR: {
Tk_Cursor new, old;
if (nullValue) {
new = None;
} else {
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
new = Tk_GetCursor(interp, tkwin, uid);
if (new == None) {
return TCL_ERROR;
}
}
old = *((Tk_Cursor *) ptr);
if (old != None) {
Tk_FreeCursor(Tk_Display(tkwin), old);
}
*((Tk_Cursor *) ptr) = new;
if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) {
Tk_DefineCursor(tkwin, new);
}
break;
}
case TK_CONFIG_JUSTIFY:
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
if (Tk_GetJustify(interp, uid, (Tk_Justify *) ptr) != TCL_OK) {
return TCL_ERROR;
}
break;
case TK_CONFIG_ANCHOR:
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
if (Tk_GetAnchor(interp, uid, (Tk_Anchor *) ptr) != TCL_OK) {
return TCL_ERROR;
}
break;
case TK_CONFIG_CAP_STYLE:
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
if (Tk_GetCapStyle(interp, uid, (int *) ptr) != TCL_OK) {
return TCL_ERROR;
}
break;
case TK_CONFIG_JOIN_STYLE:
uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
if (Tk_GetJoinStyle(interp, uid, (int *) ptr) != TCL_OK) {
return TCL_ERROR;
}
break;
case TK_CONFIG_PIXELS:
if (Tk_GetPixels(interp, tkwin, value, (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, widgRec, specPtr->offset) != TCL_OK) {
return TCL_ERROR;
}
break;
default: {
sprintf(interp->result, "bad config table: unknown type %d",
specPtr->type);
return TCL_ERROR;
}
}
specPtr++;
} while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END));
return TCL_OK;
}
int
Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags)
Tcl_Interp *interp;
Tk_Window tkwin;
Tk_ConfigSpec *specs;
char *widgRec;
char *argvName;
int flags;
{
register Tk_ConfigSpec *specPtr;
int needFlags, hateFlags;
char *list;
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;
}
Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
if (argvName != NULL) {
specPtr = FindConfigSpec(interp, specs, argvName, needFlags,
hateFlags);
if (specPtr == NULL) {
return TCL_ERROR;
}
interp->result = FormatConfigInfo(interp, tkwin, specPtr, widgRec);
interp->freeProc = TCL_DYNAMIC;
return TCL_OK;
}
for (specPtr = specs; 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) {
continue;
}
list = FormatConfigInfo(interp, tkwin, specPtr, widgRec);
Tcl_AppendResult(interp, leader, list, "}", (char *) NULL);
ckfree(list);
leader = " {";
}
return TCL_OK;
}
static char *
FormatConfigInfo(interp, tkwin, specPtr, widgRec)
Tcl_Interp *interp;
Tk_Window tkwin;
register Tk_ConfigSpec *specPtr;
char *widgRec;
{
char *argv[6], *result;
char buffer[200];
Tcl_FreeProc *freeProc = (Tcl_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) || (freeProc == (Tcl_FreeProc *) free)) {
ckfree(argv[4]);
} else {
(*freeProc)(argv[4]);
}
}
return result;
}
static char *
FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, freeProcPtr)
Tcl_Interp *interp;
Tk_Window tkwin;
Tk_ConfigSpec *specPtr;
char *widgRec;
char *buffer;
Tcl_FreeProc **freeProcPtr;
{
char *ptr, *result;
*freeProcPtr = NULL;
ptr = widgRec + specPtr->offset;
result = "";
switch (specPtr->type) {
case TK_CONFIG_BOOLEAN:
if (*((int *) ptr) == 0) {
result = "0";
} else {
result = "1";
}
break;
case TK_CONFIG_INT:
sprintf(buffer, "%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: {
XFontStruct *fontStructPtr = *((XFontStruct **) ptr);
if (fontStructPtr != NULL) {
result = Tk_NameOfFontStruct(fontStructPtr);
}
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 != None) {
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:
sprintf(buffer, "%d", *((int *) ptr));
result = buffer;
break;
case TK_CONFIG_MM:
Tcl_PrintDouble(interp, *((double *) ptr), buffer);
result = buffer;
break;
case TK_CONFIG_WINDOW: {
Tk_Window tkwin;
tkwin = *((Tk_Window *) ptr);
if (tkwin != NULL) {
result = Tk_PathName(tkwin);
}
break;
}
case TK_CONFIG_CUSTOM:
result = (*specPtr->customPtr->printProc)(
specPtr->customPtr->clientData, tkwin, widgRec,
specPtr->offset, freeProcPtr);
break;
default:
result = "?? unknown type ??";
}
return result;
}
int
Tk_ConfigureValue(interp, tkwin, specs, widgRec, argvName, flags)
Tcl_Interp *interp;
Tk_Window tkwin;
Tk_ConfigSpec *specs;
char *widgRec;
char *argvName;
int flags;
{
Tk_ConfigSpec *specPtr;
int needFlags, hateFlags;
needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
if (Tk_Depth(tkwin) <= 1) {
hateFlags = TK_CONFIG_COLOR_ONLY;
} else {
hateFlags = TK_CONFIG_MONO_ONLY;
}
specPtr = FindConfigSpec(interp, specs, argvName, needFlags, hateFlags);
if (specPtr == NULL) {
return TCL_ERROR;
}
interp->result = FormatConfigValue(interp, tkwin, specPtr, widgRec,
interp->result, &interp->freeProc);
return TCL_OK;
}
void
Tk_FreeOptions(specs, widgRec, display, needFlags)
Tk_ConfigSpec *specs;
char *widgRec;
Display *display;
int needFlags;
{
register Tk_ConfigSpec *specPtr;
char *ptr;
for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
if ((specPtr->specFlags & needFlags) != needFlags) {
continue;
}
ptr = widgRec + specPtr->offset;
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:
if (*((XFontStruct **) ptr) != NULL) {
Tk_FreeFontStruct(*((XFontStruct **) ptr));
*((XFontStruct **) 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) != None) {
Tk_FreeCursor(display, *((Tk_Cursor *) ptr));
*((Tk_Cursor *) ptr) = None;
}
}
}
}