diff options
author | James Henstridge <james@daa.com.au> | 2001-12-18 08:19:51 +0000 |
---|---|---|
committer | James Henstridge <jamesh@src.gnome.org> | 2001-12-18 08:19:51 +0000 |
commit | b98d703df4f7837c2ed5359e85d158bec880bd30 (patch) | |
tree | 29b00f83345c36acfcebad29afffb85b2fd20dd6 | |
parent | 6bd8ae3492a556aed7653c7f5da2bfd6edca402f (diff) | |
download | pygobject-b98d703df4f7837c2ed5359e85d158bec880bd30.tar.gz pygobject-b98d703df4f7837c2ed5359e85d158bec880bd30.tar.xz pygobject-b98d703df4f7837c2ed5359e85d158bec880bd30.zip |
add new example to dist.
2001-12-18 James Henstridge <james@daa.com.au>
* Makefile.am (EXTRA_DIST): add new example to dist.
* examples/gobject/properties.py: test program that implements a
few properties.
* gobjectmodule.c (add_properties): new function for parsing the
__gproperties__ class attribute.
(create_property): helper routine for creating and installing the
new pspecs.
(pyg_type_register): add code to call add_properties if a
__gproperties__ attribute is found.
(pyg_object_class_init): set set_property/get_property methods in
vtable, and get rid of debug message.
(initgobject): add G_PARAM_* constants.
-rw-r--r-- | examples/properties.py | 43 | ||||
-rw-r--r-- | gobject/gobjectmodule.c | 365 |
2 files changed, 397 insertions, 11 deletions
diff --git a/examples/properties.py b/examples/properties.py new file mode 100644 index 0000000..2d36afc --- /dev/null +++ b/examples/properties.py @@ -0,0 +1,43 @@ +import gobject + +class MyObject(gobject.GObject): + __gproperties__ = { + 'foo': (gobject.TYPE_STRING, 'foo property', 'the foo of the object', + 'bar', gobject.PARAM_READWRITE), + 'boolprop': (gobject.TYPE_BOOLEAN, 'bool prop', 'a test boolean prop', + 0, gobject.PARAM_READABLE), + } + + def __init__(self): + self.__gobject_init__() + self.foo = 'bar' + def do_set_property(self, pspec, value): + print ' do_set_property called for %s=%r' % (pspec.name, value) + if pspec.name == 'foo': + self.foo = value + else: + raise AttributeError, 'unknown property %s' % pspec.name + def do_get_property(self, pspec): + print ' do_get_property called for %s' % pspec.name + if pspec.name == 'foo': + return self.foo + elif pspec.name == 'boolprop': + return 1 + else: + raise AttributeError, 'unknown property %s' % pspec.name +gobject.type_register(MyObject) + +print "MyObject properties: ", gobject.list_properties(MyObject) +obj = MyObject() + +val = obj.get_property('foo') +print "obj.get_property('foo') == ", val + +obj.set_property('foo', 'spam') +print "obj.set_property('foo', 'spam')" + +val = obj.get_property('foo') +print "obj.get_property('foo') == ", val + +val = obj.get_property('boolprop') +print "obj.get_property('boolprop') == ", val diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c index 77e434f..a0139d9 100644 --- a/gobject/gobjectmodule.c +++ b/gobject/gobjectmodule.c @@ -1998,10 +1998,55 @@ pyg_type_interfaces (PyObject *self, PyObject *args) } static void +pyg_object_set_property (GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) +{ + PyObject *object_wrapper, *retval; + PyObject *py_pspec, *py_value; + + object_wrapper = pygobject_new(object); + g_return_if_fail(object_wrapper != NULL); + + py_pspec = pyg_param_spec_new(pspec); + py_value = pyg_value_as_pyobject (value); + retval = PyObject_CallMethod(object_wrapper, "do_set_property", + "OO", py_pspec, py_value); + if (retval) { + Py_DECREF(retval); + } else { + PyErr_Print(); + PyErr_Clear(); + } + Py_DECREF(py_pspec); + Py_DECREF(py_value); +} + +static void +pyg_object_get_property (GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + PyObject *object_wrapper, *retval; + PyObject *py_pspec; + + object_wrapper = pygobject_new(object); + g_return_if_fail(object_wrapper != NULL); + + py_pspec = pyg_param_spec_new(pspec); + retval = PyObject_CallMethod(object_wrapper, "do_get_property", + "O", py_pspec); + if (retval == NULL || pyg_value_from_pyobject(value, retval) < 0) { + PyErr_Print(); + PyErr_Clear(); + } + Py_XDECREF(retval); + Py_DECREF(py_pspec); +} + +static void pyg_object_class_init(GObjectClass *class, PyObject *py_class) { - g_message("GType class init for `%s' with python class %p", - G_OBJECT_CLASS_NAME(class), py_class); + class->set_property = pyg_object_set_property; + class->get_property = pyg_object_get_property; } static gboolean @@ -2087,6 +2132,7 @@ override_signal(GType instance_type, const gchar *signal_name) static gboolean add_signals (GType instance_type, PyObject *signals) { + gboolean ret = TRUE; GObjectClass *oclass; int pos = 0; PyObject *key, *value; @@ -2094,37 +2140,307 @@ add_signals (GType instance_type, PyObject *signals) oclass = g_type_class_ref(instance_type); while (PyDict_Next(signals, &pos, &key, &value)) { const gchar *signal_name; - gboolean retval = TRUE; if (!PyString_Check(key)) { PyErr_SetString(PyExc_TypeError, "__gsignals__ keys must be strings"); - g_type_class_unref(oclass); - return FALSE; + ret = FALSE; + break; } signal_name = PyString_AsString (key); if (value == Py_None || (PyString_Check(value) && !strcmp(PyString_AsString(value), "override"))) { - retval = override_signal(instance_type, signal_name); + ret = override_signal(instance_type, signal_name); } else { - retval = create_signal(instance_type, signal_name, value); + ret = create_signal(instance_type, signal_name, value); + } + + if (!ret) + break; + } + g_type_class_unref(oclass); + return ret; +} + +static gboolean +create_property (GObjectClass *oclass, const gchar *prop_name, + GType prop_type, const gchar *nick, const gchar *blurb, + PyObject *args, GParamFlags flags) +{ + GParamSpec *pspec = NULL; + + switch (G_TYPE_FUNDAMENTAL(prop_type)) { + case G_TYPE_CHAR: + { + gchar minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_char (prop_name, nick, blurb, minimum, + maximum, default_value, flags); } + break; + case G_TYPE_UCHAR: + { + gchar minimum, maximum, default_value; - if (!retval) { - g_type_class_unref(oclass); + if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_uchar (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_BOOLEAN: + { + gboolean default_value; + + if (!PyArg_ParseTuple(args, "i", &default_value)) + return FALSE; + pspec = g_param_spec_boolean (prop_name, nick, blurb, + default_value, flags); + } + break; + case G_TYPE_INT: + { + gint minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "iii", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_int (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_UINT: + { + guint minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "iii", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_uint (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_LONG: + { + glong minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "lll", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_long (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_ULONG: + { + gulong minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "lll", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_ulong (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_INT64: + { + gint64 minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "LLL", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_int64 (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_UINT64: + { + guint64 minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "LLL", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_uint64 (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_ENUM: + { + gint default_value; + + if (!PyArg_ParseTuple(args, "i", &default_value)) + return FALSE; + pspec = g_param_spec_enum (prop_name, nick, blurb, + prop_type, default_value, flags); + } + break; + case G_TYPE_FLAGS: + { + guint default_value; + + if (!PyArg_ParseTuple(args, "i", &default_value)) + return FALSE; + pspec = g_param_spec_flags (prop_name, nick, blurb, + prop_type, default_value, flags); + } + break; + case G_TYPE_FLOAT: + { + gfloat minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "fff", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_float (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_DOUBLE: + { + gdouble minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "ddd", &minimum, &maximum, + &default_value)) + return FALSE; + pspec = g_param_spec_double (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_STRING: + { + const gchar *default_value; + + if (!PyArg_ParseTuple(args, "z", &default_value)) + return FALSE; + pspec = g_param_spec_string (prop_name, nick, blurb, + default_value, flags); + } + break; + case G_TYPE_PARAM: + if (!PyArg_ParseTuple(args, "")) + return FALSE; + pspec = g_param_spec_param (prop_name, nick, blurb, prop_type, flags); + break; + case G_TYPE_BOXED: + if (!PyArg_ParseTuple(args, "")) + return FALSE; + pspec = g_param_spec_boxed (prop_name, nick, blurb, prop_type, flags); + break; + case G_TYPE_POINTER: + if (!PyArg_ParseTuple(args, "")) + return FALSE; + pspec = g_param_spec_pointer (prop_name, nick, blurb, flags); + break; + case G_TYPE_OBJECT: + if (!PyArg_ParseTuple(args, "")) return FALSE; + pspec = g_param_spec_object (prop_name, nick, blurb, prop_type, flags); + break; + default: + /* unhandled pspec type ... */ + break; + } + + if (!pspec) { + char buf[128]; + + g_snprintf(buf, sizeof(buf), "could not create param spec for type %s", + g_type_name(prop_type)); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + g_object_class_install_property(oclass, 1, pspec); + return TRUE; +} + +static gboolean +add_properties (GType instance_type, PyObject *properties) +{ + gboolean ret = TRUE; + GObjectClass *oclass; + int pos = 0; + PyObject *key, *value; + + oclass = g_type_class_ref(instance_type); + while (PyDict_Next(properties, &pos, &key, &value)) { + const gchar *prop_name; + GType prop_type; + const gchar *nick, *blurb; + GParamFlags flags; + gint val_length; + PyObject *slice, *item, *py_prop_type; + /* values are of format (type,nick,blurb, type_specific_args, flags) */ + + if (!PyString_Check(key)) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ keys must be strings"); + ret = FALSE; + break; + } + prop_name = PyString_AsString (key); + + if (!PyTuple_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ values must be tuples"); + ret = FALSE; + break; + } + val_length = PyTuple_Size(value); + if (val_length < 4) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ values must be at least 4 elements long"); + ret = FALSE; + break; + } + + slice = PySequence_GetSlice(value, 0, 3); + if (!slice) { + ret = FALSE; + break; + } + if (!PyArg_ParseTuple(slice, "Ozz", &py_prop_type, &nick, &blurb)) { + Py_DECREF(slice); + ret = FALSE; + break; } + Py_DECREF(slice); + prop_type = pyg_type_from_object(py_prop_type); + if (!prop_type) { + ret = FALSE; + break; + } + item = PyTuple_GetItem(value, val_length-1); + if (!PyInt_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "last element in __gproperties__ value tuple must be an int"); + ret = FALSE; + break; + } + flags = PyInt_AsLong(item); + + /* slice is the extra items in the tuple */ + slice = PySequence_GetSlice(value, 3, val_length-1); + ret = create_property(oclass, prop_name, prop_type, nick, blurb, + slice, flags); + Py_DECREF(slice); + + if (!ret) + break; } g_type_class_unref(oclass); - return TRUE; + return ret; } static PyObject * pyg_type_register(PyObject *self, PyObject *args) { - PyObject *gtype, *module, *gsignals; + PyObject *gtype, *module, *gsignals, *gproperties; PyTypeObject *class; GType parent_type, instance_type; gchar *type_name = NULL; @@ -2221,6 +2537,26 @@ pyg_type_register(PyObject *self, PyObject *args) PyErr_Clear(); } + /* we look this up in the instance dictionary, so we don't + * accidentally get a parent type's __gsignals__ attribute. */ + gproperties = PyDict_GetItemString(class->tp_dict, "__gproperties__"); + if (gproperties) { + if (!PyDict_Check(gproperties)) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ attribute not a dict!"); + Py_DECREF(gproperties); + return NULL; + } + if (!add_properties(instance_type, gproperties)) { + Py_DECREF(gproperties); + return NULL; + } + PyDict_DelItemString(class->tp_dict, "__gproperties__"); + Py_DECREF(gproperties); + } else { + PyErr_Clear(); + } + Py_INCREF(Py_None); return Py_None; } @@ -2658,6 +2994,13 @@ initgobject(void) PyModule_AddIntConstant(m, "SIGNAL_ACTION", G_SIGNAL_ACTION); PyModule_AddIntConstant(m, "SIGNAL_NO_HOOKS", G_SIGNAL_NO_HOOKS); + PyModule_AddIntConstant(m, "PARAM_READABLE", G_PARAM_READABLE); + PyModule_AddIntConstant(m, "PARAM_WRITABLE", G_PARAM_WRITABLE); + PyModule_AddIntConstant(m, "PARAM_CONSTRUCT", G_PARAM_CONSTRUCT); + PyModule_AddIntConstant(m, "PARAM_CONSTRUCT_ONLY", G_PARAM_CONSTRUCT_ONLY); + PyModule_AddIntConstant(m, "PARAM_LAX_VALIDATION", G_PARAM_LAX_VALIDATION); + PyModule_AddIntConstant(m, "PARAM_READWRITE", G_PARAM_READWRITE); + PyModule_AddObject(m, "TYPE_INVALID", pyg_type_wrapper_new(G_TYPE_INVALID)); PyModule_AddObject(m, "TYPE_NONE", pyg_type_wrapper_new(G_TYPE_NONE)); PyModule_AddObject(m, "TYPE_INTERFACE", pyg_type_wrapper_new(G_TYPE_INTERFACE)); |