diff options
Diffstat (limited to 'Modules/_tkinter.c')
-rw-r--r-- | Modules/_tkinter.c | 333 |
1 files changed, 327 insertions, 6 deletions
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 @@ Copyright (C) 1994 Steen Lumholt. #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 @@ static PyTypeObject Tkapp_Type; typedef struct { PyObject_HEAD Tcl_Interp *interp; + int want_objects; } TkappObject; #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type) @@ -424,6 +427,67 @@ Split(char *list) 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 EnableEventHook(void); /* Forward */ 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 @@ Tkapp_New(char *screenName, char *baseName, char *className, int interactive) return NULL; v->interp = Tcl_CreateInterp(); + v->want_objects = want_objects; #if defined(macintosh) /* This seems to be needed */ @@ -513,6 +579,104 @@ Tkapp_New(char *screenName, char *baseName, char *className, int interactive) /** 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 @@ AsObj(PyObject *value) } #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 @@ AsObj(PyObject *value) } } +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 @@ Tkapp_Call(PyObject *self, PyObject *args) 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 @@ Tkapp_GetInt(PyObject *self, PyObject *args) 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 @@ Tkapp_GetDouble(PyObject *self, PyObject *args) 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 @@ Tkapp_GetBoolean(PyObject *self, PyObject *args) 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 @@ Tkapp_SplitList(PyObject *self, PyObject *args) 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 @@ Tkapp_Split(PyObject *self, PyObject *args) { 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 @@ Tkapp_InterpAddr(PyObject *self, PyObject *args) } +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 @@ Tkinter_Create(PyObject *self, PyObject *args) char *baseName = NULL; char *className = NULL; int interactive = 0; + int want_objects = 0; baseName = strrchr(Py_GetProgramName(), '/'); if (baseName != NULL) @@ -1871,11 +2190,11 @@ Tkinter_Create(PyObject *self, PyObject *args) 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 @@ init_tkinter(void) 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 |