Skip to content

Commit 7bf1564

Browse files
committed
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 :-(
1 parent 6a50ba8 commit 7bf1564

File tree

1 file changed

+74
-37
lines changed

1 file changed

+74
-37
lines changed

Modules/_tkinter.c

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,24 @@ PERFORMANCE OF THIS SOFTWARE.
8383
#define HAVE_CREATEFILEHANDLER
8484
#endif
8585

86+
#ifdef MS_WINDOWS
87+
#define FHANDLETYPE TCL_WIN_SOCKET
88+
#else
89+
#define FHANDLETYPE TCL_UNIX_FD
90+
#endif
91+
92+
#if TKMAJORMINOR < 8000
93+
#define FHANDLE Tcl_File
94+
#define MAKEFHANDLE(fd) Tcl_GetFile((ClientData)(fd), FHANDLETYPE)
95+
#else
96+
#define FHANDLE int
97+
#define MAKEFHANDLE(fd) (fd)
98+
#endif
99+
100+
#if defined(HAVE_CREATEFILEHANDLER) && !defined(MS_WINDOWS)
101+
#define WAIT_FOR_STDIN
102+
#endif
103+
86104
extern int Tk_GetNumMainWindows();
87105

88106
#ifdef macintosh
@@ -342,6 +360,10 @@ Tcl_AppInit(interp)
342360
/* Initialize the Tk application; see the `main' function in
343361
* `tkMain.c'.
344362
*/
363+
364+
static void EnableEventHook(); /* Forward */
365+
static void DisableEventHook(); /* Forward */
366+
345367
static TkappObject *
346368
Tkapp_New(screenName, baseName, className, interactive)
347369
char *screenName;
@@ -392,6 +414,8 @@ Tkapp_New(screenName, baseName, className, interactive)
392414
if (Tcl_AppInit(v->interp) != TCL_OK)
393415
return (TkappObject *)Tkinter_Error(v);
394416

417+
EnableEventHook();
418+
395419
return v;
396420
}
397421

@@ -1128,9 +1152,7 @@ Tkapp_CreateFileHandler(self, args)
11281152
PyObject *file, *func, *data;
11291153
PyObject *idkey;
11301154
int mask, id;
1131-
#if TKMAJORMINOR < 8000
1132-
Tcl_File tfile;
1133-
#endif
1155+
FHANDLE tfile;
11341156

11351157
if (!Tkapp_ClientDataDict) {
11361158
if (!(Tkapp_ClientDataDict = PyDict_New()))
@@ -1159,18 +1181,9 @@ Tkapp_CreateFileHandler(self, args)
11591181
}
11601182
Py_DECREF(idkey);
11611183

1162-
#if TKMAJORMINOR < 8000
1163-
#ifdef MS_WINDOWS
1164-
/* We assume this is a socket... */
1165-
tfile = Tcl_GetFile((ClientData)id, TCL_WIN_SOCKET);
1166-
#else /* !MS_WINDOWS */
1167-
tfile = Tcl_GetFile((ClientData)id, TCL_UNIX_FD);
1168-
#endif /* !MS_WINDOWS */
1184+
tfile = MAKEFHANDLE(id);
11691185
/* Ought to check for null Tcl_File object... */
11701186
Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
1171-
#else /* >= 8000 */
1172-
Tcl_CreateFileHandler(id, mask, FileHandler, (ClientData) data);
1173-
#endif /* >= 8000 */
11741187
/* XXX fileHandlerDict */
11751188
Py_INCREF(Py_None);
11761189
return Py_None;
@@ -1186,9 +1199,7 @@ Tkapp_DeleteFileHandler(self, args)
11861199
PyObject *idkey;
11871200
PyObject *data;
11881201
int id;
1189-
#if TKMAJORMINOR < 8000
1190-
Tcl_File tfile;
1191-
#endif
1202+
FHANDLE tfile;
11921203

11931204
if (!PyArg_ParseTuple(args, "O", &file))
11941205
return NULL;
@@ -1207,18 +1218,9 @@ Tkapp_DeleteFileHandler(self, args)
12071218
PyDict_DelItem(Tkapp_ClientDataDict, idkey);
12081219
Py_DECREF(idkey);
12091220

