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