Index: gobject/gobjectmodule.c
===================================================================
RCS file: /cvs/gnome/gnome-python/pygobject/gobject/gobjectmodule.c,v
retrieving revision 1.208
diff -u -p -d -r1.208 gobjectmodule.c
--- gobject/gobjectmodule.c	14 Jan 2006 17:51:47 -0000	1.208
+++ gobject/gobjectmodule.c	15 Jan 2006 21:18:00 -0000
@@ -43,6 +43,7 @@ GQuark pygenum_class_key;
 GQuark pygflags_class_key;
 GQuark pygpointer_class_key;
 GQuark pygobject_has_updated_constructor_key;
+GQuark pygobject_instance_data_key;
 
 
 
@@ -2990,6 +2991,7 @@ initgobject(void)
     pygpointer_class_key     = g_quark_from_static_string("PyGPointer::class");
     pygobject_has_updated_constructor_key =\
         g_quark_from_static_string("PyGObject::has-updated-constructor");
+    pygobject_instance_data_key = g_quark_from_static_string("PyGObject::instance-data");
 
     REGISTER_TYPE(d, PyGTypeWrapper_Type, "GType");
 
@@ -3048,6 +3050,9 @@ initgobject(void)
     REGISTER_TYPE(d, PyGIdle_Type, "Idle");
     REGISTER_TYPE(d, PyGTimeout_Type, "Timeout");
     REGISTER_TYPE(d, PyGPollFD_Type, "PollFD");
+
+    PyType_Ready(&PyGObjectWeakRef_Type);
+    PyDict_SetItemString(d, "GObjectWeakRef", (PyObject *) &PyGObjectWeakRef_Type);
 
     /* glib version */
     tuple = Py_BuildValue ("(iii)", glib_major_version, glib_minor_version,
Index: gobject/pygobject-private.h
===================================================================
RCS file: /cvs/gnome/gnome-python/pygobject/gobject/pygobject-private.h,v
retrieving revision 1.44
diff -u -p -d -r1.44 pygobject-private.h
--- gobject/pygobject-private.h	9 Nov 2005 19:45:19 -0000	1.44
+++ gobject/pygobject-private.h	15 Jan 2006 21:18:01 -0000
@@ -39,6 +39,17 @@ extern struct _PyGObject_Functions pygob
     } G_STMT_END
 
 
+#ifndef Py_CLEAR /* since Python 2.4 */
+# define Py_CLEAR(op)				\
+        do {                            	\
+                if (op) {			\
+                        PyObject *tmp = (PyObject *)(op);	\
+                        (op) = NULL;		\
+                        Py_DECREF(tmp);		\
+                }				\
+        } while (0)
+#endif
+
 extern GType PY_TYPE_OBJECT;
 
 extern GQuark pygboxed_type_key;
@@ -52,7 +63,9 @@ extern GQuark pygobject_class_key;
 extern GQuark pygobject_wrapper_key;
 extern GQuark pygpointer_class_key;
 extern GQuark pygobject_has_updated_constructor_key;
+extern GQuark pygobject_instance_data_key;
 
+void     pygobject_data_free  (PyGObjectData *data);
 void     pyg_destroy_notify   (gpointer     user_data);
 gboolean pyg_handler_marshal  (gpointer     user_data);
 gboolean pyg_error_check      (GError     **error);
@@ -102,6 +115,7 @@ PyObject *pyg_object_descr_doc_get(void)
 
 
 extern PyTypeObject PyGObject_MetaType;
+extern PyTypeObject PyGObjectWeakRef_Type;
 
 /* from pygobject.h */
 extern PyTypeObject PyGObject_Type;
@@ -109,7 +123,6 @@ extern PyTypeObject PyGInterface_Type;
 extern PyTypeObject PyGProps_Type;
 extern PyTypeObject PyGPropsDescr_Type;
 extern PyTypeObject PyGPropsIter_Type;
-
 void          pygobject_register_class   (PyObject *dict,
 					  const gchar *type_name,
 					  GType gtype, PyTypeObject *type,
@@ -216,5 +229,11 @@ typedef struct
     PyObject *fd_obj;
 } PyGPollFD;
 