1210-
#if TKMAJORMINOR < 8000
1211-
#ifdef MS_WINDOWS
1212-
/* We assume this is a socket... */
1213-
tfile = Tcl_GetFile((ClientData)id, TCL_WIN_SOCKET);
1214-
#else
1215-
tfile = Tcl_GetFile((ClientData)id, TCL_UNIX_FD);
1216-
#endif
1221+
tfile = MAKEFHANDLE(id);
12171222
/* Ought to check for null Tcl_File object... */
12181223
Tcl_DeleteFileHandler(tfile);
1219-
#else /* >= 8000 */
1220-
Tcl_DeleteFileHandler(id);
1221-
#endif /* >= 8000 */
12221224
/* XXX fileHandlerDict */
12231225
Py_INCREF(Py_None);
12241226
return Py_None;
@@ -1511,6 +1513,7 @@ Tkapp_Dealloc(self)
15111513
{
15121514
Tcl_DeleteInterp(Tkapp_Interp(self));
15131515
PyMem_DEL(self);
1516+
DisableEventHook();
15141517
}
15151518

15161519
static PyObject *
@@ -1584,22 +1587,41 @@ static PyMethodDef moduleMethods[] =
15841587
{NULL, NULL}
15851588
};
15861589

1590+
#ifdef WAIT_FOR_STDIN
1591+
#define WAITFLAG 0
1592+
1593+
static int stdin_ready = 0;
1594+
1595+
static void
1596+
MyFileProc(clientData, mask)
1597+
void *clientData;
1598+
int mask;
1599+
{
1600+
stdin_ready = 1;
1601+
}
1602+
#else
1603+
#define WAITFLAG TCL_DONT_WAIT
1604+
#endif
1605+
15871606
static PyInterpreterState *event_interp = NULL;
15881607

15891608
static int
15901609
EventHook()
15911610
{
15921611
PyThreadState *tstate, *save_tstate;
1612+
#ifdef WAIT_FOR_STDIN
1613+
FHANDLE tfile = MAKEFHANDLE(((int)fileno(stdin)));
15931614

1594-
if (Tk_GetNumMainWindows() == 0)
1595-
return 0;
1596-
if (event_interp == NULL)
1597-
return 0;
1615+
stdin_ready = 0;
1616+
Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
1617+
#endif
15981618
tstate = PyThreadState_New(event_interp);
15991619
save_tstate = PyThreadState_Swap(NULL);
16001620
PyEval_RestoreThread(tstate);
1601-
if (!errorInCmd)
1602-
Tcl_DoOneEvent(TCL_DONT_WAIT);
1621+
#ifdef WAIT_FOR_STDIN
1622+
while (!errorInCmd && !stdin_ready)
1623+
#endif
1624+
Tcl_DoOneEvent(WAITFLAG);
16031625
if (errorInCmd) {
16041626
errorInCmd = 0;
16051627
PyErr_Restore(excInCmd, valInCmd, trbInCmd);
@@ -1610,9 +1632,29 @@ EventHook()
16101632
PyEval_SaveThread();
16111633
PyThreadState_Swap(save_tstate);
16121634
PyThreadState_Delete(tstate);
1635+
#ifdef WAIT_FOR_STDIN
1636+
Tcl_DeleteFileHandler(tfile);
1637+
#endif
16131638
return 0;
16141639
}
16151640

1641+
static void
1642+
EnableEventHook()
1643+
{
1644+
if (PyOS_InputHook == NULL) {
1645+
event_interp = PyThreadState_Get()->interp;
1646+
PyOS_InputHook = EventHook;
1647+
}
1648+
}
1649+
1650+
static void
1651+
DisableEventHook()
1652+
{
1653+
if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
1654+
PyOS_InputHook = NULL;
1655+
}
1656+
}
1657+
16161658

16171659
/* all errors will be checked in one fell swoop in init_tkinter() */
16181660
static void
@@ -1670,11 +1712,6 @@ init_tkinter()
16701712
PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type);
16711713
PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
16721714

1673-
if (PyOS_InputHook == NULL) {
1674-
event_interp = PyThreadState_Get()->interp;
1675-
PyOS_InputHook = EventHook;
1676-
}
1677-
16781715
if (PyErr_Occurred())
16791716
return;
16801717

0 commit comments

Comments
 (0)