Patch #518625: Return objects in Tkinter.
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 3dface6..b74641e 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -50,9 +50,11 @@
 
 #ifdef TK_FRAMEWORK
 #include <Tcl/tcl.h>
+#include <Tcl/tclInt.h>
 #include <Tk/tk.h>
 #else
 #include <tcl.h>
+#include <tclInt.h>
 #include <tk.h>
 #endif
 
@@ -219,6 +221,7 @@
 typedef struct {
 	PyObject_HEAD
 	Tcl_Interp *interp;
+	int want_objects;
 } TkappObject;
 
 #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
@@ -424,6 +427,67 @@
 	return v;
 }
 
+/* In some cases, Tcl will still return strings that are supposed to be
+   lists. SplitObj walks through a nested tuple, finding string objects that
+   need to be split. */
+
+PyObject *
+SplitObj(PyObject *arg)
+{
+	if (PyTuple_Check(arg)) {
+		int i, size;
+		PyObject *elem, *newelem, *result;
+
+		size = PyTuple_Size(arg);
+		result = NULL;
+		/* Recursively invoke SplitObj for all tuple items.
+		   If this does not return a new object, no action is
+		   needed. */
+		for(i = 0; i < size; i++) {
+			elem = PyTuple_GetItem(arg, i);
+			newelem = SplitObj(elem);
+			if (!newelem) {
+				Py_XDECREF(result);
+				return NULL;
+			}
+			if (!result) {
+				int k;
+				if (newelem == elem) {
+					Py_DECREF(newelem);
+					continue;
+				}
+				result = PyTuple_New(size);
+				if (!result)
+					return NULL;
+				for(k = 0; k < i; k++) {
+					elem = PyTuple_GetItem(arg, k);
+					Py_INCREF(elem);
+					PyTuple_SetItem(result, k, elem);
+				}
+			}
+			PyTuple_SetItem(result, i, newelem);
+		}
+		if (result)
+			return result;
+		/* Fall through, returning arg. */
+	}
+	else if (PyString_Check(arg)) {
+		int argc;
+		char **argv;
+		char *list = PyString_AsString(arg);
+
+		if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
+			Py_INCREF(arg);
+			return arg;
+		}
+		Tcl_Free(FREECAST argv);
+		if (argc > 1)
+			return Split(PyString_AsString(arg));
+		/* Fall through, returning arg. */
+	}
+	Py_INCREF(arg);
+	return arg;
+}
 
 
 /**** Tkapp Object ****/
@@ -458,7 +522,8 @@
 static void DisableEventHook(void); /* Forward */
 
 static TkappObject *
-Tkapp_New(char *screenName, char *baseName, char *className, int interactive)
+Tkapp_New(char *screenName, char *baseName, char *className, 
+	  int interactive, int want_objects)
 {
 	TkappObject *v;
 	char *argv0;
@@ -468,6 +533,7 @@
 		return NULL;
 
 	v->interp = Tcl_CreateInterp();
+	v->want_objects = want_objects;
 
 #if defined(macintosh)
 	/* This seems to be needed */
@@ -513,6 +579,104 @@
 
 /** Tcl Eval **/
 
+typedef struct {
+	PyObject_HEAD
+	Tcl_Obj *value;
+} PyTclObject;
+
+staticforward PyTypeObject PyTclObject_Type;
+#define PyTclObject_Check(v)	((v)->ob_type == &PyTclObject_Type)
+
+static PyObject *
+newPyTclObject(Tcl_Obj *arg)
+{
+	PyTclObject *self;
+	self = PyObject_New(PyTclObject, &PyTclObject_Type);
+	if (self == NULL)
+		return NULL;
+	Tcl_IncrRefCount(arg);
+	self->value = arg;
+	return (PyObject*)self;
+}
+
+static void
+PyTclObject_dealloc(PyTclObject *self)
+{
+	Tcl_DecrRefCount(self->value);
+	PyObject_Del(self);
+}
+
+static PyObject *
+PyTclObject_str(PyTclObject *self)
+{
+	return PyString_FromString(Tcl_GetString(self->value));
+}
+
+static PyObject *
+PyTclObject_repr(PyTclObject *self)
+{
+	char buf[50];
+	PyOS_snprintf(buf, 50, "<%s object at 0x%.8x>",
+		      self->value->typePtr->name, (int)self->value);
+	return PyString_FromString(buf);
+}
+
+static PyObject*
+get_typename(PyTclObject* obj, void* ignored)
+{
+	return PyString_FromString(obj->value->typePtr->name);
+}
+
+static PyGetSetDef PyTclObject_getsetlist[] = {
+	{"typename", (getter)get_typename, NULL, "name of the Tcl type"},
+	{0},
+};
+
+statichere PyTypeObject PyTclObject_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,			/*ob_size*/
+	"_tkinter.Tcl_Obj",		/*tp_name*/
+	sizeof(PyTclObject),	/*tp_basicsize*/
+	0,			/*tp_itemsize*/
+	/* methods */
+	(destructor)PyTclObject_dealloc, /*tp_dealloc*/
+	0,			/*tp_print*/
+	0,			/*tp_getattr*/
+	0,			/*tp_setattr*/
+	0,			/*tp_compare*/
+	(reprfunc)PyTclObject_repr,	/*tp_repr*/
+	0,			/*tp_as_number*/
+	0,			/*tp_as_sequence*/
+	0,			/*tp_as_mapping*/
+	0,			/*tp_hash*/
+        0,                      /*tp_call*/
+        (reprfunc)PyTclObject_str,        /*tp_str*/
+        PyObject_GenericGetAttr,/*tp_getattro*/
+        0,                      /*tp_setattro*/
+        0,                      /*tp_as_buffer*/
+        Py_TPFLAGS_DEFAULT,     /*tp_flags*/
+        0,                      /*tp_doc*/
+        0,                      /*tp_traverse*/
+        0,                      /*tp_clear*/
+        0,                      /*tp_richcompare*/
+        0,                      /*tp_weaklistoffset*/
+        0,                      /*tp_iter*/
+        0,                      /*tp_iternext*/
+        0,                      /*tp_methods*/
+        0,			/*tp_members*/
+        PyTclObject_getsetlist, /*tp_getset*/
+        0,                      /*tp_base*/
+        0,                      /*tp_dict*/
+        0,                      /*tp_descr_get*/
+        0,                      /*tp_descr_set*/
+        0,                      /*tp_dictoffset*/
+        0,                      /*tp_init*/
+        0,                      /*tp_alloc*/
+        0,                      /*tp_new*/
+        0,                      /*tp_free*/
+        0,                      /*tp_is_gc*/
+};
+
 static Tcl_Obj*
 AsObj(PyObject *value)
 {
@@ -570,6 +734,11 @@
 
 	}
 #endif
