[Python-checkins] python/dist/src/Modules _tkinter.c,1.130,1.131

loewis@users.sourceforge.net loewis@users.sourceforge.net
Tue, 26 Nov 2002 01:28:07 -0800


Update of /cvsroot/python/python/dist/src/Modules
In directory sc8-pr-cvs1:/tmp/cvs-serv30260/Modules

Modified Files:
	_tkinter.c 
Log Message:
Patch #518625: Return objects in Tkinter.


Index: _tkinter.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/_tkinter.c,v
retrieving revision 1.130
retrieving revision 1.131
diff -C2 -d -r1.130 -r1.131
*** _tkinter.c	1 Oct 2002 18:50:56 -0000	1.130
--- _tkinter.c	26 Nov 2002 09:28:05 -0000	1.131
***************
*** 51,57 ****
--- 51,59 ----
  #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
***************
*** 220,223 ****
--- 222,226 ----
  	PyObject_HEAD
  	Tcl_Interp *interp;
+ 	int want_objects;
  } TkappObject;
  
***************
*** 425,428 ****
--- 428,492 ----
  }
  
+ /* 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;
+ }
  
  
***************
*** 459,463 ****
  
  static TkappObject *
! Tkapp_New(char *screenName, char *baseName, char *className, int interactive)
  {
  	TkappObject *v;
--- 523,528 ----
  
  static TkappObject *
! Tkapp_New(char *screenName, char *baseName, char *className, 
! 	  int interactive, int want_objects)
  {
  	TkappObject *v;
***************
*** 469,472 ****
--- 534,538 ----
  
  	v->interp = Tcl_CreateInterp();
+ 	v->want_objects = want_objects;
  
  #if defined(macintosh)
***************
*** 514,517 ****
--- 580,681 ----
  /** 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)
***************
*** 571,574 ****
--- 735,743 ----
  	}
  #endif
+ 	else if(PyTclObject_Check(value)) {
+ 		Tcl_Obj *v = ((PyTclObject*)value)->value;
+ 		Tcl_IncrRefCount(v);
+ 		return v;
+ 	} 
  	else {
  		PyObject *v = PyObject_Str(value);
***************
*** 581,584 ****
--- 750,846 ----
  }
  
+ 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)
***************
*** 640,646 ****
  	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. */
  		const char *s = Tcl_GetStringResult(interp);
  		const char *p = s;
--- 902,914 ----
  	if (i == TCL_ERROR)
  		Tkinter_Error(self);
! 	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;
***************
*** 965,968 ****
--- 1233,1243 ----
  	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;
***************
*** 978,981 ****
--- 1253,1263 ----
  	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;
***************
*** 991,994 ****
--- 1273,1283 ----
  	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;
***************
*** 1094,1097 ****
--- 1383,1393 ----
  	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;
***************
*** 1122,1125 ****
--- 1418,1428 ----
  	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;
***************
*** 1661,1664 ****
--- 1964,1981 ----
  
  
+ 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 ****/
***************
*** 1666,1669 ****
--- 1983,1987 ----
  static PyMethodDef Tkapp_methods[] =
  {
+ 	{"wantobjects",	       Tkapp_WantObjects, METH_VARARGS},
  	{"call", 	       Tkapp_Call, METH_OLDARGS},
  	{"globalcall", 	       Tkapp_GlobalCall, METH_OLDARGS},
***************
*** 1862,1865 ****
--- 2180,2184 ----
  	char *className = NULL;
  	int interactive = 0;
+ 	int want_objects = 0;
  
  	baseName = strrchr(Py_GetProgramName(), '/');
***************
*** 1872,1880 ****
  	if (!PyArg_ParseTuple(args, "|zssi:create",
  			      &screenName, &baseName, &className,
! 			      &interactive))
  		return NULL;
  
  	return (PyObject *) Tkapp_New(screenName, baseName, className, 
! 				      interactive);
  }
  
--- 2191,2199 ----
  	if (!PyArg_ParseTuple(args, "|zssi:create",
  			      &screenName, &baseName, &className,
! 			      &interactive, &want_objects))
  		return NULL;
  
  	return (PyObject *) Tkapp_New(screenName, baseName, className, 
! 				      interactive, want_objects);
  }
  
***************
*** 2046,2049 ****
--- 2365,2370 ----
  	PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
  
+ 	PyTclObject_Type.ob_type = &PyType_Type;
+ 	PyDict_SetItemString(d, "Tcl_Obj", (PyObject *)&PyTclObject_Type);
  
  #ifdef TK_AQUA