summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorPhilippe Normand <phil@base-art.net>2010-02-25 10:54:18 +0100
committerGian Mario Tagliaretti <gianmt@gnome.org>2010-04-18 18:18:41 +0200
commitf4cc1453896a891b8197a4ddbc1b7b9706c86996 (patch)
tree68a961dc9aa06b1679ff187c8b162f34b5ea14ec /gtk
parentfd242b0e39985ef4f1d2ef0b773c4d451e789ca0 (diff)
downloadpygtk-f4cc1453896a891b8197a4ddbc1b7b9706c86996.tar.gz
gtk_main: fixed use of Python's SetWakeupFD API
I backported the last patch from Bug 481569.
Diffstat (limited to 'gtk')
-rw-r--r--gtk/gtk.override114
1 files changed, 56 insertions, 58 deletions
diff --git a/gtk/gtk.override b/gtk/gtk.override
index fa057715..35b0ec93 100644
--- a/gtk/gtk.override
+++ b/gtk/gtk.override
@@ -24,6 +24,7 @@ headers
#define NO_IMPORT_PYGOBJECT
#include "pygobject.h"
+#include <fcntl.h>
#include <locale.h>
#include <gtk/gtk.h>
@@ -1102,15 +1103,17 @@ override gtk_main noargs
/* This code (pygtk main watch) was copied with minor changes from
* pygobject/gobject/pygmainloop.c */
+
+static int pipe_fds[2];
+
typedef struct {
GSource source;
- int fds[2];
GPollFD fd;
} PySignalWatchSource;
static gboolean
pygtk_main_watch_prepare(GSource *source,
- int *timeout)
+ int *timeout)
{
/* Python only invokes signal handlers from the main thread,
* so if a thread other than the main thread receives the signal
@@ -1118,47 +1121,26 @@ pygtk_main_watch_prepare(GSource *source,
* 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
* only one thread.
*/
#ifndef PLATFORM_WIN32
- if (!pyg_threads_enabled)
- return FALSE;
-#endif
-
-#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
- {
- PySignalWatchSource *real_source = (PySignalWatchSource *)source;
-
- 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);
+ if (!pyg_threads_enabled())
+ return FALSE;
+#endif /* PLATFORM_WIN32 */
- 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
* http://bugzilla.gnome.org/show_bug.cgi?id=481569
*/
*timeout = 1000;
-#endif /* HAVE_PYSIGNAL_SETWAKEUPFD */
-
return FALSE;
+#endif /* HAVE_PYSIGNAL_SETWAKEUPFD */
}
static gboolean
@@ -1166,11 +1148,19 @@ pygtk_main_watch_check(GSource *source)
{
PyGILState_STATE state;
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+ PySignalWatchSource *real_source = (PySignalWatchSource *)source;
+ GPollFD *poll_fd = &real_source->fd;
+ int data_size = 0;
+ if (poll_fd->revents & G_IO_IN)
+ data_size = read(poll_fd->fd, 0, 1);
+#endif
+
state = pyg_gil_state_ensure();
if (PyErr_CheckSignals() == -1 && gtk_main_level() > 0) {
- PyErr_SetNone(PyExc_KeyboardInterrupt);
- gtk_main_quit();
+ PyErr_SetNone(PyExc_KeyboardInterrupt);
+ gtk_main_quit();
}
pyg_gil_state_release(state);
@@ -1188,41 +1178,49 @@ pygtk_main_watch_dispatch(GSource *source,
return TRUE;
}
-static void
-pygtk_main_watch_finalize(GSource *source)
-{
- 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) {
-#if HAVE_PYSIGNAL_SETWAKEUPFD
- int wakeup_fd = PySignal_SetWakeupFd(-1);
- if (wakeup_fd != real_source->fds[1]) {
- /* Probably should never happen. */
- PySignal_SetWakeupFd(wakeup_fd);
- }
-#endif
-
- close(real_source->fds[1]);
- }
- }
-}
-
static GSourceFuncs pygtk_main_watch_funcs =
{
pygtk_main_watch_prepare,
pygtk_main_watch_check,
- pygtk_main_watch_dispatch,
- pygtk_main_watch_finalize
+ pygtk_main_watch_dispatch
};
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;
+ int flag;
+
+ /* 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 More efficient than a pipe, we could use an eventfd on Linux
+ * kernels that support it.
+ */
+ gint already_piped = (pipe_fds[0] > 0);
+ if (!already_piped) {
+ if (pipe(pipe_fds) < 0)
+ g_error("Cannot create main loop pipe: %s\n",
+ g_strerror(errno));
+
+ /* Make the write end of the fd non blocking */
+ flag = fcntl(pipe_fds[1], F_GETFL, 0);
+ flag |= O_NONBLOCK;
+ fcntl(pipe_fds[1], F_SETFL, flag);
+ }
+
+ real_source->fd.fd = pipe_fds[0];
+ real_source->fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+ g_source_add_poll(source, &real_source->fd);
+
+ if (!already_piped)
+ PySignal_SetWakeupFd(pipe_fds[1]);
+#endif
+ return source;
}