summaryrefslogtreecommitdiffstats
path: root/gobject
diff options
context:
space:
mode:
authorGustavo J. A. M. Carneiro <gjc@src.gnome.org>2005-07-09 18:25:32 +0000
committerGustavo J. A. M. Carneiro <gjc@src.gnome.org>2005-07-09 18:25:32 +0000
commit83a43997b2136c6f5337219ddfe6aa6829d66fae (patch)
treee31a18b2a0f0fcc7cb55849c88c2afa12aa85d3d /gobject
parent49eabd6c5ab0b3c849bd03bd2149b47e50f19aee (diff)
downloadpygobject-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.c172
-rw-r--r--gobject/pygobject-private.h15
-rw-r--r--gobject/pygobject.c18
-rw-r--r--gobject/pygobject.h11
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, &parameters[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(&params[n_params].value, G_PARAM_SPEC_VALUE_TYPE(pspec));
+ G_VALUE_COLLECT(&params[n_params].value, var_args, 0, &error);
+ if (error)
+ {
+ g_warning("%s: %s", G_STRFUNC, error);
+ g_free(error);
+ g_value_unset(&params[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(&params[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) \