diff -r b806e1370565 Modules/_tkinter.c --- a/Modules/_tkinter.c Sat Aug 18 12:32:45 2012 +0200 +++ b/Modules/_tkinter.c Sat Aug 18 12:40:08 2012 +0200 @@ -173,6 +173,57 @@ threads. So we use the Tcl TLS API. */ +typedef struct { + PyObject *Tkapp_Type; + PyObject *Tkinter_TclError; + PyObject *excInCmd; + PyObject *valInCmd; + PyObject *trbInCmd; + PyObject *PyTclObject_Type; + PyObject *Tktt_Type; +} _tkinterstate; + + +#define _tkinter_state(o) ((_tkinterstate *)PyModule_GetState(o)) + +static int +_tkinter_clear(PyObject *m) +{ + _tkinterstate *state = _tkinter_state(m); + Py_CLEAR(state->Tkapp_Type); + Py_CLEAR(state->Tkinter_TclError); + Py_CLEAR(state->excInCmd); + Py_CLEAR(state->valInCmd); + Py_CLEAR(state->trbInCmd); + Py_CLEAR(state->PyTclObject_Type); + Py_CLEAR(state->Tktt_Type); + return 0; +} + +static int +_tkinter_traverse(PyObject *m, visitproc visit, void *arg) +{ + _tkinterstate *state = _tkinter_state(m); + Py_VISIT(state->Tkapp_Type); + Py_VISIT(state->Tkinter_TclError); + Py_VISIT(state->excInCmd); + Py_VISIT(state->valInCmd); + Py_VISIT(state->trbInCmd); + Py_VISIT(state->PyTclObject_Type); + Py_VISIT(state->Tktt_Type); + return 0; +} + +static void +_tkinter_free(void *m) +{ + _tkinter_clear((PyObject *)m); +} + +static PyModuleDef _tkintermodule; + +#define _tkinterstate_global ((_tkinterstate *)PyModule_GetState(PyState_FindModule(&_tkintermodule))) + static PyThread_type_lock tcl_lock = 0; @@ -230,7 +281,6 @@ /**** Tkapp Object Declaration ****/ -static PyTypeObject Tkapp_Type; typedef struct { PyObject_HEAD @@ -250,7 +300,7 @@ Tcl_ObjType *StringType; } TkappObject; -#define Tkapp_Check(v) (Py_TYPE(v) == &Tkapp_Type) +#define Tkapp_Check(v) (Py_TYPE(v) == (PyTypeObject *)_tkinterstate_global->Tkapp_Type) #define Tkapp_Interp(v) (((TkappObject *) (v))->interp) #define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v)) @@ -261,12 +311,12 @@ /**** Error Handling ****/ -static PyObject *Tkinter_TclError; + static int quitMainLoop = 0; static int errorInCmd = 0; -static PyObject *excInCmd; -static PyObject *valInCmd; -static PyObject *trbInCmd; + + + #ifdef TKINTER_PROTECT_LOADTK static int tk_load_failed = 0; @@ -276,7 +326,7 @@ static PyObject * Tkinter_Error(PyObject *v) { - PyErr_SetString(Tkinter_TclError, Tkapp_Result(v)); + PyErr_SetString(_tkinterstate_global->Tkinter_TclError, Tkapp_Result(v)); return NULL; } @@ -416,7 +466,7 @@ } res = Tcl_Merge(argc, argv); if (res == NULL) - PyErr_SetString(Tkinter_TclError, "merge failed"); + PyErr_SetString(_tkinterstate_global->Tkinter_TclError, "merge failed"); finally: for (i = 0; i < fvc; i++) @@ -594,9 +644,11 @@ TkappObject *v; char *argv0; - v = PyObject_New(TkappObject, &Tkapp_Type); + v = PyObject_New(TkappObject, + (PyTypeObject *)_tkinterstate_global->Tkapp_Type); if (v == NULL) return NULL; + Py_INCREF(_tkinterstate_global->Tkapp_Type); v->interp = Tcl_CreateInterp(); v->wantobjects = wantobjects; @@ -744,16 +796,17 @@ PyObject *string; /* This cannot cause cycles. */ } PyTclObject; -static PyTypeObject PyTclObject_Type; -#define PyTclObject_Check(v) ((v)->ob_type == &PyTclObject_Type) +#define PyTclObject_Check(v) ((v)->ob_type == (PyTypeObject *)_tkinterstate_global->PyTclObject_Type) static PyObject * newPyTclObject(Tcl_Obj *arg) { PyTclObject *self; - self = PyObject_New(PyTclObject, &PyTclObject_Type); + self = PyObject_New(PyTclObject, + (PyTypeObject *)_tkinterstate_global->PyTclObject_Type); if (self == NULL) return NULL; + Py_INCREF(_tkinterstate_global->PyTclObject_Type); Tcl_IncrRefCount(arg); self->value = arg; self->string = NULL; @@ -763,8 +816,12 @@ static void PyTclObject_dealloc(PyTclObject *self) { + PyTypeObject *type = Py_TYPE(self); Tcl_DecrRefCount(self->value); Py_XDECREF(self->string); + if((void *)type->tp_dealloc == (void *)PyTclObject_dealloc) { + Py_DECREF(type); + } PyObject_Del(self); } @@ -885,50 +942,25 @@ {0}, }; -static PyTypeObject PyTclObject_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_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_reserved*/ - (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*/ - PyTclObject_richcompare, /*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 PyType_Slot PyTclObject_Type_slots[] = { + {Py_tp_dealloc, (destructor)PyTclObject_dealloc}, + {Py_tp_repr, (reprfunc)PyTclObject_repr}, + {Py_tp_str, (reprfunc)PyTclObject_str}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_richcompare, PyTclObject_richcompare}, + {Py_tp_getset, PyTclObject_getsetlist}, + {0, 0} }; +static PyType_Spec PyTclObject_Type_spec = { + "_tkinter.Tcl_Obj", + sizeof(PyTclObject), + 0, + Py_TPFLAGS_DEFAULT, + PyTclObject_Type_slots, +}; + + static Tcl_Obj* AsObj(PyObject *value) { @@ -1228,7 +1260,7 @@ *(e->exc_type) = NULL; *(e->exc_tb) = NULL; *(e->exc_value) = PyObject_CallFunction( - Tkinter_TclError, "s", + _tkinterstate_global->Tkinter_TclError, "s", Tcl_GetStringResult(e->self->interp)); } else { @@ -1300,7 +1332,7 @@ if (exc_type) PyErr_Restore(exc_type, exc_value, exc_tb); else - PyErr_SetObject(Tkinter_TclError, exc_value); + PyErr_SetObject(_tkinterstate_global->Tkinter_TclError, exc_value); } Tcl_ConditionFinalize(&cond); } @@ -1677,7 +1709,7 @@ tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags); ENTER_OVERLAP if (tres == NULL) { - PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); + PyErr_SetString(_tkinterstate_global->Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); } else { if (((TkappObject*)self)->wantobjects) { res = FromObj(self, tres); @@ -1996,7 +2028,9 @@ PythonCmd_Error(Tcl_Interp *interp) { errorInCmd = 1; - PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + PyErr_Fetch(&_tkinterstate_global->excInCmd, + &_tkinterstate_global->valInCmd, + &_tkinterstate_global->trbInCmd); LEAVE_PYTHON return TCL_ERROR; } @@ -2162,7 +2196,7 @@ LEAVE_TCL } if (err) { - PyErr_SetString(Tkinter_TclError, "can't create Tcl command"); + PyErr_SetString(_tkinterstate_global->Tkinter_TclError, "can't create Tcl command"); PyMem_DEL(data); return NULL; } @@ -2206,7 +2240,7 @@ LEAVE_TCL } if (err == -1) { - PyErr_SetString(Tkinter_TclError, "can't delete Tcl command"); + PyErr_SetString(_tkinterstate_global->Tkinter_TclError, "can't delete Tcl command"); return NULL; } Py_INCREF(Py_None); @@ -2278,7 +2312,9 @@ if (res == NULL) { errorInCmd = 1; - PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + PyErr_Fetch(&_tkinterstate_global->excInCmd, + &_tkinterstate_global->valInCmd, + &_tkinterstate_global->trbInCmd); } Py_XDECREF(res); LEAVE_PYTHON @@ -2347,8 +2383,6 @@ /**** Tktt Object (timer token) ****/ -static PyTypeObject Tktt_Type; - typedef struct { PyObject_HEAD Tcl_TimerToken token; @@ -2387,10 +2421,12 @@ { TkttObject *v; - v = PyObject_New(TkttObject, &Tktt_Type); + v = PyObject_New(TkttObject, + (PyTypeObject *)_tkinterstate_global->Tktt_Type); if (v == NULL) return NULL; + Py_INCREF(_tkinterstate_global->Tktt_Type); Py_INCREF(func); v->token = NULL; v->func = func; @@ -2403,11 +2439,15 @@ static void Tktt_Dealloc(PyObject *self) { + PyTypeObject *type = Py_TYPE(self); TkttObject *v = (TkttObject *)self; PyObject *func = v->func; Py_XDECREF(func); + if((void *)type->tp_dealloc == (void *)Tktt_Dealloc) { + Py_DECREF(type); + } PyObject_Del(self); } @@ -2420,38 +2460,25 @@ v->func == NULL ? ", handler deleted" : ""); } -static PyTypeObject Tktt_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "tktimertoken", /*tp_name */ - sizeof(TkttObject), /*tp_basicsize */ - 0, /*tp_itemsize */ - Tktt_Dealloc, /*tp_dealloc */ - 0, /*tp_print */ - 0, /*tp_getattr */ - 0, /*tp_setattr */ - 0, /*tp_reserved */ - Tktt_Repr, /*tp_repr */ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*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*/ - Tktt_methods, /*tp_methods*/ + + + +static PyType_Slot Tktt_Type_slots[] = { + {Py_tp_dealloc, Tktt_Dealloc}, + {Py_tp_repr, Tktt_Repr}, + {Py_tp_methods, Tktt_methods}, + {0, 0} }; +static PyType_Spec Tktt_Type_spec = { + "tktimertoken", + sizeof(TkttObject), + 0, + Py_TPFLAGS_DEFAULT, + Tktt_Type_slots, +}; + + /** Timer Handler **/ @@ -2476,7 +2503,9 @@ if (res == NULL) { errorInCmd = 1; - PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + PyErr_Fetch(&_tkinterstate_global->excInCmd, + &_tkinterstate_global->valInCmd, + &_tkinterstate_global->trbInCmd); } else Py_DECREF(res); @@ -2569,8 +2598,12 @@ if (errorInCmd) { errorInCmd = 0; - PyErr_Restore(excInCmd, valInCmd, trbInCmd); - excInCmd = valInCmd = trbInCmd = NULL; + PyErr_Restore(_tkinterstate_global->excInCmd, + _tkinterstate_global->valInCmd, + _tkinterstate_global->trbInCmd); + _tkinterstate_global->excInCmd = + _tkinterstate_global->valInCmd = + _tkinterstate_global->trbInCmd = NULL; return NULL; } Py_INCREF(Py_None); @@ -2628,7 +2661,7 @@ * a static variable. */ if (tk_load_failed) { - PyErr_SetString(Tkinter_TclError, TKINTER_LOADTK_ERRMSG); + PyErr_SetString(_tkinterstate_global->Tkinter_TclError, TKINTER_LOADTK_ERRMSG); return NULL; } #endif @@ -2651,7 +2684,7 @@ } if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) { if (Tk_Init(interp) == TCL_ERROR) { - PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); + PyErr_SetString(_tkinterstate_global->Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); #ifdef TKINTER_PROTECT_LOADTK tk_load_failed = 1; #endif @@ -2739,47 +2772,31 @@ static void Tkapp_Dealloc(PyObject *self) { + PyTypeObject *type = Py_TYPE(self); /*CHECK_TCL_APPARTMENT;*/ ENTER_TCL Tcl_DeleteInterp(Tkapp_Interp(self)); LEAVE_TCL PyObject_Del(self); DisableEventHook(); + if((void *)type->tp_dealloc == (void *)Tkapp_Dealloc) { + Py_DECREF(type); + } } -static PyTypeObject Tkapp_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "tkapp", /*tp_name */ - sizeof(TkappObject), /*tp_basicsize */ - 0, /*tp_itemsize */ - Tkapp_Dealloc, /*tp_dealloc */ - 0, /*tp_print */ - 0, /*tp_getattr */ - 0, /*tp_setattr */ - 0, /*tp_reserved */ - 0, /*tp_repr */ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*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*/ - Tkapp_methods, /*tp_methods*/ +static PyType_Slot Tkapp_Type_slots[] = { + {Py_tp_dealloc, Tkapp_Dealloc}, + {Py_tp_methods, Tkapp_methods}, + {0, 0} }; - +static PyType_Spec Tkapp_Type_spec = { + "tkapp", + sizeof(TkappObject), + 0, + Py_TPFLAGS_DEFAULT, + Tkapp_Type_slots, +}; /**** Tkinter Module ****/ @@ -3030,8 +3047,12 @@ #endif if (errorInCmd) { errorInCmd = 0; - PyErr_Restore(excInCmd, valInCmd, trbInCmd); - excInCmd = valInCmd = trbInCmd = NULL; + PyErr_Restore(_tkinterstate_global->excInCmd, + _tkinterstate_global->valInCmd, + _tkinterstate_global->trbInCmd); + _tkinterstate_global->excInCmd = + _tkinterstate_global->valInCmd = + _tkinterstate_global->trbInCmd = NULL; PyErr_Print(); } #ifdef WITH_THREAD @@ -3091,33 +3112,37 @@ PyModuleDef_HEAD_INIT, "_tkinter", NULL, - -1, + sizeof(_tkinterstate), moduleMethods, NULL, - NULL, - NULL, - NULL + _tkinter_traverse, + _tkinter_clear, + _tkinter_free }; PyMODINIT_FUNC PyInit__tkinter(void) { PyObject *m, *d, *uexe, *cexe; - - if (PyType_Ready(&Tkapp_Type) < 0) + _tkinterstate *state; + + m = PyModule_Create(&_tkintermodule); + if (m == NULL) + return NULL; + + state = _tkinter_state(m); + + state->Tkapp_Type = PyType_FromSpec(&Tkapp_Type_spec); + if (state->Tkapp_Type == NULL) return NULL; #ifdef WITH_THREAD tcl_lock = PyThread_allocate_lock(); #endif - m = PyModule_Create(&_tkintermodule); - if (m == NULL) - return NULL; - d = PyModule_GetDict(m); - Tkinter_TclError = PyErr_NewException("_tkinter.TclError", NULL, NULL); - PyDict_SetItemString(d, "TclError", Tkinter_TclError); + state->Tkinter_TclError = PyErr_NewException("_tkinter.TclError", NULL, NULL); + PyDict_SetItemString(d, "TclError", state->Tkinter_TclError); ins_long(d, "READABLE", TCL_READABLE); ins_long(d, "WRITABLE", TCL_WRITABLE); @@ -3131,16 +3156,20 @@ ins_string(d, "TK_VERSION", TK_VERSION); ins_string(d, "TCL_VERSION", TCL_VERSION); - PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type); - - if (PyType_Ready(&Tktt_Type) < 0) { + PyDict_SetItemString(d, "TkappType", state->Tkapp_Type); + + state->Tktt_Type = PyType_FromSpec(&Tktt_Type_spec); + if (state->Tktt_Type == NULL) { Py_DECREF(m); return NULL; } - PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type); - - Py_TYPE(&PyTclObject_Type) = &PyType_Type; - PyDict_SetItemString(d, "Tcl_Obj", (PyObject *)&PyTclObject_Type); + PyDict_SetItemString(d, "TkttType", state->Tktt_Type); + + state->PyTclObject_Type = + PyType_FromSpec(&PyTclObject_Type_spec); + if(state->PyTclObject_Type == NULL) + return NULL; + PyDict_SetItemString(d, "Tcl_Obj", state->PyTclObject_Type); #ifdef TK_AQUA /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems