diff options
author | TizenOpenSource <tizenopensrc@samsung.com> | 2023-12-08 13:16:12 +0900 |
---|---|---|
committer | TizenOpenSource <tizenopensrc@samsung.com> | 2023-12-08 13:16:12 +0900 |
commit | 454aa52f950f2348756dfffc9c26fb74d4aa3bef (patch) | |
tree | 4e8be3f8c8218dbafe65e22dfc73e9351c1d5bbb /gi/pygenum.c | |
parent | f3eae5a895fc60cb99c0c366bdd011018ce3bc7b (diff) | |
download | pygobject2-454aa52f950f2348756dfffc9c26fb74d4aa3bef.tar.gz pygobject2-454aa52f950f2348756dfffc9c26fb74d4aa3bef.tar.bz2 pygobject2-454aa52f950f2348756dfffc9c26fb74d4aa3bef.zip |
Imported Upstream version 3.46.0upstream/3.46.0
Diffstat (limited to 'gi/pygenum.c')
-rw-r--r-- | gi/pygenum.c | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/gi/pygenum.c b/gi/pygenum.c new file mode 100644 index 0000000..37495e8 --- /dev/null +++ b/gi/pygenum.c @@ -0,0 +1,408 @@ +/* -*- 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, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "pygi-type.h" +#include "pygi-util.h" +#include "pygi-type.h" +#include "pygi-basictype.h" +#include "pygenum.h" +#include "pygboxed.h" + +GQuark pygenum_class_key; + +PYGI_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type, PyGEnum); + +static PyObject * +pyg_enum_val_new(PyObject* subclass, GType gtype, PyObject *intval) +{ + PyObject *args, *item; + args = Py_BuildValue("(O)", intval); + item = (&PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL); + Py_DECREF(args); + if (!item) + return NULL; + ((PyGEnum*)item)->gtype = gtype; + + return item; +} + +static PyObject * +pyg_enum_richcompare(PyGEnum *self, PyObject *other, int op) +{ + static char warning[256]; + + if (!PyLong_Check (other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (PyObject_TypeCheck(other, &PyGEnum_Type) && ((PyGEnum*)other)->gtype != self->gtype) { + g_snprintf(warning, sizeof(warning), "comparing different enum types: %s and %s", + g_type_name(self->gtype), g_type_name(((PyGEnum*)other)->gtype)); + if (PyErr_Warn(PyExc_Warning, warning)) + return NULL; + } + + return pyg_integer_richcompare((PyObject *)self, other, op); +} + +static PyObject * +pyg_enum_repr(PyGEnum *self) +{ + PyObject *module; + GEnumClass *enum_class; + const char *value; + guint index; + char *namespace, *module_str; + static char tmp[256]; + long l; + + module = PyObject_GetAttrString ((PyObject *)self, "__module__"); + if (module == NULL) + return NULL; + + if (!PyUnicode_Check (module)) { + Py_DECREF (module); + return NULL; + } + + enum_class = g_type_class_ref(self->gtype); + g_assert(G_IS_ENUM_CLASS(enum_class)); + + l = PyLong_AS_LONG ((PyObject*)self); + for (index = 0; index < enum_class->n_values; index++) + if (l == enum_class->values[index].value) + break; + + module_str = PyUnicode_AsUTF8 (module); + namespace = g_strrstr (module_str, "."); + if (namespace == NULL) { + namespace = module_str; + } else { + namespace += 1; + } + + value = enum_class->values[index].value_name; + if (value) + sprintf(tmp, "<enum %s of type %s.%s>", value, + namespace, Py_TYPE (self)->tp_name); + else + sprintf(tmp, "<enum %ld of type %s.%s>", PyLong_AS_LONG ((PyObject*)self), + namespace, Py_TYPE (self)->tp_name); + Py_DECREF (module); + g_type_class_unref(enum_class); + + return PyUnicode_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)); + + /* A check that 0 < value < eclass->n_values was here but got + * removed: enumeration values do not need to be consequitive, + * e.g. GtkPathPriorityType values are not. + */ + + values = PyObject_GetAttrString((PyObject *)type, "__enum_values__"); + if (!values) { + g_type_class_unref(eclass); + return NULL; + } + + /* Note that size of __enum_values__ dictionary can easily be less + * than 'n_values'. This happens if some values of the enum are + * numerically equal, e.g. gtk.ANCHOR_N == gtk.ANCHOR_NORTH. + * Johan said that "In retrospect, using a dictionary to store the + * values might not have been that good", but we need to keep + * backward compatibility. + */ + if (!PyDict_Check(values) || (gsize)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 = PyLong_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); + + /* Get a wrapper class by: + * 1. check for one attached to the gtype + * 2. lookup one in a typelib + * 3. creating a new one + */ + pyclass = (PyObject*)g_type_get_qdata(gtype, pygenum_class_key); + if (!pyclass) + pyclass = pygi_type_import_by_g_type(gtype); + if (!pyclass) + pyclass = pyg_enum_add(NULL, g_type_name(gtype), NULL, gtype); + if (!pyclass) + return PyLong_FromLong(value); + + values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, + "__enum_values__"); + intvalue = PyLong_FromLong(value); + retval = PyDict_GetItem(values, intvalue); + if (retval) { + Py_INCREF(retval); + } + else { + PyErr_Clear(); + retval = pyg_enum_val_new(pyclass, gtype, intvalue); + } + Py_DECREF(intvalue); + + return retval; +} + +/* + * pyg_enum_add + * Dynamically create a class derived from PyGEnum based on the given GType. + */ +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; + guint i; + + g_return_val_if_fail(typename != NULL, NULL); + if (!g_type_is_a (gtype, G_TYPE_ENUM)) { + PyErr_Format (PyExc_TypeError, "Trying to register gtype '%s' as enum when in fact it is of type '%s'", + g_type_name (gtype), g_type_name (G_TYPE_FUNDAMENTAL (gtype))); + return NULL; + } + + state = PyGILState_Ensure(); + + /* Create a new type derived from GEnum. This is the same as: + * >>> stub = type(typename, (GEnum,), {}) + */ + 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"); + PyGILState_Release(state); + return NULL; + } + + ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; + + if (module) + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__module__", + PyUnicode_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; + + intval = PyLong_FromLong(eclass->values[i].value); + item = pyg_enum_val_new(stub, gtype, intval); + PyDict_SetItem(values, intval, item); + Py_DECREF(intval); + + if (module) { + char *prefix; + + prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix)); + PyModule_AddObject(module, prefix, item); + g_free(prefix); + + Py_INCREF(item); + } + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__enum_values__", values); + Py_DECREF(values); + + g_type_class_unref(eclass); + + PyGILState_Release(state); + return stub; +} + +static PyObject * +pyg_enum_reduce(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GEnum.__reduce__")) + return NULL; + + return Py_BuildValue("(O(i)O)", Py_TYPE(self), PyLong_AsLong (self), + PyObject_GetAttrString(self, "__dict__")); +} + +static PyObject * +pyg_enum_get_value_name(PyGEnum *self, void *closure) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + PyObject *retval; + gint intvalue; + + if (!pygi_gint_from_py ((PyObject*) self, &intvalue)) + return NULL; + + enum_class = g_type_class_ref(self->gtype); + g_assert(G_IS_ENUM_CLASS(enum_class)); + + enum_value = g_enum_get_value(enum_class, intvalue); + + retval = pygi_utf8_to_py (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; + gint intvalue; + + if (!pygi_gint_from_py ((PyObject*) self, &intvalue)) + return NULL; + + enum_class = g_type_class_ref(self->gtype); + g_assert(G_IS_ENUM_CLASS(enum_class)); + + enum_value = g_enum_get_value(enum_class, intvalue); + + retval = pygi_utf8_to_py (enum_value->value_nick); + + g_type_class_unref(enum_class); + + return retval; +} + + +static PyMethodDef pyg_enum_methods[] = { + { "__reduce__", (PyCFunction)pyg_enum_reduce, METH_VARARGS }, + { NULL, NULL, 0 } +}; + +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 } +}; + +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_enum_register_types(PyObject *d) +{ + PyObject *pygtype; + + pygenum_class_key = g_quark_from_static_string("PyGEnum::class"); + + PyGEnum_Type.tp_base = &PyLong_Type; + PyGEnum_Type.tp_new = pyg_enum_new; + PyGEnum_Type.tp_hash = PyLong_Type.tp_hash; + PyGEnum_Type.tp_repr = (reprfunc)pyg_enum_repr; + PyGEnum_Type.tp_str = (reprfunc)pyg_enum_repr; + PyGEnum_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyGEnum_Type.tp_richcompare = (richcmpfunc)pyg_enum_richcompare; + PyGEnum_Type.tp_methods = pyg_enum_methods; + PyGEnum_Type.tp_getset = pyg_enum_getsets; + PyGEnum_Type.tp_alloc = PyType_GenericAlloc; + if (PyType_Ready(&PyGEnum_Type)) + return -1; + + pygtype = pyg_type_wrapper_new (G_TYPE_ENUM); + PyDict_SetItemString (PyGEnum_Type.tp_dict, "__gtype__", pygtype); + Py_DECREF (pygtype); + + PyDict_SetItemString(d, "GEnum", (PyObject *)&PyGEnum_Type); + + return 0; +} |