This commit was manufactured by cvs2svn to create tag 'r221'.
[python/dscho.git] / Modules / _tkinter.c
blobba0a383170f13e8de4ff53fe46df7057f14c7e69
1 /***********************************************************
2 Copyright (C) 1994 Steen Lumholt.
4 All Rights Reserved
6 ******************************************************************/
8 /* _tkinter.c -- Interface to libtk.a and libtcl.a. */
10 /* TCL/TK VERSION INFO:
12 Only Tcl/Tk 8.0 and later are supported. Older versions are not
13 supported. (Use Python 1.5.2 if you cannot upgrade your Tcl/Tk
14 libraries.)
17 /* XXX Further speed-up ideas, involving Tcl 8.0 features:
19 - In Tcl_Call(), create Tcl objects from the arguments, possibly using
20 intelligent mappings between Python objects and Tcl objects (e.g. ints,
21 floats and Tcl window pointers could be handled specially).
23 - Register a new Tcl type, "Python callable", which can be called more
24 efficiently and passed to Tcl_EvalObj() directly (if this is possible).
29 #include "Python.h"
30 #include <ctype.h>
32 #ifdef WITH_THREAD
33 #include "pythread.h"
34 #endif
36 #ifdef MS_WINDOWS
37 #include <windows.h>
38 #endif
40 #ifdef macintosh
41 #define MAC_TCL
42 #endif
44 #ifdef TK_FRAMEWORK
45 #include <Tcl/tcl.h>
46 #include <Tk/tk.h>
47 #else
48 #include <tcl.h>
49 #include <tk.h>
50 #endif
52 #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION)
54 #if TKMAJORMINOR < 8000
55 #error "Tk older than 8.0 not supported"
56 #endif
58 #if defined(macintosh)
59 /* Sigh, we have to include this to get at the tcl qd pointer */
60 #include <tkMac.h>
61 /* And this one we need to clear the menu bar */
62 #include <Menus.h>
63 #endif
65 #if !(defined(MS_WINDOWS) || defined(__CYGWIN__) || defined(macintosh))
66 /* Mac has it, but it doesn't really work:-( */
67 #define HAVE_CREATEFILEHANDLER
68 #endif
70 #ifdef HAVE_CREATEFILEHANDLER
72 /* Tcl_CreateFileHandler() changed several times; these macros deal with the
73 messiness. In Tcl 8.0 and later, it is not available on Windows (and on
74 Unix, only because Jack added it back); when available on Windows, it only
75 applies to sockets. */
77 #ifdef MS_WINDOWS
78 #define FHANDLETYPE TCL_WIN_SOCKET
79 #else
80 #define FHANDLETYPE TCL_UNIX_FD
81 #endif
83 /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine
84 which uses this to handle Tcl events while the user is typing commands. */
86 #if FHANDLETYPE == TCL_UNIX_FD
87 #define WAIT_FOR_STDIN
88 #endif
90 #endif /* HAVE_CREATEFILEHANDLER */
92 #ifdef MS_WINDOWS
93 #include <conio.h>
94 #define WAIT_FOR_STDIN
95 #endif
97 #ifdef WITH_THREAD
99 /* The threading situation is complicated. Tcl is not thread-safe, except for
100 Tcl 8.1, which will probably remain in alpha status for another 6 months
101 (and the README says that Tk will probably remain thread-unsafe forever).
102 So we need to use a lock around all uses of Tcl. Previously, the Python
103 interpreter lock was used for this. However, this causes problems when
104 other Python threads need to run while Tcl is blocked waiting for events.
106 To solve this problem, a separate lock for Tcl is introduced. Holding it
107 is incompatible with holding Python's interpreter lock. The following four
108 macros manipulate both locks together.
110 ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and
111 Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made
112 that could call an event handler, or otherwise affect the state of a Tcl
113 interpreter. These assume that the surrounding code has the Python
114 interpreter lock; inside the brackets, the Python interpreter lock has been
115 released and the lock for Tcl has been acquired.
117 Sometimes, it is necessary to have both the Python lock and the Tcl lock.
118 (For example, when transferring data from the Tcl interpreter result to a
119 Python string object.) This can be done by using different macros to close
120 the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores
121 the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL
122 releases the Tcl lock.
124 By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event
125 handlers when the handler needs to use Python. Such event handlers are
126 entered while the lock for Tcl is held; the event handler presumably needs
127 to use Python. ENTER_PYTHON releases the lock for Tcl and acquires
128 the Python interpreter lock, restoring the appropriate thread state, and
129 LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock
130 for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside
131 the code between ENTER_PYTHON and LEAVE_PYTHON.
133 These locks expand to several statements and brackets; they should not be
134 used in branches of if statements and the like.
138 static PyThread_type_lock tcl_lock = 0;
139 static PyThreadState *tcl_tstate = NULL;
141 #define ENTER_TCL \
142 { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
143 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
145 #define LEAVE_TCL \
146 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
148 #define ENTER_OVERLAP \
149 Py_END_ALLOW_THREADS
151 #define LEAVE_OVERLAP_TCL \
152 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); }
154 #define ENTER_PYTHON \
155 { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
156 PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
158 #define LEAVE_PYTHON \
159 { PyThreadState *tstate = PyEval_SaveThread(); \
160 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
162 #else
164 #define ENTER_TCL
165 #define LEAVE_TCL
166 #define ENTER_OVERLAP
167 #define LEAVE_OVERLAP_TCL
168 #define ENTER_PYTHON
169 #define LEAVE_PYTHON
171 #endif
173 #ifdef macintosh
176 ** Additional cruft needed by Tcl/Tk on the Mac.
177 ** This is for Tcl 7.5 and Tk 4.1 (patch release 1).
180 /* ckfree() expects a char* */
181 #define FREECAST (char *)
183 #include <Events.h> /* For EventRecord */
185 typedef int (*TclMacConvertEventPtr) (EventRecord *eventPtr);
186 void Tcl_MacSetEventProc(TclMacConvertEventPtr procPtr);
187 int TkMacConvertEvent(EventRecord *eventPtr);
189 staticforward int PyMacConvertEvent(EventRecord *eventPtr);
191 #include <SIOUX.h>
192 extern int SIOUXIsAppWindow(WindowPtr);
194 #endif /* macintosh */
196 #ifndef FREECAST
197 #define FREECAST (char *)
198 #endif
200 /**** Tkapp Object Declaration ****/
202 staticforward PyTypeObject Tkapp_Type;
204 typedef struct {
205 PyObject_HEAD
206 Tcl_Interp *interp;
207 } TkappObject;
209 #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
210 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
211 #define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v))
213 #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \
214 (void *) v, ((PyObject *) v)->ob_refcnt))
218 /**** Error Handling ****/
220 static PyObject *Tkinter_TclError;
221 static int quitMainLoop = 0;
222 static int errorInCmd = 0;
223 static PyObject *excInCmd;
224 static PyObject *valInCmd;
225 static PyObject *trbInCmd;
229 static PyObject *
230 Tkinter_Error(PyObject *v)
232 PyErr_SetString(Tkinter_TclError, Tkapp_Result(v));
233 return NULL;
238 /**** Utils ****/
240 #ifdef WITH_THREAD
241 #ifndef MS_WINDOWS
243 /* Millisecond sleep() for Unix platforms. */
245 static void
246 Sleep(int milli)
248 /* XXX Too bad if you don't have select(). */
249 struct timeval t;
250 t.tv_sec = milli/1000;
251 t.tv_usec = (milli%1000) * 1000;
252 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
254 #endif /* MS_WINDOWS */
255 #endif /* WITH_THREAD */
258 static char *
259 AsString(PyObject *value, PyObject *tmp)
261 if (PyString_Check(value))
262 return PyString_AsString(value);
263 #ifdef Py_USING_UNICODE
264 else if (PyUnicode_Check(value)) {
265 PyObject *v = PyUnicode_AsUTF8String(value);
266 if (v == NULL)
267 return NULL;
268 if (PyList_Append(tmp, v) != 0) {
269 Py_DECREF(v);
270 return NULL;
272 Py_DECREF(v);
273 return PyString_AsString(v);
275 #endif
276 else {
277 PyObject *v = PyObject_Str(value);
278 if (v == NULL)
279 return NULL;
280 if (PyList_Append(tmp, v) != 0) {
281 Py_DECREF(v);
282 return NULL;
284 Py_DECREF(v);
285 return PyString_AsString(v);
291 #define ARGSZ 64
293 static char *
294 Merge(PyObject *args)
296 PyObject *tmp = NULL;
297 char *argvStore[ARGSZ];
298 char **argv = NULL;
299 int fvStore[ARGSZ];
300 int *fv = NULL;
301 int argc = 0, fvc = 0, i;
302 char *res = NULL;
304 if (!(tmp = PyList_New(0)))
305 return NULL;
307 argv = argvStore;
308 fv = fvStore;
310 if (args == NULL)
311 argc = 0;
313 else if (!PyTuple_Check(args)) {
314 argc = 1;
315 fv[0] = 0;
316 if (!(argv[0] = AsString(args, tmp)))
317 goto finally;
319 else {
320 argc = PyTuple_Size(args);
322 if (argc > ARGSZ) {
323 argv = (char **)ckalloc(argc * sizeof(char *));
324 fv = (int *)ckalloc(argc * sizeof(int));
325 if (argv == NULL || fv == NULL) {
326 PyErr_NoMemory();
327 goto finally;
331 for (i = 0; i < argc; i++) {
332 PyObject *v = PyTuple_GetItem(args, i);
333 if (PyTuple_Check(v)) {
334 fv[i] = 1;
335 if (!(argv[i] = Merge(v)))
336 goto finally;
337 fvc++;
339 else if (v == Py_None) {
340 argc = i;
341 break;
343 else {
344 fv[i] = 0;
345 if (!(argv[i] = AsString(v, tmp)))
346 goto finally;
347 fvc++;
351 res = Tcl_Merge(argc, argv);
352 if (res == NULL)
353 PyErr_SetString(Tkinter_TclError, "merge failed");
355 finally:
356 for (i = 0; i < fvc; i++)
357 if (fv[i]) {
358 ckfree(argv[i]);
360 if (argv != argvStore)
361 ckfree(FREECAST argv);
362 if (fv != fvStore)
363 ckfree(FREECAST fv);
365 Py_DECREF(tmp);
366 return res;
371 static PyObject *
372 Split(char *list)
374 int argc;
375 char **argv;
376 PyObject *v;
378 if (list == NULL) {
379 Py_INCREF(Py_None);
380 return Py_None;
383 if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
384 /* Not a list.
385 * Could be a quoted string containing funnies, e.g. {"}.
386 * Return the string itself.
388 return PyString_FromString(list);
391 if (argc == 0)
392 v = PyString_FromString("");
393 else if (argc == 1)
394 v = PyString_FromString(argv[0]);
395 else if ((v = PyTuple_New(argc)) != NULL) {
396 int i;
397 PyObject *w;
399 for (i = 0; i < argc; i++) {
400 if ((w = Split(argv[i])) == NULL) {
401 Py_DECREF(v);
402 v = NULL;
403 break;
405 PyTuple_SetItem(v, i, w);
408 Tcl_Free(FREECAST argv);
409 return v;
414 /**** Tkapp Object ****/
416 #ifndef WITH_APPINIT
418 Tcl_AppInit(Tcl_Interp *interp)
420 Tk_Window main;
422 main = Tk_MainWindow(interp);
423 if (Tcl_Init(interp) == TCL_ERROR) {
424 PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp));
425 return TCL_ERROR;
427 if (Tk_Init(interp) == TCL_ERROR) {
428 PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
429 return TCL_ERROR;
431 return TCL_OK;
433 #endif /* !WITH_APPINIT */
438 /* Initialize the Tk application; see the `main' function in
439 * `tkMain.c'.
442 static void EnableEventHook(void); /* Forward */
443 static void DisableEventHook(void); /* Forward */
445 static TkappObject *
446 Tkapp_New(char *screenName, char *baseName, char *className, int interactive)
448 TkappObject *v;
449 char *argv0;
451 v = PyObject_New(TkappObject, &Tkapp_Type);
452 if (v == NULL)
453 return NULL;
455 v->interp = Tcl_CreateInterp();
457 #if defined(macintosh)
458 /* This seems to be needed */
459 ClearMenuBar();
460 TkMacInitMenus(v->interp);
461 #endif
463 /* Delete the 'exit' command, which can screw things up */
464 Tcl_DeleteCommand(v->interp, "exit");
466 if (screenName != NULL)
467 Tcl_SetVar2(v->interp, "env", "DISPLAY",
468 screenName, TCL_GLOBAL_ONLY);
470 if (interactive)
471 Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
472 else
473 Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
475 /* This is used to get the application class for Tk 4.1 and up */
476 argv0 = (char*)ckalloc(strlen(className) + 1);
477 if (!argv0) {
478 PyErr_NoMemory();
479 Py_DECREF(v);
480 return NULL;
483 strcpy(argv0, className);
484 if (isupper((int)(argv0[0])))
485 argv0[0] = tolower(argv0[0]);
486 Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY);
487 ckfree(argv0);
489 if (Tcl_AppInit(v->interp) != TCL_OK)
490 return (TkappObject *)Tkinter_Error((PyObject *)v);
492 EnableEventHook();
494 return v;
499 /** Tcl Eval **/
501 #if TKMAJORMINOR >= 8001
502 #define USING_OBJECTS
503 #endif
505 #ifdef USING_OBJECTS
507 static Tcl_Obj*
508 AsObj(PyObject *value)
510 Tcl_Obj *result;
512 if (PyString_Check(value))
513 return Tcl_NewStringObj(PyString_AS_STRING(value),
514 PyString_GET_SIZE(value));
515 else if (PyInt_Check(value))
516 return Tcl_NewLongObj(PyInt_AS_LONG(value));
517 else if (PyFloat_Check(value))
518 return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
519 else if (PyTuple_Check(value)) {
520 Tcl_Obj **argv = (Tcl_Obj**)
521 ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*));
522 int i;
523 if(!argv)
524 return 0;
525 for(i=0;i<PyTuple_Size(value);i++)
526 argv[i] = AsObj(PyTuple_GetItem(value,i));
527 result = Tcl_NewListObj(PyTuple_Size(value), argv);
528 ckfree(FREECAST argv);
529 return result;
531 #ifdef Py_USING_UNICODE
532 else if (PyUnicode_Check(value)) {
533 #if TKMAJORMINOR <= 8001
534 /* In Tcl 8.1 we must use UTF-8 */
535 PyObject* utf8 = PyUnicode_AsUTF8String(value);
536 if (!utf8)
537 return 0;
538 result = Tcl_NewStringObj(PyString_AS_STRING(utf8),
539 PyString_GET_SIZE(utf8));
540 Py_DECREF(utf8);
541 return result;
542 #else /* TKMAJORMINOR > 8001 */
543 /* In Tcl 8.2 and later, use Tcl_NewUnicodeObj() */
544 if (sizeof(Py_UNICODE) != sizeof(Tcl_UniChar)) {
545 /* XXX Should really test this at compile time */
546 PyErr_SetString(PyExc_SystemError,
547 "Py_UNICODE and Tcl_UniChar differ in size");
548 return 0;
550 return Tcl_NewUnicodeObj(PyUnicode_AS_UNICODE(value),
551 PyUnicode_GET_SIZE(value));
552 #endif /* TKMAJORMINOR > 8001 */
554 #endif
555 else {
556 PyObject *v = PyObject_Str(value);
557 if (!v)
558 return 0;
559 result = AsObj(v);
560 Py_DECREF(v);
561 return result;
565 static PyObject *
566 Tkapp_Call(PyObject *self, PyObject *args)
568 Tcl_Obj *objStore[ARGSZ];
569 Tcl_Obj **objv = NULL;
570 int objc = 0, i;
571 PyObject *res = NULL;
572 Tcl_Interp *interp = Tkapp_Interp(self);
573 /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */
574 int flags = TCL_EVAL_DIRECT;
576 objv = objStore;
578 if (args == NULL)
579 /* do nothing */;
581 else if (!PyTuple_Check(args)) {
582 objv[0] = AsObj(args);
583 if (objv[0] == 0)
584 goto finally;
585 objc = 1;
586 Tcl_IncrRefCount(objv[0]);
588 else {
589 objc = PyTuple_Size(args);
591 if (objc > ARGSZ) {
592 objv = (Tcl_Obj **)ckalloc(objc * sizeof(char *));
593 if (objv == NULL) {
594 PyErr_NoMemory();
595 objc = 0;
596 goto finally;
600 for (i = 0; i < objc; i++) {
601 PyObject *v = PyTuple_GetItem(args, i);
602 if (v == Py_None) {
603 objc = i;
604 break;
606 objv[i] = AsObj(v);
607 if (!objv[i]) {
608 /* Reset objc, so it attempts to clear
609 objects only up to i. */
610 objc = i;
611 goto finally;
613 Tcl_IncrRefCount(objv[i]);
617 ENTER_TCL
619 i = Tcl_EvalObjv(interp, objc, objv, flags);
621 ENTER_OVERLAP
622 if (i == TCL_ERROR)
623 Tkinter_Error(self);
624 else {
625 /* We could request the object result here, but doing
626 so would confuse applications that expect a string. */
627 char *s = Tcl_GetStringResult(interp);
628 char *p = s;
630 /* If the result contains any bytes with the top bit set,
631 it's UTF-8 and we should decode it to Unicode */
632 #ifdef Py_USING_UNICODE
633 while (*p != '\0') {
634 if (*p & 0x80)
635 break;
636 p++;
639 if (*p == '\0')
640 res = PyString_FromStringAndSize(s, (int)(p-s));
641 else {
642 /* Convert UTF-8 to Unicode string */
643 p = strchr(p, '\0');
644 res = PyUnicode_DecodeUTF8(s, (int)(p-s), "strict");
645 if (res == NULL) {
646 PyErr_Clear();
647 res = PyString_FromStringAndSize(s, (int)(p-s));
650 #else
651 p = strchr(p, '\0');
652 res = PyString_FromStringAndSize(s, (int)(p-s));
653 #endif
656 LEAVE_OVERLAP_TCL
658 finally:
659 for (i = 0; i < objc; i++)
660 Tcl_DecrRefCount(objv[i]);
661 if (objv != objStore)
662 ckfree(FREECAST objv);
663 return res;
666 #else /* !USING_OBJECTS */
668 static PyObject *
669 Tkapp_Call(PyObject *self, PyObject *args)
671 /* This is copied from Merge() */
672 PyObject *tmp = NULL;
673 char *argvStore[ARGSZ];
674 char **argv = NULL;
675 int fvStore[ARGSZ];
676 int *fv = NULL;
677 int argc = 0, fvc = 0, i;
678 PyObject *res = NULL; /* except this has a different type */
679 Tcl_CmdInfo info; /* and this is added */
680 Tcl_Interp *interp = Tkapp_Interp(self); /* and this too */
682 if (!(tmp = PyList_New(0)))
683 return NULL;
685 argv = argvStore;
686 fv = fvStore;
688 if (args == NULL)
689 argc = 0;
691 else if (!PyTuple_Check(args)) {
692 argc = 1;
693 fv[0] = 0;
694 if (!(argv[0] = AsString(args, tmp)))
695 goto finally;
697 else {
698 argc = PyTuple_Size(args);
700 if (argc > ARGSZ) {
701 argv = (char **)ckalloc(argc * sizeof(char *));
702 fv = (int *)ckalloc(argc * sizeof(int));
703 if (argv == NULL || fv == NULL) {
704 PyErr_NoMemory();
705 goto finally;
709 for (i = 0; i < argc; i++) {
710 PyObject *v = PyTuple_GetItem(args, i);
711 if (PyTuple_Check(v)) {
712 fv[i] = 1;
713 if (!(argv[i] = Merge(v)))
714 goto finally;
715 fvc++;
717 else if (v == Py_None) {
718 argc = i;
719 break;
721 else {
722 fv[i] = 0;
723 if (!(argv[i] = AsString(v, tmp)))
724 goto finally;
725 fvc++;
729 /* End code copied from Merge() */
731 /* All this to avoid a call to Tcl_Merge() and the corresponding call
732 to Tcl_SplitList() inside Tcl_Eval()... It can save a bundle! */
733 if (Py_VerboseFlag >= 2) {
734 for (i = 0; i < argc; i++)
735 PySys_WriteStderr("%s ", argv[i]);
737 ENTER_TCL
738 info.proc = NULL;
739 if (argc < 1 ||
740 !Tcl_GetCommandInfo(interp, argv[0], &info) ||
741 info.proc == NULL)
743 char *cmd;
744 cmd = Tcl_Merge(argc, argv);
745 i = Tcl_Eval(interp, cmd);
746 ckfree(cmd);
748 else {
749 Tcl_ResetResult(interp);
750 i = (*info.proc)(info.clientData, interp, argc, argv);
752 ENTER_OVERLAP
753 if (info.proc == NULL && Py_VerboseFlag >= 2)
754 PySys_WriteStderr("... use TclEval ");
755 if (i == TCL_ERROR) {
756 if (Py_VerboseFlag >= 2)
757 PySys_WriteStderr("... error: '%s'\n",
758 Tcl_GetStringResult(interp));
759 Tkinter_Error(self);
761 else {
762 if (Py_VerboseFlag >= 2)
763 PySys_WriteStderr("-> '%s'\n", Tcl_GetStringResult(interp));
764 res = PyString_FromString(Tcl_GetStringResult(interp));
766 LEAVE_OVERLAP_TCL
768 /* Copied from Merge() again */
769 finally:
770 for (i = 0; i < fvc; i++)
771 if (fv[i]) {
772 ckfree(argv[i]);
774 if (argv != argvStore)
775 ckfree(FREECAST argv);
776 if (fv != fvStore)
777 ckfree(FREECAST fv);
779 Py_DECREF(tmp);
780 return res;
783 #endif /* !USING_OBJECTS */
785 static PyObject *
786 Tkapp_GlobalCall(PyObject *self, PyObject *args)
788 /* Could do the same here as for Tkapp_Call(), but this is not used
789 much, so I can't be bothered. Unfortunately Tcl doesn't export a
790 way for the user to do what all its Global* variants do (save and
791 reset the scope pointer, call the local version, restore the saved
792 scope pointer). */
794 char *cmd;
795 PyObject *res = NULL;
797 cmd = Merge(args);
798 if (cmd) {
799 int err;
800 ENTER_TCL
801 err = Tcl_GlobalEval(Tkapp_Interp(self), cmd);
802 ENTER_OVERLAP
803 if (err == TCL_ERROR)
804 res = Tkinter_Error(self);
805 else
806 res = PyString_FromString(Tkapp_Result(self));
807 LEAVE_OVERLAP_TCL
808 ckfree(cmd);
811 return res;
814 static PyObject *
815 Tkapp_Eval(PyObject *self, PyObject *args)
817 char *script;
818 PyObject *res = NULL;
819 int err;
821 if (!PyArg_ParseTuple(args, "s:eval", &script))
822 return NULL;
824 ENTER_TCL
825 err = Tcl_Eval(Tkapp_Interp(self), script);
826 ENTER_OVERLAP
827 if (err == TCL_ERROR)
828 res = Tkinter_Error(self);
829 else
830 res = PyString_FromString(Tkapp_Result(self));
831 LEAVE_OVERLAP_TCL
832 return res;
835 static PyObject *
836 Tkapp_GlobalEval(PyObject *self, PyObject *args)
838 char *script;
839 PyObject *res = NULL;
840 int err;
842 if (!PyArg_ParseTuple(args, "s:globaleval", &script))
843 return NULL;
845 ENTER_TCL
846 err = Tcl_GlobalEval(Tkapp_Interp(self), script);
847 ENTER_OVERLAP
848 if (err == TCL_ERROR)
849 res = Tkinter_Error(self);
850 else
851 res = PyString_FromString(Tkapp_Result(self));
852 LEAVE_OVERLAP_TCL
853 return res;
856 static PyObject *
857 Tkapp_EvalFile(PyObject *self, PyObject *args)
859 char *fileName;
860 PyObject *res = NULL;
861 int err;
863 if (!PyArg_ParseTuple(args, "s:evalfile", &fileName))
864 return NULL;
866 ENTER_TCL
867 err = Tcl_EvalFile(Tkapp_Interp(self), fileName);
868 ENTER_OVERLAP
869 if (err == TCL_ERROR)
870 res = Tkinter_Error(self);
872 else
873 res = PyString_FromString(Tkapp_Result(self));
874 LEAVE_OVERLAP_TCL
875 return res;
878 static PyObject *
879 Tkapp_Record(PyObject *self, PyObject *args)
881 char *script;
882 PyObject *res = NULL;
883 int err;
885 if (!PyArg_ParseTuple(args, "s", &script))
886 return NULL;
888 ENTER_TCL
889 err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL);
890 ENTER_OVERLAP
891 if (err == TCL_ERROR)
892 res = Tkinter_Error(self);
893 else
894 res = PyString_FromString(Tkapp_Result(self));
895 LEAVE_OVERLAP_TCL
896 return res;
899 static PyObject *
900 Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
902 char *msg;
904 if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg))
905 return NULL;
906 ENTER_TCL
907 Tcl_AddErrorInfo(Tkapp_Interp(self), msg);
908 LEAVE_TCL
910 Py_INCREF(Py_None);
911 return Py_None;
916 /** Tcl Variable **/
918 static PyObject *
919 SetVar(PyObject *self, PyObject *args, int flags)
921 char *name1, *name2, *ok, *s;
922 PyObject *newValue;
923 PyObject *tmp;
925 tmp = PyList_New(0);
926 if (!tmp)
927 return NULL;
929 if (PyArg_ParseTuple(args, "sO:setvar", &name1, &newValue)) {
930 /* XXX Merge? */
931 s = AsString(newValue, tmp);
932 if (s == NULL)
933 return NULL;
934 ENTER_TCL
935 ok = Tcl_SetVar(Tkapp_Interp(self), name1, s, flags);
936 LEAVE_TCL
938 else {
939 PyErr_Clear();
940 if (PyArg_ParseTuple(args, "ssO:setvar",
941 &name1, &name2, &newValue)) {
942 s = AsString(newValue, tmp);
943 if (s == NULL)
944 return NULL;
945 ENTER_TCL
946 ok = Tcl_SetVar2(Tkapp_Interp(self), name1, name2,
947 s, flags);
948 LEAVE_TCL
950 else {
951 Py_DECREF(tmp);
952 return NULL;
955 Py_DECREF(tmp);
957 if (!ok)
958 return Tkinter_Error(self);
960 Py_INCREF(Py_None);
961 return Py_None;
964 static PyObject *
965 Tkapp_SetVar(PyObject *self, PyObject *args)
967 return SetVar(self, args, TCL_LEAVE_ERR_MSG);
970 static PyObject *
971 Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
973 return SetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
978 static PyObject *
979 GetVar(PyObject *self, PyObject *args, int flags)
981 char *name1, *name2=NULL, *s;
982 PyObject *res = NULL;
984 if (!PyArg_ParseTuple(args, "s|s:getvar", &name1, &name2))
985 return NULL;
986 ENTER_TCL
987 if (name2 == NULL)
988 s = Tcl_GetVar(Tkapp_Interp(self), name1, flags);
990 else
991 s = Tcl_GetVar2(Tkapp_Interp(self), name1, name2, flags);
992 ENTER_OVERLAP
994 if (s == NULL)
995 res = Tkinter_Error(self);
996 else
997 res = PyString_FromString(s);
998 LEAVE_OVERLAP_TCL
999 return res;
1002 static PyObject *
1003 Tkapp_GetVar(PyObject *self, PyObject *args)
1005 return GetVar(self, args, TCL_LEAVE_ERR_MSG);
1008 static PyObject *
1009 Tkapp_GlobalGetVar(PyObject *self, PyObject *args)
1011 return GetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1016 static PyObject *
1017 UnsetVar(PyObject *self, PyObject *args, int flags)
1019 char *name1, *name2=NULL;
1020 PyObject *res = NULL;
1021 int code;
1023 if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
1024 return NULL;
1025 ENTER_TCL
1026 if (name2 == NULL)
1027 code = Tcl_UnsetVar(Tkapp_Interp(self), name1, flags);
1029 else
1030 code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
1031 ENTER_OVERLAP
1033 if (code == TCL_ERROR)
1034 res = Tkinter_Error(self);
1035 else {
1036 Py_INCREF(Py_None);
1037 res = Py_None;
1039 LEAVE_OVERLAP_TCL
1040 return res;
1043 static PyObject *
1044 Tkapp_UnsetVar(PyObject *self, PyObject *args)
1046 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG);
1049 static PyObject *
1050 Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args)
1052 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1057 /** Tcl to Python **/
1059 static PyObject *
1060 Tkapp_GetInt(PyObject *self, PyObject *args)
1062 char *s;
1063 int v;
1065 if (!PyArg_ParseTuple(args, "s:getint", &s))
1066 return NULL;
1067 if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1068 return Tkinter_Error(self);
1069 return Py_BuildValue("i", v);
1072 static PyObject *
1073 Tkapp_GetDouble(PyObject *self, PyObject *args)
1075 char *s;
1076 double v;
1078 if (!PyArg_ParseTuple(args, "s:getdouble", &s))
1079 return NULL;
1080 if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1081 return Tkinter_Error(self);
1082 return Py_BuildValue("d", v);
1085 static PyObject *
1086 Tkapp_GetBoolean(PyObject *self, PyObject *args)
1088 char *s;
1089 int v;
1091 if (!PyArg_ParseTuple(args, "s:getboolean", &s))
1092 return NULL;
1093 if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1094 return Tkinter_Error(self);
1095 return Py_BuildValue("i", v);
1098 static PyObject *
1099 Tkapp_ExprString(PyObject *self, PyObject *args)
1101 char *s;
1102 PyObject *res = NULL;
1103 int retval;
1105 if (!PyArg_ParseTuple(args, "s:exprstring", &s))
1106 return NULL;
1107 ENTER_TCL
1108 retval = Tcl_ExprString(Tkapp_Interp(self), s);
1109 ENTER_OVERLAP
1110 if (retval == TCL_ERROR)
1111 res = Tkinter_Error(self);
1112 else
1113 res = Py_BuildValue("s", Tkapp_Result(self));
1114 LEAVE_OVERLAP_TCL
1115 return res;
1118 static PyObject *
1119 Tkapp_ExprLong(PyObject *self, PyObject *args)
1121 char *s;
1122 PyObject *res = NULL;
1123 int retval;
1124 long v;
1126 if (!PyArg_ParseTuple(args, "s:exprlong", &s))
1127 return NULL;
1128 ENTER_TCL
1129 retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v);
1130 ENTER_OVERLAP
1131 if (retval == TCL_ERROR)
1132 res = Tkinter_Error(self);
1133 else
1134 res = Py_BuildValue("l", v);
1135 LEAVE_OVERLAP_TCL
1136 return res;
1139 static PyObject *
1140 Tkapp_ExprDouble(PyObject *self, PyObject *args)
1142 char *s;
1143 PyObject *res = NULL;
1144 double v;
1145 int retval;
1147 if (!PyArg_ParseTuple(args, "s:exprdouble", &s))
1148 return NULL;
1149 PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
1150 ENTER_TCL
1151 retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v);
1152 ENTER_OVERLAP
1153 PyFPE_END_PROTECT(retval)
1154 if (retval == TCL_ERROR)
1155 res = Tkinter_Error(self);
1156 else
1157 res = Py_BuildValue("d", v);
1158 LEAVE_OVERLAP_TCL
1159 return res;
1162 static PyObject *
1163 Tkapp_ExprBoolean(PyObject *self, PyObject *args)
1165 char *s;
1166 PyObject *res = NULL;
1167 int retval;
1168 int v;
1170 if (!PyArg_ParseTuple(args, "s:exprboolean", &s))
1171 return NULL;
1172 ENTER_TCL
1173 retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
1174 ENTER_OVERLAP
1175 if (retval == TCL_ERROR)
1176 res = Tkinter_Error(self);
1177 else
1178 res = Py_BuildValue("i", v);
1179 LEAVE_OVERLAP_TCL
1180 return res;
1185 static PyObject *
1186 Tkapp_SplitList(PyObject *self, PyObject *args)
1188 char *list;
1189 int argc;
1190 char **argv;
1191 PyObject *v;
1192 int i;
1194 if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list))
1195 return NULL;
1197 if (Tcl_SplitList(Tkapp_Interp(self), list, &argc, &argv) == TCL_ERROR)
1198 return Tkinter_Error(self);
1200 if (!(v = PyTuple_New(argc)))
1201 return NULL;
1203 for (i = 0; i < argc; i++) {
1204 PyObject *s = PyString_FromString(argv[i]);
1205 if (!s || PyTuple_SetItem(v, i, s)) {
1206 Py_DECREF(v);
1207 v = NULL;
1208 goto finally;
1212 finally:
1213 ckfree(FREECAST argv);
1214 return v;
1217 static PyObject *
1218 Tkapp_Split(PyObject *self, PyObject *args)
1220 char *list;
1222 if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list))
1223 return NULL;
1224 return Split(list);
1227 static PyObject *
1228 Tkapp_Merge(PyObject *self, PyObject *args)
1230 char *s = Merge(args);
1231 PyObject *res = NULL;
1233 if (s) {
1234 res = PyString_FromString(s);
1235 ckfree(s);
1238 return res;
1243 /** Tcl Command **/
1245 /* Client data struct */
1246 typedef struct {
1247 PyObject *self;
1248 PyObject *func;
1249 } PythonCmd_ClientData;
1251 static int
1252 PythonCmd_Error(Tcl_Interp *interp)
1254 errorInCmd = 1;
1255 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1256 LEAVE_PYTHON
1257 return TCL_ERROR;
1260 /* This is the Tcl command that acts as a wrapper for Python
1261 * function or method.
1263 static int
1264 PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1266 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1267 PyObject *self, *func, *arg, *res, *tmp;
1268 int i, rv;
1269 char *s;
1271 ENTER_PYTHON
1273 /* TBD: no error checking here since we know, via the
1274 * Tkapp_CreateCommand() that the client data is a two-tuple
1276 self = data->self;
1277 func = data->func;
1279 /* Create argument list (argv1, ..., argvN) */
1280 if (!(arg = PyTuple_New(argc - 1)))
1281 return PythonCmd_Error(interp);
1283 for (i = 0; i < (argc - 1); i++) {
1284 PyObject *s = PyString_FromString(argv[i + 1]);
1285 if (!s || PyTuple_SetItem(arg, i, s)) {
1286 Py_DECREF(arg);
1287 return PythonCmd_Error(interp);
1290 res = PyEval_CallObject(func, arg);
1291 Py_DECREF(arg);
1293 if (res == NULL)
1294 return PythonCmd_Error(interp);
1296 if (!(tmp = PyList_New(0))) {
1297 Py_DECREF(res);
1298 return PythonCmd_Error(interp);
1301 s = AsString(res, tmp);
1302 if (s == NULL) {
1303 rv = PythonCmd_Error(interp);
1305 else {
1306 Tcl_SetResult(Tkapp_Interp(self), s, TCL_VOLATILE);
1307 rv = TCL_OK;
1310 Py_DECREF(res);
1311 Py_DECREF(tmp);
1313 LEAVE_PYTHON
1315 return rv;
1318 static void
1319 PythonCmdDelete(ClientData clientData)
1321 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1323 ENTER_PYTHON
1324 Py_XDECREF(data->self);
1325 Py_XDECREF(data->func);
1326 PyMem_DEL(data);
1327 LEAVE_PYTHON
1332 static PyObject *
1333 Tkapp_CreateCommand(PyObject *self, PyObject *args)
1335 PythonCmd_ClientData *data;
1336 char *cmdName;
1337 PyObject *func;
1338 Tcl_Command err;
1340 if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func))
1341 return NULL;
1342 if (!PyCallable_Check(func)) {
1343 PyErr_SetString(PyExc_TypeError, "command not callable");
1344 return NULL;
1347 data = PyMem_NEW(PythonCmd_ClientData, 1);
1348 if (!data)
1349 return NULL;
1350 Py_XINCREF(self);
1351 Py_XINCREF(func);
1352 data->self = self;
1353 data->func = func;
1355 ENTER_TCL
1356 err = Tcl_CreateCommand(Tkapp_Interp(self), cmdName, PythonCmd,
1357 (ClientData)data, PythonCmdDelete);
1358 LEAVE_TCL
1359 if (err == NULL) {
1360 PyErr_SetString(Tkinter_TclError, "can't create Tcl command");
1361 PyMem_DEL(data);
1362 return NULL;
1365 Py_INCREF(Py_None);
1366 return Py_None;
1371 static PyObject *
1372 Tkapp_DeleteCommand(PyObject *self, PyObject *args)
1374 char *cmdName;
1375 int err;
1377 if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName))
1378 return NULL;
1379 ENTER_TCL
1380 err = Tcl_DeleteCommand(Tkapp_Interp(self), cmdName);
1381 LEAVE_TCL
1382 if (err == -1) {
1383 PyErr_SetString(Tkinter_TclError, "can't delete Tcl command");
1384 return NULL;
1386 Py_INCREF(Py_None);
1387 return Py_None;
1392 #ifdef HAVE_CREATEFILEHANDLER
1393 /** File Handler **/
1395 typedef struct _fhcdata {
1396 PyObject *func;
1397 PyObject *file;
1398 int id;
1399 struct _fhcdata *next;
1400 } FileHandler_ClientData;
1402 static FileHandler_ClientData *HeadFHCD;
1404 static FileHandler_ClientData *
1405 NewFHCD(PyObject *func, PyObject *file, int id)
1407 FileHandler_ClientData *p;
1408 p = PyMem_NEW(FileHandler_ClientData, 1);
1409 if (p != NULL) {
1410 Py_XINCREF(func);
1411 Py_XINCREF(file);
1412 p->func = func;
1413 p->file = file;
1414 p->id = id;
1415 p->next = HeadFHCD;
1416 HeadFHCD = p;
1418 return p;
1421 static void
1422 DeleteFHCD(int id)
1424 FileHandler_ClientData *p, **pp;
1426 pp = &HeadFHCD;
1427 while ((p = *pp) != NULL) {
1428 if (p->id == id) {
1429 *pp = p->next;
1430 Py_XDECREF(p->func);
1431 Py_XDECREF(p->file);
1432 PyMem_DEL(p);
1434 else
1435 pp = &p->next;
1439 static void
1440 FileHandler(ClientData clientData, int mask)
1442 FileHandler_ClientData *data = (FileHandler_ClientData *)clientData;
1443 PyObject *func, *file, *arg, *res;
1445 ENTER_PYTHON
1446 func = data->func;
1447 file = data->file;
1449 arg = Py_BuildValue("(Oi)", file, (long) mask);
1450 res = PyEval_CallObject(func, arg);
1451 Py_DECREF(arg);
1453 if (res == NULL) {
1454 errorInCmd = 1;
1455 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1457 Py_XDECREF(res);
1458 LEAVE_PYTHON
1461 static PyObject *
1462 Tkapp_CreateFileHandler(PyObject *self, PyObject *args)
1463 /* args is (file, mask, func) */
1465 FileHandler_ClientData *data;
1466 PyObject *file, *func;
1467 int mask, tfile;
1469 if (!PyArg_ParseTuple(args, "OiO:createfilehandler",
1470 &file, &mask, &func))
1471 return NULL;
1472 tfile = PyObject_AsFileDescriptor(file);
1473 if (tfile < 0)
1474 return NULL;
1475 if (!PyCallable_Check(func)) {
1476 PyErr_SetString(PyExc_TypeError, "bad argument list");
1477 return NULL;
1480 data = NewFHCD(func, file, tfile);
1481 if (data == NULL)
1482 return NULL;
1484 /* Ought to check for null Tcl_File object... */
1485 ENTER_TCL
1486 Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
1487 LEAVE_TCL
1488 Py_INCREF(Py_None);
1489 return Py_None;
1492 static PyObject *
1493 Tkapp_DeleteFileHandler(PyObject *self, PyObject *args)
1495 PyObject *file;
1496 int tfile;
1498 if (!PyArg_ParseTuple(args, "O:deletefilehandler", &file))
1499 return NULL;
1500 tfile = PyObject_AsFileDescriptor(file);
1501 if (tfile < 0)
1502 return NULL;
1504 DeleteFHCD(tfile);
1506 /* Ought to check for null Tcl_File object... */
1507 ENTER_TCL
1508 Tcl_DeleteFileHandler(tfile);
1509 LEAVE_TCL
1510 Py_INCREF(Py_None);
1511 return Py_None;
1513 #endif /* HAVE_CREATEFILEHANDLER */
1516 /**** Tktt Object (timer token) ****/
1518 staticforward PyTypeObject Tktt_Type;
1520 typedef struct {
1521 PyObject_HEAD
1522 Tcl_TimerToken token;
1523 PyObject *func;
1524 } TkttObject;
1526 static PyObject *
1527 Tktt_DeleteTimerHandler(PyObject *self, PyObject *args)
1529 TkttObject *v = (TkttObject *)self;
1530 PyObject *func = v->func;
1532 if (!PyArg_ParseTuple(args, ":deletetimerhandler"))
1533 return NULL;
1534 if (v->token != NULL) {
1535 Tcl_DeleteTimerHandler(v->token);
1536 v->token = NULL;
1538 if (func != NULL) {
1539 v->func = NULL;
1540 Py_DECREF(func);
1541 Py_DECREF(v); /* See Tktt_New() */
1543 Py_INCREF(Py_None);
1544 return Py_None;
1547 static PyMethodDef Tktt_methods[] =
1549 {"deletetimerhandler", Tktt_DeleteTimerHandler, 1},
1550 {NULL, NULL}
1553 static TkttObject *
1554 Tktt_New(PyObject *func)
1556 TkttObject *v;
1558 v = PyObject_New(TkttObject, &Tktt_Type);
1559 if (v == NULL)
1560 return NULL;
1562 Py_INCREF(func);
1563 v->token = NULL;
1564 v->func = func;
1566 /* Extra reference, deleted when called or when handler is deleted */
1567 Py_INCREF(v);
1568 return v;
1571 static void
1572 Tktt_Dealloc(PyObject *self)
1574 TkttObject *v = (TkttObject *)self;
1575 PyObject *func = v->func;
1577 Py_XDECREF(func);
1579 PyObject_Del(self);
1582 static PyObject *
1583 Tktt_Repr(PyObject *self)
1585 TkttObject *v = (TkttObject *)self;
1586 char buf[100];
1588 PyOS_snprintf(buf, sizeof(buf), "<tktimertoken at %p%s>", v,
1589 v->func == NULL ? ", handler deleted" : "");
1590 return PyString_FromString(buf);
1593 static PyObject *
1594 Tktt_GetAttr(PyObject *self, char *name)
1596 return Py_FindMethod(Tktt_methods, self, name);
1599 static PyTypeObject Tktt_Type =
1601 PyObject_HEAD_INIT(NULL)
1602 0, /*ob_size */
1603 "tktimertoken", /*tp_name */
1604 sizeof(TkttObject), /*tp_basicsize */
1605 0, /*tp_itemsize */
1606 Tktt_Dealloc, /*tp_dealloc */
1607 0, /*tp_print */
1608 Tktt_GetAttr, /*tp_getattr */
1609 0, /*tp_setattr */
1610 0, /*tp_compare */
1611 Tktt_Repr, /*tp_repr */
1612 0, /*tp_as_number */
1613 0, /*tp_as_sequence */
1614 0, /*tp_as_mapping */
1615 0, /*tp_hash */
1620 /** Timer Handler **/
1622 static void
1623 TimerHandler(ClientData clientData)
1625 TkttObject *v = (TkttObject *)clientData;
1626 PyObject *func = v->func;
1627 PyObject *res;
1629 if (func == NULL)
1630 return;
1632 v->func = NULL;
1634 ENTER_PYTHON
1636 res = PyEval_CallObject(func, NULL);
1637 Py_DECREF(func);
1638 Py_DECREF(v); /* See Tktt_New() */
1640 if (res == NULL) {
1641 errorInCmd = 1;
1642 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1644 else
1645 Py_DECREF(res);
1647 LEAVE_PYTHON
1650 static PyObject *
1651 Tkapp_CreateTimerHandler(PyObject *self, PyObject *args)
1653 int milliseconds;
1654 PyObject *func;
1655 TkttObject *v;
1657 if (!PyArg_ParseTuple(args, "iO:createtimerhandler",
1658 &milliseconds, &func))
1659 return NULL;
1660 if (!PyCallable_Check(func)) {
1661 PyErr_SetString(PyExc_TypeError, "bad argument list");
1662 return NULL;
1664 v = Tktt_New(func);
1665 v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler,
1666 (ClientData)v);
1668 return (PyObject *) v;
1672 /** Event Loop **/
1674 static PyObject *
1675 Tkapp_MainLoop(PyObject *self, PyObject *args)
1677 int threshold = 0;
1678 #ifdef WITH_THREAD
1679 PyThreadState *tstate = PyThreadState_Get();
1680 #endif
1682 if (!PyArg_ParseTuple(args, "|i:mainloop", &threshold))
1683 return NULL;
1685 quitMainLoop = 0;
1686 while (Tk_GetNumMainWindows() > threshold &&
1687 !quitMainLoop &&
1688 !errorInCmd)
1690 int result;
1692 #ifdef WITH_THREAD
1693 Py_BEGIN_ALLOW_THREADS
1694 PyThread_acquire_lock(tcl_lock, 1);
1695 tcl_tstate = tstate;
1696 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
1697 tcl_tstate = NULL;
1698 PyThread_release_lock(tcl_lock);
1699 if (result == 0)
1700 Sleep(20);
1701 Py_END_ALLOW_THREADS
1702 #else
1703 result = Tcl_DoOneEvent(0);
1704 #endif
1706 if (PyErr_CheckSignals() != 0)
1707 return NULL;
1708 if (result < 0)
1709 break;
1711 quitMainLoop = 0;
1713 if (errorInCmd) {
1714 errorInCmd = 0;
1715 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
1716 excInCmd = valInCmd = trbInCmd = NULL;
1717 return NULL;
1719 Py_INCREF(Py_None);
1720 return Py_None;
1723 static PyObject *
1724 Tkapp_DoOneEvent(PyObject *self, PyObject *args)
1726 int flags = 0;
1727 int rv;
1729 if (!PyArg_ParseTuple(args, "|i:dooneevent", &flags))
1730 return NULL;
1732 ENTER_TCL
1733 rv = Tcl_DoOneEvent(flags);
1734 LEAVE_TCL
1735 return Py_BuildValue("i", rv);
1738 static PyObject *
1739 Tkapp_Quit(PyObject *self, PyObject *args)
1742 if (!PyArg_ParseTuple(args, ":quit"))
1743 return NULL;
1745 quitMainLoop = 1;
1746 Py_INCREF(Py_None);
1747 return Py_None;
1750 static PyObject *
1751 Tkapp_InterpAddr(PyObject *self, PyObject *args)
1754 if (!PyArg_ParseTuple(args, ":interpaddr"))
1755 return NULL;
1757 return PyInt_FromLong((long)Tkapp_Interp(self));
1762 /**** Tkapp Method List ****/
1764 static PyMethodDef Tkapp_methods[] =
1766 {"call", Tkapp_Call, 0},
1767 {"globalcall", Tkapp_GlobalCall, 0},
1768 {"eval", Tkapp_Eval, 1},
1769 {"globaleval", Tkapp_GlobalEval, 1},
1770 {"evalfile", Tkapp_EvalFile, 1},
1771 {"record", Tkapp_Record, 1},
1772 {"adderrorinfo", Tkapp_AddErrorInfo, 1},
1773 {"setvar", Tkapp_SetVar, 1},
1774 {"globalsetvar", Tkapp_GlobalSetVar, 1},
1775 {"getvar", Tkapp_GetVar, 1},
1776 {"globalgetvar", Tkapp_GlobalGetVar, 1},
1777 {"unsetvar", Tkapp_UnsetVar, 1},
1778 {"globalunsetvar", Tkapp_GlobalUnsetVar, 1},
1779 {"getint", Tkapp_GetInt, 1},
1780 {"getdouble", Tkapp_GetDouble, 1},
1781 {"getboolean", Tkapp_GetBoolean, 1},
1782 {"exprstring", Tkapp_ExprString, 1},
1783 {"exprlong", Tkapp_ExprLong, 1},
1784 {"exprdouble", Tkapp_ExprDouble, 1},
1785 {"exprboolean", Tkapp_ExprBoolean, 1},
1786 {"splitlist", Tkapp_SplitList, 1},
1787 {"split", Tkapp_Split, 1},
1788 {"merge", Tkapp_Merge, 0},
1789 {"createcommand", Tkapp_CreateCommand, 1},
1790 {"deletecommand", Tkapp_DeleteCommand, 1},
1791 #ifdef HAVE_CREATEFILEHANDLER
1792 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1793 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1794 #endif
1795 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1796 {"mainloop", Tkapp_MainLoop, 1},
1797 {"dooneevent", Tkapp_DoOneEvent, 1},
1798 {"quit", Tkapp_Quit, 1},
1799 {"interpaddr", Tkapp_InterpAddr, 1},
1800 {NULL, NULL}
1805 /**** Tkapp Type Methods ****/
1807 static void
1808 Tkapp_Dealloc(PyObject *self)
1810 ENTER_TCL
1811 Tcl_DeleteInterp(Tkapp_Interp(self));
1812 LEAVE_TCL
1813 PyObject_Del(self);
1814 DisableEventHook();
1817 static PyObject *
1818 Tkapp_GetAttr(PyObject *self, char *name)
1820 return Py_FindMethod(Tkapp_methods, self, name);
1823 static PyTypeObject Tkapp_Type =
1825 PyObject_HEAD_INIT(NULL)
1826 0, /*ob_size */
1827 "tkapp", /*tp_name */
1828 sizeof(TkappObject), /*tp_basicsize */
1829 0, /*tp_itemsize */
1830 Tkapp_Dealloc, /*tp_dealloc */
1831 0, /*tp_print */
1832 Tkapp_GetAttr, /*tp_getattr */
1833 0, /*tp_setattr */
1834 0, /*tp_compare */
1835 0, /*tp_repr */
1836 0, /*tp_as_number */
1837 0, /*tp_as_sequence */
1838 0, /*tp_as_mapping */
1839 0, /*tp_hash */
1844 /**** Tkinter Module ****/
1846 typedef struct {
1847 PyObject* tuple;
1848 int size; /* current size */
1849 int maxsize; /* allocated size */
1850 } FlattenContext;
1852 static int
1853 _bump(FlattenContext* context, int size)
1855 /* expand tuple to hold (at least) size new items.
1856 return true if successful, false if an exception was raised */
1858 int maxsize = context->maxsize * 2;
1860 if (maxsize < context->size + size)
1861 maxsize = context->size + size;
1863 context->maxsize = maxsize;
1865 return _PyTuple_Resize(&context->tuple, maxsize) >= 0;
1868 static int
1869 _flatten1(FlattenContext* context, PyObject* item, int depth)
1871 /* add tuple or list to argument tuple (recursively) */
1873 int i, size;
1875 if (depth > 1000) {
1876 PyErr_SetString(PyExc_ValueError,
1877 "nesting too deep in _flatten");
1878 return 0;
1879 } else if (PyList_Check(item)) {
1880 size = PyList_GET_SIZE(item);
1881 /* preallocate (assume no nesting) */
1882 if (context->size + size > context->maxsize &&
1883 !_bump(context, size))
1884 return 0;
1885 /* copy items to output tuple */
1886 for (i = 0; i < size; i++) {
1887 PyObject *o = PyList_GET_ITEM(item, i);
1888 if (PyList_Check(o) || PyTuple_Check(o)) {
1889 if (!_flatten1(context, o, depth + 1))
1890 return 0;
1891 } else if (o != Py_None) {
1892 if (context->size + 1 > context->maxsize &&
1893 !_bump(context, 1))
1894 return 0;
1895 Py_INCREF(o);
1896 PyTuple_SET_ITEM(context->tuple,
1897 context->size++, o);
1900 } else if (PyTuple_Check(item)) {
1901 /* same, for tuples */
1902 size = PyTuple_GET_SIZE(item);
1903 if (context->size + size > context->maxsize &&
1904 !_bump(context, size))
1905 return 0;
1906 for (i = 0; i < size; i++) {
1907 PyObject *o = PyTuple_GET_ITEM(item, i);
1908 if (PyList_Check(o) || PyTuple_Check(o)) {
1909 if (!_flatten1(context, o, depth + 1))
1910 return 0;
1911 } else if (o != Py_None) {
1912 if (context->size + 1 > context->maxsize &&
1913 !_bump(context, 1))
1914 return 0;
1915 Py_INCREF(o);
1916 PyTuple_SET_ITEM(context->tuple,
1917 context->size++, o);
1920 } else {
1921 PyErr_SetString(PyExc_TypeError, "argument must be sequence");
1922 return 0;
1924 return 1;
1927 static PyObject *
1928 Tkinter_Flatten(PyObject* self, PyObject* args)
1930 FlattenContext context;
1931 PyObject* item;
1933 if (!PyArg_ParseTuple(args, "O:_flatten", &item))
1934 return NULL;
1936 context.maxsize = PySequence_Size(item);
1937 if (context.maxsize <= 0)
1938 return PyTuple_New(0);
1940 context.tuple = PyTuple_New(context.maxsize);
1941 if (!context.tuple)
1942 return NULL;
1944 context.size = 0;
1946 if (!_flatten1(&context, item,0))
1947 return NULL;
1949 if (_PyTuple_Resize(&context.tuple, context.size))
1950 return NULL;
1952 return context.tuple;
1955 static PyObject *
1956 Tkinter_Create(PyObject *self, PyObject *args)
1958 char *screenName = NULL;
1959 char *baseName = NULL;
1960 char *className = NULL;
1961 int interactive = 0;
1963 baseName = strrchr(Py_GetProgramName(), '/');
1964 if (baseName != NULL)
1965 baseName++;
1966 else
1967 baseName = Py_GetProgramName();
1968 className = "Tk";
1970 if (!PyArg_ParseTuple(args, "|zssi:create",
1971 &screenName, &baseName, &className,
1972 &interactive))
1973 return NULL;
1975 return (PyObject *) Tkapp_New(screenName, baseName, className,
1976 interactive);
1979 static PyMethodDef moduleMethods[] =
1981 {"_flatten", Tkinter_Flatten, 1},
1982 {"create", Tkinter_Create, 1},
1983 #ifdef HAVE_CREATEFILEHANDLER
1984 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1985 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1986 #endif
1987 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1988 {"mainloop", Tkapp_MainLoop, 1},
1989 {"dooneevent", Tkapp_DoOneEvent, 1},
1990 {"quit", Tkapp_Quit, 1},
1991 {NULL, NULL}
1994 #ifdef WAIT_FOR_STDIN
1996 static int stdin_ready = 0;
1998 #ifndef MS_WINDOWS
1999 static void
2000 MyFileProc(void *clientData, int mask)
2002 stdin_ready = 1;
2004 #endif
2006 static PyThreadState *event_tstate = NULL;
2008 static int
2009 EventHook(void)
2011 #ifndef MS_WINDOWS
2012 int tfile;
2013 #endif
2014 #ifdef WITH_THREAD
2015 PyEval_RestoreThread(event_tstate);
2016 #endif
2017 stdin_ready = 0;
2018 errorInCmd = 0;
2019 #ifndef MS_WINDOWS
2020 tfile = fileno(stdin);
2021 Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
2022 #endif
2023 while (!errorInCmd && !stdin_ready) {
2024 int result;
2025 #ifdef MS_WINDOWS
2026 if (_kbhit()) {
2027 stdin_ready = 1;
2028 break;
2030 #endif
2031 #if defined(WITH_THREAD) || defined(MS_WINDOWS)
2032 Py_BEGIN_ALLOW_THREADS
2033 PyThread_acquire_lock(tcl_lock, 1);
2034 tcl_tstate = event_tstate;
2036 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
2038 tcl_tstate = NULL;
2039 PyThread_release_lock(tcl_lock);
2040 if (result == 0)
2041 Sleep(20);
2042 Py_END_ALLOW_THREADS
2043 #else
2044 result = Tcl_DoOneEvent(0);
2045 #endif
2047 if (result < 0)
2048 break;
2050 #ifndef MS_WINDOWS
2051 Tcl_DeleteFileHandler(tfile);
2052 #endif
2053 if (errorInCmd) {
2054 errorInCmd = 0;
2055 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
2056 excInCmd = valInCmd = trbInCmd = NULL;
2057 PyErr_Print();
2059 #ifdef WITH_THREAD
2060 PyEval_SaveThread();
2061 #endif
2062 return 0;
2065 #endif
2067 static void
2068 EnableEventHook(void)
2070 #ifdef WAIT_FOR_STDIN
2071 if (PyOS_InputHook == NULL) {
2072 #ifdef WITH_THREAD
2073 event_tstate = PyThreadState_Get();
2074 #endif
2075 PyOS_InputHook = EventHook;
2077 #endif
2080 static void
2081 DisableEventHook(void)
2083 #ifdef WAIT_FOR_STDIN
2084 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
2085 PyOS_InputHook = NULL;
2087 #endif
2091 /* all errors will be checked in one fell swoop in init_tkinter() */
2092 static void
2093 ins_long(PyObject *d, char *name, long val)
2095 PyObject *v = PyInt_FromLong(val);
2096 if (v) {
2097 PyDict_SetItemString(d, name, v);
2098 Py_DECREF(v);
2101 static void
2102 ins_string(PyObject *d, char *name, char *val)
2104 PyObject *v = PyString_FromString(val);
2105 if (v) {
2106 PyDict_SetItemString(d, name, v);
2107 Py_DECREF(v);
2112 DL_EXPORT(void)
2113 init_tkinter(void)
2115 PyObject *m, *d;
2117 Tkapp_Type.ob_type = &PyType_Type;
2119 #ifdef WITH_THREAD
2120 tcl_lock = PyThread_allocate_lock();
2121 #endif
2123 m = Py_InitModule("_tkinter", moduleMethods);
2125 d = PyModule_GetDict(m);
2126 Tkinter_TclError = Py_BuildValue("s", "TclError");
2127 PyDict_SetItemString(d, "TclError", Tkinter_TclError);
2129 ins_long(d, "READABLE", TCL_READABLE);
2130 ins_long(d, "WRITABLE", TCL_WRITABLE);
2131 ins_long(d, "EXCEPTION", TCL_EXCEPTION);
2132 ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS);
2133 ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS);
2134 ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS);
2135 ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS);
2136 ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS);
2137 ins_long(d, "DONT_WAIT", TCL_DONT_WAIT);
2138 ins_string(d, "TK_VERSION", TK_VERSION);
2139 ins_string(d, "TCL_VERSION", TCL_VERSION);
2141 PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type);
2143 Tktt_Type.ob_type = &PyType_Type;
2144 PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
2147 #ifdef TK_AQUA
2148 /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems
2149 * start waking up. Note that Tcl_FindExecutable will do this, this
2150 * code must be above it! The original warning from
2151 * tkMacOSXAppInit.c is copied below.
2153 * NB - You have to swap in the Tk Notifier BEFORE you start up the
2154 * Tcl interpreter for now. It probably should work to do this
2155 * in the other order, but for now it doesn't seem to.
2158 Tk_MacOSXSetupTkNotifier();
2159 #endif
2162 /* This helps the dynamic loader; in Unicode aware Tcl versions
2163 it also helps Tcl find its encodings. */
2164 Tcl_FindExecutable(Py_GetProgramName());
2166 if (PyErr_Occurred())
2167 return;
2169 #if 0
2170 /* This was not a good idea; through <Destroy> bindings,
2171 Tcl_Finalize() may invoke Python code but at that point the
2172 interpreter and thread state have already been destroyed! */
2173 Py_AtExit(Tcl_Finalize);
2174 #endif
2176 #ifdef macintosh
2178 ** Part of this code is stolen from MacintoshInit in tkMacAppInit.
2179 ** Most of the initializations in that routine (toolbox init calls and
2180 ** such) have already been done for us, so we only need these.
2182 tcl_macQdPtr = &qd;
2184 Tcl_MacSetEventProc(PyMacConvertEvent);
2185 #if GENERATINGCFM
2186 mac_addlibresources();
2187 #endif /* GENERATINGCFM */
2188 #endif /* macintosh */
2193 #ifdef macintosh
2196 ** Anyone who embeds Tcl/Tk on the Mac must define panic().
2199 void
2200 panic(char * format, ...)
2202 va_list varg;
2204 va_start(varg, format);
2206 vfprintf(stderr, format, varg);
2207 (void) fflush(stderr);
2209 va_end(varg);
2211 Py_FatalError("Tcl/Tk panic");
2215 ** Pass events to SIOUX before passing them to Tk.
2218 static int
2219 PyMacConvertEvent(EventRecord *eventPtr)
2221 WindowPtr frontwin;
2223 ** Sioux eats too many events, so we don't pass it everything. We
2224 ** always pass update events to Sioux, and we only pass other events if
2225 ** the Sioux window is frontmost. This means that Tk menus don't work
2226 ** in that case, but at least we can scroll the sioux window.
2227 ** Note that the SIOUXIsAppWindow() routine we use here is not really
2228 ** part of the external interface of Sioux...
2230 frontwin = FrontWindow();
2231 if ( eventPtr->what == updateEvt || SIOUXIsAppWindow(frontwin) ) {
2232 if (SIOUXHandleOneEvent(eventPtr))
2233 return 0; /* Nothing happened to the Tcl event queue */
2235 return TkMacConvertEvent(eventPtr);
2238 #if GENERATINGCFM
2241 ** Additional Mac specific code for dealing with shared libraries.
2244 #include <Resources.h>
2245 #include <CodeFragments.h>
2247 static int loaded_from_shlib = 0;
2248 static FSSpec library_fss;
2251 ** If this module is dynamically loaded the following routine should
2252 ** be the init routine. It takes care of adding the shared library to
2253 ** the resource-file chain, so that the tk routines can find their
2254 ** resources.
2256 OSErr pascal
2257 init_tkinter_shlib(CFragInitBlockPtr data)
2259 __initialize();
2260 if ( data == nil ) return noErr;
2261 if ( data->fragLocator.where == kDataForkCFragLocator ) {
2262 library_fss = *data->fragLocator.u.onDisk.fileSpec;
2263 loaded_from_shlib = 1;
2264 } else if ( data->fragLocator.where == kResourceCFragLocator ) {
2265 library_fss = *data->fragLocator.u.inSegs.fileSpec;
2266 loaded_from_shlib = 1;
2268 return noErr;
2272 ** Insert the library resources into the search path. Put them after
2273 ** the resources from the application. Again, we ignore errors.
2275 static
2276 mac_addlibresources(void)
2278 if ( !loaded_from_shlib )
2279 return;
2280 (void)FSpOpenResFile(&library_fss, fsRdPerm);
2283 #endif /* GENERATINGCFM */
2284 #endif /* macintosh */