diff options
author | Gustavo J. A. M. Carneiro <gjc@src.gnome.org> | 2005-05-22 22:38:55 +0000 |
---|---|---|
committer | Gustavo J. A. M. Carneiro <gjc@src.gnome.org> | 2005-05-22 22:38:55 +0000 |
commit | 4b01307e0d9edcc71560a6e30f05dfed702cebdf (patch) | |
tree | 9a1630d0c38b86874570e642fda2656f78d73aa9 | |
parent | 500a5306d2868dcde7c5b3f1a9c1b7b09aedcb8e (diff) | |
download | pygobject-4b01307e0d9edcc71560a6e30f05dfed702cebdf.tar.gz pygobject-4b01307e0d9edcc71560a6e30f05dfed702cebdf.tar.xz pygobject-4b01307e0d9edcc71560a6e30f05dfed702cebdf.zip |
Bug 128765: GObject metaclass
-rw-r--r-- | examples/signal.py | 4 | ||||
-rw-r--r-- | gobject/gobjectmodule.c | 67 | ||||
-rw-r--r-- | gobject/pygobject-private.h | 3 | ||||
-rw-r--r-- | gobject/pygobject.c | 63 | ||||
-rw-r--r-- | tests/test_signal.py | 30 |
5 files changed, 130 insertions, 37 deletions
diff --git a/examples/signal.py b/examples/signal.py index 3d72e75..3ac4235 100644 --- a/examples/signal.py +++ b/examples/signal.py @@ -1,3 +1,4 @@ +import pygtk; pygtk.require("2.0") import gobject class C(gobject.GObject): @@ -9,15 +10,12 @@ class C(gobject.GObject): self.__gobject_init__() # default constructor using our new GType def do_my_signal(self, arg): print "C: class closure for `my_signal' called with argument", arg -gobject.type_register(C) class D(C): def do_my_signal(self, arg): print "D: class closure for `my_signal' called. Chaining up to C" C.do_my_signal(self, arg) -gobject.type_register(D) - def my_signal_handler(object, arg, *extra): print "handler for `my_signal' called with argument", arg, \ "and extra args", extra diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c index b8e6f77..5d288e3 100644 --- a/gobject/gobjectmodule.c +++ b/gobject/gobjectmodule.c @@ -900,12 +900,42 @@ pyg_run_class_init(GType gtype, gpointer gclass, PyTypeObject *pyclass) return 0; } - static PyObject * -pyg_type_register(PyObject *self, PyObject *args) +_wrap_pyg_type_register(PyObject *self, PyObject *args) { - PyObject *gtype, *module, *gsignals, *gproperties; PyTypeObject *class; + PyObject *gtype; + + if (PyErr_Warn(PyExc_DeprecationWarning, "gobject.type_register is deprecated;" + " now types are automatically registered")) + return NULL; + + if (!PyArg_ParseTuple(args, "O:gobject.type_register", &class)) + return NULL; + if (!PyType_IsSubtype(class, &PyGObject_Type)) { + PyErr_SetString(PyExc_TypeError,"argument must be a GObject subclass"); + return NULL; + } + + /* Check if type already registered */ + gtype = PyObject_GetAttrString((PyObject *)class, "__gtype__"); + if (gtype == NULL) { + PyErr_Clear(); + /* not registered */ + if (pyg_type_register(class)) + return NULL; + } else + /* already registered */ + Py_DECREF(gtype); + + Py_INCREF(class); + return (PyObject *) class; +} + +int +pyg_type_register(PyTypeObject *class) +{ + PyObject *gtype, *module, *gsignals, *gproperties; GType parent_type, instance_type; gchar *type_name = NULL; gint i, name_serial; @@ -926,17 +956,11 @@ pyg_type_register(PyObject *self, PyObject *args) (GInstanceInitFunc) NULL }; - if (!PyArg_ParseTuple(args, "O:gobject.type_register", &class)) - return NULL; - if (!PyType_IsSubtype(class, &PyGObject_Type)) { - PyErr_SetString(PyExc_TypeError,"argument must be a GObject subclass"); - return NULL; - } /* find the GType of the parent */ parent_type = pyg_type_from_object((PyObject *)class); if (!parent_type) { - return NULL; + return -1; } /* make name for new GType */ @@ -985,7 +1009,7 @@ pyg_type_register(PyObject *self, PyObject *args) g_free(type_name); if (instance_type == 0) { PyErr_SetString(PyExc_RuntimeError, "could not create new GType"); - return NULL; + return -1; } /* store pointer to the class with the GType */ @@ -1011,10 +1035,10 @@ pyg_type_register(PyObject *self, PyObject *args) if (!PyDict_Check(gsignals)) { PyErr_SetString(PyExc_TypeError, "__gsignals__ attribute not a dict!"); - return NULL; + return -1; } if (!add_signals(instance_type, gsignals)) { - return NULL; + return -1; } PyDict_DelItemString(class->tp_dict, "__gsignals__"); /* Borrowed reference. Py_DECREF(gsignals); */ @@ -1029,10 +1053,10 @@ pyg_type_register(PyObject *self, PyObject *args) if (!PyDict_Check(gproperties)) { PyErr_SetString(PyExc_TypeError, "__gproperties__ attribute not a dict!"); - return NULL; + return -1; } if (!add_properties(instance_type, gproperties)) { - return NULL; + return -1; } PyDict_DelItemString(class->tp_dict, "__gproperties__"); /* Borrowed reference. Py_DECREF(gproperties); */ @@ -1043,7 +1067,7 @@ pyg_type_register(PyObject *self, PyObject *args) gclass = g_type_class_ref(instance_type); if (pyg_run_class_init(instance_type, gclass, class)) { g_type_class_unref(gclass); - return NULL; + return -1; } g_type_class_unref(gclass); @@ -1074,8 +1098,7 @@ pyg_type_register(PyObject *self, PyObject *args) } else g_warning("type has no tp_bases"); - Py_INCREF(class); - return (PyObject *) class; + return 0; } static PyObject * @@ -2085,7 +2108,7 @@ static PyMethodDef pygobject_functions[] = { { "type_is_a", pyg_type_is_a, METH_VARARGS }, { "type_children", pyg_type_children, METH_VARARGS }, { "type_interfaces", pyg_type_interfaces, METH_VARARGS }, - { "type_register", pyg_type_register, METH_VARARGS }, + { "type_register", _wrap_pyg_type_register, METH_VARARGS }, { "signal_new", pyg_signal_new, METH_VARARGS }, { "signal_list_names", (PyCFunction)pyg_signal_list_names, METH_VARARGS|METH_KEYWORDS }, { "signal_list_ids", (PyCFunction)pyg_signal_list_ids, METH_VARARGS|METH_KEYWORDS }, @@ -2463,6 +2486,12 @@ initgobject(void) gerror_exc = PyErr_NewException("gobject.GError", PyExc_RuntimeError,NULL); PyDict_SetItemString(d, "GError", gerror_exc); + + PyGObject_MetaType.tp_traverse = PyType_Type.tp_traverse; + PyGObject_MetaType.tp_clear = PyType_Type.tp_clear; + PyGObject_MetaType.tp_is_gc = PyType_Type.tp_is_gc; + PyType_Ready(&PyGObject_MetaType); + PyDict_SetItemString(d, "GObjectMeta", (PyObject *) &PyGObject_MetaType); PyGObject_Type.tp_alloc = PyType_GenericAlloc; PyGObject_Type.tp_new = PyType_GenericNew; diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h index 1e13111..7710acd 100644 --- a/gobject/pygobject-private.h +++ b/gobject/pygobject-private.h @@ -77,6 +77,8 @@ GClosure *pyg_signal_class_closure_get(void); PyObject *pyg_object_descr_doc_get(void); +extern PyTypeObject PyGObject_MetaType; + /* from pygobject.h */ extern PyTypeObject PyGObject_Type; extern PyTypeObject PyGInterface_Type; @@ -92,6 +94,7 @@ PyTypeObject *pygobject_lookup_class (GType gtype); void pygobject_watch_closure (PyObject *self, GClosure *closure); void pygobject_register_sinkfunc(GType type, void (* sinkfunc)(GObject *object)); +int pyg_type_register (PyTypeObject *class); /* from pygboxed.c */ extern PyTypeObject PyGBoxed_Type; diff --git a/gobject/pygobject.c b/gobject/pygobject.c index 7379a92..fdc9026 100644 --- a/gobject/pygobject.c +++ b/gobject/pygobject.c @@ -114,7 +114,8 @@ pygobject_register_class(PyObject *dict, const gchar *type_name, if (s != NULL) class_name = s + 1; - type->ob_type = &PyType_Type; + type->ob_type = &PyGObject_MetaType; + if (bases) { type->tp_bases = bases; type->tp_base = (PyTypeObject *)PyTuple_GetItem(bases, 0); @@ -1258,3 +1259,63 @@ PyTypeObject PyGObject_Type = { (PyObject *)0, /* tp_bases */ }; + + + /* -------- GObject MetaClass -----------*/ +static int +pygobjectmeta_init(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) +{ + if (PyType_Type.tp_init((PyObject *) subtype, args, kwargs)) + return -1; + return pyg_type_register(subtype); +} + + +PyTypeObject PyGObject_MetaType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "gobject.GObjectMeta", /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)0, /* tp_dealloc */ + (printfunc)0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)0, /* tp_compare */ + (reprfunc)0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)0, /* tp_str */ + (getattrofunc)0, /* tp_getattro */ + (setattrofunc)0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, /* tp_flags */ + "GObject Metaclass -- automatically registers GObject subclasses " + "as new GType's", /* Documentation string */ + (traverseproc)0, /* tp_traverse */ + (inquiry)0, /* tp_clear */ + (richcmpfunc)0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)0, /* tp_iter */ + (iternextfunc)0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyType_Type, /* tp_base */ + (PyObject *)0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)pygobjectmeta_init, /* tp_init */ + (allocfunc)0, /* tp_alloc */ + (newfunc)0, /* tp_new */ + 0, /* tp_free */ + (inquiry)0, /* tp_is_gc */ + NULL, /* tp_bases */ +}; + + diff --git a/tests/test_signal.py b/tests/test_signal.py index b4a6cdc..53dd467 100644 --- a/tests/test_signal.py +++ b/tests/test_signal.py @@ -10,13 +10,11 @@ class C(gobject.GObject): (gobject.TYPE_INT,)) } def do_my_signal(self, arg): self.arg = arg -gobject.type_register(C) class D(C): def do_my_signal(self, arg2): self.arg2 = arg2 C.do_my_signal(self, arg2) -gobject.type_register(D) class TestChaining(unittest.TestCase): def setUp(self): @@ -46,29 +44,33 @@ class TestChaining(unittest.TestCase): # This is for bug 153718 class TestGSignalsError(unittest.TestCase): def testInvalidType(self, *args): - class Foo(gobject.GObject): - __gsignals__ = None - self.assertRaises(TypeError, gobject.type_register, Foo) + def foo(): + class Foo(gobject.GObject): + __gsignals__ = None + self.assertRaises(TypeError, foo) gc.collect() def testInvalidName(self, *args): - class Foo(gobject.GObject): - __gsignals__ = {'not-exists' : 'override'} - self.assertRaises(TypeError, gobject.type_register, Foo) + def foo(): + class Foo(gobject.GObject): + __gsignals__ = {'not-exists' : 'override'} + self.assertRaises(TypeError, foo) gc.collect() class TestGPropertyError(unittest.TestCase): def testInvalidType(self, *args): - class Foo(gobject.GObject): - __gproperties__ = None - self.assertRaises(TypeError, gobject.type_register, Foo) + def foo(): + class Foo(gobject.GObject): + __gproperties__ = None + self.assertRaises(TypeError, foo) gc.collect() def testInvalidName(self, *args): - class Foo(gobject.GObject): - __gproperties__ = { None: None } + def foo(): + class Foo(gobject.GObject): + __gproperties__ = { None: None } - self.assertRaises(TypeError, gobject.type_register, Foo) + self.assertRaises(TypeError, foo) gc.collect() if __name__ == '__main__': |