Imported Upstream version 3.21.91
[platform/upstream/python-gobject.git] / gi / pygenum.c
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
5  *
6  *   pygenum.c: GEnum wrapper
7  *
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.
12  *
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.
17  *
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/>.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25
26 #include <pyglib.h>
27 #include "pyglib-python-compat.h"
28 #include "pygi-type.h"
29 #include "pygi-util.h"
30
31 #include "pygtype.h"
32 #include "pygenum.h"
33 #include "pygboxed.h"
34
35 GQuark pygenum_class_key;
36
37 PYGLIB_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type, PyGEnum);
38
39 static PyObject *
40 pyg_enum_val_new(PyObject* subclass, GType gtype, PyObject *intval)
41 {
42     PyObject *args, *item;
43     args = Py_BuildValue("(O)", intval);
44     item =  (&PYGLIB_PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL);
45     Py_DECREF(args);
46     if (!item)
47         return NULL;
48     ((PyGEnum*)item)->gtype = gtype;
49
50     return item;
51 }
52
53 static PyObject *
54 pyg_enum_richcompare(PyGEnum *self, PyObject *other, int op)
55 {
56     static char warning[256];
57
58     if (!PYGLIB_PyLong_Check(other)) {
59         Py_INCREF(Py_NotImplemented);
60         return Py_NotImplemented;
61     }
62
63     if (PyObject_TypeCheck(other, &PyGEnum_Type) && ((PyGEnum*)other)->gtype != self->gtype) {
64         g_snprintf(warning, sizeof(warning), "comparing different enum types: %s and %s",
65                    g_type_name(self->gtype), g_type_name(((PyGEnum*)other)->gtype));
66         if (PyErr_Warn(PyExc_Warning, warning))
67             return NULL;
68     }
69
70     return pyg_integer_richcompare((PyObject *)self, other, op);
71 }
72
73 static PyObject *
74 pyg_enum_repr(PyGEnum *self)
75 {
76     PyObject *module;
77     GEnumClass *enum_class;
78     const char *value;
79     guint index;
80     char *namespace, *module_str;
81     static char tmp[256];
82     long l;
83
84     module = PyObject_GetAttrString ((PyObject *)self, "__module__");
85     if (module == NULL)
86         return NULL;
87
88     if (!PYGLIB_PyUnicode_Check (module)) {
89         Py_DECREF (module);
90         return NULL;
91     }
92
93     enum_class = g_type_class_ref(self->gtype);
94     g_assert(G_IS_ENUM_CLASS(enum_class));
95
96     l = PYGLIB_PyLong_AS_LONG(self);
97     for (index = 0; index < enum_class->n_values; index++)
98         if (l == enum_class->values[index].value)
99             break;
100
101     module_str = PYGLIB_PyUnicode_AsString (module);
102     namespace = g_strrstr (module_str, ".");
103     if (namespace == NULL) {
104         namespace = module_str;
105     } else {
106         namespace += 1;
107     }
108
109     value = enum_class->values[index].value_name;
110     if (value)
111         sprintf(tmp, "<enum %s of type %s.%s>", value,
112                 namespace, Py_TYPE (self)->tp_name);
113     else
114         sprintf(tmp, "<enum %ld of type %s.%s>", PYGLIB_PyLong_AS_LONG(self),
115                 namespace, Py_TYPE (self)->tp_name);
116     Py_DECREF (module);
117     g_type_class_unref(enum_class);
118
119     return PYGLIB_PyUnicode_FromString(tmp);
120 }
121
122 static PyObject *
123 pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
124 {
125     static char *kwlist[] = { "value", NULL };
126     long value;
127     PyObject *pytc, *values, *ret, *intvalue;
128     GType gtype;
129     GEnumClass *eclass;
130
131     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value))
132         return NULL;
133
134     pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__");
135     if (!pytc)
136         return NULL;
137
138     if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) {
139         Py_DECREF(pytc);
140         PyErr_SetString(PyExc_TypeError,
141                         "__gtype__ attribute not a typecode");
142         return NULL;
143     }
144
145     gtype = pyg_type_from_object(pytc);
146     Py_DECREF(pytc);
147
148     eclass = G_ENUM_CLASS(g_type_class_ref(gtype));
149
150     /* A check that 0 < value < eclass->n_values was here but got
151      * removed: enumeration values do not need to be consequitive,
152      * e.g. GtkPathPriorityType values are not.
153      */
154
155     values = PyObject_GetAttrString((PyObject *)type, "__enum_values__");
156     if (!values) {
157         g_type_class_unref(eclass);
158         return NULL;
159     }
160
161     /* Note that size of __enum_values__ dictionary can easily be less
162      * than 'n_values'.  This happens if some values of the enum are
163      * numerically equal, e.g. gtk.ANCHOR_N == gtk.ANCHOR_NORTH.
164      * Johan said that "In retrospect, using a dictionary to store the
165      * values might not have been that good", but we need to keep
166      * backward compatibility.
167      */
168     if (!PyDict_Check(values) || PyDict_Size(values) > eclass->n_values) {
169         PyErr_SetString(PyExc_TypeError, "__enum_values__ badly formed");
170         Py_DECREF(values);
171         g_type_class_unref(eclass);
172         return NULL;
173     }
174
175     g_type_class_unref(eclass);
176
177     intvalue = PYGLIB_PyLong_FromLong(value);
178     ret = PyDict_GetItem(values, intvalue);
179     Py_DECREF(intvalue);
180     Py_DECREF(values);
181     if (ret)
182         Py_INCREF(ret);
183     else
184         PyErr_Format(PyExc_ValueError, "invalid enum value: %ld", value);
185
186     return ret;
187 }
188
189 PyObject*
190 pyg_enum_from_gtype (GType gtype, int value)
191 {
192     PyObject *pyclass, *values, *retval, *intvalue;
193
194     g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL);
195
196     /* Get a wrapper class by:
197      * 1. check for one attached to the gtype
198      * 2. lookup one in a typelib
199      * 3. creating a new one
200      */
201     pyclass = (PyObject*)g_type_get_qdata(gtype, pygenum_class_key);
202     if (!pyclass)
203         pyclass = pygi_type_import_by_g_type(gtype);
204     if (!pyclass)
205         pyclass = pyg_enum_add(NULL, g_type_name(gtype), NULL, gtype);
206     if (!pyclass)
207         return PYGLIB_PyLong_FromLong(value);
208
209     values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict,
210                                   "__enum_values__");
211     intvalue = PYGLIB_PyLong_FromLong(value);
212     retval = PyDict_GetItem(values, intvalue);
213     if (retval) {
214         Py_INCREF(retval);
215     }
216     else {
217         PyErr_Clear();
218         retval = pyg_enum_val_new(pyclass, gtype, intvalue);
219     }
220     Py_DECREF(intvalue);
221
222     return retval;
223 }
224
225 /*
226  * pyg_enum_add
227  * Dynamically create a class derived from PyGEnum based on the given GType.
228  */
229 PyObject *
230 pyg_enum_add (PyObject *   module,
231               const char * typename,
232               const char * strip_prefix,
233               GType        gtype)
234 {
235     PyGILState_STATE state;
236     PyObject *instance_dict, *stub, *values, *o;
237     GEnumClass *eclass;
238     int i;
239
240     g_return_val_if_fail(typename != NULL, NULL);
241     if (!g_type_is_a (gtype, G_TYPE_ENUM)) {
242         PyErr_Format (PyExc_TypeError, "Trying to register gtype '%s' as enum when in fact it is of type '%s'",
243                       g_type_name (gtype), g_type_name (G_TYPE_FUNDAMENTAL (gtype)));
244         return NULL;
245     }
246
247     state = pyglib_gil_state_ensure();
248
249     /* Create a new type derived from GEnum. This is the same as:
250      * >>> stub = type(typename, (GEnum,), {})
251      */
252     instance_dict = PyDict_New();
253     stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O",
254                                  typename, (PyObject *)&PyGEnum_Type,
255                                  instance_dict);
256     Py_DECREF(instance_dict);
257     if (!stub) {
258         PyErr_SetString(PyExc_RuntimeError, "can't create const");
259         pyglib_gil_state_release(state);
260         return NULL;
261     }
262
263     ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE;
264     ((PyTypeObject *)stub)->tp_new = pyg_enum_new;
265
266     if (module)
267         PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
268                              "__module__",
269                              PYGLIB_PyUnicode_FromString(PyModule_GetName(module)));
270
271     g_type_set_qdata(gtype, pygenum_class_key, stub);
272
273     o = pyg_type_wrapper_new(gtype);
274     PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o);
275     Py_DECREF(o);
276
277     if (module) {
278         /* Add it to the module name space */
279         PyModule_AddObject(module, (char*)typename, stub);
280         Py_INCREF(stub);
281     }
282
283     /* Register enum values */
284     eclass = G_ENUM_CLASS(g_type_class_ref(gtype));
285
286     values = PyDict_New();
287     for (i = 0; i < eclass->n_values; i++) {
288         PyObject *item, *intval;
289       
290         intval = PYGLIB_PyLong_FromLong(eclass->values[i].value);
291         item = pyg_enum_val_new(stub, gtype, intval);
292         PyDict_SetItem(values, intval, item);
293         Py_DECREF(intval);
294
295         if (module) {
296             char *prefix;
297
298             prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix));
299             PyModule_AddObject(module, prefix, item);
300             g_free(prefix);
301
302             Py_INCREF(item);
303         }
304     }
305
306     PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
307                          "__enum_values__", values);
308     Py_DECREF(values);
309
310     g_type_class_unref(eclass);
311
312     pyglib_gil_state_release(state);
313     return stub;
314 }
315
316 static PyObject *
317 pyg_enum_reduce(PyObject *self, PyObject *args)
318 {
319     if (!PyArg_ParseTuple(args, ":GEnum.__reduce__"))
320         return NULL;
321
322     return Py_BuildValue("(O(i)O)", Py_TYPE(self), PYGLIB_PyLong_AsLong(self),
323                          PyObject_GetAttrString(self, "__dict__"));
324 }
325
326 static PyObject *
327 pyg_enum_get_value_name(PyGEnum *self, void *closure)
328 {
329   GEnumClass *enum_class;
330   GEnumValue *enum_value;
331   PyObject *retval;
332
333   enum_class = g_type_class_ref(self->gtype);
334   g_assert(G_IS_ENUM_CLASS(enum_class));
335
336   enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self));
337
338   retval = PYGLIB_PyUnicode_FromString(enum_value->value_name);
339   g_type_class_unref(enum_class);
340
341   return retval;
342 }
343
344 static PyObject *
345 pyg_enum_get_value_nick(PyGEnum *self, void *closure)
346 {
347   GEnumClass *enum_class;
348   GEnumValue *enum_value;
349   PyObject *retval;
350
351   enum_class = g_type_class_ref(self->gtype);
352   g_assert(G_IS_ENUM_CLASS(enum_class));
353
354   enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self));
355
356   retval = PYGLIB_PyUnicode_FromString(enum_value->value_nick);
357   g_type_class_unref(enum_class);
358
359   return retval;
360 }
361
362
363 static PyMethodDef pyg_enum_methods[] = {
364     { "__reduce__", (PyCFunction)pyg_enum_reduce, METH_VARARGS },
365     { NULL, NULL, 0 }
366 };
367
368 static PyGetSetDef pyg_enum_getsets[] = {
369     { "value_name", (getter)pyg_enum_get_value_name, (setter)0 },
370     { "value_nick", (getter)pyg_enum_get_value_nick, (setter)0 },
371     { NULL, 0, 0 }
372 };
373
374 void
375 pygobject_enum_register_types(PyObject *d)
376 {
377     pygenum_class_key        = g_quark_from_static_string("PyGEnum::class");
378
379     PyGEnum_Type.tp_base = &PYGLIB_PyLong_Type;
380 #if PY_VERSION_HEX < 0x03000000
381     PyGEnum_Type.tp_new = pyg_enum_new;
382 #else
383     PyGEnum_Type.tp_new = PyLong_Type.tp_new;
384     PyGEnum_Type.tp_hash = PyLong_Type.tp_hash;
385 #endif
386     PyGEnum_Type.tp_repr = (reprfunc)pyg_enum_repr;
387     PyGEnum_Type.tp_str = (reprfunc)pyg_enum_repr;
388     PyGEnum_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
389     PyGEnum_Type.tp_richcompare = (richcmpfunc)pyg_enum_richcompare;
390     PyGEnum_Type.tp_methods = pyg_enum_methods;
391     PyGEnum_Type.tp_getset = pyg_enum_getsets;
392     PYGOBJECT_REGISTER_GTYPE(d, PyGEnum_Type, "GEnum", G_TYPE_ENUM);
393 }