1 /***********************************************************
2 Copyright (C) 1994 Steen Lumholt.
3 Copyright 1994-1995 by Stichting Mathematisch Centrum, Amsterdam,
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
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:
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.
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).
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"
87 #if TKMAJORMINOR >= 8000 && defined(macintosh)
88 /* Sigh, we have to include this to get at the tcl qd pointer */
90 /* And this one we need to clear the menu bar */
94 #if TKMAJORMINOR < 8000 || !defined(MS_WINDOWS)
95 #define HAVE_CREATEFILEHANDLER
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. */
106 #define FHANDLETYPE TCL_WIN_SOCKET
108 #define FHANDLETYPE TCL_UNIX_FD
111 #if TKMAJORMINOR < 8000
112 #define FHANDLE Tcl_File
113 #define MAKEFHANDLE(fd) Tcl_GetFile((ClientData)(fd), FHANDLETYPE)
116 #define MAKEFHANDLE(fd) (fd)
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
126 #endif /* HAVE_CREATEFILEHANDLER */
130 #define WAIT_FOR_STDIN
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
;
178 { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
179 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
182 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
184 #define ENTER_OVERLAP \
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; }
202 #define ENTER_OVERLAP
203 #define LEAVE_OVERLAP_TCL
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
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__)
236 extern int SIOUXIsAppWindow(WindowPtr
);
238 #if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
241 #endif /* macintosh */
244 #define FREECAST (char *)
247 /**** Tkapp Object Declaration ****/
249 staticforward PyTypeObject Tkapp_Type
;
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
;
280 PyErr_SetString(Tkinter_TclError
, Tkapp_Result(v
));
291 #include "myselect.h"
293 /* Millisecond sleep() for Unix platforms. */
299 /* XXX Too bad if you don't have select(). */
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 */
315 if (PyString_Check(value
))
316 return PyString_AsString(value
);
318 PyObject
*v
= PyObject_Str(value
);
319 PyList_Append(tmp
, v
);
321 return PyString_AsString(v
);
333 PyObject
*tmp
= NULL
;
334 char *argvStore
[ARGSZ
];
341 if (!(tmp
= PyList_New(0)))
350 else if (!PyTuple_Check(args
)) {
353 argv
[0] = AsString(args
, tmp
);
356 argc
= PyTuple_Size(args
);
359 argv
= (char **)ckalloc(argc
* sizeof(char *));
360 fv
= (int *)ckalloc(argc
* sizeof(int));
361 if (argv
== NULL
|| fv
== NULL
) {
367 for (i
= 0; i
< argc
; i
++) {
368 PyObject
*v
= PyTuple_GetItem(args
, i
);
369 if (PyTuple_Check(v
)) {
371 if (!(argv
[i
] = Merge(v
)))
374 else if (v
== Py_None
) {
380 argv
[i
] = AsString(v
, tmp
);
384 res
= Tcl_Merge(argc
, argv
);
387 for (i
= 0; i
< argc
; i
++)
391 if (argv
!= argvStore
)
392 ckfree(FREECAST argv
);
415 if (Tcl_SplitList((Tcl_Interp
*)NULL
, list
, &argc
, &argv
) != TCL_OK
) {
417 * Could be a quoted string containing funnies, e.g. {"}.
418 * Return the string itself.
420 return PyString_FromString(list
);
424 v
= PyString_FromString("");
426 v
= PyString_FromString(argv
[0]);
427 else if ((v
= PyTuple_New(argc
)) != NULL
) {
431 for (i
= 0; i
< argc
; i
++) {
432 if ((w
= Split(argv
[i
])) == NULL
) {
437 PyTuple_SetItem(v
, i
, w
);
440 Tcl_Free(FREECAST argv
);
446 /**** Tkapp Object ****/
455 main
= Tk_MainWindow(interp
);
456 if (Tcl_Init(interp
) == TCL_ERROR
) {
457 PySys_WriteStderr("Tcl_Init error: %s\n", interp
->result
);
460 if (Tk_Init(interp
) == TCL_ERROR
) {
461 PySys_WriteStderr("Tk_Init error: %s\n", interp
->result
);
466 #endif /* !WITH_APPINIT */
471 /* Initialize the Tk application; see the `main' function in
475 static void EnableEventHook(); /* Forward */
476 static void DisableEventHook(); /* Forward */
479 Tkapp_New(screenName
, baseName
, className
, interactive
)
488 v
= PyObject_NEW(TkappObject
, &Tkapp_Type
);
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 */
501 TkMacInitMenus(v
->interp
);
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
);
511 Tcl_SetVar(v
->interp
, "tcl_interactive", "1", TCL_GLOBAL_ONLY
);
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);
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
);
529 if (Tcl_AppInit(v
->interp
) != TCL_OK
)
530 return (TkappObject
*)Tkinter_Error((PyObject
*)v
);
542 Tkapp_Call(self
, args
)
546 /* This is copied from Merge() */
547 PyObject
*tmp
= NULL
;
548 char *argvStore
[ARGSZ
];
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)))
566 else if (!PyTuple_Check(args
)) {
569 argv
[0] = AsString(args
, tmp
);
572 argc
= PyTuple_Size(args
);
575 argv
= (char **)ckalloc(argc
* sizeof(char *));
576 fv
= (int *)ckalloc(argc
* sizeof(int));
577 if (argv
== NULL
|| fv
== NULL
) {
583 for (i
= 0; i
< argc
; i
++) {
584 PyObject
*v
= PyTuple_GetItem(args
, i
);
585 if (PyTuple_Check(v
)) {
587 if (!(argv
[i
] = Merge(v
)))
590 else if (v
== Py_None
) {
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
]);
611 !Tcl_GetCommandInfo(interp
, argv
[0], &info
) ||
615 cmd
= Tcl_Merge(argc
, argv
);
616 i
= Tcl_Eval(interp
, cmd
);
620 Tcl_ResetResult(interp
);
621 i
= (*info
.proc
)(info
.clientData
, interp
, argc
, argv
);
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",
633 if (Py_VerboseFlag
>= 2)
634 PySys_WriteStderr("-> '%s'\n", interp
->result
);
635 res
= PyString_FromString(interp
->result
);
639 /* Copied from Merge() again */
641 for (i
= 0; i
< argc
; i
++)
645 if (argv
!= argvStore
)
646 ckfree(FREECAST argv
);
656 Tkapp_GlobalCall(self
, 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
667 PyObject
*res
= NULL
;
671 PyErr_SetString(Tkinter_TclError
, "merge failed");
676 err
= Tcl_GlobalEval(Tkapp_Interp(self
), cmd
);
678 if (err
== TCL_ERROR
)
679 res
= Tkinter_Error(self
);
681 res
= PyString_FromString(Tkapp_Result(self
));
692 Tkapp_Eval(self
, args
)
697 PyObject
*res
= NULL
;
700 if (!PyArg_ParseTuple(args
, "s", &script
))
704 err
= Tcl_Eval(Tkapp_Interp(self
), script
);
706 if (err
== TCL_ERROR
)
707 res
= Tkinter_Error(self
);
709 res
= PyString_FromString(Tkapp_Result(self
));
715 Tkapp_GlobalEval(self
, args
)
720 PyObject
*res
= NULL
;
723 if (!PyArg_ParseTuple(args
, "s", &script
))
727 err
= Tcl_GlobalEval(Tkapp_Interp(self
), script
);
729 if (err
== TCL_ERROR
)
730 res
= Tkinter_Error(self
);
732 res
= PyString_FromString(Tkapp_Result(self
));
738 Tkapp_EvalFile(self
, args
)
743 PyObject
*res
= NULL
;
746 if (!PyArg_ParseTuple(args
, "s", &fileName
))
750 err
= Tcl_EvalFile(Tkapp_Interp(self
), fileName
);
752 if (err
== TCL_ERROR
)
753 res
= Tkinter_Error(self
);
756 res
= PyString_FromString(Tkapp_Result(self
));
762 Tkapp_Record(self
, args
)
767 PyObject
*res
= NULL
;
770 if (!PyArg_ParseTuple(args
, "s", &script
))
774 err
= Tcl_RecordAndEval(Tkapp_Interp(self
), script
, TCL_NO_EVAL
);
776 if (err
== TCL_ERROR
)
777 res
= Tkinter_Error(self
);
779 res
= PyString_FromString(Tkapp_Result(self
));
785 Tkapp_AddErrorInfo(self
, args
)
791 if (!PyArg_ParseTuple(args
, "s", &msg
))
794 Tcl_AddErrorInfo(Tkapp_Interp(self
), msg
);
806 SetVar(self
, args
, flags
)
811 char *name1
, *name2
, *ok
, *s
;
819 if (PyArg_ParseTuple(args
, "sO", &name1
, &newValue
)) {
821 s
= AsString(newValue
, tmp
);
823 ok
= Tcl_SetVar(Tkapp_Interp(self
), name1
, s
, flags
);
828 if (PyArg_ParseTuple(args
, "ssO", &name1
, &name2
, &newValue
)) {
829 s
= AsString (newValue
, tmp
);
831 ok
= Tcl_SetVar2(Tkapp_Interp(self
), name1
, name2
,
843 return Tkinter_Error(self
);
850 Tkapp_SetVar(self
, args
)
854 return SetVar(self
, args
, TCL_LEAVE_ERR_MSG
);
858 Tkapp_GlobalSetVar(self
, args
)
862 return SetVar(self
, args
, TCL_LEAVE_ERR_MSG
| TCL_GLOBAL_ONLY
);
868 GetVar(self
, args
, flags
)
873 char *name1
, *name2
=NULL
, *s
;
874 PyObject
*res
= NULL
;
876 if (!PyArg_ParseTuple(args
, "s|s", &name1
, &name2
))
880 s
= Tcl_GetVar(Tkapp_Interp(self
), name1
, flags
);
883 s
= Tcl_GetVar2(Tkapp_Interp(self
), name1
, name2
, flags
);
887 res
= Tkinter_Error(self
);
889 res
= PyString_FromString(s
);
895 Tkapp_GetVar(self
, args
)
899 return GetVar(self
, args
, TCL_LEAVE_ERR_MSG
);
903 Tkapp_GlobalGetVar(self
, args
)
907 return GetVar(self
, args
, TCL_LEAVE_ERR_MSG
| TCL_GLOBAL_ONLY
);
913 UnsetVar(self
, args
, flags
)
918 char *name1
, *name2
=NULL
;
919 PyObject
*res
= NULL
;
922 if (!PyArg_ParseTuple(args
, "s|s", &name1
, &name2
))
926 code
= Tcl_UnsetVar(Tkapp_Interp(self
), name1
, flags
);
929 code
= Tcl_UnsetVar2(Tkapp_Interp(self
), name1
, name2
, flags
);
932 if (code
== TCL_ERROR
)
933 res
= Tkinter_Error(self
);
943 Tkapp_UnsetVar(self
, args
)
947 return UnsetVar(self
, args
, TCL_LEAVE_ERR_MSG
);
951 Tkapp_GlobalUnsetVar(self
, args
)
955 return UnsetVar(self
, args
, TCL_LEAVE_ERR_MSG
| TCL_GLOBAL_ONLY
);
960 /** Tcl to Python **/
963 Tkapp_GetInt(self
, args
)
970 if (!PyArg_ParseTuple(args
, "s", &s
))
972 if (Tcl_GetInt(Tkapp_Interp(self
), s
, &v
) == TCL_ERROR
)
973 return Tkinter_Error(self
);
974 return Py_BuildValue("i", v
);
978 Tkapp_GetDouble(self
, args
)
985 if (!PyArg_ParseTuple(args
, "s", &s
))
987 if (Tcl_GetDouble(Tkapp_Interp(self
), s
, &v
) == TCL_ERROR
)
988 return Tkinter_Error(self
);
989 return Py_BuildValue("d", v
);
993 Tkapp_GetBoolean(self
, args
)
1000 if (!PyArg_ParseTuple(args
, "s", &s
))
1002 if (Tcl_GetBoolean(Tkapp_Interp(self
), s
, &v
) == TCL_ERROR
)
1003 return Tkinter_Error(self
);
1004 return Py_BuildValue("i", v
);
1008 Tkapp_ExprString(self
, args
)
1013 PyObject
*res
= NULL
;
1016 if (!PyArg_ParseTuple(args
, "s", &s
))
1019 retval
= Tcl_ExprString(Tkapp_Interp(self
), s
);
1021 if (retval
== TCL_ERROR
)
1022 res
= Tkinter_Error(self
);
1024 res
= Py_BuildValue("s", Tkapp_Result(self
));
1030 Tkapp_ExprLong(self
, args
)
1035 PyObject
*res
= NULL
;
1039 if (!PyArg_ParseTuple(args
, "s", &s
))
1042 retval
= Tcl_ExprLong(Tkapp_Interp(self
), s
, &v
);
1044 if (retval
== TCL_ERROR
)
1045 res
= Tkinter_Error(self
);
1047 res
= Py_BuildValue("l", v
);
1053 Tkapp_ExprDouble(self
, args
)
1058 PyObject
*res
= NULL
;
1062 if (!PyArg_ParseTuple(args
, "s", &s
))
1064 PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
1066 retval
= Tcl_ExprDouble(Tkapp_Interp(self
), s
, &v
);
1068 PyFPE_END_PROTECT(retval
)
1069 if (retval
== TCL_ERROR
)
1070 res
= Tkinter_Error(self
);
1072 res
= Py_BuildValue("d", v
);
1078 Tkapp_ExprBoolean(self
, args
)
1083 PyObject
*res
= NULL
;
1087 if (!PyArg_ParseTuple(args
, "s", &s
))
1090 retval
= Tcl_ExprBoolean(Tkapp_Interp(self
), s
, &v
);
1092 if (retval
== TCL_ERROR
)
1093 res
= Tkinter_Error(self
);
1095 res
= Py_BuildValue("i", v
);
1103 Tkapp_SplitList(self
, args
)
1113 if (!PyArg_ParseTuple(args
, "s", &list
))
1116 if (Tcl_SplitList(Tkapp_Interp(self
), list
, &argc
, &argv
) == TCL_ERROR
)
1117 return Tkinter_Error(self
);
1119 if (!(v
= PyTuple_New(argc
)))
1122 for (i
= 0; i
< argc
; i
++) {
1123 PyObject
*s
= PyString_FromString(argv
[i
]);
1124 if (!s
|| PyTuple_SetItem(v
, i
, s
)) {
1132 ckfree(FREECAST argv
);
1137 Tkapp_Split(self
, args
)
1143 if (!PyArg_ParseTuple(args
, "s", &list
))
1149 Tkapp_Merge(self
, args
)
1153 char *s
= Merge(args
);
1154 PyObject
*res
= NULL
;
1157 res
= PyString_FromString(s
);
1161 PyErr_SetString(Tkinter_TclError
, "merge failed");
1170 /* Client data struct */
1174 } PythonCmd_ClientData
;
1177 PythonCmd_Error(interp
)
1181 PyErr_Fetch(&excInCmd
, &valInCmd
, &trbInCmd
);
1186 /* This is the Tcl command that acts as a wrapper for Python
1187 * function or method.
1190 PythonCmd(clientData
, interp
, argc
, argv
)
1191 ClientData clientData
;
1196 PythonCmd_ClientData
*data
= (PythonCmd_ClientData
*)clientData
;
1197 PyObject
*self
, *func
, *arg
, *res
, *tmp
;
1202 /* TBD: no error checking here since we know, via the
1203 * Tkapp_CreateCommand() that the client data is a two-tuple
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
)) {
1216 return PythonCmd_Error(interp
);
1219 res
= PyEval_CallObject(func
, arg
);
1223 return PythonCmd_Error(interp
);
1225 if (!(tmp
= PyList_New(0))) {
1227 return PythonCmd_Error(interp
);
1230 Tcl_SetResult(Tkapp_Interp(self
), AsString(res
, tmp
), TCL_VOLATILE
);
1240 PythonCmdDelete(clientData
)
1241 ClientData clientData
;
1243 PythonCmd_ClientData
*data
= (PythonCmd_ClientData
*)clientData
;
1246 Py_XDECREF(data
->self
);
1247 Py_XDECREF(data
->func
);
1255 Tkapp_CreateCommand(self
, args
)
1259 PythonCmd_ClientData
*data
;
1264 if (!PyArg_ParseTuple(args
, "sO", &cmdName
, &func
))
1266 if (!PyCallable_Check(func
)) {
1267 PyErr_SetString(PyExc_TypeError
, "command not callable");
1271 data
= PyMem_NEW(PythonCmd_ClientData
, 1);
1280 err
= Tcl_CreateCommand(Tkapp_Interp(self
), cmdName
, PythonCmd
,
1281 (ClientData
)data
, PythonCmdDelete
);
1284 PyErr_SetString(Tkinter_TclError
, "can't create Tcl command");
1296 Tkapp_DeleteCommand(self
, args
)
1303 if (!PyArg_ParseTuple(args
, "s", &cmdName
))
1306 err
= Tcl_DeleteCommand(Tkapp_Interp(self
), cmdName
);
1309 PyErr_SetString(Tkinter_TclError
, "can't delete Tcl command");
1318 #ifdef HAVE_CREATEFILEHANDLER
1319 /** File Handler **/
1321 typedef struct _fhcdata
{
1325 struct _fhcdata
*next
;
1326 } FileHandler_ClientData
;
1328 static FileHandler_ClientData
*HeadFHCD
;
1330 static FileHandler_ClientData
*
1331 NewFHCD(func
, file
, id
)
1336 FileHandler_ClientData
*p
;
1337 p
= PyMem_NEW(FileHandler_ClientData
, 1);
1354 FileHandler_ClientData
*p
, **pp
;
1357 while ((p
= *pp
) != NULL
) {
1360 Py_XDECREF(p
->func
);
1361 Py_XDECREF(p
->file
);
1370 FileHandler(clientData
, mask
)
1371 ClientData clientData
;
1374 FileHandler_ClientData
*data
= (FileHandler_ClientData
*)clientData
;
1375 PyObject
*func
, *file
, *arg
, *res
;
1381 arg
= Py_BuildValue("(Oi)", file
, (long) mask
);
1382 res
= PyEval_CallObject(func
, arg
);
1387 PyErr_Fetch(&excInCmd
, &valInCmd
, &trbInCmd
);
1395 /* Either an int >= 0 or an object with a
1396 *.fileno() method that returns an int >= 0
1400 PyObject
*meth
, *args
, *res
;
1402 if (PyInt_Check(file
)) {
1403 id
= PyInt_AsLong(file
);
1405 PyErr_SetString(PyExc_ValueError
, "invalid file id");
1408 args
= PyTuple_New(0);
1412 meth
= PyObject_GetAttrString(file
, "fileno");
1418 res
= PyEval_CallObject(meth
, args
);
1424 if (PyInt_Check(res
))
1425 id
= PyInt_AsLong(res
);
1430 PyErr_SetString(PyExc_ValueError
,
1431 "invalid fileno() return value");
1437 Tkapp_CreateFileHandler(self
, args
)
1439 PyObject
*args
; /* Is (file, mask, func) */
1441 FileHandler_ClientData
*data
;
1442 PyObject
*file
, *func
;
1446 if (!PyArg_ParseTuple(args
, "OiO", &file
, &mask
, &func
))
1448 id
= GetFileNo(file
);
1451 if (!PyCallable_Check(func
)) {
1452 PyErr_SetString(PyExc_TypeError
, "bad argument list");
1456 data
= NewFHCD(func
, file
, id
);
1460 tfile
= MAKEFHANDLE(id
);
1461 /* Ought to check for null Tcl_File object... */
1463 Tcl_CreateFileHandler(tfile
, mask
, FileHandler
, (ClientData
) data
);
1470 Tkapp_DeleteFileHandler(self
, args
)
1472 PyObject
*args
; /* Args: file */
1475 FileHandler_ClientData
*data
;
1479 if (!PyArg_ParseTuple(args
, "O", &file
))
1481 id
= GetFileNo(file
);
1487 tfile
= MAKEFHANDLE(id
);
1488 /* Ought to check for null Tcl_File object... */
1490 Tcl_DeleteFileHandler(tfile
);
1495 #endif /* HAVE_CREATEFILEHANDLER */
1498 /**** Tktt Object (timer token) ****/
1500 staticforward PyTypeObject Tktt_Type
;
1504 Tcl_TimerToken token
;
1509 Tktt_DeleteTimerHandler(self
, args
)
1513 TkttObject
*v
= (TkttObject
*)self
;
1514 PyObject
*func
= v
->func
;
1516 if (!PyArg_ParseTuple(args
, ""))
1518 if (v
->token
!= NULL
) {
1519 Tcl_DeleteTimerHandler(v
->token
);
1525 Py_DECREF(v
); /* See Tktt_New() */
1531 static PyMethodDef Tktt_methods
[] =
1533 {"deletetimerhandler", Tktt_DeleteTimerHandler
, 1},
1543 v
= PyObject_NEW(TkttObject
, &Tktt_Type
);
1551 /* Extra reference, deleted when called or when handler is deleted */
1560 TkttObject
*v
= (TkttObject
*)self
;
1561 PyObject
*func
= v
->func
;
1572 TkttObject
*v
= (TkttObject
*)self
;
1575 sprintf(buf
, "<tktimertoken at 0x%lx%s>", (long)v
,
1576 v
->func
== NULL
? ", handler deleted" : "");
1577 return PyString_FromString(buf
);
1581 Tktt_GetAttr(self
, name
)
1585 return Py_FindMethod(Tktt_methods
, self
, name
);
1588 static PyTypeObject Tktt_Type
=
1590 PyObject_HEAD_INIT(NULL
)
1592 "tktimertoken", /*tp_name */
1593 sizeof(TkttObject
), /*tp_basicsize */
1595 Tktt_Dealloc
, /*tp_dealloc */
1597 Tktt_GetAttr
, /*tp_getattr */
1600 Tktt_Repr
, /*tp_repr */
1601 0, /*tp_as_number */
1602 0, /*tp_as_sequence */
1603 0, /*tp_as_mapping */
1609 /** Timer Handler **/
1612 TimerHandler(clientData
)
1613 ClientData clientData
;
1615 TkttObject
*v
= (TkttObject
*)clientData
;
1616 PyObject
*func
= v
->func
;
1626 res
= PyEval_CallObject(func
, NULL
);
1628 Py_DECREF(v
); /* See Tktt_New() */
1632 PyErr_Fetch(&excInCmd
, &valInCmd
, &trbInCmd
);
1641 Tkapp_CreateTimerHandler(self
, args
)
1643 PyObject
*args
; /* Is (milliseconds, func) */
1649 if (!PyArg_ParseTuple(args
, "iO", &milliseconds
, &func
))
1651 if (!PyCallable_Check(func
)) {
1652 PyErr_SetString(PyExc_TypeError
, "bad argument list");
1656 v
->token
= Tcl_CreateTimerHandler(milliseconds
, TimerHandler
,
1659 return (PyObject
*) v
;
1666 Tkapp_MainLoop(self
, args
)
1672 PyThreadState
*tstate
= PyThreadState_Get();
1675 if (!PyArg_ParseTuple(args
, "|i", &threshold
))
1679 while (Tk_GetNumMainWindows() > threshold
&&
1686 Py_BEGIN_ALLOW_THREADS
1687 PyThread_acquire_lock(tcl_lock
, 1);
1688 tcl_tstate
= tstate
;
1689 result
= Tcl_DoOneEvent(TCL_DONT_WAIT
);
1691 PyThread_release_lock(tcl_lock
);
1694 Py_END_ALLOW_THREADS
1696 result
= Tcl_DoOneEvent(0);
1699 if (PyErr_CheckSignals() != 0)
1708 PyErr_Restore(excInCmd
, valInCmd
, trbInCmd
);
1709 excInCmd
= valInCmd
= trbInCmd
= NULL
;
1717 Tkapp_DoOneEvent(self
, args
)
1724 if (!PyArg_ParseTuple(args
, "|i", &flags
))
1728 rv
= Tcl_DoOneEvent(flags
);
1730 return Py_BuildValue("i", rv
);
1734 Tkapp_Quit(self
, args
)
1739 if (!PyArg_ParseTuple(args
, ""))
1748 Tkapp_InterpAddr(self
, args
)
1753 if (!PyArg_ParseTuple(args
, ""))
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},
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},
1804 /**** Tkapp Type Methods ****/
1811 Tcl_DeleteInterp(Tkapp_Interp(self
));
1818 Tkapp_GetAttr(self
, name
)
1822 return Py_FindMethod(Tkapp_methods
, self
, name
);
1825 static PyTypeObject Tkapp_Type
=
1827 PyObject_HEAD_INIT(NULL
)
1829 "tkapp", /*tp_name */
1830 sizeof(TkappObject
), /*tp_basicsize */
1832 Tkapp_Dealloc
, /*tp_dealloc */
1834 Tkapp_GetAttr
, /*tp_getattr */
1838 0, /*tp_as_number */
1839 0, /*tp_as_sequence */
1840 0, /*tp_as_mapping */
1846 /**** Tkinter Module ****/
1849 Tkinter_Create(self
, 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
)
1862 baseName
= Py_GetProgramName();
1865 if (!PyArg_ParseTuple(args
, "|zssi",
1866 &screenName
, &baseName
, &className
,
1870 return (PyObject
*) Tkapp_New(screenName
, baseName
, className
,
1874 static PyMethodDef moduleMethods
[] =
1876 {"create", Tkinter_Create
, 1},
1877 #ifdef HAVE_CREATEFILEHANDLER
1878 {"createfilehandler", Tkapp_CreateFileHandler
, 1},
1879 {"deletefilehandler", Tkapp_DeleteFileHandler
, 1},
1881 {"createtimerhandler", Tkapp_CreateTimerHandler
, 1},
1882 {"mainloop", Tkapp_MainLoop
, 1},
1883 {"dooneevent", Tkapp_DoOneEvent
, 1},
1884 {"quit", Tkapp_Quit
, 1},
1888 #ifdef WAIT_FOR_STDIN
1890 static int stdin_ready
= 0;
1894 MyFileProc(clientData
, mask
)
1902 static PyThreadState
*event_tstate
= NULL
;
1911 PyEval_RestoreThread(event_tstate
);
1916 tfile
= MAKEFHANDLE(fileno(stdin
));
1917 Tcl_CreateFileHandler(tfile
, TCL_READABLE
, MyFileProc
, NULL
);
1919 while (!errorInCmd
&& !stdin_ready
) {
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
);
1935 PyThread_release_lock(tcl_lock
);
1938 Py_END_ALLOW_THREADS
1940 result
= Tcl_DoOneEvent(0);
1947 Tcl_DeleteFileHandler(tfile
);
1951 PyErr_Restore(excInCmd
, valInCmd
, trbInCmd
);
1952 excInCmd
= valInCmd
= trbInCmd
= NULL
;
1956 PyEval_SaveThread();
1966 #ifdef WAIT_FOR_STDIN
1967 if (PyOS_InputHook
== NULL
) {
1969 event_tstate
= PyThreadState_Get();
1971 PyOS_InputHook
= EventHook
;
1979 #ifdef WAIT_FOR_STDIN
1980 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook
== EventHook
) {
1981 PyOS_InputHook
= NULL
;
1987 /* all errors will be checked in one fell swoop in init_tkinter() */
1989 ins_long(d
, name
, val
)
1994 PyObject
*v
= PyInt_FromLong(val
);
1996 PyDict_SetItemString(d
, name
, v
);
2001 ins_string(d
, name
, val
)
2006 PyObject
*v
= PyString_FromString(val
);
2008 PyDict_SetItemString(d
, name
, v
);
2019 Tkapp_Type
.ob_type
= &PyType_Type
;
2022 tcl_lock
= PyThread_allocate_lock();
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())
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
);
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
2070 Tcl_MacSetEventProc(PyMacConvertEvent
);
2072 mac_addlibresources();
2073 #endif /* GENERATINGCFM */
2074 #endif /* macintosh */
2082 ** Anyone who embeds Tcl/Tk on the Mac must define panic().
2086 panic(char * format
, ...)
2090 va_start(varg
, format
);
2092 vfprintf(stderr
, format
, varg
);
2093 (void) fflush(stderr
);
2097 Py_FatalError("Tcl/Tk panic");
2101 ** Pass events to SIOUX before passing them to Tk.
2105 PyMacConvertEvent(eventPtr
)
2106 EventRecord
*eventPtr
;
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. */
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.
2157 } else if (type
== TCL_UNIX_FD
) {
2158 fd_set readset
, writeset
, 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 )
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
;
2183 #endif /* USE_GUSI */
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
2204 init_tkinter_shlib(CFragInitBlockPtr data
)
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;
2219 ** Insert the library resources into the search path. Put them after
2220 ** the resources from the application. Again, we ignore errors.
2223 mac_addlibresources()
2225 if ( !loaded_from_shlib
)
2227 (void)FSpOpenResFile(&library_fss
, fsRdPerm
);
2230 #endif /* GENERATINGCFM */
2231 #endif /* macintosh */