Add sphinx based documentation
[pygobject.git] / gi / pygflags.c
blobfa12341fece5b9cb06feeeb07dd7db7ae48fa152
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, see <http://www.gnu.org/licenses/>.
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
26 #include <pyglib.h>
27 #include "pygi-type.h"
28 #include "pygi-util.h"
29 #include "pygtype.h"
30 #include "pygflags.h"
31 #include "pygboxed.h"
33 GQuark pygflags_class_key;
35 PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags);
37 static PyObject *
38 pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval)
40 PyObject *args, *item;
41 args = Py_BuildValue("(O)", intval);
42 g_assert(PyObject_IsSubclass(subclass, (PyObject*) &PyGFlags_Type));
43 item = PYGLIB_PyLong_Type.tp_new((PyTypeObject*)subclass, args, NULL);
44 Py_DECREF(args);
45 if (!item)
46 return NULL;
47 ((PyGFlags*)item)->gtype = gtype;
49 return item;
52 static PyObject *
53 pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op)
55 static char warning[256];
57 if (!PYGLIB_PyLong_Check(other)) {
58 Py_INCREF(Py_NotImplemented);
59 return Py_NotImplemented;
62 if (PyObject_TypeCheck(other, &PyGFlags_Type) && ((PyGFlags*)other)->gtype != self->gtype) {
63 g_snprintf(warning, sizeof(warning), "comparing different flags types: %s and %s",
64 g_type_name(self->gtype), g_type_name(((PyGFlags*)other)->gtype));
65 if (PyErr_Warn(PyExc_Warning, warning))
66 return NULL;
69 return pyg_integer_richcompare((PyObject *)self, other, op);
72 static char *
73 generate_repr(GType gtype, guint value)
75 GFlagsClass *flags_class;
76 char *retval = NULL, *tmp;
77 guint i;
79 flags_class = g_type_class_ref(gtype);
80 g_assert(G_IS_FLAGS_CLASS(flags_class));
82 for (i = 0; i < flags_class->n_values; i++) {
83 /* Some types (eg GstElementState in GStreamer 0.8) has flags with 0 values,
84 * we're just ignore them for now otherwise they'll always show up
86 if (flags_class->values[i].value == 0)
87 continue;
89 if ((value & flags_class->values[i].value) == flags_class->values[i].value) {
90 if (retval) {
91 tmp = g_strdup_printf("%s | %s", retval, flags_class->values[i].value_name);
92 g_free(retval);
93 retval = tmp;
94 } else {
95 retval = g_strdup_printf("%s", flags_class->values[i].value_name);
100 g_type_class_unref(flags_class);
102 return retval;
105 static PyObject *
106 pyg_flags_repr(PyGFlags *self)
108 char *tmp, *retval, *module_str, *namespace;
109 PyObject *pyretval, *module;
111 tmp = generate_repr(self->gtype, PYGLIB_PyLong_AsUnsignedLong(self));
113 module = PyObject_GetAttrString ((PyObject *)self, "__module__");
114 if (module == NULL)
115 return NULL;
117 if (!PYGLIB_PyUnicode_Check (module)) {
118 Py_DECREF (module);
119 return NULL;
122 module_str = PYGLIB_PyUnicode_AsString (module);
123 namespace = g_strrstr (module_str, ".");
124 if (namespace == NULL) {
125 namespace = module_str;
126 } else {
127 namespace += 1;
130 if (tmp)
131 retval = g_strdup_printf("<flags %s of type %s.%s>", tmp,
132 namespace, Py_TYPE (self)->tp_name);
133 else
134 retval = g_strdup_printf("<flags %ld of type %s.%s>",
135 PYGLIB_PyLong_AsUnsignedLong (self),
136 namespace, Py_TYPE (self)->tp_name);
137 g_free(tmp);
138 Py_DECREF (module);
140 pyretval = PYGLIB_PyUnicode_FromString(retval);
141 g_free(retval);
143 return pyretval;
146 static PyObject *
147 pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
149 static char *kwlist[] = { "value", NULL };
150 gulong value;
151 PyObject *pytc, *values, *ret, *pyint;
152 GType gtype;
153 GFlagsClass *eclass;
155 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k", kwlist, &value))
156 return NULL;
158 pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__");
159 if (!pytc)
160 return NULL;
162 if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) {
163 Py_DECREF(pytc);
164 PyErr_SetString(PyExc_TypeError,
165 "__gtype__ attribute not a typecode");
166 return NULL;
169 gtype = pyg_type_from_object(pytc);
170 Py_DECREF(pytc);
172 eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
174 values = PyObject_GetAttrString((PyObject *)type, "__flags_values__");
175 if (!values) {
176 g_type_class_unref(eclass);
177 return NULL;
180 if (!PyDict_Check(values)) {
181 PyErr_SetString(PyExc_TypeError, "__flags_values__ badly formed");
182 Py_DECREF(values);
183 g_type_class_unref(eclass);
184 return NULL;
187 g_type_class_unref(eclass);
189 pyint = PYGLIB_PyLong_FromUnsignedLong(value);
190 ret = PyDict_GetItem(values, pyint);
191 if (!ret) {
192 PyErr_Clear();
194 ret = pyg_flags_val_new((PyObject *)type, gtype, pyint);
195 g_assert(ret != NULL);
196 } else {
197 Py_INCREF(ret);
200 Py_DECREF(pyint);
201 Py_DECREF(values);
203 return ret;
206 PyObject*
207 pyg_flags_from_gtype (GType gtype, guint value)
209 PyObject *pyclass, *values, *retval, *pyint;
211 if (PyErr_Occurred())
212 return PYGLIB_PyLong_FromUnsignedLong(0);
214 g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL);
216 /* Get a wrapper class by:
217 * 1. check for one attached to the gtype
218 * 2. lookup one in a typelib
219 * 3. creating a new one
221 pyclass = (PyObject*)g_type_get_qdata(gtype, pygflags_class_key);
222 if (!pyclass)
223 pyclass = pygi_type_import_by_g_type(gtype);
224 if (!pyclass)
225 pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype);
226 if (!pyclass)
227 return PYGLIB_PyLong_FromUnsignedLong(value);
229 values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict,
230 "__flags_values__");
231 pyint = PYGLIB_PyLong_FromUnsignedLong(value);
232 retval = PyDict_GetItem(values, pyint);
233 if (!retval) {
234 PyErr_Clear();
236 retval = pyg_flags_val_new(pyclass, gtype, pyint);
237 g_assert(retval != NULL);
238 } else {
239 Py_INCREF(retval);
241 Py_DECREF(pyint);
243 return retval;
247 * pyg_flags_add
248 * Dynamically create a class derived from PyGFlags based on the given GType.
250 PyObject *
251 pyg_flags_add (PyObject * module,
252 const char * typename,
253 const char * strip_prefix,
254 GType gtype)
256 PyGILState_STATE state;
257 PyObject *instance_dict, *stub, *values, *o;
258 GFlagsClass *eclass;
259 guint i;
261 g_return_val_if_fail(typename != NULL, NULL);
262 if (!g_type_is_a(gtype, G_TYPE_FLAGS)) {
263 g_warning("Trying to register gtype '%s' as flags when in fact it is of type '%s'",
264 g_type_name(gtype), g_type_name(G_TYPE_FUNDAMENTAL(gtype)));
265 return NULL;
268 state = PyGILState_Ensure();
270 /* Create a new type derived from GFlags. This is the same as:
271 * >>> stub = type(typename, (GFlags,), {})
273 instance_dict = PyDict_New();
274 stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O",
275 typename, (PyObject *)&PyGFlags_Type,
276 instance_dict);
277 Py_DECREF(instance_dict);
278 if (!stub) {
279 PyErr_SetString(PyExc_RuntimeError, "can't create GFlags subtype");
280 PyGILState_Release(state);
281 return NULL;
284 ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE;
285 ((PyTypeObject *)stub)->tp_new = pyg_flags_new;
287 if (module) {
288 PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
289 "__module__",
290 PYGLIB_PyUnicode_FromString(PyModule_GetName(module)));
292 /* Add it to the module name space */
293 PyModule_AddObject(module, (char*)typename, stub);
294 Py_INCREF(stub);
296 g_type_set_qdata(gtype, pygflags_class_key, stub);
298 o = pyg_type_wrapper_new(gtype);
299 PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o);
300 Py_DECREF(o);
302 /* Register flag values */
303 eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
305 values = PyDict_New();
306 for (i = 0; i < eclass->n_values; i++) {
307 PyObject *item, *intval;
309 intval = PYGLIB_PyLong_FromUnsignedLong(eclass->values[i].value);
310 g_assert(PyErr_Occurred() == NULL);
311 item = pyg_flags_val_new(stub, gtype, intval);
312 PyDict_SetItem(values, intval, item);
313 Py_DECREF(intval);
315 if (module) {
316 char *prefix;
318 prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix));
319 Py_INCREF(item);
320 PyModule_AddObject(module, prefix, item);
321 g_free(prefix);
323 Py_DECREF(item);
326 PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
327 "__flags_values__", values);
328 Py_DECREF(values);
330 g_type_class_unref(eclass);
332 PyGILState_Release(state);
334 return stub;
337 static PyObject *
338 pyg_flags_and(PyGFlags *a, PyGFlags *b)
340 if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
341 return PYGLIB_PyLong_Type.tp_as_number->nb_and((PyObject*)a,
342 (PyObject*)b);
344 return pyg_flags_from_gtype(a->gtype,
345 PYGLIB_PyLong_AsUnsignedLong(a) & PYGLIB_PyLong_AsUnsignedLong(b));
348 static PyObject *
349 pyg_flags_or(PyGFlags *a, PyGFlags *b)
351 if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
352 return PYGLIB_PyLong_Type.tp_as_number->nb_or((PyObject*)a,
353 (PyObject*)b);
355 return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AsUnsignedLong(a) | PYGLIB_PyLong_AsUnsignedLong(b));
358 static PyObject *
359 pyg_flags_xor(PyGFlags *a, PyGFlags *b)
361 if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
362 return PYGLIB_PyLong_Type.tp_as_number->nb_xor((PyObject*)a,
363 (PyObject*)b);
365 return pyg_flags_from_gtype(a->gtype,
366 PYGLIB_PyLong_AsUnsignedLong(a) ^ PYGLIB_PyLong_AsUnsignedLong(b));
370 static PyObject *
371 pyg_flags_warn (PyObject *self, PyObject *args)
373 if (PyErr_Warn(PyExc_Warning, "unsupported arithmetic operation for flags type"))
374 return NULL;
376 Py_INCREF(Py_None);
377 return Py_None;
380 static PyObject *
381 pyg_flags_get_first_value_name(PyGFlags *self, void *closure)
383 GFlagsClass *flags_class;
384 GFlagsValue *flags_value;
385 PyObject *retval;
387 flags_class = g_type_class_ref(self->gtype);
388 g_assert(G_IS_FLAGS_CLASS(flags_class));
389 flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self));
390 if (flags_value)
391 retval = PYGLIB_PyUnicode_FromString(flags_value->value_name);
392 else {
393 retval = Py_None;
394 Py_INCREF(Py_None);
396 g_type_class_unref(flags_class);
398 return retval;
401 static PyObject *
402 pyg_flags_get_first_value_nick(PyGFlags *self, void *closure)
404 GFlagsClass *flags_class;
405 GFlagsValue *flags_value;
406 PyObject *retval;
408 flags_class = g_type_class_ref(self->gtype);
409 g_assert(G_IS_FLAGS_CLASS(flags_class));
411 flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self));
412 if (flags_value)
413 retval = PYGLIB_PyUnicode_FromString(flags_value->value_nick);
414 else {
415 retval = Py_None;
416 Py_INCREF(Py_None);
418 g_type_class_unref(flags_class);
420 return retval;
423 static PyObject *
424 pyg_flags_get_value_names(PyGFlags *self, void *closure)
426 GFlagsClass *flags_class;
427 PyObject *retval;
428 guint i;
430 flags_class = g_type_class_ref(self->gtype);
431 g_assert(G_IS_FLAGS_CLASS(flags_class));
433 retval = PyList_New(0);
434 for (i = 0; i < flags_class->n_values; i++)
435 if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value)
436 PyList_Append(retval, PYGLIB_PyUnicode_FromString(flags_class->values[i].value_name));
438 g_type_class_unref(flags_class);
440 return retval;
443 static PyObject *
444 pyg_flags_get_value_nicks(PyGFlags *self, void *closure)
446 GFlagsClass *flags_class;
447 PyObject *retval;
448 guint i;
450 flags_class = g_type_class_ref(self->gtype);
451 g_assert(G_IS_FLAGS_CLASS(flags_class));
453 retval = PyList_New(0);
454 for (i = 0; i < flags_class->n_values; i++)
455 if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value) {
456 PyObject *py_nick = PYGLIB_PyUnicode_FromString(flags_class->values[i].value_nick);
457 PyList_Append(retval, py_nick);
458 Py_DECREF (py_nick);
461 g_type_class_unref(flags_class);
463 return retval;
466 static PyGetSetDef pyg_flags_getsets[] = {
467 { "first_value_name", (getter)pyg_flags_get_first_value_name, (setter)0 },
468 { "first_value_nick", (getter)pyg_flags_get_first_value_nick, (setter)0 },
469 { "value_names", (getter)pyg_flags_get_value_names, (setter)0 },
470 { "value_nicks", (getter)pyg_flags_get_value_nicks, (setter)0 },
471 { NULL, 0, 0 }
474 static PyNumberMethods pyg_flags_as_number = {
475 (binaryfunc)pyg_flags_warn, /* nb_add */
476 (binaryfunc)pyg_flags_warn, /* nb_subtract */
477 (binaryfunc)pyg_flags_warn, /* nb_multiply */
478 (binaryfunc)pyg_flags_warn, /* nb_divide */
479 (binaryfunc)pyg_flags_warn, /* nb_remainder */
480 #if PY_VERSION_HEX < 0x03000000
481 (binaryfunc)pyg_flags_warn, /* nb_divmod */
482 #endif
483 (ternaryfunc)pyg_flags_warn, /* nb_power */
484 0, /* nb_negative */
485 0, /* nb_positive */
486 0, /* nb_absolute */
487 0, /* nb_nonzero */
488 0, /* nb_invert */
489 0, /* nb_lshift */
490 0, /* nb_rshift */
491 (binaryfunc)pyg_flags_and, /* nb_and */
492 (binaryfunc)pyg_flags_xor, /* nb_xor */
493 (binaryfunc)pyg_flags_or, /* nb_or */
496 void
497 pygobject_flags_register_types(PyObject *d)
499 pygflags_class_key = g_quark_from_static_string("PyGFlags::class");
501 PyGFlags_Type.tp_base = &PYGLIB_PyLong_Type;
502 #if PY_VERSION_HEX < 0x03000000
503 PyGFlags_Type.tp_new = pyg_flags_new;
504 #else
505 PyGFlags_Type.tp_new = PyLong_Type.tp_new;
506 PyGFlags_Type.tp_hash = PyLong_Type.tp_hash;
507 #endif
508 PyGFlags_Type.tp_repr = (reprfunc)pyg_flags_repr;
509 PyGFlags_Type.tp_as_number = &pyg_flags_as_number;
510 PyGFlags_Type.tp_str = (reprfunc)pyg_flags_repr;
511 PyGFlags_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
512 PyGFlags_Type.tp_richcompare = (richcmpfunc)pyg_flags_richcompare;
513 PyGFlags_Type.tp_getset = pyg_flags_getsets;
514 PYGOBJECT_REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS);