This commit was manufactured by cvs2svn to create tag 'r212'.
[python/dscho.git] / Modules / _tkinter.c
bloba279713a1c501117a68bfa53a2667b54f2cfdbd5
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 #include <tcl.h>
45 #include <tk.h>
47 #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION)
49 #if TKMAJORMINOR < 8000
50 #error "Tk older than 8.0 not supported"
51 #endif
53 #if defined(macintosh)
54 /* Sigh, we have to include this to get at the tcl qd pointer */
55 #include <tkMac.h>
56 /* And this one we need to clear the menu bar */
57 #include <Menus.h>
58 #endif
60 #if !(defined(MS_WINDOWS) || defined(__CYGWIN__) || defined(macintosh))
61 /* Mac has it, but it doesn't really work:-( */
62 #define HAVE_CREATEFILEHANDLER
63 #endif
65 #ifdef HAVE_CREATEFILEHANDLER
67 /* Tcl_CreateFileHandler() changed several times; these macros deal with the
68 messiness. In Tcl 8.0 and later, it is not available on Windows (and on
69 Unix, only because Jack added it back); when available on Windows, it only
70 applies to sockets. */
72 #ifdef MS_WINDOWS
73 #define FHANDLETYPE TCL_WIN_SOCKET
74 #else
75 #define FHANDLETYPE TCL_UNIX_FD
76 #endif
78 /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine
79 which uses this to handle Tcl events while the user is typing commands. */
81 #if FHANDLETYPE == TCL_UNIX_FD
82 #define WAIT_FOR_STDIN
83 #endif
85 #endif /* HAVE_CREATEFILEHANDLER */
87 #ifdef MS_WINDOWS
88 #include <conio.h>
89 #define WAIT_FOR_STDIN
90 #endif
92 #ifdef WITH_THREAD
94 /* The threading situation is complicated. Tcl is not thread-safe, except for
95 Tcl 8.1, which will probably remain in alpha status for another 6 months
96 (and the README says that Tk will probably remain thread-unsafe forever).
97 So we need to use a lock around all uses of Tcl. Previously, the Python
98 interpreter lock was used for this. However, this causes problems when
99 other Python threads need to run while Tcl is blocked waiting for events.
101 To solve this problem, a separate lock for Tcl is introduced. Holding it
102 is incompatible with holding Python's interpreter lock. The following four
103 macros manipulate both locks together.
105 ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and
106 Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made
107 that could call an event handler, or otherwise affect the state of a Tcl
108 interpreter. These assume that the surrounding code has the Python
109 interpreter lock; inside the brackets, the Python interpreter lock has been
110 released and the lock for Tcl has been acquired.
112 Sometimes, it is necessary to have both the Python lock and the Tcl lock.
113 (For example, when transferring data from the Tcl interpreter result to a
114 Python string object.) This can be done by using different macros to close
115 the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores
116 the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL
117 releases the Tcl lock.
119 By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event
120 handlers when the handler needs to use Python. Such event handlers are
121 entered while the lock for Tcl is held; the event handler presumably needs
122 to use Python. ENTER_PYTHON releases the lock for Tcl and acquires
123 the Python interpreter lock, restoring the appropriate thread state, and
124 LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock
125 for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside
126 the code between ENTER_PYTHON and LEAVE_PYTHON.
128 These locks expand to several statements and brackets; they should not be
129 used in branches of if statements and the like.
133 static PyThread_type_lock tcl_lock = 0;
134 static PyThreadState *tcl_tstate = NULL;
136 #define ENTER_TCL \
137 { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
138 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
140 #define LEAVE_TCL \
141 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
143 #define ENTER_OVERLAP \
144 Py_END_ALLOW_THREADS
146 #define LEAVE_OVERLAP_TCL \
147 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); }
149 #define ENTER_PYTHON \
150 { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
151 PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
153 #define LEAVE_PYTHON \
154 { PyThreadState *tstate = PyEval_SaveThread(); \
155 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
157 #else
159 #define ENTER_TCL
160 #define LEAVE_TCL
161 #define ENTER_OVERLAP
162 #define LEAVE_OVERLAP_TCL
163 #define ENTER_PYTHON
164 #define LEAVE_PYTHON
166 #endif
168 #ifdef macintosh
171 ** Additional cruft needed by Tcl/Tk on the Mac.
172 ** This is for Tcl 7.5 and Tk 4.1 (patch release 1).
175 /* ckfree() expects a char* */
176 #define FREECAST (char *)
178 #include <Events.h> /* For EventRecord */
180 typedef int (*TclMacConvertEventPtr) (EventRecord *eventPtr);
181 void Tcl_MacSetEventProc(TclMacConvertEventPtr procPtr);
182 int TkMacConvertEvent(EventRecord *eventPtr);
184 staticforward int PyMacConvertEvent(EventRecord *eventPtr);
186 #if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
187 #pragma import on
188 #endif
190 #include <SIOUX.h>
191 extern int SIOUXIsAppWindow(WindowPtr);
193 #if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
194 #pragma import reset
195 #endif
196 #endif /* macintosh */
198 #ifndef FREECAST
199 #define FREECAST (char *)
200 #endif
202 /**** Tkapp Object Declaration ****/
204 staticforward PyTypeObject Tkapp_Type;
206 typedef struct {
207 PyObject_HEAD
208 Tcl_Interp *interp;
209 } TkappObject;
211 #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
212 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
213 #define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v))
215 #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \
216 (void *) v, ((PyObject *) v)->ob_refcnt))
220 /**** Error Handling ****/
222 static PyObject *Tkinter_TclError;
223 static int quitMainLoop = 0;
224 static int errorInCmd = 0;
225 static PyObject *excInCmd;
226 static PyObject *valInCmd;
227 static PyObject *trbInCmd;
231 static PyObject *
232 Tkinter_Error(PyObject *v)
234 PyErr_SetString(Tkinter_TclError, Tkapp_Result(v));
235 return NULL;
240 /**** Utils ****/
242 #ifdef WITH_THREAD
243 #ifndef MS_WINDOWS
245 /* Millisecond sleep() for Unix platforms. */
247 static void
248 Sleep(int milli)
250 /* XXX Too bad if you don't have select(). */
251 struct timeval t;
252 t.tv_sec = milli/1000;
253 t.tv_usec = (milli%1000) * 1000;
254 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
256 #endif /* MS_WINDOWS */
257 #endif /* WITH_THREAD */
260 static char *
261 AsString(PyObject *value, PyObject *tmp)
263 if (PyString_Check(value))
264 return PyString_AsString(value);
265 else if (PyUnicode_Check(value)) {
266 PyObject *v = PyUnicode_AsUTF8String(value);
267 if (v == NULL)
268 return NULL;
269 if (PyList_Append(tmp, v) != 0) {
270 Py_DECREF(v);
271 return NULL;
273 Py_DECREF(v);
274 return PyString_AsString(v);
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
462 /* Delete the 'exit' command, which can screw things up */
463 Tcl_DeleteCommand(v->interp, "exit");
465 if (screenName != NULL)
466 Tcl_SetVar2(v->interp, "env", "DISPLAY",
467 screenName, TCL_GLOBAL_ONLY);
469 if (interactive)
470 Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
471 else
472 Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
474 /* This is used to get the application class for Tk 4.1 and up */
475 argv0 = (char*)ckalloc(strlen(className) + 1);
476 if (!argv0) {
477 PyErr_NoMemory();
478 Py_DECREF(v);
479 return NULL;
482 strcpy(argv0, className);
483 if (isupper((int)(argv0[0])))
484 argv0[0] = tolower(argv0[0]);
485 Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY);
486 ckfree(argv0);
488 if (Tcl_AppInit(v->interp) != TCL_OK)
489 return (TkappObject *)Tkinter_Error((PyObject *)v);
491 EnableEventHook();
493 return v;
498 /** Tcl Eval **/
500 #if TKMAJORMINOR >= 8001
501 #define USING_OBJECTS
502 #endif
504 #ifdef USING_OBJECTS
506 static Tcl_Obj*
507 AsObj(PyObject *value)
509 Tcl_Obj *result;
511 if (PyString_Check(value))
512 return Tcl_NewStringObj(PyString_AS_STRING(value),
513 PyString_GET_SIZE(value));
514 else if (PyInt_Check(value))
515 return Tcl_NewLongObj(PyInt_AS_LONG(value));
516 else if (PyFloat_Check(value))
517 return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
518 else if (PyTuple_Check(value)) {
519 Tcl_Obj **argv = (Tcl_Obj**)
520 ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*));
521 int i;
522 if(!argv)
523 return 0;
524 for(i=0;i<PyTuple_Size(value);i++)
525 argv[i] = AsObj(PyTuple_GetItem(value,i));
526 result = Tcl_NewListObj(PyTuple_Size(value), argv);
527 ckfree(FREECAST argv);
528 return result;
530 else if (PyUnicode_Check(value)) {
531 #if TKMAJORMINOR <= 8001
532 /* In Tcl 8.1 we must use UTF-8 */
533 PyObject* utf8 = PyUnicode_AsUTF8String(value);
534 if (!utf8)
535 return 0;
536 result = Tcl_NewStringObj(PyString_AS_STRING(utf8),
537 PyString_GET_SIZE(utf8));
538 Py_DECREF(utf8);
539 return result;
540 #else /* TKMAJORMINOR > 8001 */
541 /* In Tcl 8.2 and later, use Tcl_NewUnicodeObj() */
542 if (sizeof(Py_UNICODE) != sizeof(Tcl_UniChar)) {
543 /* XXX Should really test this at compile time */
544 PyErr_SetString(PyExc_SystemError,
545 "Py_UNICODE and Tcl_UniChar differ in size");
546 return 0;
548 return Tcl_NewUnicodeObj(PyUnicode_AS_UNICODE(value),
549 PyUnicode_GET_SIZE(value));
550 #endif /* TKMAJORMINOR > 8001 */
552 else {
553 PyObject *v = PyObject_Str(value);
554 if (!v)
555 return 0;
556 result = AsObj(v);
557 Py_DECREF(v);
558 return result;
562 static PyObject *
563 Tkapp_Call(PyObject *self, PyObject *args)
565 Tcl_Obj *objStore[ARGSZ];
566 Tcl_Obj **objv = NULL;
567 int objc = 0, i;
568 PyObject *res = NULL;
569 Tcl_Interp *interp = Tkapp_Interp(self);
570 /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */
571 int flags = TCL_EVAL_DIRECT;
573 objv = objStore;
575 if (args == NULL)
576 /* do nothing */;
578 else if (!PyTuple_Check(args)) {
579 objv[0] = AsObj(args);
580 if (objv[0] == 0)
581 goto finally;
582 objc = 1;
583 Tcl_IncrRefCount(objv[0]);
585 else {
586 objc = PyTuple_Size(args);
588 if (objc > ARGSZ) {
589 objv = (Tcl_Obj **)ckalloc(objc * sizeof(char *));
590 if (objv == NULL) {
591 PyErr_NoMemory();
592 objc = 0;
593 goto finally;
597 for (i = 0; i < objc; i++) {
598 PyObject *v = PyTuple_GetItem(args, i);
599 if (v == Py_None) {
600 objc = i;
601 break;
603 objv[i] = AsObj(v);
604 if (!objv[i]) {
605 /* Reset objc, so it attempts to clear
606 objects only up to i. */
607 objc = i;
608 goto finally;
610 Tcl_IncrRefCount(objv[i]);
614 ENTER_TCL
616 i = Tcl_EvalObjv(interp, objc, objv, flags);
618 ENTER_OVERLAP
619 if (i == TCL_ERROR)
620 Tkinter_Error(self);
621 else {
622 /* We could request the object result here, but doing
623 so would confuse applications that expect a string. */
624 char *s = Tcl_GetStringResult(interp);
625 char *p = s;
626 /* If the result contains any bytes with the top bit set,
627 it's UTF-8 and we should decode it to Unicode */
628 while (*p != '\0') {
629 if (*p & 0x80)
630 break;
631 p++;
633 if (*p == '\0')
634 res = PyString_FromStringAndSize(s, (int)(p-s));
635 else {
636 /* Convert UTF-8 to Unicode string */
637 p = strchr(p, '\0');
638 res = PyUnicode_DecodeUTF8(s, (int)(p-s), "strict");
639 if (res == NULL) {
640 PyErr_Clear();
641 res = PyString_FromStringAndSize(s, (int)(p-s));
646 LEAVE_OVERLAP_TCL
648 finally:
649 for (i = 0; i < objc; i++)
650 Tcl_DecrRefCount(objv[i]);
651 if (objv != objStore)
652 ckfree(FREECAST objv);
653 return res;
656 #else /* !USING_OBJECTS */
658 static PyObject *
659 Tkapp_Call(PyObject *self, PyObject *args)
661 /* This is copied from Merge() */
662 PyObject *tmp = NULL;
663 char *argvStore[ARGSZ];
664 char **argv = NULL;
665 int fvStore[ARGSZ];
666 int *fv = NULL;
667 int argc = 0, fvc = 0, i;
668 PyObject *res = NULL; /* except this has a different type */
669 Tcl_CmdInfo info; /* and this is added */
670 Tcl_Interp *interp = Tkapp_Interp(self); /* and this too */
672 if (!(tmp = PyList_New(0)))
673 return NULL;
675 argv = argvStore;
676 fv = fvStore;
678 if (args == NULL)
679 argc = 0;
681 else if (!PyTuple_Check(args)) {
682 argc = 1;
683 fv[0] = 0;
684 if (!(argv[0] = AsString(args, tmp)))
685 goto finally;
687 else {
688 argc = PyTuple_Size(args);
690 if (argc > ARGSZ) {
691 argv = (char **)ckalloc(argc * sizeof(char *));
692 fv = (int *)ckalloc(argc * sizeof(int));
693 if (argv == NULL || fv == NULL) {
694 PyErr_NoMemory();
695 goto finally;
699 for (i = 0; i < argc; i++) {
700 PyObject *v = PyTuple_GetItem(args, i);
701 if (PyTuple_Check(v)) {
702 fv[i] = 1;
703 if (!(argv[i] = Merge(v)))
704 goto finally;
705 fvc++;
707 else if (v == Py_None) {
708 argc = i;
709 break;
711 else {
712 fv[i] = 0;
713 if (!(argv[i] = AsString(v, tmp)))
714 goto finally;
715 fvc++;
719 /* End code copied from Merge() */
721 /* All this to avoid a call to Tcl_Merge() and the corresponding call
722 to Tcl_SplitList() inside Tcl_Eval()... It can save a bundle! */
723 if (Py_VerboseFlag >= 2) {
724 for (i = 0; i < argc; i++)
725 PySys_WriteStderr("%s ", argv[i]);
727 ENTER_TCL
728 info.proc = NULL;
729 if (argc < 1 ||
730 !Tcl_GetCommandInfo(interp, argv[0], &info) ||
731 info.proc == NULL)
733 char *cmd;
734 cmd = Tcl_Merge(argc, argv);
735 i = Tcl_Eval(interp, cmd);
736 ckfree(cmd);
738 else {
739 Tcl_ResetResult(interp);
740 i = (*info.proc)(info.clientData, interp, argc, argv);
742 ENTER_OVERLAP
743 if (info.proc == NULL && Py_VerboseFlag >= 2)
744 PySys_WriteStderr("... use TclEval ");
745 if (i == TCL_ERROR) {
746 if (Py_VerboseFlag >= 2)
747 PySys_WriteStderr("... error: '%s'\n",
748 Tcl_GetStringResult(interp));
749 Tkinter_Error(self);
751 else {
752 if (Py_VerboseFlag >= 2)
753 PySys_WriteStderr("-> '%s'\n", Tcl_GetStringResult(interp));
754 res = PyString_FromString(Tcl_GetStringResult(interp));
756 LEAVE_OVERLAP_TCL
758 /* Copied from Merge() again */
759 finally:
760 for (i = 0; i < fvc; i++)
761 if (fv[i]) {
762 ckfree(argv[i]);
764 if (argv != argvStore)
765 ckfree(FREECAST argv);
766 if (fv != fvStore)
767 ckfree(FREECAST fv);
769 Py_DECREF(tmp);
770 return res;
773 #endif /* !USING_OBJECTS */
775 static PyObject *
776 Tkapp_GlobalCall(PyObject *self, PyObject *args)
778 /* Could do the same here as for Tkapp_Call(), but this is not used
779 much, so I can't be bothered. Unfortunately Tcl doesn't export a
780 way for the user to do what all its Global* variants do (save and
781 reset the scope pointer, call the local version, restore the saved
782 scope pointer). */
784 char *cmd;
785 PyObject *res = NULL;
787 cmd = Merge(args);
788 if (cmd) {
789 int err;
790 ENTER_TCL
791 err = Tcl_GlobalEval(Tkapp_Interp(self), cmd);
792 ENTER_OVERLAP
793 if (err == TCL_ERROR)
794 res = Tkinter_Error(self);
795 else
796 res = PyString_FromString(Tkapp_Result(self));
797 LEAVE_OVERLAP_TCL
798 ckfree(cmd);
801 return res;
804 static PyObject *
805 Tkapp_Eval(PyObject *self, PyObject *args)
807 char *script;
808 PyObject *res = NULL;
809 int err;
811 if (!PyArg_ParseTuple(args, "s:eval", &script))
812 return NULL;
814 ENTER_TCL
815 err = Tcl_Eval(Tkapp_Interp(self), script);
816 ENTER_OVERLAP
817 if (err == TCL_ERROR)
818 res = Tkinter_Error(self);
819 else
820 res = PyString_FromString(Tkapp_Result(self));
821 LEAVE_OVERLAP_TCL
822 return res;
825 static PyObject *
826 Tkapp_GlobalEval(PyObject *self, PyObject *args)
828 char *script;
829 PyObject *res = NULL;
830 int err;
832 if (!PyArg_ParseTuple(args, "s:globaleval", &script))
833 return NULL;
835 ENTER_TCL
836 err = Tcl_GlobalEval(Tkapp_Interp(self), script);
837 ENTER_OVERLAP
838 if (err == TCL_ERROR)
839 res = Tkinter_Error(self);
840 else
841 res = PyString_FromString(Tkapp_Result(self));
842 LEAVE_OVERLAP_TCL
843 return res;
846 static PyObject *
847 Tkapp_EvalFile(PyObject *self, PyObject *args)
849 char *fileName;
850 PyObject *res = NULL;
851 int err;
853 if (!PyArg_ParseTuple(args, "s:evalfile", &fileName))
854 return NULL;
856 ENTER_TCL
857 err = Tcl_EvalFile(Tkapp_Interp(self), fileName);
858 ENTER_OVERLAP
859 if (err == TCL_ERROR)
860 res = Tkinter_Error(self);
862 else
863 res = PyString_FromString(Tkapp_Result(self));
864 LEAVE_OVERLAP_TCL
865 return res;
868 static PyObject *
869 Tkapp_Record(PyObject *self, PyObject *args)
871 char *script;
872 PyObject *res = NULL;
873 int err;
875 if (!PyArg_ParseTuple(args, "s", &script))
876 return NULL;
878 ENTER_TCL
879 err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL);
880 ENTER_OVERLAP
881 if (err == TCL_ERROR)
882 res = Tkinter_Error(self);
883 else
884 res = PyString_FromString(Tkapp_Result(self));
885 LEAVE_OVERLAP_TCL
886 return res;
889 static PyObject *
890 Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
892 char *msg;
894 if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg))
895 return NULL;
896 ENTER_TCL
897 Tcl_AddErrorInfo(Tkapp_Interp(self), msg);
898 LEAVE_TCL
900 Py_INCREF(Py_None);
901 return Py_None;
906 /** Tcl Variable **/
908 static PyObject *
909 SetVar(PyObject *self, PyObject *args, int flags)
911 char *name1, *name2, *ok, *s;
912 PyObject *newValue;
913 PyObject *tmp;
915 tmp = PyList_New(0);
916 if (!tmp)
917 return NULL;
919 if (PyArg_ParseTuple(args, "sO:setvar", &name1, &newValue)) {
920 /* XXX Merge? */
921 s = AsString(newValue, tmp);
922 if (s == NULL)
923 return NULL;
924 ENTER_TCL
925 ok = Tcl_SetVar(Tkapp_Interp(self), name1, s, flags);
926 LEAVE_TCL
928 else {
929 PyErr_Clear();
930 if (PyArg_ParseTuple(args, "ssO:setvar",
931 &name1, &name2, &newValue)) {
932 s = AsString(newValue, tmp);
933 if (s == NULL)
934 return NULL;
935 ENTER_TCL
936 ok = Tcl_SetVar2(Tkapp_Interp(self), name1, name2,
937 s, flags);
938 LEAVE_TCL
940 else {
941 Py_DECREF(tmp);
942 return NULL;
945 Py_DECREF(tmp);
947 if (!ok)
948 return Tkinter_Error(self);
950 Py_INCREF(Py_None);
951 return Py_None;
954 static PyObject *
955 Tkapp_SetVar(PyObject *self, PyObject *args)
957 return SetVar(self, args, TCL_LEAVE_ERR_MSG);
960 static PyObject *
961 Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
963 return SetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
968 static PyObject *
969 GetVar(PyObject *self, PyObject *args, int flags)
971 char *name1, *name2=NULL, *s;
972 PyObject *res = NULL;
974 if (!PyArg_ParseTuple(args, "s|s:getvar", &name1, &name2))
975 return NULL;
976 ENTER_TCL
977 if (name2 == NULL)
978 s = Tcl_GetVar(Tkapp_Interp(self), name1, flags);
980 else
981 s = Tcl_GetVar2(Tkapp_Interp(self), name1, name2, flags);
982 ENTER_OVERLAP
984 if (s == NULL)
985 res = Tkinter_Error(self);
986 else
987 res = PyString_FromString(s);
988 LEAVE_OVERLAP_TCL
989 return res;
992 static PyObject *
993 Tkapp_GetVar(PyObject *self, PyObject *args)
995 return GetVar(self, args, TCL_LEAVE_ERR_MSG);
998 static PyObject *
999 Tkapp_GlobalGetVar(PyObject *self, PyObject *args)
1001 return GetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1006 static PyObject *
1007 UnsetVar(PyObject *self, PyObject *args, int flags)
1009 char *name1, *name2=NULL;
1010 PyObject *res = NULL;
1011 int code;
1013 if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
1014 return NULL;
1015 ENTER_TCL
1016 if (name2 == NULL)
1017 code = Tcl_UnsetVar(Tkapp_Interp(self), name1, flags);
1019 else
1020 code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
1021 ENTER_OVERLAP
1023 if (code == TCL_ERROR)
1024 res = Tkinter_Error(self);
1025 else {
1026 Py_INCREF(Py_None);
1027 res = Py_None;
1029 LEAVE_OVERLAP_TCL
1030 return res;
1033 static PyObject *
1034 Tkapp_UnsetVar(PyObject *self, PyObject *args)
1036 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG);
1039 static PyObject *
1040 Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args)
1042 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1047 /** Tcl to Python **/
1049 static PyObject *
1050 Tkapp_GetInt(PyObject *self, PyObject *args)
1052 char *s;
1053 int v;
1055 if (!PyArg_ParseTuple(args, "s:getint", &s))
1056 return NULL;
1057 if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1058 return Tkinter_Error(self);
1059 return Py_BuildValue("i", v);
1062 static PyObject *
1063 Tkapp_GetDouble(PyObject *self, PyObject *args)
1065 char *s;
1066 double v;
1068 if (!PyArg_ParseTuple(args, "s:getdouble", &s))
1069 return NULL;
1070 if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1071 return Tkinter_Error(self);
1072 return Py_BuildValue("d", v);
1075 static PyObject *
1076 Tkapp_GetBoolean(PyObject *self, PyObject *args)
1078 char *s;
1079 int v;
1081 if (!PyArg_ParseTuple(args, "s:getboolean", &s))
1082 return NULL;
1083 if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1084 return Tkinter_Error(self);
1085 return Py_BuildValue("i", v);
1088 static PyObject *
1089 Tkapp_ExprString(PyObject *self, PyObject *args)
1091 char *s;
1092 PyObject *res = NULL;
1093 int retval;
1095 if (!PyArg_ParseTuple(args, "s:exprstring", &s))
1096 return NULL;
1097 ENTER_TCL
1098 retval = Tcl_ExprString(Tkapp_Interp(self), s);
1099 ENTER_OVERLAP
1100 if (retval == TCL_ERROR)
1101 res = Tkinter_Error(self);
1102 else
1103 res = Py_BuildValue("s", Tkapp_Result(self));
1104 LEAVE_OVERLAP_TCL
1105 return res;
1108 static PyObject *
1109 Tkapp_ExprLong(PyObject *self, PyObject *args)
1111 char *s;
1112 PyObject *res = NULL;
1113 int retval;
1114 long v;
1116 if (!PyArg_ParseTuple(args, "s:exprlong", &s))
1117 return NULL;
1118 ENTER_TCL
1119 retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v);
1120 ENTER_OVERLAP
1121 if (retval == TCL_ERROR)
1122 res = Tkinter_Error(self);
1123 else
1124 res = Py_BuildValue("l", v);
1125 LEAVE_OVERLAP_TCL
1126 return res;
1129 static PyObject *
1130 Tkapp_ExprDouble(PyObject *self, PyObject *args)
1132 char *s;
1133 PyObject *res = NULL;
1134 double v;
1135 int retval;
1137 if (!PyArg_ParseTuple(args, "s:exprdouble", &s))
1138 return NULL;
1139 PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
1140 ENTER_TCL
1141 retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v);
1142 ENTER_OVERLAP
1143 PyFPE_END_PROTECT(retval)
1144 if (retval == TCL_ERROR)
1145 res = Tkinter_Error(self);
1146 else
1147 res = Py_BuildValue("d", v);
1148 LEAVE_OVERLAP_TCL
1149 return res;
1152 static PyObject *
1153 Tkapp_ExprBoolean(PyObject *self, PyObject *args)
1155 char *s;
1156 PyObject *res = NULL;
1157 int retval;
1158 int v;
1160 if (!PyArg_ParseTuple(args, "s:exprboolean", &s))
1161 return NULL;
1162 ENTER_TCL
1163 retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
1164 ENTER_OVERLAP
1165 if (retval == TCL_ERROR)
1166 res = Tkinter_Error(self);
1167 else
1168 res = Py_BuildValue("i", v);
1169 LEAVE_OVERLAP_TCL
1170 return res;
1175 static PyObject *
1176 Tkapp_SplitList(PyObject *self, PyObject *args)
1178 char *list;
1179 int argc;
1180 char **argv;
1181 PyObject *v;
1182 int i;
1184 if (!PyArg_ParseTuple(args, "s:splitlist", &list))
1185 return NULL;
1187 if (Tcl_SplitList(Tkapp_Interp(self), list, &argc, &argv) == TCL_ERROR)
1188 return Tkinter_Error(self);
1190 if (!(v = PyTuple_New(argc)))
1191 return NULL;
1193 for (i = 0; i < argc; i++) {
1194 PyObject *s = PyString_FromString(argv[i]);
1195 if (!s || PyTuple_SetItem(v, i, s)) {
1196 Py_DECREF(v);
1197 v = NULL;
1198 goto finally;
1202 finally:
1203 ckfree(FREECAST argv);
1204 return v;
1207 static PyObject *
1208 Tkapp_Split(PyObject *self, PyObject *args)
1210 char *list;
1212 if (!PyArg_ParseTuple(args, "s:split", &list))
1213 return NULL;
1214 return Split(list);
1217 static PyObject *
1218 Tkapp_Merge(PyObject *self, PyObject *args)
1220 char *s = Merge(args);
1221 PyObject *res = NULL;
1223 if (s) {
1224 res = PyString_FromString(s);
1225 ckfree(s);
1228 return res;
1233 /** Tcl Command **/
1235 /* Client data struct */
1236 typedef struct {
1237 PyObject *self;
1238 PyObject *func;
1239 } PythonCmd_ClientData;
1241 static int
1242 PythonCmd_Error(Tcl_Interp *interp)
1244 errorInCmd = 1;
1245 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1246 LEAVE_PYTHON
1247 return TCL_ERROR;
1250 /* This is the Tcl command that acts as a wrapper for Python
1251 * function or method.
1253 static int
1254 PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1256 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1257 PyObject *self, *func, *arg, *res, *tmp;
1258 int i, rv;
1259 char *s;
1261 ENTER_PYTHON
1263 /* TBD: no error checking here since we know, via the
1264 * Tkapp_CreateCommand() that the client data is a two-tuple
1266 self = data->self;
1267 func = data->func;
1269 /* Create argument list (argv1, ..., argvN) */
1270 if (!(arg = PyTuple_New(argc - 1)))
1271 return PythonCmd_Error(interp);
1273 for (i = 0; i < (argc - 1); i++) {
1274 PyObject *s = PyString_FromString(argv[i + 1]);
1275 if (!s || PyTuple_SetItem(arg, i, s)) {
1276 Py_DECREF(arg);
1277 return PythonCmd_Error(interp);
1280 res = PyEval_CallObject(func, arg);
1281 Py_DECREF(arg);
1283 if (res == NULL)
1284 return PythonCmd_Error(interp);
1286 if (!(tmp = PyList_New(0))) {
1287 Py_DECREF(res);
1288 return PythonCmd_Error(interp);
1291 s = AsString(res, tmp);
1292 if (s == NULL) {
1293 rv = PythonCmd_Error(interp);
1295 else {
1296 Tcl_SetResult(Tkapp_Interp(self), s, TCL_VOLATILE);
1297 rv = TCL_OK;
1300 Py_DECREF(res);
1301 Py_DECREF(tmp);
1303 LEAVE_PYTHON
1305 return rv;
1308 static void
1309 PythonCmdDelete(ClientData clientData)
1311 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1313 ENTER_PYTHON
1314 Py_XDECREF(data->self);
1315 Py_XDECREF(data->func);
1316 PyMem_DEL(data);
1317 LEAVE_PYTHON
1322 static PyObject *
1323 Tkapp_CreateCommand(PyObject *self, PyObject *args)
1325 PythonCmd_ClientData *data;
1326 char *cmdName;
1327 PyObject *func;
1328 Tcl_Command err;
1330 if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func))
1331 return NULL;
1332 if (!PyCallable_Check(func)) {
1333 PyErr_SetString(PyExc_TypeError, "command not callable");
1334 return NULL;
1337 data = PyMem_NEW(PythonCmd_ClientData, 1);
1338 if (!data)
1339 return NULL;
1340 Py_XINCREF(self);
1341 Py_XINCREF(func);
1342 data->self = self;
1343 data->func = func;
1345 ENTER_TCL
1346 err = Tcl_CreateCommand(Tkapp_Interp(self), cmdName, PythonCmd,
1347 (ClientData)data, PythonCmdDelete);
1348 LEAVE_TCL
1349 if (err == NULL) {
1350 PyErr_SetString(Tkinter_TclError, "can't create Tcl command");
1351 PyMem_DEL(data);
1352 return NULL;
1355 Py_INCREF(Py_None);
1356 return Py_None;
1361 static PyObject *
1362 Tkapp_DeleteCommand(PyObject *self, PyObject *args)
1364 char *cmdName;
1365 int err;
1367 if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName))
1368 return NULL;
1369 ENTER_TCL
1370 err = Tcl_DeleteCommand(Tkapp_Interp(self), cmdName);
1371 LEAVE_TCL
1372 if (err == -1) {
1373 PyErr_SetString(Tkinter_TclError, "can't delete Tcl command");
1374 return NULL;
1376 Py_INCREF(Py_None);
1377 return Py_None;
1382 #ifdef HAVE_CREATEFILEHANDLER
1383 /** File Handler **/
1385 typedef struct _fhcdata {
1386 PyObject *func;
1387 PyObject *file;
1388 int id;
1389 struct _fhcdata *next;
1390 } FileHandler_ClientData;
1392 static FileHandler_ClientData *HeadFHCD;
1394 static FileHandler_ClientData *
1395 NewFHCD(PyObject *func, PyObject *file, int id)
1397 FileHandler_ClientData *p;
1398 p = PyMem_NEW(FileHandler_ClientData, 1);
1399 if (p != NULL) {
1400 Py_XINCREF(func);
1401 Py_XINCREF(file);
1402 p->func = func;
1403 p->file = file;
1404 p->id = id;
1405 p->next = HeadFHCD;
1406 HeadFHCD = p;
1408 return p;
1411 static void
1412 DeleteFHCD(int id)
1414 FileHandler_ClientData *p, **pp;
1416 pp = &HeadFHCD;
1417 while ((p = *pp) != NULL) {
1418 if (p->id == id) {
1419 *pp = p->next;
1420 Py_XDECREF(p->func);
1421 Py_XDECREF(p->file);
1422 PyMem_DEL(p);
1424 else
1425 pp = &p->next;
1429 static void
1430 FileHandler(ClientData clientData, int mask)
1432 FileHandler_ClientData *data = (FileHandler_ClientData *)clientData;
1433 PyObject *func, *file, *arg, *res;
1435 ENTER_PYTHON
1436 func = data->func;
1437 file = data->file;
1439 arg = Py_BuildValue("(Oi)", file, (long) mask);
1440 res = PyEval_CallObject(func, arg);
1441 Py_DECREF(arg);
1443 if (res == NULL) {
1444 errorInCmd = 1;
1445 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1447 Py_XDECREF(res);
1448 LEAVE_PYTHON
1451 static PyObject *
1452 Tkapp_CreateFileHandler(PyObject *self, PyObject *args)
1453 /* args is (file, mask, func) */
1455 FileHandler_ClientData *data;
1456 PyObject *file, *func;
1457 int mask, tfile;
1459 if (!PyArg_ParseTuple(args, "OiO:createfilehandler",
1460 &file, &mask, &func))
1461 return NULL;
1462 tfile = PyObject_AsFileDescriptor(file);
1463 if (tfile < 0)
1464 return NULL;
1465 if (!PyCallable_Check(func)) {
1466 PyErr_SetString(PyExc_TypeError, "bad argument list");
1467 return NULL;
1470 data = NewFHCD(func, file, tfile);
1471 if (data == NULL)
1472 return NULL;
1474 /* Ought to check for null Tcl_File object... */
1475 ENTER_TCL
1476 Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
1477 LEAVE_TCL
1478 Py_INCREF(Py_None);
1479 return Py_None;
1482 static PyObject *
1483 Tkapp_DeleteFileHandler(PyObject *self, PyObject *args)
1485 PyObject *file;
1486 int tfile;
1488 if (!PyArg_ParseTuple(args, "O:deletefilehandler", &file))
1489 return NULL;
1490 tfile = PyObject_AsFileDescriptor(file);
1491 if (tfile < 0)
1492 return NULL;
1494 DeleteFHCD(tfile);
1496 /* Ought to check for null Tcl_File object... */
1497 ENTER_TCL
1498 Tcl_DeleteFileHandler(tfile);
1499 LEAVE_TCL
1500 Py_INCREF(Py_None);
1501 return Py_None;
1503 #endif /* HAVE_CREATEFILEHANDLER */
1506 /**** Tktt Object (timer token) ****/
1508 staticforward PyTypeObject Tktt_Type;
1510 typedef struct {
1511 PyObject_HEAD
1512 Tcl_TimerToken token;
1513 PyObject *func;
1514 } TkttObject;
1516 static PyObject *
1517 Tktt_DeleteTimerHandler(PyObject *self, PyObject *args)
1519 TkttObject *v = (TkttObject *)self;
1520 PyObject *func = v->func;
1522 if (!PyArg_ParseTuple(args, ":deletetimerhandler"))
1523 return NULL;
1524 if (v->token != NULL) {
1525 Tcl_DeleteTimerHandler(v->token);
1526 v->token = NULL;
1528 if (func != NULL) {
1529 v->func = NULL;
1530 Py_DECREF(func);
1531 Py_DECREF(v); /* See Tktt_New() */
1533 Py_INCREF(Py_None);
1534 return Py_None;
1537 static PyMethodDef Tktt_methods[] =
1539 {"deletetimerhandler", Tktt_DeleteTimerHandler, 1},
1540 {NULL, NULL}
1543 static TkttObject *
1544 Tktt_New(PyObject *func)
1546 TkttObject *v;
1548 v = PyObject_New(TkttObject, &Tktt_Type);
1549 if (v == NULL)
1550 return NULL;
1552 Py_INCREF(func);
1553 v->token = NULL;
1554 v->func = func;
1556 /* Extra reference, deleted when called or when handler is deleted */
1557 Py_INCREF(v);
1558 return v;
1561 static void
1562 Tktt_Dealloc(PyObject *self)
1564 TkttObject *v = (TkttObject *)self;
1565 PyObject *func = v->func;
1567 Py_XDECREF(func);
1569 PyObject_Del(self);
1572 static PyObject *
1573 Tktt_Repr(PyObject *self)
1575 TkttObject *v = (TkttObject *)self;
1576 char buf[100];
1578 sprintf(buf, "<tktimertoken at %p%s>", v,
1579 v->func == NULL ? ", handler deleted" : "");
1580 return PyString_FromString(buf);
1583 static PyObject *
1584 Tktt_GetAttr(PyObject *self, char *name)
1586 return Py_FindMethod(Tktt_methods, self, name);
1589 static PyTypeObject Tktt_Type =
1591 PyObject_HEAD_INIT(NULL)
1592 0, /*ob_size */
1593 "tktimertoken", /*tp_name */
1594 sizeof(TkttObject), /*tp_basicsize */
1595 0, /*tp_itemsize */
1596 Tktt_Dealloc, /*tp_dealloc */
1597 0, /*tp_print */
1598 Tktt_GetAttr, /*tp_getattr */
1599 0, /*tp_setattr */
1600 0, /*tp_compare */
1601 Tktt_Repr, /*tp_repr */
1602 0, /*tp_as_number */
1603 0, /*tp_as_sequence */
1604 0, /*tp_as_mapping */
1605 0, /*tp_hash */
1610 /** Timer Handler **/
1612 static void
1613 TimerHandler(ClientData clientData)
1615 TkttObject *v = (TkttObject *)clientData;
1616 PyObject *func = v->func;
1617 PyObject *res;
1619 if (func == NULL)
1620 return;
1622 v->func = NULL;
1624 ENTER_PYTHON
1626 res = PyEval_CallObject(func, NULL);
1627 Py_DECREF(func);
1628 Py_DECREF(v); /* See Tktt_New() */
1630 if (res == NULL) {
1631 errorInCmd = 1;
1632 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1634 else
1635 Py_DECREF(res);
1637 LEAVE_PYTHON
1640 static PyObject *
1641 Tkapp_CreateTimerHandler(PyObject *self, PyObject *args)
1643 int milliseconds;
1644 PyObject *func;
1645 TkttObject *v;
1647 if (!PyArg_ParseTuple(args, "iO:createtimerhandler",
1648 &milliseconds, &func))
1649 return NULL;
1650 if (!PyCallable_Check(func)) {
1651 PyErr_SetString(PyExc_TypeError, "bad argument list");
1652 return NULL;
1654 v = Tktt_New(func);
1655 v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler,
1656 (ClientData)v);
1658 return (PyObject *) v;
1662 /** Event Loop **/
1664 static PyObject *
1665 Tkapp_MainLoop(PyObject *self, PyObject *args)
1667 int threshold = 0;
1668 #ifdef WITH_THREAD
1669 PyThreadState *tstate = PyThreadState_Get();
1670 #endif
1672 if (!PyArg_ParseTuple(args, "|i:mainloop", &threshold))
1673 return NULL;
1675 quitMainLoop = 0;
1676 while (Tk_GetNumMainWindows() > threshold &&
1677 !quitMainLoop &&
1678 !errorInCmd)
1680 int result;
1682 #ifdef WITH_THREAD
1683 Py_BEGIN_ALLOW_THREADS
1684 PyThread_acquire_lock(tcl_lock, 1);
1685 tcl_tstate = tstate;
1686 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
1687 tcl_tstate = NULL;
1688 PyThread_release_lock(tcl_lock);
1689 if (result == 0)
1690 Sleep(20);
1691 Py_END_ALLOW_THREADS
1692 #else
1693 result = Tcl_DoOneEvent(0);
1694 #endif
1696 if (PyErr_CheckSignals() != 0)
1697 return NULL;
1698 if (result < 0)
1699 break;
1701 quitMainLoop = 0;
1703 if (errorInCmd) {
1704 errorInCmd = 0;
1705 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
1706 excInCmd = valInCmd = trbInCmd = NULL;
1707 return NULL;
1709 Py_INCREF(Py_None);
1710 return Py_None;
1713 static PyObject *
1714 Tkapp_DoOneEvent(PyObject *self, PyObject *args)
1716 int flags = 0;
1717 int rv;
1719 if (!PyArg_ParseTuple(args, "|i:dooneevent", &flags))
1720 return NULL;
1722 ENTER_TCL
1723 rv = Tcl_DoOneEvent(flags);
1724 LEAVE_TCL
1725 return Py_BuildValue("i", rv);
1728 static PyObject *
1729 Tkapp_Quit(PyObject *self, PyObject *args)
1732 if (!PyArg_ParseTuple(args, ":quit"))
1733 return NULL;
1735 quitMainLoop = 1;
1736 Py_INCREF(Py_None);
1737 return Py_None;
1740 static PyObject *
1741 Tkapp_InterpAddr(PyObject *self, PyObject *args)
1744 if (!PyArg_ParseTuple(args, ":interpaddr"))
1745 return NULL;
1747 return PyInt_FromLong((long)Tkapp_Interp(self));
1752 /**** Tkapp Method List ****/
1754 static PyMethodDef Tkapp_methods[] =
1756 {"call", Tkapp_Call, 0},
1757 {"globalcall", Tkapp_GlobalCall, 0},
1758 {"eval", Tkapp_Eval, 1},
1759 {"globaleval", Tkapp_GlobalEval, 1},
1760 {"evalfile", Tkapp_EvalFile, 1},
1761 {"record", Tkapp_Record, 1},
1762 {"adderrorinfo", Tkapp_AddErrorInfo, 1},
1763 {"setvar", Tkapp_SetVar, 1},
1764 {"globalsetvar", Tkapp_GlobalSetVar, 1},
1765 {"getvar", Tkapp_GetVar, 1},
1766 {"globalgetvar", Tkapp_GlobalGetVar, 1},
1767 {"unsetvar", Tkapp_UnsetVar, 1},
1768 {"globalunsetvar", Tkapp_GlobalUnsetVar, 1},
1769 {"getint", Tkapp_GetInt, 1},
1770 {"getdouble", Tkapp_GetDouble, 1},
1771 {"getboolean", Tkapp_GetBoolean, 1},
1772 {"exprstring", Tkapp_ExprString, 1},
1773 {"exprlong", Tkapp_ExprLong, 1},
1774 {"exprdouble", Tkapp_ExprDouble, 1},
1775 {"exprboolean", Tkapp_ExprBoolean, 1},
1776 {"splitlist", Tkapp_SplitList, 1},
1777 {"split", Tkapp_Split, 1},
1778 {"merge", Tkapp_Merge, 0},
1779 {"createcommand", Tkapp_CreateCommand, 1},
1780 {"deletecommand", Tkapp_DeleteCommand, 1},
1781 #ifdef HAVE_CREATEFILEHANDLER
1782 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1783 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1784 #endif
1785 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1786 {"mainloop", Tkapp_MainLoop, 1},
1787 {"dooneevent", Tkapp_DoOneEvent, 1},
1788 {"quit", Tkapp_Quit, 1},
1789 {"interpaddr", Tkapp_InterpAddr, 1},
1790 {NULL, NULL}
1795 /**** Tkapp Type Methods ****/
1797 static void
1798 Tkapp_Dealloc(PyObject *self)
1800 ENTER_TCL
1801 Tcl_DeleteInterp(Tkapp_Interp(self));
1802 LEAVE_TCL
1803 PyObject_Del(self);
1804 DisableEventHook();
1807 static PyObject *
1808 Tkapp_GetAttr(PyObject *self, char *name)
1810 return Py_FindMethod(Tkapp_methods, self, name);
1813 static PyTypeObject Tkapp_Type =
1815 PyObject_HEAD_INIT(NULL)
1816 0, /*ob_size */
1817 "tkapp", /*tp_name */
1818 sizeof(TkappObject), /*tp_basicsize */
1819 0, /*tp_itemsize */
1820 Tkapp_Dealloc, /*tp_dealloc */
1821 0, /*tp_print */
1822 Tkapp_GetAttr, /*tp_getattr */
1823 0, /*tp_setattr */
1824 0, /*tp_compare */
1825 0, /*tp_repr */
1826 0, /*tp_as_number */
1827 0, /*tp_as_sequence */
1828 0, /*tp_as_mapping */
1829 0, /*tp_hash */
1834 /**** Tkinter Module ****/
1836 typedef struct {
1837 PyObject* tuple;
1838 int size; /* current size */
1839 int maxsize; /* allocated size */
1840 } FlattenContext;
1842 static int
1843 _bump(FlattenContext* context, int size)
1845 /* expand tuple to hold (at least) size new items.
1846 return true if successful, false if an exception was raised */
1848 int maxsize = context->maxsize * 2;
1850 if (maxsize < context->size + size)
1851 maxsize = context->size + size;
1853 context->maxsize = maxsize;
1855 return _PyTuple_Resize(&context->tuple, maxsize, 0) >= 0;
1858 static int
1859 _flatten1(FlattenContext* context, PyObject* item, int depth)
1861 /* add tuple or list to argument tuple (recursively) */
1863 int i, size;
1865 if (depth > 1000) {
1866 PyErr_SetString(PyExc_ValueError,
1867 "nesting too deep in _flatten");
1868 return 0;
1869 } else if (PyList_Check(item)) {
1870 size = PyList_GET_SIZE(item);
1871 /* preallocate (assume no nesting) */
1872 if (context->size + size > context->maxsize &&
1873 !_bump(context, size))
1874 return 0;
1875 /* copy items to output tuple */
1876 for (i = 0; i < size; i++) {
1877 PyObject *o = PyList_GET_ITEM(item, i);
1878 if (PyList_Check(o) || PyTuple_Check(o)) {
1879 if (!_flatten1(context, o, depth + 1))
1880 return 0;
1881 } else if (o != Py_None) {
1882 if (context->size + 1 > context->maxsize &&
1883 !_bump(context, 1))
1884 return 0;
1885 Py_INCREF(o);
1886 PyTuple_SET_ITEM(context->tuple,
1887 context->size++, o);
1890 } else if (PyTuple_Check(item)) {
1891 /* same, for tuples */
1892 size = PyTuple_GET_SIZE(item);
1893 if (context->size + size > context->maxsize &&
1894 !_bump(context, size))
1895 return 0;
1896 for (i = 0; i < size; i++) {
1897 PyObject *o = PyTuple_GET_ITEM(item, i);
1898 if (PyList_Check(o) || PyTuple_Check(o)) {
1899 if (!_flatten1(context, o, depth + 1))
1900 return 0;
1901 } else if (o != Py_None) {
1902 if (context->size + 1 > context->maxsize &&
1903 !_bump(context, 1))
1904 return 0;
1905 Py_INCREF(o);
1906 PyTuple_SET_ITEM(context->tuple,
1907 context->size++, o);
1910 } else {
1911 PyErr_SetString(PyExc_TypeError, "argument must be sequence");
1912 return 0;
1914 return 1;
1917 static PyObject *
1918 Tkinter_Flatten(PyObject* self, PyObject* args)
1920 FlattenContext context;
1921 PyObject* item;
1923 if (!PyArg_ParseTuple(args, "O:_flatten", &item))
1924 return NULL;
1926 context.maxsize = PySequence_Size(item);
1927 if (context.maxsize <= 0)
1928 return PyTuple_New(0);
1930 context.tuple = PyTuple_New(context.maxsize);
1931 if (!context.tuple)
1932 return NULL;
1934 context.size = 0;
1936 if (!_flatten1(&context, item,0))
1937 return NULL;
1939 if (_PyTuple_Resize(&context.tuple, context.size, 0))
1940 return NULL;
1942 return context.tuple;
1945 static PyObject *
1946 Tkinter_Create(PyObject *self, PyObject *args)
1948 char *screenName = NULL;
1949 char *baseName = NULL;
1950 char *className = NULL;
1951 int interactive = 0;
1953 baseName = strrchr(Py_GetProgramName(), '/');
1954 if (baseName != NULL)
1955 baseName++;
1956 else
1957 baseName = Py_GetProgramName();
1958 className = "Tk";
1960 if (!PyArg_ParseTuple(args, "|zssi:create",
1961 &screenName, &baseName, &className,
1962 &interactive))
1963 return NULL;
1965 return (PyObject *) Tkapp_New(screenName, baseName, className,
1966 interactive);
1969 static PyMethodDef moduleMethods[] =
1971 {"_flatten", Tkinter_Flatten, 1},
1972 {"create", Tkinter_Create, 1},
1973 #ifdef HAVE_CREATEFILEHANDLER
1974 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1975 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1976 #endif
1977 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1978 {"mainloop", Tkapp_MainLoop, 1},
1979 {"dooneevent", Tkapp_DoOneEvent, 1},
1980 {"quit", Tkapp_Quit, 1},
1981 {NULL, NULL}
1984 #ifdef WAIT_FOR_STDIN
1986 static int stdin_ready = 0;
1988 #ifndef MS_WINDOWS
1989 static void
1990 MyFileProc(void *clientData, int mask)
1992 stdin_ready = 1;
1994 #endif
1996 static PyThreadState *event_tstate = NULL;
1998 static int
1999 EventHook(void)
2001 #ifndef MS_WINDOWS
2002 int tfile;
2003 #endif
2004 #ifdef WITH_THREAD
2005 PyEval_RestoreThread(event_tstate);
2006 #endif
2007 stdin_ready = 0;
2008 errorInCmd = 0;
2009 #ifndef MS_WINDOWS
2010 tfile = fileno(stdin);
2011 Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
2012 #endif
2013 while (!errorInCmd && !stdin_ready) {
2014 int result;
2015 #ifdef MS_WINDOWS
2016 if (_kbhit()) {
2017 stdin_ready = 1;
2018 break;
2020 #endif
2021 #if defined(WITH_THREAD) || defined(MS_WINDOWS)
2022 Py_BEGIN_ALLOW_THREADS
2023 PyThread_acquire_lock(tcl_lock, 1);
2024 tcl_tstate = event_tstate;
2026 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
2028 tcl_tstate = NULL;
2029 PyThread_release_lock(tcl_lock);
2030 if (result == 0)
2031 Sleep(20);
2032 Py_END_ALLOW_THREADS
2033 #else
2034 result = Tcl_DoOneEvent(0);
2035 #endif
2037 if (result < 0)
2038 break;
2040 #ifndef MS_WINDOWS
2041 Tcl_DeleteFileHandler(tfile);
2042 #endif
2043 if (errorInCmd) {
2044 errorInCmd = 0;
2045 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
2046 excInCmd = valInCmd = trbInCmd = NULL;
2047 PyErr_Print();
2049 #ifdef WITH_THREAD
2050 PyEval_SaveThread();
2051 #endif
2052 return 0;
2055 #endif
2057 static void
2058 EnableEventHook(void)
2060 #ifdef WAIT_FOR_STDIN
2061 if (PyOS_InputHook == NULL) {
2062 #ifdef WITH_THREAD
2063 event_tstate = PyThreadState_Get();
2064 #endif
2065 PyOS_InputHook = EventHook;
2067 #endif
2070 static void
2071 DisableEventHook(void)
2073 #ifdef WAIT_FOR_STDIN
2074 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
2075 PyOS_InputHook = NULL;
2077 #endif
2081 /* all errors will be checked in one fell swoop in init_tkinter() */
2082 static void
2083 ins_long(PyObject *d, char *name, long val)
2085 PyObject *v = PyInt_FromLong(val);
2086 if (v) {
2087 PyDict_SetItemString(d, name, v);
2088 Py_DECREF(v);
2091 static void
2092 ins_string(PyObject *d, char *name, char *val)
2094 PyObject *v = PyString_FromString(val);
2095 if (v) {
2096 PyDict_SetItemString(d, name, v);
2097 Py_DECREF(v);
2102 DL_EXPORT(void)
2103 init_tkinter(void)
2105 PyObject *m, *d;
2107 Tkapp_Type.ob_type = &PyType_Type;
2109 #ifdef WITH_THREAD
2110 tcl_lock = PyThread_allocate_lock();
2111 #endif
2113 m = Py_InitModule("_tkinter", moduleMethods);
2115 d = PyModule_GetDict(m);
2116 Tkinter_TclError = Py_BuildValue("s", "TclError");
2117 PyDict_SetItemString(d, "TclError", Tkinter_TclError);
2119 ins_long(d, "READABLE", TCL_READABLE);
2120 ins_long(d, "WRITABLE", TCL_WRITABLE);
2121 ins_long(d, "EXCEPTION", TCL_EXCEPTION);
2122 ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS);
2123 ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS);
2124 ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS);
2125 ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS);
2126 ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS);
2127 ins_long(d, "DONT_WAIT", TCL_DONT_WAIT);
2128 ins_string(d, "TK_VERSION", TK_VERSION);
2129 ins_string(d, "TCL_VERSION", TCL_VERSION);
2131 PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type);
2133 Tktt_Type.ob_type = &PyType_Type;
2134 PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
2136 /* This helps the dynamic loader; in Unicode aware Tcl versions
2137 it also helps Tcl find its encodings. */
2138 Tcl_FindExecutable(Py_GetProgramName());
2140 if (PyErr_Occurred())
2141 return;
2143 #if 0
2144 /* This was not a good idea; through <Destroy> bindings,
2145 Tcl_Finalize() may invoke Python code but at that point the
2146 interpreter and thread state have already been destroyed! */
2147 Py_AtExit(Tcl_Finalize);
2148 #endif
2150 #ifdef macintosh
2152 ** Part of this code is stolen from MacintoshInit in tkMacAppInit.
2153 ** Most of the initializations in that routine (toolbox init calls and
2154 ** such) have already been done for us, so we only need these.
2156 tcl_macQdPtr = &qd;
2158 Tcl_MacSetEventProc(PyMacConvertEvent);
2159 #if GENERATINGCFM
2160 mac_addlibresources();
2161 #endif /* GENERATINGCFM */
2162 #endif /* macintosh */
2167 #ifdef macintosh
2170 ** Anyone who embeds Tcl/Tk on the Mac must define panic().
2173 void
2174 panic(char * format, ...)
2176 va_list varg;
2178 va_start(varg, format);
2180 vfprintf(stderr, format, varg);
2181 (void) fflush(stderr);
2183 va_end(varg);
2185 Py_FatalError("Tcl/Tk panic");
2189 ** Pass events to SIOUX before passing them to Tk.
2192 static int
2193 PyMacConvertEvent(EventRecord *eventPtr)
2195 WindowPtr frontwin;
2197 ** Sioux eats too many events, so we don't pass it everything. We
2198 ** always pass update events to Sioux, and we only pass other events if
2199 ** the Sioux window is frontmost. This means that Tk menus don't work
2200 ** in that case, but at least we can scroll the sioux window.
2201 ** Note that the SIOUXIsAppWindow() routine we use here is not really
2202 ** part of the external interface of Sioux...
2204 frontwin = FrontWindow();
2205 if ( eventPtr->what == updateEvt || SIOUXIsAppWindow(frontwin) ) {
2206 if (SIOUXHandleOneEvent(eventPtr))
2207 return 0; /* Nothing happened to the Tcl event queue */
2209 return TkMacConvertEvent(eventPtr);
2212 #if GENERATINGCFM
2215 ** Additional Mac specific code for dealing with shared libraries.
2218 #include <Resources.h>
2219 #include <CodeFragments.h>
2221 static int loaded_from_shlib = 0;
2222 static FSSpec library_fss;
2225 ** If this module is dynamically loaded the following routine should
2226 ** be the init routine. It takes care of adding the shared library to
2227 ** the resource-file chain, so that the tk routines can find their
2228 ** resources.
2230 OSErr pascal
2231 init_tkinter_shlib(CFragInitBlockPtr data)
2233 __initialize();
2234 if ( data == nil ) return noErr;
2235 if ( data->fragLocator.where == kDataForkCFragLocator ) {
2236 library_fss = *data->fragLocator.u.onDisk.fileSpec;
2237 loaded_from_shlib = 1;
2238 } else if ( data->fragLocator.where == kResourceCFragLocator ) {
2239 library_fss = *data->fragLocator.u.inSegs.fileSpec;
2240 loaded_from_shlib = 1;
2242 return noErr;
2246 ** Insert the library resources into the search path. Put them after
2247 ** the resources from the application. Again, we ignore errors.
2249 static
2250 mac_addlibresources(void)
2252 if ( !loaded_from_shlib )
2253 return;
2254 (void)FSpOpenResFile(&library_fss, fsRdPerm);
2257 #endif /* GENERATINGCFM */
2258 #endif /* macintosh */