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