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 *
_get_tcl_lib_path()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 *
Tkinter_Error(TkappObject * self)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
Sleep(int milli)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
WaitForMainloop(TkappObject * self)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 *
unicodeFromTclStringAndSize(const char * s,Py_ssize_t size)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 *
unicodeFromTclString(const char * s)487 unicodeFromTclString(const char *s)
488 {
489 return unicodeFromTclStringAndSize(s, strlen(s));
490 }
491
492 static PyObject *
unicodeFromTclObj(Tcl_Obj * value)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
Tcl_AppInit(Tcl_Interp * interp)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 *
Tkapp_New(const char * screenName,const char * className,int interactive,int wantobjects,int wantTk,int sync,const char * use)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
Tkapp_ThreadSend(TkappObject * self,Tcl_Event * ev,Tcl_Condition * cond,Tcl_Mutex * mutex)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 *
newPyTclObject(Tcl_Obj * arg)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
PyTclObject_dealloc(PyTclObject * self)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 *
PyTclObject_string(PyTclObject * self,void * ignored)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 *
PyTclObject_str(PyTclObject * self)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 *
PyTclObject_repr(PyTclObject * self)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 *
PyTclObject_richcompare(PyObject * self,PyObject * other,int op)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*
get_typename(PyTclObject * obj,void * ignored)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*
asBignumObj(PyObject * value)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 mp_init(&bigValue);
910 if (mp_read_radix(&bigValue, hexchars, 16) != MP_OKAY) {
911 mp_clear(&bigValue);
912 Py_DECREF(hexstr);
913 PyErr_NoMemory();
914 return NULL;
915 }
916 Py_DECREF(hexstr);
917 bigValue.sign = neg ? MP_NEG : MP_ZPOS;
918 result = Tcl_NewBignumObj(&bigValue);
919 mp_clear(&bigValue);
920 if (result == NULL) {
921 PyErr_NoMemory();
922 return NULL;
923 }
924 return result;
925 }
926
927 static Tcl_Obj*
AsObj(PyObject * value)928 AsObj(PyObject *value)
929 {
930 Tcl_Obj *result;
931
932 if (PyBytes_Check(value)) {
933 if (PyBytes_GET_SIZE(value) >= INT_MAX) {
934 PyErr_SetString(PyExc_OverflowError, "bytes object is too long");
935 return NULL;
936 }
937 return Tcl_NewByteArrayObj((unsigned char *)PyBytes_AS_STRING(value),
938 (int)PyBytes_GET_SIZE(value));
939 }
940
941 if (PyBool_Check(value))
942 return Tcl_NewBooleanObj(PyObject_IsTrue(value));
943
944 if (PyLong_CheckExact(value)) {
945 int overflow;
946 long longValue;
947 #ifdef TCL_WIDE_INT_TYPE
948 Tcl_WideInt wideValue;
949 #endif
950 longValue = PyLong_AsLongAndOverflow(value, &overflow);
951 if (!overflow) {
952 return Tcl_NewLongObj(longValue);
953 }
954 /* If there is an overflow in the long conversion,
955 fall through to wideInt handling. */
956 #ifdef TCL_WIDE_INT_TYPE
957 if (_PyLong_AsByteArray((PyLongObject *)value,
958 (unsigned char *)(void *)&wideValue,
959 sizeof(wideValue),
960 PY_LITTLE_ENDIAN,
961 /* signed */ 1) == 0) {
962 return Tcl_NewWideIntObj(wideValue);
963 }
964 PyErr_Clear();
965 #endif
966 /* If there is an overflow in the wideInt conversion,
967 fall through to bignum handling. */
968 return asBignumObj(value);
969 /* If there is no wideInt or bignum support,
970 fall through to default object handling. */
971 }
972
973 if (PyFloat_Check(value))
974 return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
975
976 if (PyTuple_Check(value) || PyList_Check(value)) {
977 Tcl_Obj **argv;
978 Py_ssize_t size, i;
979
980 size = PySequence_Fast_GET_SIZE(value);
981 if (size == 0)
982 return Tcl_NewListObj(0, NULL);
983 if (!CHECK_SIZE(size, sizeof(Tcl_Obj *))) {
984 PyErr_SetString(PyExc_OverflowError,
985 PyTuple_Check(value) ? "tuple is too long" :
986 "list is too long");
987 return NULL;
988 }
989 argv = (Tcl_Obj **) PyMem_Malloc(((size_t)size) * sizeof(Tcl_Obj *));
990 if (!argv) {
991 PyErr_NoMemory();
992 return NULL;
993 }
994 for (i = 0; i < size; i++)
995 argv[i] = AsObj(PySequence_Fast_GET_ITEM(value,i));
996 result = Tcl_NewListObj((int)size, argv);
997 PyMem_Free(argv);
998 return result;
999 }
1000
1001 if (PyUnicode_Check(value)) {
1002 if (PyUnicode_READY(value) == -1)
1003 return NULL;
1004
1005 Py_ssize_t size = PyUnicode_GET_LENGTH(value);
1006 if (size == 0) {
1007 return Tcl_NewStringObj("", 0);
1008 }
1009 if (!CHECK_SIZE(size, sizeof(Tcl_UniChar))) {
1010 PyErr_SetString(PyExc_OverflowError, "string is too long");
1011 return NULL;
1012 }
1013 if (PyUnicode_IS_ASCII(value)) {
1014 return Tcl_NewStringObj((const char *)PyUnicode_DATA(value),
1015 (int)size);
1016 }
1017
1018 PyObject *encoded;
1019 #if USE_TCL_UNICODE
1020 if (sizeof(Tcl_UniChar) == 2)
1021 encoded = _PyUnicode_EncodeUTF16(value,
1022 "surrogatepass", NATIVE_BYTEORDER);
1023 else if (sizeof(Tcl_UniChar) == 4)
1024 encoded = _PyUnicode_EncodeUTF32(value,
1025 "surrogatepass", NATIVE_BYTEORDER);
1026 else
1027 Py_UNREACHABLE();
1028 #else
1029 encoded = _PyUnicode_AsUTF8String(value, "surrogateescape");
1030 #endif
1031 if (!encoded) {
1032 return NULL;
1033 }
1034 size = PyBytes_GET_SIZE(encoded);
1035 if (size > INT_MAX) {
1036 Py_DECREF(encoded);
1037 PyErr_SetString(PyExc_OverflowError, "string is too long");
1038 return NULL;
1039 }
1040 #if USE_TCL_UNICODE
1041 result = Tcl_NewUnicodeObj((const Tcl_UniChar *)PyBytes_AS_STRING(encoded),
1042 (int)(size / sizeof(Tcl_UniChar)));
1043 #else
1044 result = Tcl_NewStringObj(PyBytes_AS_STRING(encoded), (int)size);
1045 #endif
1046 Py_DECREF(encoded);
1047 return result;
1048 }
1049
1050 if (PyTclObject_Check(value)) {
1051 return ((PyTclObject*)value)->value;
1052 }
1053
1054 {
1055 PyObject *v = PyObject_Str(value);
1056 if (!v)
1057 return 0;
1058 result = AsObj(v);
1059 Py_DECREF(v);
1060 return result;
1061 }
1062 }
1063
1064 static PyObject *
fromBoolean(TkappObject * tkapp,Tcl_Obj * value)1065 fromBoolean(TkappObject *tkapp, Tcl_Obj *value)
1066 {
1067 int boolValue;
1068 if (Tcl_GetBooleanFromObj(Tkapp_Interp(tkapp), value, &boolValue) == TCL_ERROR)
1069 return Tkinter_Error(tkapp);
1070 return PyBool_FromLong(boolValue);
1071 }
1072
1073 static PyObject*
fromWideIntObj(TkappObject * tkapp,Tcl_Obj * value)1074 fromWideIntObj(TkappObject *tkapp, Tcl_Obj *value)
1075 {
1076 Tcl_WideInt wideValue;
1077 if (Tcl_GetWideIntFromObj(Tkapp_Interp(tkapp), value, &wideValue) == TCL_OK) {
1078 if (sizeof(wideValue) <= SIZEOF_LONG_LONG)
1079 return PyLong_FromLongLong(wideValue);
1080 return _PyLong_FromByteArray((unsigned char *)(void *)&wideValue,
1081 sizeof(wideValue),
1082 PY_LITTLE_ENDIAN,
1083 /* signed */ 1);
1084 }
1085 return NULL;
1086 }
1087
1088 static PyObject*
fromBignumObj(TkappObject * tkapp,Tcl_Obj * value)1089 fromBignumObj(TkappObject *tkapp, Tcl_Obj *value)
1090 {
1091 mp_int bigValue;
1092 mp_err err;
1093 #if USE_DEPRECATED_TOMMATH_API
1094 unsigned long numBytes;
1095 #else
1096 size_t numBytes;
1097 #endif
1098 unsigned char *bytes;
1099 PyObject *res;
1100
1101 if (Tcl_GetBignumFromObj(Tkapp_Interp(tkapp), value, &bigValue) != TCL_OK)
1102 return Tkinter_Error(tkapp);
1103 #if USE_DEPRECATED_TOMMATH_API
1104 numBytes = mp_unsigned_bin_size(&bigValue);
1105 #else
1106 numBytes = mp_ubin_size(&bigValue);
1107 #endif
1108 bytes = PyMem_Malloc(numBytes);
1109 if (bytes == NULL) {
1110 mp_clear(&bigValue);
1111 return PyErr_NoMemory();
1112 }
1113 #if USE_DEPRECATED_TOMMATH_API
1114 err = mp_to_unsigned_bin_n(&bigValue, bytes, &numBytes);
1115 #else
1116 err = mp_to_ubin(&bigValue, bytes, numBytes, NULL);
1117 #endif
1118 if (err != MP_OKAY) {
1119 mp_clear(&bigValue);
1120 PyMem_Free(bytes);
1121 return PyErr_NoMemory();
1122 }
1123 res = _PyLong_FromByteArray(bytes, numBytes,
1124 /* big-endian */ 0,
1125 /* unsigned */ 0);
1126 PyMem_Free(bytes);
1127 if (res != NULL && bigValue.sign == MP_NEG) {
1128 PyObject *res2 = PyNumber_Negative(res);
1129 Py_DECREF(res);
1130 res = res2;
1131 }
1132 mp_clear(&bigValue);
1133 return res;
1134 }
1135
1136 static PyObject*
FromObj(TkappObject * tkapp,Tcl_Obj * value)1137 FromObj(TkappObject *tkapp, Tcl_Obj *value)
1138 {
1139 PyObject *result = NULL;
1140 Tcl_Interp *interp = Tkapp_Interp(tkapp);
1141
1142 if (value->typePtr == NULL) {
1143 return unicodeFromTclObj(value);
1144 }
1145
1146 if (value->typePtr == tkapp->BooleanType ||
1147 value->typePtr == tkapp->OldBooleanType) {
1148 return fromBoolean(tkapp, value);
1149 }
1150
1151 if (value->typePtr == tkapp->ByteArrayType) {
1152 int size;
1153 char *data = (char*)Tcl_GetByteArrayFromObj(value, &size);
1154 return PyBytes_FromStringAndSize(data, size);
1155 }
1156
1157 if (value->typePtr == tkapp->DoubleType) {
1158 return PyFloat_FromDouble(value->internalRep.doubleValue);
1159 }
1160
1161 if (value->typePtr == tkapp->IntType) {
1162 long longValue;
1163 if (Tcl_GetLongFromObj(interp, value, &longValue) == TCL_OK)
1164 return PyLong_FromLong(longValue);
1165 /* If there is an error in the long conversion,
1166 fall through to wideInt handling. */
1167 }
1168
1169 if (value->typePtr == tkapp->IntType ||
1170 value->typePtr == tkapp->WideIntType) {
1171 result = fromWideIntObj(tkapp, value);
1172 if (result != NULL || PyErr_Occurred())
1173 return result;
1174 Tcl_ResetResult(interp);
1175 /* If there is an error in the wideInt conversion,
1176 fall through to bignum handling. */
1177 }
1178
1179 if (value->typePtr == tkapp->IntType ||
1180 value->typePtr == tkapp->WideIntType ||
1181 value->typePtr == tkapp->BignumType) {
1182 return fromBignumObj(tkapp, value);
1183 }
1184
1185 if (value->typePtr == tkapp->ListType) {
1186 int size;
1187 int i, status;
1188 PyObject *elem;
1189 Tcl_Obj *tcl_elem;
1190
1191 status = Tcl_ListObjLength(interp, value, &size);
1192 if (status == TCL_ERROR)
1193 return Tkinter_Error(tkapp);
1194 result = PyTuple_New(size);
1195 if (!result)
1196 return NULL;
1197 for (i = 0; i < size; i++) {
1198 status = Tcl_ListObjIndex(interp, value, i, &tcl_elem);
1199 if (status == TCL_ERROR) {
1200 Py_DECREF(result);
1201 return Tkinter_Error(tkapp);
1202 }
1203 elem = FromObj(tkapp, tcl_elem);
1204 if (!elem) {
1205 Py_DECREF(result);
1206 return NULL;
1207 }
1208 PyTuple_SET_ITEM(result, i, elem);
1209 }
1210 return result;
1211 }
1212
1213 if (value->typePtr == tkapp->ProcBodyType) {
1214 /* fall through: return tcl object. */
1215 }
1216
1217 if (value->typePtr == tkapp->StringType) {
1218 return unicodeFromTclObj(value);
1219 }
1220
1221 if (tkapp->BooleanType == NULL &&
1222 strcmp(value->typePtr->name, "booleanString") == 0) {
1223 /* booleanString type is not registered in Tcl */
1224 tkapp->BooleanType = value->typePtr;
1225 return fromBoolean(tkapp, value);
1226 }
1227
1228 if (tkapp->BignumType == NULL &&
1229 strcmp(value->typePtr->name, "bignum") == 0) {
1230 /* bignum type is not registered in Tcl */
1231 tkapp->BignumType = value->typePtr;
1232 return fromBignumObj(tkapp, value);
1233 }
1234
1235 return newPyTclObject(value);
1236 }
1237
1238 /* This mutex synchronizes inter-thread command calls. */
1239 TCL_DECLARE_MUTEX(call_mutex)
1240
1241 typedef struct Tkapp_CallEvent {
1242 Tcl_Event ev; /* Must be first */
1243 TkappObject *self;
1244 PyObject *args;
1245 int flags;
1246 PyObject **res;
1247 PyObject **exc_type, **exc_value, **exc_tb;
1248 Tcl_Condition *done;
1249 } Tkapp_CallEvent;
1250
1251 void
Tkapp_CallDeallocArgs(Tcl_Obj ** objv,Tcl_Obj ** objStore,int objc)1252 Tkapp_CallDeallocArgs(Tcl_Obj** objv, Tcl_Obj** objStore, int objc)
1253 {
1254 int i;
1255 for (i = 0; i < objc; i++)
1256 Tcl_DecrRefCount(objv[i]);
1257 if (objv != objStore)
1258 PyMem_Free(objv);
1259 }
1260
1261 /* Convert Python objects to Tcl objects. This must happen in the
1262 interpreter thread, which may or may not be the calling thread. */
1263
1264 static Tcl_Obj**
Tkapp_CallArgs(PyObject * args,Tcl_Obj ** objStore,int * pobjc)1265 Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc)
1266 {
1267 Tcl_Obj **objv = objStore;
1268 Py_ssize_t objc = 0, i;
1269 if (args == NULL)
1270 /* do nothing */;
1271
1272 else if (!(PyTuple_Check(args) || PyList_Check(args))) {
1273 objv[0] = AsObj(args);
1274 if (objv[0] == NULL)
1275 goto finally;
1276 objc = 1;
1277 Tcl_IncrRefCount(objv[0]);
1278 }
1279 else {
1280 objc = PySequence_Fast_GET_SIZE(args);
1281
1282 if (objc > ARGSZ) {
1283 if (!CHECK_SIZE(objc, sizeof(Tcl_Obj *))) {
1284 PyErr_SetString(PyExc_OverflowError,
1285 PyTuple_Check(args) ? "tuple is too long" :
1286 "list is too long");
1287 return NULL;
1288 }
1289 objv = (Tcl_Obj **)PyMem_Malloc(((size_t)objc) * sizeof(Tcl_Obj *));
1290 if (objv == NULL) {
1291 PyErr_NoMemory();
1292 objc = 0;
1293 goto finally;
1294 }
1295 }
1296
1297 for (i = 0; i < objc; i++) {
1298 PyObject *v = PySequence_Fast_GET_ITEM(args, i);
1299 if (v == Py_None) {
1300 objc = i;
1301 break;
1302 }
1303 objv[i] = AsObj(v);
1304 if (!objv[i]) {
1305 /* Reset objc, so it attempts to clear
1306 objects only up to i. */
1307 objc = i;
1308 goto finally;
1309 }
1310 Tcl_IncrRefCount(objv[i]);
1311 }
1312 }
1313 *pobjc = (int)objc;
1314 return objv;
1315 finally:
1316 Tkapp_CallDeallocArgs(objv, objStore, (int)objc);
1317 return NULL;
1318 }
1319
1320 /* Convert the results of a command call into a Python string. */
1321
1322 static PyObject *
Tkapp_UnicodeResult(TkappObject * self)1323 Tkapp_UnicodeResult(TkappObject *self)
1324 {
1325 return unicodeFromTclObj(Tcl_GetObjResult(self->interp));
1326 }
1327
1328
1329 /* Convert the results of a command call into a Python objects. */
1330
1331 static PyObject *
Tkapp_ObjectResult(TkappObject * self)1332 Tkapp_ObjectResult(TkappObject *self)
1333 {
1334 PyObject *res = NULL;
1335 Tcl_Obj *value = Tcl_GetObjResult(self->interp);
1336 if (self->wantobjects) {
1337 /* Not sure whether the IncrRef is necessary, but something
1338 may overwrite the interpreter result while we are
1339 converting it. */
1340 Tcl_IncrRefCount(value);
1341 res = FromObj(self, value);
1342 Tcl_DecrRefCount(value);
1343 } else {
1344 res = unicodeFromTclObj(value);
1345 }
1346 return res;
1347 }
1348
1349
1350 /* Tkapp_CallProc is the event procedure that is executed in the context of
1351 the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't
1352 hold the Python lock. */
1353
1354 static int
Tkapp_CallProc(Tkapp_CallEvent * e,int flags)1355 Tkapp_CallProc(Tkapp_CallEvent *e, int flags)
1356 {
1357 Tcl_Obj *objStore[ARGSZ];
1358 Tcl_Obj **objv;
1359 int objc;
1360 int i;
1361 ENTER_PYTHON
1362 objv = Tkapp_CallArgs(e->args, objStore, &objc);
1363 if (!objv) {
1364 PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb);
1365 *(e->res) = NULL;
1366 }
1367 LEAVE_PYTHON
1368 if (!objv)
1369 goto done;
1370 i = Tcl_EvalObjv(e->self->interp, objc, objv, e->flags);
1371 ENTER_PYTHON
1372 if (i == TCL_ERROR) {
1373 *(e->res) = Tkinter_Error(e->self);
1374 }
1375 else {
1376 *(e->res) = Tkapp_ObjectResult(e->self);
1377 }
1378 if (*(e->res) == NULL) {
1379 PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb);
1380 }
1381 LEAVE_PYTHON
1382
1383 Tkapp_CallDeallocArgs(objv, objStore, objc);
1384 done:
1385 /* Wake up calling thread. */
1386 Tcl_MutexLock(&call_mutex);
1387 Tcl_ConditionNotify(e->done);
1388 Tcl_MutexUnlock(&call_mutex);
1389 return 1;
1390 }
1391
1392
1393 /* This is the main entry point for calling a Tcl command.
1394 It supports three cases, with regard to threading:
1395 1. Tcl is not threaded: Must have the Tcl lock, then can invoke command in
1396 the context of the calling thread.
1397 2. Tcl is threaded, caller of the command is in the interpreter thread:
1398 Execute the command in the calling thread. Since the Tcl lock will
1399 not be used, we can merge that with case 1.
1400 3. Tcl is threaded, caller is in a different thread: Must queue an event to
1401 the interpreter thread. Allocation of Tcl objects needs to occur in the
1402 interpreter thread, so we ship the PyObject* args to the target thread,
1403 and perform processing there. */
1404
1405 static PyObject *
Tkapp_Call(PyObject * selfptr,PyObject * args)1406 Tkapp_Call(PyObject *selfptr, PyObject *args)
1407 {
1408 Tcl_Obj *objStore[ARGSZ];
1409 Tcl_Obj **objv = NULL;
1410 int objc, i;
1411 PyObject *res = NULL;
1412 TkappObject *self = (TkappObject*)selfptr;
1413 int flags = TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL;
1414
1415 /* If args is a single tuple, replace with contents of tuple */
1416 if (PyTuple_GET_SIZE(args) == 1) {
1417 PyObject *item = PyTuple_GET_ITEM(args, 0);
1418 if (PyTuple_Check(item))
1419 args = item;
1420 }
1421 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
1422 /* We cannot call the command directly. Instead, we must
1423 marshal the parameters to the interpreter thread. */
1424 Tkapp_CallEvent *ev;
1425 Tcl_Condition cond = NULL;
1426 PyObject *exc_type, *exc_value, *exc_tb;
1427 if (!WaitForMainloop(self))
1428 return NULL;
1429 ev = (Tkapp_CallEvent*)attemptckalloc(sizeof(Tkapp_CallEvent));
1430 if (ev == NULL) {
1431 PyErr_NoMemory();
1432 return NULL;
1433 }
1434 ev->ev.proc = (Tcl_EventProc*)Tkapp_CallProc;
1435 ev->self = self;
1436 ev->args = args;
1437 ev->res = &res;
1438 ev->exc_type = &exc_type;
1439 ev->exc_value = &exc_value;
1440 ev->exc_tb = &exc_tb;
1441 ev->done = &cond;
1442
1443 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &call_mutex);
1444
1445 if (res == NULL) {
1446 if (exc_type)
1447 PyErr_Restore(exc_type, exc_value, exc_tb);
1448 else
1449 PyErr_SetObject(Tkinter_TclError, exc_value);
1450 }
1451 Tcl_ConditionFinalize(&cond);
1452 }
1453 else
1454 {
1455
1456 objv = Tkapp_CallArgs(args, objStore, &objc);
1457 if (!objv)
1458 return NULL;
1459
1460 ENTER_TCL
1461
1462 i = Tcl_EvalObjv(self->interp, objc, objv, flags);
1463
1464 ENTER_OVERLAP
1465
1466 if (i == TCL_ERROR)
1467 Tkinter_Error(self);
1468 else
1469 res = Tkapp_ObjectResult(self);
1470
1471 LEAVE_OVERLAP_TCL
1472
1473 Tkapp_CallDeallocArgs(objv, objStore, objc);
1474 }
1475 return res;
1476 }
1477
1478
1479 /*[clinic input]
1480 _tkinter.tkapp.eval
1481
1482 script: str
1483 /
1484
1485 [clinic start generated code]*/
1486
1487 static PyObject *
_tkinter_tkapp_eval_impl(TkappObject * self,const char * script)1488 _tkinter_tkapp_eval_impl(TkappObject *self, const char *script)
1489 /*[clinic end generated code: output=24b79831f700dea0 input=481484123a455f22]*/
1490 {
1491 PyObject *res = NULL;
1492 int err;
1493
1494 CHECK_STRING_LENGTH(script);
1495 CHECK_TCL_APPARTMENT;
1496
1497 ENTER_TCL
1498 err = Tcl_Eval(Tkapp_Interp(self), script);
1499 ENTER_OVERLAP
1500 if (err == TCL_ERROR)
1501 res = Tkinter_Error(self);
1502 else
1503 res = Tkapp_UnicodeResult(self);
1504 LEAVE_OVERLAP_TCL
1505 return res;
1506 }
1507
1508 /*[clinic input]
1509 _tkinter.tkapp.evalfile
1510
1511 fileName: str
1512 /
1513
1514 [clinic start generated code]*/
1515
1516 static PyObject *
_tkinter_tkapp_evalfile_impl(TkappObject * self,const char * fileName)1517 _tkinter_tkapp_evalfile_impl(TkappObject *self, const char *fileName)
1518 /*[clinic end generated code: output=63be88dcee4f11d3 input=873ab707e5e947e1]*/
1519 {
1520 PyObject *res = NULL;
1521 int err;
1522
1523 CHECK_STRING_LENGTH(fileName);
1524 CHECK_TCL_APPARTMENT;
1525
1526 ENTER_TCL
1527 err = Tcl_EvalFile(Tkapp_Interp(self), fileName);
1528 ENTER_OVERLAP
1529 if (err == TCL_ERROR)
1530 res = Tkinter_Error(self);
1531 else
1532 res = Tkapp_UnicodeResult(self);
1533 LEAVE_OVERLAP_TCL
1534 return res;
1535 }
1536
1537 /*[clinic input]
1538 _tkinter.tkapp.record
1539
1540 script: str
1541 /
1542
1543 [clinic start generated code]*/
1544
1545 static PyObject *
_tkinter_tkapp_record_impl(TkappObject * self,const char * script)1546 _tkinter_tkapp_record_impl(TkappObject *self, const char *script)
1547 /*[clinic end generated code: output=0ffe08a0061730df input=c0b0db5a21412cac]*/
1548 {
1549 PyObject *res = NULL;
1550 int err;
1551
1552 CHECK_STRING_LENGTH(script);
1553 CHECK_TCL_APPARTMENT;
1554
1555 ENTER_TCL
1556 err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL);
1557 ENTER_OVERLAP
1558 if (err == TCL_ERROR)
1559 res = Tkinter_Error(self);
1560 else
1561 res = Tkapp_UnicodeResult(self);
1562 LEAVE_OVERLAP_TCL
1563 return res;
1564 }
1565
1566 /*[clinic input]
1567 _tkinter.tkapp.adderrorinfo
1568
1569 msg: str
1570 /
1571
1572 [clinic start generated code]*/
1573
1574 static PyObject *
_tkinter_tkapp_adderrorinfo_impl(TkappObject * self,const char * msg)1575 _tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg)
1576 /*[clinic end generated code: output=52162eaca2ee53cb input=f4b37aec7c7e8c77]*/
1577 {
1578 CHECK_STRING_LENGTH(msg);
1579 CHECK_TCL_APPARTMENT;
1580
1581 ENTER_TCL
1582 Tcl_AddErrorInfo(Tkapp_Interp(self), msg);
1583 LEAVE_TCL
1584
1585 Py_RETURN_NONE;
1586 }
1587
1588
1589
1590 /** Tcl Variable **/
1591
1592 typedef PyObject* (*EventFunc)(TkappObject *, PyObject *, int);
1593
1594 TCL_DECLARE_MUTEX(var_mutex)
1595
1596 typedef struct VarEvent {
1597 Tcl_Event ev; /* must be first */
1598 TkappObject *self;
1599 PyObject *args;
1600 int flags;
1601 EventFunc func;
1602 PyObject **res;
1603 PyObject **exc_type;
1604 PyObject **exc_val;
1605 Tcl_Condition *cond;
1606 } VarEvent;
1607
1608 /*[python]
1609
1610 class varname_converter(CConverter):
1611 type = 'const char *'
1612 converter = 'varname_converter'
1613
1614 [python]*/
1615 /*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
1616
1617 static int
varname_converter(PyObject * in,void * _out)1618 varname_converter(PyObject *in, void *_out)
1619 {
1620 const char *s;
1621 const char **out = (const char**)_out;
1622 if (PyBytes_Check(in)) {
1623 if (PyBytes_GET_SIZE(in) > INT_MAX) {
1624 PyErr_SetString(PyExc_OverflowError, "bytes object is too long");
1625 return 0;
1626 }
1627 s = PyBytes_AS_STRING(in);
1628 if (strlen(s) != (size_t)PyBytes_GET_SIZE(in)) {
1629 PyErr_SetString(PyExc_ValueError, "embedded null byte");
1630 return 0;
1631 }
1632 *out = s;
1633 return 1;
1634 }
1635 if (PyUnicode_Check(in)) {
1636 Py_ssize_t size;
1637 s = PyUnicode_AsUTF8AndSize(in, &size);
1638 if (s == NULL) {
1639 return 0;
1640 }
1641 if (size > INT_MAX) {
1642 PyErr_SetString(PyExc_OverflowError, "string is too long");
1643 return 0;
1644 }
1645 if (strlen(s) != (size_t)size) {
1646 PyErr_SetString(PyExc_ValueError, "embedded null character");
1647 return 0;
1648 }
1649 *out = s;
1650 return 1;
1651 }
1652 if (PyTclObject_Check(in)) {
1653 *out = Tcl_GetString(((PyTclObject *)in)->value);
1654 return 1;
1655 }
1656 PyErr_Format(PyExc_TypeError,
1657 "must be str, bytes or Tcl_Obj, not %.50s",
1658 Py_TYPE(in)->tp_name);
1659 return 0;
1660 }
1661
1662
1663 static void
var_perform(VarEvent * ev)1664 var_perform(VarEvent *ev)
1665 {
1666 *(ev->res) = ev->func(ev->self, ev->args, ev->flags);
1667 if (!*(ev->res)) {
1668 PyObject *exc, *val, *tb;
1669 PyErr_Fetch(&exc, &val, &tb);
1670 PyErr_NormalizeException(&exc, &val, &tb);
1671 *(ev->exc_type) = exc;
1672 *(ev->exc_val) = val;
1673 Py_XDECREF(tb);
1674 }
1675
1676 }
1677
1678 static int
var_proc(VarEvent * ev,int flags)1679 var_proc(VarEvent* ev, int flags)
1680 {
1681 ENTER_PYTHON
1682 var_perform(ev);
1683 Tcl_MutexLock(&var_mutex);
1684 Tcl_ConditionNotify(ev->cond);
1685 Tcl_MutexUnlock(&var_mutex);
1686 LEAVE_PYTHON
1687 return 1;
1688 }
1689
1690
1691 static PyObject*
var_invoke(EventFunc func,PyObject * selfptr,PyObject * args,int flags)1692 var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags)
1693 {
1694 TkappObject *self = (TkappObject*)selfptr;
1695 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
1696 VarEvent *ev;
1697 PyObject *res, *exc_type, *exc_val;
1698 Tcl_Condition cond = NULL;
1699
1700 /* The current thread is not the interpreter thread. Marshal
1701 the call to the interpreter thread, then wait for
1702 completion. */
1703 if (!WaitForMainloop(self))
1704 return NULL;
1705
1706 ev = (VarEvent*)attemptckalloc(sizeof(VarEvent));
1707 if (ev == NULL) {
1708 PyErr_NoMemory();
1709 return NULL;
1710 }
1711 ev->self = self;
1712 ev->args = args;
1713 ev->flags = flags;
1714 ev->func = func;
1715 ev->res = &res;
1716 ev->exc_type = &exc_type;
1717 ev->exc_val = &exc_val;
1718 ev->cond = &cond;
1719 ev->ev.proc = (Tcl_EventProc*)var_proc;
1720 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &var_mutex);
1721 Tcl_ConditionFinalize(&cond);
1722 if (!res) {
1723 PyErr_SetObject(exc_type, exc_val);
1724 Py_DECREF(exc_type);
1725 Py_DECREF(exc_val);
1726 return NULL;
1727 }
1728 return res;
1729 }
1730 /* Tcl is not threaded, or this is the interpreter thread. */
1731 return func(self, args, flags);
1732 }
1733
1734 static PyObject *
SetVar(TkappObject * self,PyObject * args,int flags)1735 SetVar(TkappObject *self, PyObject *args, int flags)
1736 {
1737 const char *name1, *name2;
1738 PyObject *newValue;
1739 PyObject *res = NULL;
1740 Tcl_Obj *newval, *ok;
1741
1742 switch (PyTuple_GET_SIZE(args)) {
1743 case 2:
1744 if (!PyArg_ParseTuple(args, "O&O:setvar",
1745 varname_converter, &name1, &newValue))
1746 return NULL;
1747 /* XXX Acquire tcl lock??? */
1748 newval = AsObj(newValue);
1749 if (newval == NULL)
1750 return NULL;
1751 ENTER_TCL
1752 ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, NULL,
1753 newval, flags);
1754 ENTER_OVERLAP
1755 if (!ok)
1756 Tkinter_Error(self);
1757 else {
1758 res = Py_None;
1759 Py_INCREF(res);
1760 }
1761 LEAVE_OVERLAP_TCL
1762 break;
1763 case 3:
1764 if (!PyArg_ParseTuple(args, "ssO:setvar",
1765 &name1, &name2, &newValue))
1766 return NULL;
1767 CHECK_STRING_LENGTH(name1);
1768 CHECK_STRING_LENGTH(name2);
1769 /* XXX must hold tcl lock already??? */
1770 newval = AsObj(newValue);
1771 ENTER_TCL
1772 ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, name2, newval, flags);
1773 ENTER_OVERLAP
1774 if (!ok)
1775 Tkinter_Error(self);
1776 else {
1777 res = Py_None;
1778 Py_INCREF(res);
1779 }
1780 LEAVE_OVERLAP_TCL
1781 break;
1782 default:
1783 PyErr_SetString(PyExc_TypeError, "setvar requires 2 to 3 arguments");
1784 return NULL;
1785 }
1786 return res;
1787 }
1788
1789 static PyObject *
Tkapp_SetVar(PyObject * self,PyObject * args)1790 Tkapp_SetVar(PyObject *self, PyObject *args)
1791 {
1792 return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG);
1793 }
1794
1795 static PyObject *
Tkapp_GlobalSetVar(PyObject * self,PyObject * args)1796 Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
1797 {
1798 return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1799 }
1800
1801
1802
1803 static PyObject *
GetVar(TkappObject * self,PyObject * args,int flags)1804 GetVar(TkappObject *self, PyObject *args, int flags)
1805 {
1806 const char *name1, *name2=NULL;
1807 PyObject *res = NULL;
1808 Tcl_Obj *tres;
1809
1810 if (!PyArg_ParseTuple(args, "O&|s:getvar",
1811 varname_converter, &name1, &name2))
1812 return NULL;
1813
1814 CHECK_STRING_LENGTH(name2);
1815 ENTER_TCL
1816 tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags);
1817 ENTER_OVERLAP
1818 if (tres == NULL) {
1819 Tkinter_Error(self);
1820 } else {
1821 if (self->wantobjects) {
1822 res = FromObj(self, tres);
1823 }
1824 else {
1825 res = unicodeFromTclObj(tres);
1826 }
1827 }
1828 LEAVE_OVERLAP_TCL
1829 return res;
1830 }
1831
1832 static PyObject *
Tkapp_GetVar(PyObject * self,PyObject * args)1833 Tkapp_GetVar(PyObject *self, PyObject *args)
1834 {
1835 return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG);
1836 }
1837
1838 static PyObject *
Tkapp_GlobalGetVar(PyObject * self,PyObject * args)1839 Tkapp_GlobalGetVar(PyObject *self, PyObject *args)
1840 {
1841 return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1842 }
1843
1844
1845
1846 static PyObject *
UnsetVar(TkappObject * self,PyObject * args,int flags)1847 UnsetVar(TkappObject *self, PyObject *args, int flags)
1848 {
1849 char *name1, *name2=NULL;
1850 int code;
1851 PyObject *res = NULL;
1852
1853 if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
1854 return NULL;
1855
1856 CHECK_STRING_LENGTH(name1);
1857 CHECK_STRING_LENGTH(name2);
1858 ENTER_TCL
1859 code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
1860 ENTER_OVERLAP
1861 if (code == TCL_ERROR)
1862 res = Tkinter_Error(self);
1863 else {
1864 Py_INCREF(Py_None);
1865 res = Py_None;
1866 }
1867 LEAVE_OVERLAP_TCL
1868 return res;
1869 }
1870
1871 static PyObject *
Tkapp_UnsetVar(PyObject * self,PyObject * args)1872 Tkapp_UnsetVar(PyObject *self, PyObject *args)
1873 {
1874 return var_invoke(UnsetVar, self, args, TCL_LEAVE_ERR_MSG);
1875 }
1876
1877 static PyObject *
Tkapp_GlobalUnsetVar(PyObject * self,PyObject * args)1878 Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args)
1879 {
1880 return var_invoke(UnsetVar, self, args,
1881 TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1882 }
1883
1884
1885
1886 /** Tcl to Python **/
1887
1888 /*[clinic input]
1889 _tkinter.tkapp.getint
1890
1891 arg: object
1892 /
1893
1894 [clinic start generated code]*/
1895
1896 static PyObject *
_tkinter_tkapp_getint(TkappObject * self,PyObject * arg)1897 _tkinter_tkapp_getint(TkappObject *self, PyObject *arg)
1898 /*[clinic end generated code: output=88cf293fae307cfe input=034026997c5b91f8]*/
1899 {
1900 char *s;
1901 Tcl_Obj *value;
1902 PyObject *result;
1903
1904 if (PyLong_Check(arg)) {
1905 Py_INCREF(arg);
1906 return arg;
1907 }
1908
1909 if (PyTclObject_Check(arg)) {
1910 value = ((PyTclObject*)arg)->value;
1911 Tcl_IncrRefCount(value);
1912 }
1913 else {
1914 if (!PyArg_Parse(arg, "s:getint", &s))
1915 return NULL;
1916 CHECK_STRING_LENGTH(s);
1917 value = Tcl_NewStringObj(s, -1);
1918 if (value == NULL)
1919 return Tkinter_Error(self);
1920 }
1921 /* Don't use Tcl_GetInt() because it returns ambiguous result for value
1922 in ranges -2**32..-2**31-1 and 2**31..2**32-1 (on 32-bit platform).
1923
1924 Prefer bignum because Tcl_GetWideIntFromObj returns ambiguous result for
1925 value in ranges -2**64..-2**63-1 and 2**63..2**64-1 (on 32-bit platform).
1926 */
1927 result = fromBignumObj(self, value);
1928 Tcl_DecrRefCount(value);
1929 if (result != NULL || PyErr_Occurred())
1930 return result;
1931 return Tkinter_Error(self);
1932 }
1933
1934 /*[clinic input]
1935 _tkinter.tkapp.getdouble
1936
1937 arg: object
1938 /
1939
1940 [clinic start generated code]*/
1941
1942 static PyObject *
_tkinter_tkapp_getdouble(TkappObject * self,PyObject * arg)1943 _tkinter_tkapp_getdouble(TkappObject *self, PyObject *arg)
1944 /*[clinic end generated code: output=c52b138bd8b956b9 input=22015729ce9ef7f8]*/
1945 {
1946 char *s;
1947 double v;
1948
1949 if (PyFloat_Check(arg)) {
1950 Py_INCREF(arg);
1951 return arg;
1952 }
1953
1954 if (PyNumber_Check(arg)) {
1955 return PyNumber_Float(arg);
1956 }
1957
1958 if (PyTclObject_Check(arg)) {
1959 if (Tcl_GetDoubleFromObj(Tkapp_Interp(self),
1960 ((PyTclObject*)arg)->value,
1961 &v) == TCL_ERROR)
1962 return Tkinter_Error(self);
1963 return PyFloat_FromDouble(v);
1964 }
1965
1966 if (!PyArg_Parse(arg, "s:getdouble", &s))
1967 return NULL;
1968 CHECK_STRING_LENGTH(s);
1969 if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1970 return Tkinter_Error(self);
1971 return PyFloat_FromDouble(v);
1972 }
1973
1974 /*[clinic input]
1975 _tkinter.tkapp.getboolean
1976
1977 arg: object
1978 /
1979
1980 [clinic start generated code]*/
1981
1982 static PyObject *
_tkinter_tkapp_getboolean(TkappObject * self,PyObject * arg)1983 _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg)
1984 /*[clinic end generated code: output=726a9ae445821d91 input=7f11248ef8f8776e]*/
1985 {
1986 char *s;
1987 int v;
1988
1989 if (PyLong_Check(arg)) { /* int or bool */
1990 return PyBool_FromLong(Py_SIZE(arg) != 0);
1991 }
1992
1993 if (PyTclObject_Check(arg)) {
1994 if (Tcl_GetBooleanFromObj(Tkapp_Interp(self),
1995 ((PyTclObject*)arg)->value,
1996 &v) == TCL_ERROR)
1997 return Tkinter_Error(self);
1998 return PyBool_FromLong(v);
1999 }
2000
2001 if (!PyArg_Parse(arg, "s:getboolean", &s))
2002 return NULL;
2003 CHECK_STRING_LENGTH(s);
2004 if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
2005 return Tkinter_Error(self);
2006 return PyBool_FromLong(v);
2007 }
2008
2009 /*[clinic input]
2010 _tkinter.tkapp.exprstring
2011
2012 s: str
2013 /
2014
2015 [clinic start generated code]*/
2016
2017 static PyObject *
_tkinter_tkapp_exprstring_impl(TkappObject * self,const char * s)2018 _tkinter_tkapp_exprstring_impl(TkappObject *self, const char *s)
2019 /*[clinic end generated code: output=beda323d3ed0abb1 input=fa78f751afb2f21b]*/
2020 {
2021 PyObject *res = NULL;
2022 int retval;
2023
2024 CHECK_STRING_LENGTH(s);
2025 CHECK_TCL_APPARTMENT;
2026
2027 ENTER_TCL
2028 retval = Tcl_ExprString(Tkapp_Interp(self), s);
2029 ENTER_OVERLAP
2030 if (retval == TCL_ERROR)
2031 res = Tkinter_Error(self);
2032 else
2033 res = Tkapp_UnicodeResult(self);
2034 LEAVE_OVERLAP_TCL
2035 return res;
2036 }
2037
2038 /*[clinic input]
2039 _tkinter.tkapp.exprlong
2040
2041 s: str
2042 /
2043
2044 [clinic start generated code]*/
2045
2046 static PyObject *
_tkinter_tkapp_exprlong_impl(TkappObject * self,const char * s)2047 _tkinter_tkapp_exprlong_impl(TkappObject *self, const char *s)
2048 /*[clinic end generated code: output=5d6a46b63c6ebcf9 input=11bd7eee0c57b4dc]*/
2049 {
2050 PyObject *res = NULL;
2051 int retval;
2052 long v;
2053
2054 CHECK_STRING_LENGTH(s);
2055 CHECK_TCL_APPARTMENT;
2056
2057 ENTER_TCL
2058 retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v);
2059 ENTER_OVERLAP
2060 if (retval == TCL_ERROR)
2061 res = Tkinter_Error(self);
2062 else
2063 res = PyLong_FromLong(v);
2064 LEAVE_OVERLAP_TCL
2065 return res;
2066 }
2067
2068 /*[clinic input]
2069 _tkinter.tkapp.exprdouble
2070
2071 s: str
2072 /
2073
2074 [clinic start generated code]*/
2075
2076 static PyObject *
_tkinter_tkapp_exprdouble_impl(TkappObject * self,const char * s)2077 _tkinter_tkapp_exprdouble_impl(TkappObject *self, const char *s)
2078 /*[clinic end generated code: output=ff78df1081ea4158 input=ff02bc11798832d5]*/
2079 {
2080 PyObject *res = NULL;
2081 double v;
2082 int retval;
2083
2084 CHECK_STRING_LENGTH(s);
2085 CHECK_TCL_APPARTMENT;
2086 ENTER_TCL
2087 retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v);
2088 ENTER_OVERLAP
2089 if (retval == TCL_ERROR)
2090 res = Tkinter_Error(self);
2091 else
2092 res = PyFloat_FromDouble(v);
2093 LEAVE_OVERLAP_TCL
2094 return res;
2095 }
2096
2097 /*[clinic input]
2098 _tkinter.tkapp.exprboolean
2099
2100 s: str
2101 /
2102
2103 [clinic start generated code]*/
2104
2105 static PyObject *
_tkinter_tkapp_exprboolean_impl(TkappObject * self,const char * s)2106 _tkinter_tkapp_exprboolean_impl(TkappObject *self, const char *s)
2107 /*[clinic end generated code: output=8b28038c22887311 input=c8c66022bdb8d5d3]*/
2108 {
2109 PyObject *res = NULL;
2110 int retval;
2111 int v;
2112
2113 CHECK_STRING_LENGTH(s);
2114 CHECK_TCL_APPARTMENT;
2115 ENTER_TCL
2116 retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
2117 ENTER_OVERLAP
2118 if (retval == TCL_ERROR)
2119 res = Tkinter_Error(self);
2120 else
2121 res = PyLong_FromLong(v);
2122 LEAVE_OVERLAP_TCL
2123 return res;
2124 }
2125
2126
2127
2128 /*[clinic input]
2129 _tkinter.tkapp.splitlist
2130
2131 arg: object
2132 /
2133
2134 [clinic start generated code]*/
2135
2136 static PyObject *
_tkinter_tkapp_splitlist(TkappObject * self,PyObject * arg)2137 _tkinter_tkapp_splitlist(TkappObject *self, PyObject *arg)
2138 /*[clinic end generated code: output=13b51d34386d36fb input=2b2e13351e3c0b53]*/
2139 {
2140 char *list;
2141 int argc;
2142 const char **argv;
2143 PyObject *v;
2144 int i;
2145
2146 if (PyTclObject_Check(arg)) {
2147 int objc;
2148 Tcl_Obj **objv;
2149 if (Tcl_ListObjGetElements(Tkapp_Interp(self),
2150 ((PyTclObject*)arg)->value,
2151 &objc, &objv) == TCL_ERROR) {
2152 return Tkinter_Error(self);
2153 }
2154 if (!(v = PyTuple_New(objc)))
2155 return NULL;
2156 for (i = 0; i < objc; i++) {
2157 PyObject *s = FromObj(self, objv[i]);
2158 if (!s) {
2159 Py_DECREF(v);
2160 return NULL;
2161 }
2162 PyTuple_SET_ITEM(v, i, s);
2163 }
2164 return v;
2165 }
2166 if (PyTuple_Check(arg)) {
2167 Py_INCREF(arg);
2168 return arg;
2169 }
2170 if (PyList_Check(arg)) {
2171 return PySequence_Tuple(arg);
2172 }
2173
2174 if (!PyArg_Parse(arg, "et:splitlist", "utf-8", &list))
2175 return NULL;
2176
2177 if (strlen(list) >= INT_MAX) {
2178 PyErr_SetString(PyExc_OverflowError, "string is too long");
2179 PyMem_Free(list);
2180 return NULL;
2181 }
2182 if (Tcl_SplitList(Tkapp_Interp(self), list,
2183 &argc, &argv) == TCL_ERROR) {
2184 PyMem_Free(list);
2185 return Tkinter_Error(self);
2186 }
2187
2188 if (!(v = PyTuple_New(argc)))
2189 goto finally;
2190
2191 for (i = 0; i < argc; i++) {
2192 PyObject *s = unicodeFromTclString(argv[i]);
2193 if (!s) {
2194 Py_DECREF(v);
2195 v = NULL;
2196 goto finally;
2197 }
2198 PyTuple_SET_ITEM(v, i, s);
2199 }
2200
2201 finally:
2202 ckfree(FREECAST argv);
2203 PyMem_Free(list);
2204 return v;
2205 }
2206
2207
2208 /** Tcl Command **/
2209
2210 /* Client data struct */
2211 typedef struct {
2212 PyObject *self;
2213 PyObject *func;
2214 } PythonCmd_ClientData;
2215
2216 static int
PythonCmd_Error(Tcl_Interp * interp)2217 PythonCmd_Error(Tcl_Interp *interp)
2218 {
2219 errorInCmd = 1;
2220 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
2221 LEAVE_PYTHON
2222 return TCL_ERROR;
2223 }
2224
2225 /* This is the Tcl command that acts as a wrapper for Python
2226 * function or method.
2227 */
2228 static int
PythonCmd(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])2229 PythonCmd(ClientData clientData, Tcl_Interp *interp,
2230 int objc, Tcl_Obj *const objv[])
2231 {
2232 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
2233 PyObject *args, *res;
2234 int i;
2235 Tcl_Obj *obj_res;
2236
2237 ENTER_PYTHON
2238
2239 /* Create argument tuple (objv1, ..., objvN) */
2240 if (!(args = PyTuple_New(objc - 1)))
2241 return PythonCmd_Error(interp);
2242
2243 for (i = 0; i < (objc - 1); i++) {
2244 PyObject *s = unicodeFromTclObj(objv[i + 1]);
2245 if (!s) {
2246 Py_DECREF(args);
2247 return PythonCmd_Error(interp);
2248 }
2249 PyTuple_SET_ITEM(args, i, s);
2250 }
2251
2252 res = PyObject_Call(data->func, args, NULL);
2253 Py_DECREF(args);
2254
2255 if (res == NULL)
2256 return PythonCmd_Error(interp);
2257
2258 obj_res = AsObj(res);
2259 if (obj_res == NULL) {
2260 Py_DECREF(res);
2261 return PythonCmd_Error(interp);
2262 }
2263 Tcl_SetObjResult(interp, obj_res);
2264 Py_DECREF(res);
2265
2266 LEAVE_PYTHON
2267
2268 return TCL_OK;
2269 }
2270
2271
2272 static void
PythonCmdDelete(ClientData clientData)2273 PythonCmdDelete(ClientData clientData)
2274 {
2275 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
2276
2277 ENTER_PYTHON
2278 Py_XDECREF(data->self);
2279 Py_XDECREF(data->func);
2280 PyMem_Free(data);
2281 LEAVE_PYTHON
2282 }
2283
2284
2285
2286
2287 TCL_DECLARE_MUTEX(command_mutex)
2288
2289 typedef struct CommandEvent{
2290 Tcl_Event ev;
2291 Tcl_Interp* interp;
2292 const char *name;
2293 int create;
2294 int *status;
2295 ClientData *data;
2296 Tcl_Condition *done;
2297 } CommandEvent;
2298
2299 static int
Tkapp_CommandProc(CommandEvent * ev,int flags)2300 Tkapp_CommandProc(CommandEvent *ev, int flags)
2301 {
2302 if (ev->create)
2303 *ev->status = Tcl_CreateObjCommand(
2304 ev->interp, ev->name, PythonCmd,
2305 ev->data, PythonCmdDelete) == NULL;
2306 else
2307 *ev->status = Tcl_DeleteCommand(ev->interp, ev->name);
2308 Tcl_MutexLock(&command_mutex);
2309 Tcl_ConditionNotify(ev->done);
2310 Tcl_MutexUnlock(&command_mutex);
2311 return 1;
2312 }
2313
2314 /*[clinic input]
2315 _tkinter.tkapp.createcommand
2316
2317 name: str
2318 func: object
2319 /
2320
2321 [clinic start generated code]*/
2322
2323 static PyObject *
_tkinter_tkapp_createcommand_impl(TkappObject * self,const char * name,PyObject * func)2324 _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name,
2325 PyObject *func)
2326 /*[clinic end generated code: output=2a1c79a4ee2af410 input=255785cb70edc6a0]*/
2327 {
2328 PythonCmd_ClientData *data;
2329 int err;
2330
2331 CHECK_STRING_LENGTH(name);
2332 if (!PyCallable_Check(func)) {
2333 PyErr_SetString(PyExc_TypeError, "command not callable");
2334 return NULL;
2335 }
2336
2337 if (self->threaded && self->thread_id != Tcl_GetCurrentThread() &&
2338 !WaitForMainloop(self))
2339 return NULL;
2340
2341 data = PyMem_NEW(PythonCmd_ClientData, 1);
2342 if (!data)
2343 return PyErr_NoMemory();
2344 Py_INCREF(self);
2345 Py_INCREF(func);
2346 data->self = (PyObject *) self;
2347 data->func = func;
2348 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
2349 Tcl_Condition cond = NULL;
2350 CommandEvent *ev = (CommandEvent*)attemptckalloc(sizeof(CommandEvent));
2351 if (ev == NULL) {
2352 PyErr_NoMemory();
2353 PyMem_Free(data);
2354 return NULL;
2355 }
2356 ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc;
2357 ev->interp = self->interp;
2358 ev->create = 1;
2359 ev->name = name;
2360 ev->data = (ClientData)data;
2361 ev->status = &err;
2362 ev->done = &cond;
2363 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &command_mutex);
2364 Tcl_ConditionFinalize(&cond);
2365 }
2366 else
2367 {
2368 ENTER_TCL
2369 err = Tcl_CreateObjCommand(
2370 Tkapp_Interp(self), name, PythonCmd,
2371 (ClientData)data, PythonCmdDelete) == NULL;
2372 LEAVE_TCL
2373 }
2374 if (err) {
2375 PyErr_SetString(Tkinter_TclError, "can't create Tcl command");
2376 PyMem_Free(data);
2377 return NULL;
2378 }
2379
2380 Py_RETURN_NONE;
2381 }
2382
2383
2384
2385 /*[clinic input]
2386 _tkinter.tkapp.deletecommand
2387
2388 name: str
2389 /
2390
2391 [clinic start generated code]*/
2392
2393 static PyObject *
_tkinter_tkapp_deletecommand_impl(TkappObject * self,const char * name)2394 _tkinter_tkapp_deletecommand_impl(TkappObject *self, const char *name)
2395 /*[clinic end generated code: output=a67e8cb5845e0d2d input=53e9952eae1f85f5]*/
2396 {
2397 int err;
2398
2399 CHECK_STRING_LENGTH(name);
2400
2401 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
2402 Tcl_Condition cond = NULL;
2403 CommandEvent *ev;
2404 ev = (CommandEvent*)attemptckalloc(sizeof(CommandEvent));
2405 if (ev == NULL) {
2406 PyErr_NoMemory();
2407 return NULL;
2408 }
2409 ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc;
2410 ev->interp = self->interp;
2411 ev->create = 0;
2412 ev->name = name;
2413 ev->status = &err;
2414 ev->done = &cond;
2415 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond,
2416 &command_mutex);
2417 Tcl_ConditionFinalize(&cond);
2418 }
2419 else
2420 {
2421 ENTER_TCL
2422 err = Tcl_DeleteCommand(self->interp, name);
2423 LEAVE_TCL
2424 }
2425 if (err == -1) {
2426 PyErr_SetString(Tkinter_TclError, "can't delete Tcl command");
2427 return NULL;
2428 }
2429 Py_RETURN_NONE;
2430 }
2431
2432
2433
2434 #ifdef HAVE_CREATEFILEHANDLER
2435 /** File Handler **/
2436
2437 typedef struct _fhcdata {
2438 PyObject *func;
2439 PyObject *file;
2440 int id;
2441 struct _fhcdata *next;
2442 } FileHandler_ClientData;
2443
2444 static FileHandler_ClientData *HeadFHCD;
2445
2446 static FileHandler_ClientData *
NewFHCD(PyObject * func,PyObject * file,int id)2447 NewFHCD(PyObject *func, PyObject *file, int id)
2448 {
2449 FileHandler_ClientData *p;
2450 p = PyMem_NEW(FileHandler_ClientData, 1);
2451 if (p != NULL) {
2452 Py_XINCREF(func);
2453 Py_XINCREF(file);
2454 p->func = func;
2455 p->file = file;
2456 p->id = id;
2457 p->next = HeadFHCD;
2458 HeadFHCD = p;
2459 }
2460 return p;
2461 }
2462
2463 static void
DeleteFHCD(int id)2464 DeleteFHCD(int id)
2465 {
2466 FileHandler_ClientData *p, **pp;
2467
2468 pp = &HeadFHCD;
2469 while ((p = *pp) != NULL) {
2470 if (p->id == id) {
2471 *pp = p->next;
2472 Py_XDECREF(p->func);
2473 Py_XDECREF(p->file);
2474 PyMem_Free(p);
2475 }
2476 else
2477 pp = &p->next;
2478 }
2479 }
2480
2481 static void
FileHandler(ClientData clientData,int mask)2482 FileHandler(ClientData clientData, int mask)
2483 {
2484 FileHandler_ClientData *data = (FileHandler_ClientData *)clientData;
2485 PyObject *func, *file, *res;
2486
2487 ENTER_PYTHON
2488 func = data->func;
2489 file = data->file;
2490
2491 res = PyObject_CallFunction(func, "Oi", file, mask);
2492 if (res == NULL) {
2493 errorInCmd = 1;
2494 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
2495 }
2496 Py_XDECREF(res);
2497 LEAVE_PYTHON
2498 }
2499
2500 /*[clinic input]
2501 _tkinter.tkapp.createfilehandler
2502
2503 file: object
2504 mask: int
2505 func: object
2506 /
2507
2508 [clinic start generated code]*/
2509
2510 static PyObject *
_tkinter_tkapp_createfilehandler_impl(TkappObject * self,PyObject * file,int mask,PyObject * func)2511 _tkinter_tkapp_createfilehandler_impl(TkappObject *self, PyObject *file,
2512 int mask, PyObject *func)
2513 /*[clinic end generated code: output=f73ce82de801c353 input=84943a5286e47947]*/
2514 {
2515 FileHandler_ClientData *data;
2516 int tfile;
2517
2518 CHECK_TCL_APPARTMENT;
2519
2520 tfile = PyObject_AsFileDescriptor(file);
2521 if (tfile < 0)
2522 return NULL;
2523 if (!PyCallable_Check(func)) {
2524 PyErr_SetString(PyExc_TypeError, "bad argument list");
2525 return NULL;
2526 }
2527
2528 data = NewFHCD(func, file, tfile);
2529 if (data == NULL)
2530 return NULL;
2531
2532 /* Ought to check for null Tcl_File object... */
2533 ENTER_TCL
2534 Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
2535 LEAVE_TCL
2536 Py_RETURN_NONE;
2537 }
2538
2539 /*[clinic input]
2540 _tkinter.tkapp.deletefilehandler
2541
2542 file: object
2543 /
2544
2545 [clinic start generated code]*/
2546
2547 static PyObject *
_tkinter_tkapp_deletefilehandler(TkappObject * self,PyObject * file)2548 _tkinter_tkapp_deletefilehandler(TkappObject *self, PyObject *file)
2549 /*[clinic end generated code: output=b53cc96ebf9476fd input=abbec19d66312e2a]*/
2550 {
2551 int tfile;
2552
2553 CHECK_TCL_APPARTMENT;
2554
2555 tfile = PyObject_AsFileDescriptor(file);
2556 if (tfile < 0)
2557 return NULL;
2558
2559 DeleteFHCD(tfile);
2560
2561 /* Ought to check for null Tcl_File object... */
2562 ENTER_TCL
2563 Tcl_DeleteFileHandler(tfile);
2564 LEAVE_TCL
2565 Py_RETURN_NONE;
2566 }
2567 #endif /* HAVE_CREATEFILEHANDLER */
2568
2569
2570 /**** Tktt Object (timer token) ****/
2571
2572 static PyObject *Tktt_Type;
2573
2574 typedef struct {
2575 PyObject_HEAD
2576 Tcl_TimerToken token;
2577 PyObject *func;
2578 } TkttObject;
2579
2580 /*[clinic input]
2581 _tkinter.tktimertoken.deletetimerhandler
2582
2583 [clinic start generated code]*/
2584
2585 static PyObject *
_tkinter_tktimertoken_deletetimerhandler_impl(TkttObject * self)2586 _tkinter_tktimertoken_deletetimerhandler_impl(TkttObject *self)
2587 /*[clinic end generated code: output=bd7fe17f328cfa55 input=40bd070ff85f5cf3]*/
2588 {
2589 TkttObject *v = self;
2590 PyObject *func = v->func;
2591
2592 if (v->token != NULL) {
2593 Tcl_DeleteTimerHandler(v->token);
2594 v->token = NULL;
2595 }
2596 if (func != NULL) {
2597 v->func = NULL;
2598 Py_DECREF(func);
2599 Py_DECREF(v); /* See Tktt_New() */
2600 }
2601 Py_RETURN_NONE;
2602 }
2603
2604 static TkttObject *
Tktt_New(PyObject * func)2605 Tktt_New(PyObject *func)
2606 {
2607 TkttObject *v;
2608
2609 v = PyObject_New(TkttObject, (PyTypeObject *) Tktt_Type);
2610 if (v == NULL)
2611 return NULL;
2612
2613 Py_INCREF(func);
2614 v->token = NULL;
2615 v->func = func;
2616
2617 /* Extra reference, deleted when called or when handler is deleted */
2618 Py_INCREF(v);
2619 return v;
2620 }
2621
2622 static void
Tktt_Dealloc(PyObject * self)2623 Tktt_Dealloc(PyObject *self)
2624 {
2625 TkttObject *v = (TkttObject *)self;
2626 PyObject *func = v->func;
2627 PyObject *tp = (PyObject *) Py_TYPE(self);
2628
2629 Py_XDECREF(func);
2630
2631 PyObject_Free(self);
2632 Py_DECREF(tp);
2633 }
2634
2635 static PyObject *
Tktt_Repr(PyObject * self)2636 Tktt_Repr(PyObject *self)
2637 {
2638 TkttObject *v = (TkttObject *)self;
2639 return PyUnicode_FromFormat("<tktimertoken at %p%s>",
2640 v,
2641 v->func == NULL ? ", handler deleted" : "");
2642 }
2643
2644 /** Timer Handler **/
2645
2646 static void
TimerHandler(ClientData clientData)2647 TimerHandler(ClientData clientData)
2648 {
2649 TkttObject *v = (TkttObject *)clientData;
2650 PyObject *func = v->func;
2651 PyObject *res;
2652
2653 if (func == NULL)
2654 return;
2655
2656 v->func = NULL;
2657
2658 ENTER_PYTHON
2659
2660 res = PyObject_CallNoArgs(func);
2661 Py_DECREF(func);
2662 Py_DECREF(v); /* See Tktt_New() */
2663
2664 if (res == NULL) {
2665 errorInCmd = 1;
2666 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
2667 }
2668 else
2669 Py_DECREF(res);
2670
2671 LEAVE_PYTHON
2672 }
2673
2674 /*[clinic input]
2675 _tkinter.tkapp.createtimerhandler
2676
2677 milliseconds: int
2678 func: object
2679 /
2680
2681 [clinic start generated code]*/
2682
2683 static PyObject *
_tkinter_tkapp_createtimerhandler_impl(TkappObject * self,int milliseconds,PyObject * func)2684 _tkinter_tkapp_createtimerhandler_impl(TkappObject *self, int milliseconds,
2685 PyObject *func)
2686 /*[clinic end generated code: output=2da5959b9d031911 input=ba6729f32f0277a5]*/
2687 {
2688 TkttObject *v;
2689
2690 if (!PyCallable_Check(func)) {
2691 PyErr_SetString(PyExc_TypeError, "bad argument list");
2692 return NULL;
2693 }
2694
2695 CHECK_TCL_APPARTMENT;
2696
2697 v = Tktt_New(func);
2698 if (v) {
2699 v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler,
2700 (ClientData)v);
2701 }
2702
2703 return (PyObject *) v;
2704 }
2705
2706
2707 /** Event Loop **/
2708
2709 /*[clinic input]
2710 _tkinter.tkapp.mainloop
2711
2712 threshold: int = 0
2713 /
2714
2715 [clinic start generated code]*/
2716
2717 static PyObject *
_tkinter_tkapp_mainloop_impl(TkappObject * self,int threshold)2718 _tkinter_tkapp_mainloop_impl(TkappObject *self, int threshold)
2719 /*[clinic end generated code: output=0ba8eabbe57841b0 input=036bcdcf03d5eca0]*/
2720 {
2721 PyThreadState *tstate = PyThreadState_Get();
2722
2723 CHECK_TCL_APPARTMENT;
2724 self->dispatching = 1;
2725
2726 quitMainLoop = 0;
2727 while (Tk_GetNumMainWindows() > threshold &&
2728 !quitMainLoop &&
2729 !errorInCmd)
2730 {
2731 int result;
2732
2733 if (self->threaded) {
2734 /* Allow other Python threads to run. */
2735 ENTER_TCL
2736 result = Tcl_DoOneEvent(0);
2737 LEAVE_TCL
2738 }
2739 else {
2740 Py_BEGIN_ALLOW_THREADS
2741 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1);
2742 tcl_tstate = tstate;
2743 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
2744 tcl_tstate = NULL;
2745 if(tcl_lock)PyThread_release_lock(tcl_lock);
2746 if (result == 0)
2747 Sleep(Tkinter_busywaitinterval);
2748 Py_END_ALLOW_THREADS
2749 }
2750
2751 if (PyErr_CheckSignals() != 0) {
2752 self->dispatching = 0;
2753 return NULL;
2754 }
2755 if (result < 0)
2756 break;
2757 }
2758 self->dispatching = 0;
2759 quitMainLoop = 0;
2760
2761 if (errorInCmd) {
2762 errorInCmd = 0;
2763 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
2764 excInCmd = valInCmd = trbInCmd = NULL;
2765 return NULL;
2766 }
2767 Py_RETURN_NONE;
2768 }
2769
2770 /*[clinic input]
2771 _tkinter.tkapp.dooneevent
2772
2773 flags: int = 0
2774 /
2775
2776 [clinic start generated code]*/
2777
2778 static PyObject *
_tkinter_tkapp_dooneevent_impl(TkappObject * self,int flags)2779 _tkinter_tkapp_dooneevent_impl(TkappObject *self, int flags)
2780 /*[clinic end generated code: output=27c6b2aa464cac29 input=6542b928e364b793]*/
2781 {
2782 int rv;
2783
2784 ENTER_TCL
2785 rv = Tcl_DoOneEvent(flags);
2786 LEAVE_TCL
2787 return PyLong_FromLong(rv);
2788 }
2789
2790 /*[clinic input]
2791 _tkinter.tkapp.quit
2792 [clinic start generated code]*/
2793
2794 static PyObject *
_tkinter_tkapp_quit_impl(TkappObject * self)2795 _tkinter_tkapp_quit_impl(TkappObject *self)
2796 /*[clinic end generated code: output=7f21eeff481f754f input=e03020dc38aff23c]*/
2797 {
2798 quitMainLoop = 1;
2799 Py_RETURN_NONE;
2800 }
2801
2802 /*[clinic input]
2803 _tkinter.tkapp.interpaddr
2804 [clinic start generated code]*/
2805
2806 static PyObject *
_tkinter_tkapp_interpaddr_impl(TkappObject * self)2807 _tkinter_tkapp_interpaddr_impl(TkappObject *self)
2808 /*[clinic end generated code: output=6caaae3273b3c95a input=2dd32cbddb55a111]*/
2809 {
2810 return PyLong_FromVoidPtr(Tkapp_Interp(self));
2811 }
2812
2813 /*[clinic input]
2814 _tkinter.tkapp.loadtk
2815 [clinic start generated code]*/
2816
2817 static PyObject *
_tkinter_tkapp_loadtk_impl(TkappObject * self)2818 _tkinter_tkapp_loadtk_impl(TkappObject *self)
2819 /*[clinic end generated code: output=e9e10a954ce46d2a input=b5e82afedd6354f0]*/
2820 {
2821 Tcl_Interp *interp = Tkapp_Interp(self);
2822 const char * _tk_exists = NULL;
2823 int err;
2824
2825 #ifdef TKINTER_PROTECT_LOADTK
2826 /* Up to Tk 8.4.13, Tk_Init deadlocks on the second call when the
2827 * first call failed.
2828 * To avoid the deadlock, we just refuse the second call through
2829 * a static variable.
2830 */
2831 if (tk_load_failed) {
2832 PyErr_SetString(Tkinter_TclError, TKINTER_LOADTK_ERRMSG);
2833 return NULL;
2834 }
2835 #endif
2836
2837 /* We want to guard against calling Tk_Init() multiple times */
2838 CHECK_TCL_APPARTMENT;
2839 ENTER_TCL
2840 err = Tcl_Eval(Tkapp_Interp(self), "info exists tk_version");
2841 ENTER_OVERLAP
2842 if (err == TCL_ERROR) {
2843 /* This sets an exception, but we cannot return right
2844 away because we need to exit the overlap first. */
2845 Tkinter_Error(self);
2846 } else {
2847 _tk_exists = Tcl_GetStringResult(Tkapp_Interp(self));
2848 }
2849 LEAVE_OVERLAP_TCL
2850 if (err == TCL_ERROR) {
2851 return NULL;
2852 }
2853 if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) {
2854 if (Tk_Init(interp) == TCL_ERROR) {
2855 Tkinter_Error(self);
2856 #ifdef TKINTER_PROTECT_LOADTK
2857 tk_load_failed = 1;
2858 #endif
2859 return NULL;
2860 }
2861 }
2862 Py_RETURN_NONE;
2863 }
2864
2865 static PyObject *
Tkapp_WantObjects(PyObject * self,PyObject * args)2866 Tkapp_WantObjects(PyObject *self, PyObject *args)
2867 {
2868
2869 int wantobjects = -1;
2870 if (!PyArg_ParseTuple(args, "|i:wantobjects", &wantobjects))
2871 return NULL;
2872 if (wantobjects == -1)
2873 return PyBool_FromLong(((TkappObject*)self)->wantobjects);
2874 ((TkappObject*)self)->wantobjects = wantobjects;
2875
2876 Py_RETURN_NONE;
2877 }
2878
2879 /*[clinic input]
2880 _tkinter.tkapp.willdispatch
2881
2882 [clinic start generated code]*/
2883
2884 static PyObject *
_tkinter_tkapp_willdispatch_impl(TkappObject * self)2885 _tkinter_tkapp_willdispatch_impl(TkappObject *self)
2886 /*[clinic end generated code: output=0e3f46d244642155 input=d88f5970843d6dab]*/
2887 {
2888 self->dispatching = 1;
2889
2890 Py_RETURN_NONE;
2891 }
2892
2893
2894 /**** Tkapp Type Methods ****/
2895
2896 static void
Tkapp_Dealloc(PyObject * self)2897 Tkapp_Dealloc(PyObject *self)
2898 {
2899 PyObject *tp = (PyObject *) Py_TYPE(self);
2900 /*CHECK_TCL_APPARTMENT;*/
2901 ENTER_TCL
2902 Tcl_DeleteInterp(Tkapp_Interp(self));
2903 LEAVE_TCL
2904 PyObject_Free(self);
2905 Py_DECREF(tp);
2906 DisableEventHook();
2907 }
2908
2909
2910
2911 /**** Tkinter Module ****/
2912
2913 typedef struct {
2914 PyObject* tuple;
2915 Py_ssize_t size; /* current size */
2916 Py_ssize_t maxsize; /* allocated size */
2917 } FlattenContext;
2918
2919 static int
_bump(FlattenContext * context,Py_ssize_t size)2920 _bump(FlattenContext* context, Py_ssize_t size)
2921 {
2922 /* expand tuple to hold (at least) size new items.
2923 return true if successful, false if an exception was raised */
2924
2925 Py_ssize_t maxsize = context->maxsize * 2; /* never overflows */
2926
2927 if (maxsize < context->size + size)
2928 maxsize = context->size + size; /* never overflows */
2929
2930 context->maxsize = maxsize;
2931
2932 return _PyTuple_Resize(&context->tuple, maxsize) >= 0;
2933 }
2934
2935 static int
_flatten1(FlattenContext * context,PyObject * item,int depth)2936 _flatten1(FlattenContext* context, PyObject* item, int depth)
2937 {
2938 /* add tuple or list to argument tuple (recursively) */
2939
2940 Py_ssize_t i, size;
2941
2942 if (depth > 1000) {
2943 PyErr_SetString(PyExc_ValueError,
2944 "nesting too deep in _flatten");
2945 return 0;
2946 } else if (PyTuple_Check(item) || PyList_Check(item)) {
2947 size = PySequence_Fast_GET_SIZE(item);
2948 /* preallocate (assume no nesting) */
2949 if (context->size + size > context->maxsize &&
2950 !_bump(context, size))
2951 return 0;
2952 /* copy items to output tuple */
2953 for (i = 0; i < size; i++) {
2954 PyObject *o = PySequence_Fast_GET_ITEM(item, i);
2955 if (PyList_Check(o) || PyTuple_Check(o)) {
2956 if (!_flatten1(context, o, depth + 1))
2957 return 0;
2958 } else if (o != Py_None) {
2959 if (context->size + 1 > context->maxsize &&
2960 !_bump(context, 1))
2961 return 0;
2962 Py_INCREF(o);
2963 PyTuple_SET_ITEM(context->tuple,
2964 context->size++, o);
2965 }
2966 }
2967 } else {
2968 PyErr_SetString(PyExc_TypeError, "argument must be sequence");
2969 return 0;
2970 }
2971 return 1;
2972 }
2973
2974 /*[clinic input]
2975 _tkinter._flatten
2976
2977 item: object
2978 /
2979
2980 [clinic start generated code]*/
2981
2982 static PyObject *
_tkinter__flatten(PyObject * module,PyObject * item)2983 _tkinter__flatten(PyObject *module, PyObject *item)
2984 /*[clinic end generated code: output=cad02a3f97f29862 input=6b9c12260aa1157f]*/
2985 {
2986 FlattenContext context;
2987
2988 context.maxsize = PySequence_Size(item);
2989 if (context.maxsize < 0)
2990 return NULL;
2991 if (context.maxsize == 0)
2992 return PyTuple_New(0);
2993
2994 context.tuple = PyTuple_New(context.maxsize);
2995 if (!context.tuple)
2996 return NULL;
2997
2998 context.size = 0;
2999
3000 if (!_flatten1(&context, item, 0)) {
3001 Py_XDECREF(context.tuple);
3002 return NULL;
3003 }
3004
3005 if (_PyTuple_Resize(&context.tuple, context.size))
3006 return NULL;
3007
3008 return context.tuple;
3009 }
3010
3011 /*[clinic input]
3012 _tkinter.create
3013
3014 screenName: str(accept={str, NoneType}) = None
3015 baseName: str = ""
3016 className: str = "Tk"
3017 interactive: bool(accept={int}) = False
3018 wantobjects: bool(accept={int}) = False
3019 wantTk: bool(accept={int}) = True
3020 if false, then Tk_Init() doesn't get called
3021 sync: bool(accept={int}) = False
3022 if true, then pass -sync to wish
3023 use: str(accept={str, NoneType}) = None
3024 if not None, then pass -use to wish
3025 /
3026
3027 [clinic start generated code]*/
3028
3029 static PyObject *
_tkinter_create_impl(PyObject * module,const char * screenName,const char * baseName,const char * className,int interactive,int wantobjects,int wantTk,int sync,const char * use)3030 _tkinter_create_impl(PyObject *module, const char *screenName,
3031 const char *baseName, const char *className,
3032 int interactive, int wantobjects, int wantTk, int sync,
3033 const char *use)
3034 /*[clinic end generated code: output=e3315607648e6bb4 input=da9b17ee7358d862]*/
3035 {
3036 /* XXX baseName is not used anymore;
3037 * try getting rid of it. */
3038 CHECK_STRING_LENGTH(screenName);
3039 CHECK_STRING_LENGTH(baseName);
3040 CHECK_STRING_LENGTH(className);
3041 CHECK_STRING_LENGTH(use);
3042
3043 return (PyObject *) Tkapp_New(screenName, className,
3044 interactive, wantobjects, wantTk,
3045 sync, use);
3046 }
3047
3048 /*[clinic input]
3049 _tkinter.setbusywaitinterval
3050
3051 new_val: int
3052 /
3053
3054 Set the busy-wait interval in milliseconds between successive calls to Tcl_DoOneEvent in a threaded Python interpreter.
3055
3056 It should be set to a divisor of the maximum time between frames in an animation.
3057 [clinic start generated code]*/
3058
3059 static PyObject *
_tkinter_setbusywaitinterval_impl(PyObject * module,int new_val)3060 _tkinter_setbusywaitinterval_impl(PyObject *module, int new_val)
3061 /*[clinic end generated code: output=42bf7757dc2d0ab6 input=deca1d6f9e6dae47]*/
3062 {
3063 if (new_val < 0) {
3064 PyErr_SetString(PyExc_ValueError,
3065 "busywaitinterval must be >= 0");
3066 return NULL;
3067 }
3068 Tkinter_busywaitinterval = new_val;
3069 Py_RETURN_NONE;
3070 }
3071
3072 /*[clinic input]
3073 _tkinter.getbusywaitinterval -> int
3074
3075 Return the current busy-wait interval between successive calls to Tcl_DoOneEvent in a threaded Python interpreter.
3076 [clinic start generated code]*/
3077
3078 static int
_tkinter_getbusywaitinterval_impl(PyObject * module)3079 _tkinter_getbusywaitinterval_impl(PyObject *module)
3080 /*[clinic end generated code: output=23b72d552001f5c7 input=a695878d2d576a84]*/
3081 {
3082 return Tkinter_busywaitinterval;
3083 }
3084
3085 #include "clinic/_tkinter.c.h"
3086
3087 static PyMethodDef Tktt_methods[] =
3088 {
3089 _TKINTER_TKTIMERTOKEN_DELETETIMERHANDLER_METHODDEF
3090 {NULL, NULL}
3091 };
3092
3093 static PyType_Slot Tktt_Type_slots[] = {
3094 {Py_tp_dealloc, Tktt_Dealloc},
3095 {Py_tp_repr, Tktt_Repr},
3096 {Py_tp_methods, Tktt_methods},
3097 {0, 0}
3098 };
3099
3100 static PyType_Spec Tktt_Type_spec = {
3101 "_tkinter.tktimertoken",
3102 sizeof(TkttObject),
3103 0,
3104 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
3105 Tktt_Type_slots,
3106 };
3107
3108
3109 /**** Tkapp Method List ****/
3110
3111 static PyMethodDef Tkapp_methods[] =
3112 {
3113 _TKINTER_TKAPP_WILLDISPATCH_METHODDEF
3114 {"wantobjects", Tkapp_WantObjects, METH_VARARGS},
3115 {"call", Tkapp_Call, METH_VARARGS},
3116 _TKINTER_TKAPP_EVAL_METHODDEF
3117 _TKINTER_TKAPP_EVALFILE_METHODDEF
3118 _TKINTER_TKAPP_RECORD_METHODDEF
3119 _TKINTER_TKAPP_ADDERRORINFO_METHODDEF
3120 {"setvar", Tkapp_SetVar, METH_VARARGS},
3121 {"globalsetvar", Tkapp_GlobalSetVar, METH_VARARGS},
3122 {"getvar", Tkapp_GetVar, METH_VARARGS},
3123 {"globalgetvar", Tkapp_GlobalGetVar, METH_VARARGS},
3124 {"unsetvar", Tkapp_UnsetVar, METH_VARARGS},
3125 {"globalunsetvar", Tkapp_GlobalUnsetVar, METH_VARARGS},
3126 _TKINTER_TKAPP_GETINT_METHODDEF
3127 _TKINTER_TKAPP_GETDOUBLE_METHODDEF
3128 _TKINTER_TKAPP_GETBOOLEAN_METHODDEF
3129 _TKINTER_TKAPP_EXPRSTRING_METHODDEF
3130 _TKINTER_TKAPP_EXPRLONG_METHODDEF
3131 _TKINTER_TKAPP_EXPRDOUBLE_METHODDEF
3132 _TKINTER_TKAPP_EXPRBOOLEAN_METHODDEF
3133 _TKINTER_TKAPP_SPLITLIST_METHODDEF
3134 _TKINTER_TKAPP_CREATECOMMAND_METHODDEF
3135 _TKINTER_TKAPP_DELETECOMMAND_METHODDEF
3136 _TKINTER_TKAPP_CREATEFILEHANDLER_METHODDEF
3137 _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF
3138 _TKINTER_TKAPP_CREATETIMERHANDLER_METHODDEF
3139 _TKINTER_TKAPP_MAINLOOP_METHODDEF
3140 _TKINTER_TKAPP_DOONEEVENT_METHODDEF
3141 _TKINTER_TKAPP_QUIT_METHODDEF
3142 _TKINTER_TKAPP_INTERPADDR_METHODDEF
3143 _TKINTER_TKAPP_LOADTK_METHODDEF
3144 {NULL, NULL}
3145 };
3146
3147 static PyType_Slot Tkapp_Type_slots[] = {
3148 {Py_tp_dealloc, Tkapp_Dealloc},
3149 {Py_tp_methods, Tkapp_methods},
3150 {0, 0}
3151 };
3152
3153
3154 static PyType_Spec Tkapp_Type_spec = {
3155 "_tkinter.tkapp",
3156 sizeof(TkappObject),
3157 0,
3158 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
3159 Tkapp_Type_slots,
3160 };
3161
3162 static PyMethodDef moduleMethods[] =
3163 {
3164 _TKINTER__FLATTEN_METHODDEF
3165 _TKINTER_CREATE_METHODDEF
3166 _TKINTER_SETBUSYWAITINTERVAL_METHODDEF
3167 _TKINTER_GETBUSYWAITINTERVAL_METHODDEF
3168 {NULL, NULL}
3169 };
3170
3171 #ifdef WAIT_FOR_STDIN
3172
3173 static int stdin_ready = 0;
3174
3175 #ifndef MS_WINDOWS
3176 static void
MyFileProc(void * clientData,int mask)3177 MyFileProc(void *clientData, int mask)
3178 {
3179 stdin_ready = 1;
3180 }
3181 #endif
3182
3183 static PyThreadState *event_tstate = NULL;
3184
3185 static int
EventHook(void)3186 EventHook(void)
3187 {
3188 #ifndef MS_WINDOWS
3189 int tfile;
3190 #endif
3191 PyEval_RestoreThread(event_tstate);
3192 stdin_ready = 0;
3193 errorInCmd = 0;
3194 #ifndef MS_WINDOWS
3195 tfile = fileno(stdin);
3196 Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
3197 #endif
3198 while (!errorInCmd && !stdin_ready) {
3199 int result;
3200 #ifdef MS_WINDOWS
3201 if (_kbhit()) {
3202 stdin_ready = 1;
3203 break;
3204 }
3205 #endif
3206 Py_BEGIN_ALLOW_THREADS
3207 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1);
3208 tcl_tstate = event_tstate;
3209
3210 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
3211
3212 tcl_tstate = NULL;
3213 if(tcl_lock)PyThread_release_lock(tcl_lock);
3214 if (result == 0)
3215 Sleep(Tkinter_busywaitinterval);
3216 Py_END_ALLOW_THREADS
3217
3218 if (result < 0)
3219 break;
3220 }
3221 #ifndef MS_WINDOWS
3222 Tcl_DeleteFileHandler(tfile);
3223 #endif
3224 if (errorInCmd) {
3225 errorInCmd = 0;
3226 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
3227 excInCmd = valInCmd = trbInCmd = NULL;
3228 PyErr_Print();
3229 }
3230 PyEval_SaveThread();
3231 return 0;
3232 }
3233
3234 #endif
3235
3236 static void
EnableEventHook(void)3237 EnableEventHook(void)
3238 {
3239 #ifdef WAIT_FOR_STDIN
3240 if (PyOS_InputHook == NULL) {
3241 event_tstate = PyThreadState_Get();
3242 PyOS_InputHook = EventHook;
3243 }
3244 #endif
3245 }
3246
3247 static void
DisableEventHook(void)3248 DisableEventHook(void)
3249 {
3250 #ifdef WAIT_FOR_STDIN
3251 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
3252 PyOS_InputHook = NULL;
3253 }
3254 #endif
3255 }
3256
3257
3258 static struct PyModuleDef _tkintermodule = {
3259 PyModuleDef_HEAD_INIT,
3260 "_tkinter",
3261 NULL,
3262 -1,
3263 moduleMethods,
3264 NULL,
3265 NULL,
3266 NULL,
3267 NULL
3268 };
3269
3270 PyMODINIT_FUNC
PyInit__tkinter(void)3271 PyInit__tkinter(void)
3272 {
3273 PyObject *m, *uexe, *cexe, *o;
3274
3275 tcl_lock = PyThread_allocate_lock();
3276 if (tcl_lock == NULL)
3277 return NULL;
3278
3279 m = PyModule_Create(&_tkintermodule);
3280 if (m == NULL)
3281 return NULL;
3282
3283 o = PyErr_NewException("_tkinter.TclError", NULL, NULL);
3284 if (o == NULL) {
3285 Py_DECREF(m);
3286 return NULL;
3287 }
3288 Py_INCREF(o);
3289 if (PyModule_AddObject(m, "TclError", o)) {
3290 Py_DECREF(o);
3291 Py_DECREF(m);
3292 return NULL;
3293 }
3294 Tkinter_TclError = o;
3295
3296 if (PyModule_AddIntConstant(m, "READABLE", TCL_READABLE)) {
3297 Py_DECREF(m);
3298 return NULL;
3299 }
3300 if (PyModule_AddIntConstant(m, "WRITABLE", TCL_WRITABLE)) {
3301 Py_DECREF(m);
3302 return NULL;
3303 }
3304 if (PyModule_AddIntConstant(m, "EXCEPTION", TCL_EXCEPTION)) {
3305 Py_DECREF(m);
3306 return NULL;
3307 }
3308 if (PyModule_AddIntConstant(m, "WINDOW_EVENTS", TCL_WINDOW_EVENTS)) {
3309 Py_DECREF(m);
3310 return NULL;
3311 }
3312 if (PyModule_AddIntConstant(m, "FILE_EVENTS", TCL_FILE_EVENTS)) {
3313 Py_DECREF(m);
3314 return NULL;
3315 }
3316 if (PyModule_AddIntConstant(m, "TIMER_EVENTS", TCL_TIMER_EVENTS)) {
3317 Py_DECREF(m);
3318 return NULL;
3319 }
3320 if (PyModule_AddIntConstant(m, "IDLE_EVENTS", TCL_IDLE_EVENTS)) {
3321 Py_DECREF(m);
3322 return NULL;
3323 }
3324 if (PyModule_AddIntConstant(m, "ALL_EVENTS", TCL_ALL_EVENTS)) {
3325 Py_DECREF(m);
3326 return NULL;
3327 }
3328 if (PyModule_AddIntConstant(m, "DONT_WAIT", TCL_DONT_WAIT)) {
3329 Py_DECREF(m);
3330 return NULL;
3331 }
3332 if (PyModule_AddStringConstant(m, "TK_VERSION", TK_VERSION)) {
3333 Py_DECREF(m);
3334 return NULL;
3335 }
3336 if (PyModule_AddStringConstant(m, "TCL_VERSION", TCL_VERSION)) {
3337 Py_DECREF(m);
3338 return NULL;
3339 }
3340
3341 o = PyType_FromSpec(&Tkapp_Type_spec);
3342 if (o == NULL) {
3343 Py_DECREF(m);
3344 return NULL;
3345 }
3346 if (PyModule_AddObject(m, "TkappType", o)) {
3347 Py_DECREF(o);
3348 Py_DECREF(m);
3349 return NULL;
3350 }
3351 Tkapp_Type = o;
3352
3353 o = PyType_FromSpec(&Tktt_Type_spec);
3354 if (o == NULL) {
3355 Py_DECREF(m);
3356 return NULL;
3357 }
3358 if (PyModule_AddObject(m, "TkttType", o)) {
3359 Py_DECREF(o);
3360 Py_DECREF(m);
3361 return NULL;
3362 }
3363 Tktt_Type = o;
3364
3365 o = PyType_FromSpec(&PyTclObject_Type_spec);
3366 if (o == NULL) {
3367 Py_DECREF(m);
3368 return NULL;
3369 }
3370 if (PyModule_AddObject(m, "Tcl_Obj", o)) {
3371 Py_DECREF(o);
3372 Py_DECREF(m);
3373 return NULL;
3374 }
3375 PyTclObject_Type = o;
3376
3377 #ifdef TK_AQUA
3378 /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems
3379 * start waking up. Note that Tcl_FindExecutable will do this, this
3380 * code must be above it! The original warning from
3381 * tkMacOSXAppInit.c is copied below.
3382 *
3383 * NB - You have to swap in the Tk Notifier BEFORE you start up the
3384 * Tcl interpreter for now. It probably should work to do this
3385 * in the other order, but for now it doesn't seem to.
3386 *
3387 */
3388 Tk_MacOSXSetupTkNotifier();
3389 #endif
3390
3391
3392 /* This helps the dynamic loader; in Unicode aware Tcl versions
3393 it also helps Tcl find its encodings. */
3394 uexe = PyUnicode_FromWideChar(Py_GetProgramName(), -1);
3395 if (uexe) {
3396 cexe = PyUnicode_EncodeFSDefault(uexe);
3397 if (cexe) {
3398 #ifdef MS_WINDOWS
3399 int set_var = 0;
3400 PyObject *str_path;
3401 wchar_t *wcs_path;
3402 DWORD ret;
3403
3404 ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
3405
3406 if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
3407 str_path = _get_tcl_lib_path();
3408 if (str_path == NULL && PyErr_Occurred()) {
3409 Py_DECREF(m);
3410 return NULL;
3411 }
3412 if (str_path != NULL) {
3413 wcs_path = PyUnicode_AsWideCharString(str_path, NULL);
3414 if (wcs_path == NULL) {
3415 Py_DECREF(m);
3416 return NULL;
3417 }
3418 SetEnvironmentVariableW(L"TCL_LIBRARY", wcs_path);
3419 set_var = 1;
3420 }
3421 }
3422
3423 Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
3424
3425 if (set_var) {
3426 SetEnvironmentVariableW(L"TCL_LIBRARY", NULL);
3427 PyMem_Free(wcs_path);
3428 }
3429 #else
3430 Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
3431 #endif /* MS_WINDOWS */
3432 }
3433 Py_XDECREF(cexe);
3434 Py_DECREF(uexe);
3435 }
3436
3437 if (PyErr_Occurred()) {
3438 Py_DECREF(m);
3439 return NULL;
3440 }
3441
3442 return m;
3443 }
3444