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