struct.pack has become picky about h (short) and H (unsigned short).
[python/dscho.git] / Modules / _tkinter.c
blob528b04871983ff76adcbc8404d8bafadec285ac6
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__))
61 #define HAVE_CREATEFILEHANDLER
62 #endif
64 #ifdef HAVE_CREATEFILEHANDLER
66 /* Tcl_CreateFileHandler() changed several times; these macros deal with the
67 messiness. In Tcl 8.0 and later, it is not available on Windows (and on
68 Unix, only because Jack added it back); when available on Windows, it only
69 applies to sockets. */
71 #ifdef MS_WINDOWS
72 #define FHANDLETYPE TCL_WIN_SOCKET
73 #else
74 #define FHANDLETYPE TCL_UNIX_FD
75 #endif
77 /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine
78 which uses this to handle Tcl events while the user is typing commands. */
80 #if FHANDLETYPE == TCL_UNIX_FD
81 #define WAIT_FOR_STDIN
82 #endif
84 #endif /* HAVE_CREATEFILEHANDLER */
86 #ifdef MS_WINDOWS
87 #include <conio.h>
88 #define WAIT_FOR_STDIN
89 #endif
91 #ifdef WITH_THREAD
93 /* The threading situation is complicated. Tcl is not thread-safe, except for
94 Tcl 8.1, which will probably remain in alpha status for another 6 months
95 (and the README says that Tk will probably remain thread-unsafe forever).
96 So we need to use a lock around all uses of Tcl. Previously, the Python
97 interpreter lock was used for this. However, this causes problems when
98 other Python threads need to run while Tcl is blocked waiting for events.
100 To solve this problem, a separate lock for Tcl is introduced. Holding it
101 is incompatible with holding Python's interpreter lock. The following four
102 macros manipulate both locks together.
104 ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and
105 Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made
106 that could call an event handler, or otherwise affect the state of a Tcl
107 interpreter. These assume that the surrounding code has the Python
108 interpreter lock; inside the brackets, the Python interpreter lock has been
109 released and the lock for Tcl has been acquired.
111 Sometimes, it is necessary to have both the Python lock and the Tcl lock.
112 (For example, when transferring data from the Tcl interpreter result to a
113 Python string object.) This can be done by using different macros to close
114 the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores
115 the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL
116 releases the Tcl lock.
118 By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event
119 handlers when the handler needs to use Python. Such event handlers are
120 entered while the lock for Tcl is held; the event handler presumably needs
121 to use Python. ENTER_PYTHON releases the lock for Tcl and acquires
122 the Python interpreter lock, restoring the appropriate thread state, and
123 LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock
124 for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside
125 the code between ENTER_PYTHON and LEAVE_PYTHON.
127 These locks expand to several statements and brackets; they should not be
128 used in branches of if statements and the like.
132 static PyThread_type_lock tcl_lock = 0;
133 static PyThreadState *tcl_tstate = NULL;
135 #define ENTER_TCL \
136 { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
137 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
139 #define LEAVE_TCL \
140 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
142 #define ENTER_OVERLAP \
143 Py_END_ALLOW_THREADS
145 #define LEAVE_OVERLAP_TCL \
146 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); }
148 #define ENTER_PYTHON \
149 { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
150 PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
152 #define LEAVE_PYTHON \
153 { PyThreadState *tstate = PyEval_SaveThread(); \
154 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
156 #else
158 #define ENTER_TCL
159 #define LEAVE_TCL
160 #define ENTER_OVERLAP
161 #define LEAVE_OVERLAP_TCL
162 #define ENTER_PYTHON
163 #define LEAVE_PYTHON
165 #endif
167 #ifdef macintosh
170 ** Additional cruft needed by Tcl/Tk on the Mac.
171 ** This is for Tcl 7.5 and Tk 4.1 (patch release 1).
174 /* ckfree() expects a char* */
175 #define FREECAST (char *)
177 #include <Events.h> /* For EventRecord */
179 typedef int (*TclMacConvertEventPtr) (EventRecord *eventPtr);
180 void Tcl_MacSetEventProc(TclMacConvertEventPtr procPtr);
181 int TkMacConvertEvent(EventRecord *eventPtr);
183 staticforward int PyMacConvertEvent(EventRecord *eventPtr);
185 #if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
186 #pragma import on
187 #endif
189 #include <SIOUX.h>
190 extern int SIOUXIsAppWindow(WindowPtr);
192 #if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
193 #pragma import reset
194 #endif
195 #endif /* macintosh */
197 #ifndef FREECAST
198 #define FREECAST (char *)
199 #endif
201 /**** Tkapp Object Declaration ****/
203 staticforward PyTypeObject Tkapp_Type;
205 typedef struct {
206 PyObject_HEAD
207 Tcl_Interp *interp;
208 } TkappObject;
210 #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
211 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
212 #define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v))
214 #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \
215 (void *) v, ((PyObject *) v)->ob_refcnt))
219 /**** Error Handling ****/
221 static PyObject *Tkinter_TclError;
222 static int quitMainLoop = 0;
223 static int errorInCmd = 0;
224 static PyObject *excInCmd;
225 static PyObject *valInCmd;
226 static PyObject *trbInCmd;
230 static PyObject *
231 Tkinter_Error(PyObject *v)
233 PyErr_SetString(Tkinter_TclError, Tkapp_Result(v));
234 return NULL;
239 /**** Utils ****/
241 #ifdef WITH_THREAD
242 #ifndef MS_WINDOWS
244 /* Millisecond sleep() for Unix platforms. */
246 static void
247 Sleep(int milli)
249 /* XXX Too bad if you don't have select(). */
250 struct timeval t;
251 t.tv_sec = milli/1000;
252 t.tv_usec = (milli%1000) * 1000;
253 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
255 #endif /* MS_WINDOWS */
256 #endif /* WITH_THREAD */
259 static char *
260 AsString(PyObject *value, PyObject *tmp)
262 if (PyString_Check(value))
263 return PyString_AsString(value);
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 else {
276 PyObject *v = PyObject_Str(value);
277 if (v == NULL)
278 return NULL;
279 if (PyList_Append(tmp, v) != 0) {
280 Py_DECREF(v);
281 return NULL;
283 Py_DECREF(v);
284 return PyString_AsString(v);
290 #define ARGSZ 64
292 static char *
293 Merge(PyObject *args)
295 PyObject *tmp = NULL;
296 char *argvStore[ARGSZ];
297 char **argv = NULL;
298 int fvStore[ARGSZ];
299 int *fv = NULL;
300 int argc = 0, fvc = 0, i;
301 char *res = NULL;
303 if (!(tmp = PyList_New(0)))
304 return NULL;
306 argv = argvStore;
307 fv = fvStore;
309 if (args == NULL)
310 argc = 0;
312 else if (!PyTuple_Check(args)) {
313 argc = 1;
314 fv[0] = 0;
315 if (!(argv[0] = AsString(args, tmp)))
316 goto finally;
318 else {
319 argc = PyTuple_Size(args);
321 if (argc > ARGSZ) {
322 argv = (char **)ckalloc(argc * sizeof(char *));
323 fv = (int *)ckalloc(argc * sizeof(int));
324 if (argv == NULL || fv == NULL) {
325 PyErr_NoMemory();
326 goto finally;
330 for (i = 0; i < argc; i++) {
331 PyObject *v = PyTuple_GetItem(args, i);
332 if (PyTuple_Check(v)) {
333 fv[i] = 1;
334 if (!(argv[i] = Merge(v)))
335 goto finally;
336 fvc++;
338 else if (v == Py_None) {
339 argc = i;
340 break;
342 else {
343 fv[i] = 0;
344 if (!(argv[i] = AsString(v, tmp)))
345 goto finally;
346 fvc++;
350 res = Tcl_Merge(argc, argv);
351 if (res == NULL)
352 PyErr_SetString(Tkinter_TclError, "merge failed");
354 finally:
355 for (i = 0; i < fvc; i++)
356 if (fv[i]) {
357 ckfree(argv[i]);
359 if (argv != argvStore)
360 ckfree(FREECAST argv);
361 if (fv != fvStore)
362 ckfree(FREECAST fv);
364 Py_DECREF(tmp);
365 return res;
370 static PyObject *
371 Split(char *list)
373 int argc;
374 char **argv;
375 PyObject *v;
377 if (list == NULL) {
378 Py_INCREF(Py_None);
379 return Py_None;
382 if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
383 /* Not a list.
384 * Could be a quoted string containing funnies, e.g. {"}.
385 * Return the string itself.
387 return PyString_FromString(list);
390 if (argc == 0)
391 v = PyString_FromString("");
392 else if (argc == 1)
393 v = PyString_FromString(argv[0]);
394 else if ((v = PyTuple_New(argc)) != NULL) {
395 int i;
396 PyObject *w;
398 for (i = 0; i < argc; i++) {
399 if ((w = Split(argv[i])) == NULL) {
400 Py_DECREF(v);
401 v = NULL;
402 break;
404 PyTuple_SetItem(v, i, w);
407 Tcl_Free(FREECAST argv);
408 return v;
413 /**** Tkapp Object ****/
415 #ifndef WITH_APPINIT
417 Tcl_AppInit(Tcl_Interp *interp)
419 Tk_Window main;
421 main = Tk_MainWindow(interp);
422 if (Tcl_Init(interp) == TCL_ERROR) {
423 PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp));
424 return TCL_ERROR;
426 if (Tk_Init(interp) == TCL_ERROR) {
427 PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
428 return TCL_ERROR;
430 return TCL_OK;
432 #endif /* !WITH_APPINIT */
437 /* Initialize the Tk application; see the `main' function in
438 * `tkMain.c'.
441 static void EnableEventHook(void); /* Forward */
442 static void DisableEventHook(void); /* Forward */
444 static TkappObject *
445 Tkapp_New(char *screenName, char *baseName, char *className, int interactive)
447 TkappObject *v;
448 char *argv0;
450 v = PyObject_New(TkappObject, &Tkapp_Type);
451 if (v == NULL)
452 return NULL;
454 v->interp = Tcl_CreateInterp();
456 #if defined(macintosh)
457 /* This seems to be needed */
458 ClearMenuBar();
459 TkMacInitMenus(v->interp);
460 #endif
461 /* Delete the 'exit' command, which can screw things up */
462 Tcl_DeleteCommand(v->interp, "exit");
464 if (screenName != NULL)
465 Tcl_SetVar2(v->interp, "env", "DISPLAY",
466 screenName, TCL_GLOBAL_ONLY);
468 if (interactive)
469 Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
470 else
471 Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
473 /* This is used to get the application class for Tk 4.1 and up */
474 argv0 = (char*)ckalloc(strlen(className) + 1);
475 if (!argv0) {
476 PyErr_NoMemory();
477 Py_DECREF(v);
478 return NULL;
481 strcpy(argv0, className);
482 if (isupper((int)(argv0[0])))
483 argv0[0] = tolower(argv0[0]);
484 Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY);
485 ckfree(argv0);
487 if (Tcl_AppInit(v->interp) != TCL_OK)
488 return (TkappObject *)Tkinter_Error((PyObject *)v);
490 EnableEventHook();
492 return v;
497 /** Tcl Eval **/
499 #if TKMAJORMINOR >= 8001
500 #define USING_OBJECTS
501 #endif
503 #ifdef USING_OBJECTS
505 static Tcl_Obj*
506 AsObj(PyObject *value)
508 Tcl_Obj *result;
510 if (PyString_Check(value))
511 return Tcl_NewStringObj(PyString_AS_STRING(value),
512 PyString_GET_SIZE(value));
513 else if (PyInt_Check(value))
514 return Tcl_NewLongObj(PyInt_AS_LONG(value));
515 else if (PyFloat_Check(value))
516 return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
517 else if (PyTuple_Check(value)) {
518 Tcl_Obj **argv = (Tcl_Obj**)
519 ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*));
520 int i;
521 if(!argv)
522 return 0;
523 for(i=0;i<PyTuple_Size(value);i++)
524 argv[i] = AsObj(PyTuple_GetItem(value,i));
525 result = Tcl_NewListObj(PyTuple_Size(value), argv);
526 ckfree(FREECAST argv);
527 return result;
529 else if (PyUnicode_Check(value)) {
530 #if TKMAJORMINOR <= 8001
531 /* In Tcl 8.1 we must use UTF-8 */
532 PyObject* utf8 = PyUnicode_AsUTF8String(value);
533 if (!utf8)
534 return 0;
535 result = Tcl_NewStringObj(PyString_AS_STRING(utf8),
536 PyString_GET_SIZE(utf8));
537 Py_DECREF(utf8);
538 return result;
539 #else /* TKMAJORMINOR > 8001 */
540 /* In Tcl 8.2 and later, use Tcl_NewUnicodeObj() */
541 if (sizeof(Py_UNICODE) != sizeof(Tcl_UniChar)) {
542 /* XXX Should really test this at compile time */
543 PyErr_SetString(PyExc_SystemError,
544 "Py_UNICODE and Tcl_UniChar differ in size");
545 return 0;
547 return Tcl_NewUnicodeObj(PyUnicode_AS_UNICODE(value),
548 PyUnicode_GET_SIZE(value));
549 #endif /* TKMAJORMINOR > 8001 */
551 else {
552 PyObject *v = PyObject_Str(value);
553 if (!v)
554 return 0;
555 result = AsObj(v);
556 Py_DECREF(v);
557 return result;
561 static PyObject *
562 Tkapp_Call(PyObject *self, PyObject *args)
564 Tcl_Obj *objStore[ARGSZ];
565 Tcl_Obj **objv = NULL;
566 int objc = 0, i;
567 PyObject *res = NULL;
568 Tcl_Interp *interp = Tkapp_Interp(self);
569 /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */
570 int flags = TCL_EVAL_DIRECT;
572 objv = objStore;
574 if (args == NULL)
575 objc = 0;
577 else if (!PyTuple_Check(args)) {
578 objc = 1;
579 objv[0] = AsObj(args);
580 if (objv[0] == 0)
581 goto finally;
582 Tcl_IncrRefCount(objv[0]);
584 else {
585 objc = PyTuple_Size(args);
587 if (objc > ARGSZ) {
588 objv = (Tcl_Obj **)ckalloc(objc * sizeof(char *));
589 if (objv == NULL) {
590 PyErr_NoMemory();
591 goto finally;
595 for (i = 0; i < objc; i++) {
596 PyObject *v = PyTuple_GetItem(args, i);
597 if (v == Py_None) {
598 objc = i;
599 break;
601 objv[i] = AsObj(v);
602 if (!objv[i])
603 goto finally;
604 Tcl_IncrRefCount(objv[i]);
608 ENTER_TCL
610 i = Tcl_EvalObjv(interp, objc, objv, flags);
612 ENTER_OVERLAP
613 if (i == TCL_ERROR)
614 Tkinter_Error(self);
615 else {
616 /* We could request the object result here, but doing
617 so would confuse applications that expect a string. */
618 char *s = Tcl_GetStringResult(interp);
619 char *p = s;
620 /* If the result contains any bytes with the top bit set,
621 it's UTF-8 and we should decode it to Unicode */
622 while (*p != '\0') {
623 if (*p & 0x80)
624 break;
625 p++;
627 if (*p == '\0')
628 res = PyString_FromStringAndSize(s, (int)(p-s));
629 else {
630 /* Convert UTF-8 to Unicode string */
631 p = strchr(p, '\0');
632 res = PyUnicode_DecodeUTF8(s, (int)(p-s), "strict");
633 if (res == NULL) {
634 PyErr_Clear();
635 res = PyString_FromStringAndSize(s, (int)(p-s));
640 LEAVE_OVERLAP_TCL
642 finally:
643 for (i = 0; i < objc; i++)
644 Tcl_DecrRefCount(objv[i]);
645 if (objv != objStore)
646 ckfree(FREECAST objv);
647 return res;
650 #else /* !USING_OBJECTS */
652 static PyObject *
653 Tkapp_Call(PyObject *self, PyObject *args)
655 /* This is copied from Merge() */
656 PyObject *tmp = NULL;
657 char *argvStore[ARGSZ];
658 char **argv = NULL;
659 int fvStore[ARGSZ];
660 int *fv = NULL;
661 int argc = 0, fvc = 0, i;
662 PyObject *res = NULL; /* except this has a different type */
663 Tcl_CmdInfo info; /* and this is added */
664 Tcl_Interp *interp = Tkapp_Interp(self); /* and this too */
666 if (!(tmp = PyList_New(0)))
667 return NULL;
669 argv = argvStore;
670 fv = fvStore;
672 if (args == NULL)
673 argc = 0;
675 else if (!PyTuple_Check(args)) {
676 argc = 1;
677 fv[0] = 0;
678 if (!(argv[0] = AsString(args, tmp)))
679 goto finally;
681 else {
682 argc = PyTuple_Size(args);
684 if (argc > ARGSZ) {
685 argv = (char **)ckalloc(argc * sizeof(char *));
686 fv = (int *)ckalloc(argc * sizeof(int));
687 if (argv == NULL || fv == NULL) {
688 PyErr_NoMemory();
689 goto finally;
693 for (i = 0; i < argc; i++) {
694 PyObject *v = PyTuple_GetItem(args, i);
695 if (PyTuple_Check(v)) {
696 fv[i] = 1;
697 if (!(argv[i] = Merge(v)))
698 goto finally;
699 fvc++;
701 else if (v == Py_None) {
702 argc = i;
703 break;
705 else {
706 fv[i] = 0;
707 if (!(argv[i] = AsString(v, tmp)))
708 goto finally;
709 fvc++;
713 /* End code copied from Merge() */
715 /* All this to avoid a call to Tcl_Merge() and the corresponding call
716 to Tcl_SplitList() inside Tcl_Eval()... It can save a bundle! */
717 if (Py_VerboseFlag >= 2) {
718 for (i = 0; i < argc; i++)
719 PySys_WriteStderr("%s ", argv[i]);
721 ENTER_TCL
722 info.proc = NULL;
723 if (argc < 1 ||
724 !Tcl_GetCommandInfo(interp, argv[0], &info) ||
725 info.proc == NULL)
727 char *cmd;
728 cmd = Tcl_Merge(argc, argv);
729 i = Tcl_Eval(interp, cmd);
730 ckfree(cmd);
732 else {
733 Tcl_ResetResult(interp);
734 i = (*info.proc)(info.clientData, interp, argc, argv);
736 ENTER_OVERLAP
737 if (info.proc == NULL && Py_VerboseFlag >= 2)
738 PySys_WriteStderr("... use TclEval ");
739 if (i == TCL_ERROR) {
740 if (Py_VerboseFlag >= 2)
741 PySys_WriteStderr("... error: '%s'\n",
742 Tcl_GetStringResult(interp));
743 Tkinter_Error(self);
745 else {
746 if (Py_VerboseFlag >= 2)
747 PySys_WriteStderr("-> '%s'\n", Tcl_GetStringResult(interp));
748 res = PyString_FromString(Tcl_GetStringResult(interp));
750 LEAVE_OVERLAP_TCL
752 /* Copied from Merge() again */
753 finally:
754 for (i = 0; i < fvc; i++)
755 if (fv[i]) {
756 ckfree(argv[i]);
758 if (argv != argvStore)
759 ckfree(FREECAST argv);
760 if (fv != fvStore)
761 ckfree(FREECAST fv);
763 Py_DECREF(tmp);
764 return res;
767 #endif /* !USING_OBJECTS */
769 static PyObject *
770 Tkapp_GlobalCall(PyObject *self, PyObject *args)
772 /* Could do the same here as for Tkapp_Call(), but this is not used
773 much, so I can't be bothered. Unfortunately Tcl doesn't export a
774 way for the user to do what all its Global* variants do (save and
775 reset the scope pointer, call the local version, restore the saved
776 scope pointer). */
778 char *cmd;
779 PyObject *res = NULL;
781 cmd = Merge(args);
782 if (cmd) {
783 int err;
784 ENTER_TCL
785 err = Tcl_GlobalEval(Tkapp_Interp(self), cmd);
786 ENTER_OVERLAP
787 if (err == TCL_ERROR)
788 res = Tkinter_Error(self);
789 else
790 res = PyString_FromString(Tkapp_Result(self));
791 LEAVE_OVERLAP_TCL
792 ckfree(cmd);
795 return res;
798 static PyObject *
799 Tkapp_Eval(PyObject *self, PyObject *args)
801 char *script;
802 PyObject *res = NULL;
803 int err;
805 if (!PyArg_ParseTuple(args, "s:eval", &script))
806 return NULL;
808 ENTER_TCL
809 err = Tcl_Eval(Tkapp_Interp(self), script);
810 ENTER_OVERLAP
811 if (err == TCL_ERROR)
812 res = Tkinter_Error(self);
813 else
814 res = PyString_FromString(Tkapp_Result(self));
815 LEAVE_OVERLAP_TCL
816 return res;
819 static PyObject *
820 Tkapp_GlobalEval(PyObject *self, PyObject *args)
822 char *script;
823 PyObject *res = NULL;
824 int err;
826 if (!PyArg_ParseTuple(args, "s:globaleval", &script))
827 return NULL;
829 ENTER_TCL
830 err = Tcl_GlobalEval(Tkapp_Interp(self), script);
831 ENTER_OVERLAP
832 if (err == TCL_ERROR)
833 res = Tkinter_Error(self);
834 else
835 res = PyString_FromString(Tkapp_Result(self));
836 LEAVE_OVERLAP_TCL
837 return res;
840 static PyObject *
841 Tkapp_EvalFile(PyObject *self, PyObject *args)
843 char *fileName;
844 PyObject *res = NULL;
845 int err;
847 if (!PyArg_ParseTuple(args, "s:evalfile", &fileName))
848 return NULL;
850 ENTER_TCL
851 err = Tcl_EvalFile(Tkapp_Interp(self), fileName);
852 ENTER_OVERLAP
853 if (err == TCL_ERROR)
854 res = Tkinter_Error(self);
856 else
857 res = PyString_FromString(Tkapp_Result(self));
858 LEAVE_OVERLAP_TCL
859 return res;
862 static PyObject *
863 Tkapp_Record(PyObject *self, PyObject *args)
865 char *script;
866 PyObject *res = NULL;
867 int err;
869 if (!PyArg_ParseTuple(args, "s", &script))
870 return NULL;
872 ENTER_TCL
873 err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL);
874 ENTER_OVERLAP
875 if (err == TCL_ERROR)
876 res = Tkinter_Error(self);
877 else
878 res = PyString_FromString(Tkapp_Result(self));
879 LEAVE_OVERLAP_TCL
880 return res;
883 static PyObject *
884 Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
886 char *msg;
888 if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg))
889 return NULL;
890 ENTER_TCL
891 Tcl_AddErrorInfo(Tkapp_Interp(self), msg);
892 LEAVE_TCL
894 Py_INCREF(Py_None);
895 return Py_None;
900 /** Tcl Variable **/
902 static PyObject *
903 SetVar(PyObject *self, PyObject *args, int flags)
905 char *name1, *name2, *ok, *s;
906 PyObject *newValue;
907 PyObject *tmp;
909 tmp = PyList_New(0);
910 if (!tmp)
911 return NULL;
913 if (PyArg_ParseTuple(args, "sO:setvar", &name1, &newValue)) {
914 /* XXX Merge? */
915 s = AsString(newValue, tmp);
916 if (s == NULL)
917 return NULL;
918 ENTER_TCL
919 ok = Tcl_SetVar(Tkapp_Interp(self), name1, s, flags);
920 LEAVE_TCL
922 else {
923 PyErr_Clear();
924 if (PyArg_ParseTuple(args, "ssO:setvar",
925 &name1, &name2, &newValue)) {
926 s = AsString(newValue, tmp);
927 if (s == NULL)
928 return NULL;
929 ENTER_TCL
930 ok = Tcl_SetVar2(Tkapp_Interp(self), name1, name2,
931 s, flags);
932 LEAVE_TCL
934 else {
935 Py_DECREF(tmp);
936 return NULL;
939 Py_DECREF(tmp);
941 if (!ok)
942 return Tkinter_Error(self);
944 Py_INCREF(Py_None);
945 return Py_None;
948 static PyObject *
949 Tkapp_SetVar(PyObject *self, PyObject *args)
951 return SetVar(self, args, TCL_LEAVE_ERR_MSG);
954 static PyObject *
955 Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
957 return SetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
962 static PyObject *
963 GetVar(PyObject *self, PyObject *args, int flags)
965 char *name1, *name2=NULL, *s;
966 PyObject *res = NULL;
968 if (!PyArg_ParseTuple(args, "s|s:getvar", &name1, &name2))
969 return NULL;
970 ENTER_TCL
971 if (name2 == NULL)
972 s = Tcl_GetVar(Tkapp_Interp(self), name1, flags);
974 else
975 s = Tcl_GetVar2(Tkapp_Interp(self), name1, name2, flags);
976 ENTER_OVERLAP
978 if (s == NULL)
979 res = Tkinter_Error(self);
980 else
981 res = PyString_FromString(s);
982 LEAVE_OVERLAP_TCL
983 return res;
986 static PyObject *
987 Tkapp_GetVar(PyObject *self, PyObject *args)
989 return GetVar(self, args, TCL_LEAVE_ERR_MSG);
992 static PyObject *
993 Tkapp_GlobalGetVar(PyObject *self, PyObject *args)
995 return GetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1000 static PyObject *
1001 UnsetVar(PyObject *self, PyObject *args, int flags)
1003 char *name1, *name2=NULL;
1004 PyObject *res = NULL;
1005 int code;
1007 if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
1008 return NULL;
1009 ENTER_TCL
1010 if (name2 == NULL)
1011 code = Tcl_UnsetVar(Tkapp_Interp(self), name1, flags);
1013 else
1014 code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
1015 ENTER_OVERLAP
1017 if (code == TCL_ERROR)
1018 res = Tkinter_Error(self);
1019 else {
1020 Py_INCREF(Py_None);
1021 res = Py_None;
1023 LEAVE_OVERLAP_TCL
1024 return res;
1027 static PyObject *
1028 Tkapp_UnsetVar(PyObject *self, PyObject *args)
1030 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG);
1033 static PyObject *
1034 Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args)
1036 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1041 /** Tcl to Python **/
1043 static PyObject *
1044 Tkapp_GetInt(PyObject *self, PyObject *args)
1046 char *s;
1047 int v;
1049 if (!PyArg_ParseTuple(args, "s:getint", &s))
1050 return NULL;
1051 if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1052 return Tkinter_Error(self);
1053 return Py_BuildValue("i", v);
1056 static PyObject *
1057 Tkapp_GetDouble(PyObject *self, PyObject *args)
1059 char *s;
1060 double v;
1062 if (!PyArg_ParseTuple(args, "s:getdouble", &s))
1063 return NULL;
1064 if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1065 return Tkinter_Error(self);
1066 return Py_BuildValue("d", v);
1069 static PyObject *
1070 Tkapp_GetBoolean(PyObject *self, PyObject *args)
1072 char *s;
1073 int v;
1075 if (!PyArg_ParseTuple(args, "s:getboolean", &s))
1076 return NULL;
1077 if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1078 return Tkinter_Error(self);
1079 return Py_BuildValue("i", v);
1082 static PyObject *
1083 Tkapp_ExprString(PyObject *self, PyObject *args)
1085 char *s;
1086 PyObject *res = NULL;
1087 int retval;
1089 if (!PyArg_ParseTuple(args, "s:exprstring", &s))
1090 return NULL;
1091 ENTER_TCL
1092 retval = Tcl_ExprString(Tkapp_Interp(self), s);
1093 ENTER_OVERLAP
1094 if (retval == TCL_ERROR)
1095 res = Tkinter_Error(self);
1096 else
1097 res = Py_BuildValue("s", Tkapp_Result(self));
1098 LEAVE_OVERLAP_TCL
1099 return res;
1102 static PyObject *
1103 Tkapp_ExprLong(PyObject *self, PyObject *args)
1105 char *s;
1106 PyObject *res = NULL;
1107 int retval;
1108 long v;
1110 if (!PyArg_ParseTuple(args, "s:exprlong", &s))
1111 return NULL;
1112 ENTER_TCL
1113 retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v);
1114 ENTER_OVERLAP
1115 if (retval == TCL_ERROR)
1116 res = Tkinter_Error(self);
1117 else
1118 res = Py_BuildValue("l", v);
1119 LEAVE_OVERLAP_TCL
1120 return res;
1123 static PyObject *
1124 Tkapp_ExprDouble(PyObject *self, PyObject *args)
1126 char *s;
1127 PyObject *res = NULL;
1128 double v;
1129 int retval;
1131 if (!PyArg_ParseTuple(args, "s:exprdouble", &s))
1132 return NULL;
1133 PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
1134 ENTER_TCL
1135 retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v);
1136 ENTER_OVERLAP
1137 PyFPE_END_PROTECT(retval)
1138 if (retval == TCL_ERROR)
1139 res = Tkinter_Error(self);
1140 else
1141 res = Py_BuildValue("d", v);
1142 LEAVE_OVERLAP_TCL
1143 return res;
1146 static PyObject *
1147 Tkapp_ExprBoolean(PyObject *self, PyObject *args)
1149 char *s;
1150 PyObject *res = NULL;
1151 int retval;
1152 int v;
1154 if (!PyArg_ParseTuple(args, "s:exprboolean", &s))
1155 return NULL;
1156 ENTER_TCL
1157 retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
1158 ENTER_OVERLAP
1159 if (retval == TCL_ERROR)
1160 res = Tkinter_Error(self);
1161 else
1162 res = Py_BuildValue("i", v);
1163 LEAVE_OVERLAP_TCL
1164 return res;
1169 static PyObject *
1170 Tkapp_SplitList(PyObject *self, PyObject *args)
1172 char *list;
1173 int argc;
1174 char **argv;
1175 PyObject *v;
1176 int i;
1178 if (!PyArg_ParseTuple(args, "s:splitlist", &list))
1179 return NULL;
1181 if (Tcl_SplitList(Tkapp_Interp(self), list, &argc, &argv) == TCL_ERROR)
1182 return Tkinter_Error(self);
1184 if (!(v = PyTuple_New(argc)))
1185 return NULL;
1187 for (i = 0; i < argc; i++) {
1188 PyObject *s = PyString_FromString(argv[i]);
1189 if (!s || PyTuple_SetItem(v, i, s)) {
1190 Py_DECREF(v);
1191 v = NULL;
1192 goto finally;
1196 finally:
1197 ckfree(FREECAST argv);
1198 return v;
1201 static PyObject *
1202 Tkapp_Split(PyObject *self, PyObject *args)
1204 char *list;
1206 if (!PyArg_ParseTuple(args, "s:split", &list))
1207 return NULL;
1208 return Split(list);
1211 static PyObject *
1212 Tkapp_Merge(PyObject *self, PyObject *args)
1214 char *s = Merge(args);
1215 PyObject *res = NULL;
1217 if (s) {
1218 res = PyString_FromString(s);
1219 ckfree(s);
1222 return res;
1227 /** Tcl Command **/
1229 /* Client data struct */
1230 typedef struct {
1231 PyObject *self;
1232 PyObject *func;
1233 } PythonCmd_ClientData;
1235 static int
1236 PythonCmd_Error(Tcl_Interp *interp)
1238 errorInCmd = 1;
1239 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1240 LEAVE_PYTHON
1241 return TCL_ERROR;
1244 /* This is the Tcl command that acts as a wrapper for Python
1245 * function or method.
1247 static int
1248 PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1250 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1251 PyObject *self, *func, *arg, *res, *tmp;
1252 int i, rv;
1253 char *s;
1255 ENTER_PYTHON
1257 /* TBD: no error checking here since we know, via the
1258 * Tkapp_CreateCommand() that the client data is a two-tuple
1260 self = data->self;
1261 func = data->func;
1263 /* Create argument list (argv1, ..., argvN) */
1264 if (!(arg = PyTuple_New(argc - 1)))
1265 return PythonCmd_Error(interp);
1267 for (i = 0; i < (argc - 1); i++) {
1268 PyObject *s = PyString_FromString(argv[i + 1]);
1269 if (!s || PyTuple_SetItem(arg, i, s)) {
1270 Py_DECREF(arg);
1271 return PythonCmd_Error(interp);
1274 res = PyEval_CallObject(func, arg);
1275 Py_DECREF(arg);
1277 if (res == NULL)
1278 return PythonCmd_Error(interp);
1280 if (!(tmp = PyList_New(0))) {
1281 Py_DECREF(res);
1282 return PythonCmd_Error(interp);
1285 s = AsString(res, tmp);
1286 if (s == NULL) {
1287 rv = PythonCmd_Error(interp);
1289 else {
1290 Tcl_SetResult(Tkapp_Interp(self), s, TCL_VOLATILE);
1291 rv = TCL_OK;
1294 Py_DECREF(res);
1295 Py_DECREF(tmp);
1297 LEAVE_PYTHON
1299 return rv;
1302 static void
1303 PythonCmdDelete(ClientData clientData)
1305 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1307 ENTER_PYTHON
1308 Py_XDECREF(data->self);
1309 Py_XDECREF(data->func);
1310 PyMem_DEL(data);
1311 LEAVE_PYTHON
1316 static PyObject *
1317 Tkapp_CreateCommand(PyObject *self, PyObject *args)
1319 PythonCmd_ClientData *data;
1320 char *cmdName;
1321 PyObject *func;
1322 Tcl_Command err;
1324 if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func))
1325 return NULL;
1326 if (!PyCallable_Check(func)) {
1327 PyErr_SetString(PyExc_TypeError, "command not callable");
1328 return NULL;
1331 data = PyMem_NEW(PythonCmd_ClientData, 1);
1332 if (!data)
1333 return NULL;
1334 Py_XINCREF(self);
1335 Py_XINCREF(func);
1336 data->self = self;
1337 data->func = func;
1339 ENTER_TCL
1340 err = Tcl_CreateCommand(Tkapp_Interp(self), cmdName, PythonCmd,
1341 (ClientData)data, PythonCmdDelete);
1342 LEAVE_TCL
1343 if (err == NULL) {
1344 PyErr_SetString(Tkinter_TclError, "can't create Tcl command");
1345 PyMem_DEL(data);
1346 return NULL;
1349 Py_INCREF(Py_None);
1350 return Py_None;
1355 static PyObject *
1356 Tkapp_DeleteCommand(PyObject *self, PyObject *args)
1358 char *cmdName;
1359 int err;
1361 if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName))
1362 return NULL;
1363 ENTER_TCL
1364 err = Tcl_DeleteCommand(Tkapp_Interp(self), cmdName);
1365 LEAVE_TCL
1366 if (err == -1) {
1367 PyErr_SetString(Tkinter_TclError, "can't delete Tcl command");
1368 return NULL;
1370 Py_INCREF(Py_None);
1371 return Py_None;
1376 #ifdef HAVE_CREATEFILEHANDLER
1377 /** File Handler **/
1379 typedef struct _fhcdata {
1380 PyObject *func;
1381 PyObject *file;
1382 int id;
1383 struct _fhcdata *next;
1384 } FileHandler_ClientData;
1386 static FileHandler_ClientData *HeadFHCD;
1388 static FileHandler_ClientData *
1389 NewFHCD(PyObject *func, PyObject *file, int id)
1391 FileHandler_ClientData *p;
1392 p = PyMem_NEW(FileHandler_ClientData, 1);
1393 if (p != NULL) {
1394 Py_XINCREF(func);
1395 Py_XINCREF(file);
1396 p->func = func;
1397 p->file = file;
1398 p->id = id;
1399 p->next = HeadFHCD;
1400 HeadFHCD = p;
1402 return p;
1405 static void
1406 DeleteFHCD(int id)
1408 FileHandler_ClientData *p, **pp;
1410 pp = &HeadFHCD;
1411 while ((p = *pp) != NULL) {
1412 if (p->id == id) {
1413 *pp = p->next;
1414 Py_XDECREF(p->func);
1415 Py_XDECREF(p->file);
1416 PyMem_DEL(p);
1418 else
1419 pp = &p->next;
1423 static void
1424 FileHandler(ClientData clientData, int mask)
1426 FileHandler_ClientData *data = (FileHandler_ClientData *)clientData;
1427 PyObject *func, *file, *arg, *res;
1429 ENTER_PYTHON
1430 func = data->func;
1431 file = data->file;
1433 arg = Py_BuildValue("(Oi)", file, (long) mask);
1434 res = PyEval_CallObject(func, arg);
1435 Py_DECREF(arg);
1437 if (res == NULL) {
1438 errorInCmd = 1;
1439 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1441 Py_XDECREF(res);
1442 LEAVE_PYTHON
1445 static PyObject *
1446 Tkapp_CreateFileHandler(PyObject *self, PyObject *args)
1447 /* args is (file, mask, func) */
1449 FileHandler_ClientData *data;
1450 PyObject *file, *func;
1451 int mask, tfile;
1453 if (!PyArg_ParseTuple(args, "OiO:createfilehandler",
1454 &file, &mask, &func))
1455 return NULL;
1456 tfile = PyObject_AsFileDescriptor(file);
1457 if (tfile < 0)
1458 return NULL;
1459 if (!PyCallable_Check(func)) {
1460 PyErr_SetString(PyExc_TypeError, "bad argument list");
1461 return NULL;
1464 data = NewFHCD(func, file, tfile);
1465 if (data == NULL)
1466 return NULL;
1468 /* Ought to check for null Tcl_File object... */
1469 ENTER_TCL
1470 Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
1471 LEAVE_TCL
1472 Py_INCREF(Py_None);
1473 return Py_None;
1476 static PyObject *
1477 Tkapp_DeleteFileHandler(PyObject *self, PyObject *args)
1479 PyObject *file;
1480 int tfile;
1482 if (!PyArg_ParseTuple(args, "O:deletefilehandler", &file))
1483 return NULL;
1484 tfile = PyObject_AsFileDescriptor(file);
1485 if (tfile < 0)
1486 return NULL;
1488 DeleteFHCD(tfile);
1490 /* Ought to check for null Tcl_File object... */
1491 ENTER_TCL
1492 Tcl_DeleteFileHandler(tfile);
1493 LEAVE_TCL
1494 Py_INCREF(Py_None);
1495 return Py_None;
1497 #endif /* HAVE_CREATEFILEHANDLER */
1500 /**** Tktt Object (timer token) ****/
1502 staticforward PyTypeObject Tktt_Type;
1504 typedef struct {
1505 PyObject_HEAD
1506 Tcl_TimerToken token;
1507 PyObject *func;
1508 } TkttObject;
1510 static PyObject *
1511 Tktt_DeleteTimerHandler(PyObject *self, PyObject *args)
1513 TkttObject *v = (TkttObject *)self;
1514 PyObject *func = v->func;
1516 if (!PyArg_ParseTuple(args, ":deletetimerhandler"))
1517 return NULL;
1518 if (v->token != NULL) {
1519 Tcl_DeleteTimerHandler(v->token);
1520 v->token = NULL;
1522 if (func != NULL) {
1523 v->func = NULL;
1524 Py_DECREF(func);
1525 Py_DECREF(v); /* See Tktt_New() */
1527 Py_INCREF(Py_None);
1528 return Py_None;
1531 static PyMethodDef Tktt_methods[] =
1533 {"deletetimerhandler", Tktt_DeleteTimerHandler, 1},
1534 {NULL, NULL}
1537 static TkttObject *
1538 Tktt_New(PyObject *func)
1540 TkttObject *v;
1542 v = PyObject_New(TkttObject, &Tktt_Type);
1543 if (v == NULL)
1544 return NULL;
1546 Py_INCREF(func);
1547 v->token = NULL;
1548 v->func = func;
1550 /* Extra reference, deleted when called or when handler is deleted */
1551 Py_INCREF(v);
1552 return v;
1555 static void
1556 Tktt_Dealloc(PyObject *self)
1558 TkttObject *v = (TkttObject *)self;
1559 PyObject *func = v->func;
1561 Py_XDECREF(func);
1563 PyObject_Del(self);
1566 static PyObject *
1567 Tktt_Repr(PyObject *self)
1569 TkttObject *v = (TkttObject *)self;
1570 char buf[100];
1572 sprintf(buf, "<tktimertoken at %p%s>", v,
1573 v->func == NULL ? ", handler deleted" : "");
1574 return PyString_FromString(buf);
1577 static PyObject *
1578 Tktt_GetAttr(PyObject *self, char *name)
1580 return Py_FindMethod(Tktt_methods, self, name);
1583 static PyTypeObject Tktt_Type =
1585 PyObject_HEAD_INIT(NULL)
1586 0, /*ob_size */
1587 "tktimertoken", /*tp_name */
1588 sizeof(TkttObject), /*tp_basicsize */
1589 0, /*tp_itemsize */
1590 Tktt_Dealloc, /*tp_dealloc */
1591 0, /*tp_print */
1592 Tktt_GetAttr, /*tp_getattr */
1593 0, /*tp_setattr */
1594 0, /*tp_compare */
1595 Tktt_Repr, /*tp_repr */
1596 0, /*tp_as_number */
1597 0, /*tp_as_sequence */
1598 0, /*tp_as_mapping */
1599 0, /*tp_hash */
1604 /** Timer Handler **/
1606 static void
1607 TimerHandler(ClientData clientData)
1609 TkttObject *v = (TkttObject *)clientData;
1610 PyObject *func = v->func;
1611 PyObject *res;
1613 if (func == NULL)
1614 return;
1616 v->func = NULL;
1618 ENTER_PYTHON
1620 res = PyEval_CallObject(func, NULL);
1621 Py_DECREF(func);
1622 Py_DECREF(v); /* See Tktt_New() */
1624 if (res == NULL) {
1625 errorInCmd = 1;
1626 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1628 else
1629 Py_DECREF(res);
1631 LEAVE_PYTHON
1634 static PyObject *
1635 Tkapp_CreateTimerHandler(PyObject *self, PyObject *args)
1637 int milliseconds;
1638 PyObject *func;
1639 TkttObject *v;
1641 if (!PyArg_ParseTuple(args, "iO:createtimerhandler",
1642 &milliseconds, &func))
1643 return NULL;
1644 if (!PyCallable_Check(func)) {
1645 PyErr_SetString(PyExc_TypeError, "bad argument list");
1646 return NULL;
1648 v = Tktt_New(func);
1649 v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler,
1650 (ClientData)v);
1652 return (PyObject *) v;
1656 /** Event Loop **/
1658 static PyObject *
1659 Tkapp_MainLoop(PyObject *self, PyObject *args)
1661 int threshold = 0;
1662 #ifdef WITH_THREAD
1663 PyThreadState *tstate = PyThreadState_Get();
1664 #endif
1666 if (!PyArg_ParseTuple(args, "|i:mainloop", &threshold))
1667 return NULL;
1669 quitMainLoop = 0;
1670 while (Tk_GetNumMainWindows() > threshold &&
1671 !quitMainLoop &&
1672 !errorInCmd)
1674 int result;
1676 #ifdef WITH_THREAD
1677 Py_BEGIN_ALLOW_THREADS
1678 PyThread_acquire_lock(tcl_lock, 1);
1679 tcl_tstate = tstate;
1680 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
1681 tcl_tstate = NULL;
1682 PyThread_release_lock(tcl_lock);
1683 if (result == 0)
1684 Sleep(20);
1685 Py_END_ALLOW_THREADS
1686 #else
1687 result = Tcl_DoOneEvent(0);
1688 #endif
1690 if (PyErr_CheckSignals() != 0)
1691 return NULL;
1692 if (result < 0)
1693 break;
1695 quitMainLoop = 0;
1697 if (errorInCmd) {
1698 errorInCmd = 0;
1699 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
1700 excInCmd = valInCmd = trbInCmd = NULL;
1701 return NULL;
1703 Py_INCREF(Py_None);
1704 return Py_None;
1707 static PyObject *
1708 Tkapp_DoOneEvent(PyObject *self, PyObject *args)
1710 int flags = 0;
1711 int rv;
1713 if (!PyArg_ParseTuple(args, "|i:dooneevent", &flags))
1714 return NULL;
1716 ENTER_TCL
1717 rv = Tcl_DoOneEvent(flags);
1718 LEAVE_TCL
1719 return Py_BuildValue("i", rv);
1722 static PyObject *
1723 Tkapp_Quit(PyObject *self, PyObject *args)
1726 if (!PyArg_ParseTuple(args, ":quit"))
1727 return NULL;
1729 quitMainLoop = 1;
1730 Py_INCREF(Py_None);
1731 return Py_None;
1734 static PyObject *
1735 Tkapp_InterpAddr(PyObject *self, PyObject *args)
1738 if (!PyArg_ParseTuple(args, ":interpaddr"))
1739 return NULL;
1741 return PyInt_FromLong((long)Tkapp_Interp(self));
1746 /**** Tkapp Method List ****/
1748 static PyMethodDef Tkapp_methods[] =
1750 {"call", Tkapp_Call, 0},
1751 {"globalcall", Tkapp_GlobalCall, 0},
1752 {"eval", Tkapp_Eval, 1},
1753 {"globaleval", Tkapp_GlobalEval, 1},
1754 {"evalfile", Tkapp_EvalFile, 1},
1755 {"record", Tkapp_Record, 1},
1756 {"adderrorinfo", Tkapp_AddErrorInfo, 1},
1757 {"setvar", Tkapp_SetVar, 1},
1758 {"globalsetvar", Tkapp_GlobalSetVar, 1},
1759 {"getvar", Tkapp_GetVar, 1},
1760 {"globalgetvar", Tkapp_GlobalGetVar, 1},
1761 {"unsetvar", Tkapp_UnsetVar, 1},
1762 {"globalunsetvar", Tkapp_GlobalUnsetVar, 1},
1763 {"getint", Tkapp_GetInt, 1},
1764 {"getdouble", Tkapp_GetDouble, 1},
1765 {"getboolean", Tkapp_GetBoolean, 1},
1766 {"exprstring", Tkapp_ExprString, 1},
1767 {"exprlong", Tkapp_ExprLong, 1},
1768 {"exprdouble", Tkapp_ExprDouble, 1},
1769 {"exprboolean", Tkapp_ExprBoolean, 1},
1770 {"splitlist", Tkapp_SplitList, 1},
1771 {"split", Tkapp_Split, 1},
1772 {"merge", Tkapp_Merge, 0},
1773 {"createcommand", Tkapp_CreateCommand, 1},
1774 {"deletecommand", Tkapp_DeleteCommand, 1},
1775 #ifdef HAVE_CREATEFILEHANDLER
1776 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1777 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1778 #endif
1779 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1780 {"mainloop", Tkapp_MainLoop, 1},
1781 {"dooneevent", Tkapp_DoOneEvent, 1},
1782 {"quit", Tkapp_Quit, 1},
1783 {"interpaddr", Tkapp_InterpAddr, 1},
1784 {NULL, NULL}
1789 /**** Tkapp Type Methods ****/
1791 static void
1792 Tkapp_Dealloc(PyObject *self)
1794 ENTER_TCL
1795 Tcl_DeleteInterp(Tkapp_Interp(self));
1796 LEAVE_TCL
1797 PyObject_Del(self);
1798 DisableEventHook();
1801 static PyObject *
1802 Tkapp_GetAttr(PyObject *self, char *name)
1804 return Py_FindMethod(Tkapp_methods, self, name);
1807 static PyTypeObject Tkapp_Type =
1809 PyObject_HEAD_INIT(NULL)
1810 0, /*ob_size */
1811 "tkapp", /*tp_name */
1812 sizeof(TkappObject), /*tp_basicsize */
1813 0, /*tp_itemsize */
1814 Tkapp_Dealloc, /*tp_dealloc */
1815 0, /*tp_print */
1816 Tkapp_GetAttr, /*tp_getattr */
1817 0, /*tp_setattr */
1818 0, /*tp_compare */
1819 0, /*tp_repr */
1820 0, /*tp_as_number */
1821 0, /*tp_as_sequence */
1822 0, /*tp_as_mapping */
1823 0, /*tp_hash */
1828 /**** Tkinter Module ****/
1830 typedef struct {
1831 PyObject* tuple;
1832 int size; /* current size */
1833 int maxsize; /* allocated size */
1834 } FlattenContext;
1836 static int
1837 _bump(FlattenContext* context, int size)
1839 /* expand tuple to hold (at least) size new items.
1840 return true if successful, false if an exception was raised */
1842 int maxsize = context->maxsize * 2;
1844 if (maxsize < context->size + size)
1845 maxsize = context->size + size;
1847 context->maxsize = maxsize;
1849 return _PyTuple_Resize(&context->tuple, maxsize, 0) >= 0;
1852 static int
1853 _flatten1(FlattenContext* context, PyObject* item, int depth)
1855 /* add tuple or list to argument tuple (recursively) */
1857 int i, size;
1859 if (depth > 1000) {
1860 PyErr_SetString(PyExc_ValueError,
1861 "nesting too deep in _flatten");
1862 return 0;
1863 } else if (PyList_Check(item)) {
1864 size = PyList_GET_SIZE(item);
1865 /* preallocate (assume no nesting) */
1866 if (context->size + size > context->maxsize &&
1867 !_bump(context, size))
1868 return 0;
1869 /* copy items to output tuple */
1870 for (i = 0; i < size; i++) {
1871 PyObject *o = PyList_GET_ITEM(item, i);
1872 if (PyList_Check(o) || PyTuple_Check(o)) {
1873 if (!_flatten1(context, o, depth + 1))
1874 return 0;
1875 } else if (o != Py_None) {
1876 if (context->size + 1 > context->maxsize &&
1877 !_bump(context, 1))
1878 return 0;
1879 Py_INCREF(o);
1880 PyTuple_SET_ITEM(context->tuple,
1881 context->size++, o);
1884 } else if (PyTuple_Check(item)) {
1885 /* same, for tuples */
1886 size = PyTuple_GET_SIZE(item);
1887 if (context->size + size > context->maxsize &&
1888 !_bump(context, size))
1889 return 0;
1890 for (i = 0; i < size; i++) {
1891 PyObject *o = PyTuple_GET_ITEM(item, i);
1892 if (PyList_Check(o) || PyTuple_Check(o)) {
1893 if (!_flatten1(context, o, depth + 1))
1894 return 0;
1895 } else if (o != Py_None) {
1896 if (context->size + 1 > context->maxsize &&
1897 !_bump(context, 1))
1898 return 0;
1899 Py_INCREF(o);
1900 PyTuple_SET_ITEM(context->tuple,
1901 context->size++, o);
1904 } else {
1905 PyErr_SetString(PyExc_TypeError, "argument must be sequence");
1906 return 0;
1908 return 1;
1911 static PyObject *
1912 Tkinter_Flatten(PyObject* self, PyObject* args)
1914 FlattenContext context;
1915 PyObject* item;
1917 if (!PyArg_ParseTuple(args, "O:_flatten", &item))
1918 return NULL;
1920 context.maxsize = PySequence_Size(item);
1921 if (context.maxsize <= 0)
1922 return PyTuple_New(0);
1924 context.tuple = PyTuple_New(context.maxsize);
1925 if (!context.tuple)
1926 return NULL;
1928 context.size = 0;
1930 if (!_flatten1(&context, item,0))
1931 return NULL;
1933 if (_PyTuple_Resize(&context.tuple, context.size, 0))
1934 return NULL;
1936 return context.tuple;
1939 static PyObject *
1940 Tkinter_Create(PyObject *self, PyObject *args)
1942 char *screenName = NULL;
1943 char *baseName = NULL;
1944 char *className = NULL;
1945 int interactive = 0;
1947 baseName = strrchr(Py_GetProgramName(), '/');
1948 if (baseName != NULL)
1949 baseName++;
1950 else
1951 baseName = Py_GetProgramName();
1952 className = "Tk";
1954 if (!PyArg_ParseTuple(args, "|zssi:create",
1955 &screenName, &baseName, &className,
1956 &interactive))
1957 return NULL;
1959 return (PyObject *) Tkapp_New(screenName, baseName, className,
1960 interactive);
1963 static PyMethodDef moduleMethods[] =
1965 {"_flatten", Tkinter_Flatten, 1},
1966 {"create", Tkinter_Create, 1},
1967 #ifdef HAVE_CREATEFILEHANDLER
1968 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1969 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1970 #endif
1971 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1972 {"mainloop", Tkapp_MainLoop, 1},
1973 {"dooneevent", Tkapp_DoOneEvent, 1},
1974 {"quit", Tkapp_Quit, 1},
1975 {NULL, NULL}
1978 #ifdef WAIT_FOR_STDIN
1980 static int stdin_ready = 0;
1982 #ifndef MS_WINDOWS
1983 static void
1984 MyFileProc(void *clientData, int mask)
1986 stdin_ready = 1;
1988 #endif
1990 static PyThreadState *event_tstate = NULL;
1992 static int
1993 EventHook(void)
1995 #ifndef MS_WINDOWS
1996 int tfile;
1997 #endif
1998 #ifdef WITH_THREAD
1999 PyEval_RestoreThread(event_tstate);
2000 #endif
2001 stdin_ready = 0;
2002 errorInCmd = 0;
2003 #ifndef MS_WINDOWS
2004 tfile = fileno(stdin);
2005 Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
2006 #endif
2007 while (!errorInCmd && !stdin_ready) {
2008 int result;
2009 #ifdef MS_WINDOWS
2010 if (_kbhit()) {
2011 stdin_ready = 1;
2012 break;
2014 #endif
2015 #if defined(WITH_THREAD) || defined(MS_WINDOWS)
2016 Py_BEGIN_ALLOW_THREADS
2017 PyThread_acquire_lock(tcl_lock, 1);
2018 tcl_tstate = event_tstate;
2020 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
2022 tcl_tstate = NULL;
2023 PyThread_release_lock(tcl_lock);
2024 if (result == 0)
2025 Sleep(20);
2026 Py_END_ALLOW_THREADS
2027 #else
2028 result = Tcl_DoOneEvent(0);
2029 #endif
2031 if (result < 0)
2032 break;
2034 #ifndef MS_WINDOWS
2035 Tcl_DeleteFileHandler(tfile);
2036 #endif
2037 if (errorInCmd) {
2038 errorInCmd = 0;
2039 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
2040 excInCmd = valInCmd = trbInCmd = NULL;
2041 PyErr_Print();
2043 #ifdef WITH_THREAD
2044 PyEval_SaveThread();
2045 #endif
2046 return 0;
2049 #endif
2051 static void
2052 EnableEventHook(void)
2054 #ifdef WAIT_FOR_STDIN
2055 if (PyOS_InputHook == NULL) {
2056 #ifdef WITH_THREAD
2057 event_tstate = PyThreadState_Get();
2058 #endif
2059 PyOS_InputHook = EventHook;
2061 #endif
2064 static void
2065 DisableEventHook(void)
2067 #ifdef WAIT_FOR_STDIN
2068 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
2069 PyOS_InputHook = NULL;
2071 #endif
2075 /* all errors will be checked in one fell swoop in init_tkinter() */
2076 static void
2077 ins_long(PyObject *d, char *name, long val)
2079 PyObject *v = PyInt_FromLong(val);
2080 if (v) {
2081 PyDict_SetItemString(d, name, v);
2082 Py_DECREF(v);
2085 static void
2086 ins_string(PyObject *d, char *name, char *val)
2088 PyObject *v = PyString_FromString(val);
2089 if (v) {
2090 PyDict_SetItemString(d, name, v);
2091 Py_DECREF(v);
2096 DL_EXPORT(void)
2097 init_tkinter(void)
2099 PyObject *m, *d;
2101 Tkapp_Type.ob_type = &PyType_Type;
2103 #ifdef WITH_THREAD
2104 tcl_lock = PyThread_allocate_lock();
2105 #endif
2107 m = Py_InitModule("_tkinter", moduleMethods);
2109 d = PyModule_GetDict(m);
2110 Tkinter_TclError = Py_BuildValue("s", "TclError");
2111 PyDict_SetItemString(d, "TclError", Tkinter_TclError);
2113 ins_long(d, "READABLE", TCL_READABLE);
2114 ins_long(d, "WRITABLE", TCL_WRITABLE);
2115 ins_long(d, "EXCEPTION", TCL_EXCEPTION);
2116 ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS);
2117 ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS);
2118 ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS);
2119 ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS);
2120 ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS);
2121 ins_long(d, "DONT_WAIT", TCL_DONT_WAIT);
2122 ins_string(d, "TK_VERSION", TK_VERSION);
2123 ins_string(d, "TCL_VERSION", TCL_VERSION);
2125 PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type);
2127 Tktt_Type.ob_type = &PyType_Type;
2128 PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
2130 /* This helps the dynamic loader; in Unicode aware Tcl versions
2131 it also helps Tcl find its encodings. */
2132 Tcl_FindExecutable(Py_GetProgramName());
2134 if (PyErr_Occurred())
2135 return;
2137 #if 0
2138 /* This was not a good idea; through <Destroy> bindings,
2139 Tcl_Finalize() may invoke Python code but at that point the
2140 interpreter and thread state have already been destroyed! */
2141 Py_AtExit(Tcl_Finalize);
2142 #endif
2144 #ifdef macintosh
2146 ** Part of this code is stolen from MacintoshInit in tkMacAppInit.
2147 ** Most of the initializations in that routine (toolbox init calls and
2148 ** such) have already been done for us, so we only need these.
2150 tcl_macQdPtr = &qd;
2152 Tcl_MacSetEventProc(PyMacConvertEvent);
2153 #if GENERATINGCFM
2154 mac_addlibresources();
2155 #endif /* GENERATINGCFM */
2156 #endif /* macintosh */
2161 #ifdef macintosh
2164 ** Anyone who embeds Tcl/Tk on the Mac must define panic().
2167 void
2168 panic(char * format, ...)
2170 va_list varg;
2172 va_start(varg, format);
2174 vfprintf(stderr, format, varg);
2175 (void) fflush(stderr);
2177 va_end(varg);
2179 Py_FatalError("Tcl/Tk panic");
2183 ** Pass events to SIOUX before passing them to Tk.
2186 static int
2187 PyMacConvertEvent(EventRecord *eventPtr)
2189 WindowPtr frontwin;
2191 ** Sioux eats too many events, so we don't pass it everything. We
2192 ** always pass update events to Sioux, and we only pass other events if
2193 ** the Sioux window is frontmost. This means that Tk menus don't work
2194 ** in that case, but at least we can scroll the sioux window.
2195 ** Note that the SIOUXIsAppWindow() routine we use here is not really
2196 ** part of the external interface of Sioux...
2198 frontwin = FrontWindow();
2199 if ( eventPtr->what == updateEvt || SIOUXIsAppWindow(frontwin) ) {
2200 if (SIOUXHandleOneEvent(eventPtr))
2201 return 0; /* Nothing happened to the Tcl event queue */
2203 return TkMacConvertEvent(eventPtr);
2206 #if GENERATINGCFM
2209 ** Additional Mac specific code for dealing with shared libraries.
2212 #include <Resources.h>
2213 #include <CodeFragments.h>
2215 static int loaded_from_shlib = 0;
2216 static FSSpec library_fss;
2219 ** If this module is dynamically loaded the following routine should
2220 ** be the init routine. It takes care of adding the shared library to
2221 ** the resource-file chain, so that the tk routines can find their
2222 ** resources.
2224 OSErr pascal
2225 init_tkinter_shlib(CFragInitBlockPtr data)
2227 __initialize();
2228 if ( data == nil ) return noErr;
2229 if ( data->fragLocator.where == kDataForkCFragLocator ) {
2230 library_fss = *data->fragLocator.u.onDisk.fileSpec;
2231 loaded_from_shlib = 1;
2232 } else if ( data->fragLocator.where == kResourceCFragLocator ) {
2233 library_fss = *data->fragLocator.u.inSegs.fileSpec;
2234 loaded_from_shlib = 1;
2236 return noErr;
2240 ** Insert the library resources into the search path. Put them after
2241 ** the resources from the application. Again, we ignore errors.
2243 static
2244 mac_addlibresources(void)
2246 if ( !loaded_from_shlib )
2247 return;
2248 (void)FSpOpenResFile(&library_fss, fsRdPerm);
2251 #endif /* GENERATINGCFM */
2252 #endif /* macintosh */