Added 'description' class attribute to every command class (to help the
[python/dscho.git] / Modules / _tkinter.c
blobfd0a69c069b400446efdaabaa5be46df1801a209
1 /***********************************************************
2 Copyright (C) 1994 Steen Lumholt.
3 Copyright 1994-1995 by Stichting Mathematisch Centrum, Amsterdam,
4 The Netherlands.
6 All Rights Reserved
8 Permission to use, copy, modify, and distribute this software and its
9 documentation for any purpose and without fee is hereby granted,
10 provided that the above copyright notice appear in all copies and that
11 both that copyright notice and this permission notice appear in
12 supporting documentation, and that the names of Stichting Mathematisch
13 Centrum or CWI or Corporation for National Research Initiatives or
14 CNRI not be used in advertising or publicity pertaining to
15 distribution of the software without specific, written prior
16 permission.
18 While CWI is the initial source for this software, a modified version
19 is made available by the Corporation for National Research Initiatives
20 (CNRI) at the Internet address ftp://ftp.python.org.
22 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
23 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
24 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
25 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
26 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
27 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
28 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
29 PERFORMANCE OF THIS SOFTWARE.
31 ******************************************************************/
33 /* _tkinter.c -- Interface to libtk.a and libtcl.a. */
35 /* TCL/TK VERSION INFO:
37 Unix:
38 Tcl/Tk 8.0 (even alpha or beta) or 7.6/4.2 are recommended.
39 Versions 7.5/4.1 are the earliest versions still supported.
40 Versions 7.4/4.0 or Tk 3.x are no longer supported.
42 Mac and Windows:
43 Use Tcl 8.0 if available (even alpha or beta).
44 The oldest usable version is 4.1p1/7.5p1.
46 XXX Further speed-up ideas, involving Tcl 8.0 features:
48 - In Tcl_Call(), create Tcl objects from the arguments, possibly using
49 intelligent mappings between Python objects and Tcl objects (e.g. ints,
50 floats and Tcl window pointers could be handled specially).
52 - Register a new Tcl type, "Python callable", which can be called more
53 efficiently and passed to Tcl_EvalObj() directly (if this is possible).
58 #include "Python.h"
59 #include <ctype.h>
61 #ifdef WITH_THREAD
62 #include "pythread.h"
63 #endif
65 #ifdef MS_WINDOWS
66 #include <windows.h>
67 #endif
69 #ifdef macintosh
70 #define MAC_TCL
71 #include "myselect.h"
72 #endif
74 #ifdef PYOS_OS2
75 #include "myselect.h"
76 #endif
78 #include <tcl.h>
79 #include <tk.h>
81 #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION)
83 #if TKMAJORMINOR < 4001
84 #error "Tk 4.0 or 3.x are not supported -- use 4.1 or higher"
85 #endif
87 #if TKMAJORMINOR >= 8000 && defined(macintosh)
88 /* Sigh, we have to include this to get at the tcl qd pointer */
89 #include <tkMac.h>
90 /* And this one we need to clear the menu bar */
91 #include <Menus.h>
92 #endif
94 #if TKMAJORMINOR < 8000 || !defined(MS_WINDOWS)
95 #define HAVE_CREATEFILEHANDLER
96 #endif
98 #ifdef HAVE_CREATEFILEHANDLER
100 /* Tcl_CreateFileHandler() changed several times; these macros deal with the
101 messiness. In Tcl 8.0 and later, it is not available on Windows (and on
102 Unix, only because Jack added it back); when available on Windows, it only
103 applies to sockets. */
105 #ifdef MS_WINDOWS
106 #define FHANDLETYPE TCL_WIN_SOCKET
107 #else
108 #define FHANDLETYPE TCL_UNIX_FD
109 #endif
111 #if TKMAJORMINOR < 8000
112 #define FHANDLE Tcl_File
113 #define MAKEFHANDLE(fd) Tcl_GetFile((ClientData)(fd), FHANDLETYPE)
114 #else
115 #define FHANDLE int
116 #define MAKEFHANDLE(fd) (fd)
117 #endif
119 /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine
120 which uses this to handle Tcl events while the user is typing commands. */
122 #if FHANDLETYPE == TCL_UNIX_FD
123 #define WAIT_FOR_STDIN
124 #endif
126 #endif /* HAVE_CREATEFILEHANDLER */
128 #ifdef MS_WINDOWS
129 #include <conio.h>
130 #define WAIT_FOR_STDIN
131 #endif
133 #ifdef WITH_THREAD
135 /* The threading situation is complicated. Tcl is not thread-safe, except for
136 Tcl 8.1, which will probably remain in alpha status for another 6 months
137 (and the README says that Tk will probably remain thread-unsafe forever).
138 So we need to use a lock around all uses of Tcl. Previously, the Python
139 interpreter lock was used for this. However, this causes problems when
140 other Python threads need to run while Tcl is blocked waiting for events.
142 To solve this problem, a separate lock for Tcl is introduced. Holding it
143 is incompatible with holding Python's interpreter lock. The following four
144 macros manipulate both locks together.
146 ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and
147 Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made
148 that could call an event handler, or otherwise affect the state of a Tcl
149 interpreter. These assume that the surrounding code has the Python
150 interpreter lock; inside the brackets, the Python interpreter lock has been
151 released and the lock for Tcl has been acquired.
153 Sometimes, it is necessary to have both the Python lock and the Tcl lock.
154 (For example, when transferring data from the Tcl interpreter result to a
155 Python string object.) This can be done by using different macros to close
156 the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores
157 the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL
158 releases the Tcl lock.
160 By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event
161 handlers when the handler needs to use Python. Such event handlers are
162 entered while the lock for Tcl is held; the event handler presumably needs
163 to use Python. ENTER_PYTHON releases the lock for Tcl and acquires
164 the Python interpreter lock, restoring the appropriate thread state, and
165 LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock
166 for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside
167 the code between ENTER_PYTHON and LEAVE_PYTHON.
169 These locks expand to several statements and brackets; they should not be
170 used in branches of if statements and the like.
174 static PyThread_type_lock tcl_lock = 0;
175 static PyThreadState *tcl_tstate = NULL;
177 #define ENTER_TCL \
178 { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
179 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
181 #define LEAVE_TCL \
182 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
184 #define ENTER_OVERLAP \
185 Py_END_ALLOW_THREADS
187 #define LEAVE_OVERLAP_TCL \
188 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); }
190 #define ENTER_PYTHON \
191 { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
192 PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
194 #define LEAVE_PYTHON \
195 { PyThreadState *tstate = PyEval_SaveThread(); \
196 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
198 #else
200 #define ENTER_TCL
201 #define LEAVE_TCL
202 #define ENTER_OVERLAP
203 #define LEAVE_OVERLAP_TCL
204 #define ENTER_PYTHON
205 #define LEAVE_PYTHON
207 #endif
209 #ifdef macintosh
212 ** Additional cruft needed by Tcl/Tk on the Mac.
213 ** This is for Tcl 7.5 and Tk 4.1 (patch release 1).
216 /* ckfree() expects a char* */
217 #define FREECAST (char *)
219 #include <Events.h> /* For EventRecord */
221 typedef int (*TclMacConvertEventPtr) Py_PROTO((EventRecord *eventPtr));
222 /* They changed the name... */
223 #if TKMAJORMINOR < 8000
224 #define Tcl_MacSetEventProc TclMacSetEventProc
225 #endif
226 void Tcl_MacSetEventProc Py_PROTO((TclMacConvertEventPtr procPtr));
227 int TkMacConvertEvent Py_PROTO((EventRecord *eventPtr));
229 staticforward int PyMacConvertEvent Py_PROTO((EventRecord *eventPtr));
231 #if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
232 #pragma import on
233 #endif
235 #include <SIOUX.h>
236 extern int SIOUXIsAppWindow(WindowPtr);
238 #if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
239 #pragma import reset
240 #endif
241 #endif /* macintosh */
243 #ifndef FREECAST
244 #define FREECAST (char *)
245 #endif
247 /**** Tkapp Object Declaration ****/
249 staticforward PyTypeObject Tkapp_Type;
251 typedef struct {
252 PyObject_HEAD
253 Tcl_Interp *interp;
254 } TkappObject;
256 #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
257 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
258 #define Tkapp_Result(v) (((TkappObject *) (v))->interp->result)
260 #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \
261 (void *) v, ((PyObject *) v)->ob_refcnt))
265 /**** Error Handling ****/
267 static PyObject *Tkinter_TclError;
268 static int quitMainLoop = 0;
269 static int errorInCmd = 0;
270 static PyObject *excInCmd;
271 static PyObject *valInCmd;
272 static PyObject *trbInCmd;
276 static PyObject *
277 Tkinter_Error(v)
278 PyObject *v;
280 PyErr_SetString(Tkinter_TclError, Tkapp_Result(v));
281 return NULL;
286 /**** Utils ****/
288 #ifdef WITH_THREAD
289 #ifndef MS_WINDOWS
290 #include "mytime.h"
291 #include "myselect.h"
293 /* Millisecond sleep() for Unix platforms. */
295 static void
296 Sleep(milli)
297 int milli;
299 /* XXX Too bad if you don't have select(). */
300 struct timeval t;
301 double frac;
302 t.tv_sec = milli/1000;
303 t.tv_usec = (milli%1000) * 1000;
304 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
306 #endif /* MS_WINDOWS */
307 #endif /* WITH_THREAD */
310 static char *
311 AsString(value, tmp)
312 PyObject *value;
313 PyObject *tmp;
315 if (PyString_Check(value))
316 return PyString_AsString(value);
317 else {
318 PyObject *v = PyObject_Str(value);
319 PyList_Append(tmp, v);
320 Py_DECREF(v);
321 return PyString_AsString(v);
327 #define ARGSZ 64
329 static char *
330 Merge(args)
331 PyObject *args;
333 PyObject *tmp = NULL;
334 char *argvStore[ARGSZ];
335 char **argv = NULL;
336 int fvStore[ARGSZ];
337 int *fv = NULL;
338 int argc = 0, i;
339 char *res = NULL;
341 if (!(tmp = PyList_New(0)))
342 return NULL;
344 argv = argvStore;
345 fv = fvStore;
347 if (args == NULL)
348 argc = 0;
350 else if (!PyTuple_Check(args)) {
351 argc = 1;
352 fv[0] = 0;
353 argv[0] = AsString(args, tmp);
355 else {
356 argc = PyTuple_Size(args);
358 if (argc > ARGSZ) {
359 argv = (char **)ckalloc(argc * sizeof(char *));
360 fv = (int *)ckalloc(argc * sizeof(int));
361 if (argv == NULL || fv == NULL) {
362 PyErr_NoMemory();
363 goto finally;
367 for (i = 0; i < argc; i++) {
368 PyObject *v = PyTuple_GetItem(args, i);
369 if (PyTuple_Check(v)) {
370 fv[i] = 1;
371 if (!(argv[i] = Merge(v)))
372 goto finally;
374 else if (v == Py_None) {
375 argc = i;
376 break;
378 else {
379 fv[i] = 0;
380 argv[i] = AsString(v, tmp);
384 res = Tcl_Merge(argc, argv);
386 finally:
387 for (i = 0; i < argc; i++)
388 if (fv[i]) {
389 ckfree(argv[i]);
391 if (argv != argvStore)
392 ckfree(FREECAST argv);
393 if (fv != fvStore)
394 ckfree(FREECAST fv);
396 Py_DECREF(tmp);
397 return res;
402 static PyObject *
403 Split(list)
404 char *list;
406 int argc;
407 char **argv;
408 PyObject *v;
410 if (list == NULL) {
411 Py_INCREF(Py_None);
412 return Py_None;
415 if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
416 /* Not a list.
417 * Could be a quoted string containing funnies, e.g. {"}.
418 * Return the string itself.
420 return PyString_FromString(list);
423 if (argc == 0)
424 v = PyString_FromString("");
425 else if (argc == 1)
426 v = PyString_FromString(argv[0]);
427 else if ((v = PyTuple_New(argc)) != NULL) {
428 int i;
429 PyObject *w;
431 for (i = 0; i < argc; i++) {
432 if ((w = Split(argv[i])) == NULL) {
433 Py_DECREF(v);
434 v = NULL;
435 break;
437 PyTuple_SetItem(v, i, w);
440 Tcl_Free(FREECAST argv);
441 return v;
446 /**** Tkapp Object ****/
448 #ifndef WITH_APPINIT
450 Tcl_AppInit(interp)
451 Tcl_Interp *interp;
453 Tk_Window main;
455 main = Tk_MainWindow(interp);
456 if (Tcl_Init(interp) == TCL_ERROR) {
457 PySys_WriteStderr("Tcl_Init error: %s\n", interp->result);
458 return TCL_ERROR;
460 if (Tk_Init(interp) == TCL_ERROR) {
461 PySys_WriteStderr("Tk_Init error: %s\n", interp->result);
462 return TCL_ERROR;
464 return TCL_OK;
466 #endif /* !WITH_APPINIT */
471 /* Initialize the Tk application; see the `main' function in
472 * `tkMain.c'.
475 static void EnableEventHook(); /* Forward */
476 static void DisableEventHook(); /* Forward */
478 static TkappObject *
479 Tkapp_New(screenName, baseName, className, interactive)
480 char *screenName;
481 char *baseName;
482 char *className;
483 int interactive;
485 TkappObject *v;
486 char *argv0;
488 v = PyObject_NEW(TkappObject, &Tkapp_Type);
489 if (v == NULL)
490 return NULL;
492 v->interp = Tcl_CreateInterp();
494 #if TKMAJORMINOR == 8001
495 TclpInitLibraryPath(baseName);
496 #endif /* TKMAJORMINOR */
498 #if defined(macintosh) && TKMAJORMINOR >= 8000
499 /* This seems to be needed since Tk 8.0 */
500 ClearMenuBar();
501 TkMacInitMenus(v->interp);
502 #endif
503 /* Delete the 'exit' command, which can screw things up */
504 Tcl_DeleteCommand(v->interp, "exit");
506 if (screenName != NULL)
507 Tcl_SetVar2(v->interp, "env", "DISPLAY",
508 screenName, TCL_GLOBAL_ONLY);
510 if (interactive)
511 Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
512 else
513 Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
515 /* This is used to get the application class for Tk 4.1 and up */
516 argv0 = (char*)ckalloc(strlen(className) + 1);
517 if (!argv0) {
518 PyErr_NoMemory();
519 Py_DECREF(v);
520 return NULL;
523 strcpy(argv0, className);
524 if (isupper((int)(argv0[0])))
525 argv0[0] = tolower(argv0[0]);
526 Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY);
527 ckfree(argv0);
529 if (Tcl_AppInit(v->interp) != TCL_OK)
530 return (TkappObject *)Tkinter_Error((PyObject *)v);
532 EnableEventHook();
534 return v;
539 /** Tcl Eval **/
541 static PyObject *
542 Tkapp_Call(self, args)
543 PyObject *self;
544 PyObject *args;
546 /* This is copied from Merge() */
547 PyObject *tmp = NULL;
548 char *argvStore[ARGSZ];
549 char **argv = NULL;
550 int fvStore[ARGSZ];
551 int *fv = NULL;
552 int argc = 0, i;
553 PyObject *res = NULL; /* except this has a different type */
554 Tcl_CmdInfo info; /* and this is added */
555 Tcl_Interp *interp = Tkapp_Interp(self); /* and this too */
557 if (!(tmp = PyList_New(0)))
558 return NULL;
560 argv = argvStore;
561 fv = fvStore;
563 if (args == NULL)
564 argc = 0;
566 else if (!PyTuple_Check(args)) {
567 argc = 1;
568 fv[0] = 0;
569 argv[0] = AsString(args, tmp);
571 else {
572 argc = PyTuple_Size(args);
574 if (argc > ARGSZ) {
575 argv = (char **)ckalloc(argc * sizeof(char *));
576 fv = (int *)ckalloc(argc * sizeof(int));
577 if (argv == NULL || fv == NULL) {
578 PyErr_NoMemory();
579 goto finally;
583 for (i = 0; i < argc; i++) {
584 PyObject *v = PyTuple_GetItem(args, i);
585 if (PyTuple_Check(v)) {
586 fv[i] = 1;
587 if (!(argv[i] = Merge(v)))
588 goto finally;
590 else if (v == Py_None) {
591 argc = i;
592 break;
594 else {
595 fv[i] = 0;
596 argv[i] = AsString(v, tmp);
600 /* End code copied from Merge() */
602 /* All this to avoid a call to Tcl_Merge() and the corresponding call
603 to Tcl_SplitList() inside Tcl_Eval()... It can save a bundle! */
604 if (Py_VerboseFlag >= 2) {
605 for (i = 0; i < argc; i++)
606 PySys_WriteStderr("%s ", argv[i]);
608 ENTER_TCL
609 info.proc = NULL;
610 if (argc < 1 ||
611 !Tcl_GetCommandInfo(interp, argv[0], &info) ||
612 info.proc == NULL)
614 char *cmd;
615 cmd = Tcl_Merge(argc, argv);
616 i = Tcl_Eval(interp, cmd);
617 ckfree(cmd);
619 else {
620 Tcl_ResetResult(interp);
621 i = (*info.proc)(info.clientData, interp, argc, argv);
623 ENTER_OVERLAP
624 if (info.proc == NULL && Py_VerboseFlag >= 2)
625 PySys_WriteStderr("... use TclEval ");
626 if (i == TCL_ERROR) {
627 if (Py_VerboseFlag >= 2)
628 PySys_WriteStderr("... error: '%s'\n",
629 interp->result);
630 Tkinter_Error(self);
632 else {
633 if (Py_VerboseFlag >= 2)
634 PySys_WriteStderr("-> '%s'\n", interp->result);
635 res = PyString_FromString(interp->result);
637 LEAVE_OVERLAP_TCL
639 /* Copied from Merge() again */
640 finally:
641 for (i = 0; i < argc; i++)
642 if (fv[i]) {
643 ckfree(argv[i]);
645 if (argv != argvStore)
646 ckfree(FREECAST argv);
647 if (fv != fvStore)
648 ckfree(FREECAST fv);
650 Py_DECREF(tmp);
651 return res;
655 static PyObject *
656 Tkapp_GlobalCall(self, args)
657 PyObject *self;
658 PyObject *args;
660 /* Could do the same here as for Tkapp_Call(), but this is not used
661 much, so I can't be bothered. Unfortunately Tcl doesn't export a
662 way for the user to do what all its Global* variants do (save and
663 reset the scope pointer, call the local version, restore the saved
664 scope pointer). */
666 char *cmd;
667 PyObject *res = NULL;
669 cmd = Merge(args);
670 if (!cmd)
671 PyErr_SetString(Tkinter_TclError, "merge failed");
673 else {
674 int err;
675 ENTER_TCL
676 err = Tcl_GlobalEval(Tkapp_Interp(self), cmd);
677 ENTER_OVERLAP
678 if (err == TCL_ERROR)
679 res = Tkinter_Error(self);
680 else
681 res = PyString_FromString(Tkapp_Result(self));
682 LEAVE_OVERLAP_TCL
685 if (cmd)
686 ckfree(cmd);
688 return res;
691 static PyObject *
692 Tkapp_Eval(self, args)
693 PyObject *self;
694 PyObject *args;
696 char *script;
697 PyObject *res = NULL;
698 int err;
700 if (!PyArg_ParseTuple(args, "s", &script))
701 return NULL;
703 ENTER_TCL
704 err = Tcl_Eval(Tkapp_Interp(self), script);
705 ENTER_OVERLAP
706 if (err == TCL_ERROR)
707 res = Tkinter_Error(self);
708 else
709 res = PyString_FromString(Tkapp_Result(self));
710 LEAVE_OVERLAP_TCL
711 return res;
714 static PyObject *
715 Tkapp_GlobalEval(self, args)
716 PyObject *self;
717 PyObject *args;
719 char *script;
720 PyObject *res = NULL;
721 int err;
723 if (!PyArg_ParseTuple(args, "s", &script))
724 return NULL;
726 ENTER_TCL
727 err = Tcl_GlobalEval(Tkapp_Interp(self), script);
728 ENTER_OVERLAP
729 if (err == TCL_ERROR)
730 res = Tkinter_Error(self);
731 else
732 res = PyString_FromString(Tkapp_Result(self));
733 LEAVE_OVERLAP_TCL
734 return res;
737 static PyObject *
738 Tkapp_EvalFile(self, args)
739 PyObject *self;
740 PyObject *args;
742 char *fileName;
743 PyObject *res = NULL;
744 int err;
746 if (!PyArg_ParseTuple(args, "s", &fileName))
747 return NULL;
749 ENTER_TCL
750 err = Tcl_EvalFile(Tkapp_Interp(self), fileName);
751 ENTER_OVERLAP
752 if (err == TCL_ERROR)
753 res = Tkinter_Error(self);
755 else
756 res = PyString_FromString(Tkapp_Result(self));
757 LEAVE_OVERLAP_TCL
758 return res;
761 static PyObject *
762 Tkapp_Record(self, args)
763 PyObject *self;
764 PyObject *args;
766 char *script;
767 PyObject *res = NULL;
768 int err;
770 if (!PyArg_ParseTuple(args, "s", &script))
771 return NULL;
773 ENTER_TCL
774 err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL);
775 ENTER_OVERLAP
776 if (err == TCL_ERROR)
777 res = Tkinter_Error(self);
778 else
779 res = PyString_FromString(Tkapp_Result(self));
780 LEAVE_OVERLAP_TCL
781 return res;
784 static PyObject *
785 Tkapp_AddErrorInfo(self, args)
786 PyObject *self;
787 PyObject *args;
789 char *msg;
791 if (!PyArg_ParseTuple(args, "s", &msg))
792 return NULL;
793 ENTER_TCL
794 Tcl_AddErrorInfo(Tkapp_Interp(self), msg);
795 LEAVE_TCL
797 Py_INCREF(Py_None);
798 return Py_None;
803 /** Tcl Variable **/
805 static PyObject *
806 SetVar(self, args, flags)
807 PyObject *self;
808 PyObject *args;
809 int flags;
811 char *name1, *name2, *ok, *s;
812 PyObject *newValue;
813 PyObject *tmp;
815 tmp = PyList_New(0);
816 if (!tmp)
817 return NULL;
819 if (PyArg_ParseTuple(args, "sO", &name1, &newValue)) {
820 /* XXX Merge? */
821 s = AsString(newValue, tmp);
822 ENTER_TCL
823 ok = Tcl_SetVar(Tkapp_Interp(self), name1, s, flags);
824 LEAVE_TCL
826 else {
827 PyErr_Clear();
828 if (PyArg_ParseTuple(args, "ssO", &name1, &name2, &newValue)) {
829 s = AsString (newValue, tmp);
830 ENTER_TCL
831 ok = Tcl_SetVar2(Tkapp_Interp(self), name1, name2,
832 s, flags);
833 LEAVE_TCL
835 else {
836 Py_DECREF(tmp);
837 return NULL;
840 Py_DECREF(tmp);
842 if (!ok)
843 return Tkinter_Error(self);
845 Py_INCREF(Py_None);
846 return Py_None;
849 static PyObject *
850 Tkapp_SetVar(self, args)
851 PyObject *self;
852 PyObject *args;
854 return SetVar(self, args, TCL_LEAVE_ERR_MSG);
857 static PyObject *
858 Tkapp_GlobalSetVar(self, args)
859 PyObject *self;
860 PyObject *args;
862 return SetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
867 static PyObject *
868 GetVar(self, args, flags)
869 PyObject *self;
870 PyObject *args;
871 int flags;
873 char *name1, *name2=NULL, *s;
874 PyObject *res = NULL;
876 if (!PyArg_ParseTuple(args, "s|s", &name1, &name2))
877 return NULL;
878 ENTER_TCL
879 if (name2 == NULL)
880 s = Tcl_GetVar(Tkapp_Interp(self), name1, flags);
882 else
883 s = Tcl_GetVar2(Tkapp_Interp(self), name1, name2, flags);
884 ENTER_OVERLAP
886 if (s == NULL)
887 res = Tkinter_Error(self);
888 else
889 res = PyString_FromString(s);
890 LEAVE_OVERLAP_TCL
891 return res;
894 static PyObject *
895 Tkapp_GetVar(self, args)
896 PyObject *self;
897 PyObject *args;
899 return GetVar(self, args, TCL_LEAVE_ERR_MSG);
902 static PyObject *
903 Tkapp_GlobalGetVar(self, args)
904 PyObject *self;
905 PyObject *args;
907 return GetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
912 static PyObject *
913 UnsetVar(self, args, flags)
914 PyObject *self;
915 PyObject *args;
916 int flags;
918 char *name1, *name2=NULL;
919 PyObject *res = NULL;
920 int code;
922 if (!PyArg_ParseTuple(args, "s|s", &name1, &name2))
923 return NULL;
924 ENTER_TCL
925 if (name2 == NULL)
926 code = Tcl_UnsetVar(Tkapp_Interp(self), name1, flags);
928 else
929 code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
930 ENTER_OVERLAP
932 if (code == TCL_ERROR)
933 res = Tkinter_Error(self);
934 else {
935 Py_INCREF(Py_None);
936 res = Py_None;
938 LEAVE_OVERLAP_TCL
939 return res;
942 static PyObject *
943 Tkapp_UnsetVar(self, args)
944 PyObject *self;
945 PyObject *args;
947 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG);
950 static PyObject *
951 Tkapp_GlobalUnsetVar(self, args)
952 PyObject *self;
953 PyObject *args;
955 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
960 /** Tcl to Python **/
962 static PyObject *
963 Tkapp_GetInt(self, args)
964 PyObject *self;
965 PyObject *args;
967 char *s;
968 int v;
970 if (!PyArg_ParseTuple(args, "s", &s))
971 return NULL;
972 if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
973 return Tkinter_Error(self);
974 return Py_BuildValue("i", v);
977 static PyObject *
978 Tkapp_GetDouble(self, args)
979 PyObject *self;
980 PyObject *args;
982 char *s;
983 double v;
985 if (!PyArg_ParseTuple(args, "s", &s))
986 return NULL;
987 if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
988 return Tkinter_Error(self);
989 return Py_BuildValue("d", v);
992 static PyObject *
993 Tkapp_GetBoolean(self, args)
994 PyObject *self;
995 PyObject *args;
997 char *s;
998 int v;
1000 if (!PyArg_ParseTuple(args, "s", &s))
1001 return NULL;
1002 if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1003 return Tkinter_Error(self);
1004 return Py_BuildValue("i", v);
1007 static PyObject *
1008 Tkapp_ExprString(self, args)
1009 PyObject *self;
1010 PyObject *args;
1012 char *s;
1013 PyObject *res = NULL;
1014 int retval;
1016 if (!PyArg_ParseTuple(args, "s", &s))
1017 return NULL;
1018 ENTER_TCL
1019 retval = Tcl_ExprString(Tkapp_Interp(self), s);
1020 ENTER_OVERLAP
1021 if (retval == TCL_ERROR)
1022 res = Tkinter_Error(self);
1023 else
1024 res = Py_BuildValue("s", Tkapp_Result(self));
1025 LEAVE_OVERLAP_TCL
1026 return res;
1029 static PyObject *
1030 Tkapp_ExprLong(self, args)
1031 PyObject *self;
1032 PyObject *args;
1034 char *s;
1035 PyObject *res = NULL;
1036 int retval;
1037 long v;
1039 if (!PyArg_ParseTuple(args, "s", &s))
1040 return NULL;
1041 ENTER_TCL
1042 retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v);
1043 ENTER_OVERLAP
1044 if (retval == TCL_ERROR)
1045 res = Tkinter_Error(self);
1046 else
1047 res = Py_BuildValue("l", v);
1048 LEAVE_OVERLAP_TCL
1049 return res;
1052 static PyObject *
1053 Tkapp_ExprDouble(self, args)
1054 PyObject *self;
1055 PyObject *args;
1057 char *s;
1058 PyObject *res = NULL;
1059 double v;
1060 int retval;
1062 if (!PyArg_ParseTuple(args, "s", &s))
1063 return NULL;
1064 PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
1065 ENTER_TCL
1066 retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v);
1067 ENTER_OVERLAP
1068 PyFPE_END_PROTECT(retval)
1069 if (retval == TCL_ERROR)
1070 res = Tkinter_Error(self);
1071 else
1072 res = Py_BuildValue("d", v);
1073 LEAVE_OVERLAP_TCL
1074 return res;
1077 static PyObject *
1078 Tkapp_ExprBoolean(self, args)
1079 PyObject *self;
1080 PyObject *args;
1082 char *s;
1083 PyObject *res = NULL;
1084 int retval;
1085 int v;
1087 if (!PyArg_ParseTuple(args, "s", &s))
1088 return NULL;
1089 ENTER_TCL
1090 retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
1091 ENTER_OVERLAP
1092 if (retval == TCL_ERROR)
1093 res = Tkinter_Error(self);
1094 else
1095 res = Py_BuildValue("i", v);
1096 LEAVE_OVERLAP_TCL
1097 return res;
1102 static PyObject *
1103 Tkapp_SplitList(self, args)
1104 PyObject *self;
1105 PyObject *args;
1107 char *list;
1108 int argc;
1109 char **argv;
1110 PyObject *v;
1111 int i;
1113 if (!PyArg_ParseTuple(args, "s", &list))
1114 return NULL;
1116 if (Tcl_SplitList(Tkapp_Interp(self), list, &argc, &argv) == TCL_ERROR)
1117 return Tkinter_Error(self);
1119 if (!(v = PyTuple_New(argc)))
1120 return NULL;
1122 for (i = 0; i < argc; i++) {
1123 PyObject *s = PyString_FromString(argv[i]);
1124 if (!s || PyTuple_SetItem(v, i, s)) {
1125 Py_DECREF(v);
1126 v = NULL;
1127 goto finally;
1131 finally:
1132 ckfree(FREECAST argv);
1133 return v;
1136 static PyObject *
1137 Tkapp_Split(self, args)
1138 PyObject *self;
1139 PyObject *args;
1141 char *list;
1143 if (!PyArg_ParseTuple(args, "s", &list))
1144 return NULL;
1145 return Split(list);
1148 static PyObject *
1149 Tkapp_Merge(self, args)
1150 PyObject *self;
1151 PyObject *args;
1153 char *s = Merge(args);
1154 PyObject *res = NULL;
1156 if (s) {
1157 res = PyString_FromString(s);
1158 ckfree(s);
1160 else
1161 PyErr_SetString(Tkinter_TclError, "merge failed");
1163 return res;
1168 /** Tcl Command **/
1170 /* Client data struct */
1171 typedef struct {
1172 PyObject *self;
1173 PyObject *func;
1174 } PythonCmd_ClientData;
1176 static int
1177 PythonCmd_Error(interp)
1178 Tcl_Interp *interp;
1180 errorInCmd = 1;
1181 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1182 LEAVE_PYTHON
1183 return TCL_ERROR;
1186 /* This is the Tcl command that acts as a wrapper for Python
1187 * function or method.
1189 static int
1190 PythonCmd(clientData, interp, argc, argv)
1191 ClientData clientData;
1192 Tcl_Interp *interp;
1193 int argc;
1194 char *argv[];
1196 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1197 PyObject *self, *func, *arg, *res, *tmp;
1198 int i;
1200 ENTER_PYTHON
1202 /* TBD: no error checking here since we know, via the
1203 * Tkapp_CreateCommand() that the client data is a two-tuple
1205 self = data->self;
1206 func = data->func;
1208 /* Create argument list (argv1, ..., argvN) */
1209 if (!(arg = PyTuple_New(argc - 1)))
1210 return PythonCmd_Error(interp);
1212 for (i = 0; i < (argc - 1); i++) {
1213 PyObject *s = PyString_FromString(argv[i + 1]);
1214 if (!s || PyTuple_SetItem(arg, i, s)) {
1215 Py_DECREF(arg);
1216 return PythonCmd_Error(interp);
1219 res = PyEval_CallObject(func, arg);
1220 Py_DECREF(arg);
1222 if (res == NULL)
1223 return PythonCmd_Error(interp);
1225 if (!(tmp = PyList_New(0))) {
1226 Py_DECREF(res);
1227 return PythonCmd_Error(interp);
1230 Tcl_SetResult(Tkapp_Interp(self), AsString(res, tmp), TCL_VOLATILE);
1231 Py_DECREF(res);
1232 Py_DECREF(tmp);
1234 LEAVE_PYTHON
1236 return TCL_OK;
1239 static void
1240 PythonCmdDelete(clientData)
1241 ClientData clientData;
1243 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1245 ENTER_PYTHON
1246 Py_XDECREF(data->self);
1247 Py_XDECREF(data->func);
1248 PyMem_DEL(data);
1249 LEAVE_PYTHON
1254 static PyObject *
1255 Tkapp_CreateCommand(self, args)
1256 PyObject *self;
1257 PyObject *args;
1259 PythonCmd_ClientData *data;
1260 char *cmdName;
1261 PyObject *func;
1262 Tcl_Command err;
1264 if (!PyArg_ParseTuple(args, "sO", &cmdName, &func))
1265 return NULL;
1266 if (!PyCallable_Check(func)) {
1267 PyErr_SetString(PyExc_TypeError, "command not callable");
1268 return NULL;
1271 data = PyMem_NEW(PythonCmd_ClientData, 1);
1272 if (!data)
1273 return NULL;
1274 Py_XINCREF(self);
1275 Py_XINCREF(func);
1276 data->self = self;
1277 data->func = func;
1279 ENTER_TCL
1280 err = Tcl_CreateCommand(Tkapp_Interp(self), cmdName, PythonCmd,
1281 (ClientData)data, PythonCmdDelete);
1282 LEAVE_TCL
1283 if (err == NULL) {
1284 PyErr_SetString(Tkinter_TclError, "can't create Tcl command");
1285 PyMem_DEL(data);
1286 return NULL;
1289 Py_INCREF(Py_None);
1290 return Py_None;
1295 static PyObject *
1296 Tkapp_DeleteCommand(self, args)
1297 PyObject *self;
1298 PyObject *args;
1300 char *cmdName;
1301 int err;
1303 if (!PyArg_ParseTuple(args, "s", &cmdName))
1304 return NULL;
1305 ENTER_TCL
1306 err = Tcl_DeleteCommand(Tkapp_Interp(self), cmdName);
1307 LEAVE_TCL
1308 if (err == -1) {
1309 PyErr_SetString(Tkinter_TclError, "can't delete Tcl command");
1310 return NULL;
1312 Py_INCREF(Py_None);
1313 return Py_None;
1318 #ifdef HAVE_CREATEFILEHANDLER
1319 /** File Handler **/
1321 typedef struct _fhcdata {
1322 PyObject *func;
1323 PyObject *file;
1324 int id;
1325 struct _fhcdata *next;
1326 } FileHandler_ClientData;
1328 static FileHandler_ClientData *HeadFHCD;
1330 static FileHandler_ClientData *
1331 NewFHCD(func, file, id)
1332 PyObject *func;
1333 PyObject *file;
1334 int id;
1336 FileHandler_ClientData *p;
1337 p = PyMem_NEW(FileHandler_ClientData, 1);
1338 if (p != NULL) {
1339 Py_XINCREF(func);
1340 Py_XINCREF(file);
1341 p->func = func;
1342 p->file = file;
1343 p->id = id;
1344 p->next = HeadFHCD;
1345 HeadFHCD = p;
1347 return p;
1350 static void
1351 DeleteFHCD(id)
1352 int id;
1354 FileHandler_ClientData *p, **pp;
1356 pp = &HeadFHCD;
1357 while ((p = *pp) != NULL) {
1358 if (p->id == id) {
1359 *pp = p->next;
1360 Py_XDECREF(p->func);
1361 Py_XDECREF(p->file);
1362 PyMem_DEL(p);
1364 else
1365 pp = &p->next;
1369 static void
1370 FileHandler(clientData, mask)
1371 ClientData clientData;
1372 int mask;
1374 FileHandler_ClientData *data = (FileHandler_ClientData *)clientData;
1375 PyObject *func, *file, *arg, *res;
1377 ENTER_PYTHON
1378 func = data->func;
1379 file = data->file;
1381 arg = Py_BuildValue("(Oi)", file, (long) mask);
1382 res = PyEval_CallObject(func, arg);
1383 Py_DECREF(arg);
1385 if (res == NULL) {
1386 errorInCmd = 1;
1387 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1389 Py_XDECREF(res);
1390 LEAVE_PYTHON
1393 static int
1394 GetFileNo(file)
1395 /* Either an int >= 0 or an object with a
1396 *.fileno() method that returns an int >= 0
1398 PyObject *file;
1400 PyObject *meth, *args, *res;
1401 int id;
1402 if (PyInt_Check(file)) {
1403 id = PyInt_AsLong(file);
1404 if (id < 0)
1405 PyErr_SetString(PyExc_ValueError, "invalid file id");
1406 return id;
1408 args = PyTuple_New(0);
1409 if (args == NULL)
1410 return -1;
1412 meth = PyObject_GetAttrString(file, "fileno");
1413 if (meth == NULL) {
1414 Py_DECREF(args);
1415 return -1;
1418 res = PyEval_CallObject(meth, args);
1419 Py_DECREF(args);
1420 Py_DECREF(meth);
1421 if (res == NULL)
1422 return -1;
1424 if (PyInt_Check(res))
1425 id = PyInt_AsLong(res);
1426 else
1427 id = -1;
1429 if (id < 0)
1430 PyErr_SetString(PyExc_ValueError,
1431 "invalid fileno() return value");
1432 Py_DECREF(res);
1433 return id;
1436 static PyObject *
1437 Tkapp_CreateFileHandler(self, args)
1438 PyObject *self;
1439 PyObject *args; /* Is (file, mask, func) */
1441 FileHandler_ClientData *data;
1442 PyObject *file, *func;
1443 int mask, id;
1444 FHANDLE tfile;
1446 if (!PyArg_ParseTuple(args, "OiO", &file, &mask, &func))
1447 return NULL;
1448 id = GetFileNo(file);
1449 if (id < 0)
1450 return NULL;
1451 if (!PyCallable_Check(func)) {
1452 PyErr_SetString(PyExc_TypeError, "bad argument list");
1453 return NULL;
1456 data = NewFHCD(func, file, id);
1457 if (data == NULL)
1458 return NULL;
1460 tfile = MAKEFHANDLE(id);
1461 /* Ought to check for null Tcl_File object... */
1462 ENTER_TCL
1463 Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
1464 LEAVE_TCL
1465 Py_INCREF(Py_None);
1466 return Py_None;
1469 static PyObject *
1470 Tkapp_DeleteFileHandler(self, args)
1471 PyObject *self;
1472 PyObject *args; /* Args: file */
1474 PyObject *file;
1475 FileHandler_ClientData *data;
1476 int id;
1477 FHANDLE tfile;
1479 if (!PyArg_ParseTuple(args, "O", &file))
1480 return NULL;
1481 id = GetFileNo(file);
1482 if (id < 0)
1483 return NULL;
1485 DeleteFHCD(id);
1487 tfile = MAKEFHANDLE(id);
1488 /* Ought to check for null Tcl_File object... */
1489 ENTER_TCL
1490 Tcl_DeleteFileHandler(tfile);
1491 LEAVE_TCL
1492 Py_INCREF(Py_None);
1493 return Py_None;
1495 #endif /* HAVE_CREATEFILEHANDLER */
1498 /**** Tktt Object (timer token) ****/
1500 staticforward PyTypeObject Tktt_Type;
1502 typedef struct {
1503 PyObject_HEAD
1504 Tcl_TimerToken token;
1505 PyObject *func;
1506 } TkttObject;
1508 static PyObject *
1509 Tktt_DeleteTimerHandler(self, args)
1510 PyObject *self;
1511 PyObject *args;
1513 TkttObject *v = (TkttObject *)self;
1514 PyObject *func = v->func;
1516 if (!PyArg_ParseTuple(args, ""))
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(func)
1539 PyObject *func;
1541 TkttObject *v;
1543 v = PyObject_NEW(TkttObject, &Tktt_Type);
1544 if (v == NULL)
1545 return NULL;
1547 Py_INCREF(func);
1548 v->token = NULL;
1549 v->func = func;
1551 /* Extra reference, deleted when called or when handler is deleted */
1552 Py_INCREF(v);
1553 return v;
1556 static void
1557 Tktt_Dealloc(self)
1558 PyObject *self;
1560 TkttObject *v = (TkttObject *)self;
1561 PyObject *func = v->func;
1563 Py_XDECREF(func);
1565 PyMem_DEL(self);
1568 static PyObject *
1569 Tktt_Repr(self)
1570 PyObject *self;
1572 TkttObject *v = (TkttObject *)self;
1573 char buf[100];
1575 sprintf(buf, "<tktimertoken at 0x%lx%s>", (long)v,
1576 v->func == NULL ? ", handler deleted" : "");
1577 return PyString_FromString(buf);
1580 static PyObject *
1581 Tktt_GetAttr(self, name)
1582 PyObject *self;
1583 char *name;
1585 return Py_FindMethod(Tktt_methods, self, name);
1588 static PyTypeObject Tktt_Type =
1590 PyObject_HEAD_INIT(NULL)
1591 0, /*ob_size */
1592 "tktimertoken", /*tp_name */
1593 sizeof(TkttObject), /*tp_basicsize */
1594 0, /*tp_itemsize */
1595 Tktt_Dealloc, /*tp_dealloc */
1596 0, /*tp_print */
1597 Tktt_GetAttr, /*tp_getattr */
1598 0, /*tp_setattr */
1599 0, /*tp_compare */
1600 Tktt_Repr, /*tp_repr */
1601 0, /*tp_as_number */
1602 0, /*tp_as_sequence */
1603 0, /*tp_as_mapping */
1604 0, /*tp_hash */
1609 /** Timer Handler **/
1611 static void
1612 TimerHandler(clientData)
1613 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(self, args)
1642 PyObject *self;
1643 PyObject *args; /* Is (milliseconds, func) */
1645 int milliseconds;
1646 PyObject *func;
1647 TkttObject *v;
1649 if (!PyArg_ParseTuple(args, "iO", &milliseconds, &func))
1650 return NULL;
1651 if (!PyCallable_Check(func)) {
1652 PyErr_SetString(PyExc_TypeError, "bad argument list");
1653 return NULL;
1655 v = Tktt_New(func);
1656 v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler,
1657 (ClientData)v);
1659 return (PyObject *) v;
1663 /** Event Loop **/
1665 static PyObject *
1666 Tkapp_MainLoop(self, args)
1667 PyObject *self;
1668 PyObject *args;
1670 int threshold = 0;
1671 #ifdef WITH_THREAD
1672 PyThreadState *tstate = PyThreadState_Get();
1673 #endif
1675 if (!PyArg_ParseTuple(args, "|i", &threshold))
1676 return NULL;
1678 quitMainLoop = 0;
1679 while (Tk_GetNumMainWindows() > threshold &&
1680 !quitMainLoop &&
1681 !errorInCmd)
1683 int result;
1685 #ifdef WITH_THREAD
1686 Py_BEGIN_ALLOW_THREADS
1687 PyThread_acquire_lock(tcl_lock, 1);
1688 tcl_tstate = tstate;
1689 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
1690 tcl_tstate = NULL;
1691 PyThread_release_lock(tcl_lock);
1692 if (result == 0)
1693 Sleep(20);
1694 Py_END_ALLOW_THREADS
1695 #else
1696 result = Tcl_DoOneEvent(0);
1697 #endif
1699 if (PyErr_CheckSignals() != 0)
1700 return NULL;
1701 if (result < 0)
1702 break;
1704 quitMainLoop = 0;
1706 if (errorInCmd) {
1707 errorInCmd = 0;
1708 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
1709 excInCmd = valInCmd = trbInCmd = NULL;
1710 return NULL;
1712 Py_INCREF(Py_None);
1713 return Py_None;
1716 static PyObject *
1717 Tkapp_DoOneEvent(self, args)
1718 PyObject *self;
1719 PyObject *args;
1721 int flags = 0;
1722 int rv;
1724 if (!PyArg_ParseTuple(args, "|i", &flags))
1725 return NULL;
1727 ENTER_TCL
1728 rv = Tcl_DoOneEvent(flags);
1729 LEAVE_TCL
1730 return Py_BuildValue("i", rv);
1733 static PyObject *
1734 Tkapp_Quit(self, args)
1735 PyObject *self;
1736 PyObject *args;
1739 if (!PyArg_ParseTuple(args, ""))
1740 return NULL;
1742 quitMainLoop = 1;
1743 Py_INCREF(Py_None);
1744 return Py_None;
1747 static PyObject *
1748 Tkapp_InterpAddr(self, args)
1749 PyObject *self;
1750 PyObject *args;
1753 if (!PyArg_ParseTuple(args, ""))
1754 return NULL;
1756 return PyInt_FromLong((long)Tkapp_Interp(self));
1761 /**** Tkapp Method List ****/
1763 static PyMethodDef Tkapp_methods[] =
1765 {"call", Tkapp_Call, 0},
1766 {"globalcall", Tkapp_GlobalCall, 0},
1767 {"eval", Tkapp_Eval, 1},
1768 {"globaleval", Tkapp_GlobalEval, 1},
1769 {"evalfile", Tkapp_EvalFile, 1},
1770 {"record", Tkapp_Record, 1},
1771 {"adderrorinfo", Tkapp_AddErrorInfo, 1},
1772 {"setvar", Tkapp_SetVar, 1},
1773 {"globalsetvar", Tkapp_GlobalSetVar, 1},
1774 {"getvar", Tkapp_GetVar, 1},
1775 {"globalgetvar", Tkapp_GlobalGetVar, 1},
1776 {"unsetvar", Tkapp_UnsetVar, 1},
1777 {"globalunsetvar", Tkapp_GlobalUnsetVar, 1},
1778 {"getint", Tkapp_GetInt, 1},
1779 {"getdouble", Tkapp_GetDouble, 1},
1780 {"getboolean", Tkapp_GetBoolean, 1},
1781 {"exprstring", Tkapp_ExprString, 1},
1782 {"exprlong", Tkapp_ExprLong, 1},
1783 {"exprdouble", Tkapp_ExprDouble, 1},
1784 {"exprboolean", Tkapp_ExprBoolean, 1},
1785 {"splitlist", Tkapp_SplitList, 1},
1786 {"split", Tkapp_Split, 1},
1787 {"merge", Tkapp_Merge, 0},
1788 {"createcommand", Tkapp_CreateCommand, 1},
1789 {"deletecommand", Tkapp_DeleteCommand, 1},
1790 #ifdef HAVE_CREATEFILEHANDLER
1791 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1792 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1793 #endif
1794 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1795 {"mainloop", Tkapp_MainLoop, 1},
1796 {"dooneevent", Tkapp_DoOneEvent, 1},
1797 {"quit", Tkapp_Quit, 1},
1798 {"interpaddr", Tkapp_InterpAddr, 1},
1799 {NULL, NULL}
1804 /**** Tkapp Type Methods ****/
1806 static void
1807 Tkapp_Dealloc(self)
1808 PyObject *self;
1810 ENTER_TCL
1811 Tcl_DeleteInterp(Tkapp_Interp(self));
1812 LEAVE_TCL
1813 PyMem_DEL(self);
1814 DisableEventHook();
1817 static PyObject *
1818 Tkapp_GetAttr(self, name)
1819 PyObject *self;
1820 char *name;
1822 return Py_FindMethod(Tkapp_methods, self, name);
1825 static PyTypeObject Tkapp_Type =
1827 PyObject_HEAD_INIT(NULL)
1828 0, /*ob_size */
1829 "tkapp", /*tp_name */
1830 sizeof(TkappObject), /*tp_basicsize */
1831 0, /*tp_itemsize */
1832 Tkapp_Dealloc, /*tp_dealloc */
1833 0, /*tp_print */
1834 Tkapp_GetAttr, /*tp_getattr */
1835 0, /*tp_setattr */
1836 0, /*tp_compare */
1837 0, /*tp_repr */
1838 0, /*tp_as_number */
1839 0, /*tp_as_sequence */
1840 0, /*tp_as_mapping */
1841 0, /*tp_hash */
1846 /**** Tkinter Module ****/
1848 static PyObject *
1849 Tkinter_Create(self, args)
1850 PyObject *self;
1851 PyObject *args;
1853 char *screenName = NULL;
1854 char *baseName = NULL;
1855 char *className = NULL;
1856 int interactive = 0;
1858 baseName = strrchr(Py_GetProgramName(), '/');
1859 if (baseName != NULL)
1860 baseName++;
1861 else
1862 baseName = Py_GetProgramName();
1863 className = "Tk";
1865 if (!PyArg_ParseTuple(args, "|zssi",
1866 &screenName, &baseName, &className,
1867 &interactive))
1868 return NULL;
1870 return (PyObject *) Tkapp_New(screenName, baseName, className,
1871 interactive);
1874 static PyMethodDef moduleMethods[] =
1876 {"create", Tkinter_Create, 1},
1877 #ifdef HAVE_CREATEFILEHANDLER
1878 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1879 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1880 #endif
1881 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1882 {"mainloop", Tkapp_MainLoop, 1},
1883 {"dooneevent", Tkapp_DoOneEvent, 1},
1884 {"quit", Tkapp_Quit, 1},
1885 {NULL, NULL}
1888 #ifdef WAIT_FOR_STDIN
1890 static int stdin_ready = 0;
1892 #ifndef MS_WINDOWS
1893 static void
1894 MyFileProc(clientData, mask)
1895 void *clientData;
1896 int mask;
1898 stdin_ready = 1;
1900 #endif
1902 static PyThreadState *event_tstate = NULL;
1904 static int
1905 EventHook()
1907 #ifndef MS_WINDOWS
1908 FHANDLE tfile;
1909 #endif
1910 #ifdef WITH_THREAD
1911 PyEval_RestoreThread(event_tstate);
1912 #endif
1913 stdin_ready = 0;
1914 errorInCmd = 0;
1915 #ifndef MS_WINDOWS
1916 tfile = MAKEFHANDLE(fileno(stdin));
1917 Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
1918 #endif
1919 while (!errorInCmd && !stdin_ready) {
1920 int result;
1921 #ifdef MS_WINDOWS
1922 if (_kbhit()) {
1923 stdin_ready = 1;
1924 break;
1926 #endif
1927 #if defined(WITH_THREAD) || defined(MS_WINDOWS)
1928 Py_BEGIN_ALLOW_THREADS
1929 PyThread_acquire_lock(tcl_lock, 1);
1930 tcl_tstate = event_tstate;
1932 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
1934 tcl_tstate = NULL;
1935 PyThread_release_lock(tcl_lock);
1936 if (result == 0)
1937 Sleep(20);
1938 Py_END_ALLOW_THREADS
1939 #else
1940 result = Tcl_DoOneEvent(0);
1941 #endif
1943 if (result < 0)
1944 break;
1946 #ifndef MS_WINDOWS
1947 Tcl_DeleteFileHandler(tfile);
1948 #endif
1949 if (errorInCmd) {
1950 errorInCmd = 0;
1951 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
1952 excInCmd = valInCmd = trbInCmd = NULL;
1953 PyErr_Print();
1955 #ifdef WITH_THREAD
1956 PyEval_SaveThread();
1957 #endif
1958 return 0;
1961 #endif
1963 static void
1964 EnableEventHook()
1966 #ifdef WAIT_FOR_STDIN
1967 if (PyOS_InputHook == NULL) {
1968 #ifdef WITH_THREAD
1969 event_tstate = PyThreadState_Get();
1970 #endif
1971 PyOS_InputHook = EventHook;
1973 #endif
1976 static void
1977 DisableEventHook()
1979 #ifdef WAIT_FOR_STDIN
1980 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
1981 PyOS_InputHook = NULL;
1983 #endif
1987 /* all errors will be checked in one fell swoop in init_tkinter() */
1988 static void
1989 ins_long(d, name, val)
1990 PyObject *d;
1991 char *name;
1992 long val;
1994 PyObject *v = PyInt_FromLong(val);
1995 if (v) {
1996 PyDict_SetItemString(d, name, v);
1997 Py_DECREF(v);
2000 static void
2001 ins_string(d, name, val)
2002 PyObject *d;
2003 char *name;
2004 char *val;
2006 PyObject *v = PyString_FromString(val);
2007 if (v) {
2008 PyDict_SetItemString(d, name, v);
2009 Py_DECREF(v);
2014 DL_EXPORT(void)
2015 init_tkinter()
2017 PyObject *m, *d;
2019 Tkapp_Type.ob_type = &PyType_Type;
2021 #ifdef WITH_THREAD
2022 tcl_lock = PyThread_allocate_lock();
2023 #endif
2025 m = Py_InitModule("_tkinter", moduleMethods);
2027 d = PyModule_GetDict(m);
2028 Tkinter_TclError = Py_BuildValue("s", "TclError");
2029 PyDict_SetItemString(d, "TclError", Tkinter_TclError);
2031 ins_long(d, "READABLE", TCL_READABLE);
2032 ins_long(d, "WRITABLE", TCL_WRITABLE);
2033 ins_long(d, "EXCEPTION", TCL_EXCEPTION);
2034 ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS);
2035 ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS);
2036 ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS);
2037 ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS);
2038 ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS);
2039 ins_long(d, "DONT_WAIT", TCL_DONT_WAIT);
2040 ins_string(d, "TK_VERSION", TK_VERSION);
2041 ins_string(d, "TCL_VERSION", TCL_VERSION);
2043 PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type);
2045 Tktt_Type.ob_type = &PyType_Type;
2046 PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
2048 if (PyErr_Occurred())
2049 return;
2051 #if 0
2052 /* This was not a good idea; through <Destroy> bindings,
2053 Tcl_Finalize() may invoke Python code but at that point the
2054 interpreter and thread state have already been destroyed! */
2055 #if TKMAJORMINOR >= 8000
2056 Py_AtExit(Tcl_Finalize);
2057 #endif
2058 #endif
2060 #ifdef macintosh
2062 ** Part of this code is stolen from MacintoshInit in tkMacAppInit.
2063 ** Most of the initializations in that routine (toolbox init calls and
2064 ** such) have already been done for us, so we only need these.
2066 #if TKMAJORMINOR >= 8000
2067 tcl_macQdPtr = &qd;
2068 #endif
2070 Tcl_MacSetEventProc(PyMacConvertEvent);
2071 #if GENERATINGCFM
2072 mac_addlibresources();
2073 #endif /* GENERATINGCFM */
2074 #endif /* macintosh */
2079 #ifdef macintosh
2082 ** Anyone who embeds Tcl/Tk on the Mac must define panic().
2085 void
2086 panic(char * format, ...)
2088 va_list varg;
2090 va_start(varg, format);
2092 vfprintf(stderr, format, varg);
2093 (void) fflush(stderr);
2095 va_end(varg);
2097 Py_FatalError("Tcl/Tk panic");
2101 ** Pass events to SIOUX before passing them to Tk.
2104 static int
2105 PyMacConvertEvent(eventPtr)
2106 EventRecord *eventPtr;
2108 WindowPtr frontwin;
2110 ** Sioux eats too many events, so we don't pass it everything. We
2111 ** always pass update events to Sioux, and we only pass other events if
2112 ** the Sioux window is frontmost. This means that Tk menus don't work
2113 ** in that case, but at least we can scroll the sioux window.
2114 ** Note that the SIOUXIsAppWindow() routine we use here is not really
2115 ** part of the external interface of Sioux...
2117 frontwin = FrontWindow();
2118 if ( eventPtr->what == updateEvt || SIOUXIsAppWindow(frontwin) ) {
2119 if (SIOUXHandleOneEvent(eventPtr))
2120 return 0; /* Nothing happened to the Tcl event queue */
2122 return TkMacConvertEvent(eventPtr);
2125 #if defined(USE_GUSI) && TKMAJORMINOR < 8000
2127 * For Python we have to override this routine (from TclMacNotify),
2128 * since we use GUSI for our sockets, not Tcl streams. Hence, we have
2129 * to use GUSI select to see whether our socket is ready. Note that
2130 * createfilehandler (above) sets the type to TCL_UNIX_FD for our
2131 * files and sockets.
2133 * NOTE: this code was lifted from Tcl 7.6, it may need to be modified
2134 * for other versions. */
2137 Tcl_FileReady(file, mask)
2138 Tcl_File file; /* File handle for a stream. */
2139 int mask; /* OR'ed combination of TCL_READABLE,
2140 * TCL_WRITABLE, and TCL_EXCEPTION:
2141 * indicates conditions caller cares about. */
2143 int type;
2144 int fd;
2146 fd = (int) Tcl_GetFileInfo(file, &type);
2148 if (type == TCL_MAC_SOCKET) {
2149 return TclMacSocketReady(file, mask);
2150 } else if (type == TCL_MAC_FILE) {
2152 * Under the Macintosh, files are always ready, so we just
2153 * return the mask that was passed in.
2156 return mask;
2157 } else if (type == TCL_UNIX_FD) {
2158 fd_set readset, writeset, excset;
2159 struct timeval tv;
2161 FD_ZERO(&readset);
2162 FD_ZERO(&writeset);
2163 FD_ZERO(&excset);
2165 if ( mask & TCL_READABLE ) FD_SET(fd, &readset);
2166 if ( mask & TCL_WRITABLE ) FD_SET(fd, &writeset);
2167 if ( mask & TCL_EXCEPTION ) FD_SET(fd, &excset);
2169 tv.tv_sec = tv.tv_usec = 0;
2170 if ( select(fd+1, &readset, &writeset, &excset, &tv) <= 0 )
2171 return 0;
2173 mask = 0;
2174 if ( FD_ISSET(fd, &readset) ) mask |= TCL_READABLE;
2175 if ( FD_ISSET(fd, &writeset) ) mask |= TCL_WRITABLE;
2176 if ( FD_ISSET(fd, &excset) ) mask |= TCL_EXCEPTION;
2178 return mask;
2181 return 0;
2183 #endif /* USE_GUSI */
2185 #if GENERATINGCFM
2188 ** Additional Mac specific code for dealing with shared libraries.
2191 #include <Resources.h>
2192 #include <CodeFragments.h>
2194 static int loaded_from_shlib = 0;
2195 static FSSpec library_fss;
2198 ** If this module is dynamically loaded the following routine should
2199 ** be the init routine. It takes care of adding the shared library to
2200 ** the resource-file chain, so that the tk routines can find their
2201 ** resources.
2203 OSErr pascal
2204 init_tkinter_shlib(CFragInitBlockPtr data)
2206 __initialize();
2207 if ( data == nil ) return noErr;
2208 if ( data->fragLocator.where == kDataForkCFragLocator ) {
2209 library_fss = *data->fragLocator.u.onDisk.fileSpec;
2210 loaded_from_shlib = 1;
2211 } else if ( data->fragLocator.where == kResourceCFragLocator ) {
2212 library_fss = *data->fragLocator.u.inSegs.fileSpec;
2213 loaded_from_shlib = 1;
2215 return noErr;
2219 ** Insert the library resources into the search path. Put them after
2220 ** the resources from the application. Again, we ignore errors.
2222 static
2223 mac_addlibresources()
2225 if ( !loaded_from_shlib )
2226 return;
2227 (void)FSpOpenResFile(&library_fss, fsRdPerm);
2230 #endif /* GENERATINGCFM */
2231 #endif /* macintosh */