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/>.
24 #include "pygi-python-compat.h"
25 #include "pygi-type.h"
26 #include "pygi-util.h"
27 #include "pygi-type.h"
28 #include "pygi-basictype.h"
32 GQuark pygenum_class_key
;
34 PYGLIB_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type
, PyGEnum
);
37 pyg_enum_val_new(PyObject
* subclass
, GType gtype
, PyObject
*intval
)
39 PyObject
*args
, *item
;
40 args
= Py_BuildValue("(O)", intval
);
41 item
= (&PYGLIB_PyLong_Type
)->tp_new((PyTypeObject
*)subclass
, args
, NULL
);
45 ((PyGEnum
*)item
)->gtype
= gtype
;
51 pyg_enum_richcompare(PyGEnum
*self
, PyObject
*other
, int op
)
53 static char warning
[256];
55 if (!PYGLIB_PyLong_Check(other
)) {
56 Py_INCREF(Py_NotImplemented
);
57 return Py_NotImplemented
;
60 if (PyObject_TypeCheck(other
, &PyGEnum_Type
) && ((PyGEnum
*)other
)->gtype
!= self
->gtype
) {
61 g_snprintf(warning
, sizeof(warning
), "comparing different enum types: %s and %s",
62 g_type_name(self
->gtype
), g_type_name(((PyGEnum
*)other
)->gtype
));
63 if (PyErr_Warn(PyExc_Warning
, warning
))
67 return pyg_integer_richcompare((PyObject
*)self
, other
, op
);
71 pyg_enum_repr(PyGEnum
*self
)
74 GEnumClass
*enum_class
;
77 char *namespace, *module_str
;
81 module
= PyObject_GetAttrString ((PyObject
*)self
, "__module__");
85 if (!PYGLIB_PyUnicode_Check (module
)) {
90 enum_class
= g_type_class_ref(self
->gtype
);
91 g_assert(G_IS_ENUM_CLASS(enum_class
));
93 l
= PYGLIB_PyLong_AS_LONG(self
);
94 for (index
= 0; index
< enum_class
->n_values
; index
++)
95 if (l
== enum_class
->values
[index
].value
)
98 module_str
= PYGLIB_PyUnicode_AsString (module
);
99 namespace = g_strrstr (module_str
, ".");
100 if (namespace == NULL
) {
101 namespace = module_str
;
106 value
= enum_class
->values
[index
].value_name
;
108 sprintf(tmp
, "<enum %s of type %s.%s>", value
,
109 namespace, Py_TYPE (self
)->tp_name
);
111 sprintf(tmp
, "<enum %ld of type %s.%s>", PYGLIB_PyLong_AS_LONG(self
),
112 namespace, Py_TYPE (self
)->tp_name
);
114 g_type_class_unref(enum_class
);
116 return PYGLIB_PyUnicode_FromString(tmp
);
120 pyg_enum_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
122 static char *kwlist
[] = { "value", NULL
};
124 PyObject
*pytc
, *values
, *ret
, *intvalue
;
128 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "l", kwlist
, &value
))
131 pytc
= PyObject_GetAttrString((PyObject
*)type
, "__gtype__");
135 if (!PyObject_TypeCheck(pytc
, &PyGTypeWrapper_Type
)) {
137 PyErr_SetString(PyExc_TypeError
,
138 "__gtype__ attribute not a typecode");
142 gtype
= pyg_type_from_object(pytc
);
145 eclass
= G_ENUM_CLASS(g_type_class_ref(gtype
));
147 /* A check that 0 < value < eclass->n_values was here but got
148 * removed: enumeration values do not need to be consequitive,
149 * e.g. GtkPathPriorityType values are not.
152 values
= PyObject_GetAttrString((PyObject
*)type
, "__enum_values__");
154 g_type_class_unref(eclass
);
158 /* Note that size of __enum_values__ dictionary can easily be less
159 * than 'n_values'. This happens if some values of the enum are
160 * numerically equal, e.g. gtk.ANCHOR_N == gtk.ANCHOR_NORTH.
161 * Johan said that "In retrospect, using a dictionary to store the
162 * values might not have been that good", but we need to keep
163 * backward compatibility.
165 if (!PyDict_Check(values
) || (gsize
)PyDict_Size(values
) > eclass
->n_values
) {
166 PyErr_SetString(PyExc_TypeError
, "__enum_values__ badly formed");
168 g_type_class_unref(eclass
);
172 g_type_class_unref(eclass
);
174 intvalue
= PYGLIB_PyLong_FromLong(value
);
175 ret
= PyDict_GetItem(values
, intvalue
);
181 PyErr_Format(PyExc_ValueError
, "invalid enum value: %ld", value
);
187 pyg_enum_from_gtype (GType gtype
, int value
)
189 PyObject
*pyclass
, *values
, *retval
, *intvalue
;
191 g_return_val_if_fail(gtype
!= G_TYPE_INVALID
, NULL
);
193 /* Get a wrapper class by:
194 * 1. check for one attached to the gtype
195 * 2. lookup one in a typelib
196 * 3. creating a new one
198 pyclass
= (PyObject
*)g_type_get_qdata(gtype
, pygenum_class_key
);
200 pyclass
= pygi_type_import_by_g_type(gtype
);
202 pyclass
= pyg_enum_add(NULL
, g_type_name(gtype
), NULL
, gtype
);
204 return PYGLIB_PyLong_FromLong(value
);
206 values
= PyDict_GetItemString(((PyTypeObject
*)pyclass
)->tp_dict
,
208 intvalue
= PYGLIB_PyLong_FromLong(value
);
209 retval
= PyDict_GetItem(values
, intvalue
);
215 retval
= pyg_enum_val_new(pyclass
, gtype
, intvalue
);
224 * Dynamically create a class derived from PyGEnum based on the given GType.
227 pyg_enum_add (PyObject
* module
,
228 const char * typename
,
229 const char * strip_prefix
,
232 PyGILState_STATE state
;
233 PyObject
*instance_dict
, *stub
, *values
, *o
;
237 g_return_val_if_fail(typename
!= NULL
, NULL
);
238 if (!g_type_is_a (gtype
, G_TYPE_ENUM
)) {
239 PyErr_Format (PyExc_TypeError
, "Trying to register gtype '%s' as enum when in fact it is of type '%s'",
240 g_type_name (gtype
), g_type_name (G_TYPE_FUNDAMENTAL (gtype
)));
244 state
= PyGILState_Ensure();
246 /* Create a new type derived from GEnum. This is the same as:
247 * >>> stub = type(typename, (GEnum,), {})
249 instance_dict
= PyDict_New();
250 stub
= PyObject_CallFunction((PyObject
*)&PyType_Type
, "s(O)O",
251 typename
, (PyObject
*)&PyGEnum_Type
,
253 Py_DECREF(instance_dict
);
255 PyErr_SetString(PyExc_RuntimeError
, "can't create const");
256 PyGILState_Release(state
);
260 ((PyTypeObject
*)stub
)->tp_flags
&= ~Py_TPFLAGS_BASETYPE
;
263 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
,
265 PYGLIB_PyUnicode_FromString(PyModule_GetName(module
)));
267 g_type_set_qdata(gtype
, pygenum_class_key
, stub
);
269 o
= pyg_type_wrapper_new(gtype
);
270 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
, "__gtype__", o
);
274 /* Add it to the module name space */
275 PyModule_AddObject(module
, (char*)typename
, stub
);
279 /* Register enum values */
280 eclass
= G_ENUM_CLASS(g_type_class_ref(gtype
));
282 values
= PyDict_New();
283 for (i
= 0; i
< eclass
->n_values
; i
++) {
284 PyObject
*item
, *intval
;
286 intval
= PYGLIB_PyLong_FromLong(eclass
->values
[i
].value
);
287 item
= pyg_enum_val_new(stub
, gtype
, intval
);
288 PyDict_SetItem(values
, intval
, item
);
294 prefix
= g_strdup(pyg_constant_strip_prefix(eclass
->values
[i
].value_name
, strip_prefix
));
295 PyModule_AddObject(module
, prefix
, item
);
302 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
,
303 "__enum_values__", values
);
306 g_type_class_unref(eclass
);
308 PyGILState_Release(state
);
313 pyg_enum_reduce(PyObject
*self
, PyObject
*args
)
315 if (!PyArg_ParseTuple(args
, ":GEnum.__reduce__"))
318 return Py_BuildValue("(O(i)O)", Py_TYPE(self
), PYGLIB_PyLong_AsLong(self
),
319 PyObject_GetAttrString(self
, "__dict__"));
323 pyg_enum_get_value_name(PyGEnum
*self
, void *closure
)
325 GEnumClass
*enum_class
;
326 GEnumValue
*enum_value
;
330 if (!pygi_gint_from_py ((PyObject
*) self
, &intvalue
))
333 enum_class
= g_type_class_ref(self
->gtype
);
334 g_assert(G_IS_ENUM_CLASS(enum_class
));
336 enum_value
= g_enum_get_value(enum_class
, intvalue
);
338 retval
= pygi_utf8_to_py (enum_value
->value_name
);
339 g_type_class_unref(enum_class
);
345 pyg_enum_get_value_nick(PyGEnum
*self
, void *closure
)
347 GEnumClass
*enum_class
;
348 GEnumValue
*enum_value
;
352 if (!pygi_gint_from_py ((PyObject
*) self
, &intvalue
))
355 enum_class
= g_type_class_ref(self
->gtype
);
356 g_assert(G_IS_ENUM_CLASS(enum_class
));
358 enum_value
= g_enum_get_value(enum_class
, intvalue
);
360 retval
= pygi_utf8_to_py (enum_value
->value_nick
);
362 g_type_class_unref(enum_class
);
368 static PyMethodDef pyg_enum_methods
[] = {
369 { "__reduce__", (PyCFunction
)pyg_enum_reduce
, METH_VARARGS
},
373 static PyGetSetDef pyg_enum_getsets
[] = {
374 { "value_name", (getter
)pyg_enum_get_value_name
, (setter
)0 },
375 { "value_nick", (getter
)pyg_enum_get_value_nick
, (setter
)0 },
380 * Returns 0 on success, or -1 and sets an exception.
383 pygi_enum_register_types(PyObject
*d
)
385 pygenum_class_key
= g_quark_from_static_string("PyGEnum::class");
387 PyGEnum_Type
.tp_base
= &PYGLIB_PyLong_Type
;
388 PyGEnum_Type
.tp_new
= pyg_enum_new
;
389 PyGEnum_Type
.tp_hash
= PYGLIB_PyLong_Type
.tp_hash
;
390 PyGEnum_Type
.tp_repr
= (reprfunc
)pyg_enum_repr
;
391 PyGEnum_Type
.tp_str
= (reprfunc
)pyg_enum_repr
;
392 PyGEnum_Type
.tp_flags
= Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
;
393 PyGEnum_Type
.tp_richcompare
= (richcmpfunc
)pyg_enum_richcompare
;
394 PyGEnum_Type
.tp_methods
= pyg_enum_methods
;
395 PyGEnum_Type
.tp_getset
= pyg_enum_getsets
;
396 PYGOBJECT_REGISTER_GTYPE(d
, PyGEnum_Type
, "GEnum", G_TYPE_ENUM
);