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