summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gobject/gobjectmodule.c4
-rw-r--r--gobject/pygobject-private.h2
-rw-r--r--gobject/pygobject.h4
-rw-r--r--gobject/pygtype.c40
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