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