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