/* * 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 : */