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