+  /* Data that belongs to the GObject instance, not the Python wrapper */
+struct _PyGObjectData {
+    PyTypeObject *type; /* wrapper type for this instance */
+    PyObject *dict; /* the instance dictionary */
+    GSList *closures;
+};
 
 #endif
Index: gobject/pygobject.c
===================================================================
RCS file: /cvs/gnome/gnome-python/pygobject/gobject/pygobject.c,v
retrieving revision 1.66
diff -u -p -d -r1.66 pygobject.c
--- gobject/pygobject.c	13 Jan 2006 21:45:55 -0000	1.66
+++ gobject/pygobject.c	15 Jan 2006 21:18:01 -0000
@@ -25,9 +25,81 @@ static void pygobject_dealloc(PyGObject 
 static int  pygobject_traverse(PyGObject *self, visitproc visit, void *arg);
 static int  pygobject_clear(PyGObject *self);
 static PyObject * pyg_type_get_bases(GType gtype);
+static inline int pygobject_clear(PyGObject *self);
+static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data);
+static inline PyGObjectData * pyg_object_peek_inst_data(GObject *obj);
+static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data);
 
 /* -------------- class <-> wrapper manipulation --------------- */
 
+void
+pygobject_data_free(PyGObjectData *data)
+{
+    PyGILState_STATE state = pyg_gil_state_ensure();
+    GSList *closures, *tmp;
+    Py_XDECREF(data->dict);
+    Py_DECREF(data->type);
+    tmp = closures = data->closures;
+#ifndef NDEBUG
+    data->dict = NULL;
+    data->closures = NULL;
+    data->type = NULL;
+#endif
+    pyg_begin_allow_threads;
+    while (tmp) {
+ 	GClosure *closure = tmp->data;
+ 
+          /* we get next item first, because the current link gets
+           * invalidated by pygobject_unwatch_closure */
+ 	tmp = tmp->next;
+ 	g_closure_invalidate(closure);
+    }
+    pyg_end_allow_threads;
+ 
+    if (data->closures != NULL)
+ 	g_warning("invalidated all closures, but data->closures != NULL !");
+
+    g_free(data);
+    pyg_gil_state_release(state);
+}
+
+static inline PyGObjectData *
+pygobject_data_new(void)
+{
+    PyGObjectData *data;
+    data = g_new0(PyGObjectData, 1);
+    return data;
+}
+
+static inline PyGObjectData *
+pyg_object_peek_inst_data(GObject *obj)
+{
+    return ((PyGObjectData *) 
+            g_object_get_qdata(obj, pygobject_instance_data_key));
+}
+
+static inline PyGObjectData *
+pygobject_get_inst_data(PyGObject *self)
+{
+    PyGObjectData *inst_data;
+
+    g_return_val_if_fail(self->obj, NULL);
+    inst_data = g_object_get_qdata(self->obj, pygobject_instance_data_key);
+    if (inst_data == NULL)
+    {
+        inst_data = pygobject_data_new();
+
+        inst_data->type = ((PyObject *)self)->ob_type;
+        Py_INCREF((PyObject *) inst_data->type);
+
+        g_object_set_qdata_full(self->obj, pygobject_instance_data_key,
+                                inst_data, (GDestroyNotify) pygobject_data_free);
+    }
+
+    return inst_data;
+}
+
+
 typedef struct {
     GType type;
     void (* sinkfunc)(GObject *object);
@@ -556,12 +628,18 @@ pygobject_register_class(PyObject *dict,
 void
 pygobject_register_wrapper(PyObject *self)
 {
-    GObject *obj = ((PyGObject *)self)->obj;
+    PyGObject *gself = (PyGObject *) self;
+    GObject *obj = gself->obj;
+    PyGObjectData *inst_data = pyg_object_peek_inst_data(obj);
 
+    if (inst_data) {
+        if (gself->inst_dict != inst_data->dict) {
+            g_assert(gself->inst_dict == NULL);
+            gself->inst_dict = inst_data->dict;
+        }
+    }
     pygobject_sink(obj);
-    Py_INCREF(self);
-    g_object_set_qdata_full(obj, pygobject_wrapper_key, self,
-			    pyg_destroy_notify);
+    g_object_set_qdata_full(obj, pygobject_wrapper_key, self, NULL);
 }
 
 static PyObject *
@@ -765,7 +843,12 @@ pygobject_new_full(GObject *obj, gboolea
 	Py_INCREF(self);
     } else {
 	/* create wrapper */
-	PyTypeObject *tp = pygobject_lookup_class(G_OBJECT_TYPE(obj));
+        PyGObjectData *inst_data = pyg_object_peek_inst_data(obj);
+	PyTypeObject *tp;
+        if (inst_data)
+            tp = inst_data->type;
+        else
+            tp = pygobject_lookup_class(G_OBJECT_TYPE(obj));
         /* need to bump type refcount if created with
            pygobject_new_with_interfaces(). fixes bug #141042 */
         if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE)
@@ -776,14 +859,10 @@ pygobject_new_full(GObject *obj, gboolea
 	self->obj = g_object_ref(obj);
         if (sink)
             pygobject_sink(self->obj);
-
-	self->inst_dict = NULL;
+        self->inst_dict = inst_data? inst_data->dict : NULL;
 	self->weakreflist = NULL;
-	self->closures = NULL;
 	/* save wrapper pointer so we can access it later */
-	Py_INCREF(self);
-	g_object_set_qdata_full(obj, pygobject_wrapper_key, self,
-				pyg_destroy_notify);
+	g_object_set_qdata_full(obj, pygobject_wrapper_key, self, NULL);
 
 	PyObject_GC_Track((PyObject *)self);
     }
@@ -800,9 +879,9 @@ pygobject_new(GObject *obj)
 static void
 pygobject_unwatch_closure(gpointer data, GClosure *closure)
 {
-    PyGObject *self = (PyGObject *)data;
+    PyGObjectData *inst_data = data;
 
-    self->closures = g_slist_remove (self->closures, closure);
+    inst_data->closures = g_slist_remove (inst_data->closures, closure);
 }
 
 /**
@@ -821,15 +900,17 @@ void
 pygobject_watch_closure(PyObject *self, GClosure *closure)
 {
     PyGObject *gself;
+    PyGObjectData *data;
 
     g_return_if_fail(self != NULL);
     g_return_if_fail(PyObject_TypeCheck(self, &PyGObject_Type));
     g_return_if_fail(closure != NULL);
-    g_return_if_fail(g_slist_find(((PyGObject *)self)->closures, closure) == NULL);
 
     gself = (PyGObject *)self;
-    gself->closures = g_slist_prepend(gself->closures, closure);
-    g_closure_add_invalidate_notifier(closure,self, pygobject_unwatch_closure);
+    data = pygobject_get_inst_data(gself);
+    g_return_if_fail(g_slist_find(data->closures, closure) == NULL);
+    data->closures = g_slist_prepend(data->closures, closure);
+    g_closure_add_invalidate_notifier(closure, data, pygobject_unwatch_closure);
 }
 
 /* -------------- PyGObject behaviour ----------------- */
@@ -837,35 +918,9 @@ pygobject_watch_closure(PyObject *self, 
 static void
 pygobject_dealloc(PyGObject *self)
 {
-    GSList *tmp;
-
     PyObject_ClearWeakRefs((PyObject *)self);
-
     PyObject_GC_UnTrack((PyObject *)self);
-
-    if (self->obj) {
-	g_object_unref(self->obj);
-    }
-    self->obj = NULL;
-
-    if (self->inst_dict) {
-	Py_DECREF(self->inst_dict);
-    }
-    self->inst_dict = NULL;
-
-    pyg_begin_allow_threads;
-    tmp = self->closures;
-    while (tmp) {
-	GClosure *closure = tmp->data;
-
-	/* we get next item first, because the current link gets
-	 * invalidated by pygobject_unwatch_closure */
-	tmp = tmp->next;
-	g_closure_invalidate(closure);
-    }
-    self->closures = NULL;
-    pyg_end_allow_threads;
-
+    pygobject_clear(self);
     /* the following causes problems with subclassed types */
     /* self->ob_type->tp_free((PyObject *)self); */
     PyObject_GC_Del(self);
@@ -891,10 +946,11 @@ pygobject_repr(PyGObject *self)
     gchar buf[256];
 
     g_snprintf(buf, sizeof(buf),
-	       "<%s object (%s) at 0x%lx>",
+	       "<%s object at 0x%lx (%s at 0x%lx)>",
 	       self->ob_type->tp_name,
+	       (long)self,
 	       self->obj ? G_OBJECT_TYPE_NAME(self->obj) : "uninitialized",
-	       (long)self);
+               (long)self->obj);
     return PyString_FromString(buf);
 }
 
@@ -903,60 +959,40 @@ pygobject_traverse(PyGObject *self, visi
 {
     int ret = 0;
     GSList *tmp;
+    PyGObjectData *data = self->obj? pyg_object_peek_inst_data(self->obj) : NULL;
 
     if (self->inst_dict) ret = visit(self->inst_dict, arg);
     if (ret != 0) return ret;
 
-    for (tmp = self->closures; tmp != NULL; tmp = tmp->next) {
-	PyGClosure *closure = tmp->data;
+    if (data) {
+        for (tmp = data->closures; tmp != NULL; tmp = tmp->next) {
+            PyGClosure *closure = tmp->data;
 
-	if (closure->callback) ret = visit(closure->callback, arg);
-	if (ret != 0) return ret;
+            if (closure->callback) ret = visit(closure->callback, arg);
+            if (ret != 0) return ret;
 
-	if (closure->extra_args) ret = visit(closure->extra_args, arg);
-	if (ret != 0) return ret;
+            if (closure->extra_args) ret = visit(closure->extra_args, arg);
+            if (ret != 0) return ret;
 
-	if (closure->swap_data) ret = visit(closure->swap_data, arg);
-	if (ret != 0) return ret;
+            if (closure->swap_data) ret = visit(closure->swap_data, arg);
+            if (ret != 0) return ret;
+        }
     }
-
-    if (self->obj && self->obj->ref_count == 1)
-	ret = visit((PyObject *)self, arg);
-    if (ret != 0) return ret;
-
-    return 0;
+    return ret;
 }
 
-static int
+static inline int
 pygobject_clear(PyGObject *self)
 {
-    GSList *tmp;
-
-    if (self->inst_dict) {
-	Py_DECREF(self->inst_dict);
-    }
-    self->inst_dict = NULL;
-
-    pyg_begin_allow_threads;
-    tmp = self->closures;
-    while (tmp) {
-	GClosure *closure = tmp->data;
-
-	/* we get next item first, because the current link gets
-	 * invalidated by pygobject_unwatch_closure */
-	tmp = tmp->next;
-	g_closure_invalidate(closure);
-    }
-    pyg_end_allow_threads;
-
-    if (self->closures != NULL)
-	g_warning("invalidated all closures, but self->closures != NULL !");
-
     if (self->obj) {
+        PyGObjectData *inst_data;
+        inst_data = pygobject_get_inst_data(self);
+        if (self->inst_dict)
+            inst_data->dict = self->inst_dict;
+        g_object_set_qdata_full(self->obj, pygobject_wrapper_key, NULL, NULL);
 	g_object_unref(self->obj);
+        self->obj = NULL;
     }
-    self->obj = NULL;
-
     return 0;
 }
 
@@ -1629,6 +1665,26 @@ pygobject_chain_from_overridden(PyGObjec
     return py_ret;
 }
 
+
+static PyObject *
+pygobject_weak_ref(PyGObject *self, PyObject *args)
+{
+    int len;
+    PyObject *callback = NULL, *user_data = NULL;
+    PyObject *retval;
+
+    CHECK_GOBJECT(self);
+
+    if ((len = PySequence_Length(args)) >= 1) {
+        callback = PySequence_ITEM(args, 0);
+        user_data = PySequence_GetSlice(args, 1, len);
+    }
+    retval = pygobject_weak_ref_new(self->obj, callback, user_data);
+    Py_XDECREF(callback);
+    Py_XDECREF(user_data);
+    return retval;
+}
+
 static PyMethodDef pygobject_methods[] = {
     { "__gobject_init__", (PyCFunction)pygobject__gobject_init__,
       METH_VARARGS|METH_KEYWORDS },
@@ -1652,6 +1708,7 @@ static PyMethodDef pygobject_methods[] =
     { "stop_emission", (PyCFunction)pygobject_stop_emission, METH_VARARGS },
     { "emit_stop_by_name", (PyCFunction)pygobject_stop_emission,METH_VARARGS },
     { "chain", (PyCFunction)pygobject_chain_from_overridden,METH_VARARGS },
+    { "weak_ref", (PyCFunction)pygobject_weak_ref, METH_VARARGS },
     { NULL, NULL, 0 }
 };
 
@@ -1815,3 +1872,176 @@ PyTypeObject PyGObject_MetaType = {
 };
 
 
+  /* ------------------------------------ */
+  /* ****** GObject weak reference ****** */
+  /* ------------------------------------ */
+
+typedef struct {
+    PyObject_HEAD
+    GObject *obj;
+    PyObject *callback;
+    PyObject *user_data;
+    gboolean have_floating_ref;
+} PyGObjectWeakRef;
+
+static int
+pygobject_weak_ref_traverse(PyGObjectWeakRef *self, visitproc visit, void *arg)
+{
+    if (self->callback && visit(self->callback, arg) < 0)
+        return -1;
+    if (self->user_data && visit(self->user_data, arg) < 0)
+        return -1;
+    return 0;
+}
+
+static void
+pygobject_weak_ref_notify(PyGObjectWeakRef *self, GObject *dummy)
+{
+    self->obj = NULL;
+    if (self->callback) {
+        PyObject *retval;
+        PyGILState_STATE state = pyg_gil_state_ensure();
+        retval = PyObject_Call(self->callback, self->user_data, NULL);
+        if (retval) {
+            if (retval != Py_None)
+                PyErr_Format(PyExc_TypeError,
+                             "GObject weak notify callback returned a value"
+                             " of type %s, should return None",
+                             retval->ob_type->tp_name);
+            Py_DECREF(retval);
+            PyErr_Print();
+        } else
+            PyErr_Print();
+        Py_CLEAR(self->callback);
+        Py_CLEAR(self->user_data);
+        if (self->have_floating_ref) {
+            self->have_floating_ref = FALSE;
+            Py_DECREF((PyObject *) self);
+        }
+        pyg_gil_state_release(state);
+    }
+}
+
+static inline int
+pygobject_weak_ref_clear(PyGObjectWeakRef *self)
+{
+    Py_CLEAR(self->callback);
+    Py_CLEAR(self->user_data);
+    if (self->obj) {
+        g_object_weak_unref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self);
+        self->obj = NULL;
+    }
+    return 0;
+}
+
+static void
+pygobject_weak_ref_dealloc(PyGObjectWeakRef *self)
+{
+    PyObject_GC_UnTrack((PyObject *)self);
+    pygobject_weak_ref_clear(self);
+    PyObject_GC_Del(self);
+}
+
+static PyObject *
+pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data)
+{
+    PyGObjectWeakRef *self;
+
+    self = PyObject_GC_New(PyGObjectWeakRef, &PyGObjectWeakRef_Type);
+    self->callback = callback;
+    self->user_data = user_data;
+    Py_XINCREF(self->callback);
+    Py_XINCREF(self->user_data);
+    self->obj = obj;
+    g_object_weak_ref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self);
+    if (callback != NULL) {
+          /* when we have a callback, we should INCREF the weakref
+           * object to make it stay alive even if it goes out of scope */
+        self->have_floating_ref = TRUE;
+        Py_INCREF((PyObject *) self);
+    }
+    return (PyObject *) self;
+}
+
+static PyObject *
+pygobject_weak_ref_unref(PyGObjectWeakRef *self, PyObject *args)
+{
+    if (!self->obj) {
+        PyErr_SetString(PyExc_ValueError, "weak ref already unreffed");
+        return NULL;
+    }
+    g_object_weak_unref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self);
+    self->obj = NULL;
+    if (self->have_floating_ref) {
+        self->have_floating_ref = FALSE;
+        Py_DECREF(self);
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyMethodDef pygobject_weak_ref_methods[] = {
+    { "unref", (PyCFunction)pygobject_weak_ref_unref, METH_NOARGS},
+    { NULL, NULL, 0}
+};
+
+static PyObject *
+pygobject_weak_ref_call(PyGObjectWeakRef *self, PyObject *args, PyObject *kw)
+{
+    static char *argnames[] = {NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames))
+        return NULL;
+
+    if (self->obj)
+        return pygobject_new_full(self->obj, FALSE);
+    else {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+}
+
+PyTypeObject PyGObjectWeakRef_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,                                          /* ob_size */
+    "gobject.GObjectWeakRef",                   /* tp_name */
+    sizeof(PyGObjectWeakRef),                   /* tp_basicsize */
+    0,                                          /* tp_itemsize */
+    (destructor)pygobject_weak_ref_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 */
+    (ternaryfunc)pygobject_weak_ref_call,  	/*tp_call*/
+    0,                                          /* tp_str */
+    (getattrofunc)0,            		/* tp_getattro */
+    (setattrofunc)0,            		/* tp_setattro */
+    0,                                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC,	/* tp_flags */
+    "A GObject weak reference",                 /* tp_doc */
+    (traverseproc)pygobject_weak_ref_traverse,  /* tp_traverse */
+    (inquiry)pygobject_weak_ref_clear,          /* tp_clear */
+    0,                                          /* tp_richcompare */
+    0,                                          /* tp_weaklistoffset */
+    0,      					/* tp_iter */
+    0,                                          /* tp_iternext */
+    pygobject_weak_ref_methods,			/* tp_methods */
+    0,						/* tp_members */
+    0,						/* tp_getset */
+    NULL,					/* tp_base */
+    0,						/* tp_dict */
+    0,						/* tp_descr_get */
+    0,						/* tp_descr_set */
+    0,						/* tp_dictoffset */
+    0,						/* tp_init */
+    0,						/* tp_alloc */
+    0,						/* tp_new */
+    0,						/* tp_free */
+    0,						/* tp_is_gc */
+    NULL,					/* tp_bases */
+};
Index: gobject/pygobject.h
===================================================================
RCS file: /cvs/gnome/gnome-python/pygobject/gobject/pygobject.h,v
retrieving revision 1.55
diff -u -p -d -r1.55 pygobject.h
--- gobject/pygobject.h	17 Jul 2005 20:05:47 -0000	1.55
+++ gobject/pygobject.h	15 Jan 2006 21:18:01 -0000
@@ -15,6 +15,8 @@ G_BEGIN_DECLS
   /* PyGClosure is a _private_ structure */
 typedef void (* PyClosureExceptionHandler) (GValue *ret, guint n_param_values, const GValue *params);
 typedef struct _PyGClosure PyGClosure;
+typedef struct _PyGObjectData PyGObjectData;
+
 struct _PyGClosure {
     GClosure closure;
     PyObject *callback;
@@ -23,12 +25,14 @@ struct _PyGClosure {
     PyClosureExceptionHandler exception_handler;
 };
 
+  /* inst_dict and closures are just aliases for what is found in the
+   * PyGObjectData */
 typedef struct {
     PyObject_HEAD
     GObject *obj;
     PyObject *inst_dict; /* the instance dictionary -- must be last */
     PyObject *weakreflist; /* list of weak references */
-    GSList *closures;
+    GSList *closures;           /* stale field; no longer updated */
 } PyGObject;
 
 #define pygobject_get(v) (((PyGObject *)(v))->obj)
Index: tests/test_subtype.py
===================================================================
RCS file: /cvs/gnome/gnome-python/pygobject/tests/test_subtype.py,v
retrieving revision 1.9
diff -u -p -d -r1.9 test_subtype.py
--- tests/test_subtype.py	9 Jan 2006 12:26:46 -0000	1.9
+++ tests/test_subtype.py	15 Jan 2006 21:18:01 -0000
@@ -1,8 +1,22 @@
 import unittest
+import weakref
+import gc
 
 import testmodule
 from common import gobject, testhelper
-from gobject import GObject, GInterface
+from gobject import GObject, GInterface, GObjectMeta
+import gtk
+
+class _ClassInittableMetaType(GObjectMeta):
+    def __init__(cls, name, bases, namespace):
+        super(_ClassInittableMetaType, cls).__init__(name, bases, namespace)
+        cls.__class_init__(namespace)
+
+class ClassInittableObject(object):
+    __metaclass__ = _ClassInittableMetaType
+    def __class_init__(cls, namespace):
+        pass
+    __class_init__ = classmethod(__class_init__)
 
 class TestSubType(unittest.TestCase):
     def testSubType(self):
@@ -35,3 +49,127 @@ class TestSubType(unittest.TestCase):
 
     def testGObjectNewError(self):
         self.assertRaises(TypeError, gobject.new, gobject.GObject, text='foo')
+
+
+    def testUnregisteredSubclass(self):
+        class MyButton(gtk.Button):
+            def custom_method(self):
+                pass
+        b = MyButton()
+        self.assertEqual(type(b), MyButton)
+        box = gtk.EventBox()
+        box.add(b)
+        del b
+        b = box.child
+        self.assertEqual(type(b), MyButton)
+        try:
+            b.custom_method()
+        except AttributeError:
+            self.fail()
+
+    def testInstDict(self):
+        b = gtk.Button()
+        box = gtk.EventBox()
+        box.add(b)
+        b.xyz = "zbr"
+        del b
+        b = box.child
+        self.assert_(hasattr(b, "xyz"))
+        try:
+            xyz = b.xyz
+        except AttributeError:
+            self.fail()
+        self.assertEqual(xyz, "zbr")
+
+    def testImmediateCollection(self):
+        b = gtk.Button()
+        bref = weakref.ref(b)
+        while gc.collect():
+            pass
+        del b
+        self.assertEqual(gc.collect(), 0)
+        self.assertEqual(bref(), None)
+
+    def testGCCollection(self):
+        a = gtk.Button()
+        b = gtk.Button()
+        a.b = b
+        b.a = a
+        aref = weakref.ref(a)
+        bref = weakref.ref(b)
+        del a, b
+        while gc.collect():
+            pass
+        self.assertEqual(aref(), None)
+        self.assertEqual(bref(), None)
+
+    def testGhostTwice(self):
+        b = gtk.Button()
+        box = gtk.EventBox()
+        box.add(b)
+        del b
+        b = box.child
+        del b
+        box.destroy()
+        del box
+        
+
+    def testWrapperUnref(self):
+        b = gtk.Button()
+        bref = weakref.ref(b)
+        del b
+        self.assertEqual(bref(), None)
+
+    def testGObjectUnref(self):
+        b = gtk.Button()
+        bref = b.weak_ref()
+        self.assert_(bref() is b)
+        del b
+        self.assertEqual(bref(), None)
+
+    def testGCCollection(self):
+        a = gtk.Button()
+        b = gtk.Button()
+        a.b = b
+        b.a = a
+        aref = a.weak_ref()
+        bref = b.weak_ref()
+        del a, b
+        while gc.collect():
+            pass
+        self.assertEqual(aref(), None)
+        self.assertEqual(bref(), None)
+
+    def testGhostTwice(self):
+        b = gtk.Button()
+        bref = b.weak_ref()
+        box = gtk.EventBox()
+        box.add(b)
+        del b
+        b = box.child
+        del b
+        self.assertNotEqual(bref(), None)
+        box.destroy()
+        del box
+        self.assertEqual(bref(), None)
+        
+    def testGhostWeakref(self):
+        b = gtk.Button()
+        bref = b.weak_ref()
+        box = gtk.EventBox()
+        box.add(b)
+        del b
+        b = bref()
+        b.hide()
+        del box
+        b.hide()
+        del b
+
+    def testWeakRefCallback(self):
+        def callback(a, b, c):
+            self._wr_args = a, b, c
+        self._wr_args = None
+        b = gtk.Button()
+        bref = b.weak_ref(callback, 1, 2, 3)
+        del b
+        self.assertEqual(self._wr_args, (1, 2, 3))
