| /* tkintermodule.c -- Interface to libtk.a and libtcl.a. |
| Copyright (C) 1994 Steen Lumholt */ |
| |
| #include <Python.h> |
| |
| #define PyInit_tkinter inittkinter |
| |
| #include <tcl.h> |
| #include <tk.h> |
| |
| extern char *getprogramname (); |
| |
| /* Internal declarations from tkInt.h. */ |
| extern int tk_NumMainWindows; |
| extern struct { Tk_Window win; } *tkMainWindowList; |
| |
| /**** Tkapp Object Declaration ****/ |
| |
| staticforward PyTypeObject Tkapp_Type; |
| |
| typedef struct |
| { |
| PyObject_HEAD |
| Tcl_Interp *interp; |
| Tk_Window tkwin; |
| } |
| TkappObject; |
| |
| #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type) |
| #define Tkapp_Tkwin(v) (((TkappObject *) (v))->tkwin) |
| #define Tkapp_Interp(v) (((TkappObject *) (v))->interp) |
| #define Tkapp_Result(v) (((TkappObject *) (v))->interp->result) |
| |
| #define DEBUG_REFCNT(v) (printf ("DEBUG: id=%p, refcnt=%i\n", \ |
| (void *) v, ((PyObject *) v)->ob_refcnt)) |
| |
| /**** Error Handling ****/ |
| |
| static PyObject *Tkinter_TclError; |
| static int quitMainLoop = 0; |
| static int errorInCmd = 0; |
| static PyObject *excInCmd; |
| static PyObject *valInCmd; |
| static PyObject *trbInCmd; |
| |
| static PyObject * |
| Tkinter_Error (v) |
| PyObject *v; |
| { |
| PyErr_SetString (Tkinter_TclError, Tkapp_Result (v)); |
| return NULL; |
| } |
| |
| int |
| PythonCmd_Error (interp) |
| Tcl_Interp *interp; |
| { |
| errorInCmd = 1; |
| PyErr_Fetch (&excInCmd, &valInCmd, &trbInCmd); |
| return TCL_ERROR; |
| } |
| |
| /**** Utils ****/ |
| |
| static char * |
| AsString (value, tmp) |
| PyObject *value; |
| PyObject *tmp; |
| { |
| if (PyString_Check (value)) |
| return PyString_AsString (value); |
| else |
| { |
| PyObject *v; |
| |
| v = PyObject_Str (value); |
| PyList_Append (tmp, v); |
| Py_DECREF (v); |
| return PyString_AsString (v); |
| } |
| } |
| |
| #define ARGSZ 64 |
| |
| static char * |
| Merge (args) |
| PyObject *args; |
| { |
| PyObject *tmp; |
| char *argvStore[ARGSZ]; |
| char **argv; |
| int fvStore[ARGSZ]; |
| int *fv; |
| int argc; |
| char *res; |
| int i; |
| |
| tmp = PyList_New (0); |
| argv = argvStore; |
| fv = fvStore; |
| |
| if (!PyTuple_Check (args)) |
| { |
| argc = 1; |
| fv[0] = 0; |
| argv[0] = AsString (args, tmp); |
| } |
| else |
| { |
| PyObject *v; |
| |
| if (PyTuple_Size (args) > ARGSZ) |
| { |
| argv = (char **) malloc (PyTuple_Size (args) * sizeof (char *)); |
| fv = (int *) malloc (PyTuple_Size (args) * sizeof (int)); |
| if (argv == NULL || fv == NULL) |
| PyErr_NoMemory (); |
| } |
| |
| argc = PyTuple_Size (args); |
| for (i = 0; i < argc; i++) |
| { |
| v = PyTuple_GetItem (args, i); |
| if (PyTuple_Check (v)) |
| { |
| fv[i] = 1; |
| argv[i] = Merge (v); |
| } |
| else if (v == Py_None) |
| { |
| argc = i; |
| break; |
| } |
| else |
| { |
| fv[i] = 0; |
| argv[i] = AsString (v, tmp); |
| } |
| } |
| } |
| |
| res = Tcl_Merge (argc, argv); |
| |
| Py_DECREF (tmp); |
| for (i = 0; i < argc; i++) |
| if (fv[i]) free (argv[i]); |
| if (argv != argvStore) |
| free (argv); |
| if (fv != fvStore) |
| free (fv); |
| |
| return res; |
| } |
| |
| static PyObject * |
| Split (self, list) |
| PyObject *self; |
| char *list; |
| { |
| int argc; |
| char **argv; |
| PyObject *v; |
| |
| if (list == NULL) |
| { |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| if (Tcl_SplitList (Tkapp_Interp (self), list, &argc, &argv) == TCL_ERROR) |
| return Tkinter_Error (self); |
| |
| if (argc == 0) |
| v = PyString_FromString (""); |
| else if (argc == 1) |
| v = PyString_FromString (argv[0]); |
| else |
| { |
| int i; |
| |
| v = PyTuple_New (argc); |
| for (i = 0; i < argc; i++) |
| PyTuple_SetItem (v, i, Split (self, argv[i])); |
| } |
| |
| free (argv); |
| return v; |
| } |
| |
| /**** Tkapp Object ****/ |
| |
| #ifndef WITH_APPINIT |
| int |
| Tcl_AppInit (interp) |
| Tcl_Interp *interp; |
| { |
| Tk_Window main; |
| main = Tk_MainWindow(interp); |
| if (Tcl_Init (interp) == TCL_ERROR) { |
| fprintf(stderr, "Tcl_Init error: %s\n", interp->result); |
| return TCL_ERROR; |
| } |
| if (Tk_Init (interp) == TCL_ERROR) { |
| fprintf(stderr, "Tk_Init error: %s\n", interp->result); |
| return TCL_ERROR; |
| } |
| return TCL_OK; |
| } |
| #endif /* !WITH_APPINIT */ |
| |
| /* Initialize the Tk application; see the `main' function in |
| `tkMain.c'. */ |
| static TkappObject * |
| Tkapp_New (screenName, baseName, className, interactive) |
| char *screenName; |
| char *baseName; |
| char *className; |
| int interactive; |
| { |
| TkappObject *v; |
| |
| v = PyObject_NEW (TkappObject, &Tkapp_Type); |
| if (v == NULL) |
| return NULL; |
| |
| v->interp = Tcl_CreateInterp (); |
| v->tkwin = Tk_CreateMainWindow (v->interp, screenName, |
| baseName, className); |
| if (v->tkwin == NULL) |
| return (TkappObject *) Tkinter_Error ((PyObject *) v); |
| |
| Tk_GeometryRequest (v->tkwin, 200, 200); |
| |
| if (screenName != NULL) |
| Tcl_SetVar2 (v->interp, "env", "DISPLAY", screenName, TCL_GLOBAL_ONLY); |
| |
| if (interactive) |
| Tcl_SetVar (v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY); |
| else |
| Tcl_SetVar (v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY); |
| |
| if (Tcl_AppInit (v->interp) != TCL_OK) |
| { |
| PyErr_SetString (Tkinter_TclError, "Tcl_AppInit failed"); /* XXX */ |
| return NULL; |
| } |
| |
| return v; |
| } |
| |
| /** Tcl Eval **/ |
| |
| static PyObject * |
| Tkapp_Call (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *cmd; |
| |
| cmd = Merge (args); |
| if (Tcl_Eval (Tkapp_Interp (self), cmd) == TCL_ERROR) |
| { |
| free (cmd); |
| return Tkinter_Error (self); |
| } |
| |
| free (cmd); |
| return PyString_FromString (Tkapp_Result (self)); |
| } |
| |
| static PyObject * |
| Tkapp_GlobalCall (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *cmd; |
| |
| cmd = Merge (args); |
| if (Tcl_GlobalEval (Tkapp_Interp (self), cmd) == TCL_ERROR) |
| { |
| free (cmd); |
| return Tkinter_Error (self); |
| } |
| |
| free (cmd); |
| return PyString_FromString (Tkapp_Result (self)); |
| } |
| |
| static PyObject * |
| Tkapp_Eval (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *script; |
| |
| if (!PyArg_Parse (args, "s", &script)) |
| return NULL; |
| |
| if (Tcl_Eval (Tkapp_Interp (self), script) == TCL_ERROR) |
| return Tkinter_Error (self); |
| |
| return PyString_FromString (Tkapp_Result (self)); |
| } |
| |
| static PyObject * |
| Tkapp_GlobalEval (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *script; |
| |
| if (!PyArg_Parse (args, "s", &script)) |
| return NULL; |
| |
| if (Tcl_GlobalEval (Tkapp_Interp (self), script) == TCL_ERROR) |
| return Tkinter_Error (self); |
| |
| return PyString_FromString (Tkapp_Result (self)); |
| } |
| |
| static PyObject * |
| Tkapp_EvalFile (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *fileName; |
| |
| if (!PyArg_Parse (args, "s", &fileName)) |
| return NULL; |
| |
| if (Tcl_EvalFile (Tkapp_Interp (self), fileName) == TCL_ERROR) |
| return Tkinter_Error (self); |
| |
| return PyString_FromString (Tkapp_Result (self)); |
| } |
| |
| static PyObject * |
| Tkapp_Record (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *script; |
| |
| if (!PyArg_Parse (args, "s", &script)) |
| return NULL; |
| |
| if (Tcl_RecordAndEval (Tkapp_Interp (self), |
| script, TCL_NO_EVAL) == TCL_ERROR) |
| return Tkinter_Error (self); |
| |
| return PyString_FromString (Tkapp_Result (self)); |
| } |
| |
| static PyObject * |
| Tkapp_AddErrorInfo (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *msg; |
| |
| if (!PyArg_Parse (args, "s", &msg)) |
| return NULL; |
| Tcl_AddErrorInfo (Tkapp_Interp (self), msg); |
| |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| /** Tcl Variable **/ |
| |
| static PyObject * |
| SetVar (self, args, flags) |
| PyObject *self; |
| PyObject *args; |
| int flags; |
| { |
| char *name1, *name2, *ok; |
| PyObject *newValue; |
| PyObject *tmp; |
| |
| tmp = PyList_New (0); |
| |
| if (PyArg_Parse (args, "(sO)", &name1, &newValue)) |
| ok = Tcl_SetVar (Tkapp_Interp (self), name1, |
| AsString (newValue, tmp), flags); /* XXX Merge? */ |
| else if (PyArg_Parse (args, "(ssO)", &name1, &name2, &newValue)) |
| ok = Tcl_SetVar2 (Tkapp_Interp (self), name1, name2, |
| AsString (newValue, tmp), flags); |
| else |
| { |
| Py_DECREF (tmp); |
| return NULL; |
| } |
| Py_DECREF (tmp); |
| |
| if (!ok) |
| return Tkinter_Error (self); |
| |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| static PyObject * |
| Tkapp_SetVar (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| return SetVar (self, args, TCL_LEAVE_ERR_MSG); |
| } |
| |
| static PyObject * |
| Tkapp_GlobalSetVar (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| return SetVar (self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); |
| } |
| |
| static PyObject * |
| GetVar (self, args, flags) |
| PyObject *self; |
| PyObject *args; |
| int flags; |
| { |
| char *name1, *name2, *s; |
| |
| if (PyArg_Parse (args, "s", &name1)) |
| s = Tcl_GetVar (Tkapp_Interp (self), name1, flags); |
| else if (PyArg_Parse (args, "(ss)", &name1, &name2)) |
| s = Tcl_GetVar2 (Tkapp_Interp (self), name1, name2, flags); |
| else |
| return NULL; |
| |
| if (s == NULL) |
| return Tkinter_Error (self); |
| |
| return PyString_FromString (s); |
| } |
| |
| static PyObject * |
| Tkapp_GetVar (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| return GetVar (self, args, TCL_LEAVE_ERR_MSG); |
| } |
| |
| static PyObject * |
| Tkapp_GlobalGetVar (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| return GetVar (self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); |
| } |
| |
| static PyObject * |
| UnsetVar (self, args, flags) |
| PyObject *self; |
| PyObject *args; |
| int flags; |
| { |
| char *name1, *name2; |
| int code; |
| |
| if (PyArg_Parse (args, "s", &name1)) |
| code = Tcl_UnsetVar (Tkapp_Interp (self), name1, flags); |
| else if (PyArg_Parse (args, "(ss)", &name1, &name2)) |
| code = Tcl_UnsetVar2 (Tkapp_Interp (self), name1, name2, flags); |
| else |
| return NULL; |
| |
| if (code == TCL_ERROR) |
| return Tkinter_Error (self); |
| |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| static PyObject * |
| Tkapp_UnsetVar (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| return UnsetVar (self, args, TCL_LEAVE_ERR_MSG); |
| } |
| |
| static PyObject * |
| Tkapp_GlobalUnsetVar (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| return UnsetVar (self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); |
| } |
| |
| /** Tcl to Python **/ |
| |
| static PyObject * |
| Tkapp_GetInt (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *s; |
| int v; |
| |
| if (!PyArg_Parse (args, "s", &s)) |
| return NULL; |
| if (Tcl_GetInt (Tkapp_Interp (self), s, &v) == TCL_ERROR) |
| return Tkinter_Error (self); |
| return Py_BuildValue ("i", v); |
| } |
| |
| static PyObject * |
| Tkapp_GetDouble (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *s; |
| double v; |
| |
| if (!PyArg_Parse (args, "s", &s)) |
| return NULL; |
| if (Tcl_GetDouble (Tkapp_Interp (self), s, &v) == TCL_ERROR) |
| return Tkinter_Error (self); |
| return Py_BuildValue ("d", v); |
| } |
| |
| static PyObject * |
| Tkapp_GetBoolean (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *s; |
| int v; |
| |
| if (!PyArg_Parse (args, "s", &s)) |
| return NULL; |
| if (Tcl_GetBoolean (Tkapp_Interp (self), s, &v) == TCL_ERROR) |
| return Tkinter_Error (self); |
| return Py_BuildValue ("i", v); |
| } |
| |
| static PyObject * |
| Tkapp_ExprString (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *s; |
| |
| if (!PyArg_Parse (args, "s", &s)) |
| return NULL; |
| if (Tcl_ExprString (Tkapp_Interp (self), s) == TCL_ERROR) |
| return Tkinter_Error (self); |
| return Py_BuildValue ("s", Tkapp_Result (self)); |
| } |
| |
| static PyObject * |
| Tkapp_ExprLong (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *s; |
| long v; |
| |
| if (!PyArg_Parse (args, "s", &s)) |
| return NULL; |
| if (Tcl_ExprLong (Tkapp_Interp (self), s, &v) == TCL_ERROR) |
| return Tkinter_Error (self); |
| return Py_BuildValue ("l", v); |
| } |
| |
| static PyObject * |
| Tkapp_ExprDouble (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *s; |
| double v; |
| |
| if (!PyArg_Parse (args, "s", &s)) |
| return NULL; |
| if (Tcl_ExprDouble (Tkapp_Interp (self), s, &v) == TCL_ERROR) |
| return Tkinter_Error (self); |
| return Py_BuildValue ("d", v); |
| } |
| |
| static PyObject * |
| Tkapp_ExprBoolean (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *s; |
| int v; |
| |
| if (!PyArg_Parse (args, "s", &s)) |
| return NULL; |
| if (Tcl_ExprBoolean (Tkapp_Interp (self), s, &v) == TCL_ERROR) |
| return Tkinter_Error (self); |
| return Py_BuildValue ("i", v); |
| } |
| |
| static PyObject * |
| Tkapp_SplitList (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *list; |
| int argc; |
| char **argv; |
| PyObject *v; |
| int i; |
| |
| if (!PyArg_Parse (args, "s", &list)) |
| return NULL; |
| |
| if (Tcl_SplitList (Tkapp_Interp (self), list, &argc, &argv) == TCL_ERROR) |
| return Tkinter_Error (self); |
| |
| v = PyTuple_New (argc); |
| for (i = 0; i < argc; i++) |
| PyTuple_SetItem (v, i, PyString_FromString (argv[i])); |
| |
| free (argv); |
| return v; |
| } |
| |
| static PyObject * |
| Tkapp_Split (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *list; |
| |
| if (!PyArg_Parse (args, "s", &list)) |
| return NULL; |
| return Split (self, list); |
| } |
| |
| static PyObject * |
| Tkapp_Merge (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *s; |
| PyObject *v; |
| |
| s = Merge (args); |
| v = PyString_FromString (s); |
| free (s); |
| return v; |
| } |
| |
| /** Tcl Command **/ |
| |
| /* This is the Tcl command that acts as a wrapper for Python |
| function or method. */ |
| static int |
| PythonCmd (clientData, interp, argc, argv) |
| ClientData clientData; /* Is (self, func) */ |
| Tcl_Interp *interp; |
| int argc; |
| char *argv[]; |
| { |
| PyObject *self, *func, *arg, *res, *tmp; |
| int i; |
| |
| self = PyTuple_GetItem ((PyObject *) clientData, 0); |
| func = PyTuple_GetItem ((PyObject *) clientData, 1); |
| |
| /* Create argument list (argv1, ..., argvN) */ |
| arg = PyTuple_New (argc - 1); |
| for (i = 0; i < (argc - 1); i++) |
| PyTuple_SetItem (arg, i, PyString_FromString (argv[i + 1])); |
| |
| res = PyEval_CallObject (func, arg); |
| Py_DECREF (arg); |
| |
| if (res == NULL) |
| return PythonCmd_Error (interp); |
| |
| tmp = PyList_New (0); |
| Tcl_SetResult (Tkapp_Interp (self), AsString (res, tmp), TCL_VOLATILE); |
| Py_DECREF (res); |
| Py_DECREF (tmp); |
| |
| return TCL_OK; |
| } |
| |
| static void |
| PythonCmdDelete (clientData) |
| ClientData clientData; /* Is (self, func) */ |
| { |
| Py_DECREF ((PyObject *) clientData); |
| } |
| |
| static PyObject * |
| Tkapp_CreateCommand (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *cmdName; |
| PyObject *data; |
| PyObject *func; |
| |
| /* Args is: (cmdName, func) */ |
| if (!PyTuple_Check (args) |
| || !(PyTuple_Size (args) == 2) |
| || !PyString_Check (PyTuple_GetItem (args, 0)) |
| || !PyCallable_Check (PyTuple_GetItem (args, 1))) |
| { |
| PyErr_SetString (PyExc_TypeError, "bad argument list"); |
| return NULL; |
| } |
| |
| cmdName = PyString_AsString (PyTuple_GetItem (args, 0)); |
| func = PyTuple_GetItem (args, 1); |
| |
| data = PyTuple_New (2); /* ClientData is: (self, func) */ |
| |
| Py_INCREF (self); |
| PyTuple_SetItem (data, 0, self); |
| |
| Py_INCREF (func); |
| PyTuple_SetItem (data, 1, func); |
| |
| Tcl_CreateCommand (Tkapp_Interp (self), cmdName, PythonCmd, |
| (ClientData) data, PythonCmdDelete); |
| |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| static PyObject * |
| Tkapp_DeleteCommand (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *cmdName; |
| |
| if (!PyArg_Parse (args, "s", &cmdName)) |
| return NULL; |
| if (Tcl_DeleteCommand (Tkapp_Interp (self), cmdName) == -1) |
| { |
| PyErr_SetString (Tkinter_TclError, "can't delete Tcl command"); |
| return NULL; |
| } |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| /** File Handler **/ |
| |
| static void |
| FileHandler (clientData, mask) |
| ClientData clientData; /* Is: (func, file) */ |
| int mask; |
| { |
| PyObject *func, *file, *arg, *res; |
| |
| func = PyTuple_GetItem ((PyObject *) clientData, 0); |
| file = PyTuple_GetItem ((PyObject *) clientData, 1); |
| |
| arg = Py_BuildValue ("(Oi)", file, (long) mask); |
| res = PyEval_CallObject (func, arg); |
| Py_DECREF (arg); |
| if (res == NULL) |
| { |
| errorInCmd = 1; |
| PyErr_Fetch (&excInCmd, &valInCmd, &trbInCmd); |
| } |
| Py_XDECREF (res); |
| } |
| |
| static int |
| GetFileNo (file) |
| PyObject *file; /* Either an int >= 0 or an object with a |
| .fileno() method that returns an int >= 0 */ |
| { |
| PyObject *meth, *args, *res; |
| int id; |
| if (PyInt_Check(file)) { |
| id = PyInt_AsLong(file); |
| if (id < 0) |
| PyErr_SetString(PyExc_ValueError, "invalid file id"); |
| return id; |
| } |
| meth = PyObject_GetAttrString(file, "fileno"); |
| if (meth == NULL) |
| return -1; |
| args = PyTuple_New(0); |
| if (args == NULL) |
| return -1; |
| res = PyEval_CallObject(meth, args); |
| Py_DECREF(args); |
| Py_DECREF(meth); |
| if (res == NULL) |
| return -1; |
| if (PyInt_Check(res)) |
| id = PyInt_AsLong(res); |
| else |
| id = -1; |
| if (id < 0) |
| PyErr_SetString(PyExc_ValueError, |
| "invalid fileno() return value"); |
| Py_DECREF(res); |
| return id; |
| } |
| |
| static PyObject * |
| Tkapp_CreateFileHandler (self, args) |
| PyObject *self; |
| PyObject *args; /* Is (file, mask, func) */ |
| { |
| PyObject *file, *func, *data; |
| int mask, id; |
| |
| if (!PyArg_Parse (args, "(OiO)", &file, &mask, &func)) |
| return NULL; |
| id = GetFileNo (file); |
| if (id < 0) |
| return NULL; |
| if (!PyCallable_Check(func)) |
| { |
| PyErr_SetString (PyExc_TypeError, "bad argument list"); |
| return NULL; |
| } |
| |
| /* ClientData is: (func, file) */ |
| data = Py_BuildValue ("(OO)", func, file); |
| |
| Tk_CreateFileHandler (id, mask, FileHandler, (ClientData) data); |
| /* XXX fileHandlerDict */ |
| |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| static PyObject * |
| Tkapp_DeleteFileHandler (self, args) |
| PyObject *self; |
| PyObject *args; /* Args: file */ |
| { |
| PyObject *file; |
| int id; |
| |
| if (!PyArg_Parse (args, "O", &file)) |
| return NULL; |
| id = GetFileNo (file); |
| if (id < 0) |
| return NULL; |
| |
| Tk_DeleteFileHandler (id); |
| /* XXX fileHandlerDict */ |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| /**** Tktt Object (timer token) ****/ |
| |
| staticforward PyTypeObject Tktt_Type; |
| |
| typedef struct |
| { |
| PyObject_HEAD |
| Tk_TimerToken token; |
| PyObject *func; |
| } |
| TkttObject; |
| |
| static PyObject * |
| Tktt_DeleteTimerHandler (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| TkttObject *v = (TkttObject *) self; |
| |
| if (!PyArg_Parse (args, "")) |
| return NULL; |
| if (v->func != NULL) |
| { |
| Tk_DeleteTimerHandler (v->token); |
| PyMem_DEL (v->func); |
| v->func = NULL; |
| } |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| static PyMethodDef Tktt_methods[] = |
| { |
| {"deletetimerhandler", Tktt_DeleteTimerHandler}, |
| {NULL, NULL} |
| }; |
| |
| static TkttObject * |
| Tktt_New (token, func) |
| Tk_TimerToken token; |
| PyObject *func; |
| { |
| TkttObject *v; |
| |
| v = PyObject_NEW (TkttObject, &Tktt_Type); |
| if (v == NULL) |
| return NULL; |
| |
| v->token = token; |
| v->func = func; |
| Py_INCREF (v->func); |
| return v; |
| } |
| |
| static void |
| Tktt_Dealloc (self) |
| PyObject *self; |
| { |
| PyMem_DEL (self); |
| } |
| |
| static int |
| Tktt_Print (self, fp, flags) |
| PyObject *self; |
| FILE *fp; |
| int flags; |
| { |
| TkttObject *v = (TkttObject *) self; |
| |
| fprintf(fp, "<tktimertoken at 0x%x%s>", v, |
| v->func == NULL ? ", handler deleted" : ""); |
| return 0; |
| } |
| |
| static PyObject * |
| Tktt_GetAttr (self, name) |
| PyObject *self; |
| char *name; |
| { |
| return Py_FindMethod (Tktt_methods, self, name); |
| } |
| |
| static PyTypeObject Tktt_Type = |
| { |
| PyObject_HEAD_INIT (&PyType_Type) |
| 0, /*ob_size */ |
| "tktimertoken", /*tp_name */ |
| sizeof (TkttObject), /*tp_basicsize */ |
| 0, /*tp_itemsize */ |
| Tktt_Dealloc, /*tp_dealloc */ |
| Tktt_Print, /*tp_print */ |
| Tktt_GetAttr, /*tp_getattr */ |
| 0, /*tp_setattr */ |
| 0, /*tp_compare */ |
| 0, /*tp_repr */ |
| 0, /*tp_as_number */ |
| 0, /*tp_as_sequence */ |
| 0, /*tp_as_mapping */ |
| 0, /*tp_hash */ |
| }; |
| |
| /** Timer Handler **/ |
| |
| static void |
| TimerHandler (clientData) |
| ClientData clientData; |
| { |
| PyObject *func = (PyObject *) clientData; |
| PyObject *arg, *res; |
| |
| arg = PyTuple_New (0); |
| res = PyEval_CallObject (func, arg); |
| Py_DECREF (arg); |
| if (res == NULL) |
| { |
| errorInCmd = 1; |
| PyErr_Fetch (&excInCmd, &valInCmd, &trbInCmd); |
| } |
| else |
| Py_DECREF (res); |
| } |
| |
| static PyObject * |
| Tkapp_CreateTimerHandler (self, args) |
| PyObject *self; |
| PyObject *args; /* Is (milliseconds, func) */ |
| { |
| int milliseconds; |
| PyObject *func; |
| Tk_TimerToken token; |
| |
| if (!PyArg_Parse (args, "(iO)", &milliseconds, &func)) |
| return NULL; |
| if (!PyCallable_Check(func)) |
| { |
| PyErr_SetString (PyExc_TypeError, "bad argument list"); |
| return NULL; |
| } |
| token = Tk_CreateTimerHandler(milliseconds, TimerHandler, (ClientData) func); |
| return (PyObject *) Tktt_New (token, func); |
| } |
| |
| /** Event Loop **/ |
| |
| static PyObject * |
| Tkapp_MainLoop (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| int threshold = 0; |
| |
| if (!PyArg_ParseTuple (args, "|i", &threshold)) |
| return NULL; |
| |
| quitMainLoop = 0; |
| while (tk_NumMainWindows > threshold && !quitMainLoop && !errorInCmd) |
| { |
| if (PyOS_InterruptOccurred ()) |
| { |
| PyErr_SetNone (PyExc_KeyboardInterrupt); |
| return NULL; |
| } |
| Tk_DoOneEvent (0); |
| } |
| |
| if (errorInCmd) |
| { |
| errorInCmd = 0; |
| PyErr_Restore (excInCmd, valInCmd, trbInCmd); |
| excInCmd = valInCmd = trbInCmd = NULL; |
| return NULL; |
| } |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| static PyObject * |
| Tkapp_DoOneEvent (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| int flags = TK_ALL_EVENTS; |
| int rv; |
| |
| if (!PyArg_ParseTuple (args, "|i", &flags)) |
| return NULL; |
| rv = Tk_DoOneEvent(flags); |
| return Py_BuildValue ("i", rv); |
| } |
| |
| static PyObject * |
| Tkapp_Quit (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| |
| if (!PyArg_Parse (args, "")) |
| return NULL; |
| quitMainLoop = 1; |
| Py_INCREF (Py_None); |
| return Py_None; |
| } |
| |
| /**** Tkapp Method List ****/ |
| |
| static PyMethodDef Tkapp_methods[] = |
| { |
| {"call", Tkapp_Call}, |
| {"globalcall", Tkapp_GlobalCall}, |
| {"eval", Tkapp_Eval}, |
| {"globaleval", Tkapp_GlobalEval}, |
| {"evalfile", Tkapp_EvalFile}, |
| {"record", Tkapp_Record}, |
| {"adderrorinfo", Tkapp_AddErrorInfo}, |
| {"setvar", Tkapp_SetVar}, |
| {"globalsetvar", Tkapp_GlobalSetVar}, |
| {"getvar", Tkapp_GetVar}, |
| {"globalgetvar", Tkapp_GlobalGetVar}, |
| {"unsetvar", Tkapp_UnsetVar}, |
| {"globalunsetvar", Tkapp_GlobalUnsetVar}, |
| {"getint", Tkapp_GetInt}, |
| {"getdouble", Tkapp_GetDouble}, |
| {"getboolean", Tkapp_GetBoolean}, |
| {"exprstring", Tkapp_ExprString}, |
| {"exprlong", Tkapp_ExprLong}, |
| {"exprdouble", Tkapp_ExprDouble}, |
| {"exprboolean", Tkapp_ExprBoolean}, |
| {"splitlist", Tkapp_SplitList}, |
| {"split", Tkapp_Split}, |
| {"merge", Tkapp_Merge}, |
| {"createcommand", Tkapp_CreateCommand}, |
| {"deletecommand", Tkapp_DeleteCommand}, |
| {"createfilehandler", Tkapp_CreateFileHandler}, |
| {"deletefilehandler", Tkapp_DeleteFileHandler}, |
| {"createtimerhandler", Tkapp_CreateTimerHandler}, |
| {"mainloop", Tkapp_MainLoop, 1}, |
| {"dooneevent", Tkapp_DoOneEvent, 1}, |
| {"quit", Tkapp_Quit}, |
| {NULL, NULL} |
| }; |
| |
| /**** Tkapp Type Methods ****/ |
| |
| static void |
| Tkapp_Dealloc (self) |
| PyObject *self; |
| { |
| Tk_DestroyWindow (Tkapp_Tkwin (self)); |
| Tcl_DeleteInterp (Tkapp_Interp (self)); |
| PyMem_DEL (self); |
| } |
| |
| static PyObject * |
| Tkapp_GetAttr (self, name) |
| PyObject *self; |
| char *name; |
| { |
| return Py_FindMethod (Tkapp_methods, self, name); |
| } |
| |
| static PyTypeObject Tkapp_Type = |
| { |
| PyObject_HEAD_INIT (&PyType_Type) |
| 0, /*ob_size */ |
| "tkapp", /*tp_name */ |
| sizeof (TkappObject), /*tp_basicsize */ |
| 0, /*tp_itemsize */ |
| Tkapp_Dealloc, /*tp_dealloc */ |
| 0, /*tp_print */ |
| Tkapp_GetAttr, /*tp_getattr */ |
| 0, /*tp_setattr */ |
| 0, /*tp_compare */ |
| 0, /*tp_repr */ |
| 0, /*tp_as_number */ |
| 0, /*tp_as_sequence */ |
| 0, /*tp_as_mapping */ |
| 0, /*tp_hash */ |
| }; |
| |
| /**** Tkinter Module ****/ |
| |
| static PyObject * |
| Tkinter_Create (self, args) |
| PyObject *self; |
| PyObject *args; |
| { |
| char *screenName = NULL; |
| char *baseName = NULL; |
| char *className = NULL; |
| int interactive = 0; |
| |
| baseName = strrchr (getprogramname (), '/'); |
| if (baseName != NULL) |
| baseName++; |
| else |
| baseName = getprogramname (); |
| className = "Tk"; |
| |
| if (!PyArg_ParseTuple (args, "|zssi", |
| &screenName, &baseName, &className, &interactive)) |
| return NULL; |
| |
| return (PyObject *) Tkapp_New (screenName, baseName, className, |
| interactive); |
| } |
| |
| static PyMethodDef moduleMethods[] = |
| { |
| {"create", Tkinter_Create, 1}, |
| {"createfilehandler", Tkapp_CreateFileHandler, 0}, |
| {"deletefilehandler", Tkapp_DeleteFileHandler, 0}, |
| {"createtimerhandler", Tkapp_CreateTimerHandler, 0}, |
| {"mainloop", Tkapp_MainLoop, 1}, |
| {"dooneevent", Tkapp_DoOneEvent, 1}, |
| {"quit", Tkapp_Quit}, |
| {NULL, NULL} |
| }; |
| |
| #undef WITH_READLINE /* XXX */ |
| #ifdef WITH_READLINE |
| static int |
| EventHook () |
| { |
| if (errorInCmd) /* XXX Reset tty */ |
| { |
| errorInCmd = 0; |
| PyErr_Restore (excInCmd, valInCmd, trbInCmd); |
| excInCmd = valInCmd = trbInCmd = NULL; |
| PyErr_Print (); |
| } |
| if (tk_NumMainWindows > 0) |
| Tk_DoOneEvent (TK_DONT_WAIT); |
| return 0; |
| } |
| #endif /* WITH_READLINE */ |
| |
| static void |
| Tkinter_Cleanup () |
| { |
| /* This segfault with Tk 4.0 beta and seems unnecessary there as well */ |
| #if TK_MAJOR_VERSION < 4 |
| /* XXX rl_deprep_terminal is static, damned! */ |
| while (tkMainWindowList != 0) |
| Tk_DestroyWindow (tkMainWindowList->win); |
| #endif |
| } |
| |
| void |
| PyInit_tkinter () |
| { |
| static inited = 0; |
| |
| #ifdef WITH_READLINE |
| extern int (*rl_event_hook) (); |
| #endif /* WITH_READLINE */ |
| PyObject *m, *d, *v; |
| |
| m = Py_InitModule ("tkinter", moduleMethods); |
| |
| d = PyModule_GetDict (m); |
| Tkinter_TclError = Py_BuildValue ("s", "TclError"); |
| PyDict_SetItemString (d, "TclError", Tkinter_TclError); |
| |
| v = Py_BuildValue ("i", TK_READABLE); |
| PyDict_SetItemString (d, "READABLE", v); |
| v = Py_BuildValue ("i", TK_WRITABLE); |
| PyDict_SetItemString (d, "WRITABLE", v); |
| v = Py_BuildValue ("i", TK_EXCEPTION); |
| PyDict_SetItemString (d, "EXCEPTION", v); |
| v = Py_BuildValue ("i", TK_X_EVENTS); |
| PyDict_SetItemString (d, "X_EVENTS", v); |
| v = Py_BuildValue ("i", TK_FILE_EVENTS); |
| PyDict_SetItemString (d, "FILE_EVENTS", v); |
| v = Py_BuildValue ("i", TK_TIMER_EVENTS); |
| PyDict_SetItemString (d, "TIMER_EVENTS", v); |
| v = Py_BuildValue ("i", TK_IDLE_EVENTS); |
| PyDict_SetItemString (d, "IDLE_EVENTS", v); |
| v = Py_BuildValue ("i", TK_ALL_EVENTS); |
| PyDict_SetItemString (d, "ALL_EVENTS", v); |
| v = Py_BuildValue ("i", TK_DONT_WAIT); |
| PyDict_SetItemString (d, "DONT_WAIT", v); |
| v = Py_BuildValue ("s", TK_VERSION); |
| PyDict_SetItemString (d, "TK_VERSION", v); |
| v = Py_BuildValue ("s", TCL_VERSION); |
| PyDict_SetItemString (d, "TCL_VERSION", v); |
| |
| #ifdef WITH_READLINE |
| rl_event_hook = EventHook; |
| #endif /* WITH_READLINE */ |
| |
| if (!inited) |
| { |
| inited = 1; |
| if (Py_AtExit (Tkinter_Cleanup) != 0) |
| fprintf(stderr, |
| "Tkinter: warning: cleanup procedure not registered\n"); |
| } |
| |
| if (PyErr_Occurred ()) |
| Py_FatalError ("can't initialize module tkinter"); |
| } |