+	else if(PyTclObject_Check(value)) {
+		Tcl_Obj *v = ((PyTclObject*)value)->value;
+		Tcl_IncrRefCount(v);
+		return v;
+	} 
 	else {
 		PyObject *v = PyObject_Str(value);
 		if (!v)
@@ -580,6 +749,99 @@
 	}
 }
 
+static PyObject*
+FromObj(PyObject* tkapp, Tcl_Obj *value)
+{
+	PyObject *result = NULL;
+
+	if (value->typePtr == NULL)
+		return PyString_FromStringAndSize(value->bytes, value->length);
+
+	if (value->typePtr == &tclBooleanType) {
+		result = value->internalRep.longValue ? Py_True : Py_False;
+		Py_INCREF(result);
+		return result;
+	}
+
+	if (value->typePtr == &tclByteArrayType) {
+		int size;
+		char *data = Tcl_GetByteArrayFromObj(value, &size);
+		return PyString_FromStringAndSize(data, size);
+	}
+
+	if (value->typePtr == &tclDoubleType) {
+		return PyFloat_FromDouble(value->internalRep.doubleValue);
+	}
+
+	if (value->typePtr == &tclIntType) {
+		return PyInt_FromLong(value->internalRep.longValue);
+	}
+
+	if (value->typePtr == &tclListType) {
+		int size;
+		int i, status;
+		PyObject *elem;
+		Tcl_Obj *tcl_elem;
+
+		status = Tcl_ListObjLength(Tkapp_Interp(tkapp), 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);
+			if (status == TCL_ERROR) {
+				Py_DECREF(result);
+				return Tkinter_Error(tkapp);
+			}
+			elem = FromObj(tkapp, tcl_elem);
+			if (!elem) {
+				Py_DECREF(result);
+				return NULL;
+			}
+			PyTuple_SetItem(result, i, elem);
+		}
+		return result;
+	}
+
+	if (value->typePtr == &tclProcBodyType) {
+		// fall through: return tcl object
+	}
+
+	if (value->typePtr == &tclStringType) {
+#ifdef Py_USING_UNICODE
+#ifdef Py_UNICODE_WIDE
+		PyObject *result;
+		int size;
+		Tcl_UniChar *input;
+		Py_UNICODE *output;
+
+		size = Tcl_GetCharLength(value);
+		result = PyUnicode_FromUnicode(NULL, size);
+		if (!result)
+			return NULL;
+		input = Tcl_GetUnicode(value);
+		output = PyUnicode_AS_UNICODE(result);
+		while (size--)
+			*output++ = *input++;
+		return result;
+#else
+		return PyUnicode_FromUnicode(Tcl_GetUnicode(value),
+					     Tcl_GetCharLength(value));
+#endif
+#else
+		int size;
+		char *c;
+		c = Tcl_GetStringFromObj(value, &size);
+		return PyString_FromStringAndSize(c, size);
+#endif
+	}
+
+	return newPyTclObject(value);
+}
+
 static PyObject *
 Tkapp_Call(PyObject *self, PyObject *args)
 {
@@ -639,9 +901,15 @@
 	ENTER_OVERLAP
 	if (i == TCL_ERROR)
 		Tkinter_Error(self);
-	else {
-		/* We could request the object result here, but doing
-		   so would confuse applications that expect a string. */
+	else if(((TkappObject*)self)->want_objects) {
+		Tcl_Obj *value = Tcl_GetObjResult(interp);
+		/* Not sure whether the IncrRef is necessary, but something
+		   may overwrite the interpreter result while we are
+		   converting it. */
+		Tcl_IncrRefCount(value);
+		res = FromObj(self, value);
+		Tcl_DecrRefCount(value);
+	} else {
 		const char *s = Tcl_GetStringResult(interp);
 		const char *p = s;
 
@@ -964,6 +1232,13 @@
 	char *s;
 	int v;
 
+	if (PyTuple_Size(args) == 1) {
+		PyObject* o = PyTuple_GetItem(args, 0);
+		if (PyInt_Check(o)) {
+			Py_INCREF(o);
+			return o;
+		}
+	}
 	if (!PyArg_ParseTuple(args, "s:getint", &s))
 		return NULL;
 	if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
@@ -977,6 +1252,13 @@
 	char *s;
 	double v;
 
+	if (PyTuple_Size(args) == 1) {
+		PyObject *o = PyTuple_GetItem(args, 0);
+		if (PyFloat_Check(o)) {
+			Py_INCREF(o);
+			return o;
+		}
+	}
 	if (!PyArg_ParseTuple(args, "s:getdouble", &s))
 		return NULL;
 	if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
@@ -990,6 +1272,13 @@
 	char *s;
 	int v;
 
+	if (PyTuple_Size(args) == 1) {
+		PyObject *o = PyTuple_GetItem(args, 0);
+		if (PyInt_Check(o)) {
+			Py_INCREF(o);
+			return o;
+		}
+	}
 	if (!PyArg_ParseTuple(args, "s:getboolean", &s))
 		return NULL;
 	if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
@@ -1093,6 +1382,13 @@
 	PyObject *v;
 	int i;
 
+	if (PyTuple_Size(args) == 1) {
+		v = PyTuple_GetItem(args, 0);
+		if (PyTuple_Check(v)) {
+			Py_INCREF(v);
+			return v;
+		}
+	}
 	if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list))
 		return NULL;
 
@@ -1121,6 +1417,13 @@
 {
 	char *list;
 
+	if (PyTuple_Size(args) == 1) {
+		PyObject* o = PyTuple_GetItem(args, 0);
+		if (PyTuple_Check(o)) {
+			o = SplitObj(o);
+			return o;
+		}
+	}
 	if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list))
 		return NULL;
 	return Split(list);
@@ -1660,11 +1963,26 @@
 }
 
 
+static PyObject *
+Tkapp_WantObjects(PyObject *self, PyObject *args)
+{
+
+	int want_objects;
+	if (!PyArg_ParseTuple(args, "i:wantobjects", &want_objects))
+		return NULL;
+	((TkappObject*)self)->want_objects = want_objects;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
 
 /**** Tkapp Method List ****/
 
 static PyMethodDef Tkapp_methods[] =
 {
+	{"wantobjects",	       Tkapp_WantObjects, METH_VARARGS},
 	{"call", 	       Tkapp_Call, METH_OLDARGS},
 	{"globalcall", 	       Tkapp_GlobalCall, METH_OLDARGS},
 	{"eval", 	       Tkapp_Eval, METH_VARARGS},
@@ -1861,6 +2179,7 @@
 	char *baseName = NULL;
 	char *className = NULL;
 	int interactive = 0;
+	int want_objects = 0;
 
 	baseName = strrchr(Py_GetProgramName(), '/');
 	if (baseName != NULL)
@@ -1871,11 +2190,11 @@
   
 	if (!PyArg_ParseTuple(args, "|zssi:create",
 			      &screenName, &baseName, &className,
-			      &interactive))
+			      &interactive, &want_objects))
 		return NULL;
 
 	return (PyObject *) Tkapp_New(screenName, baseName, className, 
-				      interactive);
+				      interactive, want_objects);
 }
 
 static PyMethodDef moduleMethods[] =
@@ -2045,6 +2364,8 @@
 	Tktt_Type.ob_type = &PyType_Type;
 	PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
 
+	PyTclObject_Type.ob_type = &PyType_Type;
+	PyDict_SetItemString(d, "Tcl_Obj", (PyObject *)&PyTclObject_Type);
 
 #ifdef TK_AQUA
 	/* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems