From f7de3dd02d5186f30f69b80f5ee00376581f1d23 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Thu, 2 Apr 2015 10:35:57 +0300
Subject: [PATCH] Issue #21526: Tkinter now supports new boolean type in Tcl
 8.5.

---
 Lib/test/test_tcl.py | 15 ++++++++++++++
 Misc/NEWS            |  2 ++
 Modules/_tkinter.c   | 49 ++++++++++++++++++++++++++++++--------------
 3 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py
index da8f6299d6..d01f9694df 100644
--- a/Lib/test/test_tcl.py
+++ b/Lib/test/test_tcl.py
@@ -378,6 +378,21 @@ class TclTest(unittest.TestCase):
         if tcl_version >= (8, 5):
             check('2**64', True)
 
+    def test_booleans(self):
+        tcl = self.interp
+        def check(expr, expected):
+            result = tcl.call('expr', expr)
+            self.assertEqual(result, expected)
+            self.assertIsInstance(result, int)
+        check('true', True)
+        check('yes', True)
+        check('on', True)
+        check('false', False)
+        check('no', False)
+        check('off', False)
+        check('1 < 2', True)
+        check('1 > 2', False)
+
     def test_passing_values(self):
         def passValue(value):
             return self.interp.call('set', '_', value)
diff --git a/Misc/NEWS b/Misc/NEWS
index fd3856393b..7deb82012c 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -24,6 +24,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #21526: Tkinter now supports new boolean type in Tcl 8.5.
+
 - Issue #23838: linecache now clears the cache and returns an empty result on
   MemoryError.
 
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 14241e504e..43ee6786ae 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -242,13 +242,14 @@ typedef struct {
     int dispatching;
     /* We cannot include tclInt.h, as this is internal.
        So we cache interesting types here. */
-    Tcl_ObjType *BooleanType;
-    Tcl_ObjType *ByteArrayType;
-    Tcl_ObjType *DoubleType;
-    Tcl_ObjType *IntType;
-    Tcl_ObjType *ListType;
-    Tcl_ObjType *ProcBodyType;
-    Tcl_ObjType *StringType;
+    const Tcl_ObjType *OldBooleanType;
+    const Tcl_ObjType *BooleanType;
+    const Tcl_ObjType *ByteArrayType;
+    const Tcl_ObjType *DoubleType;
+    const Tcl_ObjType *IntType;
+    const Tcl_ObjType *ListType;
+    const Tcl_ObjType *ProcBodyType;
+    const Tcl_ObjType *StringType;
 } TkappObject;
 
 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
@@ -577,7 +578,8 @@ Tkapp_New(char *screenName, char *className,
     }
 #endif
 
-    v->BooleanType = Tcl_GetObjType("boolean");
+    v->OldBooleanType = Tcl_GetObjType("boolean");
+    v->BooleanType = Tcl_GetObjType("booleanString");
     v->ByteArrayType = Tcl_GetObjType("bytearray");
     v->DoubleType = Tcl_GetObjType("double");
     v->IntType = Tcl_GetObjType("int");
@@ -979,20 +981,29 @@ AsObj(PyObject *value)
     }
 }
 
+static PyObject *
+fromBoolean(PyObject* tkapp, Tcl_Obj *value)
+{
+    int boolValue;
+    if (Tcl_GetBooleanFromObj(Tkapp_Interp(tkapp), value, &boolValue) == TCL_ERROR)
+        return Tkinter_Error(tkapp);
+    return PyBool_FromLong(boolValue);
+}
+
 static PyObject*
 FromObj(PyObject* tkapp, Tcl_Obj *value)
 {
     PyObject *result = NULL;
     TkappObject *app = (TkappObject*)tkapp;
+    Tcl_Interp *interp = Tkapp_Interp(tkapp);
 
     if (value->typePtr == NULL) {
         return unicodeFromTclStringAndSize(value->bytes, value->length);
     }
 
-    if (value->typePtr == app->BooleanType) {
-        result = value->internalRep.longValue ? Py_True : Py_False;
-        Py_INCREF(result);
-        return result;
+    if (value->typePtr == app->BooleanType ||
+        value->typePtr == app->OldBooleanType) {
+        return fromBoolean(tkapp, value);
     }
 
     if (value->typePtr == app->ByteArrayType) {
@@ -1015,15 +1026,14 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
         PyObject *elem;
         Tcl_Obj *tcl_elem;
 
-        status = Tcl_ListObjLength(Tkapp_Interp(tkapp), value, &size);
+        status = Tcl_ListObjLength(interp, value, &size);
         if (status == TCL_ERROR)
             return Tkinter_Error(tkapp);
         result = PyTuple_New(size);
         if (!result)
             return NULL;
         for (i = 0; i < size; i++) {
-            status = Tcl_ListObjIndex(Tkapp_Interp(tkapp),
-                                      value, i, &tcl_elem);
+            status = Tcl_ListObjIndex(interp, value, i, &tcl_elem);
             if (status == TCL_ERROR) {
                 Py_DECREF(result);
                 return Tkinter_Error(tkapp);
@@ -1048,6 +1058,15 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
             Tcl_GetCharLength(value));
     }
 
+#if TK_VERSION_HEX >= 0x08050000
+    if (app->BooleanType == NULL &&
+        strcmp(value->typePtr->name, "booleanString") == 0) {
+        /* booleanString type is not registered in Tcl */
+        app->BooleanType = value->typePtr;
+        return fromBoolean(tkapp, value);
+    }
+#endif
+
     return newPyTclObject(value);
 }
 
-- 
2.40.0