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