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