diff options
| author | Gustavo J. A. M. Carneiro <gjc@src.gnome.org> | 2005-07-09 18:25:32 +0000 |
|---|---|---|
| committer | Gustavo J. A. M. Carneiro <gjc@src.gnome.org> | 2005-07-09 18:25:32 +0000 |
| commit | 83a43997b2136c6f5337219ddfe6aa6829d66fae (patch) | |
| tree | e31a18b2a0f0fcc7cb55849c88c2afa12aa85d3d /gobject | |
| parent | 49eabd6c5ab0b3c849bd03bd2149b47e50f19aee (diff) | |
| download | pygobject-83a43997b2136c6f5337219ddfe6aa6829d66fae.tar.gz pygobject-83a43997b2136c6f5337219ddfe6aa6829d66fae.tar.xz pygobject-83a43997b2136c6f5337219ddfe6aa6829d66fae.zip | |
Bug 161177: Allow creation of python classes from g_object_new
Diffstat (limited to 'gobject')
| -rw-r--r-- | gobject/gobjectmodule.c | 172 | ||||
| -rw-r--r-- | gobject/pygobject-private.h | 15 | ||||
| -rw-r--r-- | gobject/pygobject.c | 18 | ||||
| -rw-r--r-- | gobject/pygobject.h | 11 |
4 files changed, 202 insertions, 14 deletions
diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c index e151306..19017ac 100644 --- a/gobject/gobjectmodule.c +++ b/gobject/gobjectmodule.c @@ -26,6 +26,7 @@ #include "pygobject-private.h" #include "pythread.h" +#include <gobject/gvaluecollector.h> static PyObject *gerror_exc = NULL; static gboolean use_gil_state_api = FALSE; @@ -40,6 +41,9 @@ GQuark pygboxed_marshal_key; GQuark pygenum_class_key; GQuark pygflags_class_key; GQuark pygpointer_class_key; +GQuark pygobject_has_updated_constructor_key; + + static void pyg_flags_add_constants(PyObject *module, GType flags_type, const gchar *strip_prefix); @@ -1028,6 +1032,56 @@ get_type_name_for_class(PyTypeObject *class) return type_name; } + +static GStaticPrivate pygobject_contruction_wrapper = G_STATIC_PRIVATE_INIT; + +static inline void +pygobject_init_wrapper_set(PyObject *wrapper) +{ + g_static_private_set(&pygobject_contruction_wrapper, wrapper, NULL); +} + +static inline PyObject * +pygobject_init_wrapper_get(void) +{ + return (PyObject *) g_static_private_get(&pygobject_contruction_wrapper); +} + +static void +pygobject__g_instance_init(GTypeInstance *instance, + gpointer g_class) +{ + GObject *object = (GObject *) instance; + PyObject *wrapper, *args, *kwargs; + + if (!g_type_get_qdata(G_OBJECT_TYPE(object), pygobject_has_updated_constructor_key)) + return; + + wrapper = g_object_get_qdata(object, pygobject_wrapper_key); + if (wrapper == NULL) { + wrapper = pygobject_init_wrapper_get(); + if (wrapper) { + g_object_set_qdata(object, pygobject_wrapper_key, wrapper); + } + } + pygobject_init_wrapper_set(NULL); + if (wrapper == NULL) { + /* this looks like a python object created through + * g_object_new -> we have no python wrapper, so create it + * now */ + PyGILState_STATE state; + state = pyg_gil_state_ensure(); + wrapper = pygobject_new_full(object, FALSE); + args = PyTuple_New(0); + kwargs = PyDict_New(); + if (wrapper->ob_type->tp_init(wrapper, args, kwargs)) + PyErr_Print(); + Py_DECREF(args); + Py_DECREF(kwargs); + pyg_gil_state_release(state); + } +} + int pyg_type_register(PyTypeObject *class, char *type_name) { @@ -1036,6 +1090,7 @@ pyg_type_register(PyTypeObject *class, char *type_name) gint i; GTypeQuery query; gpointer gclass; + gpointer has_new_constructor_api; GTypeInfo type_info = { 0, /* class_size */ @@ -1048,7 +1103,7 @@ pyg_type_register(PyTypeObject *class, char *type_name) 0, /* instance_size */ 0, /* n_preallocs */ - (GInstanceInitFunc) NULL + (GInstanceInitFunc) pygobject__g_instance_init }; @@ -1088,6 +1143,16 @@ pyg_type_register(PyTypeObject *class, char *type_name) PyDict_SetItemString(class->tp_dict, "__gtype__", gtype); Py_DECREF(gtype); + /* propagate new constructor API compatility flag from parent to child type */ + has_new_constructor_api = g_type_get_qdata(parent_type, + pygobject_has_updated_constructor_key); + if (has_new_constructor_api == NULL) + g_warning("Constructor wrapper for %s needs to be updated to the new API", + g_type_name(parent_type)); + else + g_type_set_qdata(instance_type, pygobject_has_updated_constructor_key, + has_new_constructor_api); + /* if no __doc__, set it to the auto doc descriptor */ if (PyDict_GetItemString(class->tp_dict, "__doc__") == NULL) { PyDict_SetItemString(class->tp_dict, "__doc__", @@ -1572,8 +1637,12 @@ pyg_object_new (PyGObject *self, PyObject *args, PyObject *kwargs) g_type_class_unref(class); if (obj) - return pygobject_new ((GObject *)obj); - return NULL; + self = (PyGObject *) pygobject_new ((GObject *)obj); + else + self = NULL; + g_object_unref(obj); + + return (PyObject *) self; } static gint @@ -2455,6 +2524,95 @@ pyg_parse_constructor_args(GType obj_type, return TRUE; } +int +pygobject_constructv(PyGObject *self, + guint n_parameters, + GParameter *parameters) +{ + if (self->obj == NULL) { + pygobject_init_wrapper_set((PyObject *) self); + self->obj = g_object_newv(pyg_type_from_object((PyObject *) self), + n_parameters, parameters); + pygobject_init_wrapper_set(NULL); + pygobject_register_wrapper((PyObject *) self); + } else { + int i; + for (i = 0; i < n_parameters; ++i) + g_object_set_property(self->obj, parameters[i].name, ¶meters[i].value); + } + return 0; +} + +/* This function is mostly juste copy-paste from g_object_new, but + * calls pygobject_constructv instead of g_object_newv */ +int +pygobject_construct(PyGObject *self, const char *first_property_name, ...) +{ + va_list var_args; + GObjectClass *class; + GParameter *params; + const gchar *name; + guint n_params = 0, n_alloced_params = 16; + GType object_type = pyg_type_from_object((PyObject *) self); + int retval; + + if (!first_property_name) + return pygobject_constructv(self, 0, NULL); + + va_start(var_args, first_property_name); + class = g_type_class_ref(object_type); + + params = g_new(GParameter, n_alloced_params); + name = first_property_name; + while (name) + { + gchar *error = NULL; + GParamSpec *pspec = g_object_class_find_property(class, name); + + if (!pspec) + { + g_warning("%s: object class `%s' has no property named `%s'", + G_STRFUNC, + g_type_name(object_type), + name); + break; + } + if (n_params >= n_alloced_params) + { + n_alloced_params += 16; + params = g_renew(GParameter, params, n_alloced_params); + } + params[n_params].name = name; + params[n_params].value.g_type = 0; + g_value_init(¶ms[n_params].value, G_PARAM_SPEC_VALUE_TYPE(pspec)); + G_VALUE_COLLECT(¶ms[n_params].value, var_args, 0, &error); + if (error) + { + g_warning("%s: %s", G_STRFUNC, error); + g_free(error); + g_value_unset(¶ms[n_params].value); + break; + } + n_params++; + name = va_arg(var_args, gchar*); + } + + retval = pygobject_constructv(self, n_params, params); + + while (n_params--) + g_value_unset(¶ms[n_params].value); + g_free(params); + va_end(var_args); + g_type_class_unref(class); + return retval; +} + +void +pyg_set_object_has_new_constructor(GType type) +{ + g_type_set_qdata(type, pygobject_has_updated_constructor_key, GINT_TO_POINTER(1)); +} + /* ----------------- gobject module initialisation -------------- */ struct _PyGObject_Functions pygobject_api_functions = { @@ -2521,7 +2679,10 @@ struct _PyGObject_Functions pygobject_api_functions = { pyg_register_class_init, pyg_register_interface_info, - pyg_closure_set_exception_handler + pyg_closure_set_exception_handler, + pygobject_constructv, + pygobject_construct, + pyg_set_object_has_new_constructor }; #define REGISTER_TYPE(d, type, name) \ @@ -2560,6 +2721,8 @@ initgobject(void) pyginterface_type_key = g_quark_from_static_string("PyGInterface::type"); pyginterface_info_key = g_quark_from_static_string("PyGInterface::info"); pygpointer_class_key = g_quark_from_static_string("PyGPointer::class"); + pygobject_has_updated_constructor_key =\ + g_quark_from_static_string("PyGObject::has-updated-constructor"); REGISTER_TYPE(d, PyGTypeWrapper_Type, "GType"); @@ -2582,6 +2745,7 @@ initgobject(void) &PyGObject_Type, NULL); PyDict_SetItemString(PyGObject_Type.tp_dict, "__gdoc__", pyg_object_descr_doc_get()); + pyg_set_object_has_new_constructor(G_TYPE_OBJECT); /* GObject properties descriptor */ if (PyType_Ready(&PyGProps_Type) < 0) diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h index 4fd48e4..22bcab6 100644 --- a/gobject/pygobject-private.h +++ b/gobject/pygobject-private.h @@ -51,9 +51,17 @@ extern GQuark pygobject_class_init_key; extern GQuark pygobject_class_key; extern GQuark pygobject_wrapper_key; extern GQuark pygpointer_class_key; - -void pyg_destroy_notify (gpointer user_data); -gboolean pyg_error_check(GError **error); +extern GQuark pygobject_has_updated_constructor_key; + +void pyg_destroy_notify (gpointer user_data); +gboolean pyg_error_check (GError **error); +int pygobject_constructv (PyGObject *self, + guint n_parameters, + GParameter *parameters); +int pygobject_construct (PyGObject *self, + const char *first_property_name, + ...); +void pyg_set_object_has_new_constructor (GType gtype); /* from pygtype.h */ extern PyTypeObject PyGTypeWrapper_Type; @@ -103,6 +111,7 @@ void pygobject_register_class (PyObject *dict, PyObject *bases); void pygobject_register_wrapper (PyObject *self); PyObject * pygobject_new (GObject *obj); +PyObject * pygobject_new_full (GObject *obj, gboolean sink); PyTypeObject *pygobject_lookup_class (GType gtype); void pygobject_watch_closure (PyObject *self, GClosure *closure); void pygobject_register_sinkfunc(GType type, diff --git a/gobject/pygobject.c b/gobject/pygobject.c index 1263554..1fe837d 100644 --- a/gobject/pygobject.c +++ b/gobject/pygobject.c @@ -660,6 +660,7 @@ pygobject_lookup_class(GType gtype) /** * pygobject_new: * @obj: a GObject instance. + * @sink: whether to sink any floating reference found on the GObject. * * This function gets a reference to a wrapper for the given GObject * instance. If a wrapper has already been created, a new reference @@ -669,7 +670,7 @@ pygobject_lookup_class(GType gtype) * Returns: a reference to the wrapper for the GObject. */ PyObject * -pygobject_new(GObject *obj) +pygobject_new_full(GObject *obj, gboolean sink) { PyGObject *self; @@ -695,7 +696,8 @@ pygobject_new(GObject *obj) pyg_begin_allow_threads; self->obj = g_object_ref(obj); pyg_end_allow_threads; - sink_object(self->obj); + if (sink) + sink_object(self->obj); self->inst_dict = NULL; self->weakreflist = NULL; @@ -711,6 +713,12 @@ pygobject_new(GObject *obj) return (PyObject *)self; } +PyObject * +pygobject_new(GObject *obj) +{ + return pygobject_new_full(obj, TRUE); +} + static void pygobject_unwatch_closure(gpointer data, GClosure *closure) { @@ -943,11 +951,7 @@ pygobject_init(PyGObject *self, PyObject *args, PyObject *kwargs) n_params++; } } - - self->obj = g_object_newv(object_type, n_params, params); - if (self->obj) - pygobject_register_wrapper((PyObject *)self); - else + if (pygobject_constructv(self, n_params, params)) PyErr_SetString (PyExc_RuntimeError, "could not create object"); cleanup: diff --git a/gobject/pygobject.h b/gobject/pygobject.h index 18c50c0..3bba3ac 100644 --- a/gobject/pygobject.h +++ b/gobject/pygobject.h @@ -166,6 +166,13 @@ struct _PyGObject_Functions { 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); + int (*pygobject_constructv) (PyGObject *self, + guint n_parameters, + GParameter *parameters); + int (*pygobject_construct) (PyGObject *self, + const char *first_property_name, + ...); + void (*set_object_has_new_constructor) (GType type); }; #ifndef _INSIDE_PYGOBJECT_ @@ -222,6 +229,10 @@ struct _PyGObject_Functions *_PyGObject_API; #define pyg_enable_threads (_PyGObject_API->enable_threads) #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) +#define pygobject_constructv (_PyGObject_API->pygobject_constructv) +#define pyg_set_object_has_new_constructor (_PyGObject_API->set_object_has_new_constructor) + #define pyg_block_threads() G_STMT_START { \ if (_PyGObject_API->block_threads != NULL) \ |
