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