summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Henstridge <james@daa.com.au>2002-01-22 06:01:43 +0000
committerJames Henstridge <jamesh@src.gnome.org>2002-01-22 06:01:43 +0000
commit0791c30d0a5b0bbb46a214e8eeaba2a9115f069e (patch)
treecbea44099f293a4a9808db4093e1aaf02fbfbc15
parent7278c4a1b42e81be6a0ce3836bb1b0f1c8ba9a64 (diff)
downloadpygobject-0791c30d0a5b0bbb46a214e8eeaba2a9115f069e.tar.gz
pygobject-0791c30d0a5b0bbb46a214e8eeaba2a9115f069e.tar.xz
pygobject-0791c30d0a5b0bbb46a214e8eeaba2a9115f069e.zip
move closure stuff here.
2002-01-22 James Henstridge <james@daa.com.au> * pygtype.c: move closure stuff here.
-rw-r--r--gobject/pygobject-private.h4
-rw-r--r--gobject/pygtype.c205
2 files changed, 209 insertions, 0 deletions
diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h
index 8c1c637..3c767ca 100644
--- a/gobject/pygobject-private.h
+++ b/gobject/pygobject-private.h
@@ -34,6 +34,10 @@ void pyg_register_boxed_custom(GType boxed_type,
int pyg_value_from_pyobject(GValue *value, PyObject *obj);
PyObject *pyg_value_as_pyobject(const GValue *value);
+GClosure *pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data);
+GClosure *pyg_signal_class_closure_get(void);
+
+
/* from pygboxed.c */
extern PyTypeObject PyGBoxed_Type;
diff --git a/gobject/pygtype.c b/gobject/pygtype.c
index fdda265..fc2d15f 100644
--- a/gobject/pygtype.c
+++ b/gobject/pygtype.c
@@ -556,3 +556,208 @@ pyg_value_as_pyobject(const GValue *value)
return NULL;
}
+/* -------------- PyGClosure ----------------- */
+
+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 */
+};
+
+static void
+pyg_closure_destroy(gpointer data, GClosure *closure)
+{
+ PyGClosure *pc = (PyGClosure *)closure;
+
+ pyg_block_threads();
+ Py_DECREF(pc->callback);
+ Py_XDECREF(pc->extra_args);
+ Py_XDECREF(pc->swap_data);
+ pyg_unblock_threads();
+}
+
+/* XXXX - need to handle python thread context stuff */
+static void
+pyg_closure_marshal(GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ PyGClosure *pc = (PyGClosure *)closure;
+ PyObject *params, *ret;
+ guint i;
+
+ pyg_block_threads();
+ /* construct Python tuple for the parameter values */
+ params = PyTuple_New(n_param_values);
+ for (i = 0; i < n_param_values; i++) {
+ /* swap in a different initial data for connect_object() */
+ if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) {
+ g_return_if_fail(pc->swap_data != NULL);
+ Py_INCREF(pc->swap_data);
+ PyTuple_SetItem(params, 0, pc->swap_data);
+ } else {
+ PyObject *item = pyg_value_as_pyobject(&param_values[i]);
+
+ /* error condition */
+ if (!item) {
+ Py_DECREF(params);
+ pyg_unblock_threads();
+ return;
+ }
+ PyTuple_SetItem(params, i, item);
+ }
+ }
+ /* params passed to function may have extra arguments */
+ if (pc->extra_args) {
+ PyObject *tuple = params;
+ params = PySequence_Concat(tuple, pc->extra_args);
+ Py_DECREF(tuple);
+ }
+ ret = PyObject_CallObject(pc->callback, params);
+ if (ret == NULL) {
+ PyErr_Print();
+ PyErr_Clear();
+ pyg_unblock_threads();
+ return;
+ }
+ if (return_value)
+ pyg_value_from_pyobject(return_value, ret);
+ Py_DECREF(ret);
+ pyg_unblock_threads();
+}
+
+GClosure *
+pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data)
+{
+ GClosure *closure;
+
+ g_return_val_if_fail(callback != NULL, NULL);
+ closure = g_closure_new_simple(sizeof(PyGClosure), NULL);
+ g_closure_add_finalize_notifier(closure, NULL, pyg_closure_destroy);
+ g_closure_set_marshal(closure, pyg_closure_marshal);
+ Py_INCREF(callback);
+ ((PyGClosure *)closure)->callback = callback;
+ if (extra_args && extra_args != Py_None) {
+ Py_INCREF(extra_args);
+ if (!PyTuple_Check(extra_args)) {
+ PyObject *tmp = PyTuple_New(1);
+ PyTuple_SetItem(tmp, 0, extra_args);
+ extra_args = tmp;
+ }
+ ((PyGClosure *)closure)->extra_args = extra_args;
+ }
+ if (swap_data) {
+ Py_INCREF(swap_data);
+ ((PyGClosure *)closure)->swap_data = swap_data;
+ closure->derivative_flag = TRUE;
+ }
+ return closure;
+}
+
+/* -------------- 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
+ * invocation hint, we can have a single closure that handles all
+ * class closure cases. We call a method by the name of the signal
+ * with "do_" prepended.
+ *
+ * We also remove the first argument from the * param list, as it is
+ * the instance object, which is passed * implicitly to the method
+ * object. */
+
+static void
+pyg_signal_class_closure_marshal(GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ GObject *object;
+ PyObject *object_wrapper;
+ GSignalInvocationHint *hint = (GSignalInvocationHint *)invocation_hint;
+ gchar *method_name, *tmp;
+ PyObject *method;
+ PyObject *params, *ret;
+ guint i;
+
+ g_return_if_fail(invocation_hint != NULL);
+
+ pyg_block_threads();
+ /* get the object passed as the first argument to the closure */
+ object = g_value_get_object(&param_values[0]);
+ g_return_if_fail(object != NULL && G_IS_OBJECT(object));
+
+ /* get the wrapper for this object */
+ object_wrapper = pygobject_new(object);
+ g_return_if_fail(object_wrapper != NULL);
+
+ /* construct method name for this class closure */
+ method_name = g_strconcat("do_", g_signal_name(hint->signal_id), NULL);
+
+ /* convert dashes to underscores. For some reason, g_signal_name
+ * seems to convert all the underscores in the signal name to
+ dashes??? */
+ for (tmp = method_name; *tmp != '\0'; tmp++)
+ if (*tmp == '-') *tmp = '_';
+
+ method = PyObject_GetAttrString(object_wrapper, method_name);
+ g_free(method_name);
+
+ if (!method) {
+ PyErr_Clear();
+ Py_DECREF(object_wrapper);
+ pyg_unblock_threads();
+ return;
+ }
+ Py_DECREF(object_wrapper);
+
+ /* construct Python tuple for the parameter values */
+ params = PyTuple_New(n_param_values - 1);
+ for (i = 1; i < n_param_values; i++) {
+ PyObject *item = pyg_value_as_pyobject(&param_values[i]);
+
+ /* error condition */
+ if (!item) {
+ Py_DECREF(params);
+ pyg_unblock_threads();
+ return;
+ }
+ PyTuple_SetItem(params, i - 1, item);
+ }
+
+ ret = PyObject_CallObject(method, params);
+ if (ret == NULL) {
+ PyErr_Print();
+ PyErr_Clear();
+ Py_DECREF(method);
+ pyg_unblock_threads();
+ return;
+ }
+ Py_DECREF(method);
+ if (return_value)
+ pyg_value_from_pyobject(return_value, ret);
+ Py_DECREF(ret);
+ pyg_unblock_threads();
+}
+
+GClosure *
+pyg_signal_class_closure_get(void)
+{
+ static GClosure *closure;
+
+ if (closure == NULL) {
+ closure = g_closure_new_simple(sizeof(GClosure), NULL);
+ g_closure_set_marshal(closure, pyg_signal_class_closure_marshal);
+
+ g_closure_ref(closure);
+ g_closure_sink(closure);
+ }
+ return closure;
+}
+