From 45ccf5f6ff1a1805ed326b397c70cf55bba28124 Mon Sep 17 00:00:00 2001 From: Johan Dahlin Date: Sun, 20 Jul 2008 14:17:04 +0000 Subject: Move maincontext and mainloop over to glib. Update the threadstate api to 2008-07-20 Johan Dahlin * glib/Makefile.am: * glib/glibmodule.c (pyglib_main_context_default), (init_glib): * glib/pyglib.c (pyglib_init), (pyglib_threads_enabled), (pyglib_main_context_new): * glib/pyglib.h: * glib/pygmaincontext.c (_wrap_g_main_context_iteration), (pyglib_maincontext_register_types): * glib/pygmaincontext.h: * glib/pygmainloop.c (pyg_signal_watch_prepare), (pyg_signal_watch_check), (pyg_main_loop_new), (_wrap_g_main_loop_get_context), (_wrap_g_main_loop_run), (pyglib_mainloop_register_types): * glib/pygmainloop.h: * gobject/Makefile.am: * gobject/__init__.py: * gobject/gobjectmodule.c (pyg_destroy_notify), (pyobject_free), (pyg_object_set_property), (pyg_object_get_property), (_pyg_signal_accumulator), (pygobject__g_instance_init), (pyg_handler_marshal), (pygobject_gil_state_ensure), (pygobject_gil_state_release), (marshal_emission_hook), (_log_func), (init_gobject): * gobject/pygboxed.c (pyg_boxed_dealloc), (pyg_boxed_new): * gobject/pygenum.c (pyg_enum_add): * gobject/pygflags.c (pyg_flags_add): * gobject/pygiochannel.c (pyg_iowatch_marshal): * gobject/pygmaincontext.c: * gobject/pygmainloop.c: * gobject/pygobject-private.h: * gobject/pygobject.c (pygobject_data_free), (pyg_toggle_notify), (pygobject_new_with_interfaces), (pygobject_weak_ref_notify): * gobject/pygobject.h: * gobject/pygoptiongroup.c (destroy_g_group), (arg_func): * gobject/pygpointer.c (pyg_pointer_new): * gobject/pygsource.c (pyg_source_get_context), (pyg_source_prepare), (pyg_source_check), (pyg_source_dispatch), (pyg_source_finalize): * gobject/pygtype.c (pyg_closure_invalidate), (pyg_closure_marshal), (pyg_signal_class_closure_marshal): * tests/common.py: Move maincontext and mainloop over to glib. Update the threadstate api to use the variant in glib. svn path=/trunk/; revision=843 --- ChangeLog | 45 ++++++ glib/Makefile.am | 10 +- glib/glibmodule.c | 21 +-- glib/pyglib.c | 34 ++++ glib/pyglib.h | 13 ++ glib/pygmaincontext.c | 133 +++++++++++++++ glib/pygmaincontext.h | 40 +++++ glib/pygmainloop.c | 383 ++++++++++++++++++++++++++++++++++++++++++++ glib/pygmainloop.h | 36 +++++ gobject/Makefile.am | 2 - gobject/__init__.py | 3 +- gobject/gobjectmodule.c | 72 ++++----- gobject/pygboxed.c | 13 +- gobject/pygenum.c | 7 +- gobject/pygflags.c | 7 +- gobject/pygiochannel.c | 5 +- gobject/pygmaincontext.c | 144 ----------------- gobject/pygmainloop.c | 368 ------------------------------------------ gobject/pygobject-private.h | 7 +- gobject/pygobject.c | 22 +-- gobject/pygobject.h | 12 +- gobject/pygoptiongroup.c | 11 +- gobject/pygpointer.c | 7 +- gobject/pygsource.c | 19 +-- gobject/pygtype.c | 20 +-- tests/common.py | 2 + 26 files changed, 805 insertions(+), 631 deletions(-) create mode 100644 glib/pygmaincontext.c create mode 100644 glib/pygmaincontext.h create mode 100644 glib/pygmainloop.c create mode 100644 glib/pygmainloop.h delete mode 100644 gobject/pygmaincontext.c delete mode 100644 gobject/pygmainloop.c diff --git a/ChangeLog b/ChangeLog index 2b39d66..c65db60 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,48 @@ +2008-07-20 Johan Dahlin + + * glib/Makefile.am: + * glib/glibmodule.c (pyglib_main_context_default), (init_glib): + * glib/pyglib.c (pyglib_init), (pyglib_threads_enabled), + (pyglib_main_context_new): + * glib/pyglib.h: + * glib/pygmaincontext.c (_wrap_g_main_context_iteration), + (pyglib_maincontext_register_types): + * glib/pygmaincontext.h: + * glib/pygmainloop.c (pyg_signal_watch_prepare), + (pyg_signal_watch_check), (pyg_main_loop_new), + (_wrap_g_main_loop_get_context), (_wrap_g_main_loop_run), + (pyglib_mainloop_register_types): + * glib/pygmainloop.h: + * gobject/Makefile.am: + * gobject/__init__.py: + * gobject/gobjectmodule.c (pyg_destroy_notify), (pyobject_free), + (pyg_object_set_property), (pyg_object_get_property), + (_pyg_signal_accumulator), (pygobject__g_instance_init), + (pyg_handler_marshal), (pygobject_gil_state_ensure), + (pygobject_gil_state_release), (marshal_emission_hook), + (_log_func), (init_gobject): + * gobject/pygboxed.c (pyg_boxed_dealloc), (pyg_boxed_new): + * gobject/pygenum.c (pyg_enum_add): + * gobject/pygflags.c (pyg_flags_add): + * gobject/pygiochannel.c (pyg_iowatch_marshal): + * gobject/pygmaincontext.c: + * gobject/pygmainloop.c: + * gobject/pygobject-private.h: + * gobject/pygobject.c (pygobject_data_free), (pyg_toggle_notify), + (pygobject_new_with_interfaces), (pygobject_weak_ref_notify): + * gobject/pygobject.h: + * gobject/pygoptiongroup.c (destroy_g_group), (arg_func): + * gobject/pygpointer.c (pyg_pointer_new): + * gobject/pygsource.c (pyg_source_get_context), + (pyg_source_prepare), (pyg_source_check), (pyg_source_dispatch), + (pyg_source_finalize): + * gobject/pygtype.c (pyg_closure_invalidate), + (pyg_closure_marshal), (pyg_signal_class_closure_marshal): + * tests/common.py: + + Move maincontext and mainloop over to glib. + Update the threadstate api to use the variant in glib. + 2008-07-20 Johan Dahlin * glib/Makefile.am: diff --git a/glib/Makefile.am b/glib/Makefile.am index f0160d8..e32d24d 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -28,10 +28,12 @@ libpyglib_2_0_la_SOURCES = \ _glib_la_CFLAGS = $(GLIB_CFLAGS) _glib_la_LDFLAGS = $(common_ldflags) -export-symbols-regex init_glib _glib_la_LIBADD = $(GLIB_LIBS) libpyglib-2.0.la -_glib_la_SOURCES = \ - glibmodule.c \ - pygspawn.c \ - pygspawn.h +_glib_la_SOURCES = \ + glibmodule.c \ + pygspawn.c \ + pygspawn.h \ + pygmaincontext.c \ + pygmainloop.c if PLATFORM_WIN32 _glib_la_CFLAGS += -DPLATFORM_WIN32 diff --git a/glib/glibmodule.c b/glib/glibmodule.c index 25ded22..6892d1a 100644 --- a/glib/glibmodule.c +++ b/glib/glibmodule.c @@ -29,8 +29,10 @@ #include #include "pyglib.h" -#include "pygspawn.h" #include "pyglib-private.h" +#include "pygmaincontext.h" +#include "pygmainloop.h" +#include "pygspawn.h" #define PYGLIB_MAJOR_VERSION PYGOBJECT_MAJOR_VERSION #define PYGLIB_MINOR_VERSION PYGOBJECT_MINOR_VERSION @@ -343,13 +345,11 @@ pyg_source_remove(PyObject *self, PyObject *args) return PyBool_FromLong(g_source_remove(tag)); } -#ifdef FIXME static PyObject * -pyg_main_context_default(PyObject *unused) +pyglib_main_context_default(PyObject *unused) { - return pyg_main_context_new(g_main_context_default()); + return pyglib_main_context_new(g_main_context_default()); } -#endif struct _PyGChildData { PyObject *func; @@ -565,6 +565,8 @@ pyg_set_prgname(PyObject *self, PyObject *args) static PyMethodDef pyglib_functions[] = { { "spawn_async", (PyCFunction)pyglib_spawn_async, METH_VARARGS|METH_KEYWORDS }, + { "main_context_default", + (PyCFunction)pyglib_main_context_default, METH_NOARGS }, { "idle_add", (PyCFunction)pyg_idle_add, METH_VARARGS|METH_KEYWORDS }, @@ -598,10 +600,8 @@ static PyMethodDef pyglib_functions[] = { (PyCFunction)pyg_set_prgname, METH_VARARGS }, { "main_depth", (PyCFunction)pyg_main_depth, METH_NOARGS }, -#if 0 - { "main_context_default", - (PyCFunction)pyg_main_context_default, METH_NOARGS }, -#endif + + { NULL, NULL, 0 } }; @@ -675,4 +675,7 @@ init_glib(void) pyg_register_error(d); pyg_register_version_tuples(d); pyg_spawn_register_types(d); + + pyglib_mainloop_register_types(d); + pyglib_maincontext_register_types(d); } diff --git a/glib/pyglib.c b/glib/pyglib.c index 57bc095..3f7ebbd 100644 --- a/glib/pyglib.c +++ b/glib/pyglib.c @@ -27,10 +27,14 @@ #include #include "pyglib.h" #include "pyglib-private.h" +#include "pygmaincontext.h" static struct _PyGLib_Functions *_PyGLib_API; static int pyglib_thread_state_tls_key; +static PyTypeObject *_PyGMainContext_Type; +#define PyGMainContext_Type (*_PyGMainContext_Type) + void pyglib_init(void) { @@ -63,6 +67,8 @@ pyglib_init(void) "could not import glib (could not find _PyGLib_API object)"); Py_DECREF(glib); } + + _PyGMainContext_Type = (PyTypeObject*)PyObject_GetAttrString(glib, "MainContext"); } void @@ -71,6 +77,12 @@ pyglib_init_internal(PyObject *api) _PyGLib_API = (struct _PyGLib_Functions *) PyCObject_AsVoidPtr(api); } +gboolean +pyglib_threads_enabled(void) +{ + return _PyGLib_API->threads_enabled; +} + PyGILState_STATE pyglib_gil_state_ensure(void) { @@ -255,3 +267,25 @@ bad_gerror: PyErr_Print(); return -2; } + +/** + * pyglib_main_context_new: + * @context: a GMainContext. + * + * Creates a wrapper for a GMainContext. + * + * Returns: the GMainContext wrapper. + */ +PyObject * +pyglib_main_context_new(GMainContext *context) +{ + PyGMainContext *self; + + self = (PyGMainContext *)PyObject_NEW(PyGMainContext, + &PyGMainContext_Type); + if (self == NULL) + return NULL; + + self->context = g_main_context_ref(context); + return (PyObject *)self; +} diff --git a/glib/pyglib.h b/glib/pyglib.h index 30b5f74..b2235d3 100644 --- a/glib/pyglib.h +++ b/glib/pyglib.h @@ -35,6 +35,19 @@ void pyglib_gil_state_release(PyGILState_STATE state); gboolean pyglib_enable_threads(void); gboolean pyglib_error_check(GError **error); gboolean pyglib_gerror_exception_check(GError **error); +gboolean pyglib_threads_enabled(void); +PyObject *pyglib_main_context_new(GMainContext *context); + +#define pyglib_begin_allow_threads \ + G_STMT_START { \ + PyThreadState *_save = NULL; \ + if (pyglib_threads_enabled()) \ + _save = PyEval_SaveThread(); + +#define pyglib_end_allow_threads \ + if (pyglib_threads_enabled()) \ + PyEval_RestoreThread(_save); \ + } G_STMT_END G_END_DECLS diff --git a/glib/pygmaincontext.c b/glib/pygmaincontext.c new file mode 100644 index 0000000..c969af5 --- /dev/null +++ b/glib/pygmaincontext.c @@ -0,0 +1,133 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * + * pygmaincontext.c: GMainContext wrapper + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include "pygmaincontext.h" +#include "pyglib.h" +#include "pyglib-private.h" + +static int +pyg_main_context_init(PyGMainContext *self) +{ + self->context = g_main_context_new(); + return 0; +} + +static void +pyg_main_context_dealloc(PyGMainContext *self) +{ + if (self->context != NULL) { + g_main_context_unref(self->context); + self->context = NULL; + } + + PyObject_Del(self); +} + +static int +pyg_main_context_compare(PyGMainContext *self, PyGMainContext *v) +{ + if (self->context == v->context) return 0; + if (self->context > v->context) return -1; + return 1; +} + +static PyObject * +_wrap_g_main_context_iteration (PyGMainContext *self, PyObject *args) +{ + gboolean ret, may_block = TRUE; + + if (!PyArg_ParseTuple(args, "|i:GMainContext.iteration", + &may_block)) + return NULL; + + pyglib_begin_allow_threads; + ret = g_main_context_iteration(self->context, may_block); + pyglib_end_allow_threads; + + return PyBool_FromLong(ret); +} + +static PyObject * +_wrap_g_main_context_pending (PyGMainContext *self) +{ + return PyBool_FromLong(g_main_context_pending(self->context)); +} + +static PyMethodDef _PyGMainContext_methods[] = { + { "iteration", (PyCFunction)_wrap_g_main_context_iteration, METH_VARARGS }, + { "pending", (PyCFunction)_wrap_g_main_context_pending, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +PyTypeObject PyGMainContext_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "glib.MainContext", + sizeof(PyGMainContext), + 0, + /* methods */ + (destructor)pyg_main_context_dealloc, + (printfunc)0, + (getattrfunc)0, + (setattrfunc)0, + (cmpfunc)pyg_main_context_compare, + (reprfunc)0, + 0, + 0, + 0, + (hashfunc)0, + (ternaryfunc)0, + (reprfunc)0, + (getattrofunc)0, + (setattrofunc)0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + NULL, + (traverseproc)0, + (inquiry)0, + (richcmpfunc)0, + 0, + (getiterfunc)0, + (iternextfunc)0, + _PyGMainContext_methods, + 0, + 0, + NULL, + NULL, + (descrgetfunc)0, + (descrsetfunc)0, + 0, + (initproc)pyg_main_context_init, +}; + +void +pyglib_maincontext_register_types(PyObject *d) +{ + PYGLIB_REGISTER_TYPE(d, PyGMainContext_Type, "MainContext"); +} diff --git a/glib/pygmaincontext.h b/glib/pygmaincontext.h new file mode 100644 index 0000000..58ffbf0 --- /dev/null +++ b/glib/pygmaincontext.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pyglib - Python bindings for GLib toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef __PYG_MAINCONTEXT_H__ +#define __PYG_MAINCONTEXT_H__ + +#include +#include + +typedef struct { + PyObject_HEAD + GMainContext *context; +} PyGMainContext; + +extern PyTypeObject PyGMainContext_Type; + +PyObject * pyglib_main_context_new(GMainContext *context); + +void pyglib_maincontext_register_types(PyObject *d); + +#endif /* __PYG_MAINCONTEXT_H__ */ + diff --git a/glib/pygmainloop.c b/glib/pygmainloop.c new file mode 100644 index 0000000..04653de --- /dev/null +++ b/glib/pygmainloop.c @@ -0,0 +1,383 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2004 Johan Dahlin + * + * pygmainloop.c: GMainLoop wrapper + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "pygmainloop.h" +#include "pygmaincontext.h" +#include "pyglib.h" +#include "pyglib-private.h" + + +typedef struct { + GSource source; + int fds[2]; + GPollFD fd; +} PySignalWatchSource; + +#ifdef DISABLE_THREADING +static GMainLoop *pyg_current_main_loop = NULL;; + +static inline GMainLoop * +pyg_save_current_main_loop (GMainLoop *main_loop) +{ + GMainLoop *retval = pyg_current_main_loop; + + g_return_val_if_fail(main_loop != NULL, NULL); + + pyg_current_main_loop = g_main_loop_ref(main_loop); + + return retval; +} + +static inline void +pyg_restore_current_main_loop (GMainLoop *main_loop) +{ + if (pyg_current_main_loop != NULL) + g_main_loop_unref(pyg_current_main_loop); + pyg_current_main_loop = main_loop; +} + +static inline GMainLoop * +pyg_get_current_main_loop (void) +{ + return pyg_current_main_loop; +} +#else /* !defined(#ifndef DISABLE_THREADING) */ + +static int pyg_current_main_loop_key = -1; + +static inline GMainLoop * +pyg_save_current_main_loop (GMainLoop *main_loop) +{ + GMainLoop *retval; + + g_return_val_if_fail(main_loop != NULL, NULL); + + if (pyg_current_main_loop_key == -1) + pyg_current_main_loop_key = PyThread_create_key(); + + retval = PyThread_get_key_value(pyg_current_main_loop_key); + PyThread_delete_key_value(pyg_current_main_loop_key); + PyThread_set_key_value(pyg_current_main_loop_key, + g_main_loop_ref(main_loop)); + + return retval; +} + +static inline void +pyg_restore_current_main_loop (GMainLoop *main_loop) +{ + GMainLoop *prev; + + g_return_if_fail (pyg_current_main_loop_key != -1); + + prev = PyThread_get_key_value(pyg_current_main_loop_key); + if (prev != NULL) + g_main_loop_unref(prev); + PyThread_delete_key_value(pyg_current_main_loop_key); + if (main_loop != NULL) + PyThread_set_key_value(pyg_current_main_loop_key, main_loop); +} + +static inline GMainLoop * +pyg_get_current_main_loop (void) +{ + if (pyg_current_main_loop_key == -1) + return NULL; + return PyThread_get_key_value(pyg_current_main_loop_key); +} +#endif /* DISABLE_THREADING */ + +static gboolean +pyg_signal_watch_prepare(GSource *source, + int *timeout) +{ +#ifdef HAVE_PYSIGNAL_SETWAKEUPFD + PySignalWatchSource *real_source = (PySignalWatchSource *)source; +#endif + + /* 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. + */ + + /* 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 (!pyglib_threads_enabled()) + return FALSE; +#endif + +#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 + * http://bugzilla.gnome.org/show_bug.cgi?id=481569 + */ + *timeout = 1000; +#endif /* HAVE_PYSIGNAL_SETWAKEUPFD */ + + return FALSE; +} + +static gboolean +pyg_signal_watch_check(GSource *source) +{ + PyGILState_STATE state; + GMainLoop *main_loop; + + state = pyglib_gil_state_ensure(); + + main_loop = pyg_get_current_main_loop(); + + if (PyErr_CheckSignals() == -1 && main_loop != NULL) { + PyErr_SetNone(PyExc_KeyboardInterrupt); + g_main_loop_quit(main_loop); + } + + pyglib_gil_state_release(state); + + return FALSE; +} + +static gboolean +pyg_signal_watch_dispatch(GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + /* We should never be dispatched */ + g_assert_not_reached(); + return TRUE; +} + +static void +pyg_signal_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) + close(real_source->fds[1]); + } +} + +static GSourceFuncs pyg_signal_watch_funcs = +{ + pyg_signal_watch_prepare, + pyg_signal_watch_check, + pyg_signal_watch_dispatch, + pyg_signal_watch_finalize +}; + +static GSource * +pyg_signal_watch_new(void) +{ + return g_source_new(&pyg_signal_watch_funcs, sizeof(PySignalWatchSource)); +} + +static int +pyg_main_loop_new(PyGMainLoop *self, PyObject *args, PyObject *kwargs) +{ + + static char *kwlist[] = { "context", "is_running", NULL }; + PyObject *py_context = Py_None; + int is_running; + GMainContext *context; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|Ob:GMainLoop.__init__", + kwlist, &py_context, &is_running)) + return -1; + + if (!PyObject_TypeCheck(py_context, &PyGMainContext_Type) && + py_context != Py_None) { + PyErr_SetString(PyExc_TypeError, + "context must be a glib.GMainContext or None"); + return -1; + } + + if (py_context != Py_None) { + context = ((PyGMainContext*)py_context)->context; + } else { + context = NULL; + } + + self->loop = g_main_loop_new(context, is_running); + + self->signal_source = pyg_signal_watch_new(); + g_source_attach(self->signal_source, context); + + return 0; +} + +static void +pyg_main_loop_dealloc(PyGMainLoop *self) +{ + if (self->signal_source != NULL) { + g_source_destroy(self->signal_source); + self->signal_source = NULL; + } + + if (self->loop != NULL) { + g_main_loop_unref(self->loop); + self->loop = NULL; + } + + PyObject_Del(self); +} + +static int +pyg_main_loop_compare(PyGMainLoop *self, PyGMainLoop *v) +{ + if (self->loop == v->loop) return 0; + if (self->loop > v->loop) return -1; + return 1; +} + +static PyObject * +_wrap_g_main_loop_get_context (PyGMainLoop *loop) +{ + return pyglib_main_context_new(g_main_loop_get_context(loop->loop)); +} + +static PyObject * +_wrap_g_main_loop_is_running (PyGMainLoop *self) +{ + return PyBool_FromLong(g_main_loop_is_running(self->loop)); +} + +static PyObject * +_wrap_g_main_loop_quit (PyGMainLoop *self) +{ + g_main_loop_quit(self->loop); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +_wrap_g_main_loop_run (PyGMainLoop *self) +{ + GMainLoop *prev_loop; + + prev_loop = pyg_save_current_main_loop(self->loop); + + pyglib_begin_allow_threads; + g_main_loop_run(self->loop); + pyglib_end_allow_threads; + + pyg_restore_current_main_loop(prev_loop); + + if (PyErr_Occurred()) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef _PyGMainLoop_methods[] = { + { "get_context", (PyCFunction)_wrap_g_main_loop_get_context, METH_NOARGS }, + { "is_running", (PyCFunction)_wrap_g_main_loop_is_running, METH_NOARGS }, + { "quit", (PyCFunction)_wrap_g_main_loop_quit, METH_NOARGS }, + { "run", (PyCFunction)_wrap_g_main_loop_run, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +PyTypeObject PyGMainLoop_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "glib.MainLoop", + sizeof(PyGMainLoop), + 0, + /* methods */ + (destructor)pyg_main_loop_dealloc, + (printfunc)0, + (getattrfunc)0, + (setattrfunc)0, + (cmpfunc)pyg_main_loop_compare, + (reprfunc)0, + 0, + 0, + 0, + (hashfunc)0, + (ternaryfunc)0, + (reprfunc)0, + (getattrofunc)0, + (setattrofunc)0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + NULL, + (traverseproc)0, + (inquiry)0, + (richcmpfunc)0, + 0, + (getiterfunc)0, + (iternextfunc)0, + _PyGMainLoop_methods, + 0, + 0, + NULL, + NULL, + (descrgetfunc)0, + (descrsetfunc)0, + 0, + (initproc)pyg_main_loop_new, +}; + +void +pyglib_mainloop_register_types(PyObject *d) +{ + PYGLIB_REGISTER_TYPE(d, PyGMainLoop_Type, "MainLoop"); +} diff --git a/glib/pygmainloop.h b/glib/pygmainloop.h new file mode 100644 index 0000000..cdb44db --- /dev/null +++ b/glib/pygmainloop.h @@ -0,0 +1,36 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pyglib - Python bindings for GLib toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef __PYG_MAINLOOP_H__ +#define __PYG_MAINLOOP_H__ + +typedef struct { + PyObject_HEAD + GMainLoop *loop; + GSource *signal_source; +} PyGMainLoop; + +extern PyTypeObject PyGMainLoop_Type; + +void pyglib_mainloop_register_types(PyObject *d); + +#endif /* __PYG_MAINLOOP_H__ */ + diff --git a/gobject/Makefile.am b/gobject/Makefile.am index f506c3b..dfd0f50 100644 --- a/gobject/Makefile.am +++ b/gobject/Makefile.am @@ -51,8 +51,6 @@ _gobject_la_SOURCES = \ pygobject.c \ pygobject.h \ pygobject-private.h \ - pygmaincontext.c \ - pygmainloop.c \ pygparamspec.c \ pygpointer.c \ pygiochannel.c \ diff --git a/gobject/__init__.py b/gobject/__init__.py index 8eff77e..19bdd0c 100644 --- a/gobject/__init__.py +++ b/gobject/__init__.py @@ -31,7 +31,8 @@ from glib import spawn_async, idle_add, timeout_add, timeout_add_seconds, \ io_add_watch, source_remove, child_watch_add, markup_escape_text, \ get_current_time, filename_display_name, filename_display_basename, \ filename_from_utf8, get_application_name, set_application_name, \ - get_prgname, set_prgname, main_depth, Pid, GError, glib_version + get_prgname, set_prgname, main_depth, Pid, GError, glib_version, \ + MainLoop, MainContext, main_context_default from gobject.constants import * from _gobject import * _PyGObject_API = _gobject._PyGObject_API diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c index 0a55ce6..5af2c38 100644 --- a/gobject/gobjectmodule.c +++ b/gobject/gobjectmodule.c @@ -100,9 +100,9 @@ pyg_destroy_notify(gpointer user_data) PyObject *obj = (PyObject *)user_data; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); Py_DECREF(obj); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } @@ -125,9 +125,9 @@ pyobject_free(gpointer boxed) PyObject *object = boxed; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); Py_DECREF(object); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } @@ -241,9 +241,6 @@ pyg_lookup_interface_info(GType gtype) return g_type_get_qdata(gtype, pyginterface_info_key); } -/* -------------- GMainContext objects ---------------------------- */ - - /* ---------------- gobject module functions -------------------- */ static PyObject * @@ -405,12 +402,12 @@ pyg_object_set_property (GObject *object, guint property_id, PyObject *py_pspec, *py_value; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); object_wrapper = pygobject_new(object); if (object_wrapper == NULL) { - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return; } @@ -429,7 +426,7 @@ pyg_object_set_property (GObject *object, guint property_id, Py_DECREF(py_pspec); Py_DECREF(py_value); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } static void @@ -440,12 +437,12 @@ pyg_object_get_property (GObject *object, guint property_id, PyObject *py_pspec; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); object_wrapper = pygobject_new(object); if (object_wrapper == NULL) { - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return; } @@ -459,7 +456,7 @@ pyg_object_get_property (GObject *object, guint property_id, Py_DECREF(py_pspec); Py_XDECREF(retval); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } static void @@ -486,7 +483,7 @@ _pyg_signal_accumulator(GSignalInvocationHint *ihint, PyGSignalAccumulatorData *data = _data; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); if (ihint->detail) py_detail = PyString_FromString(g_quark_to_string(ihint->detail)); else { @@ -520,7 +517,7 @@ _pyg_signal_accumulator(GSignalInvocationHint *ihint, } Py_DECREF(py_retval); } - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return retval; } @@ -1191,7 +1188,7 @@ pygobject__g_instance_init(GTypeInstance *instance, * g_object_new -> we have no python wrapper, so create it * now */ PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); wrapper = pygobject_new_full(object, FALSE, g_class); args = PyTuple_New(0); kwargs = PyDict_New(); @@ -1199,7 +1196,7 @@ pygobject__g_instance_init(GTypeInstance *instance, PyErr_Print(); Py_DECREF(args); Py_DECREF(kwargs); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } } @@ -1905,7 +1902,7 @@ pyg_handler_marshal(gpointer user_data) g_return_val_if_fail(user_data != NULL, FALSE); - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); tuple = (PyObject *)user_data; ret = PyObject_CallObject(PyTuple_GetItem(tuple, 0), @@ -1918,27 +1915,21 @@ pyg_handler_marshal(gpointer user_data) Py_DECREF(ret); } - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return res; } -static PyObject * -pyg_main_context_default(PyObject *unused) -{ - return pyg_main_context_new(g_main_context_default()); -} - static int -pyg_gil_state_ensure_py23 (void) +pygobject_gil_state_ensure (void) { - return PyGILState_Ensure(); + return pyglib_gil_state_ensure (); } static void -pyg_gil_state_release_py23 (int flag) +pygobject_gil_state_release (int flag) { - PyGILState_Release(flag); + pyglib_gil_state_release(flag); } static PyObject * @@ -1973,7 +1964,7 @@ marshal_emission_hook(GSignalInvocationHint *ihint, PyObject *params; guint i; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); /* construct Python tuple for the parameter values */ params = PyTuple_New(n_param_values); @@ -2004,7 +1995,7 @@ marshal_emission_hook(GSignalInvocationHint *ihint, retval = (retobj == Py_True ? TRUE : FALSE); Py_XDECREF(retobj); out: - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return retval; } @@ -2128,8 +2119,6 @@ static PyMethodDef pygobject_functions[] = { pyg_object_class_list_properties, METH_VARARGS }, { "new", (PyCFunction)pyg_object_new, METH_VARARGS|METH_KEYWORDS }, - { "main_context_default", - (PyCFunction)pyg_main_context_default, METH_NOARGS }, { "threads_init", (PyCFunction)pyg_threads_init, METH_VARARGS|METH_KEYWORDS }, { "signal_accumulator_true_handled", @@ -2536,9 +2525,9 @@ _log_func(const gchar *log_domain, PyGILState_STATE state; PyObject* warning = user_data; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); PyErr_Warn(warning, (char *) message); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } else g_log_default_handler(log_domain, log_level, message, user_data); } @@ -2649,8 +2638,8 @@ struct _PyGObject_Functions pygobject_api_functions = { FALSE, /* threads_enabled */ pyglib_enable_threads, - pyg_gil_state_ensure_py23, - pyg_gil_state_release_py23, + pygobject_gil_state_ensure, + pygobject_gil_state_release, pyg_register_class_init, pyg_register_interface_info, @@ -2691,6 +2680,7 @@ init_gobject(void) PyObject *m, *d, *o, *tuple, *features; PyObject *descr; PyObject *warning; + PyObject *glib; PyGParamSpec_Type.ob_type = &PyType_Type; if (PyType_Ready(&PyGParamSpec_Type)) @@ -2702,6 +2692,11 @@ init_gobject(void) PyDict_SetItemString(d, "GParamSpec", (PyObject *)&PyGParamSpec_Type); g_type_init(); + pyglib_init(); + + glib = PyImport_ImportModule("glib"); + _PyGMainLoop_Type = (PyTypeObject*)PyObject_GetAttrString(glib, "MainLoop"); + _PyGMainContext_Type = (PyTypeObject*)PyObject_GetAttrString(glib, "MainContext"); pygboxed_type_key = g_quark_from_static_string("PyGBoxed::class"); pygboxed_marshal_key = g_quark_from_static_string("PyGBoxed::marshal"); @@ -2758,9 +2753,6 @@ init_gobject(void) PyGFlags_Type.tp_base = &PyInt_Type; REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS); - REGISTER_TYPE(d, PyGMainLoop_Type, "MainLoop"); - REGISTER_TYPE(d, PyGMainContext_Type, "MainContext"); - REGISTER_TYPE(d, PyGIOChannel_Type, "IOChannel"); REGISTER_TYPE(d, PyGSource_Type, "Source"); diff --git a/gobject/pygboxed.c b/gobject/pygboxed.c index 93c86ad..01217bb 100644 --- a/gobject/pygboxed.c +++ b/gobject/pygboxed.c @@ -24,15 +24,16 @@ # include #endif +#include #include "pygobject-private.h" static void pyg_boxed_dealloc(PyGBoxed *self) { if (self->free_on_dealloc && self->boxed) { - PyGILState_STATE state = pyg_gil_state_ensure(); + PyGILState_STATE state = pyglib_gil_state_ensure(); g_boxed_free(self->gtype, self->boxed); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } self->ob_type->tp_free((PyObject *)self); @@ -213,11 +214,11 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, g_return_val_if_fail(boxed_type != 0, NULL); g_return_val_if_fail(!copy_boxed || (copy_boxed && own_ref), NULL); - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); if (!boxed) { Py_INCREF(Py_None); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return Py_None; } @@ -227,7 +228,7 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, self = PyObject_NEW(PyGBoxed, tp); if (self == NULL) { - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return NULL; } @@ -237,7 +238,7 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, self->gtype = boxed_type; self->free_on_dealloc = own_ref; - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return (PyObject *)self; } diff --git a/gobject/pygenum.c b/gobject/pygenum.c index 7de2b3b..28bdf70 100644 --- a/gobject/pygenum.c +++ b/gobject/pygenum.c @@ -25,6 +25,7 @@ # include #endif +#include #include "pygobject-private.h" static PyObject * @@ -190,7 +191,7 @@ pyg_enum_add (PyObject * module, return NULL; } - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); instance_dict = PyDict_New(); stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", @@ -199,7 +200,7 @@ pyg_enum_add (PyObject * module, Py_DECREF(instance_dict); if (!stub) { PyErr_SetString(PyExc_RuntimeError, "can't create const"); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return NULL; } @@ -255,7 +256,7 @@ pyg_enum_add (PyObject * module, g_type_class_unref(eclass); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return stub; } diff --git a/gobject/pygflags.c b/gobject/pygflags.c index 4f028b9..2ce2174 100644 --- a/gobject/pygflags.c +++ b/gobject/pygflags.c @@ -25,6 +25,7 @@ # include #endif +#include #include "pygobject-private.h" #define GET_INT_VALUE(x) (((PyIntObject*)x)->ob_ival) @@ -212,7 +213,7 @@ pyg_flags_add (PyObject * module, return NULL; } - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); instance_dict = PyDict_New(); stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", @@ -221,7 +222,7 @@ pyg_flags_add (PyObject * module, Py_DECREF(instance_dict); if (!stub) { PyErr_SetString(PyExc_RuntimeError, "can't create const"); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return NULL; } @@ -275,7 +276,7 @@ pyg_flags_add (PyObject * module, g_type_class_unref(eclass); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return stub; } diff --git a/gobject/pygiochannel.c b/gobject/pygiochannel.c index a7f3629..34ef837 100644 --- a/gobject/pygiochannel.c +++ b/gobject/pygiochannel.c @@ -4,6 +4,7 @@ # include #endif +#include #include "pygobject-private.h" #include "pythread.h" #include /* for PyMemberDef */ @@ -441,7 +442,7 @@ pyg_iowatch_marshal(GIOChannel *source, g_return_val_if_fail(((PyGIOChannel *) data->iochannel)->channel == source, FALSE); - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); if (data->user_data) ret = PyObject_CallFunction(data->callback, "OiO", data->iochannel, @@ -457,7 +458,7 @@ pyg_iowatch_marshal(GIOChannel *source, res = PyObject_IsTrue(ret); Py_DECREF(ret); } - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return res; } diff --git a/gobject/pygmaincontext.c b/gobject/pygmaincontext.c deleted file mode 100644 index b320eea..0000000 --- a/gobject/pygmaincontext.c +++ /dev/null @@ -1,144 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * - * pygmaincontext.c: GMainContext wrapper - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "pygobject-private.h" - -static int -pyg_main_context_init(PyGMainContext *self) -{ - self->context = g_main_context_new(); - return 0; -} - -static void -pyg_main_context_dealloc(PyGMainContext *self) -{ - if (self->context != NULL) { - g_main_context_unref(self->context); - self->context = NULL; - } - - PyObject_Del(self); -} - -static int -pyg_main_context_compare(PyGMainContext *self, PyGMainContext *v) -{ - if (self->context == v->context) return 0; - if (self->context > v->context) return -1; - return 1; -} - -static PyObject * -_wrap_g_main_context_iteration (PyGMainContext *self, PyObject *args) -{ - gboolean ret, may_block = TRUE; - - if (!PyArg_ParseTuple(args, "|i:GMainContext.iteration", - &may_block)) - return NULL; - - pyg_begin_allow_threads; - ret = g_main_context_iteration(self->context, may_block); - pyg_end_allow_threads; - - return PyBool_FromLong(ret); -} - -static PyObject * -_wrap_g_main_context_pending (PyGMainContext *self) -{ - return PyBool_FromLong(g_main_context_pending(self->context)); -} - -static PyMethodDef _PyGMainContext_methods[] = { - { "iteration", (PyCFunction)_wrap_g_main_context_iteration, METH_VARARGS }, - { "pending", (PyCFunction)_wrap_g_main_context_pending, METH_NOARGS }, - { NULL, NULL, 0 } -}; - -PyTypeObject PyGMainContext_Type = { - PyObject_HEAD_INIT(NULL) - 0, - "gobject.MainContext", - sizeof(PyGMainContext), - 0, - /* methods */ - (destructor)pyg_main_context_dealloc, - (printfunc)0, - (getattrfunc)0, - (setattrfunc)0, - (cmpfunc)pyg_main_context_compare, - (reprfunc)0, - 0, - 0, - 0, - (hashfunc)0, - (ternaryfunc)0, - (reprfunc)0, - (getattrofunc)0, - (setattrofunc)0, - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - NULL, - (traverseproc)0, - (inquiry)0, - (richcmpfunc)0, - 0, - (getiterfunc)0, - (iternextfunc)0, - _PyGMainContext_methods, - 0, - 0, - NULL, - NULL, - (descrgetfunc)0, - (descrsetfunc)0, - 0, - (initproc)pyg_main_context_init, -}; - -/** - * pyg_main_context_new: - * @context: a GMainContext. - * - * Creates a wrapper for a GMainContext. - * - * Returns: the GMainContext wrapper. - */ -PyObject * -pyg_main_context_new(GMainContext *context) -{ - PyGMainContext *self; - - self = (PyGMainContext *)PyObject_NEW(PyGMainContext, - &PyGMainContext_Type); - if (self == NULL) - return NULL; - - self->context = g_main_context_ref(context); - return (PyObject *)self; -} diff --git a/gobject/pygmainloop.c b/gobject/pygmainloop.c deleted file mode 100644 index c80c41f..0000000 --- a/gobject/pygmainloop.c +++ /dev/null @@ -1,368 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * Copyright (C) 2004 Johan Dahlin - * - * pygmainloop.c: GMainLoop wrapper - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "pygobject-private.h" -#include "pythread.h" - -#ifdef DISABLE_THREADING -static GMainLoop *pyg_current_main_loop = NULL;; - -static inline GMainLoop * -pyg_save_current_main_loop (GMainLoop *main_loop) -{ - GMainLoop *retval = pyg_current_main_loop; - - g_return_val_if_fail(main_loop != NULL, NULL); - - pyg_current_main_loop = g_main_loop_ref(main_loop); - - return retval; -} - -static inline void -pyg_restore_current_main_loop (GMainLoop *main_loop) -{ - if (pyg_current_main_loop != NULL) - g_main_loop_unref(pyg_current_main_loop); - pyg_current_main_loop = main_loop; -} - -static inline GMainLoop * -pyg_get_current_main_loop (void) -{ - return pyg_current_main_loop; -} -#else /* !defined(#ifndef DISABLE_THREADING) */ - -static int pyg_current_main_loop_key = -1; - -static inline GMainLoop * -pyg_save_current_main_loop (GMainLoop *main_loop) -{ - GMainLoop *retval; - - g_return_val_if_fail(main_loop != NULL, NULL); - - if (pyg_current_main_loop_key == -1) - pyg_current_main_loop_key = PyThread_create_key(); - - retval = PyThread_get_key_value(pyg_current_main_loop_key); - PyThread_delete_key_value(pyg_current_main_loop_key); - PyThread_set_key_value(pyg_current_main_loop_key, - g_main_loop_ref(main_loop)); - - return retval; -} - -static inline void -pyg_restore_current_main_loop (GMainLoop *main_loop) -{ - GMainLoop *prev; - - g_return_if_fail (pyg_current_main_loop_key != -1); - - prev = PyThread_get_key_value(pyg_current_main_loop_key); - if (prev != NULL) - g_main_loop_unref(prev); - PyThread_delete_key_value(pyg_current_main_loop_key); - if (main_loop != NULL) - PyThread_set_key_value(pyg_current_main_loop_key, main_loop); -} - -static inline GMainLoop * -pyg_get_current_main_loop (void) -{ - if (pyg_current_main_loop_key == -1) - return NULL; - return PyThread_get_key_value(pyg_current_main_loop_key); -} -#endif /* DISABLE_THREADING */ - -typedef struct { - GSource source; - int fds[2]; - GPollFD fd; -} PySignalWatchSource; - -static gboolean -pyg_signal_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. - */ - - /* 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 - 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 - * http://bugzilla.gnome.org/show_bug.cgi?id=481569 - */ - *timeout = 1000; -#endif /* HAVE_PYSIGNAL_SETWAKEUPFD */ - - return FALSE; -} - -static gboolean -pyg_signal_watch_check(GSource *source) -{ - PyGILState_STATE state; - GMainLoop *main_loop; - - state = pyg_gil_state_ensure(); - - main_loop = pyg_get_current_main_loop(); - - if (PyErr_CheckSignals() == -1 && main_loop != NULL) { - PyErr_SetNone(PyExc_KeyboardInterrupt); - g_main_loop_quit(main_loop); - } - - pyg_gil_state_release(state); - - return FALSE; -} - -static gboolean -pyg_signal_watch_dispatch(GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - /* We should never be dispatched */ - g_assert_not_reached(); - return TRUE; -} - -static void -pyg_signal_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) - close(real_source->fds[1]); - } -} - -static GSourceFuncs pyg_signal_watch_funcs = -{ - pyg_signal_watch_prepare, - pyg_signal_watch_check, - pyg_signal_watch_dispatch, - pyg_signal_watch_finalize -}; - -static GSource * -pyg_signal_watch_new(void) -{ - return g_source_new(&pyg_signal_watch_funcs, sizeof(PySignalWatchSource)); -} - -static int -pyg_main_loop_new(PyGMainLoop *self, PyObject *args, PyObject *kwargs) -{ - - static char *kwlist[] = { "context", "is_running", NULL }; - PyObject *py_context = Py_None; - int is_running; - GMainContext *context; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|Ob:GMainLoop.__init__", - kwlist, &py_context, &is_running)) - return -1; - - if (!PyObject_TypeCheck(py_context, &PyGMainContext_Type) && - py_context != Py_None) { - PyErr_SetString(PyExc_TypeError, - "context must be a gobject.GMainContext or None"); - return -1; - } - - if (py_context != Py_None) { - context = ((PyGMainContext*)py_context)->context; - } else { - context = NULL; - } - - self->loop = g_main_loop_new(context, is_running); - - self->signal_source = pyg_signal_watch_new(); - g_source_attach(self->signal_source, context); - - return 0; -} - -static void -pyg_main_loop_dealloc(PyGMainLoop *self) -{ - if (self->signal_source != NULL) { - g_source_destroy(self->signal_source); - self->signal_source = NULL; - } - - if (self->loop != NULL) { - g_main_loop_unref(self->loop); - self->loop = NULL; - } - - PyObject_Del(self); -} - -static int -pyg_main_loop_compare(PyGMainLoop *self, PyGMainLoop *v) -{ - if (self->loop == v->loop) return 0; - if (self->loop > v->loop) return -1; - return 1; -} - -static PyObject * -_wrap_g_main_loop_get_context (PyGMainLoop *loop) -{ - return pyg_main_context_new(g_main_loop_get_context(loop->loop)); -} - -static PyObject * -_wrap_g_main_loop_is_running (PyGMainLoop *self) -{ - return PyBool_FromLong(g_main_loop_is_running(self->loop)); -} - -static PyObject * -_wrap_g_main_loop_quit (PyGMainLoop *self) -{ - g_main_loop_quit(self->loop); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -_wrap_g_main_loop_run (PyGMainLoop *self) -{ - GMainLoop *prev_loop; - - prev_loop = pyg_save_current_main_loop(self->loop); - - pyg_begin_allow_threads; - g_main_loop_run(self->loop); - pyg_end_allow_threads; - - pyg_restore_current_main_loop(prev_loop); - - if (PyErr_Occurred()) - return NULL; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef _PyGMainLoop_methods[] = { - { "get_context", (PyCFunction)_wrap_g_main_loop_get_context, METH_NOARGS }, - { "is_running", (PyCFunction)_wrap_g_main_loop_is_running, METH_NOARGS }, - { "quit", (PyCFunction)_wrap_g_main_loop_quit, METH_NOARGS }, - { "run", (PyCFunction)_wrap_g_main_loop_run, METH_NOARGS }, - { NULL, NULL, 0 } -}; - -PyTypeObject PyGMainLoop_Type = { - PyObject_HEAD_INIT(NULL) - 0, - "gobject.MainLoop", - sizeof(PyGMainLoop), - 0, - /* methods */ - (destructor)pyg_main_loop_dealloc, - (printfunc)0, - (getattrfunc)0, - (setattrfunc)0, - (cmpfunc)pyg_main_loop_compare, - (reprfunc)0, - 0, - 0, - 0, - (hashfunc)0, - (ternaryfunc)0, - (reprfunc)0, - (getattrofunc)0, - (setattrofunc)0, - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - NULL, - (traverseproc)0, - (inquiry)0, - (richcmpfunc)0, - 0, - (getiterfunc)0, - (iternextfunc)0, - _PyGMainLoop_methods, - 0, - 0, - NULL, - NULL, - (descrgetfunc)0, - (descrsetfunc)0, - 0, - (initproc)pyg_main_loop_new, -}; diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h index 4b41338..5b71ed5 100644 --- a/gobject/pygobject-private.h +++ b/gobject/pygobject-private.h @@ -218,7 +218,8 @@ typedef struct { GSource *signal_source; } PyGMainLoop; -extern PyTypeObject PyGMainLoop_Type; +PyTypeObject *_PyGMainLoop_Type; +#define PyGMainLoop_Type (*_PyGMainLoop_Type) /* pygmaincontext */ @@ -227,8 +228,8 @@ typedef struct { GMainContext *context; } PyGMainContext; -extern PyTypeObject PyGMainContext_Type; -PyObject * pyg_main_context_new (GMainContext *context); +PyTypeObject *_PyGMainContext_Type; +#define PyGMainContext_Type (*_PyGMainContext_Type) /* pygparamspec */ diff --git a/gobject/pygobject.c b/gobject/pygobject.c index 4563500..d41971d 100644 --- a/gobject/pygobject.c +++ b/gobject/pygobject.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ + +#include #include "pygobject-private.h" static void pygobject_dealloc(PyGObject *self); @@ -35,7 +37,7 @@ static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObj void pygobject_data_free(PyGObjectData *data) { - PyGILState_STATE state = pyg_gil_state_ensure(); + PyGILState_STATE state = pyglib_gil_state_ensure(); GSList *closures, *tmp; Py_DECREF(data->type); tmp = closures = data->closures; @@ -58,7 +60,7 @@ pygobject_data_free(PyGObjectData *data) g_warning("invalidated all closures, but data->closures != NULL !"); g_free(data); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } static inline PyGObjectData * @@ -629,14 +631,14 @@ pyg_toggle_notify (gpointer data, GObject *object, gboolean is_last_ref) PyGObject *self = (PyGObject*) data; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); if (is_last_ref) Py_DECREF(self); else Py_INCREF(self); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } /* Called when the inst_dict is first created; switches the @@ -744,7 +746,7 @@ pygobject_new_with_interfaces(GType gtype) PyObject *modules, *module; gchar *type_name, *mod_name, *gtype_name; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); bases = pyg_type_get_bases(gtype); py_parent_type = (PyTypeObject *) PyTuple_GetItem(bases, 0); @@ -787,7 +789,7 @@ pygobject_new_with_interfaces(GType gtype) if (type == NULL) { PyErr_Print(); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return NULL; } @@ -810,7 +812,7 @@ pygobject_new_with_interfaces(GType gtype) if (PyType_Ready(type) < 0) { g_warning ("couldn't make the type `%s' ready", type->tp_name); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return NULL; } /* insert type name in module dict */ @@ -824,7 +826,7 @@ pygobject_new_with_interfaces(GType gtype) Py_INCREF(type); g_type_set_qdata(gtype, pygobject_class_key, type); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return type; } @@ -2131,7 +2133,7 @@ pygobject_weak_ref_notify(PyGObjectWeakRef *self, GObject *dummy) self->obj = NULL; if (self->callback) { PyObject *retval; - PyGILState_STATE state = pyg_gil_state_ensure(); + PyGILState_STATE state = pyglib_gil_state_ensure(); retval = PyObject_Call(self->callback, self->user_data, NULL); if (retval) { if (retval != Py_None) @@ -2149,7 +2151,7 @@ pygobject_weak_ref_notify(PyGObjectWeakRef *self, GObject *dummy) self->have_floating_ref = FALSE; Py_DECREF((PyObject *) self); } - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } } diff --git a/gobject/pygobject.h b/gobject/pygobject.h index 76ab437..592853a 100644 --- a/gobject/pygobject.h +++ b/gobject/pygobject.h @@ -176,7 +176,6 @@ struct _PyGObject_Functions { gboolean threads_enabled; int (*enable_threads) (void); - /* These 2 are deprecated */ int (*gil_state_ensure) (void); void (*gil_state_release) (int flag); @@ -254,6 +253,8 @@ struct _PyGObject_Functions *_PyGObject_API; #define pyg_flags_add (_PyGObject_API->flags_add) #define pyg_flags_from_gtype (_PyGObject_API->flags_from_gtype) #define pyg_enable_threads (_PyGObject_API->enable_threads) +#define pyg_gil_state_ensure (_PyGObject_API->gil_state_ensure) +#define pyg_gil_state_release (_PyGObject_API->gil_state_release) #define pyg_register_class_init (_PyGObject_API->register_class_init) #define pyg_register_interface_info (_PyGObject_API->register_interface_info) #define pygobject_construct (_PyGObject_API->pygobject_construct) @@ -265,7 +266,6 @@ struct _PyGObject_Functions *_PyGObject_API; #define pyg_gerror_exception_check (_PyGObject_API->gerror_exception_check) #define pyg_option_group_new (_PyGObject_API->option_group_new) - #define pyg_block_threads() G_STMT_START { \ if (_PyGObject_API->block_threads != NULL) \ (* _PyGObject_API->block_threads)(); \ @@ -277,14 +277,6 @@ struct _PyGObject_Functions *_PyGObject_API; #define pyg_threads_enabled (_PyGObject_API->threads_enabled) -#define pyg_gil_state_ensure() \ - (_PyGObject_API->threads_enabled ? \ - (PyGILState_Ensure()) : 0) -#define pyg_gil_state_release(state) G_STMT_START { \ - if (_PyGObject_API->threads_enabled) \ - PyGILState_Release(state); \ - } G_STMT_END - #define pyg_begin_allow_threads \ G_STMT_START { \ PyThreadState *_save = NULL; \ diff --git a/gobject/pygoptiongroup.c b/gobject/pygoptiongroup.c index 6465401..770a497 100644 --- a/gobject/pygoptiongroup.c +++ b/gobject/pygoptiongroup.c @@ -24,6 +24,7 @@ # include #endif +#include #include "pygobject-private.h" #include "pygobject.h" @@ -43,7 +44,7 @@ static void destroy_g_group(PyGOptionGroup *self) { PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); self->group = NULL; Py_CLEAR(self->callback); @@ -56,7 +57,7 @@ destroy_g_group(PyGOptionGroup *self) Py_DECREF(self); } - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } static int @@ -107,7 +108,7 @@ arg_func(const gchar *option_name, PyGILState_STATE state; gboolean no_error; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); if (value == NULL) { @@ -123,13 +124,13 @@ arg_func(const gchar *option_name, if (ret != NULL) { Py_DECREF(ret); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return TRUE; } else { no_error = pyg_gerror_exception_check(error) != -1; - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return no_error; } } diff --git a/gobject/pygpointer.c b/gobject/pygpointer.c index 33caea2..6a7d9e2 100644 --- a/gobject/pygpointer.c +++ b/gobject/pygpointer.c @@ -24,6 +24,7 @@ # include #endif +#include #include "pygobject-private.h" static void @@ -185,11 +186,11 @@ pyg_pointer_new(GType pointer_type, gpointer pointer) PyTypeObject *tp; g_return_val_if_fail(pointer_type != 0, NULL); - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); if (!pointer) { Py_INCREF(Py_None); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return Py_None; } @@ -198,7 +199,7 @@ pyg_pointer_new(GType pointer_type, gpointer pointer) tp = (PyTypeObject *)&PyGPointer_Type; /* fallback */ self = PyObject_NEW(PyGPointer, tp); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); if (self == NULL) return NULL; diff --git a/gobject/pygsource.c b/gobject/pygsource.c index 53d0cae..ae667dc 100644 --- a/gobject/pygsource.c +++ b/gobject/pygsource.c @@ -30,6 +30,7 @@ #include "pygobject-private.h" #include "pythread.h" #include +#include #define CHECK_DESTROYED(self, ret) G_STMT_START { \ @@ -174,7 +175,7 @@ pyg_source_get_context(PyGSource *self) context = g_source_get_context(self->source); if (context) { - return pyg_main_context_new(context); + return pyglib_main_context_new(context); } else { Py_INCREF(Py_None); return Py_None; @@ -397,7 +398,7 @@ pyg_source_prepare(GSource *source, gint *timeout) gboolean got_err = TRUE; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); t = PyObject_CallMethod(pysource->obj, "prepare", NULL); @@ -433,7 +434,7 @@ bail: Py_XDECREF(t); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return ret; } @@ -446,7 +447,7 @@ pyg_source_check(GSource *source) gboolean ret; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); t = PyObject_CallMethod(pysource->obj, "check", NULL); @@ -458,7 +459,7 @@ pyg_source_check(GSource *source) Py_DECREF(t); } - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return ret; } @@ -471,7 +472,7 @@ pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) gboolean ret; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); if (callback) { tuple = user_data; @@ -493,7 +494,7 @@ pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) Py_DECREF(t); } - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return ret; } @@ -505,7 +506,7 @@ pyg_source_finalize(GSource *source) PyObject *func, *t; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); func = PyObject_GetAttrString(pysource->obj, "finalize"); if (func) { @@ -519,7 +520,7 @@ pyg_source_finalize(GSource *source) } } - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } static GSourceFuncs pyg_source_funcs = diff --git a/gobject/pygtype.c b/gobject/pygtype.c index 897234a..eb5b0bc 100644 --- a/gobject/pygtype.c +++ b/gobject/pygtype.c @@ -20,6 +20,8 @@ * USA */ +#include + #include "pygobject-private.h" /* -------------- __gtype__ objects ---------------------------- */ @@ -1076,11 +1078,11 @@ pyg_closure_invalidate(gpointer data, GClosure *closure) PyGClosure *pc = (PyGClosure *)closure; PyGILState_STATE state; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); Py_XDECREF(pc->callback); Py_XDECREF(pc->extra_args); Py_XDECREF(pc->swap_data); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); pc->callback = NULL; pc->extra_args = NULL; @@ -1100,7 +1102,7 @@ pyg_closure_marshal(GClosure *closure, PyObject *params, *ret; guint i; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); /* construct Python tuple for the parameter values */ params = PyTuple_New(n_param_values); @@ -1148,7 +1150,7 @@ pyg_closure_marshal(GClosure *closure, out: Py_DECREF(params); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } /** @@ -1241,7 +1243,7 @@ pyg_signal_class_closure_marshal(GClosure *closure, PyObject *params, *ret; guint i, len; - state = pyg_gil_state_ensure(); + state = pyglib_gil_state_ensure(); g_return_if_fail(invocation_hint != NULL); /* get the object passed as the first argument to the closure */ @@ -1267,7 +1269,7 @@ pyg_signal_class_closure_marshal(GClosure *closure, if (!method) { PyErr_Clear(); Py_DECREF(object_wrapper); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return; } Py_DECREF(object_wrapper); @@ -1281,7 +1283,7 @@ pyg_signal_class_closure_marshal(GClosure *closure, /* error condition */ if (!item) { Py_DECREF(params); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return; } PyTuple_SetItem(params, i - 1, item); @@ -1308,7 +1310,7 @@ pyg_signal_class_closure_marshal(GClosure *closure, PyErr_Print(); Py_DECREF(method); Py_DECREF(params); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); return; } Py_DECREF(method); @@ -1316,7 +1318,7 @@ pyg_signal_class_closure_marshal(GClosure *closure, if (return_value) pyg_value_from_pyobject(return_value, ret); Py_DECREF(ret); - pyg_gil_state_release(state); + pyglib_gil_state_release(state); } /** diff --git a/tests/common.py b/tests/common.py index 8568635..fe7940f 100644 --- a/tests/common.py +++ b/tests/common.py @@ -8,6 +8,7 @@ def importModules(buildDir, srcDir): # ltihooks sys.path.insert(0, srcDir) sys.path.insert(0, buildDir) + sys.path.insert(0, os.path.join(buildDir, 'glib')) sys.path.insert(0, os.path.join(buildDir, 'gobject')) sys.path.insert(0, os.path.join(buildDir, 'gio')) import ltihooks @@ -17,6 +18,7 @@ def importModules(buildDir, srcDir): sys.argv.append('--g-fatal-warnings') testhelper = importModule('testhelper', '.') + glib = importModule('glib', buildDir, 'glib') gobject = importModule('gobject', buildDir, 'gobject') gio = importModule('gio', buildDir, 'gio') -- cgit