Index: Modules/_tkinter.c =================================================================== --- Modules/_tkinter.c (revision 69260) +++ Modules/_tkinter.c (working copy) @@ -74,9 +74,13 @@ #define CONST #endif -#define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION) +#define TK_VERSION_HEX ((TK_MAJOR_VERSION << 24) | \ + (TK_MINOR_VERSION << 16) | \ + (TK_RELEASE_SERIAL << 8) | \ + (TK_RELEASE_LEVEL << 0)) -#if TKMAJORMINOR < 8002 + +#if TK_VERSION_HEX < 0x8020000 #error "Tk older than 8.2 not supported" #endif @@ -280,6 +284,9 @@ static PyObject *valInCmd; static PyObject *trbInCmd; +#if TK_VERSION_HEX < 0x8040e00 +static int tk_load_failed; +#endif static PyObject * @@ -555,21 +562,35 @@ int Tcl_AppInit(Tcl_Interp *interp) { - Tk_Window main; const char * _tkinter_skip_tk_init; if (Tcl_Init(interp) == TCL_ERROR) { PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp)); return TCL_ERROR; } - _tkinter_skip_tk_init = Tcl_GetVar(interp, "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY); - if (_tkinter_skip_tk_init == NULL || strcmp(_tkinter_skip_tk_init, "1") != 0) { - main = Tk_MainWindow(interp); - if (Tk_Init(interp) == TCL_ERROR) { - PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp)); - return TCL_ERROR; - } + + _tkinter_skip_tk_init = Tcl_GetVar(interp, + "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY); + if (_tkinter_skip_tk_init != NULL && + strcmp(_tkinter_skip_tk_init, "1") == 0) { + return TCL_OK; } + +#if TK_VERSION_HEX < 0x8040e00 + if (tk_load_failed) { + PySys_WriteStderr("Tk_Init error: %s\n", + "Calling Tk_Init again after a previous " + "call failed might deadlock"); + return TCL_ERROR; + } +#endif + + if (Tk_Init(interp) == TCL_ERROR) { + tk_load_failed = 1; + PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp)); + return TCL_ERROR; + } + return TCL_OK; } #endif /* !WITH_APPINIT */ @@ -652,8 +673,15 @@ ckfree(argv0); if (! wantTk) { - Tcl_SetVar(v->interp, "_tkinter_skip_tk_init", "1", TCL_GLOBAL_ONLY); + Tcl_SetVar(v->interp, + "_tkinter_skip_tk_init", "1", TCL_GLOBAL_ONLY); } +#if TK_VERSION_HEX < 0x8040e00 + else if (tk_load_failed) { + Tcl_SetVar(v->interp, + "_tkinter_tk_failed", "1", TCL_GLOBAL_ONLY); + } +#endif /* some initial arguments need to be in argv */ if (sync || use) { @@ -688,6 +716,18 @@ if (Tcl_AppInit(v->interp) != TCL_OK) { PyObject *result = Tkinter_Error((PyObject *)v); +#if TK_VERSION_HEX < 0x8040e00 + if (wantTk) { + const char *_tkinter_tk_failed; + _tkinter_tk_failed = Tcl_GetVar(v->interp, + "_tkinter_tk_failed", TCL_GLOBAL_ONLY); + + if ( _tkinter_tk_failed != NULL && + strcmp(_tkinter_tk_failed, "1") == 0) { + tk_load_failed = 1; + } + } +#endif Py_DECREF((PyObject *)v); return (TkappObject *)result; } @@ -2659,23 +2699,24 @@ static PyObject * Tkapp_TkInit(PyObject *self, PyObject *args) { - static int has_failed; Tcl_Interp *interp = Tkapp_Interp(self); - Tk_Window main_window; const char * _tk_exists = NULL; int err; - main_window = Tk_MainWindow(interp); - /* In all current versions of Tk (including 8.4.13), Tk_Init - deadlocks on the second call when the first call failed. - To avoid the deadlock, we just refuse the second call through - a static variable. */ - if (has_failed) { - PyErr_SetString(Tkinter_TclError, - "Calling Tk_Init again after a previous call failed might deadlock"); +#if TK_VERSION_HEX < 0x8040e00 + /* Up to Tk 8.4.13, Tk_Init deadlocks on the second call when the + * first call failed. + * To avoid the deadlock, we just refuse the second call through + * a static variable. + */ + if (tk_load_failed) { + PyErr_SetString(Tkinter_TclError, + "Calling Tk_Init again after a previous " + "call failed might deadlock"); return NULL; } - +#endif + /* We want to guard against calling Tk_Init() multiple times */ CHECK_TCL_APPARTMENT; ENTER_TCL @@ -2694,8 +2735,10 @@ } if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) { if (Tk_Init(interp) == TCL_ERROR) { - PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); - has_failed = 1; + PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); +#if TK_VERSION_HEX < 0x8040e00 + tk_load_failed = 1; +#endif return NULL; } } Index: Modules/tkappinit.c =================================================================== --- Modules/tkappinit.c (revision 69260) +++ Modules/tkappinit.c (working copy) @@ -16,11 +16,24 @@ #include #include +#define TK_VERSION_HEX ((TK_MAJOR_VERSION << 24) | \ + (TK_MINOR_VERSION << 16) | \ + (TK_RELEASE_SERIAL << 8) | \ + (TK_RELEASE_LEVEL << 0)) + +#if TK_VERSION_HEX < 0x8040e00 +/* See Tkapp_TkInit in _tkinter.c for the usage of tk_load_faile */ +static int tk_load_failed; +#endif + int Tcl_AppInit(Tcl_Interp *interp) { Tk_Window main_window; - const char * _tkinter_skip_tk_init; + const char *_tkinter_skip_tk_init; +#if TK_VERSION_HEX < 0x8040e00 + const char *_tkinter_tk_failed; +#endif #ifdef TK_AQUA #ifndef MAX_PATH_LEN @@ -74,13 +87,35 @@ /* Initialize modules that don't require Tk */ #endif - _tkinter_skip_tk_init = Tcl_GetVar(interp, "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY); - if (_tkinter_skip_tk_init != NULL && strcmp(_tkinter_skip_tk_init, "1") == 0) { + _tkinter_skip_tk_init = Tcl_GetVar(interp, + "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY); + if (_tkinter_skip_tk_init != NULL && + strcmp(_tkinter_skip_tk_init, "1") == 0) { return TCL_OK; } - if (Tk_Init(interp) == TCL_ERROR) + +#if TK_VERSION_HEX < 0x8040e00 + _tkinter_tk_failed = Tcl_GetVar(interp, + "_tkinter_tk_failed", TCL_GLOBAL_ONLY); + + if (tk_load_failed || ( + _tkinter_tk_failed != NULL && + strcmp(_tkinter_tk_failed, "1") == 0)) { + Tcl_SetResult(interp, + "Calling Tk_Init again after a previous " + "call failed might deadlock", TCL_STATIC); return TCL_ERROR; + } +#endif + if (Tk_Init(interp) == TCL_ERROR) { +#if TK_VERSION_HEX < 0x8040e00 + tk_load_failed = 1; + Tcl_SetVar(interp, "_tkinter_tk_failed", "1", TCL_GLOBAL_ONLY); +#endif + return TCL_ERROR; + } + main_window = Tk_MainWindow(interp); #ifdef TK_AQUA