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