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/>.
27 #include "pygi-type.h"
28 #include "pygi-util.h"
33 GQuark pygflags_class_key
;
35 PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type
, PyGFlags
);
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
);
47 ((PyGFlags
*)item
)->gtype
= gtype
;
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
))
69 return pyg_integer_richcompare((PyObject
*)self
, other
, op
);
73 generate_repr(GType gtype
, guint value
)
75 GFlagsClass
*flags_class
;
76 char *retval
= NULL
, *tmp
;
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)
89 if ((value
& flags_class
->values
[i
].value
) == flags_class
->values
[i
].value
) {
91 tmp
= g_strdup_printf("%s | %s", retval
, flags_class
->values
[i
].value_name
);
95 retval
= g_strdup_printf("%s", flags_class
->values
[i
].value_name
);
100 g_type_class_unref(flags_class
);
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__");
117 if (!PYGLIB_PyUnicode_Check (module
)) {
122 module_str
= PYGLIB_PyUnicode_AsString (module
);
123 namespace = g_strrstr (module_str
, ".");
124 if (namespace == NULL
) {
125 namespace = module_str
;
131 retval
= g_strdup_printf("<flags %s of type %s.%s>", tmp
,
132 namespace, Py_TYPE (self
)->tp_name
);
134 retval
= g_strdup_printf("<flags %ld of type %s.%s>",
135 PYGLIB_PyLong_AsUnsignedLong (self
),
136 namespace, Py_TYPE (self
)->tp_name
);
140 pyretval
= PYGLIB_PyUnicode_FromString(retval
);
147 pyg_flags_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
149 static char *kwlist
[] = { "value", NULL
};
151 PyObject
*pytc
, *values
, *ret
, *pyint
;
155 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "k", kwlist
, &value
))
158 pytc
= PyObject_GetAttrString((PyObject
*)type
, "__gtype__");
162 if (!PyObject_TypeCheck(pytc
, &PyGTypeWrapper_Type
)) {
164 PyErr_SetString(PyExc_TypeError
,
165 "__gtype__ attribute not a typecode");
169 gtype
= pyg_type_from_object(pytc
);
172 eclass
= G_FLAGS_CLASS(g_type_class_ref(gtype
));
174 values
= PyObject_GetAttrString((PyObject
*)type
, "__flags_values__");
176 g_type_class_unref(eclass
);
180 if (!PyDict_Check(values
)) {
181 PyErr_SetString(PyExc_TypeError
, "__flags_values__ badly formed");
183 g_type_class_unref(eclass
);
187 g_type_class_unref(eclass
);
189 pyint
= PYGLIB_PyLong_FromUnsignedLong(value
);
190 ret
= PyDict_GetItem(values
, pyint
);
194 ret
= pyg_flags_val_new((PyObject
*)type
, gtype
, pyint
);
195 g_assert(ret
!= NULL
);
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
);
223 pyclass
= pygi_type_import_by_g_type(gtype
);
225 pyclass
= pyg_flags_add(NULL
, g_type_name(gtype
), NULL
, gtype
);
227 return PYGLIB_PyLong_FromUnsignedLong(value
);
229 values
= PyDict_GetItemString(((PyTypeObject
*)pyclass
)->tp_dict
,
231 pyint
= PYGLIB_PyLong_FromUnsignedLong(value
);
232 retval
= PyDict_GetItem(values
, pyint
);
236 retval
= pyg_flags_val_new(pyclass
, gtype
, pyint
);
237 g_assert(retval
!= NULL
);
248 * Dynamically create a class derived from PyGFlags based on the given GType.
251 pyg_flags_add (PyObject
* module
,
252 const char * typename
,
253 const char * strip_prefix
,
256 PyGILState_STATE state
;
257 PyObject
*instance_dict
, *stub
, *values
, *o
;
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
)));
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
,
277 Py_DECREF(instance_dict
);
279 PyErr_SetString(PyExc_RuntimeError
, "can't create GFlags subtype");
280 PyGILState_Release(state
);
284 ((PyTypeObject
*)stub
)->tp_flags
&= ~Py_TPFLAGS_BASETYPE
;
285 ((PyTypeObject
*)stub
)->tp_new
= pyg_flags_new
;
288 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
,
290 PYGLIB_PyUnicode_FromString(PyModule_GetName(module
)));
292 /* Add it to the module name space */
293 PyModule_AddObject(module
, (char*)typename
, 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
);
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
);
318 prefix
= g_strdup(pyg_constant_strip_prefix(eclass
->values
[i
].value_name
, strip_prefix
));
320 PyModule_AddObject(module
, prefix
, item
);
326 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
,
327 "__flags_values__", values
);
330 g_type_class_unref(eclass
);
332 PyGILState_Release(state
);
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
,
344 return pyg_flags_from_gtype(a
->gtype
,
345 PYGLIB_PyLong_AsUnsignedLong(a
) & PYGLIB_PyLong_AsUnsignedLong(b
));
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
,
355 return pyg_flags_from_gtype(a
->gtype
, PYGLIB_PyLong_AsUnsignedLong(a
) | PYGLIB_PyLong_AsUnsignedLong(b
));
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
,
365 return pyg_flags_from_gtype(a
->gtype
,
366 PYGLIB_PyLong_AsUnsignedLong(a
) ^ PYGLIB_PyLong_AsUnsignedLong(b
));
371 pyg_flags_warn (PyObject
*self
, PyObject
*args
)
373 if (PyErr_Warn(PyExc_Warning
, "unsupported arithmetic operation for flags type"))
381 pyg_flags_get_first_value_name(PyGFlags
*self
, void *closure
)
383 GFlagsClass
*flags_class
;
384 GFlagsValue
*flags_value
;
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
));
391 retval
= PYGLIB_PyUnicode_FromString(flags_value
->value_name
);
396 g_type_class_unref(flags_class
);
402 pyg_flags_get_first_value_nick(PyGFlags
*self
, void *closure
)
404 GFlagsClass
*flags_class
;
405 GFlagsValue
*flags_value
;
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
));
413 retval
= PYGLIB_PyUnicode_FromString(flags_value
->value_nick
);
418 g_type_class_unref(flags_class
);
424 pyg_flags_get_value_names(PyGFlags
*self
, void *closure
)
426 GFlagsClass
*flags_class
;
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
);
444 pyg_flags_get_value_nicks(PyGFlags
*self
, void *closure
)
446 GFlagsClass
*flags_class
;
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
);
461 g_type_class_unref(flags_class
);
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 },
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 */
483 (ternaryfunc
)pyg_flags_warn
, /* nb_power */
491 (binaryfunc
)pyg_flags_and
, /* nb_and */
492 (binaryfunc
)pyg_flags_xor
, /* nb_xor */
493 (binaryfunc
)pyg_flags_or
, /* nb_or */
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
;
505 PyGFlags_Type
.tp_new
= PyLong_Type
.tp_new
;
506 PyGFlags_Type
.tp_hash
= PyLong_Type
.tp_hash
;
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
);