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