diff options
-rw-r--r-- | gobject/gobjectmodule.c | 4 | ||||
-rw-r--r-- | gobject/pygobject-private.h | 2 | ||||
-rw-r--r-- | gobject/pygobject.h | 4 | ||||
-rw-r--r-- | gobject/pygtype.c | 40 |
4 files changed, 45 insertions, 5 deletions
diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c index 10aea45..89819c6 100644 --- a/gobject/gobjectmodule.c +++ b/gobject/gobjectmodule.c @@ -2394,7 +2394,9 @@ struct _PyGObject_Functions pygobject_api_functions = { pyg_gil_state_ensure_py23, pyg_gil_state_release_py23, pyg_register_class_init, - pyg_register_interface_info + pyg_register_interface_info, + + pyg_closure_set_exception_handler }; #define REGISTER_TYPE(d, type, name) \ diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h index c5852e8..54a110e 100644 --- a/gobject/pygobject-private.h +++ b/gobject/pygobject-private.h @@ -69,6 +69,8 @@ PyObject *pyg_param_gvalue_as_pyobject(const GValue* gvalue, const GParamSpec* pspec); GClosure *pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data); +void pyg_closure_set_exception_handler(GClosure *closure, + PyClosureExceptionHandler handler); GClosure *pyg_signal_class_closure_get(void); PyObject *pyg_object_descr_doc_get(void); diff --git a/gobject/pygobject.h b/gobject/pygobject.h index 22e488c..b0c387e 100644 --- a/gobject/pygobject.h +++ b/gobject/pygobject.h @@ -17,12 +17,14 @@ G_BEGIN_DECLS #endif /* PyGClosure is a _private_ structure */ +typedef void (* PyClosureExceptionHandler) (GValue *ret, guint n_param_values, const GValue *params); typedef struct _PyGClosure PyGClosure; struct _PyGClosure { GClosure closure; PyObject *callback; PyObject *extra_args; /* tuple of extra args to pass to callback */ PyObject *swap_data; /* other object for gtk_signal_connect_object */ + PyClosureExceptionHandler exception_handler; }; typedef struct { @@ -160,6 +162,7 @@ struct _PyGObject_Functions { void (*gil_state_release) (int flag); void (*register_class_init) (GType gtype, PyGClassInitFunc class_init); void (*register_interface_info) (GType gtype, const GInterfaceInfo *info); + void (*closure_set_exception_handler) (GClosure *closure, PyClosureExceptionHandler handler); }; #ifndef _INSIDE_PYGOBJECT_ @@ -177,6 +180,7 @@ struct _PyGObject_Functions *_PyGObject_API; #define pygobject_new (_PyGObject_API->newgobj) #define pyg_closure_new (_PyGObject_API->closure_new) #define pygobject_watch_closure (_PyGObject_API->object_watch_closure) +#define pyg_closure_set_exception_handler (_PyGObject_API->closure_set_exception_handler) #define pyg_destroy_notify (_PyGObject_API->destroy_notify) #define pyg_type_from_object (_PyGObject_API->type_from_object) #define pyg_type_wrapper_new (_PyGObject_API->type_wrapper_new) diff --git a/gobject/pygtype.c b/gobject/pygtype.c index 37acf3f..92b9ec4 100644 --- a/gobject/pygtype.c +++ b/gobject/pygtype.c @@ -846,16 +846,26 @@ pyg_closure_marshal(GClosure *closure, } ret = PyObject_CallObject(pc->callback, params); if (ret == NULL) { - PyErr_Print(); + if (pc->exception_handler) + pc->exception_handler(return_value, n_param_values, param_values); + else + PyErr_Print(); goto out; } - if (return_value) - pyg_value_from_pyobject(return_value, ret); + + if (return_value && pyg_value_from_pyobject(return_value, ret) != 0) { + PyErr_SetString(PyExc_TypeError, + "can't convert return value to desired type"); + + if (pc->exception_handler) + pc->exception_handler(return_value, n_param_values, param_values); + else + PyErr_Print(); + } Py_DECREF(ret); out: Py_DECREF(params); - pyg_gil_state_release(state); } @@ -899,6 +909,28 @@ pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data) return closure; } +/** + * pyg_closure_set_exception_handler: + * @closure: a closure created with pyg_closure_new() + * @handler: the handler to call when an exception occurs or NULL for none + * + * Sets the handler to call when an exception occurs during closure invocation. + * The handler is responsible for providing a proper return value to the + * closure invocation. If @handler is %NULL, the default handler will be used. + * The default handler prints the exception to stderr and doesn't touch the + * closure's return value. + */ +void +pyg_closure_set_exception_handler(GClosure *closure, + PyClosureExceptionHandler handler) +{ + PyGClosure *pygclosure; + + g_return_if_fail(closure != NULL); + + pygclosure = (PyGClosure *)closure; + pygclosure->exception_handler = handler; +} /* -------------- PySignalClassClosure ----------------- */ /* a closure used for the `class closure' of a signal. As this gets * all the info from the first argument to the closure and the |