diff options
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtk.override | 114 |
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; } |