summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustavo J. A. M. Carneiro <gjc@src.gnome.org>2005-05-22 22:38:55 +0000
committerGustavo J. A. M. Carneiro <gjc@src.gnome.org>2005-05-22 22:38:55 +0000
commit4b01307e0d9edcc71560a6e30f05dfed702cebdf (patch)
tree9a1630d0c38b86874570e642fda2656f78d73aa9
parent500a5306d2868dcde7c5b3f1a9c1b7b09aedcb8e (diff)
downloadpygobject-4b01307e0d9edcc71560a6e30f05dfed702cebdf.tar.gz
pygobject-4b01307e0d9edcc71560a6e30f05dfed702cebdf.tar.xz
pygobject-4b01307e0d9edcc71560a6e30f05dfed702cebdf.zip
Bug 128765: GObject metaclass
-rw-r--r--examples/signal.py4
-rw-r--r--gobject/gobjectmodule.c67
-rw-r--r--gobject/pygobject-private.h3
-rw-r--r--gobject/pygobject.c63
-rw-r--r--tests/test_signal.py30
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__':