From: Daniel Drake <dsd@laptop.org>
http://bugzilla.gnome.org/show_bug.cgi?id=481569

Fix the PySignal_SetWakeupFd() implementation:
 - Prepare file descriptors and call PySignal_SetWakeupFd() just once, outside
   of the mainloop iterations
 - Fix source_prepare semantics
 - Fix source_check semantics, and actually read from the pipe

Index: pygtk-2.13.0/gtk/gtk.override
===================================================================
--- pygtk-2.13.0.orig/gtk/gtk.override
+++ pygtk-2.13.0/gtk/gtk.override
@@ -1069,13 +1069,15 @@ static gboolean
 pygtk_main_watch_prepare(GSource *source,
 			 int     *timeout)
 {
-    PySignalWatchSource *real_source = (PySignalWatchSource *)source;
 
     /* Python only invokes signal handlers from the main thread,
      * so if a thread other than the main thread receives the signal
      * from the kernel, PyErr_CheckSignals() from that thread will
      * do nothing.
      */
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+    return FALSE;
+#else /* !HAVE_PYSIGNAL_SETWAKEUPFD */
 
     /* On Windows g_poll() won't be interrupted by a signal
      * (AFAIK), so we need the timeout there too, even if there's
@@ -1084,28 +1086,8 @@ pygtk_main_watch_prepare(GSource *source
 #ifndef PLATFORM_WIN32
     if (!pyg_threads_enabled)
 	return FALSE;
-#endif
+#endif /* PLATFORM_WIN32 */
 
-#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
-    if (real_source->fds[0] != 0)
-	return FALSE;
-
-    /* Unfortunately we need to create a new pipe here instead of
-     * reusing the pipe inside the GMainContext.
-     * Ideally an api should be added to GMainContext which allows us
-     * to reuse that pipe which would suit us perfectly fine.     
-     */
-    if (pipe(real_source->fds) < 0)
-	g_error("Cannot create main loop pipe: %s\n",
-		g_strerror(errno));
-
-    real_source->fd.fd = real_source->fds[0];
-    real_source->fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
-    g_source_add_poll(source, &real_source->fd);
-
-    PySignal_SetWakeupFd(real_source->fds[1]);
-
-#else /* !HAVE_PYSIGNAL_SETWAKEUPFD */
     /* If we're using 2.5 or an earlier version of python we
      * will default to a timeout every second, be aware,
      * this will cause unnecessary wakeups, see
@@ -1122,6 +1104,14 @@ pygtk_main_watch_check(GSource *source)
 {
     PyGILState_STATE state;
 
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+    PySignalWatchSource *real_source = (PySignalWatchSource *)source;
+    GPollFD *poll_fd = &real_source->fd;
+    unsigned char dummy;
+    if (poll_fd->revents & G_IO_IN)
+	read(poll_fd->fd, &dummy, 1);
+#endif
+
     state = pyg_gil_state_ensure();
 
     if (PyErr_CheckSignals() == -1 && gtk_main_level() > 0) {
@@ -1147,15 +1137,14 @@ pygtk_main_watch_dispatch(GSource    *so
 static void
 pygtk_signal_watch_finalize(GSource *source)
 {
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
     PySignalWatchSource *real_source = (PySignalWatchSource*)source;
 
     if (source != NULL) {
-	if (real_source->fds[0] != 0)
-	    close(real_source->fds[0]);
-	
-	if (real_source->fds[1] != 0)
-	    close(real_source->fds[1]);
+	close(real_source->fds[0]);
+	close(real_source->fds[1]);
     }
+#endif
 }
 
 static GSourceFuncs pygtk_main_watch_funcs =
@@ -1169,7 +1158,31 @@ static GSourceFuncs pygtk_main_watch_fun
 static GSource *
 pygtk_main_watch_new(void)
 {
-    return g_source_new(&pygtk_main_watch_funcs, sizeof(PySignalWatchSource));
+    GSource *source = g_source_new(&pygtk_main_watch_funcs,
+	sizeof(PySignalWatchSource));
+
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+    PySignalWatchSource *real_source = (PySignalWatchSource *)source;
+
+    /* Unfortunately we need to create a new pipe here instead of
+     * reusing the pipe inside the GMainContext.
+     * Ideally an api should be added to GMainContext which allows us
+     * to reuse that pipe which would suit us perfectly fine.
+     * XXX using an eventfd on Linux kernels that support it would be more
+     * efficient
+     */
+    if (pipe(real_source->fds) < 0)
+	g_error("Cannot create main loop pipe: %s\n",
+		g_strerror(errno));
+
+    real_source->fd.fd = real_source->fds[0];
+    real_source->fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+    g_source_add_poll(source, &real_source->fd);
+
+    PySignal_SetWakeupFd(real_source->fds[1]);
+#endif
+
+    return source;
 }
 
 
