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