Remove pygi.h and pygi-private.h
[pygobject.git] / gi / pygenum.c
blobfb0873de2aa14814dced6d7366e23d7186712cc7
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * pygtk- Python bindings for the GTK toolkit.
3 * Copyright (C) 1998-2003 James Henstridge
4 * Copyright (C) 2004 Johan Dahlin
6 * pygenum.c: GEnum wrapper
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
26 #include <pyglib.h>
27 #include "pyglib-python-compat.h"
28 #include "pygobject-private.h"
29 #include "pygi-type.h"
31 #include "pygenum.h"
33 GQuark pygenum_class_key;
35 PYGLIB_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type, PyGEnum);
37 static PyObject *
38 pyg_enum_val_new(PyObject* subclass, GType gtype, PyObject *intval)
40 PyObject *args, *item;
41 args = Py_BuildValue("(O)", intval);
42 item = (&PYGLIB_PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL);
43 Py_DECREF(args);
44 if (!item)
45 return NULL;
46 ((PyGEnum*)item)->gtype = gtype;
48 return item;
51 static PyObject *
52 pyg_enum_richcompare(PyGEnum *self, PyObject *other, int op)
54 static char warning[256];
56 if (!PYGLIB_PyLong_Check(other)) {
57 Py_INCREF(Py_NotImplemented);
58 return Py_NotImplemented;
61 if (PyObject_TypeCheck(other, &PyGEnum_Type) && ((PyGEnum*)other)->gtype != self->gtype) {
62 g_snprintf(warning, sizeof(warning), "comparing different enum types: %s and %s",
63 g_type_name(self->gtype), g_type_name(((PyGEnum*)other)->gtype));
64 if (PyErr_Warn(PyExc_Warning, warning))
65 return NULL;
68 return pyg_integer_richcompare((PyObject *)self, other, op);
71 static PyObject *
72 pyg_enum_repr(PyGEnum *self)
74 PyObject *module;
75 GEnumClass *enum_class;
76 const char *value;
77 guint index;
78 char *namespace, *module_str;
79 static char tmp[256];
80 long l;
82 module = PyObject_GetAttrString ((PyObject *)self, "__module__");
83 if (module == NULL)
84 return NULL;
86 if (!PYGLIB_PyUnicode_Check (module)) {
87 Py_DECREF (module);
88 return NULL;
91 enum_class = g_type_class_ref(self->gtype);
92 g_assert(G_IS_ENUM_CLASS(enum_class));
94 l = PYGLIB_PyLong_AS_LONG(self);
95 for (index = 0; index < enum_class->n_values; index++)
96 if (l == enum_class->values[index].value)
97 break;
99 module_str = PYGLIB_PyUnicode_AsString (module);
100 namespace = g_strrstr (module_str, ".");
101 if (namespace == NULL) {
102 namespace = module_str;
103 } else {
104 namespace += 1;
107 value = enum_class->values[index].value_name;
108 if (value)
109 sprintf(tmp, "<enum %s of type %s.%s>", value,
110 namespace, Py_TYPE (self)->tp_name);
111 else
112 sprintf(tmp, "<enum %ld of type %s.%s>", PYGLIB_PyLong_AS_LONG(self),
113 namespace, Py_TYPE (self)->tp_name);
114 Py_DECREF (module);
115 g_type_class_unref(enum_class);
117 return PYGLIB_PyUnicode_FromString(tmp);
120 static PyObject *
121 pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
123 static char *kwlist[] = { "value", NULL };
124 long value;
125 PyObject *pytc, *values, *ret, *intvalue;
126 GType gtype;
127 GEnumClass *eclass;
129 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value))
130 return NULL;
132 pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__");
133 if (!pytc)
134 return NULL;
136 if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) {
137 Py_DECREF(pytc);
138 PyErr_SetString(PyExc_TypeError,
139 "__gtype__ attribute not a typecode");
140 return NULL;
143 gtype = pyg_type_from_object(pytc);
144 Py_DECREF(pytc);
146 eclass = G_ENUM_CLASS(g_type_class_ref(gtype));
148 /* A check that 0 < value < eclass->n_values was here but got
149 * removed: enumeration values do not need to be consequitive,
150 * e.g. GtkPathPriorityType values are not.
153 values = PyObject_GetAttrString((PyObject *)type, "__enum_values__");
154 if (!values) {
155 g_type_class_unref(eclass);
156 return NULL;
159 /* Note that size of __enum_values__ dictionary can easily be less
160 * than 'n_values'. This happens if some values of the enum are
161 * numerically equal, e.g. gtk.ANCHOR_N == gtk.ANCHOR_NORTH.
162 * Johan said that "In retrospect, using a dictionary to store the
163 * values might not have been that good", but we need to keep
164 * backward compatibility.
166 if (!PyDict_Check(values) || PyDict_Size(values) > eclass->n_values) {
167 PyErr_SetString(PyExc_TypeError, "__enum_values__ badly formed");
168 Py_DECREF(values);
169 g_type_class_unref(eclass);
170 return NULL;
173 g_type_class_unref(eclass);
175 intvalue = PYGLIB_PyLong_FromLong(value);
176 ret = PyDict_GetItem(values, intvalue);
177 Py_DECREF(intvalue);
178 Py_DECREF(values);
179 if (ret)
180 Py_INCREF(ret);
181 else
182 PyErr_Format(PyExc_ValueError, "invalid enum value: %ld", value);
184 return ret;
187 PyObject*
188 pyg_enum_from_gtype (GType gtype, int value)
190 PyObject *pyclass, *values, *retval, *intvalue;
192 g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL);
194 /* Get a wrapper class by:
195 * 1. check for one attached to the gtype
196 * 2. lookup one in a typelib
197 * 3. creating a new one
199 pyclass = (PyObject*)g_type_get_qdata(gtype, pygenum_class_key);
200 if (!pyclass)
201 pyclass = pygi_type_import_by_g_type(gtype);
202 if (!pyclass)
203 pyclass = pyg_enum_add(NULL, g_type_name(gtype), NULL, gtype);
204 if (!pyclass)
205 return PYGLIB_PyLong_FromLong(value);
207 values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict,
208 "__enum_values__");
209 intvalue = PYGLIB_PyLong_FromLong(value);
210 retval = PyDict_GetItem(values, intvalue);
211 if (retval) {
212 Py_INCREF(retval);
214 else {
215 PyErr_Clear();
216 retval = pyg_enum_val_new(pyclass, gtype, intvalue);
218 Py_DECREF(intvalue);
220 return retval;
224 * pyg_enum_add
225 * Dynamically create a class derived from PyGEnum based on the given GType.
227 PyObject *
228 pyg_enum_add (PyObject * module,
229 const char * typename,
230 const char * strip_prefix,
231 GType gtype)
233 PyGILState_STATE state;
234 PyObject *instance_dict, *stub, *values, *o;
235 GEnumClass *eclass;
236 int i;
238 g_return_val_if_fail(typename != NULL, NULL);
239 if (!g_type_is_a (gtype, G_TYPE_ENUM)) {
240 PyErr_Format (PyExc_TypeError, "Trying to register gtype '%s' as enum when in fact it is of type '%s'",
241 g_type_name (gtype), g_type_name (G_TYPE_FUNDAMENTAL (gtype)));
242 return NULL;
245 state = pyglib_gil_state_ensure();
247 /* Create a new type derived from GEnum. This is the same as:
248 * >>> stub = type(typename, (GEnum,), {})
250 instance_dict = PyDict_New();
251 stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O",
252 typename, (PyObject *)&PyGEnum_Type,
253 instance_dict);
254 Py_DECREF(instance_dict);
255 if (!stub) {
256 PyErr_SetString(PyExc_RuntimeError, "can't create const");
257 pyglib_gil_state_release(state);
258 return NULL;
261 ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE;
262 ((PyTypeObject *)stub)->tp_new = pyg_enum_new;
264 if (module)
265 PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
266 "__module__",
267 PYGLIB_PyUnicode_FromString(PyModule_GetName(module)));
269 g_type_set_qdata(gtype, pygenum_class_key, stub);
271 o = pyg_type_wrapper_new(gtype);
272 PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o);
273 Py_DECREF(o);
275 if (module) {
276 /* Add it to the module name space */
277 PyModule_AddObject(module, (char*)typename, stub);
278 Py_INCREF(stub);
281 /* Register enum values */
282 eclass = G_ENUM_CLASS(g_type_class_ref(gtype));
284 values = PyDict_New();
285 for (i = 0; i < eclass->n_values; i++) {
286 PyObject *item, *intval;
288 intval = PYGLIB_PyLong_FromLong(eclass->values[i].value);
289 item = pyg_enum_val_new(stub, gtype, intval);
290 PyDict_SetItem(values, intval, item);
291 Py_DECREF(intval);
293 if (module) {
294 char *prefix;
296 prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix));
297 PyModule_AddObject(module, prefix, item);
298 g_free(prefix);
300 Py_INCREF(item);
304 PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
305 "__enum_values__", values);
306 Py_DECREF(values);
308 g_type_class_unref(eclass);
310 pyglib_gil_state_release(state);
311 return stub;
314 static PyObject *
315 pyg_enum_reduce(PyObject *self, PyObject *args)
317 if (!PyArg_ParseTuple(args, ":GEnum.__reduce__"))
318 return NULL;
320 return Py_BuildValue("(O(i)O)", Py_TYPE(self), PYGLIB_PyLong_AsLong(self),
321 PyObject_GetAttrString(self, "__dict__"));
324 static PyObject *
325 pyg_enum_get_value_name(PyGEnum *self, void *closure)
327 GEnumClass *enum_class;
328 GEnumValue *enum_value;
329 PyObject *retval;
331 enum_class = g_type_class_ref(self->gtype);
332 g_assert(G_IS_ENUM_CLASS(enum_class));
334 enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self));
336 retval = PYGLIB_PyUnicode_FromString(enum_value->value_name);
337 g_type_class_unref(enum_class);
339 return retval;
342 static PyObject *
343 pyg_enum_get_value_nick(PyGEnum *self, void *closure)
345 GEnumClass *enum_class;
346 GEnumValue *enum_value;
347 PyObject *retval;
349 enum_class = g_type_class_ref(self->gtype);
350 g_assert(G_IS_ENUM_CLASS(enum_class));
352 enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self));
354 retval = PYGLIB_PyUnicode_FromString(enum_value->value_nick);
355 g_type_class_unref(enum_class);
357 return retval;
361 static PyMethodDef pyg_enum_methods[] = {
362 { "__reduce__", (PyCFunction)pyg_enum_reduce, METH_VARARGS },
363 { NULL, NULL, 0 }
366 static PyGetSetDef pyg_enum_getsets[] = {
367 { "value_name", (getter)pyg_enum_get_value_name, (setter)0 },
368 { "value_nick", (getter)pyg_enum_get_value_nick, (setter)0 },
369 { NULL, 0, 0 }
372 void
373 pygobject_enum_register_types(PyObject *d)
375 pygenum_class_key = g_quark_from_static_string("PyGEnum::class");
377 PyGEnum_Type.tp_base = &PYGLIB_PyLong_Type;
378 #if PY_VERSION_HEX < 0x03000000
379 PyGEnum_Type.tp_new = pyg_enum_new;
380 #else
381 PyGEnum_Type.tp_new = PyLong_Type.tp_new;
382 PyGEnum_Type.tp_hash = PyLong_Type.tp_hash;
383 #endif
384 PyGEnum_Type.tp_repr = (reprfunc)pyg_enum_repr;
385 PyGEnum_Type.tp_str = (reprfunc)pyg_enum_repr;
386 PyGEnum_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
387 PyGEnum_Type.tp_richcompare = (richcmpfunc)pyg_enum_richcompare;
388 PyGEnum_Type.tp_methods = pyg_enum_methods;
389 PyGEnum_Type.tp_getset = pyg_enum_getsets;
390 PYGOBJECT_REGISTER_GTYPE(d, PyGEnum_Type, "GEnum", G_TYPE_ENUM);