Commit 7bf15648 authored by Guido van Rossum's avatar Guido van Rossum

Use a different implementation of EventHook(). The new version

registers an input file handler for stdin with Tcl and handles Tcl
events until something is available on stdin; it then deletes the
handler and returns from EventHook().

This works with or without GNU readline, and doesn't busy-wait.

It still doesn't work for Mac or Windows :-(
parent 6a50ba82
...@@ -83,6 +83,24 @@ PERFORMANCE OF THIS SOFTWARE. ...@@ -83,6 +83,24 @@ PERFORMANCE OF THIS SOFTWARE.
#define HAVE_CREATEFILEHANDLER #define HAVE_CREATEFILEHANDLER
#endif #endif
#ifdef MS_WINDOWS
#define FHANDLETYPE TCL_WIN_SOCKET
#else
#define FHANDLETYPE TCL_UNIX_FD
#endif
#if TKMAJORMINOR < 8000
#define FHANDLE Tcl_File
#define MAKEFHANDLE(fd) Tcl_GetFile((ClientData)(fd), FHANDLETYPE)
#else
#define FHANDLE int
#define MAKEFHANDLE(fd) (fd)
#endif
#if defined(HAVE_CREATEFILEHANDLER) && !defined(MS_WINDOWS)
#define WAIT_FOR_STDIN
#endif
extern int Tk_GetNumMainWindows(); extern int Tk_GetNumMainWindows();
#ifdef macintosh #ifdef macintosh
...@@ -342,6 +360,10 @@ Tcl_AppInit(interp) ...@@ -342,6 +360,10 @@ Tcl_AppInit(interp)
/* Initialize the Tk application; see the `main' function in /* Initialize the Tk application; see the `main' function in
* `tkMain.c'. * `tkMain.c'.
*/ */
static void EnableEventHook(); /* Forward */
static void DisableEventHook(); /* Forward */
static TkappObject * static TkappObject *
Tkapp_New(screenName, baseName, className, interactive) Tkapp_New(screenName, baseName, className, interactive)
char *screenName; char *screenName;
...@@ -392,6 +414,8 @@ Tkapp_New(screenName, baseName, className, interactive) ...@@ -392,6 +414,8 @@ Tkapp_New(screenName, baseName, className, interactive)
if (Tcl_AppInit(v->interp) != TCL_OK) if (Tcl_AppInit(v->interp) != TCL_OK)
return (TkappObject *)Tkinter_Error(v); return (TkappObject *)Tkinter_Error(v);
EnableEventHook();
return v; return v;
} }
...@@ -1128,9 +1152,7 @@ Tkapp_CreateFileHandler(self, args) ...@@ -1128,9 +1152,7 @@ Tkapp_CreateFileHandler(self, args)
PyObject *file, *func, *data; PyObject *file, *func, *data;
PyObject *idkey; PyObject *idkey;
int mask, id; int mask, id;
#if TKMAJORMINOR < 8000 FHANDLE tfile;
Tcl_File tfile;
#endif
if (!Tkapp_ClientDataDict) { if (!Tkapp_ClientDataDict) {
if (!(Tkapp_ClientDataDict = PyDict_New())) if (!(Tkapp_ClientDataDict = PyDict_New()))
...@@ -1159,18 +1181,9 @@ Tkapp_CreateFileHandler(self, args) ...@@ -1159,18 +1181,9 @@ Tkapp_CreateFileHandler(self, args)
} }
Py_DECREF(idkey); Py_DECREF(idkey);
#if TKMAJORMINOR < 8000 tfile = MAKEFHANDLE(id);
#ifdef MS_WINDOWS
/* We assume this is a socket... */
tfile = Tcl_GetFile((ClientData)id, TCL_WIN_SOCKET);
#else /* !MS_WINDOWS */
tfile = Tcl_GetFile((ClientData)id, TCL_UNIX_FD);
#endif /* !MS_WINDOWS */
/* Ought to check for null Tcl_File object... */ /* Ought to check for null Tcl_File object... */
Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data); Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
#else /* >= 8000 */
Tcl_CreateFileHandler(id, mask, FileHandler, (ClientData) data);
#endif /* >= 8000 */
/* XXX fileHandlerDict */ /* XXX fileHandlerDict */
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
...@@ -1186,9 +1199,7 @@ Tkapp_DeleteFileHandler(self, args) ...@@ -1186,9 +1199,7 @@ Tkapp_DeleteFileHandler(self, args)
PyObject *idkey; PyObject *idkey;
PyObject *data; PyObject *data;
int id; int id;
#if TKMAJORMINOR < 8000 FHANDLE tfile;
Tcl_File tfile;
#endif
if (!PyArg_ParseTuple(args, "O", &file)) if (!PyArg_ParseTuple(args, "O", &file))
return NULL; return NULL;
...@@ -1207,18 +1218,9 @@ Tkapp_DeleteFileHandler(self, args) ...@@ -1207,18 +1218,9 @@ Tkapp_DeleteFileHandler(self, args)
PyDict_DelItem(Tkapp_ClientDataDict, idkey); PyDict_DelItem(Tkapp_ClientDataDict, idkey);
Py_DECREF(idkey); Py_DECREF(idkey);
#if TKMAJORMINOR < 8000 tfile = MAKEFHANDLE(id);
#ifdef MS_WINDOWS
/* We assume this is a socket... */
tfile = Tcl_GetFile((ClientData)id, TCL_WIN_SOCKET);
#else
tfile = Tcl_GetFile((ClientData)id, TCL_UNIX_FD);
#endif
/* Ought to check for null Tcl_File object... */ /* Ought to check for null Tcl_File object... */
Tcl_DeleteFileHandler(tfile); Tcl_DeleteFileHandler(tfile);
#else /* >= 8000 */
Tcl_DeleteFileHandler(id);
#endif /* >= 8000 */
/* XXX fileHandlerDict */ /* XXX fileHandlerDict */
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
...@@ -1511,6 +1513,7 @@ Tkapp_Dealloc(self) ...@@ -1511,6 +1513,7 @@ Tkapp_Dealloc(self)
{ {
Tcl_DeleteInterp(Tkapp_Interp(self)); Tcl_DeleteInterp(Tkapp_Interp(self));
PyMem_DEL(self); PyMem_DEL(self);
DisableEventHook();
} }
static PyObject * static PyObject *
...@@ -1584,22 +1587,41 @@ static PyMethodDef moduleMethods[] = ...@@ -1584,22 +1587,41 @@ static PyMethodDef moduleMethods[] =
{NULL, NULL} {NULL, NULL}
}; };
#ifdef WAIT_FOR_STDIN
#define WAITFLAG 0
static int stdin_ready = 0;
static void
MyFileProc(clientData, mask)
void *clientData;
int mask;
{
stdin_ready = 1;
}
#else
#define WAITFLAG TCL_DONT_WAIT
#endif
static PyInterpreterState *event_interp = NULL; static PyInterpreterState *event_interp = NULL;
static int static int
EventHook() EventHook()
{ {
PyThreadState *tstate, *save_tstate; PyThreadState *tstate, *save_tstate;
#ifdef WAIT_FOR_STDIN
FHANDLE tfile = MAKEFHANDLE(((int)fileno(stdin)));
if (Tk_GetNumMainWindows() == 0) stdin_ready = 0;
return 0; Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
if (event_interp == NULL) #endif
return 0;
tstate = PyThreadState_New(event_interp); tstate = PyThreadState_New(event_interp);
save_tstate = PyThreadState_Swap(NULL); save_tstate = PyThreadState_Swap(NULL);
PyEval_RestoreThread(tstate); PyEval_RestoreThread(tstate);
if (!errorInCmd) #ifdef WAIT_FOR_STDIN
Tcl_DoOneEvent(TCL_DONT_WAIT); while (!errorInCmd && !stdin_ready)
#endif
Tcl_DoOneEvent(WAITFLAG);
if (errorInCmd) { if (errorInCmd) {
errorInCmd = 0; errorInCmd = 0;
PyErr_Restore(excInCmd, valInCmd, trbInCmd); PyErr_Restore(excInCmd, valInCmd, trbInCmd);
...@@ -1610,9 +1632,29 @@ EventHook() ...@@ -1610,9 +1632,29 @@ EventHook()
PyEval_SaveThread(); PyEval_SaveThread();
PyThreadState_Swap(save_tstate); PyThreadState_Swap(save_tstate);
PyThreadState_Delete(tstate); PyThreadState_Delete(tstate);
#ifdef WAIT_FOR_STDIN
Tcl_DeleteFileHandler(tfile);
#endif
return 0; return 0;
} }
static void
EnableEventHook()
{
if (PyOS_InputHook == NULL) {
event_interp = PyThreadState_Get()->interp;
PyOS_InputHook = EventHook;
}
}
static void
DisableEventHook()
{
if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
PyOS_InputHook = NULL;
}
}
/* all errors will be checked in one fell swoop in init_tkinter() */ /* all errors will be checked in one fell swoop in init_tkinter() */
static void static void
...@@ -1670,11 +1712,6 @@ init_tkinter() ...@@ -1670,11 +1712,6 @@ init_tkinter()
PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type); PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type);
PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type); PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
if (PyOS_InputHook == NULL) {
event_interp = PyThreadState_Get()->interp;
PyOS_InputHook = EventHook;
}
if (PyErr_Occurred()) if (PyErr_Occurred())
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment