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