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