/***********************************************************Copyright (C) 1994 Steen Lumholt. All Rights Reserved******************************************************************//* _tkinter.c -- Interface to libtk.a and libtcl.a. *//* TCL/TK VERSION INFO: Only Tcl/Tk 8.2 and later are supported. Older versions are not supported. (Use Python 2.2 if you cannot upgrade your Tcl/Tk libraries.)*//* XXX Further speed-up ideas, involving Tcl 8.0 features: - Register a new Tcl type, "Python callable", which can be called more efficiently and passed to Tcl_EvalObj() directly (if this is possible).*/#include "Python.h"#include <ctype.h>#ifdef WITH_THREAD#include "pythread.h"#endif#ifdef MS_WINDOWS#include <windows.h>#endif/* Allow using this code in Python 2.[12] */#ifndef PyDoc_STRVAR#define PyDoc_STRVAR(name,str) static char name[] = str#endif#ifndef PyMODINIT_FUNC#define PyMODINIT_FUNC void#endif#ifndef PyBool_Check#define PyBool_Check(o) 0#define PyBool_FromLong PyLong_FromLong#endif/* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately, making _tkinter correct for this API means to break earlier versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and earlier versions. Once Tcl releases before 8.4 don't need to be supported anymore, this should go. */#define USE_COMPAT_CONST/* If Tcl is compiled for threads, we must also define TCL_THREAD. We define it always; if Tcl is not threaded, the thread functions in Tcl are empty. */#define TCL_THREADS#ifdef TK_FRAMEWORK#include <Tcl/tcl.h>#include <Tk/tk.h>#else#include <tcl.h>#include <tk.h>#endif/* For Tcl 8.2 and 8.3, CONST* is not defined (except on Cygwin). */#ifndef CONST84_RETURN#define CONST84_RETURN#undef CONST#define CONST#endif#define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION)#if TKMAJORMINOR < 8002#error "Tk older than 8.2 not supported"#endif/* Unicode conversion assumes that Tcl_UniChar is two bytes. We cannot test this directly, so we test UTF-8 size instead, expecting that TCL_UTF_MAX is changed if Tcl ever supports either UTF-16 or UCS-4. Redhat 8 sets TCL_UTF_MAX to 6, and uses wchar_t for Tcl_Unichar. This is also ok as long as Python uses UCS-4, as well.*/#if TCL_UTF_MAX != 3 && !(defined(Py_UNICODE_WIDE) && TCL_UTF_MAX==6)#error "unsupported Tcl configuration"#endif#if !(defined(MS_WINDOWS) || defined(__CYGWIN__))#define HAVE_CREATEFILEHANDLER#endif#ifdef HAVE_CREATEFILEHANDLER/* This bit is to ensure that TCL_UNIX_FD is defined and doesn't interfere with the proper calculation of FHANDLETYPE == TCL_UNIX_FD below. */#ifndef TCL_UNIX_FD# ifdef TCL_WIN_SOCKET# define TCL_UNIX_FD (! TCL_WIN_SOCKET)# else# define TCL_UNIX_FD 1# endif#endif/* Tcl_CreateFileHandler() changed several times; these macros deal with the messiness. In Tcl 8.0 and later, it is not available on Windows (and on Unix, only because Jack added it back); when available on Windows, it only applies to sockets. */#ifdef MS_WINDOWS#define FHANDLETYPE TCL_WIN_SOCKET#else#define FHANDLETYPE TCL_UNIX_FD#endif/* If Tcl can wait for a Unix file descriptor, define the EventHook() routine which uses this to handle Tcl events while the user is typing commands. */#if FHANDLETYPE == TCL_UNIX_FD#define WAIT_FOR_STDIN#endif#endif /* HAVE_CREATEFILEHANDLER */#ifdef MS_WINDOWS#include <conio.h>#define WAIT_FOR_STDIN#endif#ifdef WITH_THREAD/* The threading situation is complicated. Tcl is not thread-safe, except when configured with --enable-threads. So we need to use a lock around all uses of Tcl. Previously, the Python interpreter lock was used for this. However, this causes problems when other Python threads need to run while Tcl is blocked waiting for events. To solve this problem, a separate lock for Tcl is introduced. Holding it is incompatible with holding Python's interpreter lock. The following four macros manipulate both locks together. ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made that could call an event handler, or otherwise affect the state of a Tcl interpreter. These assume that the surrounding code has the Python interpreter lock; inside the brackets, the Python interpreter lock has been released and the lock for Tcl has been acquired. Sometimes, it is necessary to have both the Python lock and the Tcl lock. (For example, when transferring data from the Tcl interpreter result to a Python string object.) This can be done by using different macros to close the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL releases the Tcl lock. By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event handlers when the handler needs to use Python. Such event handlers are entered while the lock for Tcl is held; the event handler presumably needs to use Python. ENTER_PYTHON releases the lock for Tcl and acquires the Python interpreter lock, restoring the appropriate thread state, and LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside the code between ENTER_PYTHON and LEAVE_PYTHON. These locks expand to several statements and brackets; they should not be used in branches of if statements and the like. If Tcl is threaded, this approach won't work anymore. The Tcl interpreter is only valid in the thread that created it, and all Tk activity must happen in this thread, also. That means that the mainloop must be invoked in the thread that created the interpreter. Invoking commands from other threads is possible; _tkinter will queue an event for the interpreter thread, which will then execute the command and pass back the result. If the main thread is not in the mainloop, and invoking commands causes an exception; if the main loop is running but not processing events, the command invocation will block. In addition, for a threaded Tcl, a single global tcl_tstate won't be sufficient anymore, since multiple Tcl interpreters may simultaneously dispatch in different threads. So we use the Tcl TLS API.*/staticPyThread_type_locktcl_lock=0;#ifdef TCL_THREADSstaticTcl_ThreadDataKeystate_key;typedefPyThreadState*ThreadSpecificData;#define tcl_tstate (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*)))#elsestaticPyThreadState*tcl_tstate=NULL;#endif#define ENTER_TCL \ { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \ if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;#define LEAVE_TCL \ tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}#define ENTER_OVERLAP \ Py_END_ALLOW_THREADS#define LEAVE_OVERLAP_TCL \ tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); }#define ENTER_PYTHON \ { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \ if(tcl_lock)PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }#define LEAVE_PYTHON \ { PyThreadState *tstate = PyEval_SaveThread(); \ if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }#define CHECK_TCL_APPARTMENT \ if (((TkappObject *)self)->threaded && \ ((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \ PyErr_SetString(PyExc_RuntimeError, "Calling Tcl from different appartment"); \ return 0; \ }#else#define ENTER_TCL#define LEAVE_TCL#define ENTER_OVERLAP#define LEAVE_OVERLAP_TCL#define ENTER_PYTHON#define LEAVE_PYTHON#define CHECK_TCL_APPARTMENT#endif#ifndef FREECAST#define FREECAST (char *)#endif/**** Tkapp Object Declaration ****/staticPyTypeObjectTkapp_Type;typedefstruct{PyObject_HEADTcl_Interp*interp;intwantobjects;intthreaded;/* True if tcl_platform[threaded] */Tcl_ThreadIdthread_id;intdispatching;/* We cannot include tclInt.h, as this is internal. So we cache interesting types here. */Tcl_ObjType*BooleanType;Tcl_ObjType*ByteArrayType;Tcl_ObjType*DoubleType;Tcl_ObjType*IntType;Tcl_ObjType*ListType;Tcl_ObjType*ProcBodyType;Tcl_ObjType*StringType;}TkappObject;#define Tkapp_Check(v) (Py_Type(v) == &Tkapp_Type)#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)#define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v))#define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \(void *) v, Py_Refcnt(v)))/**** Error Handling ****/staticPyObject*Tkinter_TclError;staticintquitMainLoop=0;staticinterrorInCmd=0;staticPyObject*excInCmd;staticPyObject*valInCmd;staticPyObject*trbInCmd;staticPyObject*Tkinter_Error(PyObject*v){PyErr_SetString(Tkinter_TclError,Tkapp_Result(v));returnNULL;}/**** Utils ****/staticintTkinter_busywaitinterval=20;#ifdef WITH_THREAD#ifndef MS_WINDOWS/* Millisecond sleep() for Unix platforms. */staticvoidSleep(intmilli){/* XXX Too bad if you don't have select(). */structtimevalt;t.tv_sec=milli/1000;t.tv_usec=(milli%1000)*1000;select(0,(fd_set*)0,(fd_set*)0,(fd_set*)0,&t);}#endif /* MS_WINDOWS *//* Wait up to 1s for the mainloop to come up. */staticintWaitForMainloop(TkappObject*self){inti;for(i=0;i<10;i++){if(self->dispatching)return1;Py_BEGIN_ALLOW_THREADSSleep(100);Py_END_ALLOW_THREADS}if(self->dispatching)return1;PyErr_SetString(PyExc_RuntimeError,"main thread is not in main loop");return0;}#endif /* WITH_THREAD */staticchar*AsString(PyObject*value,PyObject*tmp){if(PyString_Check(value))returnPyString_AsString(value);elseif(PyUnicode_Check(value)){PyObject*v=PyUnicode_AsUTF8String(value);if(v==NULL)returnNULL;if(PyList_Append(tmp,v)!=0){Py_DECREF(v);returnNULL;}Py_DECREF(v);returnPyString_AsString(v);}else{PyObject*v=PyObject_Str(value);if(v==NULL)returnNULL;if(PyList_Append(tmp,v)!=0){Py_DECREF(v);returnNULL;}Py_DECREF(v);returnPyString_AsString(v);}}#define ARGSZ 64staticchar*Merge(PyObject*args){PyObject*tmp=NULL;char*argvStore[ARGSZ];char**argv=NULL;intfvStore[ARGSZ];int*fv=NULL;intargc=0,fvc=0,i;char*res=NULL;if(!(tmp=PyList_New(0)))returnNULL;argv=argvStore;fv=fvStore;if(args==NULL)argc=0;elseif(!PyTuple_Check(args)){argc=1;fv[0]=0;if(!(argv[0]=AsString(args,tmp)))gotofinally;}else{argc=PyTuple_Size(args);if(argc>ARGSZ){argv=(char**)ckalloc(argc*sizeof(char*));fv=(int*)ckalloc(argc*sizeof(int));if(argv==NULL||fv==NULL){PyErr_NoMemory();gotofinally;}}for(i=0;i<argc;i++){PyObject*v=PyTuple_GetItem(args,i);if(PyTuple_Check(v)){fv[i]=1;if(!(argv[i]=Merge(v)))gotofinally;fvc++;}elseif(v==Py_None){argc=i;break;}else{fv[i]=0;if(!(argv[i]=AsString(v,tmp)))gotofinally;fvc++;}}}res=Tcl_Merge(argc,argv);if(res==NULL)PyErr_SetString(Tkinter_TclError,"merge failed");finally:for(i=0;i<fvc;i++)if(fv[i]){ckfree(argv[i]);}if(argv!=argvStore)ckfree(FREECASTargv);if(fv!=fvStore)ckfree(FREECASTfv);Py_DECREF(tmp);returnres;}staticPyObject*Split(char*list){intargc;char**argv;PyObject*v;if(list==NULL){Py_INCREF(Py_None);returnPy_None;}if(Tcl_SplitList((Tcl_Interp*)NULL,list,&argc,&argv)!=TCL_OK){/* Not a list. * Could be a quoted string containing funnies, e.g. {"}. * Return the string itself. */returnPyUnicode_FromString(list);}if(argc==0)v=PyUnicode_FromString("");elseif(argc==1)v=PyUnicode_FromString(argv[0]);elseif((v=PyTuple_New(argc))!=NULL){inti;PyObject*w;for(i=0;i<argc;i++){if((w=Split(argv[i]))==NULL){Py_DECREF(v);v=NULL;break;}PyTuple_SetItem(v,i,w);}}Tcl_Free(FREECASTargv);returnv;}/* 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)){inti,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);returnNULL;}if(!result){intk;if(newelem==elem){Py_DECREF(newelem);continue;}result=PyTuple_New(size);if(!result)returnNULL;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)returnresult;/* Fall through, returning arg. */}elseif(PyString_Check(arg)){intargc;char**argv;char*list=PyString_AsString(arg);if(Tcl_SplitList((Tcl_Interp*)NULL,list,&argc,&argv)!=TCL_OK){Py_INCREF(arg);returnarg;}Tcl_Free(FREECASTargv);if(argc>1)returnSplit(PyString_AsString(arg));/* Fall through, returning arg. */}Py_INCREF(arg);returnarg;}/**** Tkapp Object ****/#ifndef WITH_APPINITintTcl_AppInit(Tcl_Interp*interp){Tk_Windowmain;constchar*_tkinter_skip_tk_init;if(Tcl_Init(interp)==TCL_ERROR){PySys_WriteStderr("Tcl_Init error: %s\n",Tcl_GetStringResult(interp));returnTCL_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));returnTCL_ERROR;}}returnTCL_OK;}#endif /* !WITH_APPINIT *//* Initialize the Tk application; see the `main' function in * `tkMain.c'. */staticvoidEnableEventHook(void);/* Forward */staticvoidDisableEventHook(void);/* Forward */staticTkappObject*Tkapp_New(char*screenName,char*baseName,char*className,intinteractive,intwantobjects,intwantTk,intsync,char*use){TkappObject*v;char*argv0;v=PyObject_New(TkappObject,&Tkapp_Type);if(v==NULL)returnNULL;v->interp=Tcl_CreateInterp();v->wantobjects=wantobjects;v->threaded=Tcl_GetVar2Ex(v->interp,"tcl_platform","threaded",TCL_GLOBAL_ONLY)!=NULL;v->thread_id=Tcl_GetCurrentThread();v->dispatching=0;#ifndef TCL_THREADSif(v->threaded){PyErr_SetString(PyExc_RuntimeError,"Tcl is threaded but _tkinter is not");Py_DECREF(v);return0;}#endif#ifdef WITH_THREADif(v->threaded&&tcl_lock){/* If Tcl is threaded, we don't need the lock. */PyThread_free_lock(tcl_lock);tcl_lock=NULL;}#endifv->BooleanType=Tcl_GetObjType("boolean");v->ByteArrayType=Tcl_GetObjType("bytearray");v->DoubleType=Tcl_GetObjType("double");v->IntType=Tcl_GetObjType("int");v->ListType=Tcl_GetObjType("list");v->ProcBodyType=Tcl_GetObjType("procbody");v->StringType=Tcl_GetObjType("string");/* Delete the 'exit' command, which can screw things up */Tcl_DeleteCommand(v->interp,"exit");if(screenName!=NULL)Tcl_SetVar2(v->interp,"env","DISPLAY",screenName,TCL_GLOBAL_ONLY);if(interactive)Tcl_SetVar(v->interp,"tcl_interactive","1",TCL_GLOBAL_ONLY);elseTcl_SetVar(v->interp,"tcl_interactive","0",TCL_GLOBAL_ONLY);/* This is used to get the application class for Tk 4.1 and up */argv0=(char*)ckalloc(strlen(className)+1);if(!argv0){PyErr_NoMemory();Py_DECREF(v);returnNULL;}strcpy(argv0,className);if(isupper(Py_CHARMASK(argv0[0])))argv0[0]=tolower(Py_CHARMASK(argv0[0]));Tcl_SetVar(v->interp,"argv0",argv0,TCL_GLOBAL_ONLY);ckfree(argv0);if(!wantTk){Tcl_SetVar(v->interp,"_tkinter_skip_tk_init","1",TCL_GLOBAL_ONLY);}/* some initial arguments need to be in argv */if(sync||use){char*args;intlen=0;if(sync)len+=sizeof"-sync";if(use)len+=strlen(use)+sizeof"-use ";args=(char*)ckalloc(len);if(!args){PyErr_NoMemory();Py_DECREF(v);returnNULL;}args[0]='\0';if(sync)strcat(args,"-sync");if(use){if(sync)strcat(args," ");strcat(args,"-use ");strcat(args,use);}Tcl_SetVar(v->interp,"argv",args,TCL_GLOBAL_ONLY);ckfree(args);}if(Tcl_AppInit(v->interp)!=TCL_OK){PyObject*result=Tkinter_Error((PyObject*)v);Py_DECREF((PyObject*)v);return(TkappObject*)result;}EnableEventHook();returnv;}staticvoidTkapp_ThreadSend(TkappObject*self,Tcl_Event*ev,Tcl_Condition*cond,Tcl_Mutex*mutex){Py_BEGIN_ALLOW_THREADS;Tcl_MutexLock(mutex);Tcl_ThreadQueueEvent(self->thread_id,ev,TCL_QUEUE_TAIL);Tcl_ThreadAlert(self->thread_id);Tcl_ConditionWait(cond,mutex,NULL);Tcl_MutexUnlock(mutex);Py_END_ALLOW_THREADS}/** Tcl Eval **/typedefstruct{PyObject_HEADTcl_Obj*value;PyObject*string;/* This cannot cause cycles. */}PyTclObject;staticPyTypeObjectPyTclObject_Type;#define PyTclObject_Check(v) ((v)->ob_type == &PyTclObject_Type)staticPyObject*newPyTclObject(Tcl_Obj*arg){PyTclObject*self;self=PyObject_New(PyTclObject,&PyTclObject_Type);if(self==NULL)returnNULL;Tcl_IncrRefCount(arg);self->value=arg;self->string=NULL;return(PyObject*)self;}staticvoidPyTclObject_dealloc(PyTclObject*self){Tcl_DecrRefCount(self->value);Py_XDECREF(self->string);PyObject_Del(self);}staticchar*PyTclObject_TclString(PyObject*self){returnTcl_GetString(((PyTclObject*)self)->value);}/* Like _str, but create Unicode if necessary. */PyDoc_STRVAR(PyTclObject_string__doc__,"the string representation of this object, either as str or bytes");staticPyObject*PyTclObject_string(PyTclObject*self,void*ignored){char*s;intlen;if(!self->string){s=Tcl_GetStringFromObj(self->value,&len);self->string=PyUnicode_FromStringAndSize(s,len);if(!self->string)returnNULL;}Py_INCREF(self->string);returnself->string;}staticPyObject*PyTclObject_str(PyTclObject*self,void*ignored){char*s;intlen;if(self->string&&PyUnicode_Check(self->string)){Py_INCREF(self->string);returnself->string;}/* XXX Could chache result if it is non-ASCII. */s=Tcl_GetStringFromObj(self->value,&len);returnPyUnicode_DecodeUTF8(s,len,"strict");}staticPyObject*PyTclObject_repr(PyTclObject*self){returnPyUnicode_FromFormat("<%s object at %p>",self->value->typePtr->name,self->value);}staticintPyTclObject_cmp(PyTclObject*self,PyTclObject*other){intres;res=strcmp(Tcl_GetString(self->value),Tcl_GetString(other->value));if(res<0)return-1;if(res>0)return1;return0;}PyDoc_STRVAR(get_typename__doc__,"name of the Tcl type");staticPyObject*get_typename(PyTclObject*obj,void*ignored){returnPyUnicode_FromString(obj->value->typePtr->name);}staticPyGetSetDefPyTclObject_getsetlist[]={{"typename",(getter)get_typename,NULL,get_typename__doc__},{"string",(getter)PyTclObject_string,NULL,PyTclObject_string__doc__},{0},};staticPyTypeObjectPyTclObject_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*/(cmpfunc)PyTclObject_cmp,/*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*/};staticTcl_Obj*AsObj(PyObject*value){Tcl_Obj*result;longlongVal;intoverflow;if(PyString_Check(value))returnTcl_NewStringObj(PyString_AS_STRING(value),PyString_GET_SIZE(value));elseif(PyBool_Check(value))returnTcl_NewBooleanObj(PyObject_IsTrue(value));elseif(PyLong_CheckExact(value)&&((longVal=PyLong_AsLongAndOverflow(value,&overflow)),!overflow)){/* If there is an overflow in the long conversion, fall through to default object handling. */returnTcl_NewLongObj(longVal);}elseif(PyFloat_Check(value))returnTcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));elseif(PyTuple_Check(value)){Tcl_Obj**argv=(Tcl_Obj**)ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*));inti;if(!argv)return0;for(i=0;i<PyTuple_Size(value);i++)argv[i]=AsObj(PyTuple_GetItem(value,i));result=Tcl_NewListObj(PyTuple_Size(value),argv);ckfree(FREECASTargv);returnresult;}elseif(PyUnicode_Check(value)){Py_UNICODE*inbuf=PyUnicode_AS_UNICODE(value);Py_ssize_tsize=PyUnicode_GET_SIZE(value);/* This #ifdef assumes that Tcl uses UCS-2. See TCL_UTF_MAX test above. */#if defined(Py_UNICODE_WIDE) && TCL_UTF_MAX == 3Tcl_UniChar*outbuf;Py_ssize_ti;assert(size<size*sizeof(Tcl_UniChar));outbuf=(Tcl_UniChar*)ckalloc(size*sizeof(Tcl_UniChar));if(!outbuf){PyErr_NoMemory();returnNULL;}for(i=0;i<size;i++){if(inbuf[i]>=0x10000){/* Tcl doesn't do UTF-16, yet. */PyErr_SetString(PyExc_ValueError,"unsupported character");ckfree(FREECASToutbuf);returnNULL;}outbuf[i]=inbuf[i];}result=Tcl_NewUnicodeObj(outbuf,size);ckfree(FREECASToutbuf);returnresult;#elsereturnTcl_NewUnicodeObj(inbuf,size);#endif}elseif(PyTclObject_Check(value)){Tcl_Obj*v=((PyTclObject*)value)->value;Tcl_IncrRefCount(v);returnv;}else{PyObject*v=PyObject_Str(value);if(!v)return0;result=AsObj(v);Py_DECREF(v);returnresult;}}staticPyObject*FromObj(PyObject*tkapp,Tcl_Obj*value){PyObject*result=NULL;TkappObject*app=(TkappObject*)tkapp;if(value->typePtr==NULL){returnPyUnicode_FromStringAndSize(value->bytes,value->length);}if(value->typePtr==app->BooleanType){result=value->internalRep.longValue?Py_True:Py_False;Py_INCREF(result);returnresult;}if(value->typePtr==app->ByteArrayType){intsize;char*data=(char*)Tcl_GetByteArrayFromObj(value,&size);returnPyString_FromStringAndSize(data,size);}if(value->typePtr==app->DoubleType){returnPyFloat_FromDouble(value->internalRep.doubleValue);}if(value->typePtr==app->IntType){returnPyLong_FromLong(value->internalRep.longValue);}if(value->typePtr==app->ListType){intsize;inti,status;PyObject*elem;Tcl_Obj*tcl_elem;status=Tcl_ListObjLength(Tkapp_Interp(tkapp),value,&size);if(status==TCL_ERROR)returnTkinter_Error(tkapp);result=PyTuple_New(size);if(!result)returnNULL;for(i=0;i<size;i++){status=Tcl_ListObjIndex(Tkapp_Interp(tkapp),value,i,&tcl_elem);if(status==TCL_ERROR){Py_DECREF(result);returnTkinter_Error(tkapp);}elem=FromObj(tkapp,tcl_elem);if(!elem){Py_DECREF(result);returnNULL;}PyTuple_SetItem(result,i,elem);}returnresult;}if(value->typePtr==app->ProcBodyType){/* fall through: return tcl object. */}if(value->typePtr==app->StringType){#if defined(Py_UNICODE_WIDE) && TCL_UTF_MAX==3PyObject*result;intsize;Tcl_UniChar*input;Py_UNICODE*output;size=Tcl_GetCharLength(value);result=PyUnicode_FromUnicode(NULL,size);if(!result)returnNULL;input=Tcl_GetUnicode(value);output=PyUnicode_AS_UNICODE(result);while(size--)*output++=*input++;returnresult;#elsereturnPyUnicode_FromUnicode(Tcl_GetUnicode(value),Tcl_GetCharLength(value));#endif}returnnewPyTclObject(value);}/* This mutex synchronizes inter-thread command calls. */TCL_DECLARE_MUTEX(call_mutex)typedefstructTkapp_CallEvent{Tcl_Eventev;/* Must be first */TkappObject*self;PyObject*args;intflags;PyObject**res;PyObject**exc_type,**exc_value,**exc_tb;Tcl_Conditiondone;}Tkapp_CallEvent;voidTkapp_CallDeallocArgs(Tcl_Obj**objv,Tcl_Obj**objStore,intobjc){inti;for(i=0;i<objc;i++)Tcl_DecrRefCount(objv[i]);if(objv!=objStore)ckfree(FREECASTobjv);}/* Convert Python objects to Tcl objects. This must happen in the interpreter thread, which may or may not be the calling thread. */staticTcl_Obj**Tkapp_CallArgs(PyObject*args,Tcl_Obj**objStore,int*pobjc){Tcl_Obj**objv=objStore;intobjc=0,i;if(args==NULL)/* do nothing */;elseif(!PyTuple_Check(args)){objv[0]=AsObj(args);if(objv[0]==0)gotofinally;objc=1;Tcl_IncrRefCount(objv[0]);}else{objc=PyTuple_Size(args);if(objc>ARGSZ){objv=(Tcl_Obj**)ckalloc(objc*sizeof(char*));if(objv==NULL){PyErr_NoMemory();objc=0;gotofinally;}}for(i=0;i<objc;i++){PyObject*v=PyTuple_GetItem(args,i);if(v==Py_None){objc=i;break;}objv[i]=AsObj(v);if(!objv[i]){/* Reset objc, so it attempts to clear objects only up to i. */objc=i;gotofinally;}Tcl_IncrRefCount(objv[i]);}}*pobjc=objc;returnobjv;finally:Tkapp_CallDeallocArgs(objv,objStore,objc);returnNULL;}/* Convert the results of a command call into a Python objects. */staticPyObject*Tkapp_CallResult(TkappObject*self){PyObject*res=NULL;if(self->wantobjects){Tcl_Obj*value=Tcl_GetObjResult(self->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((PyObject*)self,value);Tcl_DecrRefCount(value);}else{constchar*s=Tcl_GetStringResult(self->interp);constchar*p=s;res=PyUnicode_FromStringAndSize(s,(int)(p-s));}returnres;}/* Tkapp_CallProc is the event procedure that is executed in the context of the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't hold the Python lock. */staticintTkapp_CallProc(Tkapp_CallEvent*e,intflags){Tcl_Obj*objStore[ARGSZ];Tcl_Obj**objv;intobjc;inti;ENTER_PYTHONobjv=Tkapp_CallArgs(e->args,objStore,&objc);if(!objv){PyErr_Fetch(e->exc_type,e->exc_value,e->exc_tb);*(e->res)=NULL;}LEAVE_PYTHONif(!objv)gotodone;i=Tcl_EvalObjv(e->self->interp,objc,objv,e->flags);ENTER_PYTHONif(i==TCL_ERROR){*(e->res)=NULL;*(e->exc_type)=NULL;*(e->exc_tb)=NULL;*(e->exc_value)=PyObject_CallFunction(Tkinter_TclError,"s",Tcl_GetStringResult(e->self->interp));}else{*(e->res)=Tkapp_CallResult(e->self);}LEAVE_PYTHONdone:/* Wake up calling thread. */Tcl_MutexLock(&call_mutex);Tcl_ConditionNotify(&e->done);Tcl_MutexUnlock(&call_mutex);return1;}/* This is the main entry point for calling a Tcl command. It supports three cases, with regard to threading: 1. Tcl is not threaded: Must have the Tcl lock, then can invoke command in the context of the calling thread. 2. Tcl is threaded, caller of the command is in the interpreter thread: Execute the command in the calling thread. Since the Tcl lock will not be used, we can merge that with case 1. 3. Tcl is threaded, caller is in a different thread: Must queue an event to the interpreter thread. Allocation of Tcl objects needs to occur in the interpreter thread, so we ship the PyObject* args to the target thread, and perform processing there. */staticPyObject*Tkapp_Call(PyObject*selfptr,PyObject*args){Tcl_Obj*objStore[ARGSZ];Tcl_Obj**objv=NULL;intobjc,i;PyObject*res=NULL;TkappObject*self=(TkappObject*)selfptr;/* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */intflags=TCL_EVAL_DIRECT;/* If args is a single tuple, replace with contents of tuple */if(1==PyTuple_Size(args)){PyObject*item=PyTuple_GetItem(args,0);if(PyTuple_Check(item))args=item;}#ifdef WITH_THREADif(self->threaded&&self->thread_id!=Tcl_GetCurrentThread()){/* We cannot call the command directly. Instead, we must marshal the parameters to the interpreter thread. */Tkapp_CallEvent*ev;PyObject*exc_type,*exc_value,*exc_tb;if(!WaitForMainloop(self))returnNULL;ev=(Tkapp_CallEvent*)ckalloc(sizeof(Tkapp_CallEvent));ev->ev.proc=(Tcl_EventProc*)Tkapp_CallProc;ev->self=self;ev->args=args;ev->res=&res;ev->exc_type=&exc_type;ev->exc_value=&exc_value;ev->exc_tb=&exc_tb;ev->done=(Tcl_Condition)0;Tkapp_ThreadSend(self,(Tcl_Event*)ev,&ev->done,&call_mutex);if(res==NULL){if(exc_type)PyErr_Restore(exc_type,exc_value,exc_tb);elsePyErr_SetObject(Tkinter_TclError,exc_value);}}else#endif{objv=Tkapp_CallArgs(args,objStore,&objc);if(!objv)returnNULL;ENTER_TCLi=Tcl_EvalObjv(self->interp,objc,objv,flags);ENTER_OVERLAPif(i==TCL_ERROR)Tkinter_Error(selfptr);elseres=Tkapp_CallResult(self);LEAVE_OVERLAP_TCLTkapp_CallDeallocArgs(objv,objStore,objc);}returnres;}staticPyObject*Tkapp_GlobalCall(PyObject*self,PyObject*args){/* Could do the same here as for Tkapp_Call(), but this is not used much, so I can't be bothered. Unfortunately Tcl doesn't export a way for the user to do what all its Global* variants do (save and reset the scope pointer, call the local version, restore the saved scope pointer). */char*cmd;PyObject*res=NULL;CHECK_TCL_APPARTMENT;cmd=Merge(args);if(cmd){interr;ENTER_TCLerr=Tcl_GlobalEval(Tkapp_Interp(self),cmd);ENTER_OVERLAPif(err==TCL_ERROR)res=Tkinter_Error(self);elseres=PyUnicode_FromString(Tkapp_Result(self));LEAVE_OVERLAP_TCLckfree(cmd);}returnres;}staticPyObject*Tkapp_Eval(PyObject*self,PyObject*args){char*script;PyObject*res=NULL;interr;if(!PyArg_ParseTuple(args,"s:eval",&script))returnNULL;CHECK_TCL_APPARTMENT;ENTER_TCLerr=Tcl_Eval(Tkapp_Interp(self),script);ENTER_OVERLAPif(err==TCL_ERROR)res=Tkinter_Error(self);elseres=PyUnicode_FromString(Tkapp_Result(self));LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_GlobalEval(PyObject*self,PyObject*args){char*script;PyObject*res=NULL;interr;if(!PyArg_ParseTuple(args,"s:globaleval",&script))returnNULL;CHECK_TCL_APPARTMENT;ENTER_TCLerr=Tcl_GlobalEval(Tkapp_Interp(self),script);ENTER_OVERLAPif(err==TCL_ERROR)res=Tkinter_Error(self);elseres=PyUnicode_FromString(Tkapp_Result(self));LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_EvalFile(PyObject*self,PyObject*args){char*fileName;PyObject*res=NULL;interr;if(!PyArg_ParseTuple(args,"s:evalfile",&fileName))returnNULL;CHECK_TCL_APPARTMENT;ENTER_TCLerr=Tcl_EvalFile(Tkapp_Interp(self),fileName);ENTER_OVERLAPif(err==TCL_ERROR)res=Tkinter_Error(self);elseres=PyUnicode_FromString(Tkapp_Result(self));LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_Record(PyObject*self,PyObject*args){char*script;PyObject*res=NULL;interr;if(!PyArg_ParseTuple(args,"s",&script))returnNULL;CHECK_TCL_APPARTMENT;ENTER_TCLerr=Tcl_RecordAndEval(Tkapp_Interp(self),script,TCL_NO_EVAL);ENTER_OVERLAPif(err==TCL_ERROR)res=Tkinter_Error(self);elseres=PyUnicode_FromString(Tkapp_Result(self));LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_AddErrorInfo(PyObject*self,PyObject*args){char*msg;if(!PyArg_ParseTuple(args,"s:adderrorinfo",&msg))returnNULL;CHECK_TCL_APPARTMENT;ENTER_TCLTcl_AddErrorInfo(Tkapp_Interp(self),msg);LEAVE_TCLPy_INCREF(Py_None);returnPy_None;}/** Tcl Variable **/TCL_DECLARE_MUTEX(var_mutex)typedefPyObject*(*EventFunc)(PyObject*,PyObject*args,intflags);typedefstructVarEvent{Tcl_Eventev;/* must be first */PyObject*self;PyObject*args;intflags;EventFuncfunc;PyObject**res;PyObject**exc_type;PyObject**exc_val;Tcl_Conditioncond;}VarEvent;staticintvarname_converter(PyObject*in,void*_out){char**out=(char**)_out;if(PyString_Check(in)){*out=PyString_AsString(in);return1;}if(PyUnicode_Check(in)){*out=PyUnicode_AsString(in);return1;}if(PyTclObject_Check(in)){*out=PyTclObject_TclString(in);return1;}/* XXX: Should give diagnostics. */return0;}voidvar_perform(VarEvent*ev){*(ev->res)=ev->func(ev->self,ev->args,ev->flags);if(!*(ev->res)){PyObject*exc,*val,*tb;PyErr_Fetch(&exc,&val,&tb);PyErr_NormalizeException(&exc,&val,&tb);*(ev->exc_type)=exc;*(ev->exc_val)=val;Py_DECREF(tb);}}staticintvar_proc(VarEvent*ev,intflags){ENTER_PYTHONvar_perform(ev);Tcl_MutexLock(&var_mutex);Tcl_ConditionNotify(&ev->cond);Tcl_MutexUnlock(&var_mutex);LEAVE_PYTHONreturn1;}staticPyObject*var_invoke(EventFuncfunc,PyObject*selfptr,PyObject*args,intflags){TkappObject*self=(TkappObject*)selfptr;#ifdef WITH_THREADif(self->threaded&&self->thread_id!=Tcl_GetCurrentThread()){TkappObject*self=(TkappObject*)selfptr;VarEvent*ev;PyObject*res,*exc_type,*exc_val;/* The current thread is not the interpreter thread. Marshal the call to the interpreter thread, then wait for completion. */if(!WaitForMainloop(self))returnNULL;ev=(VarEvent*)ckalloc(sizeof(VarEvent));ev->self=selfptr;ev->args=args;ev->flags=flags;ev->func=func;ev->res=&res;ev->exc_type=&exc_type;ev->exc_val=&exc_val;ev->cond=NULL;ev->ev.proc=(Tcl_EventProc*)var_proc;Tkapp_ThreadSend(self,(Tcl_Event*)ev,&ev->cond,&var_mutex);if(!res){PyErr_SetObject(exc_type,exc_val);Py_DECREF(exc_type);Py_DECREF(exc_val);returnNULL;}returnres;}#endif/* Tcl is not threaded, or this is the interpreter thread. */returnfunc(selfptr,args,flags);}staticPyObject*SetVar(PyObject*self,PyObject*args,intflags){char*name1,*name2;PyObject*newValue;PyObject*res=NULL;Tcl_Obj*newval,*ok;if(PyArg_ParseTuple(args,"O&O:setvar",varname_converter,&name1,&newValue)){/* XXX Acquire tcl lock??? */newval=AsObj(newValue);if(newval==NULL)returnNULL;ENTER_TCLok=Tcl_SetVar2Ex(Tkapp_Interp(self),name1,NULL,newval,flags);ENTER_OVERLAPif(!ok)Tkinter_Error(self);else{res=Py_None;Py_INCREF(res);}LEAVE_OVERLAP_TCL}else{PyErr_Clear();if(PyArg_ParseTuple(args,"ssO:setvar",&name1,&name2,&newValue)){/* XXX must hold tcl lock already??? */newval=AsObj(newValue);ENTER_TCLok=Tcl_SetVar2Ex(Tkapp_Interp(self),name1,name2,newval,flags);ENTER_OVERLAPif(!ok)Tkinter_Error(self);else{res=Py_None;Py_INCREF(res);}LEAVE_OVERLAP_TCL}else{returnNULL;}}returnres;}staticPyObject*Tkapp_SetVar(PyObject*self,PyObject*args){returnvar_invoke(SetVar,self,args,TCL_LEAVE_ERR_MSG);}staticPyObject*Tkapp_GlobalSetVar(PyObject*self,PyObject*args){returnvar_invoke(SetVar,self,args,TCL_LEAVE_ERR_MSG|TCL_GLOBAL_ONLY);}staticPyObject*GetVar(PyObject*self,PyObject*args,intflags){char*name1,*name2=NULL;PyObject*res=NULL;Tcl_Obj*tres;if(!PyArg_ParseTuple(args,"O&|s:getvar",varname_converter,&name1,&name2))returnNULL;ENTER_TCLtres=Tcl_GetVar2Ex(Tkapp_Interp(self),name1,name2,flags);ENTER_OVERLAPif(tres==NULL){PyErr_SetString(Tkinter_TclError,Tcl_GetStringResult(Tkapp_Interp(self)));}else{if(((TkappObject*)self)->wantobjects){res=FromObj(self,tres);}else{res=PyUnicode_FromString(Tcl_GetString(tres));}}LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_GetVar(PyObject*self,PyObject*args){returnvar_invoke(GetVar,self,args,TCL_LEAVE_ERR_MSG);}staticPyObject*Tkapp_GlobalGetVar(PyObject*self,PyObject*args){returnvar_invoke(GetVar,self,args,TCL_LEAVE_ERR_MSG|TCL_GLOBAL_ONLY);}staticPyObject*UnsetVar(PyObject*self,PyObject*args,intflags){char*name1,*name2=NULL;intcode;PyObject*res=NULL;if(!PyArg_ParseTuple(args,"s|s:unsetvar",&name1,&name2))returnNULL;ENTER_TCLcode=Tcl_UnsetVar2(Tkapp_Interp(self),name1,name2,flags);ENTER_OVERLAPif(code==TCL_ERROR)res=Tkinter_Error(self);else{Py_INCREF(Py_None);res=Py_None;}LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_UnsetVar(PyObject*self,PyObject*args){returnvar_invoke(UnsetVar,self,args,TCL_LEAVE_ERR_MSG);}staticPyObject*Tkapp_GlobalUnsetVar(PyObject*self,PyObject*args){returnvar_invoke(UnsetVar,self,args,TCL_LEAVE_ERR_MSG|TCL_GLOBAL_ONLY);}/** Tcl to Python **/staticPyObject*Tkapp_GetInt(PyObject*self,PyObject*args){char*s;intv;if(PyTuple_Size(args)==1){PyObject*o=PyTuple_GetItem(args,0);if(PyLong_Check(o)){Py_INCREF(o);returno;}}if(!PyArg_ParseTuple(args,"s:getint",&s))returnNULL;if(Tcl_GetInt(Tkapp_Interp(self),s,&v)==TCL_ERROR)returnTkinter_Error(self);returnPy_BuildValue("i",v);}staticPyObject*Tkapp_GetDouble(PyObject*self,PyObject*args){char*s;doublev;if(PyTuple_Size(args)==1){PyObject*o=PyTuple_GetItem(args,0);if(PyFloat_Check(o)){Py_INCREF(o);returno;}}if(!PyArg_ParseTuple(args,"s:getdouble",&s))returnNULL;if(Tcl_GetDouble(Tkapp_Interp(self),s,&v)==TCL_ERROR)returnTkinter_Error(self);returnPy_BuildValue("d",v);}staticPyObject*Tkapp_GetBoolean(PyObject*self,PyObject*args){char*s;intv;if(PyTuple_Size(args)==1){PyObject*o=PyTuple_GetItem(args,0);if(PyLong_Check(o)){Py_INCREF(o);returno;}}if(!PyArg_ParseTuple(args,"s:getboolean",&s))returnNULL;if(Tcl_GetBoolean(Tkapp_Interp(self),s,&v)==TCL_ERROR)returnTkinter_Error(self);returnPyBool_FromLong(v);}staticPyObject*Tkapp_ExprString(PyObject*self,PyObject*args){char*s;PyObject*res=NULL;intretval;if(!PyArg_ParseTuple(args,"s:exprstring",&s))returnNULL;CHECK_TCL_APPARTMENT;ENTER_TCLretval=Tcl_ExprString(Tkapp_Interp(self),s);ENTER_OVERLAPif(retval==TCL_ERROR)res=Tkinter_Error(self);elseres=Py_BuildValue("s",Tkapp_Result(self));LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_ExprLong(PyObject*self,PyObject*args){char*s;PyObject*res=NULL;intretval;longv;if(!PyArg_ParseTuple(args,"s:exprlong",&s))returnNULL;CHECK_TCL_APPARTMENT;ENTER_TCLretval=Tcl_ExprLong(Tkapp_Interp(self),s,&v);ENTER_OVERLAPif(retval==TCL_ERROR)res=Tkinter_Error(self);elseres=Py_BuildValue("l",v);LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_ExprDouble(PyObject*self,PyObject*args){char*s;PyObject*res=NULL;doublev;intretval;if(!PyArg_ParseTuple(args,"s:exprdouble",&s))returnNULL;CHECK_TCL_APPARTMENT;PyFPE_START_PROTECT("Tkapp_ExprDouble",return0)ENTER_TCLretval=Tcl_ExprDouble(Tkapp_Interp(self),s,&v);ENTER_OVERLAPPyFPE_END_PROTECT(retval)if(retval==TCL_ERROR)res=Tkinter_Error(self);elseres=Py_BuildValue("d",v);LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_ExprBoolean(PyObject*self,PyObject*args){char*s;PyObject*res=NULL;intretval;intv;if(!PyArg_ParseTuple(args,"s:exprboolean",&s))returnNULL;CHECK_TCL_APPARTMENT;ENTER_TCLretval=Tcl_ExprBoolean(Tkapp_Interp(self),s,&v);ENTER_OVERLAPif(retval==TCL_ERROR)res=Tkinter_Error(self);elseres=Py_BuildValue("i",v);LEAVE_OVERLAP_TCLreturnres;}staticPyObject*Tkapp_SplitList(PyObject*self,PyObject*args){char*list;intargc;char**argv;PyObject*v;inti;if(PyTuple_Size(args)==1){v=PyTuple_GetItem(args,0);if(PyTuple_Check(v)){Py_INCREF(v);returnv;}}if(!PyArg_ParseTuple(args,"et:splitlist","utf-8",&list))returnNULL;if(Tcl_SplitList(Tkapp_Interp(self),list,&argc,&argv)==TCL_ERROR){PyMem_Free(list);returnTkinter_Error(self);}if(!(v=PyTuple_New(argc)))gotofinally;for(i=0;i<argc;i++){PyObject*s=PyUnicode_FromString(argv[i]);if(!s||PyTuple_SetItem(v,i,s)){Py_DECREF(v);v=NULL;gotofinally;}}finally:ckfree(FREECASTargv);PyMem_Free(list);returnv;}staticPyObject*Tkapp_Split(PyObject*self,PyObject*args){PyObject*v;char*list;if(PyTuple_Size(args)==1){PyObject*o=PyTuple_GetItem(args,0);if(PyTuple_Check(o)){o=SplitObj(o);returno;}}if(!PyArg_ParseTuple(args,"et:split","utf-8",&list))returnNULL;v=Split(list);PyMem_Free(list);returnv;}staticPyObject*Tkapp_Merge(PyObject*self,PyObject*args){char*s=Merge(args);PyObject*res=NULL;if(s){res=PyUnicode_FromString(s);ckfree(s);}returnres;}/** Tcl Command **//* Client data struct */typedefstruct{PyObject*self;PyObject*func;}PythonCmd_ClientData;staticintPythonCmd_Error(Tcl_Interp*interp){errorInCmd=1;PyErr_Fetch(&excInCmd,&valInCmd,&trbInCmd);LEAVE_PYTHONreturnTCL_ERROR;}/* This is the Tcl command that acts as a wrapper for Python * function or method. */staticintPythonCmd(ClientDataclientData,Tcl_Interp*interp,intargc,char*argv[]){PythonCmd_ClientData*data=(PythonCmd_ClientData*)clientData;PyObject*self,*func,*arg,*res,*s;inti,rv;Tcl_Obj*tres;ENTER_PYTHON/* TBD: no error checking here since we know, via the * Tkapp_CreateCommand() that the client data is a two-tuple */self=data->self;func=data->func;/* Create argument list (argv1, ..., argvN) */if(!(arg=PyTuple_New(argc-1)))returnPythonCmd_Error(interp);for(i=0;i<(argc-1);i++){if(11==(i+1)){/* the %A arg is the unicode char */char*a=argv[i+1];s=PyUnicode_FromUnicode((Py_UNICODE*)a,strlen(a));}else{s=PyUnicode_FromString(argv[i+1]);}if(!s||PyTuple_SetItem(arg,i,s)){Py_DECREF(arg);returnPythonCmd_Error(interp);}}res=PyEval_CallObject(func,arg);Py_DECREF(arg);if(res==NULL)returnPythonCmd_Error(interp);tres=AsObj(res);if(tres==NULL){Py_DECREF(res);returnPythonCmd_Error(interp);}else{Tcl_SetObjResult(Tkapp_Interp(self),tres);rv=TCL_OK;}Py_DECREF(res);LEAVE_PYTHONreturnrv;}staticvoidPythonCmdDelete(ClientDataclientData){PythonCmd_ClientData*data=(PythonCmd_ClientData*)clientData;ENTER_PYTHONPy_XDECREF(data->self);Py_XDECREF(data->func);PyMem_DEL(data);LEAVE_PYTHON}TCL_DECLARE_MUTEX(command_mutex)typedefstructCommandEvent{Tcl_Eventev;Tcl_Interp*interp;char*name;intcreate;int*status;ClientData*data;Tcl_Conditiondone;}CommandEvent;staticintTkapp_CommandProc(CommandEvent*ev,intflags){if(ev->create)*ev->status=Tcl_CreateCommand(ev->interp,ev->name,PythonCmd,ev->data,PythonCmdDelete)==NULL;else*ev->status=Tcl_DeleteCommand(ev->interp,ev->name);Tcl_MutexLock(&command_mutex);Tcl_ConditionNotify(&ev->done);Tcl_MutexUnlock(&command_mutex);return1;}staticPyObject*Tkapp_CreateCommand(PyObject*selfptr,PyObject*args){TkappObject*self=(TkappObject*)selfptr;PythonCmd_ClientData*data;char*cmdName;PyObject*func;interr;if(!PyArg_ParseTuple(args,"sO:createcommand",&cmdName,&func))returnNULL;if(!PyCallable_Check(func)){PyErr_SetString(PyExc_TypeError,"command not callable");returnNULL;}#ifdef WITH_THREADif(self->threaded&&self->thread_id!=Tcl_GetCurrentThread()&&!WaitForMainloop(self))returnNULL;#endifdata=PyMem_NEW(PythonCmd_ClientData,1);if(!data)returnPyErr_NoMemory();Py_INCREF(self);Py_INCREF(func);data->self=selfptr;data->func=func;if(self->threaded&&self->thread_id!=Tcl_GetCurrentThread()){CommandEvent*ev=(CommandEvent*)ckalloc(sizeof(CommandEvent));ev->ev.proc=(Tcl_EventProc*)Tkapp_CommandProc;ev->interp=self->interp;ev->create=1;ev->name=cmdName;ev->data=(ClientData)data;ev->status=&err;ev->done=NULL;Tkapp_ThreadSend(self,(Tcl_Event*)ev,&ev->done,&command_mutex);}else{ENTER_TCLerr=Tcl_CreateCommand(Tkapp_Interp(self),cmdName,PythonCmd,(ClientData)data,PythonCmdDelete)==NULL;LEAVE_TCL}if(err){PyErr_SetString(Tkinter_TclError,"can't create Tcl command");PyMem_DEL(data);returnNULL;}Py_INCREF(Py_None);returnPy_None;}staticPyObject*Tkapp_DeleteCommand(PyObject*selfptr,PyObject*args){TkappObject*self=(TkappObject*)selfptr;char*cmdName;interr;if(!PyArg_ParseTuple(args,"s:deletecommand",&cmdName))returnNULL;if(self->threaded&&self->thread_id!=Tcl_GetCurrentThread()){CommandEvent*ev;ev=(CommandEvent*)ckalloc(sizeof(CommandEvent));ev->ev.proc=(Tcl_EventProc*)Tkapp_CommandProc;ev->interp=self->interp;ev->create=0;ev->name=cmdName;ev->status=&err;ev->done=NULL;Tkapp_ThreadSend(self,(Tcl_Event*)ev,&ev->done,&command_mutex);}else{ENTER_TCLerr=Tcl_DeleteCommand(self->interp,cmdName);LEAVE_TCL}if(err==-1){PyErr_SetString(Tkinter_TclError,"can't delete Tcl command");returnNULL;}Py_INCREF(Py_None);returnPy_None;}#ifdef HAVE_CREATEFILEHANDLER/** File Handler **/typedefstruct_fhcdata{PyObject*func;PyObject*file;intid;struct_fhcdata*next;}FileHandler_ClientData;staticFileHandler_ClientData*HeadFHCD;staticFileHandler_ClientData*NewFHCD(PyObject*func,PyObject*file,intid){FileHandler_ClientData*p;p=PyMem_NEW(FileHandler_ClientData,1);if(p!=NULL){Py_XINCREF(func);Py_XINCREF(file);p->func=func;p->file=file;p->id=id;p->next=HeadFHCD;HeadFHCD=p;}returnp;}staticvoidDeleteFHCD(intid){FileHandler_ClientData*p,**pp;pp=&HeadFHCD;while((p=*pp)!=NULL){if(p->id==id){*pp=p->next;Py_XDECREF(p->func);Py_XDECREF(p->file);PyMem_DEL(p);}elsepp=&p->next;}}staticvoidFileHandler(ClientDataclientData,intmask){FileHandler_ClientData*data=(FileHandler_ClientData*)clientData;PyObject*func,*file,*arg,*res;ENTER_PYTHONfunc=data->func;file=data->file;arg=Py_BuildValue("(Oi)",file,(long)mask);res=PyEval_CallObject(func,arg);Py_DECREF(arg);if(res==NULL){errorInCmd=1;PyErr_Fetch(&excInCmd,&valInCmd,&trbInCmd);}Py_XDECREF(res);LEAVE_PYTHON}staticPyObject*Tkapp_CreateFileHandler(PyObject*self,PyObject*args)/* args is (file, mask, func) */{FileHandler_ClientData*data;PyObject*file,*func;intmask,tfile;if(!PyArg_ParseTuple(args,"OiO:createfilehandler",&file,&mask,&func))returnNULL;#ifdef WITH_THREADif(!self&&!tcl_lock){/* We don't have the Tcl lock since Tcl is threaded. */PyErr_SetString(PyExc_RuntimeError,"_tkinter.createfilehandler not supported ""for threaded Tcl");returnNULL;}#endifif(self){CHECK_TCL_APPARTMENT;}tfile=PyObject_AsFileDescriptor(file);if(tfile<0)returnNULL;if(!PyCallable_Check(func)){PyErr_SetString(PyExc_TypeError,"bad argument list");returnNULL;}data=NewFHCD(func,file,tfile);if(data==NULL)returnNULL;/* Ought to check for null Tcl_File object... */ENTER_TCLTcl_CreateFileHandler(tfile,mask,FileHandler,(ClientData)data);LEAVE_TCLPy_INCREF(Py_None);returnPy_None;}staticPyObject*Tkapp_DeleteFileHandler(PyObject*self,PyObject*args){PyObject*file;inttfile;if(!PyArg_ParseTuple(args,"O:deletefilehandler",&file))returnNULL;#ifdef WITH_THREADif(!self&&!tcl_lock){/* We don't have the Tcl lock since Tcl is threaded. */PyErr_SetString(PyExc_RuntimeError,"_tkinter.deletefilehandler not supported ""for threaded Tcl");returnNULL;}#endifif(self){CHECK_TCL_APPARTMENT;}tfile=PyObject_AsFileDescriptor(file);if(tfile<0)returnNULL;DeleteFHCD(tfile);/* Ought to check for null Tcl_File object... */ENTER_TCLTcl_DeleteFileHandler(tfile);LEAVE_TCLPy_INCREF(Py_None);returnPy_None;}#endif /* HAVE_CREATEFILEHANDLER *//**** Tktt Object (timer token) ****/staticPyTypeObjectTktt_Type;typedefstruct{PyObject_HEADTcl_TimerTokentoken;PyObject*func;}TkttObject;staticPyObject*Tktt_DeleteTimerHandler(PyObject*self,PyObject*args){TkttObject*v=(TkttObject*)self;PyObject*func=v->func;if(!PyArg_ParseTuple(args,":deletetimerhandler"))returnNULL;if(v->token!=NULL){Tcl_DeleteTimerHandler(v->token);v->token=NULL;}if(func!=NULL){v->func=NULL;Py_DECREF(func);Py_DECREF(v);/* See Tktt_New() */}Py_INCREF(Py_None);returnPy_None;}staticPyMethodDefTktt_methods[]={{"deletetimerhandler",Tktt_DeleteTimerHandler,METH_VARARGS},{NULL,NULL}};staticTkttObject*Tktt_New(PyObject*func){TkttObject*v;v=PyObject_New(TkttObject,&Tktt_Type);if(v==NULL)returnNULL;Py_INCREF(func);v->token=NULL;v->func=func;/* Extra reference, deleted when called or when handler is deleted */Py_INCREF(v);returnv;}staticvoidTktt_Dealloc(PyObject*self){TkttObject*v=(TkttObject*)self;PyObject*func=v->func;Py_XDECREF(func);PyObject_Del(self);}staticPyObject*Tktt_Repr(PyObject*self){TkttObject*v=(TkttObject*)self;charbuf[100];PyOS_snprintf(buf,sizeof(buf),"<tktimertoken at %p%s>",v,v->func==NULL?", handler deleted":"");returnPyUnicode_FromString(buf);}staticPyObject*Tktt_GetAttr(PyObject*self,char*name){returnPy_FindMethod(Tktt_methods,self,name);}staticPyTypeObjectTktt_Type={PyVarObject_HEAD_INIT(NULL,0)"tktimertoken",/*tp_name */sizeof(TkttObject),/*tp_basicsize */0,/*tp_itemsize */Tktt_Dealloc,/*tp_dealloc */0,/*tp_print */Tktt_GetAttr,/*tp_getattr */0,/*tp_setattr */0,/*tp_compare */Tktt_Repr,/*tp_repr */0,/*tp_as_number */0,/*tp_as_sequence */0,/*tp_as_mapping */0,/*tp_hash */};/** Timer Handler **/staticvoidTimerHandler(ClientDataclientData){TkttObject*v=(TkttObject*)clientData;PyObject*func=v->func;PyObject*res;if(func==NULL)return;v->func=NULL;ENTER_PYTHONres=PyEval_CallObject(func,NULL);Py_DECREF(func);Py_DECREF(v);/* See Tktt_New() */if(res==NULL){errorInCmd=1;PyErr_Fetch(&excInCmd,&valInCmd,&trbInCmd);}elsePy_DECREF(res);LEAVE_PYTHON}staticPyObject*Tkapp_CreateTimerHandler(PyObject*self,PyObject*args){intmilliseconds;PyObject*func;TkttObject*v;if(!PyArg_ParseTuple(args,"iO:createtimerhandler",&milliseconds,&func))returnNULL;if(!PyCallable_Check(func)){PyErr_SetString(PyExc_TypeError,"bad argument list");returnNULL;}#ifdef WITH_THREADif(!self&&!tcl_lock){/* We don't have the Tcl lock since Tcl is threaded. */PyErr_SetString(PyExc_RuntimeError,"_tkinter.createtimerhandler not supported ""for threaded Tcl");returnNULL;}#endifif(self){CHECK_TCL_APPARTMENT;}v=Tktt_New(func);if(v){v->token=Tcl_CreateTimerHandler(milliseconds,TimerHandler,(ClientData)v);}return(PyObject*)v;}/** Event Loop **/staticPyObject*Tkapp_MainLoop(PyObject*selfptr,PyObject*args){intthreshold=0;TkappObject*self=(TkappObject*)selfptr;#ifdef WITH_THREADPyThreadState*tstate=PyThreadState_Get();#endifif(!PyArg_ParseTuple(args,"|i:mainloop",&threshold))returnNULL;#ifdef WITH_THREADif(!self&&!tcl_lock){/* We don't have the Tcl lock since Tcl is threaded. */PyErr_SetString(PyExc_RuntimeError,"_tkinter.mainloop not supported ""for threaded Tcl");returnNULL;}#endifif(self){CHECK_TCL_APPARTMENT;self->dispatching=1;}quitMainLoop=0;while(Tk_GetNumMainWindows()>threshold&&!quitMainLoop&&!errorInCmd){intresult;#ifdef WITH_THREADif(self&&self->threaded){/* Allow other Python threads to run. */ENTER_TCLresult=Tcl_DoOneEvent(0);LEAVE_TCL}else{Py_BEGIN_ALLOW_THREADSif(tcl_lock)PyThread_acquire_lock(tcl_lock,1);tcl_tstate=tstate;result=Tcl_DoOneEvent(TCL_DONT_WAIT);tcl_tstate=NULL;if(tcl_lock)PyThread_release_lock(tcl_lock);if(result==0)Sleep(Tkinter_busywaitinterval);Py_END_ALLOW_THREADS}#elseresult=Tcl_DoOneEvent(0);#endifif(PyErr_CheckSignals()!=0){if(self)self->dispatching=0;returnNULL;}if(result<0)break;}if(self)self->dispatching=0;quitMainLoop=0;if(errorInCmd){errorInCmd=0;PyErr_Restore(excInCmd,valInCmd,trbInCmd);excInCmd=valInCmd=trbInCmd=NULL;returnNULL;}Py_INCREF(Py_None);returnPy_None;}staticPyObject*Tkapp_DoOneEvent(PyObject*self,PyObject*args){intflags=0;intrv;if(!PyArg_ParseTuple(args,"|i:dooneevent",&flags))returnNULL;ENTER_TCLrv=Tcl_DoOneEvent(flags);LEAVE_TCLreturnPy_BuildValue("i",rv);}staticPyObject*Tkapp_Quit(PyObject*self,PyObject*args){if(!PyArg_ParseTuple(args,":quit"))returnNULL;quitMainLoop=1;Py_INCREF(Py_None);returnPy_None;}staticPyObject*Tkapp_InterpAddr(PyObject*self,PyObject*args){if(!PyArg_ParseTuple(args,":interpaddr"))returnNULL;returnPyLong_FromLong((long)Tkapp_Interp(self));}staticPyObject*Tkapp_TkInit(PyObject*self,PyObject*args){staticinthas_failed;Tcl_Interp*interp=Tkapp_Interp(self);Tk_Windowmain_window;constchar*_tk_exists=NULL;interr;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");returnNULL;}/* We want to guard against calling Tk_Init() multiple times */CHECK_TCL_APPARTMENT;ENTER_TCLerr=Tcl_Eval(Tkapp_Interp(self),"info exists tk_version");ENTER_OVERLAPif(err==TCL_ERROR){/* This sets an exception, but we cannot return right away because we need to exit the overlap first. */Tkinter_Error(self);}else{_tk_exists=Tkapp_Result(self);}LEAVE_OVERLAP_TCLif(err==TCL_ERROR){returnNULL;}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;returnNULL;}}Py_INCREF(Py_None);returnPy_None;}staticPyObject*Tkapp_WantObjects(PyObject*self,PyObject*args){intwantobjects=-1;if(!PyArg_ParseTuple(args,"|i:wantobjects",&wantobjects))returnNULL;if(wantobjects==-1)returnPyBool_FromLong(((TkappObject*)self)->wantobjects);((TkappObject*)self)->wantobjects=wantobjects;Py_INCREF(Py_None);returnPy_None;}staticPyObject*Tkapp_WillDispatch(PyObject*self,PyObject*args){((TkappObject*)self)->dispatching=1;Py_INCREF(Py_None);returnPy_None;}/**** Tkapp Method List ****/staticPyMethodDefTkapp_methods[]={{"willdispatch",Tkapp_WillDispatch,METH_NOARGS},{"wantobjects",Tkapp_WantObjects,METH_VARARGS},{"call",Tkapp_Call,METH_VARARGS},{"globalcall",Tkapp_GlobalCall,METH_VARARGS},{"eval",Tkapp_Eval,METH_VARARGS},{"globaleval",Tkapp_GlobalEval,METH_VARARGS},{"evalfile",Tkapp_EvalFile,METH_VARARGS},{"record",Tkapp_Record,METH_VARARGS},{"adderrorinfo",Tkapp_AddErrorInfo,METH_VARARGS},{"setvar",Tkapp_SetVar,METH_VARARGS},{"globalsetvar",Tkapp_GlobalSetVar,METH_VARARGS},{"getvar",Tkapp_GetVar,METH_VARARGS},{"globalgetvar",Tkapp_GlobalGetVar,METH_VARARGS},{"unsetvar",Tkapp_UnsetVar,METH_VARARGS},{"globalunsetvar",Tkapp_GlobalUnsetVar,METH_VARARGS},{"getint",Tkapp_GetInt,METH_VARARGS},{"getdouble",Tkapp_GetDouble,METH_VARARGS},{"getboolean",Tkapp_GetBoolean,METH_VARARGS},{"exprstring",Tkapp_ExprString,METH_VARARGS},{"exprlong",Tkapp_ExprLong,METH_VARARGS},{"exprdouble",Tkapp_ExprDouble,METH_VARARGS},{"exprboolean",Tkapp_ExprBoolean,METH_VARARGS},{"splitlist",Tkapp_SplitList,METH_VARARGS},{"split",Tkapp_Split,METH_VARARGS},{"merge",Tkapp_Merge,METH_VARARGS},{"createcommand",Tkapp_CreateCommand,METH_VARARGS},{"deletecommand",Tkapp_DeleteCommand,METH_VARARGS},#ifdef HAVE_CREATEFILEHANDLER{"createfilehandler",Tkapp_CreateFileHandler,METH_VARARGS},{"deletefilehandler",Tkapp_DeleteFileHandler,METH_VARARGS},#endif{"createtimerhandler",Tkapp_CreateTimerHandler,METH_VARARGS},{"mainloop",Tkapp_MainLoop,METH_VARARGS},{"dooneevent",Tkapp_DoOneEvent,METH_VARARGS},{"quit",Tkapp_Quit,METH_VARARGS},{"interpaddr",Tkapp_InterpAddr,METH_VARARGS},{"loadtk",Tkapp_TkInit,METH_NOARGS},{NULL,NULL}};/**** Tkapp Type Methods ****/staticvoidTkapp_Dealloc(PyObject*self){/*CHECK_TCL_APPARTMENT;*/ENTER_TCLTcl_DeleteInterp(Tkapp_Interp(self));LEAVE_TCLPyObject_Del(self);DisableEventHook();}staticPyObject*Tkapp_GetAttr(PyObject*self,char*name){returnPy_FindMethod(Tkapp_methods,self,name);}staticPyTypeObjectTkapp_Type={PyVarObject_HEAD_INIT(NULL,0)"tkapp",/*tp_name */sizeof(TkappObject),/*tp_basicsize */0,/*tp_itemsize */Tkapp_Dealloc,/*tp_dealloc */0,/*tp_print */Tkapp_GetAttr,/*tp_getattr */0,/*tp_setattr */0,/*tp_compare */0,/*tp_repr */0,/*tp_as_number */0,/*tp_as_sequence */0,/*tp_as_mapping */0,/*tp_hash */};/**** Tkinter Module ****/typedefstruct{PyObject*tuple;intsize;/* current size */intmaxsize;/* allocated size */}FlattenContext;staticint_bump(FlattenContext*context,intsize){/* expand tuple to hold (at least) size new items. return true if successful, false if an exception was raised */intmaxsize=context->maxsize*2;if(maxsize<context->size+size)maxsize=context->size+size;context->maxsize=maxsize;return_PyTuple_Resize(&context->tuple,maxsize)>=0;}staticint_flatten1(FlattenContext*context,PyObject*item,intdepth){/* add tuple or list to argument tuple (recursively) */inti,size;if(depth>1000){PyErr_SetString(PyExc_ValueError,"nesting too deep in _flatten");return0;}elseif(PyList_Check(item)){size=PyList_GET_SIZE(item);/* preallocate (assume no nesting) */if(context->size+size>context->maxsize&&!_bump(context,size))return0;/* copy items to output tuple */for(i=0;i<size;i++){PyObject*o=PyList_GET_ITEM(item,i);if(PyList_Check(o)||PyTuple_Check(o)){if(!_flatten1(context,o,depth+1))return0;}elseif(o!=Py_None){if(context->size+1>context->maxsize&&!_bump(context,1))return0;Py_INCREF(o);PyTuple_SET_ITEM(context->tuple,context->size++,o);}}}elseif(PyTuple_Check(item)){/* same, for tuples */size=PyTuple_GET_SIZE(item);if(context->size+size>context->maxsize&&!_bump(context,size))return0;for(i=0;i<size;i++){PyObject*o=PyTuple_GET_ITEM(item,i);if(PyList_Check(o)||PyTuple_Check(o)){if(!_flatten1(context,o,depth+1))return0;}elseif(o!=Py_None){if(context->size+1>context->maxsize&&!_bump(context,1))return0;Py_INCREF(o);PyTuple_SET_ITEM(context->tuple,context->size++,o);}}}else{PyErr_SetString(PyExc_TypeError,"argument must be sequence");return0;}return1;}staticPyObject*Tkinter_Flatten(PyObject*self,PyObject*args){FlattenContextcontext;PyObject*item;if(!PyArg_ParseTuple(args,"O:_flatten",&item))returnNULL;context.maxsize=PySequence_Size(item);if(context.maxsize<=0)returnPyTuple_New(0);context.tuple=PyTuple_New(context.maxsize);if(!context.tuple)returnNULL;context.size=0;if(!_flatten1(&context,item,0))returnNULL;if(_PyTuple_Resize(&context.tuple,context.size))returnNULL;returncontext.tuple;}staticPyObject*Tkinter_Create(PyObject*self,PyObject*args){char*screenName=NULL;char*baseName=NULL;char*className=NULL;intinteractive=0;intwantobjects=0;intwantTk=1;/* If false, then Tk_Init() doesn't get called */intsync=0;/* pass -sync to wish */char*use=NULL;/* pass -use to wish */baseName=strrchr(Py_GetProgramName(),'/');if(baseName!=NULL)baseName++;elsebaseName=Py_GetProgramName();className="Tk";if(!PyArg_ParseTuple(args,"|zssiiiiz:create",&screenName,&baseName,&className,&interactive,&wantobjects,&wantTk,&sync,&use))returnNULL;return(PyObject*)Tkapp_New(screenName,baseName,className,interactive,wantobjects,wantTk,sync,use);}staticPyObject*Tkinter_setbusywaitinterval(PyObject*self,PyObject*args){intnew_val;if(!PyArg_ParseTuple(args,"i:setbusywaitinterval",&new_val))returnNULL;if(new_val<0){PyErr_SetString(PyExc_ValueError,"busywaitinterval must be >= 0");returnNULL;}Tkinter_busywaitinterval=new_val;Py_INCREF(Py_None);returnPy_None;}staticcharsetbusywaitinterval_doc[]="setbusywaitinterval(n) -> None\n\\n\Set the busy-wait interval in milliseconds between successive\n\calls to Tcl_DoOneEvent in a threaded Python interpreter.\n\It should be set to a divisor of the maximum time between\n\frames in an animation.";staticPyObject*Tkinter_getbusywaitinterval(PyObject*self,PyObject*args){returnPyLong_FromLong(Tkinter_busywaitinterval);}staticchargetbusywaitinterval_doc[]="getbusywaitinterval() -> int\n\\n\Return the current busy-wait interval between successive\n\calls to Tcl_DoOneEvent in a threaded Python interpreter.";staticPyMethodDefmoduleMethods[]={{"_flatten",Tkinter_Flatten,METH_VARARGS},{"create",Tkinter_Create,METH_VARARGS},#ifdef HAVE_CREATEFILEHANDLER{"createfilehandler",Tkapp_CreateFileHandler,METH_VARARGS},{"deletefilehandler",Tkapp_DeleteFileHandler,METH_VARARGS},#endif{"createtimerhandler",Tkapp_CreateTimerHandler,METH_VARARGS},{"mainloop",Tkapp_MainLoop,METH_VARARGS},{"dooneevent",Tkapp_DoOneEvent,METH_VARARGS},{"quit",Tkapp_Quit,METH_VARARGS},{"setbusywaitinterval",Tkinter_setbusywaitinterval,METH_VARARGS,setbusywaitinterval_doc},{"getbusywaitinterval",(PyCFunction)Tkinter_getbusywaitinterval,METH_NOARGS,getbusywaitinterval_doc},{NULL,NULL}};#ifdef WAIT_FOR_STDINstaticintstdin_ready=0;#ifndef MS_WINDOWSstaticvoidMyFileProc(void*clientData,intmask){stdin_ready=1;}#endif#ifdef WITH_THREADstaticPyThreadState*event_tstate=NULL;#endifstaticintEventHook(void){#ifndef MS_WINDOWSinttfile;#endif#ifdef WITH_THREADPyEval_RestoreThread(event_tstate);#endifstdin_ready=0;errorInCmd=0;#ifndef MS_WINDOWStfile=fileno(stdin);Tcl_CreateFileHandler(tfile,TCL_READABLE,MyFileProc,NULL);#endifwhile(!errorInCmd&&!stdin_ready){intresult;#ifdef MS_WINDOWSif(_kbhit()){stdin_ready=1;break;}#endif#if defined(WITH_THREAD) || defined(MS_WINDOWS)Py_BEGIN_ALLOW_THREADSif(tcl_lock)PyThread_acquire_lock(tcl_lock,1);tcl_tstate=event_tstate;result=Tcl_DoOneEvent(TCL_DONT_WAIT);tcl_tstate=NULL;if(tcl_lock)PyThread_release_lock(tcl_lock);if(result==0)Sleep(Tkinter_busywaitinterval);Py_END_ALLOW_THREADS#elseresult=Tcl_DoOneEvent(0);#endifif(result<0)break;}#ifndef MS_WINDOWSTcl_DeleteFileHandler(tfile);#endifif(errorInCmd){errorInCmd=0;PyErr_Restore(excInCmd,valInCmd,trbInCmd);excInCmd=valInCmd=trbInCmd=NULL;PyErr_Print();}#ifdef WITH_THREADPyEval_SaveThread();#endifreturn0;}#endifstaticvoidEnableEventHook(void){#ifdef WAIT_FOR_STDINif(PyOS_InputHook==NULL){#ifdef WITH_THREADevent_tstate=PyThreadState_Get();#endifPyOS_InputHook=EventHook;}#endif}staticvoidDisableEventHook(void){#ifdef WAIT_FOR_STDINif(Tk_GetNumMainWindows()==0&&PyOS_InputHook==EventHook){PyOS_InputHook=NULL;}#endif}/* all errors will be checked in one fell swoop in init_tkinter() */staticvoidins_long(PyObject*d,char*name,longval){PyObject*v=PyLong_FromLong(val);if(v){PyDict_SetItemString(d,name,v);Py_DECREF(v);}}staticvoidins_string(PyObject*d,char*name,char*val){PyObject*v=PyUnicode_FromString(val);if(v){PyDict_SetItemString(d,name,v);Py_DECREF(v);}}PyMODINIT_FUNCinit_tkinter(void){PyObject*m,*d;Py_Type(&Tkapp_Type)=&PyType_Type;#ifdef WITH_THREADtcl_lock=PyThread_allocate_lock();#endifm=Py_InitModule("_tkinter",moduleMethods);if(m==NULL)return;d=PyModule_GetDict(m);Tkinter_TclError=PyErr_NewException("_tkinter.TclError",NULL,NULL);PyDict_SetItemString(d,"TclError",Tkinter_TclError);ins_long(d,"READABLE",TCL_READABLE);ins_long(d,"WRITABLE",TCL_WRITABLE);ins_long(d,"EXCEPTION",TCL_EXCEPTION);ins_long(d,"WINDOW_EVENTS",TCL_WINDOW_EVENTS);ins_long(d,"FILE_EVENTS",TCL_FILE_EVENTS);ins_long(d,"TIMER_EVENTS",TCL_TIMER_EVENTS);ins_long(d,"IDLE_EVENTS",TCL_IDLE_EVENTS);ins_long(d,"ALL_EVENTS",TCL_ALL_EVENTS);ins_long(d,"DONT_WAIT",TCL_DONT_WAIT);ins_string(d,"TK_VERSION",TK_VERSION);ins_string(d,"TCL_VERSION",TCL_VERSION);PyDict_SetItemString(d,"TkappType",(PyObject*)&Tkapp_Type);Py_Type(&Tktt_Type)=&PyType_Type;PyDict_SetItemString(d,"TkttType",(PyObject*)&Tktt_Type);Py_Type(&PyTclObject_Type)=&PyType_Type;PyDict_SetItemString(d,"Tcl_Obj",(PyObject*)&PyTclObject_Type);#ifdef TK_AQUA/* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems * start waking up. Note that Tcl_FindExecutable will do this, this * code must be above it! The original warning from * tkMacOSXAppInit.c is copied below. * * NB - You have to swap in the Tk Notifier BEFORE you start up the * Tcl interpreter for now. It probably should work to do this * in the other order, but for now it doesn't seem to. * */Tk_MacOSXSetupTkNotifier();#endif/* This helps the dynamic loader; in Unicode aware Tcl versions it also helps Tcl find its encodings. */Tcl_FindExecutable(Py_GetProgramName());if(PyErr_Occurred())return;#if 0 /* This was not a good idea; through <Destroy> bindings, Tcl_Finalize() may invoke Python code but at that point the interpreter and thread state have already been destroyed! */ Py_AtExit(Tcl_Finalize);#endif}