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 * pygflags.c: GFlags 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, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
29 #include "pygobject-private.h"
34 GQuark pygflags_class_key;
36 PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags);
39 pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval)
41 PyObject *args, *item;
42 args = Py_BuildValue("(O)", intval);
43 g_assert(PyObject_IsSubclass(subclass, (PyObject*) &PyGFlags_Type));
44 item = PYGLIB_PyLong_Type.tp_new((PyTypeObject*)subclass, args, NULL);
48 ((PyGFlags*)item)->gtype = gtype;
54 pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op)
56 static char warning[256];
58 if (!PYGLIB_PyLong_Check(other)) {
59 Py_INCREF(Py_NotImplemented);
60 return Py_NotImplemented;
63 if (PyObject_TypeCheck(other, &PyGFlags_Type) && ((PyGFlags*)other)->gtype != self->gtype) {
64 g_snprintf(warning, sizeof(warning), "comparing different flags types: %s and %s",
65 g_type_name(self->gtype), g_type_name(((PyGFlags*)other)->gtype));
66 if (PyErr_Warn(PyExc_Warning, warning))
70 return pyg_integer_richcompare((PyObject *)self, other, op);
74 generate_repr(GType gtype, guint value)
76 GFlagsClass *flags_class;
77 char *retval = NULL, *tmp;
80 flags_class = g_type_class_ref(gtype);
81 g_assert(G_IS_FLAGS_CLASS(flags_class));
83 for (i = 0; i < flags_class->n_values; i++) {
84 /* Some types (eg GstElementState in GStreamer 0.8) has flags with 0 values,
85 * we're just ignore them for now otherwise they'll always show up
87 if (flags_class->values[i].value == 0)
90 if ((value & flags_class->values[i].value) == flags_class->values[i].value) {
92 tmp = g_strdup_printf("%s | %s", retval, flags_class->values[i].value_name);
96 retval = g_strdup_printf("%s", flags_class->values[i].value_name);
101 g_type_class_unref(flags_class);
107 pyg_flags_repr(PyGFlags *self)
112 tmp = generate_repr(self->gtype, PYGLIB_PyLong_AsUnsignedLong(self));
115 retval = g_strdup_printf("<flags %s of type %s>", tmp,
116 g_type_name(self->gtype));
118 retval = g_strdup_printf("<flags %ld of type %s>", PYGLIB_PyLong_AsUnsignedLong(self),
119 g_type_name(self->gtype));
122 pyretval = PYGLIB_PyUnicode_FromString(retval);
129 pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
131 static char *kwlist[] = { "value", NULL };
133 PyObject *pytc, *values, *ret, *pyint;
137 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value))
140 pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__");
144 if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) {
146 PyErr_SetString(PyExc_TypeError,
147 "__gtype__ attribute not a typecode");
151 gtype = pyg_type_from_object(pytc);
154 eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
156 values = PyObject_GetAttrString((PyObject *)type, "__flags_values__");
158 g_type_class_unref(eclass);
162 if (!PyDict_Check(values)) {
163 PyErr_SetString(PyExc_TypeError, "__flags_values__ badly formed");
165 g_type_class_unref(eclass);
169 g_type_class_unref(eclass);
171 pyint = PYGLIB_PyLong_FromUnsignedLong(value);
172 ret = PyDict_GetItem(values, pyint);
176 ret = pyg_flags_val_new((PyObject *)type, gtype, pyint);
177 g_assert(ret != NULL);
189 pyg_flags_from_gtype (GType gtype, guint value)
191 PyObject *pyclass, *values, *retval, *pyint;
193 if (PyErr_Occurred())
194 return PYGLIB_PyLong_FromUnsignedLong(0);
196 g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL);
198 /* Get a wrapper class by:
199 * 1. check for one attached to the gtype
200 * 2. lookup one in a typelib
201 * 3. creating a new one
203 pyclass = (PyObject*)g_type_get_qdata(gtype, pygflags_class_key);
205 pyclass = pygi_type_import_by_g_type(gtype);
207 pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype);
209 return PYGLIB_PyLong_FromUnsignedLong(value);
211 values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict,
213 pyint = PYGLIB_PyLong_FromUnsignedLong(value);
214 retval = PyDict_GetItem(values, pyint);
218 retval = pyg_flags_val_new(pyclass, gtype, pyint);
219 g_assert(retval != NULL);
230 * Dynamically create a class derived from PyGFlags based on the given GType.
233 pyg_flags_add (PyObject * module,
234 const char * typename,
235 const char * strip_prefix,
238 PyGILState_STATE state;
239 PyObject *instance_dict, *stub, *values, *o;
243 g_return_val_if_fail(typename != NULL, NULL);
244 if (!g_type_is_a(gtype, G_TYPE_FLAGS)) {
245 g_warning("Trying to register gtype '%s' as flags when in fact it is of type '%s'",
246 g_type_name(gtype), g_type_name(G_TYPE_FUNDAMENTAL(gtype)));
250 state = pyglib_gil_state_ensure();
252 /* Create a new type derived from GFlags. This is the same as:
253 * >>> stub = type(typename, (GFlags,), {})
255 instance_dict = PyDict_New();
256 stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O",
257 typename, (PyObject *)&PyGFlags_Type,
259 Py_DECREF(instance_dict);
261 PyErr_SetString(PyExc_RuntimeError, "can't create GFlags subtype");
262 pyglib_gil_state_release(state);
266 ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE;
267 ((PyTypeObject *)stub)->tp_new = pyg_flags_new;
270 PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
272 PYGLIB_PyUnicode_FromString(PyModule_GetName(module)));
274 /* Add it to the module name space */
275 PyModule_AddObject(module, (char*)typename, stub);
278 g_type_set_qdata(gtype, pygflags_class_key, stub);
280 o = pyg_type_wrapper_new(gtype);
281 PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o);
284 /* Register flag values */
285 eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
287 values = PyDict_New();
288 for (i = 0; i < eclass->n_values; i++) {
289 PyObject *item, *intval;
291 intval = PYGLIB_PyLong_FromUnsignedLong(eclass->values[i].value);
292 g_assert(PyErr_Occurred() == NULL);
293 item = pyg_flags_val_new(stub, gtype, intval);
294 PyDict_SetItem(values, intval, item);
300 prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix));
302 PyModule_AddObject(module, prefix, item);
308 PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
309 "__flags_values__", values);
312 g_type_class_unref(eclass);
314 pyglib_gil_state_release(state);
320 pyg_flags_and(PyGFlags *a, PyGFlags *b)
322 if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
323 return PYGLIB_PyLong_Type.tp_as_number->nb_and((PyObject*)a,
326 return pyg_flags_from_gtype(a->gtype,
327 PYGLIB_PyLong_AsUnsignedLong(a) & PYGLIB_PyLong_AsUnsignedLong(b));
331 pyg_flags_or(PyGFlags *a, PyGFlags *b)
333 if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
334 return PYGLIB_PyLong_Type.tp_as_number->nb_or((PyObject*)a,
337 return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AsUnsignedLong(a) | PYGLIB_PyLong_AsUnsignedLong(b));
341 pyg_flags_xor(PyGFlags *a, PyGFlags *b)
343 if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
344 return PYGLIB_PyLong_Type.tp_as_number->nb_xor((PyObject*)a,
347 return pyg_flags_from_gtype(a->gtype,
348 PYGLIB_PyLong_AsUnsignedLong(a) ^ PYGLIB_PyLong_AsUnsignedLong(b));
353 pyg_flags_warn (PyObject *self, PyObject *args)
355 if (PyErr_Warn(PyExc_Warning, "unsupported arithmetic operation for flags type"))
363 pyg_flags_get_first_value_name(PyGFlags *self, void *closure)
365 GFlagsClass *flags_class;
366 GFlagsValue *flags_value;
369 flags_class = g_type_class_ref(self->gtype);
370 g_assert(G_IS_FLAGS_CLASS(flags_class));
371 flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self));
373 retval = PYGLIB_PyUnicode_FromString(flags_value->value_name);
378 g_type_class_unref(flags_class);
384 pyg_flags_get_first_value_nick(PyGFlags *self, void *closure)
386 GFlagsClass *flags_class;
387 GFlagsValue *flags_value;
390 flags_class = g_type_class_ref(self->gtype);
391 g_assert(G_IS_FLAGS_CLASS(flags_class));
393 flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self));
395 retval = PYGLIB_PyUnicode_FromString(flags_value->value_nick);
400 g_type_class_unref(flags_class);
406 pyg_flags_get_value_names(PyGFlags *self, void *closure)
408 GFlagsClass *flags_class;
412 flags_class = g_type_class_ref(self->gtype);
413 g_assert(G_IS_FLAGS_CLASS(flags_class));
415 retval = PyList_New(0);
416 for (i = 0; i < flags_class->n_values; i++)
417 if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value)
418 PyList_Append(retval, PYGLIB_PyUnicode_FromString(flags_class->values[i].value_name));
420 g_type_class_unref(flags_class);
426 pyg_flags_get_value_nicks(PyGFlags *self, void *closure)
428 GFlagsClass *flags_class;
432 flags_class = g_type_class_ref(self->gtype);
433 g_assert(G_IS_FLAGS_CLASS(flags_class));
435 retval = PyList_New(0);
436 for (i = 0; i < flags_class->n_values; i++)
437 if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value) {
438 PyObject *py_nick = PYGLIB_PyUnicode_FromString(flags_class->values[i].value_nick);
439 PyList_Append(retval, py_nick);
443 g_type_class_unref(flags_class);
448 static PyGetSetDef pyg_flags_getsets[] = {
449 { "first_value_name", (getter)pyg_flags_get_first_value_name, (setter)0 },
450 { "first_value_nick", (getter)pyg_flags_get_first_value_nick, (setter)0 },
451 { "value_names", (getter)pyg_flags_get_value_names, (setter)0 },
452 { "value_nicks", (getter)pyg_flags_get_value_nicks, (setter)0 },
456 static PyNumberMethods pyg_flags_as_number = {
457 (binaryfunc)pyg_flags_warn, /* nb_add */
458 (binaryfunc)pyg_flags_warn, /* nb_subtract */
459 (binaryfunc)pyg_flags_warn, /* nb_multiply */
460 (binaryfunc)pyg_flags_warn, /* nb_divide */
461 (binaryfunc)pyg_flags_warn, /* nb_remainder */
462 #if PY_VERSION_HEX < 0x03000000
463 (binaryfunc)pyg_flags_warn, /* nb_divmod */
465 (ternaryfunc)pyg_flags_warn, /* nb_power */
473 (binaryfunc)pyg_flags_and, /* nb_and */
474 (binaryfunc)pyg_flags_xor, /* nb_xor */
475 (binaryfunc)pyg_flags_or, /* nb_or */
479 pygobject_flags_register_types(PyObject *d)
481 pygflags_class_key = g_quark_from_static_string("PyGFlags::class");
483 PyGFlags_Type.tp_base = &PYGLIB_PyLong_Type;
484 #if PY_VERSION_HEX < 0x03000000
485 PyGFlags_Type.tp_new = pyg_flags_new;
487 PyGFlags_Type.tp_new = PyLong_Type.tp_new;
488 PyGFlags_Type.tp_hash = PyLong_Type.tp_hash;
490 PyGFlags_Type.tp_repr = (reprfunc)pyg_flags_repr;
491 PyGFlags_Type.tp_as_number = &pyg_flags_as_number;
492 PyGFlags_Type.tp_str = (reprfunc)pyg_flags_repr;
493 PyGFlags_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
494 PyGFlags_Type.tp_richcompare = (richcmpfunc)pyg_flags_richcompare;
495 PyGFlags_Type.tp_getset = pyg_flags_getsets;
496 PYGOBJECT_REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS);