/* -*- Mode: C; c-basic-offset: 4 -*- * pygtk- Python bindings for the GTK toolkit. * Copyright (C) 1998-2003 James Henstridge * Copyright (C) 2004 Johan Dahlin * * pygenum.c: GEnum wrapper * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #ifdef HAVE_CONFIG_H # include #endif #include "pygobject-private.h" static PyObject * pyg_enum_richcompare(PyGEnum *self, PyObject *other, int op) { if (!PyInt_Check(other)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } if (PyObject_TypeCheck(other, &PyGEnum_Type) && ((PyGEnum*)other)->gtype != self->gtype) { PyErr_Warn(PyExc_Warning, "comparing different enum types"); return NULL; } return pyg_integer_richcompare((PyObject *)self, other, op); } static PyObject * pyg_enum_repr(PyGEnum *self) { GEnumClass *enum_class; char *value; guint index; static char tmp[256]; enum_class = g_type_class_ref(self->gtype); g_assert(G_IS_ENUM_CLASS(enum_class)); for (index = 0; index < enum_class->n_values; index++) if (self->parent.ob_ival == enum_class->values[index].value) break; value = enum_class->values[index].value_name; if (value) sprintf(tmp, "", value, g_type_name(self->gtype)); else sprintf(tmp, "", self->parent.ob_ival, g_type_name(self->gtype)); g_type_class_unref(enum_class); return PyString_FromString(tmp); } static PyObject * pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "value", NULL }; long value; PyObject *pytc, *values, *ret, *intvalue; GType gtype; GEnumClass *eclass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value)) return NULL; pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__"); if (!pytc) return NULL; if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) { Py_DECREF(pytc); PyErr_SetString(PyExc_TypeError, "__gtype__ attribute not a typecode"); return NULL; } gtype = pyg_type_from_object(pytc); Py_DECREF(pytc); eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); if (value < 0 || value > eclass->n_values) { PyErr_SetString(PyExc_ValueError, "value out of range"); g_type_class_unref(eclass); return NULL; } values = PyObject_GetAttrString((PyObject *)type, "__enum_values__"); if (!values) { g_type_class_unref(eclass); return NULL; } if (!PyDict_Check(values) || PyDict_Size(values) != eclass->n_values) { PyErr_SetString(PyExc_TypeError, "__enum_values__ badly formed"); Py_DECREF(values); g_type_class_unref(eclass); return NULL; } g_type_class_unref(eclass); intvalue = PyInt_FromLong(value); ret = PyDict_GetItem(values, intvalue); Py_DECREF(intvalue); Py_DECREF(values); if (ret) Py_INCREF(ret); else PyErr_Format(PyExc_ValueError, "invalid enum value: %ld", value); return ret; } PyObject* pyg_enum_from_gtype (GType gtype, int value) { PyObject *pyclass, *values, *retval, *intvalue; g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); pyclass = (PyObject*)g_type_get_qdata(gtype, pygenum_class_key); if (pyclass == NULL) { pyclass = pyg_enum_add(NULL, g_type_name(gtype), NULL, gtype); if (!pyclass) return PyInt_FromLong(value); } values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, "__enum_values__"); intvalue = PyInt_FromLong(value); retval = PyDict_GetItem(values, intvalue); Py_DECREF(intvalue); if (!retval) { PyErr_Clear(); retval = ((PyTypeObject *)pyclass)->tp_alloc((PyTypeObject *)pyclass, 0); g_assert(retval != NULL); ((PyIntObject*)retval)->ob_ival = value; ((PyGFlags*)retval)->gtype = gtype; //return PyInt_FromLong(value); } Py_INCREF(retval); return retval; } PyObject * pyg_enum_add (PyObject * module, const char * typename, const char * strip_prefix, GType gtype) { PyGILState_STATE state; PyObject *instance_dict, *stub, *values, *o; GEnumClass *eclass; int i; g_return_val_if_fail(typename != NULL, NULL); g_return_val_if_fail(g_type_is_a(gtype, G_TYPE_ENUM), NULL); state = pyg_gil_state_ensure(); instance_dict = PyDict_New(); stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", typename, (PyObject *)&PyGEnum_Type, instance_dict); Py_DECREF(instance_dict); if (!stub) { PyErr_SetString(PyExc_RuntimeError, "can't create const"); pyg_gil_state_release(state); return NULL; } ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; ((PyTypeObject *)stub)->tp_new = pyg_enum_new; if (module) PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__module__", PyString_FromString(PyModule_GetName(module))); g_type_set_qdata(gtype, pygenum_class_key, stub); o = pyg_type_wrapper_new(gtype); PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o); Py_DECREF(o); if (module) { /* Add it to the module name space */ PyModule_AddObject(module, (char*)typename, stub); Py_INCREF(stub); } /* Register enum values */ eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); values = PyDict_New(); for (i = 0; i < eclass->n_values; i++) { PyObject *item, *intval; item = ((PyTypeObject *)stub)->tp_alloc((PyTypeObject *)stub, 0); ((PyIntObject*)item)->ob_ival = eclass->values[i].value; ((PyGEnum*)item)->gtype = gtype; intval = PyInt_FromLong(eclass->values[i].value); PyDict_SetItem(values, intval, item); Py_DECREF(intval); if (module) { PyModule_AddObject(module, pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix), item); Py_INCREF(item); } } PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__enum_values__", values); Py_DECREF(values); g_type_class_unref(eclass); pyg_gil_state_release(state); return stub; } static PyObject * pyg_enum_get_value_name(PyGEnum *self, void *closure) { GEnumClass *enum_class; GEnumValue *enum_value; PyObject *retval; enum_class = g_type_class_ref(self->gtype); g_assert(G_IS_ENUM_CLASS(enum_class)); enum_value = g_enum_get_value(enum_class, self->parent.ob_ival); retval = PyString_FromString(enum_value->value_name); g_type_class_unref(enum_class); return retval; } static PyObject * pyg_enum_get_value_nick(PyGEnum *self, void *closure) { GEnumClass *enum_class; GEnumValue *enum_value; PyObject *retval; enum_class = g_type_class_ref(self->gtype); g_assert(G_IS_ENUM_CLASS(enum_class)); enum_value = g_enum_get_value(enum_class, self->parent.ob_ival); retval = PyString_FromString(enum_value->value_nick); g_type_class_unref(enum_class); return retval; } static PyGetSetDef pyg_enum_getsets[] = { { "value_name", (getter)pyg_enum_get_value_name, (setter)0 }, { "value_nick", (getter)pyg_enum_get_value_nick, (setter)0 }, { NULL, 0, 0 } }; PyTypeObject PyGEnum_Type = { PyObject_HEAD_INIT(NULL) 0, "gobject.GEnum", sizeof(PyGEnum), 0, 0, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)pyg_enum_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ (reprfunc)pyg_enum_repr, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ (richcmpfunc)pyg_enum_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ pyg_enum_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ pyg_enum_new, /* tp_new */ };