1 /***********************************************************
2 Copyright (C) 1994 Steen Lumholt.
3 
4                         All Rights Reserved
5 
6 ******************************************************************/
7 
8 /* _tkinter.c -- Interface to libtk.a and libtcl.a. */
9 
10 /* TCL/TK VERSION INFO:
11 
12     Only Tcl/Tk 8.4 and later are supported.  Older versions are not
13     supported. Use Python 3.4 or older if you cannot upgrade your
14     Tcl/Tk libraries.
15 */
16 
17 /* XXX Further speed-up ideas, involving Tcl 8.0 features:
18 
19    - Register a new Tcl type, "Python callable", which can be called more
20    efficiently and passed to Tcl_EvalObj() directly (if this is possible).
21 
22 */
23 
24 #define PY_SSIZE_T_CLEAN
25 
26 #include "Python.h"
27 #include <ctype.h>
28 
29 #include "pythread.h"
30 
31 #ifdef MS_WINDOWS
32 #include <windows.h>
33 #endif
34 
35 #define CHECK_SIZE(size, elemsize) \
36     ((size_t)(size) <= Py_MIN((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize)))
37 
38 /* If Tcl is compiled for threads, we must also define TCL_THREAD. We define
39    it always; if Tcl is not threaded, the thread functions in
40    Tcl are empty.  */
41 #define TCL_THREADS
42 
43 #ifdef TK_FRAMEWORK
44 #include <Tcl/tcl.h>
45 #include <Tk/tk.h>
46 #else
47 #include <tcl.h>
48 #include <tk.h>
49 #endif
50 
51 #include "tkinter.h"
52 
53 #if TK_HEX_VERSION < 0x08040200
54 #error "Tk older than 8.4 not supported"
55 #endif
56 
57 #if TK_HEX_VERSION >= 0x08050208 && TK_HEX_VERSION < 0x08060000 || \
58     TK_HEX_VERSION >= 0x08060200
59 #define HAVE_LIBTOMMAMTH
60 #include <tclTomMath.h>
61 #endif
62 
63 #if !(defined(MS_WINDOWS) || defined(__CYGWIN__))
64 #define HAVE_CREATEFILEHANDLER
65 #endif
66 
67 #ifdef HAVE_CREATEFILEHANDLER
68 
69 /* This bit is to ensure that TCL_UNIX_FD is defined and doesn't interfere
70    with the proper calculation of FHANDLETYPE == TCL_UNIX_FD below. */
71 #ifndef TCL_UNIX_FD
72 #  ifdef TCL_WIN_SOCKET
73 #    define TCL_UNIX_FD (! TCL_WIN_SOCKET)
74 #  else
75 #    define TCL_UNIX_FD 1
76 #  endif
77 #endif
78 
79 /* Tcl_CreateFileHandler() changed several times; these macros deal with the
80    messiness.  In Tcl 8.0 and later, it is not available on Windows (and on
81    Unix, only because Jack added it back); when available on Windows, it only
82    applies to sockets. */
83 
84 #ifdef MS_WINDOWS
85 #define FHANDLETYPE TCL_WIN_SOCKET
86 #else
87 #define FHANDLETYPE TCL_UNIX_FD
88 #endif
89 
90 /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine
91    which uses this to handle Tcl events while the user is typing commands. */
92 
93 #if FHANDLETYPE == TCL_UNIX_FD
94 #define WAIT_FOR_STDIN
95 #endif
96 
97 #endif /* HAVE_CREATEFILEHANDLER */
98 
99 /* Use OS native encoding for converting between Python strings and
100    Tcl objects.
101    On Windows use UTF-16 (or UTF-32 for 32-bit Tcl_UniChar) with the
102    "surrogatepass" error handler for converting to/from Tcl Unicode objects.
103    On Linux use UTF-8 with the "surrogateescape" error handler for converting
104    to/from Tcl String objects. */
105 #ifdef MS_WINDOWS
106 #define USE_TCL_UNICODE 1
107 #else
108 #define USE_TCL_UNICODE 0
109 #endif
110 
111 #if PY_LITTLE_ENDIAN
112 #define NATIVE_BYTEORDER -1
113 #else
114 #define NATIVE_BYTEORDER 1
115 #endif
116 
117 #ifdef MS_WINDOWS
118 #include <conio.h>
119 #define WAIT_FOR_STDIN
120 
121 static PyObject *
_get_tcl_lib_path()122 _get_tcl_lib_path()
123 {
124     static PyObject *tcl_library_path = NULL;
125     static int already_checked = 0;
126 
127     if (already_checked == 0) {
128         PyObject *prefix;
129         struct stat stat_buf;
130         int stat_return_value;
131 
132         prefix = PyUnicode_FromWideChar(Py_GetPrefix(), -1);
133         if (prefix == NULL) {
134             return NULL;
135         }
136 
137         /* Check expected location for an installed Python first */
138         tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
139         if (tcl_library_path == NULL) {
140             return NULL;
141         }
142         tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path);
143         if (tcl_library_path == NULL) {
144             return NULL;
145         }
146         stat_return_value = _Py_stat(tcl_library_path, &stat_buf);
147         if (stat_return_value == -2) {
148             return NULL;
149         }
150         if (stat_return_value == -1) {
151             /* install location doesn't exist, reset errno and see if
152                we're a repository build */
153             errno = 0;
154 #ifdef Py_TCLTK_DIR
155             tcl_library_path = PyUnicode_FromString(
156                                     Py_TCLTK_DIR "\\lib\\tcl" TCL_VERSION);
157             if (tcl_library_path == NULL) {
158                 return NULL;
159             }
160             stat_return_value = _Py_stat(tcl_library_path, &stat_buf);
161             if (stat_return_value == -2) {
162                 return NULL;
163             }
164             if (stat_return_value == -1) {
165                 /* tcltkDir for a repository build doesn't exist either,
166                    reset errno and leave Tcl to its own devices */
167                 errno = 0;
168                 tcl_library_path = NULL;
169             }
170 #else
171             tcl_library_path = NULL;
172 #endif
173         }
174         already_checked = 1;
175     }
176     return tcl_library_path;
177 }
178 #endif /* MS_WINDOWS */
179 
180 /* The threading situation is complicated.  Tcl is not thread-safe, except
181    when configured with --enable-threads.
182 
183    So we need to use a lock around all uses of Tcl.  Previously, the
184    Python interpreter lock was used for this.  However, this causes
185    problems when other Python threads need to run while Tcl is blocked
186    waiting for events.
187 
188    To solve this problem, a separate lock for Tcl is introduced.
189    Holding it is incompatible with holding Python's interpreter lock.
190    The following four macros manipulate both locks together.
191 
192    ENTER_TCL and LEAVE_TCL are brackets, just like
193    Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS.  They should be
194    used whenever a call into Tcl is made that could call an event
195    handler, or otherwise affect the state of a Tcl interpreter.  These
196    assume that the surrounding code has the Python interpreter lock;
197    inside the brackets, the Python interpreter lock has been released
198    and the lock for Tcl has been acquired.
199 
200    Sometimes, it is necessary to have both the Python lock and the Tcl
201    lock.  (For example, when transferring data from the Tcl
202    interpreter result to a Python string object.)  This can be done by
203    using different macros to close the ENTER_TCL block: ENTER_OVERLAP
204    reacquires the Python lock (and restores the thread state) but
205    doesn't release the Tcl lock; LEAVE_OVERLAP_TCL releases the Tcl
206    lock.
207 
208    By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event
209    handlers when the handler needs to use Python.  Such event handlers
210    are entered while the lock for Tcl is held; the event handler
211    presumably needs to use Python.  ENTER_PYTHON releases the lock for
212    Tcl and acquires the Python interpreter lock, restoring the
213    appropriate thread state, and LEAVE_PYTHON releases the Python
214    interpreter lock and re-acquires the lock for Tcl.  It is okay for
215    ENTER_TCL/LEAVE_TCL pairs to be contained inside the code between
216    ENTER_PYTHON and LEAVE_PYTHON.
217 
218    These locks expand to several statements and brackets; they should
219    not be used in branches of if statements and the like.
220 
221    If Tcl is threaded, this approach won't work anymore. The Tcl
222    interpreter is only valid in the thread that created it, and all Tk
223    activity must happen in this thread, also. That means that the
224    mainloop must be invoked in the thread that created the
225    interpreter. Invoking commands from other threads is possible;
226    _tkinter will queue an event for the interpreter thread, which will
227    then execute the command and pass back the result. If the main
228    thread is not in the mainloop, and invoking commands causes an
229    exception; if the main loop is running but not processing events,
230    the command invocation will block.
231 
232    In addition, for a threaded Tcl, a single global tcl_tstate won't
233    be sufficient anymore, since multiple Tcl interpreters may
234    simultaneously dispatch in different threads. So we use the Tcl TLS
235    API.
236 
237 */
238 
239 static PyThread_type_lock tcl_lock = 0;
240 
241 #ifdef TCL_THREADS
242 static Tcl_ThreadDataKey state_key;
243 typedef PyThreadState *ThreadSpecificData;
244 #define tcl_tstate \
245     (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*)))
246 #else
247 static PyThreadState *tcl_tstate = NULL;
248 #endif
249 
250 #define ENTER_TCL \
251     { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
252         if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
253 
254 #define LEAVE_TCL \
255     tcl_tstate = NULL; \
256     if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
257 
258 #define ENTER_OVERLAP \
259     Py_END_ALLOW_THREADS
260 
261 #define LEAVE_OVERLAP_TCL \
262     tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); }
263 
264 #define ENTER_PYTHON \
265     { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
266         if(tcl_lock) \
267           PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
268 
269 #define LEAVE_PYTHON \
270     { PyThreadState *tstate = PyEval_SaveThread(); \
271         if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
272 
273 #define CHECK_TCL_APPARTMENT \
274     if (((TkappObject *)self)->threaded && \
275         ((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \
276         PyErr_SetString(PyExc_RuntimeError, \
277                         "Calling Tcl from different apartment"); \
278         return 0; \
279     }
280 
281 #ifndef FREECAST
282 #define FREECAST (char *)
283 #endif
284 
285 /**** Tkapp Object Declaration ****/
286 
287 static PyObject *Tkapp_Type;
288 
289 typedef struct {
290     PyObject_HEAD
291     Tcl_Interp *interp;
292     int wantobjects;
293     int threaded; /* True if tcl_platform[threaded] */
294     Tcl_ThreadId thread_id;
295     int dispatching;
296     /* We cannot include tclInt.h, as this is internal.
297        So we cache interesting types here. */
298     const Tcl_ObjType *OldBooleanType;
299     const Tcl_ObjType *BooleanType;
300     const Tcl_ObjType *ByteArrayType;
301     const Tcl_ObjType *DoubleType;
302     const Tcl_ObjType *IntType;
303     const Tcl_ObjType *WideIntType;
304     const Tcl_ObjType *BignumType;
305     const Tcl_ObjType *ListType;
306     const Tcl_ObjType *ProcBodyType;
307     const Tcl_ObjType *StringType;
308 } TkappObject;
309 
310 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
311 
312 #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \
313 (void *) v, Py_REFCNT(v)))
314 
315 
316 
317 /**** Error Handling ****/
318 
319 static PyObject *Tkinter_TclError;
320 static int quitMainLoop = 0;
321 static int errorInCmd = 0;
322 static PyObject *excInCmd;
323 static PyObject *valInCmd;
324 static PyObject *trbInCmd;
325 
326 #ifdef TKINTER_PROTECT_LOADTK
327 static int tk_load_failed = 0;
328 #endif
329 
330 
331 static PyObject *Tkapp_UnicodeResult(TkappObject *);
332 
333 static PyObject *
Tkinter_Error(TkappObject * self)334 Tkinter_Error(TkappObject *self)
335 {
336     PyObject *res = Tkapp_UnicodeResult(self);
337     if (res != NULL) {
338         PyErr_SetObject(Tkinter_TclError, res);
339         Py_DECREF(res);
340     }
341     return NULL;
342 }
343 
344 
345 
346 /**** Utils ****/
347 
348 static int Tkinter_busywaitinterval = 20;
349 
350 #ifndef MS_WINDOWS
351 
352 /* Millisecond sleep() for Unix platforms. */
353 
354 static void
Sleep(int milli)355 Sleep(int milli)
356 {
357     /* XXX Too bad if you don't have select(). */
358     struct timeval t;
359     t.tv_sec = milli/1000;
360     t.tv_usec = (milli%1000) * 1000;
361     select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
362 }
363 #endif /* MS_WINDOWS */
364 
365 /* Wait up to 1s for the mainloop to come up. */
366 
367 static int
WaitForMainloop(TkappObject * self)368 WaitForMainloop(TkappObject* self)
369 {
370     int i;
371     for (i = 0; i < 10; i++) {
372         if (self->dispatching)
373             return 1;
374         Py_BEGIN_ALLOW_THREADS
375         Sleep(100);
376         Py_END_ALLOW_THREADS
377     }
378     if (self->dispatching)
379         return 1;
380     PyErr_SetString(PyExc_RuntimeError, "main thread is not in main loop");
381     return 0;
382 }
383 
384 
385 
386 #define ARGSZ 64
387 
388 
389 
390 static PyObject *
unicodeFromTclStringAndSize(const char * s,Py_ssize_t size)391 unicodeFromTclStringAndSize(const char *s, Py_ssize_t size)
392 {
393     PyObject *r = PyUnicode_DecodeUTF8(s, size, NULL);
394     if (r != NULL || !PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
395         return r;
396     }
397 
398     char *buf = NULL;
399     PyErr_Clear();
400     /* Tcl encodes null character as \xc0\x80 */
401     if (memchr(s, '\xc0', size)) {
402         char *q;
403         const char *e = s + size;
404         q = buf = (char *)PyMem_Malloc(size);
405         if (buf == NULL) {
406             PyErr_NoMemory();
407             return NULL;
408         }
409         while (s != e) {
410             if (s + 1 != e && s[0] == '\xc0' && s[1] == '\x80') {
411                 *q++ = '\0';
412                 s += 2;
413             }
414             else
415                 *q++ = *s++;
416         }
417         s = buf;
418         size = q - s;
419     }
420     r = PyUnicode_DecodeUTF8(s, size, "surrogateescape");
421     if (buf != NULL) {
422         PyMem_Free(buf);
423     }
424     return r;
425 }
426 
427 static PyObject *
unicodeFromTclString(const char * s)428 unicodeFromTclString(const char *s)
429 {
430     return unicodeFromTclStringAndSize(s, strlen(s));
431 }
432 
433 static PyObject *
unicodeFromTclObj(Tcl_Obj * value)434 unicodeFromTclObj(Tcl_Obj *value)
435 {
436     int len;
437 #if USE_TCL_UNICODE
438     int byteorder = NATIVE_BYTEORDER;
439     const Tcl_UniChar *u = Tcl_GetUnicodeFromObj(value, &len);
440     if (sizeof(Tcl_UniChar) == 2)
441         return PyUnicode_DecodeUTF16((const char *)u, len * 2,
442                                      "surrogatepass", &byteorder);
443     else if (sizeof(Tcl_UniChar) == 4)
444         return PyUnicode_DecodeUTF32((const char *)u, len * 4,
445                                      "surrogatepass", &byteorder);
446     else
447         Py_UNREACHABLE();
448 #else
449     const char *s = Tcl_GetStringFromObj(value, &len);
450     return unicodeFromTclStringAndSize(s, len);
451 #endif
452 }
453 
454 
455 static PyObject *
Split(const char * list)456 Split(const char *list)
457 {
458     int argc;
459     const char **argv;
460     PyObject *v;
461 
462     if (list == NULL) {
463         Py_RETURN_NONE;
464     }
465 
466     if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
467         /* Not a list.
468          * Could be a quoted string containing funnies, e.g. {"}.
469          * Return the string itself.
470          */
471         return unicodeFromTclString(list);
472     }
473 
474     if (argc == 0)
475         v = PyUnicode_FromString("");
476     else if (argc == 1)
477         v = unicodeFromTclString(argv[0]);
478     else if ((v = PyTuple_New(argc)) != NULL) {
479         int i;
480         PyObject *w;
481 
482         for (i = 0; i < argc; i++) {
483             if ((w = Split(argv[i])) == NULL) {
484                 Py_DECREF(v);
485                 v = NULL;
486                 break;
487             }
488             PyTuple_SET_ITEM(v, i, w);
489         }
490     }
491     Tcl_Free(FREECAST argv);
492     return v;
493 }
494 
495 /* In some cases, Tcl will still return strings that are supposed to
496    be lists. SplitObj walks through a nested tuple, finding string
497    objects that need to be split. */
498 
499 static PyObject *
SplitObj(PyObject * arg)500 SplitObj(PyObject *arg)
501 {
502     if (PyTuple_Check(arg)) {
503         Py_ssize_t i, size;
504         PyObject *elem, *newelem, *result;
505 
506         size = PyTuple_GET_SIZE(arg);
507         result = NULL;
508         /* Recursively invoke SplitObj for all tuple items.
509            If this does not return a new object, no action is
510            needed. */
511         for(i = 0; i < size; i++) {
512             elem = PyTuple_GET_ITEM(arg, i);
513             newelem = SplitObj(elem);
514             if (!newelem) {
515                 Py_XDECREF(result);
516                 return NULL;
517             }
518             if (!result) {
519                 Py_ssize_t k;
520                 if (newelem == elem) {
521                     Py_DECREF(newelem);
522                     continue;
523                 }
524                 result = PyTuple_New(size);
525                 if (!result)
526                     return NULL;
527                 for(k = 0; k < i; k++) {
528                     elem = PyTuple_GET_ITEM(arg, k);
529                     Py_INCREF(elem);
530                     PyTuple_SET_ITEM(result, k, elem);
531                 }
532             }
533             PyTuple_SET_ITEM(result, i, newelem);
534         }
535         if (result)
536             return result;
537         /* Fall through, returning arg. */
538     }
539     else if (PyList_Check(arg)) {
540         Py_ssize_t i, size;
541         PyObject *elem, *newelem, *result;
542 
543         size = PyList_GET_SIZE(arg);
544         result = PyTuple_New(size);
545         if (!result)
546             return NULL;
547         /* Recursively invoke SplitObj for all list items. */
548         for(i = 0; i < size; i++) {
549             elem = PyList_GET_ITEM(arg, i);
550             newelem = SplitObj(elem);
551             if (!newelem) {
552                 Py_XDECREF(result);
553                 return NULL;
554             }
555             PyTuple_SET_ITEM(result, i, newelem);
556         }
557         return result;
558     }
559     else if (PyUnicode_Check(arg)) {
560         int argc;
561         const char **argv;
562         const char *list = PyUnicode_AsUTF8(arg);
563 
564         if (list == NULL ||
565             Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
566             Py_INCREF(arg);
567             return arg;
568         }
569         Tcl_Free(FREECAST argv);
570         if (argc > 1)
571             return Split(list);
572         /* Fall through, returning arg. */
573     }
574     else if (PyBytes_Check(arg)) {
575         int argc;
576         const char **argv;
577         char *list = PyBytes_AS_STRING(arg);
578 
579         if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
580             Py_INCREF(arg);
581             return arg;
582         }
583         Tcl_Free(FREECAST argv);
584         if (argc > 1)
585             return Split(PyBytes_AS_STRING(arg));
586         /* Fall through, returning arg. */
587     }
588     Py_INCREF(arg);
589     return arg;
590 }
591 
592 
593 /*[clinic input]
594 module _tkinter
595 class _tkinter.tkapp "TkappObject *" "&Tkapp_Type_spec"
596 class _tkinter.Tcl_Obj "PyTclObject *" "&PyTclObject_Type_spec"
597 class _tkinter.tktimertoken "TkttObject *" "&Tktt_Type_spec"
598 [clinic start generated code]*/
599 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=b1ebf15c162ee229]*/
600 
601 /**** Tkapp Object ****/
602 
603 #ifndef WITH_APPINIT
604 int
Tcl_AppInit(Tcl_Interp * interp)605 Tcl_AppInit(Tcl_Interp *interp)
606 {
607     const char * _tkinter_skip_tk_init;
608 
609     if (Tcl_Init(interp) == TCL_ERROR) {
610         PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp));
611         return TCL_ERROR;
612     }
613 
614     _tkinter_skip_tk_init = Tcl_GetVar(interp,
615                     "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY);
616     if (_tkinter_skip_tk_init != NULL &&
617                     strcmp(_tkinter_skip_tk_init, "1") == 0) {
618         return TCL_OK;
619     }
620 
621 #ifdef TKINTER_PROTECT_LOADTK
622     if (tk_load_failed) {
623         PySys_WriteStderr("Tk_Init error: %s\n", TKINTER_LOADTK_ERRMSG);
624         return TCL_ERROR;
625     }
626 #endif
627 
628     if (Tk_Init(interp) == TCL_ERROR) {
629 #ifdef TKINTER_PROTECT_LOADTK
630         tk_load_failed = 1;
631 #endif
632         PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
633         return TCL_ERROR;
634     }
635 
636     return TCL_OK;
637 }
638 #endif /* !WITH_APPINIT */
639 
640 
641 
642 
643 /* Initialize the Tk application; see the `main' function in
644  * `tkMain.c'.
645  */
646 
647 static void EnableEventHook(void); /* Forward */
648 static void DisableEventHook(void); /* Forward */
649 
650 static TkappObject *
Tkapp_New(const char * screenName,const char * className,int interactive,int wantobjects,int wantTk,int sync,const char * use)651 Tkapp_New(const char *screenName, const char *className,
652           int interactive, int wantobjects, int wantTk, int sync,
653           const char *use)
654 {
655     TkappObject *v;
656     char *argv0;
657 
658     v = PyObject_New(TkappObject, (PyTypeObject *) Tkapp_Type);
659     if (v == NULL)
660         return NULL;
661     Py_INCREF(Tkapp_Type);
662 
663     v->interp = Tcl_CreateInterp();
664     v->wantobjects = wantobjects;
665     v->threaded = Tcl_GetVar2Ex(v->interp, "tcl_platform", "threaded",
666                                 TCL_GLOBAL_ONLY) != NULL;
667     v->thread_id = Tcl_GetCurrentThread();
668     v->dispatching = 0;
669 
670 #ifndef TCL_THREADS
671     if (v->threaded) {
672         PyErr_SetString(PyExc_RuntimeError,
673                         "Tcl is threaded but _tkinter is not");
674         Py_DECREF(v);
675         return 0;
676     }
677 #endif
678     if (v->threaded && tcl_lock) {
679         /* If Tcl is threaded, we don't need the lock. */
680         PyThread_free_lock(tcl_lock);
681         tcl_lock = NULL;
682     }
683 
684     v->OldBooleanType = Tcl_GetObjType("boolean");
685     v->BooleanType = Tcl_GetObjType("booleanString");
686     v->ByteArrayType = Tcl_GetObjType("bytearray");
687     v->DoubleType = Tcl_GetObjType("double");
688     v->IntType = Tcl_GetObjType("int");
689     v->WideIntType = Tcl_GetObjType("wideInt");
690     v->BignumType = Tcl_GetObjType("bignum");
691     v->ListType = Tcl_GetObjType("list");
692     v->ProcBodyType = Tcl_GetObjType("procbody");
693     v->StringType = Tcl_GetObjType("string");
694 
695     /* Delete the 'exit' command, which can screw things up */
696     Tcl_DeleteCommand(v->interp, "exit");
697 
698     if (screenName != NULL)
699         Tcl_SetVar2(v->interp, "env", "DISPLAY",
700                     screenName, TCL_GLOBAL_ONLY);
701 
702     if (interactive)
703         Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
704     else
705         Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
706 
707     /* This is used to get the application class for Tk 4.1 and up */
708     argv0 = (char*)PyMem_Malloc(strlen(className) + 1);
709     if (!argv0) {
710         PyErr_NoMemory();
711         Py_DECREF(v);
712         return NULL;
713     }
714 
715     strcpy(argv0, className);
716     if (Py_ISUPPER(Py_CHARMASK(argv0[0])))
717         argv0[0] = Py_TOLOWER(Py_CHARMASK(argv0[0]));
718     Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY);
719     PyMem_Free(argv0);
720 
721     if (! wantTk) {
722         Tcl_SetVar(v->interp,
723                         "_tkinter_skip_tk_init", "1", TCL_GLOBAL_ONLY);
724     }
725 #ifdef TKINTER_PROTECT_LOADTK
726     else if (tk_load_failed) {
727         Tcl_SetVar(v->interp,
728                         "_tkinter_tk_failed", "1", TCL_GLOBAL_ONLY);
729     }
730 #endif
731 
732     /* some initial arguments need to be in argv */
733     if (sync || use) {
734         char *args;
735         Py_ssize_t len = 0;
736 
737         if (sync)
738             len += sizeof "-sync";
739         if (use)
740             len += strlen(use) + sizeof "-use ";  /* never overflows */
741 
742         args = (char*)PyMem_Malloc(len);
743         if (!args) {
744             PyErr_NoMemory();
745             Py_DECREF(v);
746             return NULL;
747         }
748 
749         args[0] = '\0';
750         if (sync)
751             strcat(args, "-sync");
752         if (use) {
753             if (sync)
754                 strcat(args, " ");
755             strcat(args, "-use ");
756             strcat(args, use);
757         }
758 
759         Tcl_SetVar(v->interp, "argv", args, TCL_GLOBAL_ONLY);
760         PyMem_Free(args);
761     }
762 
763 #ifdef MS_WINDOWS
764     {
765         PyObject *str_path;
766         PyObject *utf8_path;
767         DWORD ret;
768 
769         ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
770         if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
771             str_path = _get_tcl_lib_path();
772             if (str_path == NULL && PyErr_Occurred()) {
773                 return NULL;
774             }
775             if (str_path != NULL) {
776                 utf8_path = PyUnicode_AsUTF8String(str_path);
777                 if (utf8_path == NULL) {
778                     return NULL;
779                 }
780                 Tcl_SetVar(v->interp,
781                            "tcl_library",
782                            PyBytes_AS_STRING(utf8_path),
783                            TCL_GLOBAL_ONLY);
784                 Py_DECREF(utf8_path);
785             }
786         }
787     }
788 #endif
789 
790     if (Tcl_AppInit(v->interp) != TCL_OK) {
791         PyObject *result = Tkinter_Error(v);
792 #ifdef TKINTER_PROTECT_LOADTK
793         if (wantTk) {
794             const char *_tkinter_tk_failed;
795             _tkinter_tk_failed = Tcl_GetVar(v->interp,
796                             "_tkinter_tk_failed", TCL_GLOBAL_ONLY);
797 
798             if ( _tkinter_tk_failed != NULL &&
799                             strcmp(_tkinter_tk_failed, "1") == 0) {
800                 tk_load_failed = 1;
801             }
802         }
803 #endif
804         Py_DECREF((PyObject *)v);
805         return (TkappObject *)result;
806     }
807 
808     EnableEventHook();
809 
810     return v;
811 }
812 
813 
814 static void
Tkapp_ThreadSend(TkappObject * self,Tcl_Event * ev,Tcl_Condition * cond,Tcl_Mutex * mutex)815 Tkapp_ThreadSend(TkappObject *self, Tcl_Event *ev,
816                  Tcl_Condition *cond, Tcl_Mutex *mutex)
817 {
818     Py_BEGIN_ALLOW_THREADS;
819     Tcl_MutexLock(mutex);
820     Tcl_ThreadQueueEvent(self->thread_id, ev, TCL_QUEUE_TAIL);
821     Tcl_ThreadAlert(self->thread_id);
822     Tcl_ConditionWait(cond, mutex, NULL);
823     Tcl_MutexUnlock(mutex);
824     Py_END_ALLOW_THREADS
825 }
826 
827 
828 /** Tcl Eval **/
829 
830 typedef struct {
831     PyObject_HEAD
832     Tcl_Obj *value;
833     PyObject *string; /* This cannot cause cycles. */
834 } PyTclObject;
835 
836 static PyObject *PyTclObject_Type;
837 #define PyTclObject_Check(v) ((v)->ob_type == (PyTypeObject *) PyTclObject_Type)
838 
839 static PyObject *
newPyTclObject(Tcl_Obj * arg)840 newPyTclObject(Tcl_Obj *arg)
841 {
842     PyTclObject *self;
843     self = PyObject_New(PyTclObject, (PyTypeObject *) PyTclObject_Type);
844     if (self == NULL)
845         return NULL;
846     Py_INCREF(PyTclObject_Type);
847     Tcl_IncrRefCount(arg);
848     self->value = arg;
849     self->string = NULL;
850     return (PyObject*)self;
851 }
852 
853 static void
PyTclObject_dealloc(PyTclObject * self)854 PyTclObject_dealloc(PyTclObject *self)
855 {
856     PyObject *tp = (PyObject *) Py_TYPE(self);
857     Tcl_DecrRefCount(self->value);
858     Py_XDECREF(self->string);
859     PyObject_Del(self);
860     Py_DECREF(tp);
861 }
862 
863 /* Like _str, but create Unicode if necessary. */
864 PyDoc_STRVAR(PyTclObject_string__doc__,
865 "the string representation of this object, either as str or bytes");
866 
867 static PyObject *
PyTclObject_string(PyTclObject * self,void * ignored)868 PyTclObject_string(PyTclObject *self, void *ignored)
869 {
870     if (!self->string) {
871         self->string = unicodeFromTclObj(self->value);
872         if (!self->string)
873             return NULL;
874     }
875     Py_INCREF(self->string);
876     return self->string;
877 }
878 
879 static PyObject *
PyTclObject_str(PyTclObject * self)880 PyTclObject_str(PyTclObject *self)
881 {
882     if (self->string) {
883         Py_INCREF(self->string);
884         return self->string;
885     }
886     /* XXX Could chache result if it is non-ASCII. */
887     return unicodeFromTclObj(self->value);
888 }
889 
890 static PyObject *
PyTclObject_repr(PyTclObject * self)891 PyTclObject_repr(PyTclObject *self)
892 {
893     PyObject *repr, *str = PyTclObject_str(self);
894     if (str == NULL)
895         return NULL;
896     repr = PyUnicode_FromFormat("<%s object: %R>",
897                                 self->value->typePtr->name, str);
898     Py_DECREF(str);
899     return repr;
900 }
901 
902 static PyObject *
PyTclObject_richcompare(PyObject * self,PyObject * other,int op)903 PyTclObject_richcompare(PyObject *self, PyObject *other, int op)
904 {
905     int result;
906 
907     /* neither argument should be NULL, unless something's gone wrong */
908     if (self == NULL || other == NULL) {
909         PyErr_BadInternalCall();
910         return NULL;
911     }
912 
913     /* both arguments should be instances of PyTclObject */
914     if (!PyTclObject_Check(self) || !PyTclObject_Check(other)) {
915         Py_RETURN_NOTIMPLEMENTED;
916     }
917 
918     if (self == other)
919         /* fast path when self and other are identical */
920         result = 0;
921     else
922         result = strcmp(Tcl_GetString(((PyTclObject *)self)->value),
923                         Tcl_GetString(((PyTclObject *)other)->value));
924     Py_RETURN_RICHCOMPARE(result, 0, op);
925 }
926 
927 PyDoc_STRVAR(get_typename__doc__, "name of the Tcl type");
928 
929 static PyObject*
get_typename(PyTclObject * obj,void * ignored)930 get_typename(PyTclObject* obj, void* ignored)
931 {
932     return unicodeFromTclString(obj->value->typePtr->name);
933 }
934 
935 
936 static PyGetSetDef PyTclObject_getsetlist[] = {
937     {"typename", (getter)get_typename, NULL, get_typename__doc__},
938     {"string", (getter)PyTclObject_string, NULL,
939      PyTclObject_string__doc__},
940     {0},
941 };
942 
943 static PyType_Slot PyTclObject_Type_slots[] = {
944     {Py_tp_dealloc, (destructor)PyTclObject_dealloc},
945     {Py_tp_repr, (reprfunc)PyTclObject_repr},
946     {Py_tp_str, (reprfunc)PyTclObject_str},
947     {Py_tp_getattro, PyObject_GenericGetAttr},
948     {Py_tp_richcompare, PyTclObject_richcompare},
949     {Py_tp_getset, PyTclObject_getsetlist},
950     {0, 0}
951 };
952 
953 static PyType_Spec PyTclObject_Type_spec = {
954     "_tkinter.Tcl_Obj",
955     sizeof(PyTclObject),
956     0,
957     Py_TPFLAGS_DEFAULT,
958     PyTclObject_Type_slots,
959 };
960 
961 
962 #if SIZE_MAX > INT_MAX
963 #define CHECK_STRING_LENGTH(s) do {                                     \
964         if (s != NULL && strlen(s) >= INT_MAX) {                        \
965             PyErr_SetString(PyExc_OverflowError, "string is too long"); \
966             return NULL;                                                \
967         } } while(0)
968 #else
969 #define CHECK_STRING_LENGTH(s)
970 #endif
971 
972 #ifdef HAVE_LIBTOMMAMTH
973 static Tcl_Obj*
asBignumObj(PyObject * value)974 asBignumObj(PyObject *value)
975 {
976     Tcl_Obj *result;
977     int neg;
978     PyObject *hexstr;
979     const char *hexchars;
980     mp_int bigValue;
981 
982     neg = Py_SIZE(value) < 0;
983     hexstr = _PyLong_Format(value, 16);
984     if (hexstr == NULL)
985         return NULL;
986     hexchars = PyUnicode_AsUTF8(hexstr);
987     if (hexchars == NULL) {
988         Py_DECREF(hexstr);
989         return NULL;
990     }
991     hexchars += neg + 2; /* skip sign and "0x" */
992     mp_init(&bigValue);
993     if (mp_read_radix(&bigValue, hexchars, 16) != MP_OKAY) {
994         mp_clear(&bigValue);
995         Py_DECREF(hexstr);
996         PyErr_NoMemory();
997         return NULL;
998     }
999     Py_DECREF(hexstr);
1000     bigValue.sign = neg ? MP_NEG : MP_ZPOS;
1001     result = Tcl_NewBignumObj(&bigValue);
1002     mp_clear(&bigValue);
1003     if (result == NULL) {
1004         PyErr_NoMemory();
1005         return NULL;
1006     }
1007     return result;
1008 }
1009 #endif
1010 
1011 static Tcl_Obj*
AsObj(PyObject * value)1012 AsObj(PyObject *value)
1013 {
1014     Tcl_Obj *result;
1015 
1016     if (PyBytes_Check(value)) {
1017         if (PyBytes_GET_SIZE(value) >= INT_MAX) {
1018             PyErr_SetString(PyExc_OverflowError, "bytes object is too long");
1019             return NULL;
1020         }
1021         return Tcl_NewByteArrayObj((unsigned char *)PyBytes_AS_STRING(value),
1022                                    (int)PyBytes_GET_SIZE(value));
1023     }
1024 
1025     if (PyBool_Check(value))
1026         return Tcl_NewBooleanObj(PyObject_IsTrue(value));
1027 
1028     if (PyLong_CheckExact(value)) {
1029         int overflow;
1030         long longValue;
1031 #ifdef TCL_WIDE_INT_TYPE
1032         Tcl_WideInt wideValue;
1033 #endif
1034         longValue = PyLong_AsLongAndOverflow(value, &overflow);
1035         if (!overflow) {
1036             return Tcl_NewLongObj(longValue);
1037         }
1038         /* If there is an overflow in the long conversion,
1039            fall through to wideInt handling. */
1040 #ifdef TCL_WIDE_INT_TYPE
1041         if (_PyLong_AsByteArray((PyLongObject *)value,
1042                                 (unsigned char *)(void *)&wideValue,
1043                                 sizeof(wideValue),
1044                                 PY_LITTLE_ENDIAN,
1045                                 /* signed */ 1) == 0) {
1046             return Tcl_NewWideIntObj(wideValue);
1047         }
1048         PyErr_Clear();
1049 #endif
1050         /* If there is an overflow in the wideInt conversion,
1051            fall through to bignum handling. */
1052 #ifdef HAVE_LIBTOMMAMTH
1053         return asBignumObj(value);
1054 #endif
1055         /* If there is no wideInt or bignum support,
1056            fall through to default object handling. */
1057     }
1058 
1059     if (PyFloat_Check(value))
1060         return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
1061 
1062     if (PyTuple_Check(value) || PyList_Check(value)) {
1063         Tcl_Obj **argv;
1064         Py_ssize_t size, i;
1065 
1066         size = PySequence_Fast_GET_SIZE(value);
1067         if (size == 0)
1068             return Tcl_NewListObj(0, NULL);
1069         if (!CHECK_SIZE(size, sizeof(Tcl_Obj *))) {
1070             PyErr_SetString(PyExc_OverflowError,
1071                             PyTuple_Check(value) ? "tuple is too long" :
1072                                                    "list is too long");
1073             return NULL;
1074         }
1075         argv = (Tcl_Obj **) PyMem_Malloc(((size_t)size) * sizeof(Tcl_Obj *));
1076         if (!argv) {
1077           PyErr_NoMemory();
1078           return NULL;
1079         }
1080         for (i = 0; i < size; i++)
1081           argv[i] = AsObj(PySequence_Fast_GET_ITEM(value,i));
1082         result = Tcl_NewListObj((int)size, argv);
1083         PyMem_Free(argv);
1084         return result;
1085     }
1086 
1087     if (PyUnicode_Check(value)) {
1088         if (PyUnicode_READY(value) == -1)
1089             return NULL;
1090 
1091         Py_ssize_t size = PyUnicode_GET_LENGTH(value);
1092         if (size == 0) {
1093             return Tcl_NewStringObj("", 0);
1094         }
1095         if (!CHECK_SIZE(size, sizeof(Tcl_UniChar))) {
1096             PyErr_SetString(PyExc_OverflowError, "string is too long");
1097             return NULL;
1098         }
1099         if (PyUnicode_IS_ASCII(value)) {
1100             return Tcl_NewStringObj((const char *)PyUnicode_DATA(value),
1101                                     (int)size);
1102         }
1103 
1104         PyObject *encoded;
1105 #if USE_TCL_UNICODE
1106         if (sizeof(Tcl_UniChar) == 2)
1107             encoded = _PyUnicode_EncodeUTF16(value,
1108                     "surrogatepass", NATIVE_BYTEORDER);
1109         else if (sizeof(Tcl_UniChar) == 4)
1110             encoded = _PyUnicode_EncodeUTF32(value,
1111                     "surrogatepass", NATIVE_BYTEORDER);
1112         else
1113             Py_UNREACHABLE();
1114 #else
1115         encoded = _PyUnicode_AsUTF8String(value, "surrogateescape");
1116 #endif
1117         if (!encoded) {
1118             return NULL;
1119         }
1120         size = PyBytes_GET_SIZE(encoded);
1121         if (size > INT_MAX) {
1122             Py_DECREF(encoded);
1123             PyErr_SetString(PyExc_OverflowError, "string is too long");
1124             return NULL;
1125         }
1126 #if USE_TCL_UNICODE
1127         result = Tcl_NewUnicodeObj((const Tcl_UniChar *)PyBytes_AS_STRING(encoded),
1128                                    (int)(size / sizeof(Tcl_UniChar)));
1129 #else
1130         result = Tcl_NewStringObj(PyBytes_AS_STRING(encoded), (int)size);
1131 #endif
1132         Py_DECREF(encoded);
1133         return result;
1134     }
1135 
1136     if (PyTclObject_Check(value)) {
1137         return ((PyTclObject*)value)->value;
1138     }
1139 
1140     {
1141         PyObject *v = PyObject_Str(value);
1142         if (!v)
1143             return 0;
1144         result = AsObj(v);
1145         Py_DECREF(v);
1146         return result;
1147     }
1148 }
1149 
1150 static PyObject *
fromBoolean(TkappObject * tkapp,Tcl_Obj * value)1151 fromBoolean(TkappObject *tkapp, Tcl_Obj *value)
1152 {
1153     int boolValue;
1154     if (Tcl_GetBooleanFromObj(Tkapp_Interp(tkapp), value, &boolValue) == TCL_ERROR)
1155         return Tkinter_Error(tkapp);
1156     return PyBool_FromLong(boolValue);
1157 }
1158 
1159 static PyObject*
fromWideIntObj(TkappObject * tkapp,Tcl_Obj * value)1160 fromWideIntObj(TkappObject *tkapp, Tcl_Obj *value)
1161 {
1162         Tcl_WideInt wideValue;
1163         if (Tcl_GetWideIntFromObj(Tkapp_Interp(tkapp), value, &wideValue) == TCL_OK) {
1164             if (sizeof(wideValue) <= SIZEOF_LONG_LONG)
1165                 return PyLong_FromLongLong(wideValue);
1166             return _PyLong_FromByteArray((unsigned char *)(void *)&wideValue,
1167                                          sizeof(wideValue),
1168                                          PY_LITTLE_ENDIAN,
1169                                          /* signed */ 1);
1170         }
1171         return NULL;
1172 }
1173 
1174 #ifdef HAVE_LIBTOMMAMTH
1175 static PyObject*
fromBignumObj(TkappObject * tkapp,Tcl_Obj * value)1176 fromBignumObj(TkappObject *tkapp, Tcl_Obj *value)
1177 {
1178     mp_int bigValue;
1179     unsigned long numBytes;
1180     unsigned char *bytes;
1181     PyObject *res;
1182 
1183     if (Tcl_GetBignumFromObj(Tkapp_Interp(tkapp), value, &bigValue) != TCL_OK)
1184         return Tkinter_Error(tkapp);
1185     numBytes = mp_unsigned_bin_size(&bigValue);
1186     bytes = PyMem_Malloc(numBytes);
1187     if (bytes == NULL) {
1188         mp_clear(&bigValue);
1189         return PyErr_NoMemory();
1190     }
1191     if (mp_to_unsigned_bin_n(&bigValue, bytes,
1192                                 &numBytes) != MP_OKAY) {
1193         mp_clear(&bigValue);
1194         PyMem_Free(bytes);
1195         return PyErr_NoMemory();
1196     }
1197     res = _PyLong_FromByteArray(bytes, numBytes,
1198                                 /* big-endian */ 0,
1199                                 /* unsigned */ 0);
1200     PyMem_Free(bytes);
1201     if (res != NULL && bigValue.sign == MP_NEG) {
1202         PyObject *res2 = PyNumber_Negative(res);
1203         Py_DECREF(res);
1204         res = res2;
1205     }
1206     mp_clear(&bigValue);
1207     return res;
1208 }
1209 #endif
1210 
1211 static PyObject*
FromObj(TkappObject * tkapp,Tcl_Obj * value)1212 FromObj(TkappObject *tkapp, Tcl_Obj *value)
1213 {
1214     PyObject *result = NULL;
1215     Tcl_Interp *interp = Tkapp_Interp(tkapp);
1216 
1217     if (value->typePtr == NULL) {
1218         return unicodeFromTclObj(value);
1219     }
1220 
1221     if (value->typePtr == tkapp->BooleanType ||
1222         value->typePtr == tkapp->OldBooleanType) {
1223         return fromBoolean(tkapp, value);
1224     }
1225 
1226     if (value->typePtr == tkapp->ByteArrayType) {
1227         int size;
1228         char *data = (char*)Tcl_GetByteArrayFromObj(value, &size);
1229         return PyBytes_FromStringAndSize(data, size);
1230     }
1231 
1232     if (value->typePtr == tkapp->DoubleType) {
1233         return PyFloat_FromDouble(value->internalRep.doubleValue);
1234     }
1235 
1236     if (value->typePtr == tkapp->IntType) {
1237         long longValue;
1238         if (Tcl_GetLongFromObj(interp, value, &longValue) == TCL_OK)
1239             return PyLong_FromLong(longValue);
1240         /* If there is an error in the long conversion,
1241            fall through to wideInt handling. */
1242     }
1243 
1244     if (value->typePtr == tkapp->IntType ||
1245         value->typePtr == tkapp->WideIntType) {
1246         result = fromWideIntObj(tkapp, value);
1247         if (result != NULL || PyErr_Occurred())
1248             return result;
1249         Tcl_ResetResult(interp);
1250         /* If there is an error in the wideInt conversion,
1251            fall through to bignum handling. */
1252     }
1253 
1254 #ifdef HAVE_LIBTOMMAMTH
1255     if (value->typePtr == tkapp->IntType ||
1256         value->typePtr == tkapp->WideIntType ||
1257         value->typePtr == tkapp->BignumType) {
1258         return fromBignumObj(tkapp, value);
1259     }
1260 #endif
1261 
1262     if (value->typePtr == tkapp->ListType) {
1263         int size;
1264         int i, status;
1265         PyObject *elem;
1266         Tcl_Obj *tcl_elem;
1267 
1268         status = Tcl_ListObjLength(interp, value, &size);
1269         if (status == TCL_ERROR)
1270             return Tkinter_Error(tkapp);
1271         result = PyTuple_New(size);
1272         if (!result)
1273             return NULL;
1274         for (i = 0; i < size; i++) {
1275             status = Tcl_ListObjIndex(interp, value, i, &tcl_elem);
1276             if (status == TCL_ERROR) {
1277                 Py_DECREF(result);
1278                 return Tkinter_Error(tkapp);
1279             }
1280             elem = FromObj(tkapp, tcl_elem);
1281             if (!elem) {
1282                 Py_DECREF(result);
1283                 return NULL;
1284             }
1285             PyTuple_SET_ITEM(result, i, elem);
1286         }
1287         return result;
1288     }
1289 
1290     if (value->typePtr == tkapp->ProcBodyType) {
1291       /* fall through: return tcl object. */
1292     }
1293 
1294     if (value->typePtr == tkapp->StringType) {
1295         return unicodeFromTclObj(value);
1296     }
1297 
1298 #if TK_HEX_VERSION >= 0x08050000
1299     if (tkapp->BooleanType == NULL &&
1300         strcmp(value->typePtr->name, "booleanString") == 0) {
1301         /* booleanString type is not registered in Tcl */
1302         tkapp->BooleanType = value->typePtr;
1303         return fromBoolean(tkapp, value);
1304     }
1305 #endif
1306 
1307 #ifdef HAVE_LIBTOMMAMTH
1308     if (tkapp->BignumType == NULL &&
1309         strcmp(value->typePtr->name, "bignum") == 0) {
1310         /* bignum type is not registered in Tcl */
1311         tkapp->BignumType = value->typePtr;
1312         return fromBignumObj(tkapp, value);
1313     }
1314 #endif
1315 
1316     return newPyTclObject(value);
1317 }
1318 
1319 /* This mutex synchronizes inter-thread command calls. */
1320 TCL_DECLARE_MUTEX(call_mutex)
1321 
1322 typedef struct Tkapp_CallEvent {
1323     Tcl_Event ev;            /* Must be first */
1324     TkappObject *self;
1325     PyObject *args;
1326     int flags;
1327     PyObject **res;
1328     PyObject **exc_type, **exc_value, **exc_tb;
1329     Tcl_Condition *done;
1330 } Tkapp_CallEvent;
1331 
1332 void
Tkapp_CallDeallocArgs(Tcl_Obj ** objv,Tcl_Obj ** objStore,int objc)1333 Tkapp_CallDeallocArgs(Tcl_Obj** objv, Tcl_Obj** objStore, int objc)
1334 {
1335     int i;
1336     for (i = 0; i < objc; i++)
1337         Tcl_DecrRefCount(objv[i]);
1338     if (objv != objStore)
1339         PyMem_Free(objv);
1340 }
1341 
1342 /* Convert Python objects to Tcl objects. This must happen in the
1343    interpreter thread, which may or may not be the calling thread. */
1344 
1345 static Tcl_Obj**
Tkapp_CallArgs(PyObject * args,Tcl_Obj ** objStore,int * pobjc)1346 Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc)
1347 {
1348     Tcl_Obj **objv = objStore;
1349     Py_ssize_t objc = 0, i;
1350     if (args == NULL)
1351         /* do nothing */;
1352 
1353     else if (!(PyTuple_Check(args) || PyList_Check(args))) {
1354         objv[0] = AsObj(args);
1355         if (objv[0] == NULL)
1356             goto finally;
1357         objc = 1;
1358         Tcl_IncrRefCount(objv[0]);
1359     }
1360     else {
1361         objc = PySequence_Fast_GET_SIZE(args);
1362 
1363         if (objc > ARGSZ) {
1364             if (!CHECK_SIZE(objc, sizeof(Tcl_Obj *))) {
1365                 PyErr_SetString(PyExc_OverflowError,
1366                                 PyTuple_Check(args) ? "tuple is too long" :
1367                                                       "list is too long");
1368                 return NULL;
1369             }
1370             objv = (Tcl_Obj **)PyMem_Malloc(((size_t)objc) * sizeof(Tcl_Obj *));
1371             if (objv == NULL) {
1372                 PyErr_NoMemory();
1373                 objc = 0;
1374                 goto finally;
1375             }
1376         }
1377 
1378         for (i = 0; i < objc; i++) {
1379             PyObject *v = PySequence_Fast_GET_ITEM(args, i);
1380             if (v == Py_None) {
1381                 objc = i;
1382                 break;
1383             }
1384             objv[i] = AsObj(v);
1385             if (!objv[i]) {
1386                 /* Reset objc, so it attempts to clear
1387                    objects only up to i. */
1388                 objc = i;
1389                 goto finally;
1390             }
1391             Tcl_IncrRefCount(objv[i]);
1392         }
1393     }
1394     *pobjc = (int)objc;
1395     return objv;
1396 finally:
1397     Tkapp_CallDeallocArgs(objv, objStore, (int)objc);
1398     return NULL;
1399 }
1400 
1401 /* Convert the results of a command call into a Python string. */
1402 
1403 static PyObject *
Tkapp_UnicodeResult(TkappObject * self)1404 Tkapp_UnicodeResult(TkappObject *self)
1405 {
1406     return unicodeFromTclObj(Tcl_GetObjResult(self->interp));
1407 }
1408 
1409 
1410 /* Convert the results of a command call into a Python objects. */
1411 
1412 static PyObject *
Tkapp_ObjectResult(TkappObject * self)1413 Tkapp_ObjectResult(TkappObject *self)
1414 {
1415     PyObject *res = NULL;
1416     Tcl_Obj *value = Tcl_GetObjResult(self->interp);
1417     if (self->wantobjects) {
1418         /* Not sure whether the IncrRef is necessary, but something
1419            may overwrite the interpreter result while we are
1420            converting it. */
1421         Tcl_IncrRefCount(value);
1422         res = FromObj(self, value);
1423         Tcl_DecrRefCount(value);
1424     } else {
1425         res = unicodeFromTclObj(value);
1426     }
1427     return res;
1428 }
1429 
1430 
1431 /* Tkapp_CallProc is the event procedure that is executed in the context of
1432    the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't
1433    hold the Python lock. */
1434 
1435 static int
Tkapp_CallProc(Tkapp_CallEvent * e,int flags)1436 Tkapp_CallProc(Tkapp_CallEvent *e, int flags)
1437 {
1438     Tcl_Obj *objStore[ARGSZ];
1439     Tcl_Obj **objv;
1440     int objc;
1441     int i;
1442     ENTER_PYTHON
1443     objv = Tkapp_CallArgs(e->args, objStore, &objc);
1444     if (!objv) {
1445         PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb);
1446         *(e->res) = NULL;
1447     }
1448     LEAVE_PYTHON
1449     if (!objv)
1450         goto done;
1451     i = Tcl_EvalObjv(e->self->interp, objc, objv, e->flags);
1452     ENTER_PYTHON
1453     if (i == TCL_ERROR) {
1454         *(e->res) = Tkinter_Error(e->self);
1455     }
1456     else {
1457         *(e->res) = Tkapp_ObjectResult(e->self);
1458     }
1459     if (*(e->res) == NULL) {
1460         PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb);
1461     }
1462     LEAVE_PYTHON
1463 
1464     Tkapp_CallDeallocArgs(objv, objStore, objc);
1465 done:
1466     /* Wake up calling thread. */
1467     Tcl_MutexLock(&call_mutex);
1468     Tcl_ConditionNotify(e->done);
1469     Tcl_MutexUnlock(&call_mutex);
1470     return 1;
1471 }
1472 
1473 
1474 /* This is the main entry point for calling a Tcl command.
1475    It supports three cases, with regard to threading:
1476    1. Tcl is not threaded: Must have the Tcl lock, then can invoke command in
1477       the context of the calling thread.
1478    2. Tcl is threaded, caller of the command is in the interpreter thread:
1479       Execute the command in the calling thread. Since the Tcl lock will
1480       not be used, we can merge that with case 1.
1481    3. Tcl is threaded, caller is in a different thread: Must queue an event to
1482       the interpreter thread. Allocation of Tcl objects needs to occur in the
1483       interpreter thread, so we ship the PyObject* args to the target thread,
1484       and perform processing there. */
1485 
1486 static PyObject *
Tkapp_Call(PyObject * selfptr,PyObject * args)1487 Tkapp_Call(PyObject *selfptr, PyObject *args)
1488 {
1489     Tcl_Obj *objStore[ARGSZ];
1490     Tcl_Obj **objv = NULL;
1491     int objc, i;
1492     PyObject *res = NULL;
1493     TkappObject *self = (TkappObject*)selfptr;
1494     int flags = TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL;
1495 
1496     /* If args is a single tuple, replace with contents of tuple */
1497     if (PyTuple_GET_SIZE(args) == 1) {
1498         PyObject *item = PyTuple_GET_ITEM(args, 0);
1499         if (PyTuple_Check(item))
1500             args = item;
1501     }
1502     if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
1503         /* We cannot call the command directly. Instead, we must
1504            marshal the parameters to the interpreter thread. */
1505         Tkapp_CallEvent *ev;
1506         Tcl_Condition cond = NULL;
1507         PyObject *exc_type, *exc_value, *exc_tb;
1508         if (!WaitForMainloop(self))
1509             return NULL;
1510         ev = (Tkapp_CallEvent*)attemptckalloc(sizeof(Tkapp_CallEvent));
1511         if (ev == NULL) {
1512             PyErr_NoMemory();
1513             return NULL;
1514         }
1515         ev->ev.proc = (Tcl_EventProc*)Tkapp_CallProc;
1516         ev->self = self;
1517         ev->args = args;
1518         ev->res = &res;
1519         ev->exc_type = &exc_type;
1520         ev->exc_value = &exc_value;
1521         ev->exc_tb = &exc_tb;
1522         ev->done = &cond;
1523 
1524         Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &call_mutex);
1525 
1526         if (res == NULL) {
1527             if (exc_type)
1528                 PyErr_Restore(exc_type, exc_value, exc_tb);
1529             else
1530                 PyErr_SetObject(Tkinter_TclError, exc_value);
1531         }
1532         Tcl_ConditionFinalize(&cond);
1533     }
1534     else
1535     {
1536 
1537         objv = Tkapp_CallArgs(args, objStore, &objc);
1538         if (!objv)
1539             return NULL;
1540 
1541         ENTER_TCL
1542 
1543         i = Tcl_EvalObjv(self->interp, objc, objv, flags);
1544 
1545         ENTER_OVERLAP
1546 
1547         if (i == TCL_ERROR)
1548             Tkinter_Error(self);
1549         else
1550             res = Tkapp_ObjectResult(self);
1551 
1552         LEAVE_OVERLAP_TCL
1553 
1554         Tkapp_CallDeallocArgs(objv, objStore, objc);
1555     }
1556     return res;
1557 }
1558 
1559 
1560 /*[clinic input]
1561 _tkinter.tkapp.eval
1562 
1563     script: str
1564     /
1565 
1566 [clinic start generated code]*/
1567 
1568 static PyObject *
_tkinter_tkapp_eval_impl(TkappObject * self,const char * script)1569 _tkinter_tkapp_eval_impl(TkappObject *self, const char *script)
1570 /*[clinic end generated code: output=24b79831f700dea0 input=481484123a455f22]*/
1571 {
1572     PyObject *res = NULL;
1573     int err;
1574 
1575     CHECK_STRING_LENGTH(script);
1576     CHECK_TCL_APPARTMENT;
1577 
1578     ENTER_TCL
1579     err = Tcl_Eval(Tkapp_Interp(self), script);
1580     ENTER_OVERLAP
1581     if (err == TCL_ERROR)
1582         res = Tkinter_Error(self);
1583     else
1584         res = Tkapp_UnicodeResult(self);
1585     LEAVE_OVERLAP_TCL
1586     return res;
1587 }
1588 
1589 /*[clinic input]
1590 _tkinter.tkapp.evalfile
1591 
1592     fileName: str
1593     /
1594 
1595 [clinic start generated code]*/
1596 
1597 static PyObject *
_tkinter_tkapp_evalfile_impl(TkappObject * self,const char * fileName)1598 _tkinter_tkapp_evalfile_impl(TkappObject *self, const char *fileName)
1599 /*[clinic end generated code: output=63be88dcee4f11d3 input=873ab707e5e947e1]*/
1600 {
1601     PyObject *res = NULL;
1602     int err;
1603 
1604     CHECK_STRING_LENGTH(fileName);
1605     CHECK_TCL_APPARTMENT;
1606 
1607     ENTER_TCL
1608     err = Tcl_EvalFile(Tkapp_Interp(self), fileName);
1609     ENTER_OVERLAP
1610     if (err == TCL_ERROR)
1611         res = Tkinter_Error(self);
1612     else
1613         res = Tkapp_UnicodeResult(self);
1614     LEAVE_OVERLAP_TCL
1615     return res;
1616 }
1617 
1618 /*[clinic input]
1619 _tkinter.tkapp.record
1620 
1621     script: str
1622     /
1623 
1624 [clinic start generated code]*/
1625 
1626 static PyObject *
_tkinter_tkapp_record_impl(TkappObject * self,const char * script)1627 _tkinter_tkapp_record_impl(TkappObject *self, const char *script)
1628 /*[clinic end generated code: output=0ffe08a0061730df input=c0b0db5a21412cac]*/
1629 {
1630     PyObject *res = NULL;
1631     int err;
1632 
1633     CHECK_STRING_LENGTH(script);
1634     CHECK_TCL_APPARTMENT;
1635 
1636     ENTER_TCL
1637     err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL);
1638     ENTER_OVERLAP
1639     if (err == TCL_ERROR)
1640         res = Tkinter_Error(self);
1641     else
1642         res = Tkapp_UnicodeResult(self);
1643     LEAVE_OVERLAP_TCL
1644     return res;
1645 }
1646 
1647 /*[clinic input]
1648 _tkinter.tkapp.adderrorinfo
1649 
1650     msg: str
1651     /
1652 
1653 [clinic start generated code]*/
1654 
1655 static PyObject *
_tkinter_tkapp_adderrorinfo_impl(TkappObject * self,const char * msg)1656 _tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg)
1657 /*[clinic end generated code: output=52162eaca2ee53cb input=f4b37aec7c7e8c77]*/
1658 {
1659     CHECK_STRING_LENGTH(msg);
1660     CHECK_TCL_APPARTMENT;
1661 
1662     ENTER_TCL
1663     Tcl_AddErrorInfo(Tkapp_Interp(self), msg);
1664     LEAVE_TCL
1665 
1666     Py_RETURN_NONE;
1667 }
1668 
1669 
1670 
1671 /** Tcl Variable **/
1672 
1673 typedef PyObject* (*EventFunc)(TkappObject *, PyObject *, int);
1674 
1675 TCL_DECLARE_MUTEX(var_mutex)
1676 
1677 typedef struct VarEvent {
1678     Tcl_Event ev; /* must be first */
1679     TkappObject *self;
1680     PyObject *args;
1681     int flags;
1682     EventFunc func;
1683     PyObject **res;
1684     PyObject **exc_type;
1685     PyObject **exc_val;
1686     Tcl_Condition *cond;
1687 } VarEvent;
1688 
1689 /*[python]
1690 
1691 class varname_converter(CConverter):
1692     type = 'const char *'
1693     converter = 'varname_converter'
1694 
1695 [python]*/
1696 /*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
1697 
1698 static int
varname_converter(PyObject * in,void * _out)1699 varname_converter(PyObject *in, void *_out)
1700 {
1701     const char *s;
1702     const char **out = (const char**)_out;
1703     if (PyBytes_Check(in)) {
1704         if (PyBytes_GET_SIZE(in) > INT_MAX) {
1705             PyErr_SetString(PyExc_OverflowError, "bytes object is too long");
1706             return 0;
1707         }
1708         s = PyBytes_AS_STRING(in);
1709         if (strlen(s) != (size_t)PyBytes_GET_SIZE(in)) {
1710             PyErr_SetString(PyExc_ValueError, "embedded null byte");
1711             return 0;
1712         }
1713         *out = s;
1714         return 1;
1715     }
1716     if (PyUnicode_Check(in)) {
1717         Py_ssize_t size;
1718         s = PyUnicode_AsUTF8AndSize(in, &size);
1719         if (s == NULL) {
1720             return 0;
1721         }
1722         if (size > INT_MAX) {
1723             PyErr_SetString(PyExc_OverflowError, "string is too long");
1724             return 0;
1725         }
1726         if (strlen(s) != (size_t)size) {
1727             PyErr_SetString(PyExc_ValueError, "embedded null character");
1728             return 0;
1729         }
1730         *out = s;
1731         return 1;
1732     }
1733     if (PyTclObject_Check(in)) {
1734         *out = Tcl_GetString(((PyTclObject *)in)->value);
1735         return 1;
1736     }
1737     PyErr_Format(PyExc_TypeError,
1738                  "must be str, bytes or Tcl_Obj, not %.50s",
1739                  in->ob_type->tp_name);
1740     return 0;
1741 }
1742 
1743 
1744 static void
var_perform(VarEvent * ev)1745 var_perform(VarEvent *ev)
1746 {
1747     *(ev->res) = ev->func(ev->self, ev->args, ev->flags);
1748     if (!*(ev->res)) {
1749         PyObject *exc, *val, *tb;
1750         PyErr_Fetch(&exc, &val, &tb);
1751         PyErr_NormalizeException(&exc, &val, &tb);
1752         *(ev->exc_type) = exc;
1753         *(ev->exc_val) = val;
1754         Py_XDECREF(tb);
1755     }
1756 
1757 }
1758 
1759 static int
var_proc(VarEvent * ev,int flags)1760 var_proc(VarEvent* ev, int flags)
1761 {
1762     ENTER_PYTHON
1763     var_perform(ev);
1764     Tcl_MutexLock(&var_mutex);
1765     Tcl_ConditionNotify(ev->cond);
1766     Tcl_MutexUnlock(&var_mutex);
1767     LEAVE_PYTHON
1768     return 1;
1769 }
1770 
1771 
1772 static PyObject*
var_invoke(EventFunc func,PyObject * selfptr,PyObject * args,int flags)1773 var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags)
1774 {
1775     TkappObject *self = (TkappObject*)selfptr;
1776     if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
1777         VarEvent *ev;
1778         PyObject *res, *exc_type, *exc_val;
1779         Tcl_Condition cond = NULL;
1780 
1781         /* The current thread is not the interpreter thread.  Marshal
1782            the call to the interpreter thread, then wait for
1783            completion. */
1784         if (!WaitForMainloop(self))
1785             return NULL;
1786 
1787         ev = (VarEvent*)attemptckalloc(sizeof(VarEvent));
1788         if (ev == NULL) {
1789             PyErr_NoMemory();
1790             return NULL;
1791         }
1792         ev->self = self;
1793         ev->args = args;
1794         ev->flags = flags;
1795         ev->func = func;
1796         ev->res = &res;
1797         ev->exc_type = &exc_type;
1798         ev->exc_val = &exc_val;
1799         ev->cond = &cond;
1800         ev->ev.proc = (Tcl_EventProc*)var_proc;
1801         Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &var_mutex);
1802         Tcl_ConditionFinalize(&cond);
1803         if (!res) {
1804             PyErr_SetObject(exc_type, exc_val);
1805             Py_DECREF(exc_type);
1806             Py_DECREF(exc_val);
1807             return NULL;
1808         }
1809         return res;
1810     }
1811     /* Tcl is not threaded, or this is the interpreter thread. */
1812     return func(self, args, flags);
1813 }
1814 
1815 static PyObject *
SetVar(TkappObject * self,PyObject * args,int flags)1816 SetVar(TkappObject *self, PyObject *args, int flags)
1817 {
1818     const char *name1, *name2;
1819     PyObject *newValue;
1820     PyObject *res = NULL;
1821     Tcl_Obj *newval, *ok;
1822 
1823     switch (PyTuple_GET_SIZE(args)) {
1824     case 2:
1825         if (!PyArg_ParseTuple(args, "O&O:setvar",
1826                               varname_converter, &name1, &newValue))
1827             return NULL;
1828         /* XXX Acquire tcl lock??? */
1829         newval = AsObj(newValue);
1830         if (newval == NULL)
1831             return NULL;
1832         ENTER_TCL
1833         ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, NULL,
1834                            newval, flags);
1835         ENTER_OVERLAP
1836         if (!ok)
1837             Tkinter_Error(self);
1838         else {
1839             res = Py_None;
1840             Py_INCREF(res);
1841         }
1842         LEAVE_OVERLAP_TCL
1843         break;
1844     case 3:
1845         if (!PyArg_ParseTuple(args, "ssO:setvar",
1846                               &name1, &name2, &newValue))
1847             return NULL;
1848         CHECK_STRING_LENGTH(name1);
1849         CHECK_STRING_LENGTH(name2);
1850         /* XXX must hold tcl lock already??? */
1851         newval = AsObj(newValue);
1852         ENTER_TCL
1853         ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, name2, newval, flags);
1854         ENTER_OVERLAP
1855         if (!ok)
1856             Tkinter_Error(self);
1857         else {
1858             res = Py_None;
1859             Py_INCREF(res);
1860         }
1861         LEAVE_OVERLAP_TCL
1862         break;
1863     default:
1864         PyErr_SetString(PyExc_TypeError, "setvar requires 2 to 3 arguments");
1865         return NULL;
1866     }
1867     return res;
1868 }
1869 
1870 static PyObject *
Tkapp_SetVar(PyObject * self,PyObject * args)1871 Tkapp_SetVar(PyObject *self, PyObject *args)
1872 {
1873     return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG);
1874 }
1875 
1876 static PyObject *
Tkapp_GlobalSetVar(PyObject * self,PyObject * args)1877 Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
1878 {
1879     return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1880 }
1881 
1882 
1883 
1884 static PyObject *
GetVar(TkappObject * self,PyObject * args,int flags)1885 GetVar(TkappObject *self, PyObject *args, int flags)
1886 {
1887     const char *name1, *name2=NULL;
1888     PyObject *res = NULL;
1889     Tcl_Obj *tres;
1890 
1891     if (!PyArg_ParseTuple(args, "O&|s:getvar",
1892                           varname_converter, &name1, &name2))
1893         return NULL;
1894 
1895     CHECK_STRING_LENGTH(name2);
1896     ENTER_TCL
1897     tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags);
1898     ENTER_OVERLAP
1899     if (tres == NULL) {
1900         Tkinter_Error(self);
1901     } else {
1902         if (self->wantobjects) {
1903             res = FromObj(self, tres);
1904         }
1905         else {
1906             res = unicodeFromTclObj(tres);
1907         }
1908     }
1909     LEAVE_OVERLAP_TCL
1910     return res;
1911 }
1912 
1913 static PyObject *
Tkapp_GetVar(PyObject * self,PyObject * args)1914 Tkapp_GetVar(PyObject *self, PyObject *args)
1915 {
1916     return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG);
1917 }
1918 
1919 static PyObject *
Tkapp_GlobalGetVar(PyObject * self,PyObject * args)1920 Tkapp_GlobalGetVar(PyObject *self, PyObject *args)
1921 {
1922     return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1923 }
1924 
1925 
1926 
1927 static PyObject *
UnsetVar(TkappObject * self,PyObject * args,int flags)1928 UnsetVar(TkappObject *self, PyObject *args, int flags)
1929 {
1930     char *name1, *name2=NULL;
1931     int code;
1932     PyObject *res = NULL;
1933 
1934     if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
1935         return NULL;
1936 
1937     CHECK_STRING_LENGTH(name1);
1938     CHECK_STRING_LENGTH(name2);
1939     ENTER_TCL
1940     code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
1941     ENTER_OVERLAP
1942     if (code == TCL_ERROR)
1943         res = Tkinter_Error(self);
1944     else {
1945         Py_INCREF(Py_None);
1946         res = Py_None;
1947     }
1948     LEAVE_OVERLAP_TCL
1949     return res;
1950 }
1951 
1952 static PyObject *
Tkapp_UnsetVar(PyObject * self,PyObject * args)1953 Tkapp_UnsetVar(PyObject *self, PyObject *args)
1954 {
1955     return var_invoke(UnsetVar, self, args, TCL_LEAVE_ERR_MSG);
1956 }
1957 
1958 static PyObject *
Tkapp_GlobalUnsetVar(PyObject * self,PyObject * args)1959 Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args)
1960 {
1961     return var_invoke(UnsetVar, self, args,
1962                       TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1963 }
1964 
1965 
1966 
1967 /** Tcl to Python **/
1968 
1969 /*[clinic input]
1970 _tkinter.tkapp.getint
1971 
1972     arg: object
1973     /
1974 
1975 [clinic start generated code]*/
1976 
1977 static PyObject *
_tkinter_tkapp_getint(TkappObject * self,PyObject * arg)1978 _tkinter_tkapp_getint(TkappObject *self, PyObject *arg)
1979 /*[clinic end generated code: output=88cf293fae307cfe input=034026997c5b91f8]*/
1980 {
1981     char *s;
1982     Tcl_Obj *value;
1983     PyObject *result;
1984 
1985     if (PyLong_Check(arg)) {
1986         Py_INCREF(arg);
1987         return arg;
1988     }
1989 
1990     if (PyTclObject_Check(arg)) {
1991         value = ((PyTclObject*)arg)->value;
1992         Tcl_IncrRefCount(value);
1993     }
1994     else {
1995         if (!PyArg_Parse(arg, "s:getint", &s))
1996             return NULL;
1997         CHECK_STRING_LENGTH(s);
1998         value = Tcl_NewStringObj(s, -1);
1999         if (value == NULL)
2000             return Tkinter_Error(self);
2001     }
2002     /* Don't use Tcl_GetInt() because it returns ambiguous result for value
2003        in ranges -2**32..-2**31-1 and 2**31..2**32-1 (on 32-bit platform).
2004 
2005        Prefer bignum because Tcl_GetWideIntFromObj returns ambiguous result for
2006        value in ranges -2**64..-2**63-1 and 2**63..2**64-1 (on 32-bit platform).
2007      */
2008 #ifdef HAVE_LIBTOMMAMTH
2009     result = fromBignumObj(self, value);
2010 #else
2011     result = fromWideIntObj(self, value);
2012 #endif
2013     Tcl_DecrRefCount(value);
2014     if (result != NULL || PyErr_Occurred())
2015         return result;
2016     return Tkinter_Error(self);
2017 }
2018 
2019 /*[clinic input]
2020 _tkinter.tkapp.getdouble
2021 
2022     arg: object
2023     /
2024 
2025 [clinic start generated code]*/
2026 
2027 static PyObject *
_tkinter_tkapp_getdouble(TkappObject * self,PyObject * arg)2028 _tkinter_tkapp_getdouble(TkappObject *self, PyObject *arg)
2029 /*[clinic end generated code: output=c52b138bd8b956b9 input=22015729ce9ef7f8]*/
2030 {
2031     char *s;
2032     double v;
2033 
2034     if (PyFloat_Check(arg)) {
2035         Py_INCREF(arg);
2036         return arg;
2037     }
2038 
2039     if (PyNumber_Check(arg)) {
2040         return PyNumber_Float(arg);
2041     }
2042 
2043     if (PyTclObject_Check(arg)) {
2044         if (Tcl_GetDoubleFromObj(Tkapp_Interp(self),
2045                                  ((PyTclObject*)arg)->value,
2046                                  &v) == TCL_ERROR)
2047             return Tkinter_Error(self);
2048         return PyFloat_FromDouble(v);
2049     }
2050 
2051     if (!PyArg_Parse(arg, "s:getdouble", &s))
2052         return NULL;
2053     CHECK_STRING_LENGTH(s);
2054     if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
2055         return Tkinter_Error(self);
2056     return PyFloat_FromDouble(v);
2057 }
2058 
2059 /*[clinic input]
2060 _tkinter.tkapp.getboolean
2061 
2062     arg: object
2063     /
2064 
2065 [clinic start generated code]*/
2066 
2067 static PyObject *
_tkinter_tkapp_getboolean(TkappObject * self,PyObject * arg)2068 _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg)
2069 /*[clinic end generated code: output=726a9ae445821d91 input=7f11248ef8f8776e]*/
2070 {
2071     char *s;
2072     int v;
2073 
2074     if (PyLong_Check(arg)) { /* int or bool */
2075         return PyBool_FromLong(Py_SIZE(arg) != 0);
2076     }
2077 
2078     if (PyTclObject_Check(arg)) {
2079         if (Tcl_GetBooleanFromObj(Tkapp_Interp(self),
2080                                   ((PyTclObject*)arg)->value,
2081                                   &v) == TCL_ERROR)
2082             return Tkinter_Error(self);
2083         return PyBool_FromLong(v);
2084     }
2085 
2086     if (!PyArg_Parse(arg, "s:getboolean", &s))
2087         return NULL;
2088     CHECK_STRING_LENGTH(s);
2089     if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
2090         return Tkinter_Error(self);
2091     return PyBool_FromLong(v);
2092 }
2093 
2094 /*[clinic input]
2095 _tkinter.tkapp.exprstring
2096 
2097     s: str
2098     /
2099 
2100 [clinic start generated code]*/
2101 
2102 static PyObject *
_tkinter_tkapp_exprstring_impl(TkappObject * self,const char * s)2103 _tkinter_tkapp_exprstring_impl(TkappObject *self, const char *s)
2104 /*[clinic end generated code: output=beda323d3ed0abb1 input=fa78f751afb2f21b]*/
2105 {
2106     PyObject *res = NULL;
2107     int retval;
2108 
2109     CHECK_STRING_LENGTH(s);
2110     CHECK_TCL_APPARTMENT;
2111 
2112     ENTER_TCL
2113     retval = Tcl_ExprString(Tkapp_Interp(self), s);
2114     ENTER_OVERLAP
2115     if (retval == TCL_ERROR)
2116         res = Tkinter_Error(self);
2117     else
2118         res = Tkapp_UnicodeResult(self);
2119     LEAVE_OVERLAP_TCL
2120     return res;
2121 }
2122 
2123 /*[clinic input]
2124 _tkinter.tkapp.exprlong
2125 
2126     s: str
2127     /
2128 
2129 [clinic start generated code]*/
2130 
2131 static PyObject *
_tkinter_tkapp_exprlong_impl(TkappObject * self,const char * s)2132 _tkinter_tkapp_exprlong_impl(TkappObject *self, const char *s)
2133 /*[clinic end generated code: output=5d6a46b63c6ebcf9 input=11bd7eee0c57b4dc]*/
2134 {
2135     PyObject *res = NULL;
2136     int retval;
2137     long v;
2138 
2139     CHECK_STRING_LENGTH(s);
2140     CHECK_TCL_APPARTMENT;
2141 
2142     ENTER_TCL
2143     retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v);
2144     ENTER_OVERLAP
2145     if (retval == TCL_ERROR)
2146         res = Tkinter_Error(self);
2147     else
2148         res = PyLong_FromLong(v);
2149     LEAVE_OVERLAP_TCL
2150     return res;
2151 }
2152 
2153 /*[clinic input]
2154 _tkinter.tkapp.exprdouble
2155 
2156     s: str
2157     /
2158 
2159 [clinic start generated code]*/
2160 
2161 static PyObject *
_tkinter_tkapp_exprdouble_impl(TkappObject * self,const char * s)2162 _tkinter_tkapp_exprdouble_impl(TkappObject *self, const char *s)
2163 /*[clinic end generated code: output=ff78df1081ea4158 input=ff02bc11798832d5]*/
2164 {
2165     PyObject *res = NULL;
2166     double v;
2167     int retval;
2168 
2169     CHECK_STRING_LENGTH(s);
2170     CHECK_TCL_APPARTMENT;
2171     PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
2172     ENTER_TCL
2173     retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v);
2174     ENTER_OVERLAP
2175     PyFPE_END_PROTECT(retval)
2176     if (retval == TCL_ERROR)
2177         res = Tkinter_Error(self);
2178     else
2179         res = PyFloat_FromDouble(v);
2180     LEAVE_OVERLAP_TCL
2181     return res;
2182 }
2183 
2184 /*[clinic input]
2185 _tkinter.tkapp.exprboolean
2186 
2187     s: str
2188     /
2189 
2190 [clinic start generated code]*/
2191 
2192 static PyObject *
_tkinter_tkapp_exprboolean_impl(TkappObject * self,const char * s)2193 _tkinter_tkapp_exprboolean_impl(TkappObject *self, const char *s)
2194 /*[clinic end generated code: output=8b28038c22887311 input=c8c66022bdb8d5d3]*/
2195 {
2196     PyObject *res = NULL;
2197     int retval;
2198     int v;
2199 
2200     CHECK_STRING_LENGTH(s);
2201     CHECK_TCL_APPARTMENT;
2202     ENTER_TCL
2203     retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
2204     ENTER_OVERLAP
2205     if (retval == TCL_ERROR)
2206         res = Tkinter_Error(self);
2207     else
2208         res = PyLong_FromLong(v);
2209     LEAVE_OVERLAP_TCL
2210     return res;
2211 }
2212 
2213 
2214 
2215 /*[clinic input]
2216 _tkinter.tkapp.splitlist
2217 
2218     arg: object
2219     /
2220 
2221 [clinic start generated code]*/
2222 
2223 static PyObject *
_tkinter_tkapp_splitlist(TkappObject * self,PyObject * arg)2224 _tkinter_tkapp_splitlist(TkappObject *self, PyObject *arg)
2225 /*[clinic end generated code: output=13b51d34386d36fb input=2b2e13351e3c0b53]*/
2226 {
2227     char *list;
2228     int argc;
2229     const char **argv;
2230     PyObject *v;
2231     int i;
2232 
2233     if (PyTclObject_Check(arg)) {
2234         int objc;
2235         Tcl_Obj **objv;
2236         if (Tcl_ListObjGetElements(Tkapp_Interp(self),
2237                                    ((PyTclObject*)arg)->value,
2238                                    &objc, &objv) == TCL_ERROR) {
2239             return Tkinter_Error(self);
2240         }
2241         if (!(v = PyTuple_New(objc)))
2242             return NULL;
2243         for (i = 0; i < objc; i++) {
2244             PyObject *s = FromObj(self, objv[i]);
2245             if (!s) {
2246                 Py_DECREF(v);
2247                 return NULL;
2248             }
2249             PyTuple_SET_ITEM(v, i, s);
2250         }
2251         return v;
2252     }
2253     if (PyTuple_Check(arg)) {
2254         Py_INCREF(arg);
2255         return arg;
2256     }
2257     if (PyList_Check(arg)) {
2258         return PySequence_Tuple(arg);
2259     }
2260 
2261     if (!PyArg_Parse(arg, "et:splitlist", "utf-8", &list))
2262         return NULL;
2263 
2264     if (strlen(list) >= INT_MAX) {
2265         PyErr_SetString(PyExc_OverflowError, "string is too long");
2266         PyMem_Free(list);
2267         return NULL;
2268     }
2269     if (Tcl_SplitList(Tkapp_Interp(self), list,
2270                       &argc, &argv) == TCL_ERROR)  {
2271         PyMem_Free(list);
2272         return Tkinter_Error(self);
2273     }
2274 
2275     if (!(v = PyTuple_New(argc)))
2276         goto finally;
2277 
2278     for (i = 0; i < argc; i++) {
2279         PyObject *s = unicodeFromTclString(argv[i]);
2280         if (!s) {
2281             Py_DECREF(v);
2282             v = NULL;
2283             goto finally;
2284         }
2285         PyTuple_SET_ITEM(v, i, s);
2286     }
2287 
2288   finally:
2289     ckfree(FREECAST argv);
2290     PyMem_Free(list);
2291     return v;
2292 }
2293 
2294 /*[clinic input]
2295 _tkinter.tkapp.split
2296 
2297     arg: object
2298     /
2299 
2300 [clinic start generated code]*/
2301 
2302 static PyObject *
_tkinter_tkapp_split(TkappObject * self,PyObject * arg)2303 _tkinter_tkapp_split(TkappObject *self, PyObject *arg)
2304 /*[clinic end generated code: output=e08ad832363facfd input=a1c78349eacaa140]*/
2305 {
2306     PyObject *v;
2307     char *list;
2308 
2309     if (PyTclObject_Check(arg)) {
2310         Tcl_Obj *value = ((PyTclObject*)arg)->value;
2311         int objc;
2312         Tcl_Obj **objv;
2313         int i;
2314         if (Tcl_ListObjGetElements(Tkapp_Interp(self), value,
2315                                    &objc, &objv) == TCL_ERROR) {
2316             return FromObj(self, value);
2317         }
2318         if (objc == 0)
2319             return PyUnicode_FromString("");
2320         if (objc == 1)
2321             return FromObj(self, objv[0]);
2322         if (!(v = PyTuple_New(objc)))
2323             return NULL;
2324         for (i = 0; i < objc; i++) {
2325             PyObject *s = FromObj(self, objv[i]);
2326             if (!s) {
2327                 Py_DECREF(v);
2328                 return NULL;
2329             }
2330             PyTuple_SET_ITEM(v, i, s);
2331         }
2332         return v;
2333     }
2334     if (PyTuple_Check(arg) || PyList_Check(arg))
2335         return SplitObj(arg);
2336 
2337     if (!PyArg_Parse(arg, "et:split", "utf-8", &list))
2338         return NULL;
2339     if (strlen(list) >= INT_MAX) {
2340         PyErr_SetString(PyExc_OverflowError, "string is too long");
2341         PyMem_Free(list);
2342         return NULL;
2343     }
2344     v = Split(list);
2345     PyMem_Free(list);
2346     return v;
2347 }
2348 
2349 
2350 
2351 /** Tcl Command **/
2352 
2353 /* Client data struct */
2354 typedef struct {
2355     PyObject *self;
2356     PyObject *func;
2357 } PythonCmd_ClientData;
2358 
2359 static int
PythonCmd_Error(Tcl_Interp * interp)2360 PythonCmd_Error(Tcl_Interp *interp)
2361 {
2362     errorInCmd = 1;
2363     PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
2364     LEAVE_PYTHON
2365     return TCL_ERROR;
2366 }
2367 
2368 /* This is the Tcl command that acts as a wrapper for Python
2369  * function or method.
2370  */
2371 static int
PythonCmd(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])2372 PythonCmd(ClientData clientData, Tcl_Interp *interp,
2373           int objc, Tcl_Obj *const objv[])
2374 {
2375     PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
2376     PyObject *args, *res;
2377     int i;
2378     Tcl_Obj *obj_res;
2379 
2380     ENTER_PYTHON
2381 
2382     /* Create argument tuple (objv1, ..., objvN) */
2383     if (!(args = PyTuple_New(objc - 1)))
2384         return PythonCmd_Error(interp);
2385 
2386     for (i = 0; i < (objc - 1); i++) {
2387         PyObject *s = unicodeFromTclObj(objv[i + 1]);
2388         if (!s) {
2389             Py_DECREF(args);
2390             return PythonCmd_Error(interp);
2391         }
2392         PyTuple_SET_ITEM(args, i, s);
2393     }
2394 
2395     res = PyObject_Call(data->func, args, NULL);
2396     Py_DECREF(args);
2397 
2398     if (res == NULL)
2399         return PythonCmd_Error(interp);
2400 
2401     obj_res = AsObj(res);
2402     if (obj_res == NULL) {
2403         Py_DECREF(res);
2404         return PythonCmd_Error(interp);
2405     }
2406     Tcl_SetObjResult(interp, obj_res);
2407     Py_DECREF(res);
2408 
2409     LEAVE_PYTHON
2410 
2411     return TCL_OK;
2412 }
2413 
2414 
2415 static void
PythonCmdDelete(ClientData clientData)2416 PythonCmdDelete(ClientData clientData)
2417 {
2418     PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
2419 
2420     ENTER_PYTHON
2421     Py_XDECREF(data->self);
2422     Py_XDECREF(data->func);
2423     PyMem_DEL(data);
2424     LEAVE_PYTHON
2425 }
2426 
2427 
2428 
2429 
2430 TCL_DECLARE_MUTEX(command_mutex)
2431 
2432 typedef struct CommandEvent{
2433     Tcl_Event ev;
2434     Tcl_Interp* interp;
2435     const char *name;
2436     int create;
2437     int *status;
2438     ClientData *data;
2439     Tcl_Condition *done;
2440 } CommandEvent;
2441 
2442 static int
Tkapp_CommandProc(CommandEvent * ev,int flags)2443 Tkapp_CommandProc(CommandEvent *ev, int flags)
2444 {
2445     if (ev->create)
2446         *ev->status = Tcl_CreateObjCommand(
2447             ev->interp, ev->name, PythonCmd,
2448             ev->data, PythonCmdDelete) == NULL;
2449     else
2450         *ev->status = Tcl_DeleteCommand(ev->interp, ev->name);
2451     Tcl_MutexLock(&command_mutex);
2452     Tcl_ConditionNotify(ev->done);
2453     Tcl_MutexUnlock(&command_mutex);
2454     return 1;
2455 }
2456 
2457 /*[clinic input]
2458 _tkinter.tkapp.createcommand
2459 
2460     name: str
2461     func: object
2462     /
2463 
2464 [clinic start generated code]*/
2465 
2466 static PyObject *
_tkinter_tkapp_createcommand_impl(TkappObject * self,const char * name,PyObject * func)2467 _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name,
2468                                   PyObject *func)
2469 /*[clinic end generated code: output=2a1c79a4ee2af410 input=255785cb70edc6a0]*/
2470 {
2471     PythonCmd_ClientData *data;
2472     int err;
2473 
2474     CHECK_STRING_LENGTH(name);
2475     if (!PyCallable_Check(func)) {
2476         PyErr_SetString(PyExc_TypeError, "command not callable");
2477         return NULL;
2478     }
2479 
2480     if (self->threaded && self->thread_id != Tcl_GetCurrentThread() &&
2481         !WaitForMainloop(self))
2482         return NULL;
2483 
2484     data = PyMem_NEW(PythonCmd_ClientData, 1);
2485     if (!data)
2486         return PyErr_NoMemory();
2487     Py_INCREF(self);
2488     Py_INCREF(func);
2489     data->self = (PyObject *) self;
2490     data->func = func;
2491     if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
2492         Tcl_Condition cond = NULL;
2493         CommandEvent *ev = (CommandEvent*)attemptckalloc(sizeof(CommandEvent));
2494         if (ev == NULL) {
2495             PyErr_NoMemory();
2496             PyMem_DEL(data);
2497             return NULL;
2498         }
2499         ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc;
2500         ev->interp = self->interp;
2501         ev->create = 1;
2502         ev->name = name;
2503         ev->data = (ClientData)data;
2504         ev->status = &err;
2505         ev->done = &cond;
2506         Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &command_mutex);
2507         Tcl_ConditionFinalize(&cond);
2508     }
2509     else
2510     {
2511         ENTER_TCL
2512         err = Tcl_CreateObjCommand(
2513             Tkapp_Interp(self), name, PythonCmd,
2514             (ClientData)data, PythonCmdDelete) == NULL;
2515         LEAVE_TCL
2516     }
2517     if (err) {
2518         PyErr_SetString(Tkinter_TclError, "can't create Tcl command");
2519         PyMem_DEL(data);
2520         return NULL;
2521     }
2522 
2523     Py_RETURN_NONE;
2524 }
2525 
2526 
2527 
2528 /*[clinic input]
2529 _tkinter.tkapp.deletecommand
2530 
2531     name: str
2532     /
2533 
2534 [clinic start generated code]*/
2535 
2536 static PyObject *
_tkinter_tkapp_deletecommand_impl(TkappObject * self,const char * name)2537 _tkinter_tkapp_deletecommand_impl(TkappObject *self, const char *name)
2538 /*[clinic end generated code: output=a67e8cb5845e0d2d input=53e9952eae1f85f5]*/
2539 {
2540     int err;
2541 
2542     CHECK_STRING_LENGTH(name);
2543 
2544     if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
2545         Tcl_Condition cond = NULL;
2546         CommandEvent *ev;
2547         ev = (CommandEvent*)attemptckalloc(sizeof(CommandEvent));
2548         if (ev == NULL) {
2549             PyErr_NoMemory();
2550             return NULL;
2551         }
2552         ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc;
2553         ev->interp = self->interp;
2554         ev->create = 0;
2555         ev->name = name;
2556         ev->status = &err;
2557         ev->done = &cond;
2558         Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond,
2559                          &command_mutex);
2560         Tcl_ConditionFinalize(&cond);
2561     }
2562     else
2563     {
2564         ENTER_TCL
2565         err = Tcl_DeleteCommand(self->interp, name);
2566         LEAVE_TCL
2567     }
2568     if (err == -1) {
2569         PyErr_SetString(Tkinter_TclError, "can't delete Tcl command");
2570         return NULL;
2571     }
2572     Py_RETURN_NONE;
2573 }
2574 
2575 
2576 
2577 #ifdef HAVE_CREATEFILEHANDLER
2578 /** File Handler **/
2579 
2580 typedef struct _fhcdata {
2581     PyObject *func;
2582     PyObject *file;
2583     int id;
2584     struct _fhcdata *next;
2585 } FileHandler_ClientData;
2586 
2587 static FileHandler_ClientData *HeadFHCD;
2588 
2589 static FileHandler_ClientData *
NewFHCD(PyObject * func,PyObject * file,int id)2590 NewFHCD(PyObject *func, PyObject *file, int id)
2591 {
2592     FileHandler_ClientData *p;
2593     p = PyMem_NEW(FileHandler_ClientData, 1);
2594     if (p != NULL) {
2595         Py_XINCREF(func);
2596         Py_XINCREF(file);
2597         p->func = func;
2598         p->file = file;
2599         p->id = id;
2600         p->next = HeadFHCD;
2601         HeadFHCD = p;
2602     }
2603     return p;
2604 }
2605 
2606 static void
DeleteFHCD(int id)2607 DeleteFHCD(int id)
2608 {
2609     FileHandler_ClientData *p, **pp;
2610 
2611     pp = &HeadFHCD;
2612     while ((p = *pp) != NULL) {
2613         if (p->id == id) {
2614             *pp = p->next;
2615             Py_XDECREF(p->func);
2616             Py_XDECREF(p->file);
2617             PyMem_DEL(p);
2618         }
2619         else
2620             pp = &p->next;
2621     }
2622 }
2623 
2624 static void
FileHandler(ClientData clientData,int mask)2625 FileHandler(ClientData clientData, int mask)
2626 {
2627     FileHandler_ClientData *data = (FileHandler_ClientData *)clientData;
2628     PyObject *func, *file, *res;
2629 
2630     ENTER_PYTHON
2631     func = data->func;
2632     file = data->file;
2633 
2634     res = PyObject_CallFunction(func, "Oi", file, mask);
2635     if (res == NULL) {
2636         errorInCmd = 1;
2637         PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
2638     }
2639     Py_XDECREF(res);
2640     LEAVE_PYTHON
2641 }
2642 
2643 /*[clinic input]
2644 _tkinter.tkapp.createfilehandler
2645 
2646     file: object
2647     mask: int
2648     func: object
2649     /
2650 
2651 [clinic start generated code]*/
2652 
2653 static PyObject *
_tkinter_tkapp_createfilehandler_impl(TkappObject * self,PyObject * file,int mask,PyObject * func)2654 _tkinter_tkapp_createfilehandler_impl(TkappObject *self, PyObject *file,
2655                                       int mask, PyObject *func)
2656 /*[clinic end generated code: output=f73ce82de801c353 input=84943a5286e47947]*/
2657 {
2658     FileHandler_ClientData *data;
2659     int tfile;
2660 
2661     CHECK_TCL_APPARTMENT;
2662 
2663     tfile = PyObject_AsFileDescriptor(file);
2664     if (tfile < 0)
2665         return NULL;
2666     if (!PyCallable_Check(func)) {
2667         PyErr_SetString(PyExc_TypeError, "bad argument list");
2668         return NULL;
2669     }
2670 
2671     data = NewFHCD(func, file, tfile);
2672     if (data == NULL)
2673         return NULL;
2674 
2675     /* Ought to check for null Tcl_File object... */
2676     ENTER_TCL
2677     Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
2678     LEAVE_TCL
2679     Py_RETURN_NONE;
2680 }
2681 
2682 /*[clinic input]
2683 _tkinter.tkapp.deletefilehandler
2684 
2685     file: object
2686     /
2687 
2688 [clinic start generated code]*/
2689 
2690 static PyObject *
_tkinter_tkapp_deletefilehandler(TkappObject * self,PyObject * file)2691 _tkinter_tkapp_deletefilehandler(TkappObject *self, PyObject *file)
2692 /*[clinic end generated code: output=b53cc96ebf9476fd input=abbec19d66312e2a]*/
2693 {
2694     int tfile;
2695 
2696     CHECK_TCL_APPARTMENT;
2697 
2698     tfile = PyObject_AsFileDescriptor(file);
2699     if (tfile < 0)
2700         return NULL;
2701 
2702     DeleteFHCD(tfile);
2703 
2704     /* Ought to check for null Tcl_File object... */
2705     ENTER_TCL
2706     Tcl_DeleteFileHandler(tfile);
2707     LEAVE_TCL
2708     Py_RETURN_NONE;
2709 }
2710 #endif /* HAVE_CREATEFILEHANDLER */
2711 
2712 
2713 /**** Tktt Object (timer token) ****/
2714 
2715 static PyObject *Tktt_Type;
2716 
2717 typedef struct {
2718     PyObject_HEAD
2719     Tcl_TimerToken token;
2720     PyObject *func;
2721 } TkttObject;
2722 
2723 /*[clinic input]
2724 _tkinter.tktimertoken.deletetimerhandler
2725 
2726 [clinic start generated code]*/
2727 
2728 static PyObject *
_tkinter_tktimertoken_deletetimerhandler_impl(TkttObject * self)2729 _tkinter_tktimertoken_deletetimerhandler_impl(TkttObject *self)
2730 /*[clinic end generated code: output=bd7fe17f328cfa55 input=40bd070ff85f5cf3]*/
2731 {
2732     TkttObject *v = self;
2733     PyObject *func = v->func;
2734 
2735     if (v->token != NULL) {
2736         Tcl_DeleteTimerHandler(v->token);
2737         v->token = NULL;
2738     }
2739     if (func != NULL) {
2740         v->func = NULL;
2741         Py_DECREF(func);
2742         Py_DECREF(v); /* See Tktt_New() */
2743     }
2744     Py_RETURN_NONE;
2745 }
2746 
2747 static TkttObject *
Tktt_New(PyObject * func)2748 Tktt_New(PyObject *func)
2749 {
2750     TkttObject *v;
2751 
2752     v = PyObject_New(TkttObject, (PyTypeObject *) Tktt_Type);
2753     if (v == NULL)
2754         return NULL;
2755     Py_INCREF(Tktt_Type);
2756 
2757     Py_INCREF(func);
2758     v->token = NULL;
2759     v->func = func;
2760 
2761     /* Extra reference, deleted when called or when handler is deleted */
2762     Py_INCREF(v);
2763     return v;
2764 }
2765 
2766 static void
Tktt_Dealloc(PyObject * self)2767 Tktt_Dealloc(PyObject *self)
2768 {
2769     TkttObject *v = (TkttObject *)self;
2770     PyObject *func = v->func;
2771     PyObject *tp = (PyObject *) Py_TYPE(self);
2772 
2773     Py_XDECREF(func);
2774 
2775     PyObject_Del(self);
2776     Py_DECREF(tp);
2777 }
2778 
2779 static PyObject *
Tktt_Repr(PyObject * self)2780 Tktt_Repr(PyObject *self)
2781 {
2782     TkttObject *v = (TkttObject *)self;
2783     return PyUnicode_FromFormat("<tktimertoken at %p%s>",
2784                                 v,
2785                                 v->func == NULL ? ", handler deleted" : "");
2786 }
2787 
2788 /** Timer Handler **/
2789 
2790 static void
TimerHandler(ClientData clientData)2791 TimerHandler(ClientData clientData)
2792 {
2793     TkttObject *v = (TkttObject *)clientData;
2794     PyObject *func = v->func;
2795     PyObject *res;
2796 
2797     if (func == NULL)
2798         return;
2799 
2800     v->func = NULL;
2801 
2802     ENTER_PYTHON
2803 
2804     res = _PyObject_CallNoArg(func);
2805     Py_DECREF(func);
2806     Py_DECREF(v); /* See Tktt_New() */
2807 
2808     if (res == NULL) {
2809         errorInCmd = 1;
2810         PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
2811     }
2812     else
2813         Py_DECREF(res);
2814 
2815     LEAVE_PYTHON
2816 }
2817 
2818 /*[clinic input]
2819 _tkinter.tkapp.createtimerhandler
2820 
2821     milliseconds: int
2822     func: object
2823     /
2824 
2825 [clinic start generated code]*/
2826 
2827 static PyObject *
_tkinter_tkapp_createtimerhandler_impl(TkappObject * self,int milliseconds,PyObject * func)2828 _tkinter_tkapp_createtimerhandler_impl(TkappObject *self, int milliseconds,
2829                                        PyObject *func)
2830 /*[clinic end generated code: output=2da5959b9d031911 input=ba6729f32f0277a5]*/
2831 {
2832     TkttObject *v;
2833 
2834     if (!PyCallable_Check(func)) {
2835         PyErr_SetString(PyExc_TypeError, "bad argument list");
2836         return NULL;
2837     }
2838 
2839     CHECK_TCL_APPARTMENT;
2840 
2841     v = Tktt_New(func);
2842     if (v) {
2843         v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler,
2844                                           (ClientData)v);
2845     }
2846 
2847     return (PyObject *) v;
2848 }
2849 
2850 
2851 /** Event Loop **/
2852 
2853 /*[clinic input]
2854 _tkinter.tkapp.mainloop
2855 
2856     threshold: int = 0
2857     /
2858 
2859 [clinic start generated code]*/
2860 
2861 static PyObject *
_tkinter_tkapp_mainloop_impl(TkappObject * self,int threshold)2862 _tkinter_tkapp_mainloop_impl(TkappObject *self, int threshold)
2863 /*[clinic end generated code: output=0ba8eabbe57841b0 input=036bcdcf03d5eca0]*/
2864 {
2865     PyThreadState *tstate = PyThreadState_Get();
2866 
2867     CHECK_TCL_APPARTMENT;
2868     self->dispatching = 1;
2869 
2870     quitMainLoop = 0;
2871     while (Tk_GetNumMainWindows() > threshold &&
2872            !quitMainLoop &&
2873            !errorInCmd)
2874     {
2875         int result;
2876 
2877         if (self->threaded) {
2878             /* Allow other Python threads to run. */
2879             ENTER_TCL
2880             result = Tcl_DoOneEvent(0);
2881             LEAVE_TCL
2882         }
2883         else {
2884             Py_BEGIN_ALLOW_THREADS
2885             if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1);
2886             tcl_tstate = tstate;
2887             result = Tcl_DoOneEvent(TCL_DONT_WAIT);
2888             tcl_tstate = NULL;
2889             if(tcl_lock)PyThread_release_lock(tcl_lock);
2890             if (result == 0)
2891                 Sleep(Tkinter_busywaitinterval);
2892             Py_END_ALLOW_THREADS
2893         }
2894 
2895         if (PyErr_CheckSignals() != 0) {
2896             self->dispatching = 0;
2897             return NULL;
2898         }
2899         if (result < 0)
2900             break;
2901     }
2902     self->dispatching = 0;
2903     quitMainLoop = 0;
2904 
2905     if (errorInCmd) {
2906         errorInCmd = 0;
2907         PyErr_Restore(excInCmd, valInCmd, trbInCmd);
2908         excInCmd = valInCmd = trbInCmd = NULL;
2909         return NULL;
2910     }
2911     Py_RETURN_NONE;
2912 }
2913 
2914 /*[clinic input]
2915 _tkinter.tkapp.dooneevent
2916 
2917     flags: int = 0
2918     /
2919 
2920 [clinic start generated code]*/
2921 
2922 static PyObject *
_tkinter_tkapp_dooneevent_impl(TkappObject * self,int flags)2923 _tkinter_tkapp_dooneevent_impl(TkappObject *self, int flags)
2924 /*[clinic end generated code: output=27c6b2aa464cac29 input=6542b928e364b793]*/
2925 {
2926     int rv;
2927 
2928     ENTER_TCL
2929     rv = Tcl_DoOneEvent(flags);
2930     LEAVE_TCL
2931     return PyLong_FromLong(rv);
2932 }
2933 
2934 /*[clinic input]
2935 _tkinter.tkapp.quit
2936 [clinic start generated code]*/
2937 
2938 static PyObject *
_tkinter_tkapp_quit_impl(TkappObject * self)2939 _tkinter_tkapp_quit_impl(TkappObject *self)
2940 /*[clinic end generated code: output=7f21eeff481f754f input=e03020dc38aff23c]*/
2941 {
2942     quitMainLoop = 1;
2943     Py_RETURN_NONE;
2944 }
2945 
2946 /*[clinic input]
2947 _tkinter.tkapp.interpaddr
2948 [clinic start generated code]*/
2949 
2950 static PyObject *
_tkinter_tkapp_interpaddr_impl(TkappObject * self)2951 _tkinter_tkapp_interpaddr_impl(TkappObject *self)
2952 /*[clinic end generated code: output=6caaae3273b3c95a input=2dd32cbddb55a111]*/
2953 {
2954     return PyLong_FromVoidPtr(Tkapp_Interp(self));
2955 }
2956 
2957 /*[clinic input]
2958 _tkinter.tkapp.loadtk
2959 [clinic start generated code]*/
2960 
2961 static PyObject *
_tkinter_tkapp_loadtk_impl(TkappObject * self)2962 _tkinter_tkapp_loadtk_impl(TkappObject *self)
2963 /*[clinic end generated code: output=e9e10a954ce46d2a input=b5e82afedd6354f0]*/
2964 {
2965     Tcl_Interp *interp = Tkapp_Interp(self);
2966     const char * _tk_exists = NULL;
2967     int err;
2968 
2969 #ifdef TKINTER_PROTECT_LOADTK
2970     /* Up to Tk 8.4.13, Tk_Init deadlocks on the second call when the
2971      * first call failed.
2972      * To avoid the deadlock, we just refuse the second call through
2973      * a static variable.
2974      */
2975     if (tk_load_failed) {
2976         PyErr_SetString(Tkinter_TclError, TKINTER_LOADTK_ERRMSG);
2977         return NULL;
2978     }
2979 #endif
2980 
2981     /* We want to guard against calling Tk_Init() multiple times */
2982     CHECK_TCL_APPARTMENT;
2983     ENTER_TCL
2984     err = Tcl_Eval(Tkapp_Interp(self), "info exists     tk_version");
2985     ENTER_OVERLAP
2986     if (err == TCL_ERROR) {
2987         /* This sets an exception, but we cannot return right
2988            away because we need to exit the overlap first. */
2989         Tkinter_Error(self);
2990     } else {
2991         _tk_exists = Tcl_GetStringResult(Tkapp_Interp(self));
2992     }
2993     LEAVE_OVERLAP_TCL
2994     if (err == TCL_ERROR) {
2995         return NULL;
2996     }
2997     if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0)     {
2998         if (Tk_Init(interp)             == TCL_ERROR) {
2999             Tkinter_Error(self);
3000 #ifdef TKINTER_PROTECT_LOADTK
3001             tk_load_failed = 1;
3002 #endif
3003             return NULL;
3004         }
3005     }
3006     Py_RETURN_NONE;
3007 }
3008 
3009 static PyObject *
Tkapp_WantObjects(PyObject * self,PyObject * args)3010 Tkapp_WantObjects(PyObject *self, PyObject *args)
3011 {
3012 
3013     int wantobjects = -1;
3014     if (!PyArg_ParseTuple(args, "|i:wantobjects", &wantobjects))
3015         return NULL;
3016     if (wantobjects == -1)
3017         return PyBool_FromLong(((TkappObject*)self)->wantobjects);
3018     ((TkappObject*)self)->wantobjects = wantobjects;
3019 
3020     Py_RETURN_NONE;
3021 }
3022 
3023 /*[clinic input]
3024 _tkinter.tkapp.willdispatch
3025 
3026 [clinic start generated code]*/
3027 
3028 static PyObject *
_tkinter_tkapp_willdispatch_impl(TkappObject * self)3029 _tkinter_tkapp_willdispatch_impl(TkappObject *self)
3030 /*[clinic end generated code: output=0e3f46d244642155 input=d88f5970843d6dab]*/
3031 {
3032     self->dispatching = 1;
3033 
3034     Py_RETURN_NONE;
3035 }
3036 
3037 
3038 /**** Tkapp Type Methods ****/
3039 
3040 static void
Tkapp_Dealloc(PyObject * self)3041 Tkapp_Dealloc(PyObject *self)
3042 {
3043     PyObject *tp = (PyObject *) Py_TYPE(self);
3044     /*CHECK_TCL_APPARTMENT;*/
3045     ENTER_TCL
3046     Tcl_DeleteInterp(Tkapp_Interp(self));
3047     LEAVE_TCL
3048     PyObject_Del(self);
3049     Py_DECREF(tp);
3050     DisableEventHook();
3051 }
3052 
3053 
3054 
3055 /**** Tkinter Module ****/
3056 
3057 typedef struct {
3058     PyObject* tuple;
3059     Py_ssize_t size; /* current size */
3060     Py_ssize_t maxsize; /* allocated size */
3061 } FlattenContext;
3062 
3063 static int
_bump(FlattenContext * context,Py_ssize_t size)3064 _bump(FlattenContext* context, Py_ssize_t size)
3065 {
3066     /* expand tuple to hold (at least) size new items.
3067        return true if successful, false if an exception was raised */
3068 
3069     Py_ssize_t maxsize = context->maxsize * 2;  /* never overflows */
3070 
3071     if (maxsize < context->size + size)
3072         maxsize = context->size + size;  /* never overflows */
3073 
3074     context->maxsize = maxsize;
3075 
3076     return _PyTuple_Resize(&context->tuple, maxsize) >= 0;
3077 }
3078 
3079 static int
_flatten1(FlattenContext * context,PyObject * item,int depth)3080 _flatten1(FlattenContext* context, PyObject* item, int depth)
3081 {
3082     /* add tuple or list to argument tuple (recursively) */
3083 
3084     Py_ssize_t i, size;
3085 
3086     if (depth > 1000) {
3087         PyErr_SetString(PyExc_ValueError,
3088                         "nesting too deep in _flatten");
3089         return 0;
3090     } else if (PyTuple_Check(item) || PyList_Check(item)) {
3091         size = PySequence_Fast_GET_SIZE(item);
3092         /* preallocate (assume no nesting) */
3093         if (context->size + size > context->maxsize &&
3094             !_bump(context, size))
3095             return 0;
3096         /* copy items to output tuple */
3097         for (i = 0; i < size; i++) {
3098             PyObject *o = PySequence_Fast_GET_ITEM(item, i);
3099             if (PyList_Check(o) || PyTuple_Check(o)) {
3100                 if (!_flatten1(context, o, depth + 1))
3101                     return 0;
3102             } else if (o != Py_None) {
3103                 if (context->size + 1 > context->maxsize &&
3104                     !_bump(context, 1))
3105                     return 0;
3106                 Py_INCREF(o);
3107                 PyTuple_SET_ITEM(context->tuple,
3108                                  context->size++, o);
3109             }
3110         }
3111     } else {
3112         PyErr_SetString(PyExc_TypeError, "argument must be sequence");
3113         return 0;
3114     }
3115     return 1;
3116 }
3117 
3118 /*[clinic input]
3119 _tkinter._flatten
3120 
3121     item: object
3122     /
3123 
3124 [clinic start generated code]*/
3125 
3126 static PyObject *
_tkinter__flatten(PyObject * module,PyObject * item)3127 _tkinter__flatten(PyObject *module, PyObject *item)
3128 /*[clinic end generated code: output=cad02a3f97f29862 input=6b9c12260aa1157f]*/
3129 {
3130     FlattenContext context;
3131 
3132     context.maxsize = PySequence_Size(item);
3133     if (context.maxsize < 0)
3134         return NULL;
3135     if (context.maxsize == 0)
3136         return PyTuple_New(0);
3137 
3138     context.tuple = PyTuple_New(context.maxsize);
3139     if (!context.tuple)
3140         return NULL;
3141 
3142     context.size = 0;
3143 
3144     if (!_flatten1(&context, item,0))
3145         return NULL;
3146 
3147     if (_PyTuple_Resize(&context.tuple, context.size))
3148         return NULL;
3149 
3150     return context.tuple;
3151 }
3152 
3153 /*[clinic input]
3154 _tkinter.create
3155 
3156     screenName: str(accept={str, NoneType}) = NULL
3157     baseName: str = NULL
3158     className: str = "Tk"
3159     interactive: bool(accept={int}) = False
3160     wantobjects: bool(accept={int}) = False
3161     wantTk: bool(accept={int}) = True
3162         if false, then Tk_Init() doesn't get called
3163     sync: bool(accept={int}) = False
3164         if true, then pass -sync to wish
3165     use: str(accept={str, NoneType}) = NULL
3166         if not None, then pass -use to wish
3167     /
3168 
3169 [clinic start generated code]*/
3170 
3171 static PyObject *
_tkinter_create_impl(PyObject * module,const char * screenName,const char * baseName,const char * className,int interactive,int wantobjects,int wantTk,int sync,const char * use)3172 _tkinter_create_impl(PyObject *module, const char *screenName,
3173                      const char *baseName, const char *className,
3174                      int interactive, int wantobjects, int wantTk, int sync,
3175                      const char *use)
3176 /*[clinic end generated code: output=e3315607648e6bb4 input=431907c134c80085]*/
3177 {
3178     /* XXX baseName is not used anymore;
3179      * try getting rid of it. */
3180     CHECK_STRING_LENGTH(screenName);
3181     CHECK_STRING_LENGTH(baseName);
3182     CHECK_STRING_LENGTH(className);
3183     CHECK_STRING_LENGTH(use);
3184 
3185     return (PyObject *) Tkapp_New(screenName, className,
3186                                   interactive, wantobjects, wantTk,
3187                                   sync, use);
3188 }
3189 
3190 /*[clinic input]
3191 _tkinter.setbusywaitinterval
3192 
3193     new_val: int
3194     /
3195 
3196 Set the busy-wait interval in milliseconds between successive calls to Tcl_DoOneEvent in a threaded Python interpreter.
3197 
3198 It should be set to a divisor of the maximum time between frames in an animation.
3199 [clinic start generated code]*/
3200 
3201 static PyObject *
_tkinter_setbusywaitinterval_impl(PyObject * module,int new_val)3202 _tkinter_setbusywaitinterval_impl(PyObject *module, int new_val)
3203 /*[clinic end generated code: output=42bf7757dc2d0ab6 input=deca1d6f9e6dae47]*/
3204 {
3205     if (new_val < 0) {
3206         PyErr_SetString(PyExc_ValueError,
3207                         "busywaitinterval must be >= 0");
3208         return NULL;
3209     }
3210     Tkinter_busywaitinterval = new_val;
3211     Py_RETURN_NONE;
3212 }
3213 
3214 /*[clinic input]
3215 _tkinter.getbusywaitinterval -> int
3216 
3217 Return the current busy-wait interval between successive calls to Tcl_DoOneEvent in a threaded Python interpreter.
3218 [clinic start generated code]*/
3219 
3220 static int
_tkinter_getbusywaitinterval_impl(PyObject * module)3221 _tkinter_getbusywaitinterval_impl(PyObject *module)
3222 /*[clinic end generated code: output=23b72d552001f5c7 input=a695878d2d576a84]*/
3223 {
3224     return Tkinter_busywaitinterval;
3225 }
3226 
3227 #include "clinic/_tkinter.c.h"
3228 
3229 static PyMethodDef Tktt_methods[] =
3230 {
3231     _TKINTER_TKTIMERTOKEN_DELETETIMERHANDLER_METHODDEF
3232     {NULL, NULL}
3233 };
3234 
3235 static PyType_Slot Tktt_Type_slots[] = {
3236     {Py_tp_dealloc, Tktt_Dealloc},
3237     {Py_tp_repr, Tktt_Repr},
3238     {Py_tp_methods, Tktt_methods},
3239     {0, 0}
3240 };
3241 
3242 static PyType_Spec Tktt_Type_spec = {
3243     "_tkinter.tktimertoken",
3244     sizeof(TkttObject),
3245     0,
3246     Py_TPFLAGS_DEFAULT,
3247     Tktt_Type_slots,
3248 };
3249 
3250 
3251 /**** Tkapp Method List ****/
3252 
3253 static PyMethodDef Tkapp_methods[] =
3254 {
3255     _TKINTER_TKAPP_WILLDISPATCH_METHODDEF
3256     {"wantobjects",            Tkapp_WantObjects, METH_VARARGS},
3257     {"call",                   Tkapp_Call, METH_VARARGS},
3258     _TKINTER_TKAPP_EVAL_METHODDEF
3259     _TKINTER_TKAPP_EVALFILE_METHODDEF
3260     _TKINTER_TKAPP_RECORD_METHODDEF
3261     _TKINTER_TKAPP_ADDERRORINFO_METHODDEF
3262     {"setvar",                 Tkapp_SetVar, METH_VARARGS},
3263     {"globalsetvar",       Tkapp_GlobalSetVar, METH_VARARGS},
3264     {"getvar",       Tkapp_GetVar, METH_VARARGS},
3265     {"globalgetvar",       Tkapp_GlobalGetVar, METH_VARARGS},
3266     {"unsetvar",     Tkapp_UnsetVar, METH_VARARGS},
3267     {"globalunsetvar",     Tkapp_GlobalUnsetVar, METH_VARARGS},
3268     _TKINTER_TKAPP_GETINT_METHODDEF
3269     _TKINTER_TKAPP_GETDOUBLE_METHODDEF
3270     _TKINTER_TKAPP_GETBOOLEAN_METHODDEF
3271     _TKINTER_TKAPP_EXPRSTRING_METHODDEF
3272     _TKINTER_TKAPP_EXPRLONG_METHODDEF
3273     _TKINTER_TKAPP_EXPRDOUBLE_METHODDEF
3274     _TKINTER_TKAPP_EXPRBOOLEAN_METHODDEF
3275     _TKINTER_TKAPP_SPLITLIST_METHODDEF
3276     _TKINTER_TKAPP_SPLIT_METHODDEF
3277     _TKINTER_TKAPP_CREATECOMMAND_METHODDEF
3278     _TKINTER_TKAPP_DELETECOMMAND_METHODDEF
3279     _TKINTER_TKAPP_CREATEFILEHANDLER_METHODDEF
3280     _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF
3281     _TKINTER_TKAPP_CREATETIMERHANDLER_METHODDEF
3282     _TKINTER_TKAPP_MAINLOOP_METHODDEF
3283     _TKINTER_TKAPP_DOONEEVENT_METHODDEF
3284     _TKINTER_TKAPP_QUIT_METHODDEF
3285     _TKINTER_TKAPP_INTERPADDR_METHODDEF
3286     _TKINTER_TKAPP_LOADTK_METHODDEF
3287     {NULL,                     NULL}
3288 };
3289 
3290 static PyType_Slot Tkapp_Type_slots[] = {
3291     {Py_tp_dealloc, Tkapp_Dealloc},
3292     {Py_tp_methods, Tkapp_methods},
3293     {0, 0}
3294 };
3295 
3296 
3297 static PyType_Spec Tkapp_Type_spec = {
3298     "_tkinter.tkapp",
3299     sizeof(TkappObject),
3300     0,
3301     Py_TPFLAGS_DEFAULT,
3302     Tkapp_Type_slots,
3303 };
3304 
3305 static PyMethodDef moduleMethods[] =
3306 {
3307     _TKINTER__FLATTEN_METHODDEF
3308     _TKINTER_CREATE_METHODDEF
3309     _TKINTER_SETBUSYWAITINTERVAL_METHODDEF
3310     _TKINTER_GETBUSYWAITINTERVAL_METHODDEF
3311     {NULL,                 NULL}
3312 };
3313 
3314 #ifdef WAIT_FOR_STDIN
3315 
3316 static int stdin_ready = 0;
3317 
3318 #ifndef MS_WINDOWS
3319 static void
MyFileProc(void * clientData,int mask)3320 MyFileProc(void *clientData, int mask)
3321 {
3322     stdin_ready = 1;
3323 }
3324 #endif
3325 
3326 static PyThreadState *event_tstate = NULL;
3327 
3328 static int
EventHook(void)3329 EventHook(void)
3330 {
3331 #ifndef MS_WINDOWS
3332     int tfile;
3333 #endif
3334     PyEval_RestoreThread(event_tstate);
3335     stdin_ready = 0;
3336     errorInCmd = 0;
3337 #ifndef MS_WINDOWS
3338     tfile = fileno(stdin);
3339     Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
3340 #endif
3341     while (!errorInCmd && !stdin_ready) {
3342         int result;
3343 #ifdef MS_WINDOWS
3344         if (_kbhit()) {
3345             stdin_ready = 1;
3346             break;
3347         }
3348 #endif
3349         Py_BEGIN_ALLOW_THREADS
3350         if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1);
3351         tcl_tstate = event_tstate;
3352 
3353         result = Tcl_DoOneEvent(TCL_DONT_WAIT);
3354 
3355         tcl_tstate = NULL;
3356         if(tcl_lock)PyThread_release_lock(tcl_lock);
3357         if (result == 0)
3358             Sleep(Tkinter_busywaitinterval);
3359         Py_END_ALLOW_THREADS
3360 
3361         if (result < 0)
3362             break;
3363     }
3364 #ifndef MS_WINDOWS
3365     Tcl_DeleteFileHandler(tfile);
3366 #endif
3367     if (errorInCmd) {
3368         errorInCmd = 0;
3369         PyErr_Restore(excInCmd, valInCmd, trbInCmd);
3370         excInCmd = valInCmd = trbInCmd = NULL;
3371         PyErr_Print();
3372     }
3373     PyEval_SaveThread();
3374     return 0;
3375 }
3376 
3377 #endif
3378 
3379 static void
EnableEventHook(void)3380 EnableEventHook(void)
3381 {
3382 #ifdef WAIT_FOR_STDIN
3383     if (PyOS_InputHook == NULL) {
3384         event_tstate = PyThreadState_Get();
3385         PyOS_InputHook = EventHook;
3386     }
3387 #endif
3388 }
3389 
3390 static void
DisableEventHook(void)3391 DisableEventHook(void)
3392 {
3393 #ifdef WAIT_FOR_STDIN
3394     if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
3395         PyOS_InputHook = NULL;
3396     }
3397 #endif
3398 }
3399 
3400 
3401 static struct PyModuleDef _tkintermodule = {
3402     PyModuleDef_HEAD_INIT,
3403     "_tkinter",
3404     NULL,
3405     -1,
3406     moduleMethods,
3407     NULL,
3408     NULL,
3409     NULL,
3410     NULL
3411 };
3412 
3413 PyMODINIT_FUNC
PyInit__tkinter(void)3414 PyInit__tkinter(void)
3415 {
3416   PyObject *m, *uexe, *cexe, *o;
3417 
3418     tcl_lock = PyThread_allocate_lock();
3419     if (tcl_lock == NULL)
3420         return NULL;
3421 
3422     m = PyModule_Create(&_tkintermodule);
3423     if (m == NULL)
3424         return NULL;
3425 
3426     o = PyErr_NewException("_tkinter.TclError", NULL, NULL);
3427     if (o == NULL) {
3428         Py_DECREF(m);
3429         return NULL;
3430     }
3431     Py_INCREF(o);
3432     if (PyModule_AddObject(m, "TclError", o)) {
3433         Py_DECREF(o);
3434         Py_DECREF(m);
3435         return NULL;
3436     }
3437     Tkinter_TclError = o;
3438 
3439     if (PyModule_AddIntConstant(m, "READABLE", TCL_READABLE)) {
3440         Py_DECREF(m);
3441         return NULL;
3442     }
3443     if (PyModule_AddIntConstant(m, "WRITABLE", TCL_WRITABLE)) {
3444         Py_DECREF(m);
3445         return NULL;
3446     }
3447     if (PyModule_AddIntConstant(m, "EXCEPTION", TCL_EXCEPTION)) {
3448         Py_DECREF(m);
3449         return NULL;
3450     }
3451     if (PyModule_AddIntConstant(m, "WINDOW_EVENTS", TCL_WINDOW_EVENTS)) {
3452         Py_DECREF(m);
3453         return NULL;
3454     }
3455     if (PyModule_AddIntConstant(m, "FILE_EVENTS", TCL_FILE_EVENTS)) {
3456         Py_DECREF(m);
3457         return NULL;
3458     }
3459     if (PyModule_AddIntConstant(m, "TIMER_EVENTS", TCL_TIMER_EVENTS)) {
3460         Py_DECREF(m);
3461         return NULL;
3462     }
3463     if (PyModule_AddIntConstant(m, "IDLE_EVENTS", TCL_IDLE_EVENTS)) {
3464         Py_DECREF(m);
3465         return NULL;
3466     }
3467     if (PyModule_AddIntConstant(m, "ALL_EVENTS", TCL_ALL_EVENTS)) {
3468         Py_DECREF(m);
3469         return NULL;
3470     }
3471     if (PyModule_AddIntConstant(m, "DONT_WAIT", TCL_DONT_WAIT)) {
3472         Py_DECREF(m);
3473         return NULL;
3474     }
3475     if (PyModule_AddStringConstant(m, "TK_VERSION", TK_VERSION)) {
3476         Py_DECREF(m);
3477         return NULL;
3478     }
3479     if (PyModule_AddStringConstant(m, "TCL_VERSION", TCL_VERSION)) {
3480         Py_DECREF(m);
3481         return NULL;
3482     }
3483 
3484     o = PyType_FromSpec(&Tkapp_Type_spec);
3485     if (o == NULL) {
3486         Py_DECREF(m);
3487         return NULL;
3488     }
3489     ((PyTypeObject *)o)->tp_new = NULL;
3490     if (PyModule_AddObject(m, "TkappType", o)) {
3491         Py_DECREF(o);
3492         Py_DECREF(m);
3493         return NULL;
3494     }
3495     Tkapp_Type = o;
3496 
3497     o = PyType_FromSpec(&Tktt_Type_spec);
3498     if (o == NULL) {
3499         Py_DECREF(m);
3500         return NULL;
3501     }
3502     ((PyTypeObject *)o)->tp_new = NULL;
3503     if (PyModule_AddObject(m, "TkttType", o)) {
3504         Py_DECREF(o);
3505         Py_DECREF(m);
3506         return NULL;
3507     }
3508     Tktt_Type = o;
3509 
3510     o = PyType_FromSpec(&PyTclObject_Type_spec);
3511     if (o == NULL) {
3512         Py_DECREF(m);
3513         return NULL;
3514     }
3515     ((PyTypeObject *)o)->tp_new = NULL;
3516     if (PyModule_AddObject(m, "Tcl_Obj", o)) {
3517         Py_DECREF(o);
3518         Py_DECREF(m);
3519         return NULL;
3520     }
3521     PyTclObject_Type = o;
3522 
3523 #ifdef TK_AQUA
3524     /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems
3525      * start waking up.  Note that Tcl_FindExecutable will do this, this
3526      * code must be above it! The original warning from
3527      * tkMacOSXAppInit.c is copied below.
3528      *
3529      * NB - You have to swap in the Tk Notifier BEFORE you start up the
3530      * Tcl interpreter for now.  It probably should work to do this
3531      * in the other order, but for now it doesn't seem to.
3532      *
3533      */
3534     Tk_MacOSXSetupTkNotifier();
3535 #endif
3536 
3537 
3538     /* This helps the dynamic loader; in Unicode aware Tcl versions
3539        it also helps Tcl find its encodings. */
3540     uexe = PyUnicode_FromWideChar(Py_GetProgramName(), -1);
3541     if (uexe) {
3542         cexe = PyUnicode_EncodeFSDefault(uexe);
3543         if (cexe) {
3544 #ifdef MS_WINDOWS
3545             int set_var = 0;
3546             PyObject *str_path;
3547             wchar_t *wcs_path;
3548             DWORD ret;
3549 
3550             ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
3551 
3552             if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
3553                 str_path = _get_tcl_lib_path();
3554                 if (str_path == NULL && PyErr_Occurred()) {
3555                     Py_DECREF(m);
3556                     return NULL;
3557                 }
3558                 if (str_path != NULL) {
3559                     wcs_path = PyUnicode_AsWideCharString(str_path, NULL);
3560                     if (wcs_path == NULL) {
3561                         Py_DECREF(m);
3562                         return NULL;
3563                     }
3564                     SetEnvironmentVariableW(L"TCL_LIBRARY", wcs_path);
3565                     set_var = 1;
3566                 }
3567             }
3568 
3569             Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
3570 
3571             if (set_var) {
3572                 SetEnvironmentVariableW(L"TCL_LIBRARY", NULL);
3573                 PyMem_Free(wcs_path);
3574             }
3575 #else
3576             Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
3577 #endif /* MS_WINDOWS */
3578         }
3579         Py_XDECREF(cexe);
3580         Py_DECREF(uexe);
3581     }
3582 
3583     if (PyErr_Occurred()) {
3584         Py_DECREF(m);
3585         return NULL;
3586     }
3587 
3588 #if 0
3589     /* This was not a good idea; through <Destroy> bindings,
3590        Tcl_Finalize() may invoke Python code but at that point the
3591        interpreter and thread state have already been destroyed! */
3592     Py_AtExit(Tcl_Finalize);
3593 #endif
3594     return m;
3595 }
3596