@@ -356,6 +356,15 @@ typedef struct {
356356 const Tcl_ObjType * StringType ;
357357 const Tcl_ObjType * UTF32StringType ;
358358 const Tcl_ObjType * PixelType ;
359+ const Tcl_ObjType * IndexType ;
360+ const Tcl_ObjType * ColorType ;
361+ const Tcl_ObjType * BorderType ;
362+ const Tcl_ObjType * FontType ;
363+ const Tcl_ObjType * CursorType ;
364+ const Tcl_ObjType * WindowType ;
365+ const Tcl_ObjType * NsNameType ;
366+ const Tcl_ObjType * ParsedVarNameType ;
367+ const Tcl_ObjType * DictType ;
359368} TkappObject ;
360369
361370#define TkappObject_CAST (op ) ((TkappObject *)(op))
@@ -687,11 +696,22 @@ Tkapp_New(const char *screenName, const char *className,
687696 Tcl_DecrRefCount (value );
688697 }
689698 v -> WideIntType = Tcl_GetObjType ("wideInt" );
690- v -> BignumType = Tcl_GetObjType ("bignum" );
691699 v -> ListType = Tcl_GetObjType ("list" );
692700 v -> StringType = Tcl_GetObjType ("string" );
693701 v -> UTF32StringType = Tcl_GetObjType ("utf32string" );
702+ /* These types may not be registered until first used, so these may be NULL;
703+ FromObj() caches them lazily on first encounter. */
704+ v -> BignumType = Tcl_GetObjType ("bignum" );
694705 v -> PixelType = Tcl_GetObjType ("pixel" );
706+ v -> IndexType = Tcl_GetObjType ("index" );
707+ v -> ColorType = Tcl_GetObjType ("color" );
708+ v -> BorderType = Tcl_GetObjType ("border" );
709+ v -> FontType = Tcl_GetObjType ("font" );
710+ v -> CursorType = Tcl_GetObjType ("cursor" );
711+ v -> WindowType = Tcl_GetObjType ("window" );
712+ v -> NsNameType = Tcl_GetObjType ("nsName" );
713+ v -> ParsedVarNameType = Tcl_GetObjType ("parsedVarName" );
714+ v -> DictType = Tcl_GetObjType ("dict" );
695715
696716 /* Delete the 'exit' command, which can screw things up */
697717 Tcl_DeleteCommand (v -> interp , "exit" );
@@ -1257,6 +1277,39 @@ fromBignumObj(TkappObject *tkapp, Tcl_Obj *value)
12571277 return res ;
12581278}
12591279
1280+ /* Convert a "pixel" screen distance to a Python object. A value with no unit
1281+ suffix is screen independent and is returned as an int or float. A value with
1282+ an m/c/i/p suffix needs a Tk_Window to be resolved to pixels, which is not
1283+ available here, so it is kept as a Tcl_Obj. Tcl_Get*FromObj() only set the
1284+ object's type on success, so a unit-bearing value does not shimmer. */
1285+ static PyObject *
1286+ fromPixelObj (TkappObject * tkapp , Tcl_Obj * value )
1287+ {
1288+ PyObject * result = fromWideIntObj (tkapp , value );
1289+ if (result != NULL || PyErr_Occurred ()) {
1290+ return result ;
1291+ }
1292+ Tcl_ResetResult (Tkapp_Interp (tkapp ));
1293+ double doubleValue ;
1294+ if (Tcl_GetDoubleFromObj (NULL , value , & doubleValue ) == TCL_OK ) {
1295+ return PyFloat_FromDouble (doubleValue );
1296+ }
1297+ return newPyTclObject (value );
1298+ }
1299+
1300+ /* Convert an "index" object to a Python str. Index values are enumeration
1301+ keywords from a small fixed set (e.g. "horizontal", "disabled"), so the result
1302+ is interned to share one str object per keyword. */
1303+ static PyObject *
1304+ fromIndexObj (TkappObject * tkapp , Tcl_Obj * value )
1305+ {
1306+ PyObject * result = unicodeFromTclObj (tkapp , value );
1307+ if (result != NULL ) {
1308+ PyUnicode_InternInPlace (& result );
1309+ }
1310+ return result ;
1311+ }
1312+
12601313static PyObject *
12611314FromObj (TkappObject * tkapp , Tcl_Obj * value )
12621315{
@@ -1327,19 +1380,96 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
13271380 }
13281381
13291382 if (value -> typePtr == tkapp -> StringType ||
1330- value -> typePtr == tkapp -> UTF32StringType ||
1331- value -> typePtr == tkapp -> PixelType )
1383+ value -> typePtr == tkapp -> UTF32StringType )
13321384 {
13331385 return unicodeFromTclObj (tkapp , value );
13341386 }
13351387
1336- if (tkapp -> BignumType == NULL &&
1337- strcmp (value -> typePtr -> name , "bignum" ) == 0 ) {
1338- /* bignum type is not registered in Tcl */
1388+ if (value -> typePtr == tkapp -> PixelType ) {
1389+ return fromPixelObj (tkapp , value );
1390+ }
1391+
1392+ if (value -> typePtr == tkapp -> IndexType ) {
1393+ return fromIndexObj (tkapp , value );
1394+ }
1395+
1396+ /* A dict is kept as a Tcl_Obj to preserve its structure for _splitdict(). */
1397+ if (value -> typePtr == tkapp -> DictType ) {
1398+ return newPyTclObject (value );
1399+ }
1400+
1401+ /* Resource types are kept as a Tcl_Obj so that Tk can reuse the parsed
1402+ X/font resource when the object is passed back to it. */
1403+ if (value -> typePtr == tkapp -> ColorType ||
1404+ value -> typePtr == tkapp -> BorderType ||
1405+ value -> typePtr == tkapp -> FontType ||
1406+ value -> typePtr == tkapp -> CursorType ) {
1407+ return newPyTclObject (value );
1408+ }
1409+
1410+ /* These types are context-bound lookups (a cached window or namespace
1411+ resolution, or a parsed variable name) with nothing worth preserving in
1412+ a Tcl_Obj, so they are returned as str. */
1413+ if (value -> typePtr == tkapp -> WindowType ||
1414+ value -> typePtr == tkapp -> NsNameType ||
1415+ value -> typePtr == tkapp -> ParsedVarNameType ) {
1416+ return unicodeFromTclObj (tkapp , value );
1417+ }
1418+
1419+ /* The types below may not be registered until first used, so they are
1420+ matched by name and cached on first encounter; the pointer checks above
1421+ then catch them. */
1422+ const char * name = value -> typePtr -> name ;
1423+
1424+ if (tkapp -> BignumType == NULL && strcmp (name , "bignum" ) == 0 ) {
13391425 tkapp -> BignumType = value -> typePtr ;
13401426 return fromBignumObj (tkapp , value );
13411427 }
13421428
1429+ if (tkapp -> DictType == NULL && strcmp (name , "dict" ) == 0 ) {
1430+ tkapp -> DictType = value -> typePtr ;
1431+ return newPyTclObject (value );
1432+ }
1433+
1434+ if (tkapp -> PixelType == NULL && strcmp (name , "pixel" ) == 0 ) {
1435+ tkapp -> PixelType = value -> typePtr ;
1436+ return fromPixelObj (tkapp , value );
1437+ }
1438+
1439+ if (tkapp -> IndexType == NULL && strcmp (name , "index" ) == 0 ) {
1440+ tkapp -> IndexType = value -> typePtr ;
1441+ return fromIndexObj (tkapp , value );
1442+ }
1443+
1444+ if (tkapp -> WindowType == NULL && strcmp (name , "window" ) == 0 ) {
1445+ tkapp -> WindowType = value -> typePtr ;
1446+ return unicodeFromTclObj (tkapp , value );
1447+ }
1448+
1449+ if (tkapp -> NsNameType == NULL && strcmp (name , "nsName" ) == 0 ) {
1450+ tkapp -> NsNameType = value -> typePtr ;
1451+ return unicodeFromTclObj (tkapp , value );
1452+ }
1453+
1454+ if (tkapp -> ParsedVarNameType == NULL && strcmp (name , "parsedVarName" ) == 0 ) {
1455+ tkapp -> ParsedVarNameType = value -> typePtr ;
1456+ return unicodeFromTclObj (tkapp , value );
1457+ }
1458+
1459+ /* Any other type is returned as a Tcl_Obj. Cache the resource types so the
1460+ pointer check above catches them next time. */
1461+ if (tkapp -> ColorType == NULL && strcmp (name , "color" ) == 0 ) {
1462+ tkapp -> ColorType = value -> typePtr ;
1463+ }
1464+ else if (tkapp -> BorderType == NULL && strcmp (name , "border" ) == 0 ) {
1465+ tkapp -> BorderType = value -> typePtr ;
1466+ }
1467+ else if (tkapp -> FontType == NULL && strcmp (name , "font" ) == 0 ) {
1468+ tkapp -> FontType = value -> typePtr ;
1469+ }
1470+ else if (tkapp -> CursorType == NULL && strcmp (name , "cursor" ) == 0 ) {
1471+ tkapp -> CursorType = value -> typePtr ;
1472+ }
13431473 return newPyTclObject (value );
13441474}
13451475
0 commit comments