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