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/>.
27 #include "pyglib-python-compat.h"
28 #include "pygobject-private.h"
29 #include "pygi-type.h"
33 GQuark pygenum_class_key
;
35 PYGLIB_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type
, PyGEnum
);
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
);
46 ((PyGEnum
*)item
)->gtype
= gtype
;
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
))
68 return pyg_integer_richcompare((PyObject
*)self
, other
, op
);
72 pyg_enum_repr(PyGEnum
*self
)
75 GEnumClass
*enum_class
;
78 char *namespace, *module_str
;
82 module
= PyObject_GetAttrString ((PyObject
*)self
, "__module__");
86 if (!PYGLIB_PyUnicode_Check (module
)) {
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
)
99 module_str
= PYGLIB_PyUnicode_AsString (module
);
100 namespace = g_strrstr (module_str
, ".");
101 if (namespace == NULL
) {
102 namespace = module_str
;
107 value
= enum_class
->values
[index
].value_name
;
109 sprintf(tmp
, "<enum %s of type %s.%s>", value
,
110 namespace, Py_TYPE (self
)->tp_name
);
112 sprintf(tmp
, "<enum %ld of type %s.%s>", PYGLIB_PyLong_AS_LONG(self
),
113 namespace, Py_TYPE (self
)->tp_name
);
115 g_type_class_unref(enum_class
);
117 return PYGLIB_PyUnicode_FromString(tmp
);
121 pyg_enum_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
123 static char *kwlist
[] = { "value", NULL
};
125 PyObject
*pytc
, *values
, *ret
, *intvalue
;
129 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "l", kwlist
, &value
))
132 pytc
= PyObject_GetAttrString((PyObject
*)type
, "__gtype__");
136 if (!PyObject_TypeCheck(pytc
, &PyGTypeWrapper_Type
)) {
138 PyErr_SetString(PyExc_TypeError
,
139 "__gtype__ attribute not a typecode");
143 gtype
= pyg_type_from_object(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__");
155 g_type_class_unref(eclass
);
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");
169 g_type_class_unref(eclass
);
173 g_type_class_unref(eclass
);
175 intvalue
= PYGLIB_PyLong_FromLong(value
);
176 ret
= PyDict_GetItem(values
, intvalue
);
182 PyErr_Format(PyExc_ValueError
, "invalid enum value: %ld", value
);
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
);
201 pyclass
= pygi_type_import_by_g_type(gtype
);
203 pyclass
= pyg_enum_add(NULL
, g_type_name(gtype
), NULL
, gtype
);
205 return PYGLIB_PyLong_FromLong(value
);
207 values
= PyDict_GetItemString(((PyTypeObject
*)pyclass
)->tp_dict
,
209 intvalue
= PYGLIB_PyLong_FromLong(value
);
210 retval
= PyDict_GetItem(values
, intvalue
);
216 retval
= pyg_enum_val_new(pyclass
, gtype
, intvalue
);
225 * Dynamically create a class derived from PyGEnum based on the given GType.
228 pyg_enum_add (PyObject
* module
,
229 const char * typename
,
230 const char * strip_prefix
,
233 PyGILState_STATE state
;
234 PyObject
*instance_dict
, *stub
, *values
, *o
;
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
)));
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
,
254 Py_DECREF(instance_dict
);
256 PyErr_SetString(PyExc_RuntimeError
, "can't create const");
257 pyglib_gil_state_release(state
);
261 ((PyTypeObject
*)stub
)->tp_flags
&= ~Py_TPFLAGS_BASETYPE
;
262 ((PyTypeObject
*)stub
)->tp_new
= pyg_enum_new
;
265 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
,
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
);
276 /* Add it to the module name space */
277 PyModule_AddObject(module
, (char*)typename
, 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
);
296 prefix
= g_strdup(pyg_constant_strip_prefix(eclass
->values
[i
].value_name
, strip_prefix
));
297 PyModule_AddObject(module
, prefix
, item
);
304 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
,
305 "__enum_values__", values
);
308 g_type_class_unref(eclass
);
310 pyglib_gil_state_release(state
);
315 pyg_enum_reduce(PyObject
*self
, PyObject
*args
)
317 if (!PyArg_ParseTuple(args
, ":GEnum.__reduce__"))
320 return Py_BuildValue("(O(i)O)", Py_TYPE(self
), PYGLIB_PyLong_AsLong(self
),
321 PyObject_GetAttrString(self
, "__dict__"));
325 pyg_enum_get_value_name(PyGEnum
*self
, void *closure
)
327 GEnumClass
*enum_class
;
328 GEnumValue
*enum_value
;
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
);
343 pyg_enum_get_value_nick(PyGEnum
*self
, void *closure
)
345 GEnumClass
*enum_class
;
346 GEnumValue
*enum_value
;
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
);
361 static PyMethodDef pyg_enum_methods
[] = {
362 { "__reduce__", (PyCFunction
)pyg_enum_reduce
, METH_VARARGS
},
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 },
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
;
381 PyGEnum_Type
.tp_new
= PyLong_Type
.tp_new
;
382 PyGEnum_Type
.tp_hash
= PyLong_Type
.tp_hash
;
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
);