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