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