/*
* tkoWidget.c --
*
* This file contains the tko widget class.
*
* Copyright (c) 2019 Rene Zaumseil
*
*/
#include "tkoWidget.h"
#include "tclOOInt.h" /*TODO needed for Widget_GetClassName() below */
/*
* Widget_GetClassName --
* Return class name of object.
* Should be OO core function.
*
* Results:
* Name of class or NULL on error.
*
* Side effects:
* Use internal OO structures!!!
*/
Tcl_Obj *
Widget_GetClassName(
Tcl_Interp * interp,
Tcl_Object object)
{
Tcl_Object classPtr;
classPtr = (Tcl_Object)(((Object *)object)->selfCls->thisPtr);
if (classPtr == NULL) return NULL;
return Tcl_GetObjectName(interp, classPtr);
}
/*
* Widget option.
*/
typedef struct WidgetOption {
Tcl_Obj *option; /* Name of option */
Tcl_Obj *dbname; /* Database name or name of synonym option */
Tcl_Obj *dbclass; /* Class name or NULL for synonym options */
Tcl_Obj *defvalue; /* Default value from initialization */
Tcl_Obj *flags; /* Default value from initialization */
Tcl_Obj *value; /* Contain last known value of option */
int flagbits; /* see flags in struct Tko_WidgetOptionDefine */
} WidgetOption;
/*
* Clientdata of option methods.
*/
typedef struct WidgetClientdata {
Tcl_MethodType method;
Tcl_Obj *option;
int offset;
int type;
int flags;
} WidgetClientdata;
typedef struct TkoThreadData {
/* UID of class sctring */
Tk_Uid Uid_class;
Tk_Uid Uid_empty;
/* Static string objects. */
Tcl_Obj *Obj_empty; /* "" */
Tcl_Obj *Obj_tko__option; /* "::tko::_option" */
Tcl_Obj *Obj_tko__eventoption; /* "::tko::_eventoption" */
Tcl_Obj *Obj_next; /* "next" */
Tcl_Obj *Obj_uplevel; /* "::uplevel" */
Tcl_Obj *Obj_oo_define; /* "::oo::define" */
Tcl_Obj *Obj_oo_objdefine; /* "::oo::objdefine" */
Tcl_Obj *Obj_method; /* "method" */
Tcl_Obj *Obj__tko_configure; /* "_tko_configure" */
Tcl_Obj *Obj__tko; /* "_tko" */
Tcl_Obj *Obj_cget; /* "cget" */
Tcl_Obj *Obj_configure; /* "configure" */
Tcl_Obj *Obj_tko; /* "::tko" */
Tcl_Obj *Obj_tko_widget; /* "::tko::widget" */
Tcl_Obj *Obj_lsort; /* "::lsort" */
Tcl_Obj *Obj_point; /* "." */
Tcl_Obj *Obj_point2; /* ".." */
Tcl_Obj *Obj__screen; /* "-screen" */
Tcl_Obj *Obj_flags_r; /* "r" */
Tcl_Obj *Obj_flags_rh; /* "rh" */
Tcl_Obj *Obj_flags_h; /* "h" */
Tcl_Obj *Obj_rename; /* "rename" */
Tcl_Obj *Obj_tko__self; /* "::tko::_self" */
} TkoThreadData;
static Tcl_ThreadDataKey tkoKey;
/*
* Methods
*/
static int WidgetMethod_cget(
ClientData clientData,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[]);
static int WidgetMethod_configure(
ClientData clientData,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[]);
static int WidgetMethod_tko_configure(
ClientData clientData,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[]);
static int WidgetMethod_tko(
ClientData clientData,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[]);
/*
* Functions
*/
static char *WidgetOptionTrace(
ClientData clientData,
Tcl_Interp * interp,
const char *name1,
const char *name2,
int flags);
static void WidgetOptionDelEntry(
Tcl_HashEntry * entry);
static void WidgetEventProc(
ClientData clientData,
XEvent * eventPtr);
static void WidgetEventChanged(
Tko_Widget *widget);
static int WidgetOptionAdd(
Tcl_Interp * interp,
Tko_Widget * widget,
Tcl_Obj * option,
Tcl_Obj * dbname,
Tcl_Obj * dbclass,
Tcl_Obj * defvalue,
Tcl_Obj * flags,
Tcl_Obj * value,
int initmode);
static int WidgetOptionGet(
Tcl_Interp * interp,
Tko_Widget * widget,
Tcl_Obj * option);
static int WidgetOptionSet(
Tcl_Interp * interp,
Tko_Widget * widget,
Tcl_Obj * option,
Tcl_Obj * value);
static void WidgetMetaDestroy(
Tko_Widget * widget);
static void WidgetMetaDelete(
ClientData clientData);
static int WidgetMethod_(
ClientData clientData,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[]);
static int WidgetFlagsObj(
Tcl_Obj *flagsPtr,
int *flags);
static int WidgetFlagsHideGet(
Tcl_Obj *flags);
static Tcl_Obj *WidgetFlagsHideSet(
Tcl_Obj *flags);
static Tcl_Obj *WidgetFlagsHideUnset(
Tcl_Obj *flags);
static void WidgetClientdataDelete(
ClientData clientdata);
static int WidgetClientdataClone(
Tcl_Interp *interp,
ClientData clientdata,
ClientData *newPtr);
static int WidgetDestructor(
ClientData clientData,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[]);
static int WidgetWrapConstructor(
ClientData clientData,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[]);
static int WidgetClassConstructor(
ClientData clientData,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[]);
static void WidgetDeleteTkwin(
Tko_Widget *widget);
/* List of all internally defined public and private methods. */
#define TKO_1 TCL_OO_METHOD_VERSION_CURRENT
static Tcl_MethodType tkoWidgetMethods[] = {
{ TKO_1, NULL, WidgetClassConstructor, NULL, NULL },
{ TKO_1, NULL, WidgetWrapConstructor, NULL, NULL },
{ TKO_1, NULL, WidgetDestructor, NULL, NULL },
{ TKO_1, "cget", WidgetMethod_cget, NULL, NULL },
{ TKO_1, "configure", WidgetMethod_configure, NULL, NULL },
{ TKO_1, "_tko_configure", WidgetMethod_tko_configure, NULL, NULL },
{ TKO_1, "_tko", WidgetMethod_tko, NULL, NULL },
};
/*
* tkoWidgetMeta --
* Identifier for attached tko widget data.
*/
Tcl_ObjectMetadataType tkoWidgetMeta = {
TCL_OO_METADATA_VERSION_CURRENT,
"tkoWidgetMeta",
WidgetMetaDelete,
NULL
};
/*
* Tko_TkoObjCmd --
* Implementation of the "::tko" command.
* Initialization of new widgets.
* Configuration of widget class options.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Create available oo::class tko widgets.
* Add, delete return, hide and show options.
*/
int
Tko_TkoObjCmd(
ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const myOptions[] = {
"initclass", "initfrom", "initwrap",
"eventoption",
"optiondef", "optiondel","optionget",
"optionhide","optionshow",NULL
};
enum options {
MY_INITCLASS, MY_INITFROM, MY_INITWRAP,
MY_EVENTOPTION,
MY_OPTIONDEF, MY_OPTIONDEL, MY_OPTIONGET,
MY_OPTIONHIDE, MY_OPTIONSHOW
};
int index;
Tcl_Obj *dictPtr;
Tcl_Obj *namePtr;
Tcl_Obj *listPtr;
int ret;
int i;
Tcl_DictSearch search;
Tcl_Obj *key, *value;
int argObjc;
Tcl_Obj **argObjv;
int done;
Tcl_Obj *myCmd[6];
const char *ch, *ch1;
int length;
Tcl_Obj *tmpPtr;
Tcl_Class clazz;
Tcl_Object object;
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
(void)dummy;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObjStruct(interp, objv[1], myOptions,
sizeof(char *), "option", 0, &index) != TCL_OK) {
return TCL_ERROR;
}
switch ((enum options) index) {
case MY_INITCLASS: /* Add cget/configure functionalite to current class */
if (objc != 2) {
Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR;
}
ret = Tcl_Eval(interp, "set ::tko::_option([self]) {} ; variable tko ; self");
if (ret != TCL_OK) {
return TCL_ERROR;
}
/* Get class object */
tmpPtr = Tcl_GetObjResult(interp);
if ((object = Tcl_GetObjectFromObj(interp, tmpPtr)) == NULL
|| (clazz = Tcl_GetObjectAsClass(object)) == NULL) {
return TCL_ERROR;
}
/*
* Add methods
*/
Tcl_ClassSetConstructor(interp, clazz,
Tcl_NewMethod(interp, clazz, NULL, 1, &tkoWidgetMethods[0], NULL));
Tcl_ClassSetDestructor(interp, clazz,
Tcl_NewMethod(interp, clazz, NULL, 1, &tkoWidgetMethods[2], NULL));
Tcl_NewMethod(interp, clazz, tkoPtr->Obj_cget, 1, &tkoWidgetMethods[3], NULL);
Tcl_NewMethod(interp, clazz, tkoPtr->Obj_configure, 1, &tkoWidgetMethods[4], NULL);
Tcl_NewMethod(interp, clazz, tkoPtr->Obj__tko_configure, 0, &tkoWidgetMethods[5], NULL);
Tcl_NewMethod(interp, clazz, tkoPtr->Obj__tko, 0, &tkoWidgetMethods[6], NULL);
return TCL_OK;
case MY_INITFROM: /* Initialize new tko class */
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "tkoclass");
return TCL_ERROR;
}
/* Use fqn superclass and get all options from it */
ch = Tcl_GetStringFromObj(objv[2], &length);
if (length < 2 || ch[0] != ':') {
tmpPtr = Tcl_ObjPrintf(
"set ::tko::_option([self]) {} ; unexport destroy; variable tko; {*}$::tko::_unknown\n"
"superclass ::%s ; set ::tko::_option([self]) [::tko optionget ::%s]",
ch,ch);
}
else{
tmpPtr = Tcl_ObjPrintf(
"set ::tko::_option([self]) {} ; unexport destroy; variable tko; {*}$::tko::_unknown\n"
"superclass %s ; set ::tko::_option([self]) [::tko optionget %s]",
ch,ch);
}
Tcl_IncrRefCount(tmpPtr);
ret = Tcl_Eval(interp, Tcl_GetString(tmpPtr));
Tcl_DecrRefCount(tmpPtr);
if (ret != TCL_OK) {
return TCL_ERROR;
}
return TCL_OK;
case MY_INITWRAP: /* Wrap widget in new class */
if (objc != 5) {
Tcl_WrongNumArgs(interp, 2, objv, "widget readonlyoptionlist methodlist");
return TCL_ERROR;
}
/* Create fqn widgetname */
ch = Tcl_GetStringFromObj(objv[2], &length);
if (length < 2 || ch[0] != ':') {
namePtr = Tcl_ObjPrintf("::%s", Tcl_GetString(objv[2]));
}
else {
namePtr = objv[2];
}
Tcl_IncrRefCount(namePtr);
ch = Tcl_GetString(namePtr);
ch1 = Tcl_GetString(objv[3]);
tmpPtr = Tcl_ObjPrintf("set ::tko::_option([self]) {}\n"
"unexport destroy ; variable tko\n"
"::tko::_initwrap [self] %s {%s} {%s}\n"
"self method unknown {pathName args} {\n"
" set a {}; foreach {o v} $args {if {$o in {%s}} {lappend a $o $v}}\n"
" rename [%s $pathName {*}$a] ::tko::$pathName\n"
" tailcall [[self] create ::$pathName {*}$args] configure .\n"
"}\n"
"self",
ch,ch1,Tcl_GetString(objv[4]),ch1,ch);
Tcl_IncrRefCount(tmpPtr);
ret = Tcl_Eval(interp, Tcl_GetString(tmpPtr));
Tcl_DecrRefCount(namePtr);
Tcl_DecrRefCount(tmpPtr);
if (ret != TCL_OK) {
return TCL_ERROR;
}
/* Get class object */
tmpPtr = Tcl_GetObjResult(interp);
if ((object = Tcl_GetObjectFromObj(interp, tmpPtr)) == NULL
|| (clazz = Tcl_GetObjectAsClass(object)) == NULL) {
return TCL_ERROR;
}
/*
* Add methods
*/
Tcl_ClassSetConstructor(interp, clazz,
Tcl_NewMethod(interp, clazz, NULL, 1, &tkoWidgetMethods[1], NULL));
Tcl_ClassSetDestructor(interp, clazz,
Tcl_NewMethod(interp, clazz, NULL, 1, &tkoWidgetMethods[2], NULL));
Tcl_NewMethod(interp, clazz, tkoPtr->Obj_cget, 1, &tkoWidgetMethods[3], NULL);
Tcl_NewMethod(interp, clazz, tkoPtr->Obj_configure, 1, &tkoWidgetMethods[4], NULL);
Tcl_NewMethod(interp, clazz, tkoPtr->Obj__tko_configure, 0, &tkoWidgetMethods[5], NULL);
Tcl_NewMethod(interp, clazz, tkoPtr->Obj__tko, 0, &tkoWidgetMethods[6], NULL);
return TCL_OK;
case MY_EVENTOPTION: /* Call proc ::tko::_eventoption */
return Tcl_EvalObjEx(interp, tkoPtr->Obj_tko__eventoption, TCL_EVAL_GLOBAL);
case MY_OPTIONDEF: /* Add or replace option definitions and return new state */
if (objc != 3 && objc < 5) {
Tcl_WrongNumArgs(interp, 2, objv, "::classname ?-option definition? .. ?body?");
return TCL_ERROR;
}
/* Create fqn classname */
ch = Tcl_GetStringFromObj(objv[2], &length);
if (length < 2 || ch[0] != ':') {
namePtr = Tcl_ObjPrintf("::%s", Tcl_GetString(objv[2]));
}
else {
namePtr = objv[2];
}
Tcl_IncrRefCount(namePtr);
/* get current value or create new one */
dictPtr = Tcl_ObjGetVar2(interp, tkoPtr->Obj_tko__option, namePtr, TCL_GLOBAL_ONLY);
if (dictPtr == NULL) {
dictPtr = Tcl_NewObj();
}
else {
dictPtr = Tcl_DuplicateObj(dictPtr);
}
Tcl_IncrRefCount(dictPtr);
/* if no options then return current state */
if (objc == 3) {
Tcl_SetObjResult(interp, dictPtr);
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
return TCL_OK;
}
/* Add or replace options */
for (i = 3; i < objc-1; i = i + 2) {
/* check definition list */
if (Tcl_ListObjGetElements(interp, objv[i + 1], &argObjc, &argObjv) != TCL_OK) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no definition list: %s {%s}",
Tcl_GetString(objv[i]), Tcl_GetString(objv[i + 1])));
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
/* Check definition list */
switch (argObjc) {
case 2: /* synonym flags */
ret = WidgetOptionAdd(interp, NULL, objv[i], argObjv[0], NULL, NULL, argObjv[1], NULL, 0);
if (ret == TCL_OK) {
ret = Tcl_DictObjPut(interp, dictPtr, objv[i], objv[i + 1]);
}
break;
case 4: /* dbname dbclass default flags */
ret = WidgetOptionAdd(interp, NULL, objv[i], argObjv[0], argObjv[1], argObjv[2], argObjv[3], NULL, 0);
if (ret == TCL_OK) {
ret = Tcl_DictObjPut(interp, dictPtr, objv[i], objv[i + 1]);
}
break;
default:
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong definition: %s {%s}",
Tcl_GetString(objv[i]), Tcl_GetString(objv[i + 1])));
ret = TCL_ERROR;
}
if (ret != TCL_OK) {
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
}
/* Add body to last definition. */
if (objc % 2 == 0) {
myCmd[0] = tkoPtr->Obj_oo_define;
myCmd[1] = namePtr;
myCmd[2] = tkoPtr->Obj_method;
myCmd[3] = objv[objc - 3];
myCmd[4] = tkoPtr->Obj_empty;
myCmd[5] = objv[objc - 1];
ret = Tcl_EvalObjv(interp, 6, myCmd, TCL_EVAL_GLOBAL);
if (ret != TCL_OK) {
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
} tmpPtr = Tcl_ObjSetVar2(interp, tkoPtr->Obj_tko__option, namePtr, dictPtr, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
if (tmpPtr == NULL) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, tmpPtr);
return TCL_OK;
case MY_OPTIONDEL: /* Delete option definitions and return new state */
if (objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv, "::classname ?-option? ..");
return TCL_ERROR;
}
/* Create fqn classname */
ch = Tcl_GetStringFromObj(objv[2], &length);
if (length < 2 || ch[0] != ':') {
namePtr = Tcl_ObjPrintf("::%s", Tcl_GetString(objv[2]));
}
else {
namePtr = objv[2];
}
Tcl_IncrRefCount(namePtr);
/* if no options then remove all options */
if (objc == 3) {
tmpPtr = Tcl_ObjSetVar2(interp, tkoPtr->Obj_tko__option, namePtr,tkoPtr->Obj_empty,TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(namePtr);
if (tmpPtr == NULL) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, tmpPtr);
return TCL_OK;
}
/* remove given options from dictionary */
dictPtr = Tcl_ObjGetVar2(interp, tkoPtr->Obj_tko__option, namePtr, TCL_GLOBAL_ONLY);
if (dictPtr == NULL) {
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
dictPtr = Tcl_DuplicateObj(dictPtr);
Tcl_IncrRefCount(dictPtr);
/* remove with error check */
for (i = 3; i < objc; i++) {
if (Tcl_DictObjRemove(interp, dictPtr, objv[i]) != TCL_OK) {
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
}
tmpPtr = Tcl_ObjSetVar2(interp, tkoPtr->Obj_tko__option, namePtr,dictPtr,TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
if (tmpPtr == NULL) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, tmpPtr);
return TCL_OK;
case MY_OPTIONGET: /* Return all or selected option definitions */
if (objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv, "::classname ?-option? ..");
return TCL_ERROR;
}
/* Create fqn classname */
ch = Tcl_GetStringFromObj(objv[2], &length);
if (length < 2 || ch[0] != ':') {
namePtr = Tcl_ObjPrintf("::%s", Tcl_GetString(objv[2]));
}
else {
namePtr = objv[2];
}
Tcl_IncrRefCount(namePtr);
/* return all definitions */
dictPtr = Tcl_ObjGetVar2(interp, tkoPtr->Obj_tko__option, namePtr, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(namePtr);
if (dictPtr == NULL) {
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
if (objc == 3) {
Tcl_SetObjResult(interp, dictPtr);
return TCL_OK;
}
/* return only selected definitions */
listPtr = Tcl_NewListObj(0, NULL);
Tcl_IncrRefCount(listPtr);
/* get with error checks */
for (i = 3; i < objc; i++) {
if (Tcl_DictObjGet(interp, dictPtr, objv[i], &tmpPtr) != TCL_OK
|| tmpPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unknown option: %s",
Tcl_GetString(objv[i])));
Tcl_DecrRefCount(listPtr);
return TCL_ERROR;
}
Tcl_ListObjAppendElement(interp, listPtr, objv[i]);
Tcl_ListObjAppendElement(interp, listPtr, tmpPtr);
}
Tcl_SetObjResult(interp, listPtr);
Tcl_DecrRefCount(listPtr);
return TCL_OK;
case MY_OPTIONHIDE: /* Hide given options or return all hide'able options */
if (objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv, "::classname ?-option? ..");
return TCL_ERROR;
}
/* Create fqn classname */
ch = Tcl_GetStringFromObj(objv[2], &length);
if (length < 2 || ch[0] != ':') {
namePtr = Tcl_ObjPrintf("::%s", Tcl_GetString(objv[2]));
}
else {
namePtr = objv[2];
}
Tcl_IncrRefCount(namePtr);
dictPtr = Tcl_ObjGetVar2(interp, tkoPtr->Obj_tko__option, namePtr, TCL_GLOBAL_ONLY);
if (dictPtr == NULL) {
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
/* return list of hide'able options */
if (objc == 3) {
/* return list of visible options */
if (Tcl_DictObjFirst(interp, dictPtr, &search,
&key, &value, &done) != TCL_OK) {
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
listPtr = Tcl_NewListObj(0, NULL);
for (; !done; Tcl_DictObjNext(&search, &key, &value, &done)) {
Tcl_ListObjGetElements(interp, value, &argObjc, &argObjv);
switch (argObjc) {
case 1:
case 3:
Tcl_ListObjAppendElement(interp, listPtr, key);
break;
case 2:
if (WidgetFlagsHideGet(argObjv[1]) == 0) {
Tcl_ListObjAppendElement(interp, listPtr, key);
}
break;
case 4:
if (WidgetFlagsHideGet(argObjv[3]) == 0) {
Tcl_ListObjAppendElement(interp, listPtr, key);
}
break;
}
/* ignore internal error on wrong definition lists */
}
Tcl_DictObjDone(&search);
Tcl_SetObjResult(interp, listPtr);
Tcl_DecrRefCount(namePtr);
return TCL_OK;
}
/* hide given options */
dictPtr = Tcl_DuplicateObj(dictPtr);
Tcl_IncrRefCount(dictPtr);
for (i = 3; i < objc; i++) {
if (Tcl_DictObjGet(interp, dictPtr, objv[i], &listPtr) != TCL_OK
|| listPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unknown option: %s",
Tcl_GetString(objv[i])));
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
Tcl_ListObjGetElements(interp, listPtr, &argObjc, &argObjv);
listPtr = NULL;
switch (argObjc) {
case 1:
listPtr = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[0]);
Tcl_ListObjAppendElement(interp, listPtr, tkoPtr->Obj_flags_h);
break;
case 2:
listPtr = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[0]);
Tcl_ListObjAppendElement(interp, listPtr, WidgetFlagsHideSet(argObjv[1]));
break;
case 3:
listPtr = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[0]);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[1]);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[2]);
Tcl_ListObjAppendElement(interp, listPtr, tkoPtr->Obj_flags_h);
break;
case 4:
listPtr = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[0]);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[1]);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[2]);
Tcl_ListObjAppendElement(interp, listPtr, WidgetFlagsHideSet(argObjv[3]));
break;
default: /* ignore internal error */
continue;
}
if (Tcl_DictObjPut(interp, dictPtr, objv[i], listPtr) != TCL_OK) {
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
}
tmpPtr = Tcl_ObjSetVar2(interp, tkoPtr->Obj_tko__option, namePtr, dictPtr, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
if (tmpPtr == NULL) {
return TCL_ERROR;
}
return TCL_OK;
case MY_OPTIONSHOW: /* Show given options or return all hidden options */
if (objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv, "::classname ?-option? ..");
return TCL_ERROR;
}
/* Create fqn classname */
ch = Tcl_GetStringFromObj(objv[2], &length);
if (length < 2 || ch[0] != ':') {
namePtr = Tcl_ObjPrintf("::%s", Tcl_GetString(objv[2]));
}
else {
namePtr = objv[2];
}
Tcl_IncrRefCount(namePtr);
dictPtr = Tcl_ObjGetVar2(interp, tkoPtr->Obj_tko__option, namePtr, TCL_GLOBAL_ONLY);
if (dictPtr == NULL) {
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
/* return list of show'able options */
if (objc == 3) {
/* return list of visible options */
if (Tcl_DictObjFirst(interp, dictPtr, &search,
&key, &value, &done) != TCL_OK) {
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
listPtr = Tcl_NewListObj(0, NULL);
for (; !done; Tcl_DictObjNext(&search, &key, &value, &done)) {
Tcl_ListObjGetElements(interp, value, &argObjc, &argObjv);
if (argObjc == 2) {
if (WidgetFlagsHideGet(argObjv[1]) == 1) {
Tcl_ListObjAppendElement(interp, listPtr, key);
}
} else if (argObjc == 4) {
if (WidgetFlagsHideGet(argObjv[3]) == 1) {
Tcl_ListObjAppendElement(interp, listPtr, key);
}
}
}
Tcl_DictObjDone(&search);
Tcl_SetObjResult(interp, listPtr);
Tcl_DecrRefCount(namePtr);
return TCL_OK;
}
/* show given options */
dictPtr = Tcl_DuplicateObj(dictPtr);
Tcl_IncrRefCount(dictPtr);
for (i = 3; i < objc; i++) {
if (Tcl_DictObjGet(interp, dictPtr, objv[i], &listPtr) != TCL_OK
|| listPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unknown option: %s",
Tcl_GetString(objv[i])));
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
Tcl_ListObjGetElements(interp, listPtr, &argObjc, &argObjv);
switch (argObjc) {
case 1: /* already visible */
continue;
case 2:
listPtr = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[0]);
Tcl_ListObjAppendElement(interp, listPtr, WidgetFlagsHideUnset(argObjv[1]));
break;
case 3: /* already visible */
continue;
case 4:
listPtr = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[0]);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[1]);
Tcl_ListObjAppendElement(interp, listPtr, argObjv[2]);
Tcl_ListObjAppendElement(interp, listPtr, WidgetFlagsHideUnset(argObjv[3]));
continue;
default: /* ignore internal error */
continue;
}
if (Tcl_DictObjPut(interp, dictPtr, objv[i], listPtr) != TCL_OK) {
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
return TCL_ERROR;
}
}
tmpPtr = Tcl_ObjSetVar2(interp, tkoPtr->Obj_tko__option, namePtr, dictPtr, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(dictPtr);
Tcl_DecrRefCount(namePtr);
if (tmpPtr == NULL) {
return TCL_ERROR;
}
return TCL_OK;
}
return TCL_ERROR;
}
/*
* WidgetMethod_tko --
* Implementation of the "my _tko" method.
* Configuration of widget object options.
*
* Results:
* A standard Tcl result.
*
* Side effects:
*/
static int WidgetMethod_tko(
ClientData dummy,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[])
{
static const char *const myOptions[] = {
"optionadd", "optiondel",
"optionhide", "optionshow",NULL
};
enum options {
MY_OPTIONADD, MY_OPTIONDEL,
MY_OPTIONHIDE, MY_OPTIONSHOW
};
int index;
Tcl_Obj *listPtr;
int i;
Tko_Widget *widget;
int skip;
Tcl_HashEntry *entryPtr;
Tcl_HashSearch search;
WidgetOption *optionPtr;
Tcl_Obj *myCmd[6];
Tcl_Object object;
int argObjc;
Tcl_Obj **argObjv;
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
(void)dummy;
widget = (Tko_Widget *) Tko_WidgetClientData(context);
if (widget == NULL || widget->myCmd == NULL) {
return TCL_ERROR;
}
skip = Tcl_ObjectContextSkippedArgs(context);
if (objc-skip <= 0) {
Tcl_WrongNumArgs(interp, objc, objv, "option ?arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObjStruct(interp, objv[skip], myOptions,
sizeof(char *), "option", 0, &index) != TCL_OK) {
return TCL_ERROR;
}
switch ((enum options) index) {
case MY_OPTIONADD:
if (objc - skip != 3 && objc - skip != 4) {
Tcl_WrongNumArgs(interp, skip + 1, objv,
"-option definitionlist ?body?");
}
/* Check definition list */
if (Tcl_ListObjGetElements(interp, objv[skip + 2], &argObjc, &argObjv) != TCL_OK) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no definition list: %s {%s}",
Tcl_GetString(objv[skip+1]), Tcl_GetString(objv[skip+2])));
return TCL_ERROR;
}
/* Add body if given. */
if (objc - skip == 4) {
object = Tcl_ObjectContextObject(context);
if (object == NULL) return TCL_ERROR;
myCmd[0] = tkoPtr->Obj_oo_objdefine;
myCmd[1] = Tcl_GetObjectName(interp, object);
myCmd[2] = tkoPtr->Obj_method;
myCmd[3] = objv[skip + 1];
myCmd[4] = tkoPtr->Obj_empty;
myCmd[5] = objv[skip + 3];
if (Tcl_EvalObjv(interp, 6, myCmd, TCL_EVAL_GLOBAL) != TCL_OK) {
return TCL_ERROR;
}
}
switch (argObjc) {
case 2: /* synonym flags */
return (WidgetOptionAdd(interp, widget, objv[skip+1], argObjv[0], NULL, NULL, argObjv[1], NULL, 0));
case 4: /* dbname dbclass default flags */
return (WidgetOptionAdd(interp, widget, objv[skip+1], argObjv[0], argObjv[1], argObjv[2], argObjv[3], NULL, 0));
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong definition list: %s {%s}",
Tcl_GetString(objv[skip+1]), Tcl_GetString(objv[skip+2])));
return TCL_ERROR;
case MY_OPTIONDEL: /* delete object options */
for (i= skip+1; i<objc; i++) {
entryPtr =
Tcl_FindHashEntry(widget->optionsTable,
Tk_GetUid(Tcl_GetString(objv[i])));
if (entryPtr == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("unknown option \"%s\"", Tcl_GetString(objv[i])));
return TCL_ERROR;
}
/* delete with no additional check on synonym option */
Tcl_UnsetVar2(interp, Tcl_GetString(widget->optionsArray),
Tcl_GetString(objv[i]), TCL_GLOBAL_ONLY);
WidgetOptionDelEntry(entryPtr);
}
return TCL_OK;
case MY_OPTIONHIDE:
/* Without args return all not hidden options */
if ((objc - skip) == 1) {
listPtr = Tcl_NewListObj(0,NULL);
entryPtr = Tcl_FirstHashEntry(widget->optionsTable, &search);
while (entryPtr != NULL) {
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
entryPtr = Tcl_NextHashEntry(&search);
if ((optionPtr->flagbits&TKO_OPTION_HIDE)==0) {
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->option);
}
}
Tcl_SetObjResult(interp, listPtr);
return TCL_OK;
}
/* Hide given options */
skip++;
while (skip < objc) {
entryPtr = Tcl_FindHashEntry(widget->optionsTable,
Tk_GetUid(Tcl_GetString(objv[skip])));
if (entryPtr == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("unknown option \"%s\"", Tcl_GetString(objv[skip])));
return TCL_ERROR;
}
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
optionPtr->flagbits |= TKO_OPTION_HIDE;
skip++;
}
return TCL_OK;
case MY_OPTIONSHOW:
/* Without args return all hidden options */
if ((objc - skip) == 1) {
listPtr = Tcl_NewObj();
entryPtr = Tcl_FirstHashEntry(widget->optionsTable, &search);
while (entryPtr != NULL) {
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
entryPtr = Tcl_NextHashEntry(&search);
if (optionPtr->flagbits & TKO_OPTION_HIDE) {
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->option);
}
}
Tcl_SetObjResult(interp, listPtr);
return TCL_OK;
}
/* Show given options */
skip++;
while (skip < objc) {
entryPtr = Tcl_FindHashEntry(widget->optionsTable,
Tk_GetUid(Tcl_GetString(objv[skip])));
if (entryPtr == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("unknown option \"%s\"", Tcl_GetString(objv[skip])));
return TCL_ERROR;
}
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
optionPtr->flagbits &= ~TKO_OPTION_HIDE;
skip++;
}
return TCL_OK;
}
return TCL_OK;
}
/*
* Tko_Init --
* Initialize tko widgets.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Create available oo::class tko widgets.
*/
int
Tko_Init(
Tcl_Interp * interp /* Tcl interpreter. */)
{
/* Create common tko variables. */
/* tko::_eventoption according library/ttk.tcl proc ttk::ThemeChanged */
static const char initScript[] =
"namespace eval ::tko {}\n"
"array set ::tko::_option {}\n"
"set ::tko::_unknown [list self method unknown {pathName args} {\n"
" tailcall [[self] create ::$pathName {*}$args] configure .\n"
"}]\n"
"proc ::tko::_eventoption {} {\n"
" set l .\n"
" while {[llength $l]} {\n"
" set l1 [list]\n"
" foreach w $l {\n"
" event generate $w <<TkoEventOption>>\n"
" foreach c [winfo children $w] {\n"
" lappend l1 $c\n"
" }\n"
" }\n"
" set l $l1\n"
" }\n"
"}\n"
"proc ::tko::_initwrap {class widget ro ml} {\n"
" catch {destroy .__tko__}\n"
" set myConf [[$widget .__tko__] configure]\n"
" destroy .__tko__\n"
" foreach myCmd $ml {\n"
" if {$myCmd in {cget configure}} continue\n"
" uplevel 1 [list method $myCmd args \"\\$tko(..) $myCmd {*}\\$args\"]\n"
" }\n"
" foreach myList $myConf {\n"
" lassign $myList o n c d\n"
" switch [llength $myList] {\n"
" 2 {::tko optiondef $class $o [list $n {}]}\n"
" 5 {if {$o in $ro} {set f r} else {set f {}}\n"
" ::tko optiondef $class $o [list $n $c $d $f ] \"\\$tko(..) configure $o \\$tko($o) ; set tko($o) \\[\\$tko(..) cget $o\\]\"\n"
" }\n"
" }\n"
" }\n"
"}";
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
/* Needed oo extension */
if (Tcl_OOInitStubs(interp) == NULL) {
return TCL_ERROR;
}
/*
* Create tko namespace and data
*/
if (Tcl_Eval(interp, initScript) != TCL_OK) {
return TCL_ERROR;
}
/*
* Constants
*/
tkoPtr->Uid_class = Tk_GetUid("-class");
tkoPtr->Uid_empty = Tk_GetUid("");
Tcl_IncrRefCount((tkoPtr->Obj_empty = Tcl_NewStringObj("", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_tko__option =
Tcl_NewStringObj("::tko::_option", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_tko__eventoption =
Tcl_NewStringObj("::tko::_eventoption", -1)));
/* Internally visible */
Tcl_IncrRefCount((tkoPtr->Obj_next = Tcl_NewStringObj("next", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_uplevel = Tcl_NewStringObj("::uplevel", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_oo_define =
Tcl_NewStringObj("::oo::define", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_oo_objdefine =
Tcl_NewStringObj("::oo::objdefine", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_method = Tcl_NewStringObj("method", -1)));
Tcl_IncrRefCount((tkoPtr->Obj__tko_configure =
Tcl_NewStringObj("_tko_configure", -1)));
Tcl_IncrRefCount((tkoPtr->Obj__tko =
Tcl_NewStringObj("_tko", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_cget =
Tcl_NewStringObj("cget", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_configure =
Tcl_NewStringObj("configure", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_tko = Tcl_NewStringObj("::tko", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_tko_widget =
Tcl_NewStringObj("::tko::widget", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_lsort = Tcl_NewStringObj("::lsort", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_point = Tcl_NewStringObj(".", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_point2 = Tcl_NewStringObj("..", -1)));
Tcl_IncrRefCount((tkoPtr->Obj__screen = Tcl_NewStringObj("-screen", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_flags_r = Tcl_NewStringObj("r", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_flags_rh = Tcl_NewStringObj("rh", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_flags_h = Tcl_NewStringObj("h", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_rename = Tcl_NewStringObj("rename", -1)));
Tcl_IncrRefCount((tkoPtr->Obj_tko__self = Tcl_NewStringObj("::tko::_self", -1)));
/* commands */
Tcl_CreateObjCommand(interp, "::tko", Tko_TkoObjCmd, NULL, NULL);
if (Tko_FrameInit(interp) != TCL_OK) {
return TCL_ERROR;
}
/* TODO */
#ifdef USE_RBC
if (Tko_GraphInit(interp) != TCL_OK) {
return TCL_ERROR;
}
if (Tko_VectorInit(interp) != TCL_OK) {
return TCL_ERROR;
}
#endif
return TCL_OK;
}
/*
* Tko_WidgetClassDefine --
* Create a new tko widget class.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Create new class with methods and option defines.
*/
int
Tko_WidgetClassDefine(
Tcl_Interp * interp,
Tcl_Obj * classname,
const Tcl_MethodType * methods,
const Tko_WidgetOptionDefine * options)
{
Tcl_Class clazz;
Tcl_Object object;
Tcl_Obj *listPtr;
Tcl_Obj *optionPtr;
Tcl_Obj *tmpObj;
Tcl_Obj *dictPtr;
WidgetClientdata *clientdata;
int i;
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
if (classname == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("missing class name"));
return TCL_ERROR;
}
/*
* Create widget class.
*/
tmpObj = Tcl_ObjPrintf("::oo::class create %s {unexport destroy; variable tko; {*}$::tko::_unknown}", Tcl_GetString(classname));
Tcl_IncrRefCount(tmpObj);
if (Tcl_GlobalEval(interp, Tcl_GetString(tmpObj)) != TCL_OK) {
Tcl_DecrRefCount(tmpObj);
return TCL_ERROR;
}
Tcl_DecrRefCount(tmpObj);
/* Get class object */
if ((object = Tcl_GetObjectFromObj(interp, classname)) == NULL
|| (clazz = Tcl_GetObjectAsClass(object)) == NULL) {
return TCL_ERROR;
}
/*
* Add methods
*/
if(methods) {
/* constructor */
if(methods[0].name == NULL && methods[0].callProc) {
Tcl_ClassSetConstructor(interp, clazz,
Tcl_NewMethod(interp, clazz, NULL, 1, &methods[0], NULL));
}
/* destructor */
if(methods[1].name == NULL && methods[1].callProc) {
Tcl_ClassSetDestructor(interp, clazz,
Tcl_NewMethod(interp, clazz, NULL, 1, &methods[1], NULL));
}
/* our own methods */
Tcl_NewMethod(interp, clazz, tkoPtr->Obj_cget, 1, &tkoWidgetMethods[3], NULL);
Tcl_NewMethod(interp, clazz, tkoPtr->Obj_configure, 1, &tkoWidgetMethods[4], NULL);
Tcl_NewMethod(interp, clazz, tkoPtr->Obj__tko_configure, 0, &tkoWidgetMethods[5], NULL);
Tcl_NewMethod(interp, clazz, tkoPtr->Obj__tko, 0, &tkoWidgetMethods[6], NULL);
/* public */
for(i = 2; methods[i].name != NULL; i++) {
tmpObj = Tcl_NewStringObj(methods[i].name, -1);
Tcl_IncrRefCount(tmpObj);
Tcl_NewMethod(interp, clazz, tmpObj, 1, &methods[i], NULL);
Tcl_DecrRefCount(tmpObj);
}
i++;
/* private */
for(; methods[i].name != NULL; i++) {
tmpObj = Tcl_NewStringObj(methods[i].name, -1);
Tcl_IncrRefCount(tmpObj);
Tcl_NewMethod(interp, clazz, tmpObj, 0, &methods[i], NULL);
Tcl_DecrRefCount(tmpObj);
}
}
/*
*Add options
*/
if(options) {
/* get dict variable */
dictPtr = Tcl_ObjGetVar2(interp, tkoPtr->Obj_tko__option, classname,
TCL_GLOBAL_ONLY);
if (dictPtr == NULL) {
dictPtr = Tcl_NewDictObj();
}
else {
dictPtr = Tcl_DuplicateObj(dictPtr);
}
Tcl_IncrRefCount(dictPtr);
/* Loop over all option definitions */
for(i = 0;; i++) {
/* test on end of options */
if (options[i].option == NULL) {
break;
}
/* test option name starting with "-" */
if (options[i].option[0] != '-') {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong option name: %s",
options[i].option));
Tcl_DecrRefCount(dictPtr);
return TCL_ERROR;
}
/* we need at least an synonym name here */
if(options[i].dbname == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("wrong option definition: %d", i));
Tcl_DecrRefCount(dictPtr);
return TCL_ERROR;
}
/* no dbclass means synonym option definition */
if (options[i].dbclass == NULL || options[i].dbclass[0] == '\0') {
/* test synonym option starting with "-" */
if (options[i].dbname[0] != '-') {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong synonym name: %s",
options[i].dbname));
Tcl_DecrRefCount(dictPtr);
return TCL_ERROR;
}
}
/* we build all options with {dbname dbclass defvalue flag} */
optionPtr = Tcl_NewStringObj(options[i].option, -1);
Tcl_IncrRefCount(optionPtr);
listPtr = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(interp, listPtr,
Tcl_NewStringObj(options[i].dbname, -1));
/* only if not synonym option */
if (options[i].dbclass != NULL) {
Tcl_ListObjAppendElement(interp, listPtr,
Tcl_NewStringObj(options[i].dbclass, -1));
if (options[i].defvalue == NULL) {
Tcl_ListObjAppendElement(interp, listPtr, tkoPtr->Obj_empty);
}
else {
Tcl_ListObjAppendElement(interp, listPtr,
Tcl_NewStringObj(options[i].defvalue, -1));
}
}
/* always add flags */
if (options[i].flags & TKO_OPTION_READONLY) {
if (options[i].flags & TKO_OPTION_HIDE) {
Tcl_ListObjAppendElement(interp, listPtr, tkoPtr->Obj_flags_rh);
}
Tcl_ListObjAppendElement(interp, listPtr, tkoPtr->Obj_flags_r);
}
else if (options[i].flags & TKO_OPTION_HIDE) {
Tcl_ListObjAppendElement(interp, listPtr, tkoPtr->Obj_flags_h);
}
else {
Tcl_ListObjAppendElement(interp, listPtr, tkoPtr->Obj_empty);
}
if (Tcl_DictObjPut(interp, dictPtr, optionPtr, listPtr) != TCL_OK) {
Tcl_DecrRefCount(optionPtr);
Tcl_DecrRefCount(dictPtr);
return TCL_ERROR;
}
/*
* Now we create the necessary -option method if provided.
* If given we create the -option method with the given method.
* Or we use the internal implementation of a given type.
* If none of the above are provided it is up to the caller
* to create the necessary -option method.
*/
if (options[i].method != NULL || options[i].type >= 0) {
clientdata = (WidgetClientdata *)ckalloc(sizeof(WidgetClientdata));
assert(clientdata);
clientdata->method.version = TCL_OO_METHOD_VERSION_CURRENT;
clientdata->method.name = options[i].option;
if (options[i].method != NULL) {
clientdata->method.callProc = options[i].method;
}
else {
clientdata->method.callProc = WidgetMethod_;
}
clientdata->method.deleteProc = WidgetClientdataDelete;
clientdata->method.cloneProc = WidgetClientdataClone;
clientdata->option = optionPtr;/* we do not decrement here */
clientdata->offset = options[i].offset;
clientdata->type = options[i].type;
clientdata->flags = options[i].flags;
Tcl_NewMethod(interp, clazz, optionPtr, 0, &clientdata->method,
(ClientData) clientdata);
}
else {
Tcl_DecrRefCount(optionPtr);
}
}
if (Tcl_ObjSetVar2(interp, tkoPtr->Obj_tko__option, classname, dictPtr,
TCL_GLOBAL_ONLY) == 0) {
Tcl_DecrRefCount(dictPtr);
return TCL_ERROR;
}
Tcl_DecrRefCount(dictPtr);
}
return TCL_OK;
}
/*
* WidgetDestructor --
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Delete widget ressources.
*/
static int
WidgetDestructor(
ClientData dummy,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[])
{
Tko_Widget *widget;
(void)dummy;
(void)interp;
(void)objc;
(void)objv;
if ((widget = (Tko_Widget *)Tko_WidgetClientData(context)) != NULL) {
Tcl_Preserve(widget);
Tko_WidgetDestroy(context);
Tcl_Release(widget);
}
return TCL_OK;
}
/*
* WidgetClassConstructor --
* Create a new tko class object with common methods.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Create new object with methods and option defines.
*/
static int
WidgetClassConstructor(
ClientData dummy,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[])
{
Tcl_Object object;
Tko_Widget *widget;
Tcl_Obj *myArglist;
int skip;
(void)dummy;
/* Get current object. Should not fail? */
if ((object = Tcl_ObjectContextObject(context)) == NULL) {
return TCL_ERROR;
}
/* Create and initialize internal widget structure */
widget = (Tko_Widget *)ckalloc(sizeof(Tko_Widget));
assert(widget);
memset(widget, 0, sizeof(Tko_Widget));
skip = Tcl_ObjectContextSkippedArgs(context);
if (objc - skip > 0) {
myArglist = Tcl_NewListObj(objc - skip, &objv[skip]);
}
else {
myArglist = Tcl_NewListObj(0,NULL);
}
Tcl_IncrRefCount(myArglist);
if (Tko_WidgetCreate(widget, interp, object, TKO_CREATE_CLASS,
myArglist) != TCL_OK) {
Tcl_DecrRefCount(myArglist);
return TCL_ERROR;
}
Tcl_DecrRefCount(myArglist);
return TCL_OK;
}
/*
* WidgetWrapConstructor --
* Create a new tko widget object with wrapping of the given widget command.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Create new object with methods and option defines.
*/
static int
WidgetWrapConstructor(
ClientData dummy,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[])
{
Tcl_Object object;
Tko_Widget *widget;
Tcl_Obj *myArglist;
int skip;
const char *ch;
int length;
Tk_Window tkWin;
Tk_Window tkWinTmp; /* tmp. created window to get Tk_Window from embedded window */
Tcl_Obj *tmpPtr; /* tmp. string for evaluating code */
(void)dummy;
/* Get current object. Should not fail? */
if ((object = Tcl_ObjectContextObject(context)) == NULL) {
return TCL_ERROR;
}
/* Check widget name on "::.*" */
ch = NULL;
if ((tmpPtr = Tcl_GetObjectName(interp, object)) == NULL
|| (ch = TclGetStringFromObj(tmpPtr, &length)) == NULL
|| length < 4 || ch[0] != ':' || ch[1] != ':' || ch[2] != '.') {
if (ch == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no pathName"));
}
else {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong pathName: %s", ch));
}
return TCL_ERROR;
}
/*
* Get real widget Tk_Window.
*/
tmpPtr = Tcl_NewStringObj(&ch[2], length - 2);
Tcl_AppendToObj(tmpPtr, ".1", 2);
Tcl_IncrRefCount(tmpPtr);
tkWinTmp = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), Tcl_GetString(tmpPtr), NULL);
Tcl_DecrRefCount(tmpPtr);
if (tkWinTmp == NULL) {
return TCL_ERROR;
}
tkWin = Tk_NameToWindow(interp, &ch[2], tkWinTmp);
Tk_DestroyWindow(tkWinTmp);
if (tkWin == NULL) {
return TCL_ERROR;
}
/* Create and initialize internal widget structure */
widget = (Tko_Widget *)ckalloc(sizeof(Tko_Widget));
assert(widget);
memset(widget, 0, sizeof(Tko_Widget));
widget->tkWin = tkWin;
skip = Tcl_ObjectContextSkippedArgs(context);
if (objc - skip > 0) {
myArglist = Tcl_NewListObj(objc - skip, &objv[skip]);
}
else {
myArglist = Tcl_NewListObj(0, NULL);
}
Tcl_IncrRefCount(myArglist);
if (Tko_WidgetCreate(widget, interp, object, TKO_CREATE_WRAP,
myArglist) != TCL_OK) {
Tcl_DecrRefCount(myArglist);
return TCL_ERROR;
}
Tcl_DecrRefCount(myArglist);
return TCL_OK;
}
/*
* Tko_WidgetCreate --
* Create new tko object.
* A check on the correct name of the object should be done in the calling function.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Can create new widget.
*/
int
Tko_WidgetCreate(
ClientData clientdata, /* pointer to Tko_Widget structure */
Tcl_Interp * interp,
Tcl_Object object,
Tko_WidgetCreateMode createmode, /* */
Tcl_Obj *arglist) /* -value option .. list, used options will be removed */
{
Tko_Widget *widget;
char *nsPtr;
int argSize;
Tcl_Obj *classObj;
Tcl_Obj *optionList;
Tcl_Obj *tmpObj;
Tcl_Obj **optionObjv;
int optionObjc;
Tcl_Obj **argObjv;
int argObjc;
int index = 0; /* Index in option list */
int ret;
Tcl_Obj *value;
Tcl_Obj *screen;
char *ch;
int length;
Tcl_Obj *tmpPtr;
int initmode=1;/* 1=own widget 2=wrapped widget */
Tk_Window wrapWin = NULL;/* needed in error case */
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
/* This would be an internal programming error */
if (clientdata == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no widget data"));
return TCL_ERROR;
}
/* Check name starting with "::" */
if ((tmpPtr = Tcl_GetObjectName(interp, object)) == NULL
|| (ch = TclGetStringFromObj(tmpPtr, &length)) == NULL
|| length < 3 || ch[0] != ':' || ch[1] != ':') {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no object"));
return TCL_ERROR;
}
/* Add widget to metadata so it can be released */
Tcl_ObjectSetMetadata(object, &tkoWidgetMeta, clientdata);
/*
* Initialize internal widget strucure.
*/
widget = (Tko_Widget *)clientdata;
widget->interp = interp;
widget->object = object;
widget->optionsTable = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(widget->optionsTable, TCL_ONE_WORD_KEYS);
widget->widgetCmd = Tcl_GetObjectCommand(object);
/* Create option array variable */
nsPtr = Tcl_GetObjectNamespace(object)->fullName;
widget->optionsArray = Tcl_ObjPrintf("%s::tko", nsPtr);
Tcl_IncrRefCount(widget->optionsArray);
/* Create my command */
widget->myCmd = Tcl_ObjPrintf("%s::my", nsPtr);
Tcl_IncrRefCount(widget->myCmd);
if (createmode == TKO_CREATE_WRAP) {
wrapWin = widget->tkWin;
widget->tkWin = NULL;
}
/*
* Get options from outermost class.
*/
classObj = Widget_GetClassName(interp, object);
if (classObj == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no class name"));
goto error;
}
optionList = Tcl_ObjGetVar2(interp, tkoPtr->Obj_tko__option, classObj, TCL_GLOBAL_ONLY);
if (optionList == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no option definitions"));
goto error;
}
if (Tcl_ListObjGetElements(interp, optionList, &optionObjc, &optionObjv) != TCL_OK
|| optionObjc % 2 != 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong option definitions"));
goto error;
}
/* Convert argument list in dictionary */
if (Tcl_DictObjSize(interp, arglist, &argSize) != TCL_OK) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not get arglist"));
goto error;
}
/*
* Do some initialization depending on the given createmode.
*/
switch (createmode) {
case TKO_CREATE_CLASS:
widget->tkWin = NULL;
break;
case TKO_CREATE_TOPLEVEL:
/* Check name starting with "::." */
if (ch[2] != '.') {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong pathName: %s", ch));
goto error;
}
if (optionObjc < 2) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("missing option definitions"));
goto error;
}
/* The "-screen" option definition should be the first option in toplevels. */
screen = NULL;
/* -screen option should be first */
if (strncmp("-screen", Tcl_GetString(optionObjv[0]), 8) != 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("missing -screen option"));
goto error;
}
/* we only check argument number and assume readonly flag */
if (Tcl_ListObjGetElements(interp, optionObjv[1], &argObjc, &argObjv) != TCL_OK
|| argObjc != 4) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong -screen option"));
goto error;
}
/* Try to get value from command line or use default one. */
Tcl_DictObjGet(interp, arglist, tkoPtr->Obj__screen, &screen);
if (screen != NULL) {
Tcl_DictObjRemove(interp, arglist, tkoPtr->Obj__screen);
argSize--;
}
else {
screen = argObjv[2];
}
Tcl_IncrRefCount(screen);
widget->tkWin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), &ch[2],
Tcl_GetString(screen));
if (widget->tkWin == NULL) {
goto error;
}
Tk_MakeWindowExist(widget->tkWin);
if ((widget->display = Tk_Display(widget->tkWin))==NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not get display"));
goto error;
}
/* When creating toplevels then check on "-screen" as first option. */
ret = WidgetOptionAdd(interp, widget, optionObjv[0], argObjv[0],
argObjv[1], argObjv[2], argObjv[3], screen, initmode);
Tcl_DecrRefCount(screen);
if (ret != TCL_OK) {
goto error;
}
index = 2;
break;
case TKO_CREATE_WIDGET:
/* Check name starting with "::." */
if (ch[2] != '.') {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong pathName: %s", ch));
goto error;
}
widget->tkWin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), &ch[2],
NULL);
if (widget->tkWin == NULL) {
goto error;
}
Tk_MakeWindowExist(widget->tkWin);
if ((widget->display = Tk_Display(widget->tkWin))==NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not get display"));
goto error;
}
if (optionObjc < 1) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("empty option definitions"));
goto error;
}
break;
case TKO_CREATE_WRAP:
if (wrapWin == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrap widget not found"));
goto error;
}
/* Check name starting with "::." */
if (ch[2] != '.') {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong pathName: %s", ch));
goto error;
}
/* Set tko(..) to name of hidden widget */
tmpObj = Tcl_ObjPrintf("::tko::%s", &ch[2]);
Tcl_IncrRefCount(tmpObj);
if (Tcl_ObjSetVar2(interp, widget->optionsArray, tkoPtr->Obj_point2,
tmpObj, TCL_GLOBAL_ONLY) == NULL) {
Tcl_DecrRefCount(tmpObj);
goto error;
}
Tcl_DecrRefCount(tmpObj);
if ((widget->display = Tk_Display(wrapWin))==NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not get display"));
goto error;
}
widget->tkWin = wrapWin;
wrapWin = NULL;
initmode = 2;
break;
default:
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong internal create mode"));
goto error;
}
/* Set tko(.) to name of widget or class */
if (Tcl_ObjSetVar2(interp, widget->optionsArray, tkoPtr->Obj_point,
Tcl_NewStringObj(&ch[2], length - 2), TCL_GLOBAL_ONLY) == NULL) {
goto error;
}
/*
* When creating widgets then "-class" option should be first option now.
* It's value is needed to get option informations from option database.
*/
if (createmode == TKO_CREATE_TOPLEVEL || createmode == TKO_CREATE_WIDGET) {
ch = Tcl_GetStringFromObj(optionObjv[index], &length);
if (strncmp(ch, "-class", length) != 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("missing -class option"));
goto error;
}
}
/*
* Add options.
*/
for(; index < optionObjc; index=index+2) {
if (Tcl_ListObjGetElements(interp, optionObjv[index+1], &argObjc, &argObjv) !=TCL_OK
|| argObjc < 1 || argObjc > 4) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong option def: %s {%s}",
Tcl_GetString(optionObjv[index]),Tcl_GetString(optionObjv[index+1])));
goto error;
}
Tcl_DictObjGet(interp, arglist, optionObjv[index], &value);
if(value) {
Tcl_IncrRefCount(value);
Tcl_DictObjRemove(interp, arglist, optionObjv[index]);
argSize--;
}
switch (argObjc) {
case 2: /* synonym flags */
ret = WidgetOptionAdd(interp, widget, optionObjv[index], argObjv[0],
NULL, NULL, argObjv[1], value, initmode);
break;
case 4: /* dbname dbclass default flags */
ret = WidgetOptionAdd(interp, widget, optionObjv[index], argObjv[0],
argObjv[1], argObjv[2], argObjv[3], value, initmode);
break;
}
if (value) {
Tcl_DecrRefCount(value);
}
if (ret != TCL_OK) goto error;
}
if(argSize) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unknown options: %s",
Tcl_GetString(arglist)));
goto error;
}
Tcl_TraceVar2(interp, Tcl_GetString(widget->optionsArray), NULL,
TCL_TRACE_WRITES | TCL_TRACE_RESULT_OBJECT, WidgetOptionTrace, widget);
if (widget->tkWin) {
Tk_CreateEventHandler(widget->tkWin, StructureNotifyMask | VirtualEventMask,
WidgetEventProc, (ClientData)widget);
}
return TCL_OK;
error:
if (wrapWin) {
tmpObj = Tcl_ObjPrintf("rename ::tko::%s {}", &ch[2]);
Tcl_IncrRefCount(tmpObj);
Tcl_EvalObjEx(interp, tmpObj, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(tmpObj);
}
Tcl_DeleteCommandFromToken(interp, widget->widgetCmd);
return TCL_ERROR;
}
/*
* Tko_WidgetDestroy --
* Delete widget window and command.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Delete widget ressources and remove widget window.
*/
void
Tko_WidgetDestroy(
Tcl_ObjectContext context)
{
Tko_Widget *widget;
if ((widget = (Tko_Widget *)Tko_WidgetClientData(context)) == NULL) {
return;
}
Tcl_Preserve(widget);
if (widget->tkWin) {
WidgetDeleteTkwin(widget);
}
if (widget->myCmd) {
Tcl_DecrRefCount(widget->myCmd);
widget->myCmd = NULL;
}
Tcl_ObjectSetMetadata(widget->object, &tkoWidgetMeta, NULL);
Tcl_Release(widget);
return;
}
/*
* Tko_WidgetClientData --
* Return pointer to widget client data.
*
* Results:
* None.
*
* Side effects:
* None.
*/
ClientData Tko_WidgetClientData(
Tcl_ObjectContext context)
{
Tcl_Object object;
if ((object = Tcl_ObjectContextObject(context)) == NULL) {
return NULL;
}
return Tcl_ObjectGetMetadata(object, &tkoWidgetMeta);
}
/*
* WidgetMetaDestroy --
* Free ressources.
*
* Results:
* None.
*
* Side effects:
* Delete or give back all used internal ressources
*/
static void
WidgetMetaDestroy(
Tko_Widget * widget)
{
Tcl_HashSearch search;
Tcl_HashEntry *entryPtr;
entryPtr = Tcl_FirstHashEntry(widget->optionsTable, &search);
while (entryPtr != NULL) {
WidgetOptionDelEntry(entryPtr);
entryPtr = Tcl_NextHashEntry(&search);
}
if (widget->optionsTable) {
Tcl_DeleteHashTable(widget->optionsTable);
ckfree(widget->optionsTable);
}
if (widget->optionsArray != NULL) {
Tcl_DecrRefCount((widget->optionsArray));
widget->optionsArray = NULL;
}
ckfree(widget);
}
/*
* WidgetDeleteTkwin --
* Resets internal Tk_Window in widget structure.
*
* Results:
* None.
*
* Side effects:
* Delete event handler of widget.
* When the widget is wrappen then delete wrap widget command.
*/
static void WidgetDeleteTkwin(
Tko_Widget *widget)
{
Tcl_Obj *tmpObj;
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
Tk_DeleteEventHandler(widget->tkWin, StructureNotifyMask | VirtualEventMask,
WidgetEventProc, widget);
tmpObj = Tcl_ObjGetVar2(widget->interp, widget->optionsArray, tkoPtr->Obj_point2, TCL_GLOBAL_ONLY);
if (tmpObj) {
tmpObj = Tcl_ObjPrintf("rename %s {}", Tcl_GetString(tmpObj));
Tcl_IncrRefCount(tmpObj);
Tcl_EvalObjEx(widget->interp, tmpObj,TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(tmpObj);
}
else {
Tk_DestroyWindow(widget->tkWin);
}
widget->tkWin = NULL;
}
/*
* WidgetEventProc --
* This function is invoked by the Tk dispatcher for various events on
* canvases.
*
* Results:
* None.
*
* Side effects:
* When the window gets deleted, internal structures get cleaned up.
*/
static void
WidgetEventProc(
ClientData clientData, /* Information about window. */
XEvent * eventPtr)
{ /* Information about event. */
Tko_Widget *widget = (Tko_Widget *)clientData;
switch (eventPtr->type) {
case DestroyNotify:
if (widget->tkWin) {
WidgetDeleteTkwin(widget);
Tcl_DeleteCommandFromToken(widget->interp, widget->widgetCmd);
}
if (widget->myCmd) {
Tcl_DecrRefCount(widget->myCmd);
widget->myCmd = NULL;
}
break;
case VirtualEvent:
if (widget->tkWin) {
if (!strcmp("TkoEventOption", ((XVirtualEvent *)(eventPtr))->name)) {
WidgetEventChanged(widget);
}
}
}
}
/*
* WidgetEventChanged --
* Reset all option with no TKO_OPTION_USER bit from option database.
* canvases.
*
* Results:
* None.
*
* Side effects:
* Apply changed option database values.
*/
static void
WidgetEventChanged(
Tko_Widget *widget)
{
Tcl_HashSearch search;
Tcl_HashEntry *entryPtr;
WidgetOption *optionPtr;
Tk_Uid valueUid;
Tk_Uid dbnameUid;
Tk_Uid dbclassUid;
int changed;
Tcl_Obj *defvalue;
Tcl_Obj *myObjv[2];
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
if (widget->myCmd == NULL) return;
Tcl_Preserve(widget);
entryPtr = Tcl_FirstHashEntry(widget->optionsTable, &search);
changed = 0;
while (entryPtr != NULL) {
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
entryPtr = Tcl_NextHashEntry(&search);
if (optionPtr->dbclass == NULL) continue;/* synonym option */
if (optionPtr->dbname == tkoPtr->Obj_empty && optionPtr->dbclass == tkoPtr->Obj_empty) continue;
if (optionPtr->flagbits & TKO_OPTION_READONLY) continue;/* readonly option */
if (optionPtr->flagbits & TKO_OPTION__USER) continue;/* user changed option */
/*
* Get value from option database or
* check for a system-specific default value.
*/
dbnameUid = Tk_GetUid(Tcl_GetString(optionPtr->dbname));
dbclassUid = Tk_GetUid(Tcl_GetString(optionPtr->dbclass));
if ((valueUid = Tk_GetOption(widget->tkWin, dbnameUid, dbclassUid)) != NULL) {
defvalue = Tcl_NewStringObj(valueUid, -1);
}
else {
defvalue = Tk_GetSystemDefault(widget->tkWin, dbnameUid, dbclassUid);
if (defvalue == NULL) continue;
}
Tcl_IncrRefCount(defvalue);
/* No need to set same value again */
if (strcmp(Tcl_GetString(defvalue), Tcl_GetString(optionPtr->value)) == 0) {
Tcl_DecrRefCount(defvalue);
continue;
}
/* Set new value */
if (WidgetOptionSet(widget->interp, widget, optionPtr->option, defvalue) != TCL_OK) {
Tcl_DecrRefCount(defvalue);
optionPtr->flagbits &= ~TKO_OPTION__USER;/* reset option */
continue; /* no additional error handling here */
}
Tcl_DecrRefCount(defvalue);
changed++;
}
if (changed) {
myObjv[0] = widget->myCmd;
myObjv[1] = tkoPtr->Obj__tko_configure;
if (Tcl_EvalObjv(widget->interp, 2, myObjv, TCL_EVAL_GLOBAL) != TCL_OK) {
/* ignore errors */
}
}
Tcl_Release(widget);
}
/*
* WidgetMethod_cget --
* Tcl syntax: "widget cget -option".
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Return option value in interpreter result.
*/
static int
WidgetMethod_cget(
ClientData dummy,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[])
{
Tko_Widget *widget; /* widget. */
int skip;
(void)dummy;
if ((widget = (Tko_Widget *)Tko_WidgetClientData(context)) == NULL
|| widget->myCmd == NULL) {
return TCL_ERROR;
}
skip = Tcl_ObjectContextSkippedArgs(context);
if(objc - skip != 1) {
Tcl_WrongNumArgs(interp, skip, objv, "option");
return TCL_ERROR;
}
return WidgetOptionGet(interp, widget, objv[skip]);
}
/*
* WidgetMethod_configure --
* Tcl syntax:
* configure
* configure "-option"
* configure "-option value .."
* configure "add option dbname dbclass ?default?"
* configure "del option"
* configure "after"
* Changing of option values:
* 1. set tk(-option)
* 2. WidgetTraceOption()
* 3. "my -option $v .."
*
* Results:
* A standard Tcl result. Return result value in interpreter result.
*
* Side effects:
* Can add, delete or change options.
*/
static int
WidgetMethod_configure(
ClientData dummy,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[])
{
Tko_Widget *widget; /* widget. */
int skip;
Tcl_Obj *myObjv[2];
Tcl_HashSearch search;
Tcl_HashEntry *entryPtr;
WidgetOption *optionPtr;
Tcl_Obj *retPtr;
Tcl_Obj *listPtr;
const char *ch;
int length;
int i;
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
(void)dummy;
if ((widget = (Tko_Widget *)Tko_WidgetClientData(context)) == NULL
|| widget->myCmd == NULL) {
return TCL_ERROR;
}
skip = Tcl_ObjectContextSkippedArgs(context);
/* configure */
if(objc - skip == 0) {
retPtr = Tcl_NewObj();
entryPtr = Tcl_FirstHashEntry(widget->optionsTable, &search);
while(entryPtr != NULL) {
optionPtr = (WidgetOption *) Tcl_GetHashValue(entryPtr);
entryPtr = Tcl_NextHashEntry(&search);
/* hidden option, not visible in configure method */
if (optionPtr->flagbits&TKO_OPTION_HIDE) continue;
listPtr = Tcl_NewObj();
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->option);
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->dbname);
if (optionPtr->dbclass != NULL) {
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->dbclass);
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->defvalue);
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->value);
}
Tcl_ListObjAppendElement(interp, retPtr, listPtr);
}
/* Return sorted list */
myObjv[0] = tkoPtr->Obj_lsort;
myObjv[1] = retPtr;
return (Tcl_EvalObjv(interp, 2, myObjv, TCL_EVAL_GLOBAL));
}
/* configure "-option ?value? .." */
if(objc - skip == 1) { /* configure -option */
ch = Tcl_GetStringFromObj(objv[skip],&length);
/* configure . */
if(ch[0] == '.' && length == 1) {
// collect all not readonly options and configure
Tcl_Preserve(widget);
myObjv[0] = widget->myCmd;
entryPtr = Tcl_FirstHashEntry(widget->optionsTable, &search);
while (entryPtr != NULL) {
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
entryPtr = Tcl_NextHashEntry(&search);
if (optionPtr->dbclass == NULL) { /* synonym option */
if (optionPtr->value) {
Tcl_ObjSetVar2(interp, widget->optionsArray,
optionPtr->dbname, optionPtr->value, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(optionPtr->value);
optionPtr->value = NULL;
}
}
else { /* normal option */
if ((optionPtr->flagbits & TKO_OPTION_READONLY) == 0) {
myObjv[1] = optionPtr->option;
if (Tcl_EvalObjv(interp, 2, myObjv,
TCL_EVAL_GLOBAL) != TCL_OK) {
retPtr = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(retPtr);
Tcl_Release(widget);
Tcl_DeleteCommandFromToken(interp, widget->widgetCmd);
Tcl_SetObjResult(interp, retPtr);
Tcl_DecrRefCount(retPtr);
return TCL_ERROR;
}
}
}
}
myObjv[1] = tkoPtr->Obj__tko_configure;
if (Tcl_EvalObjv(interp, 2, myObjv, TCL_EVAL_GLOBAL) != TCL_OK) {
retPtr = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(retPtr);
Tcl_Release(widget);
Tcl_DeleteCommandFromToken(interp, widget->widgetCmd);
Tcl_SetObjResult(interp, retPtr);
Tcl_DecrRefCount(retPtr);
return TCL_ERROR;
}
Tcl_Release(widget);
Tcl_SetObjResult(interp, Tcl_ObjGetVar2(interp, widget->optionsArray, tkoPtr->Obj_point, TCL_GLOBAL_ONLY));
return TCL_OK;
}
entryPtr =
Tcl_FindHashEntry(widget->optionsTable,
Tk_GetUid(Tcl_GetString(objv[skip])));
if(entryPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unknown option \"%s\"",
Tcl_GetString(objv[skip])));
return TCL_ERROR;
}
optionPtr = (WidgetOption *) Tcl_GetHashValue(entryPtr);
/* hidden option, not visible in configure method */
if (optionPtr->flagbits&TKO_OPTION_HIDE) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("hidden option \"%s\"",
Tcl_GetString(objv[skip])));
return TCL_ERROR;
}
if (optionPtr->dbclass == NULL) {
entryPtr =
Tcl_FindHashEntry(widget->optionsTable,
Tk_GetUid(Tcl_GetString(optionPtr->dbname)));
if(entryPtr == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("unknown option \"%s\"",
Tcl_GetString(objv[skip])));
return TCL_ERROR;
}
optionPtr = (WidgetOption *) Tcl_GetHashValue(entryPtr);
if(optionPtr->dbclass == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("unknown option \"%s\"",
Tcl_GetString(objv[skip])));
return TCL_ERROR;
}
}
listPtr = Tcl_NewObj();
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->option);
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->dbname);
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->dbclass);
if (optionPtr->defvalue) {
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->defvalue);
}
else {
Tcl_ListObjAppendElement(interp, listPtr, tkoPtr->Obj_empty);
}
Tcl_ListObjAppendElement(interp, listPtr, optionPtr->value);
Tcl_SetObjResult(interp, listPtr);
return TCL_OK;
}
/* configure "-option ?value? .." */
if((objc - skip) % 2 == 0) {
Tcl_Preserve(widget);
for (i = skip; i < objc; i = i + 2) {
if (WidgetOptionSet(interp, widget, objv[i], objv[i + 1]) != TCL_OK) {
Tcl_Release(widget);
return TCL_ERROR;
}
}
myObjv[0] = widget->myCmd;
myObjv[1] = tkoPtr->Obj__tko_configure;
if (Tcl_EvalObjv(interp, 2, myObjv, TCL_EVAL_GLOBAL) != TCL_OK) {
Tcl_Release(widget);
return TCL_ERROR;
}
Tcl_Release(widget);
return TCL_OK;
}
Tcl_WrongNumArgs(interp, skip, objv, "?-option value ..?");
return TCL_ERROR;
}
/*
* WidgetOptionAdd --
* Add a new option to a created widget.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Add and initialize the new option.
*/
static int
WidgetOptionAdd(
Tcl_Interp * interp, /* used interpreter */
Tko_Widget * widget, /* currrent widget or NULL if only checks should be done */
Tcl_Obj * option, /* name of option, always given*/
Tcl_Obj * dbname, /* dbname or synonym, always given */
Tcl_Obj * dbclass, /* dbclass or NULL if synonym option */
Tcl_Obj * defvalue, /* default value of option */
Tcl_Obj * flags, /* value or NULL if synonym option */
Tcl_Obj * value, /* initialization value */
int initmode) /* 0 when adding to existing object, 1 when constructor, 2 when wrapped widget */
{
Tcl_HashEntry *entryPtr;
WidgetOption *optionPtr;
Tk_Uid valueUid;
int isNew;
Tk_Uid optionUid;
Tk_Uid dbnameUid;
Tk_Uid dbclassUid;
int intFlags;
int readonly;
Tcl_Obj *myObjv[2];
const char *ch;
const char *opt;
int traceadd = 0; /* if not 0 then readd trace on array variable */
int searchdb = 0; /* search optiondb for values */
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
if((opt=Tcl_GetString(option))[0] != '-') {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("wrong option: %s", opt));
return TCL_ERROR;
}
/* synonym option check */
if(dbclass == NULL) {
if((ch=Tcl_GetString(dbname))[0] != '-' || ch[1]=='\0') {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("wrong synonym: %s %s", opt, ch));
return TCL_ERROR;
}
}
/* int flag */
intFlags = 0;
if (flags && WidgetFlagsObj(flags,&intFlags) != TCL_OK) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("wrong flags: %s %s",opt,Tcl_GetString(flags)));
return TCL_ERROR;
}
if (intFlags & TKO_OPTION_READONLY) {
intFlags &= ~TKO_OPTION_READONLY;
readonly = TKO_OPTION_READONLY;
}
else {
readonly = 0;
}
/* return if no widget given, all class checks are done */
if(widget == NULL) {
return TCL_OK;
}
optionUid = Tk_GetUid(opt);
entryPtr = Tcl_CreateHashEntry(widget->optionsTable, optionUid, &isNew);
if(isNew == 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("option exists: %s", opt));
return TCL_ERROR;
}
/* create option */
optionPtr = (WidgetOption *)ckalloc(sizeof(WidgetOption));
assert(optionPtr);
memset(optionPtr, 0, sizeof(WidgetOption));
optionPtr->option = option;
Tcl_IncrRefCount(optionPtr->option);
if (Tcl_GetString(dbname)[0] == '\0') {
optionPtr->dbname = tkoPtr->Obj_empty;
searchdb++;
}
else {
optionPtr->dbname = dbname;
}
Tcl_IncrRefCount(optionPtr->dbname);
Tcl_SetHashValue(entryPtr, (char *)optionPtr);
if (flags) {
optionPtr->flags = flags;
}
else {
optionPtr->flags = tkoPtr->Obj_empty;
}
Tcl_IncrRefCount(optionPtr->flags);
optionPtr->flagbits = intFlags;
/* synonym options can have flags.
* Need to check usage of init value! */
if(dbclass == NULL) {
optionPtr->dbclass = NULL;
optionPtr->defvalue = NULL;
if(value) {
optionPtr->value = value;
Tcl_IncrRefCount(optionPtr->value);
}
/* normal option */
} else {
if (Tcl_GetString(dbclass)[0] == '\0') {
optionPtr->dbclass = tkoPtr->Obj_empty;
dbclassUid = tkoPtr->Uid_empty;
searchdb++;
}
else {
dbclassUid = Tk_GetUid(Tcl_GetString(dbclass));
optionPtr->dbclass = dbclass;
}
Tcl_IncrRefCount(optionPtr->dbclass);
optionPtr->defvalue = defvalue;
Tcl_IncrRefCount(optionPtr->defvalue);
/*
* If value is given use it.
*/
if(value) {
optionPtr->value = value;
optionPtr->flagbits |= TKO_OPTION__USER;
} else {
if (searchdb < 2 && widget->tkWin != NULL) {
/*
* Get value from option database
*/
dbnameUid = Tk_GetUid(Tcl_GetString(dbname));
if (optionPtr->value == NULL) {
valueUid = Tk_GetOption(widget->tkWin, dbnameUid, dbclassUid);
if (valueUid != NULL) {
optionPtr->value = Tcl_NewStringObj(valueUid, -1);
}
}
/*
* Check for a system-specific default value.
* Do not for -class because Tcl_SetClass was not called.
* When -class is not first option (after -screen) we get a crash!
*/
if (optionPtr->value == NULL && optionUid != tkoPtr->Uid_class) {
optionPtr->value =
Tk_GetSystemDefault(widget->tkWin, dbnameUid, dbclassUid);
}
}
/*
* Use default value.
*/
if(optionPtr->value == NULL) {
optionPtr->value = defvalue;
optionPtr->flagbits |= TKO_OPTION__USER;
}
}
/*
* No given value defaults to empty string.
*/
if(optionPtr->value == NULL) {
optionPtr->value = tkoPtr->Obj_empty;
/* No flag as this does not count as user supplied */
}
Tcl_IncrRefCount(optionPtr->value);
/*
* Outside initmode the trace on the array variable needs to be disabled.
*/
if (initmode == 0) {
Tcl_UntraceVar2(interp, Tcl_GetString(widget->optionsArray), NULL,
TCL_TRACE_WRITES | TCL_TRACE_RESULT_OBJECT, WidgetOptionTrace, widget);
traceadd = 1;
}
/*
*Set option array variable
*/
if (Tcl_ObjSetVar2(interp, widget->optionsArray, option,
optionPtr->value, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
goto error;
}
/*
* Do initialization with -option method.
* We do it for readonly options only here.
* And we do it for options added with "configure optionadd ..".
*/
if (readonly || initmode == 0) {
if (initmode != 2) {
myObjv[0] = widget->myCmd;
myObjv[1] = option;
if (Tcl_EvalObjv(interp, 2, myObjv, TCL_EVAL_GLOBAL) != TCL_OK) {
goto error;
}
/*
* We set the value again because the -option method may have changed it.
*/
if (optionPtr->value) {
Tcl_DecrRefCount(optionPtr->value);
}
optionPtr->value = Tcl_ObjGetVar2(interp, widget->optionsArray, option, TCL_GLOBAL_ONLY);
Tcl_IncrRefCount(optionPtr->value);
}
/* Now we are ready to set the readonly bit */
if (readonly) {
optionPtr->flagbits |= TKO_OPTION_READONLY;
}
}
}
if (traceadd) {
Tcl_TraceVar2(interp, Tcl_GetString(widget->optionsArray), NULL,
TCL_TRACE_WRITES | TCL_TRACE_RESULT_OBJECT, WidgetOptionTrace, widget);
}
return TCL_OK;
error:
if (traceadd) {
/* There should be no error and thus we don't need to save the result. */
Tcl_TraceVar2(interp, Tcl_GetString(widget->optionsArray), NULL,
TCL_TRACE_WRITES | TCL_TRACE_RESULT_OBJECT, WidgetOptionTrace, widget);
}
WidgetOptionDelEntry(entryPtr);
return TCL_ERROR;
}
/*
* WidgetOptionGet --
* Get option value.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* return current vlaue of widget option.
*/
static int
WidgetOptionGet(
Tcl_Interp * interp,
Tko_Widget * widget,
Tcl_Obj * option)
{
Tcl_Obj *retPtr;
Tcl_HashEntry *entryPtr;
WidgetOption *optionPtr;
if(option == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no option given"));
return TCL_ERROR;
}
entryPtr =
Tcl_FindHashEntry(widget->optionsTable,
Tk_GetUid(Tcl_GetString(option)));
if(entryPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unknown option \"%s\"",
Tcl_GetString(option)));
return TCL_ERROR;
}
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
/* hidden option, not visible in cget method */
if (optionPtr->flagbits&TKO_OPTION_HIDE) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("hidden option \"%s\"",
Tcl_GetString(option)));
return TCL_ERROR;
}
/* synonym option */
if(optionPtr->dbclass == NULL) {
entryPtr =
Tcl_FindHashEntry(widget->optionsTable,
Tk_GetUid(Tcl_GetString(optionPtr->dbname)));
if(entryPtr == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("unknown synonym option \"%s\"",
Tcl_GetString(option)));
return TCL_ERROR;
}
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
if(optionPtr->dbclass == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("synonym option is synonym \"%s\"",
Tcl_GetString(option)));
return TCL_ERROR;
}
}
retPtr = optionPtr->value;
Tcl_SetObjResult(interp, retPtr);
return TCL_OK;
}
/*
* WidgetOptionSet --
* Set new widget option value.
* Results:
* A standard Tcl result.
*
* Side effects:
* Set option value and call
*/
static int
WidgetOptionSet(
Tcl_Interp * interp,
Tko_Widget * widget,
Tcl_Obj * option,
Tcl_Obj * value)
{
Tcl_HashEntry *entryPtr;
WidgetOption *optionPtr;
if(option == NULL || value == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("missing option and/or value"));
return TCL_ERROR;
}
entryPtr =
Tcl_FindHashEntry(widget->optionsTable,
Tk_GetUid(Tcl_GetString(option)));
if(entryPtr == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("unknown option \"%s\"", Tcl_GetString(option)));
return TCL_ERROR;
}
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
/* hidden option, not visible in cget method */
if (optionPtr->flagbits&TKO_OPTION_HIDE) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("hidden option \"%s\"",
Tcl_GetString(option)));
return TCL_ERROR;
}
/* synonym option */
if(optionPtr->dbclass == NULL) {
entryPtr =
Tcl_FindHashEntry(widget->optionsTable,
Tk_GetUid(Tcl_GetString(optionPtr->dbname)));
if(entryPtr == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("unknown synonym option \"%s\"",
Tcl_GetString(option)));
return TCL_ERROR;
}
optionPtr = (WidgetOption *)Tcl_GetHashValue(entryPtr);
if(optionPtr->dbclass == NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("synonym option is synonym \"%s\"",
Tcl_GetString(option)));
return TCL_ERROR;
}
if(Tcl_ObjSetVar2(interp, widget->optionsArray, optionPtr->option,
value, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
return TCL_ERROR;
}
} else {
if(Tcl_ObjSetVar2(interp, widget->optionsArray, option, value,
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
return TCL_ERROR;
}
}
optionPtr->flagbits |= TKO_OPTION__USER;
return TCL_OK;
}
/*
* Tko_WidgetOptionGet --
*
* Results:
* Return TclObj value of option or NULL if widget is destroyed.
*
* Side effects:
*/
Tcl_Obj *
Tko_WidgetOptionGet(
Tko_Widget *widget,
Tcl_Obj *option)
{
if (widget->optionsArray == NULL || option ==NULL) return NULL;
return Tcl_ObjGetVar2(widget->interp, widget->optionsArray, option,
TCL_GLOBAL_ONLY);
}
/*
* Tko_WidgetOptionSet --
* Set option value.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Create necessary C-values.
*/
Tcl_Obj *
Tko_WidgetOptionSet(
Tko_Widget *widget,
Tcl_Obj * option,
Tcl_Obj * value)
{
if (widget->optionsArray == NULL || option==NULL || value == NULL) return NULL;
return Tcl_ObjSetVar2(widget->interp, widget->optionsArray, option, value,
TCL_GLOBAL_ONLY);
}
/*
* WidgetOptionTrace --
* Write trace on option array variable
*
* Results:
* Return NULL if successfull and leave error message otherwise.
*
* Side effects:
* Check on existence of option and call "-option" method with new value.
*/
static char *
WidgetOptionTrace(
ClientData clientData,
Tcl_Interp * interp,
const char *name1,
const char *name2,
int flags)
{
Tko_Widget *widget = (Tko_Widget *) clientData;
Tcl_HashEntry *entryPtr;
Tcl_Obj *valuePtr;
// const char *result;
WidgetOption *optionPtr;
Tcl_Obj *myObjv[2];
Tcl_Obj *myRet;
(void)name1;
(void)flags;
/* get new value */
entryPtr = Tcl_FindHashEntry(widget->optionsTable, Tk_GetUid(name2));
if(entryPtr == NULL) {
myRet = Tcl_ObjPrintf("option \"%s\" not found", name2);
Tcl_IncrRefCount(myRet);
return (char *)myRet;
}
optionPtr = (WidgetOption *) Tcl_GetHashValue(entryPtr);
if(optionPtr->flagbits & TKO_OPTION_READONLY) {
myRet = Tcl_ObjPrintf("option \"%s\" is readonly", name2);
Tcl_IncrRefCount(myRet);
return (char *)myRet;
}
myObjv[0] = widget->myCmd;
myObjv[1] = optionPtr->option;
if(Tcl_EvalObjv(interp, 2, myObjv, TCL_EVAL_GLOBAL) != TCL_OK) {
myRet = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(myRet);
/* reset to old value TODO checks? */
if(optionPtr->value != NULL) {
Tcl_ObjSetVar2(interp, widget->optionsArray, optionPtr->option,
optionPtr->value, TCL_GLOBAL_ONLY);
Tcl_EvalObjv(interp, 2, myObjv, TCL_EVAL_GLOBAL);
}
return (char *)myRet;
}
if(optionPtr->value != NULL) {
Tcl_DecrRefCount(optionPtr->value);
}
valuePtr = Tcl_ObjGetVar2(interp, widget->optionsArray, optionPtr->option, TCL_GLOBAL_ONLY);
optionPtr->value = valuePtr;
Tcl_IncrRefCount(optionPtr->value);
return NULL;
}
/*
* WidgetOptionDelEntry --
* Delete internal entry value.
*
* Results:
* None.
*
* Side effects:
*/
static void
WidgetOptionDelEntry(
Tcl_HashEntry * entry)
{
WidgetOption *optionPtr = (WidgetOption *)Tcl_GetHashValue(entry);
if(optionPtr->option)
Tcl_DecrRefCount(optionPtr->option);
if(optionPtr->dbname)
Tcl_DecrRefCount(optionPtr->dbname);
if(optionPtr->dbclass)
Tcl_DecrRefCount(optionPtr->dbclass);
if(optionPtr->flags)
Tcl_DecrRefCount(optionPtr->flags);
if(optionPtr->defvalue)
Tcl_DecrRefCount(optionPtr->defvalue);
if(optionPtr->value)
Tcl_DecrRefCount(optionPtr->value);
ckfree(optionPtr);
Tcl_DeleteHashEntry(entry);
}
/*
* WidgetMethod_tko_configure --
* Virtual method called after configuring options.
* Should be implemented in derived classes.
*
* Results:
* A standard Tcl result.
*
* Side effects:
*/
static int
WidgetMethod_tko_configure(
ClientData dummy,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[])
{ /* virtual method */
(void)dummy;
(void)interp;
(void)context;
(void)objc;
(void)objv;
return TCL_OK;
}
/*
* WidgetMetaDelete --
* Delete widget meta data when all preserve calls done.
*
* Results:
* None.
*
* Side effects:
*/
static void
WidgetMetaDelete(
ClientData clientData)
{
(void)clientData;
/* Tcl_EventuallyFree(clientData, (Tcl_FreeProc *)WidgetMetaDestroy); */
}
/*
* WidgetMethod_ --
* Standard option set method.
*
* Results:
* A standard Tcl result.
*
* Side effects:
*/
static int
WidgetMethod_(
ClientData clientdata,
Tcl_Interp * interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj * const objv[])
{
WidgetClientdata *define;
Tcl_Object object;
Tko_Widget *widget;
Tcl_Obj *value;
char *address = NULL;
int intVal;
double dblVal;
Colormap colormap;
int *intPtr;
const char *str;
int length;
int pixels[4] = { 0, 0, 0, 0 };
int myObjc;
Tcl_Obj **myObjv;
Visual * visual;
XColor * color;
Tk_3DBorder border;
Tk_Anchor anchor;
Tk_Cursor cursor;
Tk_Window newWin;
Tk_Font newFont;
Tk_Justify justify;
(void)objc;
if ((define = (WidgetClientdata *)clientdata) == NULL
|| (object = Tcl_ObjectContextObject(context)) == NULL
|| (widget = (Tko_Widget *)Tcl_ObjectGetMetadata(object, &tkoWidgetMeta))
== NULL
|| (value = Tcl_ObjGetVar2(interp, widget->optionsArray, define->option,
TCL_GLOBAL_ONLY)) == NULL
|| widget->myCmd == NULL) {
return TCL_ERROR;
}
if (define->offset > 0) {
address = ((char *)widget) + define->offset;
}
switch (define->type) {
case TKO_SET_CLASS: /* (Tcl_Obj **)address */
Tk_SetClass(widget->tkWin, Tcl_GetString(value));
if (address) {
if (*((Tcl_Obj **)address) != NULL)
Tcl_DecrRefCount(*((Tcl_Obj **)address));
*((Tcl_Obj **)address) = value;
Tcl_IncrRefCount(value);
}
return TCL_OK;
case TKO_SET_VISUAL: /* (Tcl_Obj **)address */
visual =
Tk_GetVisual(interp, widget->tkWin, Tcl_GetString(value), &intVal,
&colormap);
if (visual == NULL)
return TCL_ERROR;
Tk_SetWindowVisual(widget->tkWin, visual, intVal, colormap);
if (address) {
if (*((Tcl_Obj **)address) != NULL)
Tcl_DecrRefCount(*((Tcl_Obj **)address));
*((Tcl_Obj **)address) = value;
Tcl_IncrRefCount(value);
}
return TCL_OK;
case TKO_SET_COLORMAP: /* (Tcl_Obj **)address */
str = Tcl_GetStringFromObj(value, &length);
if (str && length) {
colormap = Tk_GetColormap(interp, widget->tkWin, str);
if (colormap == None)
return TCL_ERROR;
Tk_SetWindowColormap(widget->tkWin, colormap);
}
if (address) {
if (*((Tcl_Obj **)address) != NULL)
Tcl_DecrRefCount(*((Tcl_Obj **)address));
*((Tcl_Obj **)address) = value;
Tcl_IncrRefCount(value);
}
return TCL_OK;
case TKO_SET_USE: /* (Tcl_Obj **)address */
str = Tcl_GetStringFromObj(value, &length);
if (str && length) {
if (Tk_UseWindow(interp, widget->tkWin, str) != TCL_OK) {
return TCL_ERROR;
}
}
else if (!(define->flags & TKO_OPTION_NULL)) {
return TCL_ERROR;
}
if (address) {
if (*((Tcl_Obj **)address) != NULL)
Tcl_DecrRefCount(*((Tcl_Obj **)address));
if (length) {
*((Tcl_Obj **)address) = value;
Tcl_IncrRefCount(value);
}
else {
*((Tcl_Obj **)address) = NULL;
}
}
return TCL_OK;
case TKO_SET_CONTAINER: /* (int *)address */
if (Tcl_GetBooleanFromObj(interp, value, &intVal) != TCL_OK)
return TCL_ERROR;
if (intVal) {
Tk_MakeContainer(widget->tkWin);
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1], Tcl_NewIntObj(1),
TCL_GLOBAL_ONLY);
}
else {
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1], Tcl_NewIntObj(0),
TCL_GLOBAL_ONLY);
}
if (address) {
*(int *)address = intVal;
}
return TCL_OK;
case TKO_SET_TCLOBJ: /* (Tcl_Obj **)address */
if (address) {
if (*((Tcl_Obj **)address) != NULL)
Tcl_DecrRefCount(*((Tcl_Obj **)address));
*((Tcl_Obj **)address) = value;
Tcl_IncrRefCount(value);
}
return TCL_OK;
case TKO_SET_XCOLOR: /* (Xcolor **)address */
color = Tk_AllocColorFromObj(interp, widget->tkWin, value);
if (color == NULL)
return TCL_ERROR;
if (address) {
if (*((XColor **)address) != NULL) {
Tk_FreeColor(*((XColor **)address));
}
*((XColor **)address) = color;
}
else {
Tk_FreeColor(color);
}
return TCL_OK;
case TKO_SET_3DBORDER: /* (Tk_3DBorder *)address */
str = Tcl_GetStringFromObj(value, &length);
if (str && length) {
border = Tk_Alloc3DBorderFromObj(interp, widget->tkWin, value);
if (border == NULL)
return TCL_ERROR;
}
else if (define->flags & TKO_OPTION_NULL) {
border = NULL;
} else {
return TCL_ERROR;
}
if (address) {
if (*(Tk_3DBorder *)address != NULL) {
Tk_Free3DBorder(*(Tk_3DBorder *)address);
}
*(Tk_3DBorder *)address = border;
}
else {
Tk_Free3DBorder(border);
}
return TCL_OK;
case TKO_SET_PIXEL: /* (int *)address */
if (Tk_GetPixelsFromObj(interp, widget->tkWin, value, &intVal) != TCL_OK) {
return TCL_ERROR;
}
if (address) {
*(int *)address = intVal;
}
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1],
Tcl_NewIntObj(intVal), TCL_GLOBAL_ONLY);
return TCL_OK;
case TKO_SET_PIXELNONEGATIV: /* (int *)address */
if (Tk_GetPixelsFromObj(interp, widget->tkWin, value, &intVal) != TCL_OK) {
return TCL_ERROR;
}
if (intVal >= SHRT_MAX) {
Tcl_AppendResult(interp, "bad distance \"", Tcl_GetString(value),
"\": ", "too big to represent", (char *)NULL);
return TCL_ERROR;
}
if (intVal < 0) {
Tcl_AppendResult(interp, "bad distance \"", Tcl_GetString(value),
"\": ", "can't be negative", (char *)NULL);
return TCL_ERROR;
}
if (address) {
*(int *)address = intVal;
}
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1],
Tcl_NewIntObj(intVal), TCL_GLOBAL_ONLY);
return TCL_OK;
case TKO_SET_PIXELPOSITIV: /* (int *)address */
if (Tk_GetPixelsFromObj(interp, widget->tkWin, value, &intVal) != TCL_OK) {
return TCL_ERROR;
}
if (intVal >= SHRT_MAX) {
Tcl_AppendResult(interp, "bad distance \"", Tcl_GetString(value),
"\": ", "too big to represent", (char *)NULL);
return TCL_ERROR;
}
if (intVal <= 0) {
Tcl_AppendResult(interp, "bad distance \"", Tcl_GetString(value),
"\": ", "must be positive", (char *)NULL);
return TCL_ERROR;
}
if (address) {
*(int *)address = intVal;
}
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1],
Tcl_NewIntObj(intVal), TCL_GLOBAL_ONLY);
return TCL_OK;
case TKO_SET_DOUBLE: /* (double *)address */
if (Tcl_GetDoubleFromObj(interp, value, &dblVal) != TCL_OK) {
return TCL_ERROR;
}
if (address) {
*(double *)address = dblVal;
}
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1],
Tcl_NewDoubleObj(dblVal), TCL_GLOBAL_ONLY);
return TCL_OK;
case TKO_SET_BOOLEAN: /* (int *)address */
if (Tcl_GetBooleanFromObj(interp, value, &intVal) != TCL_OK) {
return TCL_ERROR;
}
if (intVal) {
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1], Tcl_NewIntObj(1),
TCL_GLOBAL_ONLY);
}
else {
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1], Tcl_NewIntObj(0),
TCL_GLOBAL_ONLY);
}
if (address) {
*(int *)address = intVal;
}
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1],
Tcl_NewIntObj(intVal), TCL_GLOBAL_ONLY);
return TCL_OK;
case TKO_SET_CURSOR: /* (Tk_Cursor *)address */
cursor = NULL;
if (Tcl_GetString(value)[0] != '\0') {
cursor = Tk_AllocCursorFromObj(interp, widget->tkWin, value);
if (cursor == NULL) {
return TCL_ERROR;
}
Tk_DefineCursor(widget->tkWin, cursor);
}
if (address) {
if (*(Tk_Cursor *)address != NULL) {
Tk_FreeCursor(Tk_Display(widget->tkWin),
*(Tk_Cursor *)address);
}
*(Tk_Cursor *)address = cursor;
}
else {
if (cursor != NULL) {
Tk_FreeCursor(Tk_Display(widget->tkWin), cursor);/*TODO necessary? */
}
}
return TCL_OK;
case TKO_SET_INT: /* (int *)address */
if (Tcl_GetIntFromObj(interp, value, &intVal) != TCL_OK) {
return TCL_ERROR;
}
if (address) {
*(int *)address = intVal;
}
Tcl_ObjSetVar2(interp, widget->optionsArray, objv[1],
Tcl_NewIntObj(intVal), TCL_GLOBAL_ONLY);
return TCL_OK;
case TKO_SET_RELIEF: /* (int *)address */
if (Tk_GetReliefFromObj(interp, value, &intVal) != TCL_OK) {
return TCL_ERROR;
}
if (address) {
*(int *)address = intVal;
}
return TCL_OK;
case TKO_SET_ANCHOR: /* (Tk_Anchor *)address */
if (Tk_GetAnchorFromObj(interp, value, &anchor) != TCL_OK) {
return TCL_ERROR;
}
if (address) {
*(Tk_Anchor *)address = anchor;
}
return TCL_OK;
case TKO_SET_WINDOW: /* (Tk_Window *)address */
if (value == NULL || Tcl_GetCharLength(value) == 0) {
newWin = NULL;
}
else {
if (TkGetWindowFromObj(interp, widget->tkWin, value,
&newWin) != TCL_OK) {
return TCL_ERROR;
}
}
if (address) {
*(Tk_Window *)address = newWin;
}
return TCL_OK;
case TKO_SET_FONT: /* (Tk_Font *)address */
newFont = Tk_AllocFontFromObj(interp, widget->tkWin, value);
if (newFont == NULL) {
return TCL_ERROR;
}
if (address) {
if (*(Tk_Font *)address != NULL) {
Tk_FreeFont(*(Tk_Font *)address);
}
*(Tk_Font *)address = newFont;
}
else {
Tk_FreeFont(newFont);
}
return TCL_OK;
case TKO_SET_STRING: /* (char **)address */
if (address) {
str = Tcl_GetStringFromObj(value, &length);
if (*(char **)address != NULL) {
ckfree(*(char **)address);
}
if (length == 0 && define->flags&TKO_OPTION_NULL) {
*(char **)address = NULL;
}
else {
*(char **)address=(char *)ckalloc(length + 1);
assert(*(char **)address);
memcpy(*(char **)address, str, length + 1);
}
}
return TCL_OK;
case TKO_SET_SCROLLREGION: /* (int *[4])address */
if (Tcl_ListObjGetElements(interp, value, &myObjc, &myObjv) != TCL_OK) {
return TCL_ERROR;
}
if (myObjc == 4) {
if (Tk_GetPixelsFromObj(interp, widget->tkWin, myObjv[0],
&pixels[0]) != TCL_OK
|| Tk_GetPixelsFromObj(interp, widget->tkWin, myObjv[1],
&pixels[1]) != TCL_OK
|| Tk_GetPixelsFromObj(interp, widget->tkWin, myObjv[2],
&pixels[2]) != TCL_OK
|| Tk_GetPixelsFromObj(interp, widget->tkWin, myObjv[3],
&pixels[3]) != TCL_OK) {
return TCL_ERROR;
}
}
else if (myObjc != 0) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("found %d instead of 4 values", myObjc));
return TCL_ERROR;
}
if (address) {
intPtr = (int *)address;
intPtr[0] = pixels[0];
intPtr[1] = pixels[1];
intPtr[2] = pixels[2];
intPtr[3] = pixels[3];
}
return TCL_OK;
case TKO_SET_JUSTIFY: /* (Tk_Justify *)address */
if (Tk_GetJustify(interp, Tk_GetUid(Tcl_GetString(value)),
&justify) != TCL_OK) {
return TCL_ERROR;
}
if (address) {
*(Tk_Justify *)address = justify;
}
return TCL_OK;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unknown type \"%d\"", define->type));
return TCL_ERROR;
}
/*
* WidgetMethod_ --
* Check given flagsPtr object and if flags is given set int value from string.
*
* Results:
* A standard Tcl result.
*
* Side effects:
*/
static int WidgetFlagsObj(Tcl_Obj *flagsPtr, int *flags)
{
char *ch;
int retValue = 0;
if (flagsPtr == NULL) return TCL_ERROR;
ch = Tcl_GetString(flagsPtr);
if (ch[0] != '\0') {
if (ch[0] == 'r') {
retValue |= TKO_OPTION_READONLY;
if (ch[1] != '\0') {
if (ch[1] == 'h') {
retValue |= TKO_OPTION_HIDE;
}
else {
return TCL_ERROR;
}
}
}
else if (ch[0] == 'h') {
retValue |= TKO_OPTION_HIDE;
if (ch[1] != '\0') {
if (ch[1] == 'r') {
retValue |= TKO_OPTION_READONLY;
}
else {
return TCL_ERROR;
}
}
}
else {
return TCL_ERROR;
}
}
if (flags) {
*flags |= retValue;
}
return TCL_OK;
}
/*
* WidgetFlagsHideGet --
* Return 1 if option is hidden and 0 otherwise.
*
* Results:
* Return 1 if option is hidden and 0 otherwise.
*
* Side effects:
*/
static int WidgetFlagsHideGet(Tcl_Obj *flags)
{
const char *ch;
ch = Tcl_GetString(flags);
if (ch[0] == 'h' || (ch[0] == 'r' && ch[1] == 'h')) {
return 1;
}
return 0;
}
/*
* WidgetFlagsHideSet --
* Set hidden option state.
*
* Results:
* Return object with new state.
*
* Side effects:
*/
static Tcl_Obj *WidgetFlagsHideSet(
Tcl_Obj *flags) /* last flag value object */
{
const char *ch;
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
ch = Tcl_GetString(flags);
if (ch[0] != '\0' && (ch[0] == 'r' || ch[1] == 'r')) {
return tkoPtr->Obj_flags_rh;
}
return tkoPtr->Obj_flags_h;
}
/*
* WidgetFlagsHideUnset --
* Unset hidden option state.
*
* Results:
* Return object with new state.
*
* Side effects:
*/
static Tcl_Obj *WidgetFlagsHideUnset(
Tcl_Obj *flags) /* last flag value object */
{
const char *ch;
TkoThreadData *tkoPtr = (TkoThreadData *)Tcl_GetThreadData(&tkoKey, sizeof(TkoThreadData));
ch = Tcl_GetString(flags);
if (ch[0] != '\0') {
if (ch[0] == 'h') {
if (ch[1] == 'r') {
return tkoPtr->Obj_flags_r;
}
else {
return tkoPtr->Obj_empty;
}
}
else {
if (ch[1] == 'h') {
return tkoPtr->Obj_flags_r;
}
}
}
return tkoPtr->Obj_empty;
}
/*
* WidgetClientdataDelete --
* Delete widget internal method clientdata.
*
* Results:
* None.
*
* Side effects:
* Free memory.
*/
static void WidgetClientdataDelete(
ClientData clientdata)
{
WidgetClientdata *cd = (WidgetClientdata *)clientdata;
Tcl_DecrRefCount(cd->option);
ckfree(cd);
}
/*
* WidgetClientdataClone --
* Copy widget internal method clientdata.
*
* Results:
* Return copied clientdata in newPtr.
*
* Side effects:
*/
static int WidgetClientdataClone(
Tcl_Interp *dummy,
ClientData clientdata,
ClientData *newPtr)
{
WidgetClientdata *cd = (WidgetClientdata *)clientdata;
(void)dummy;
if (cd) {
*newPtr = ckalloc(sizeof(WidgetClientdata));
assert(*newPtr);
memcpy(*newPtr, cd, sizeof(WidgetClientdata));
Tcl_IncrRefCount(cd->option);
}
return TCL_OK;
}
/* vim: set ts=4 sw=4 sts=4 ff=unix et : */