--- pygobject.c	2004-11-27 20:12:55.000000000 +0100
+++ /usr/src/redhat/BUILD/pygtk-2.6.0/gobject/pygobject.c	2005-06-30 13:34:26.000000000 +0200
@@ -85,6 +85,194 @@
     g_array_append_val(sink_funcs, sf);
 }
 
+typedef struct {
+    PyObject_HEAD
+    /* a reference to the object containing the properties */
+    PyGObject	*pygobject;
+} PyGProps;
+
+static void
+PyGProps_dealloc(PyGProps* self)
+{
+    Py_DECREF(self->pygobject);
+
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject*
+build_parameter_list(GObject *obj)
+{
+    GObjectClass *class;
+    GParamSpec **props;
+    guint n_props = 0, i;
+    PyObject *prop_str;
+    char *name;
+    PyObject *props_tuple;
+
+    class = g_type_class_ref(G_OBJECT_TYPE(obj));
+    props = g_object_class_list_properties(class, &n_props);
+    props_tuple = PyList_New(n_props);
+    for (i=0; i<n_props; i++) {
+	name = g_strdup(g_param_spec_get_name(props[i]));
+	/* hyphens cannot belong in identifiers */
+	g_strdelimit(name, "-", '_');
+	prop_str = PyString_FromString(name);
+	
+	PyList_SetItem(props_tuple, i, prop_str);
+    }
+    g_free (props);
+    g_type_class_unref (class);
+    
+    return props_tuple;
+}
+
+static PyObject*
+PyGProps_getattro(PyGProps *gprops, PyObject *attr)
+{
+    GParamSpec *pspec;
+    GValue value = { 0, };
+    char *attr_name;
+    PyObject *ret;
+
+    attr_name = PyString_AsString(attr);
+
+    if (!strcmp(attr_name, "__members__")) {
+	return build_parameter_list(gprops->pygobject->obj);
+    }
+
+    pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(gprops->pygobject->obj), attr_name);
+
+    if (!pspec) {
+	return PyObject_GenericGetAttr((PyObject *)gprops, attr);
+    }
+
+    if (!(pspec->flags & G_PARAM_READABLE)) {
+	PyErr_Format(PyExc_TypeError,
+		     "property '%s' is not readable", attr_name);
+	return NULL;
+    }
+
+    g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
+    g_object_get_property(gprops->pygobject->obj, attr_name, &value);
+    ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec);
+    g_value_unset(&value);
+    return ret;
+}
+
+static int
+PyGProps_setattro(PyGProps *gprops, PyObject *attr, PyObject *pvalue)
+{
+    GParamSpec *pspec;
+    GValue value = { 0, };
+    char *attr_name;
+
+    if (pvalue == NULL) {
+	PyErr_SetString(PyExc_TypeError, "properties cannot be "
+			"deleted");
+	return -1;
+    }
+
+    attr_name = PyString_AsString(attr);
+
+    pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(gprops->pygobject->obj), attr_name);
+
+    if (!pspec) {
+	return PyObject_GenericSetAttr((PyObject *)gprops, attr, pvalue);
+    }
+
+    if (!(pspec->flags & G_PARAM_WRITABLE)) {
+	PyErr_Format(PyExc_TypeError,
+		     "property '%s' is not writable", attr_name);
+	return -1;
+    }	
+
+    g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
+    if (pyg_param_gvalue_from_pyobject(&value, pvalue, pspec) < 0) {
+	PyErr_SetString(PyExc_TypeError,
+			"could not convert argument to correct param type");
+	return -1;
+    }
+
+    g_object_set_property(gprops->pygobject->obj, attr_name, &value);
+    g_value_unset(&value);
+    return 0;
+}
+
+static PyTypeObject props_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "gobject.GProps",          /*tp_name*/
+    sizeof(PyGProps),	       /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)PyGProps_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,			       /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    (getattrofunc)PyGProps_getattro, /*tp_getattro*/
+    (setattrofunc)PyGProps_setattro, /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT,        /*tp_flags*/
+    "The properties of the GObject accessible as "
+    "Python attributes.",      /* tp_doc */
+};
+
+static PyObject *
+pygobject_get_props_descr(PyGObject *self, gpointer unused)
+{
+    PyGProps *gprops;
+    PyGILState_STATE state;
+
+    state = pyg_gil_state_ensure();
+
+    Py_INCREF(self);
+    gprops = PyObject_NEW(PyGProps, &props_Type);
+    gprops->pygobject = self;
+
+    pyg_gil_state_release(state);
+    
+    return (PyObject *)gprops;
+}
+
+static void init_props(void)
+{
+    static gboolean inited = FALSE;
+
+    if (inited)
+	return;
+
+    inited = TRUE;
+    props_Type.tp_new = PyType_GenericNew;
+    if (PyType_Ready(&props_Type) < 0)
+        return;
+}
+
+static void
+pygobject_add_props (GType gtype, PyTypeObject *type)
+{
+    PyGetSetDef *def;
+    PyObject *descr;
+
+    init_props();
+
+    def = g_new0(struct PyGetSetDef, 1);
+    def->name = g_strdup("props");
+    def->doc = g_strdup("The properties of the GObject accessible as "
+			"Python attributes.");
+    def->closure = NULL;
+    def->get = (getter)pygobject_get_props_descr;
+    def->set = NULL;
+    descr = PyDescr_NewGetSet(type, def);
+    PyDict_SetItemString(type->tp_dict, "props", descr);
+}
+
 /**
  * pygobject_register_class:
  * @dict: the module dictionary.  A reference to the type will be stored here.
@@ -140,6 +328,9 @@
 			 pyg_object_descr_doc_get());
 
     PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type);
+
+    /* add the class properties as .props */
+    pygobject_add_props(gtype, type);
 }
 
 /**
