@@ -33,6 +33,8 @@ Copyright (C) 1994 Steen Lumholt.
3333#include <windows.h>
3434#endif
3535
36+ #include "tkinter.h"
37+
3638/* Allow using this code in Python 2.[12] */
3739#ifndef PyDoc_STRVAR
3840#define PyDoc_STRVAR (name ,str ) static char name[] = str
@@ -74,9 +76,7 @@ Copyright (C) 1994 Steen Lumholt.
7476#define CONST
7577#endif
7678
77- #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION)
78-
79- #if TKMAJORMINOR < 8002
79+ #if TK_VERSION_HEX < 0x08020002
8080#error "Tk older than 8.2 not supported"
8181#endif
8282
@@ -280,6 +280,9 @@ static PyObject *excInCmd;
280280static PyObject * valInCmd ;
281281static PyObject * trbInCmd ;
282282
283+ #ifdef TKINTER_PROTECT_LOADTK
284+ static int tk_load_failed ;
285+ #endif
283286
284287
285288static PyObject *
@@ -553,21 +556,35 @@ SplitObj(PyObject *arg)
553556int
554557Tcl_AppInit (Tcl_Interp * interp )
555558{
556- Tk_Window main ;
557559 const char * _tkinter_skip_tk_init ;
558560
559561 if (Tcl_Init (interp ) == TCL_ERROR ) {
560562 PySys_WriteStderr ("Tcl_Init error: %s\n" , Tcl_GetStringResult (interp ));
561563 return TCL_ERROR ;
562564 }
563- _tkinter_skip_tk_init = Tcl_GetVar (interp , "_tkinter_skip_tk_init" , TCL_GLOBAL_ONLY );
564- if (_tkinter_skip_tk_init == NULL || strcmp (_tkinter_skip_tk_init , "1" ) != 0 ) {
565- main = Tk_MainWindow (interp );
566- if (Tk_Init (interp ) == TCL_ERROR ) {
567- PySys_WriteStderr ("Tk_Init error: %s\n" , Tcl_GetStringResult (interp ));
568- return TCL_ERROR ;
569- }
565+
566+ _tkinter_skip_tk_init = Tcl_GetVar (interp ,
567+ "_tkinter_skip_tk_init" , TCL_GLOBAL_ONLY );
568+ if (_tkinter_skip_tk_init != NULL &&
569+ strcmp (_tkinter_skip_tk_init , "1" ) == 0 ) {
570+ return TCL_OK ;
571+ }
572+
573+ #ifdef TKINTER_PROTECT_LOADTK
574+ if (tk_load_failed ) {
575+ PySys_WriteStderr ("Tk_Init error: %s\n" , TKINTER_LOADTK_ERRMSG );
576+ return TCL_ERROR ;
570577 }
578+ #endif
579+
580+ if (Tk_Init (interp ) == TCL_ERROR ) {
581+ #ifdef TKINTER_PROTECT_LOADTK
582+ tk_load_failed = 1 ;
583+ #endif
584+ PySys_WriteStderr ("Tk_Init error: %s\n" , Tcl_GetStringResult (interp ));
585+ return TCL_ERROR ;
586+ }
587+
571588 return TCL_OK ;
572589}
573590#endif /* !WITH_APPINIT */
@@ -650,8 +667,15 @@ Tkapp_New(char *screenName, char *className,
650667 ckfree (argv0 );
651668
652669 if (! wantTk ) {
653- Tcl_SetVar (v -> interp , "_tkinter_skip_tk_init" , "1" , TCL_GLOBAL_ONLY );
670+ Tcl_SetVar (v -> interp ,
671+ "_tkinter_skip_tk_init" , "1" , TCL_GLOBAL_ONLY );
672+ }
673+ #ifdef TKINTER_PROTECT_LOADTK
674+ else if (tk_load_failed ) {
675+ Tcl_SetVar (v -> interp ,
676+ "_tkinter_tk_failed" , "1" , TCL_GLOBAL_ONLY );
654677 }
678+ #endif
655679
656680 /* some initial arguments need to be in argv */
657681 if (sync || use ) {
@@ -686,6 +710,18 @@ Tkapp_New(char *screenName, char *className,
686710
687711 if (Tcl_AppInit (v -> interp ) != TCL_OK ) {
688712 PyObject * result = Tkinter_Error ((PyObject * )v );
713+ #ifdef TKINTER_PROTECT_LOADTK
714+ if (wantTk ) {
715+ const char * _tkinter_tk_failed ;
716+ _tkinter_tk_failed = Tcl_GetVar (v -> interp ,
717+ "_tkinter_tk_failed" , TCL_GLOBAL_ONLY );
718+
719+ if ( _tkinter_tk_failed != NULL &&
720+ strcmp (_tkinter_tk_failed , "1" ) == 0 ) {
721+ tk_load_failed = 1 ;
722+ }
723+ }
724+ #endif
689725 Py_DECREF ((PyObject * )v );
690726 return (TkappObject * )result ;
691727 }
@@ -2547,22 +2583,21 @@ Tkapp_InterpAddr(PyObject *self, PyObject *args)
25472583static PyObject *
25482584Tkapp_TkInit (PyObject * self , PyObject * args )
25492585{
2550- static int has_failed ;
25512586 Tcl_Interp * interp = Tkapp_Interp (self );
2552- Tk_Window main_window ;
25532587 const char * _tk_exists = NULL ;
25542588 int err ;
2555- main_window = Tk_MainWindow ( interp );
2556-
2557- /* In all current versions of Tk (including 8.4.13) , Tk_Init
2558- deadlocks on the second call when the first call failed.
2559- To avoid the deadlock, we just refuse the second call through
2560- a static variable. */
2561- if ( has_failed ) {
2562- PyErr_SetString ( Tkinter_TclError ,
2563- "Calling Tk_Init again after a previous call failed might deadlock" );
2589+
2590+ #ifdef TKINTER_PROTECT_LOADTK
2591+ /* Up to Tk 8.4.13, Tk_Init deadlocks on the second call when the
2592+ * first call failed.
2593+ * To avoid the deadlock, we just refuse the second call through
2594+ * a static variable.
2595+ */
2596+ if ( tk_load_failed ) {
2597+ PyErr_SetString ( Tkinter_TclError , TKINTER_LOADTK_ERRMSG );
25642598 return NULL ;
25652599 }
2600+ #endif
25662601
25672602 /* We want to guard against calling Tk_Init() multiple times */
25682603 CHECK_TCL_APPARTMENT ;
@@ -2582,8 +2617,10 @@ Tkapp_TkInit(PyObject *self, PyObject *args)
25822617 }
25832618 if (_tk_exists == NULL || strcmp (_tk_exists , "1" ) != 0 ) {
25842619 if (Tk_Init (interp ) == TCL_ERROR ) {
2585- PyErr_SetString (Tkinter_TclError , Tcl_GetStringResult (Tkapp_Interp (self )));
2586- has_failed = 1 ;
2620+ PyErr_SetString (Tkinter_TclError , Tcl_GetStringResult (Tkapp_Interp (self )));
2621+ #ifdef TKINTER_PROTECT_LOADTK
2622+ tk_load_failed = 1 ;
2623+ #endif
25872624 return NULL ;
25882625 }
25892626 }
0 commit comments