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/>.
24 #include "pygi-type.h"
25 #include "pygi-util.h"
26 #include "pygi-type.h"
30 GQuark pygflags_class_key
;
32 PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type
, PyGFlags
);
35 pyg_flags_val_new(PyObject
* subclass
, GType gtype
, PyObject
*intval
)
37 PyObject
*args
, *item
;
38 args
= Py_BuildValue("(O)", intval
);
39 g_assert(PyObject_IsSubclass(subclass
, (PyObject
*) &PyGFlags_Type
));
40 item
= PYGLIB_PyLong_Type
.tp_new((PyTypeObject
*)subclass
, args
, NULL
);
44 ((PyGFlags
*)item
)->gtype
= gtype
;
50 pyg_flags_richcompare(PyGFlags
*self
, PyObject
*other
, int op
)
52 static char warning
[256];
54 if (!PYGLIB_PyLong_Check(other
)) {
55 Py_INCREF(Py_NotImplemented
);
56 return Py_NotImplemented
;
59 if (PyObject_TypeCheck(other
, &PyGFlags_Type
) && ((PyGFlags
*)other
)->gtype
!= self
->gtype
) {
60 g_snprintf(warning
, sizeof(warning
), "comparing different flags types: %s and %s",
61 g_type_name(self
->gtype
), g_type_name(((PyGFlags
*)other
)->gtype
));
62 if (PyErr_Warn(PyExc_Warning
, warning
))
66 return pyg_integer_richcompare((PyObject
*)self
, other
, op
);
70 generate_repr(GType gtype
, guint value
)
72 GFlagsClass
*flags_class
;
73 char *retval
= NULL
, *tmp
;
76 flags_class
= g_type_class_ref(gtype
);
77 g_assert(G_IS_FLAGS_CLASS(flags_class
));
79 for (i
= 0; i
< flags_class
->n_values
; i
++) {
80 /* Some types (eg GstElementState in GStreamer 0.8) has flags with 0 values,
81 * we're just ignore them for now otherwise they'll always show up
83 if (flags_class
->values
[i
].value
== 0)
86 if ((value
& flags_class
->values
[i
].value
) == flags_class
->values
[i
].value
) {
88 tmp
= g_strdup_printf("%s | %s", retval
, flags_class
->values
[i
].value_name
);
92 retval
= g_strdup_printf("%s", flags_class
->values
[i
].value_name
);
97 g_type_class_unref(flags_class
);
103 pyg_flags_repr(PyGFlags
*self
)
105 char *tmp
, *retval
, *module_str
, *namespace;
106 PyObject
*pyretval
, *module
;
108 tmp
= generate_repr(self
->gtype
, (guint
)PYGLIB_PyLong_AsUnsignedLong(self
));
110 module
= PyObject_GetAttrString ((PyObject
*)self
, "__module__");
114 if (!PYGLIB_PyUnicode_Check (module
)) {
119 module_str
= PYGLIB_PyUnicode_AsString (module
);
120 namespace = g_strrstr (module_str
, ".");
121 if (namespace == NULL
) {
122 namespace = module_str
;
128 retval
= g_strdup_printf("<flags %s of type %s.%s>", tmp
,
129 namespace, Py_TYPE (self
)->tp_name
);
131 retval
= g_strdup_printf("<flags %ld of type %s.%s>",
132 PYGLIB_PyLong_AsUnsignedLong (self
),
133 namespace, Py_TYPE (self
)->tp_name
);
137 pyretval
= PYGLIB_PyUnicode_FromString(retval
);
144 pyg_flags_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
146 static char *kwlist
[] = { "value", NULL
};
148 PyObject
*pytc
, *values
, *ret
, *pyint
;
152 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "k", kwlist
, &value
))
155 pytc
= PyObject_GetAttrString((PyObject
*)type
, "__gtype__");
159 if (!PyObject_TypeCheck(pytc
, &PyGTypeWrapper_Type
)) {
161 PyErr_SetString(PyExc_TypeError
,
162 "__gtype__ attribute not a typecode");
166 gtype
= pyg_type_from_object(pytc
);
169 eclass
= G_FLAGS_CLASS(g_type_class_ref(gtype
));
171 values
= PyObject_GetAttrString((PyObject
*)type
, "__flags_values__");
173 g_type_class_unref(eclass
);
177 if (!PyDict_Check(values
)) {
178 PyErr_SetString(PyExc_TypeError
, "__flags_values__ badly formed");
180 g_type_class_unref(eclass
);
184 g_type_class_unref(eclass
);
186 pyint
= PYGLIB_PyLong_FromUnsignedLong(value
);
187 ret
= PyDict_GetItem(values
, pyint
);
191 ret
= pyg_flags_val_new((PyObject
*)type
, gtype
, pyint
);
192 g_assert(ret
!= NULL
);
204 pyg_flags_from_gtype (GType gtype
, guint value
)
206 PyObject
*pyclass
, *values
, *retval
, *pyint
;
208 if (PyErr_Occurred())
209 return PYGLIB_PyLong_FromUnsignedLong(0);
211 g_return_val_if_fail(gtype
!= G_TYPE_INVALID
, NULL
);
213 /* Get a wrapper class by:
214 * 1. check for one attached to the gtype
215 * 2. lookup one in a typelib
216 * 3. creating a new one
218 pyclass
= (PyObject
*)g_type_get_qdata(gtype
, pygflags_class_key
);
220 pyclass
= pygi_type_import_by_g_type(gtype
);
222 pyclass
= pyg_flags_add(NULL
, g_type_name(gtype
), NULL
, gtype
);
224 return PYGLIB_PyLong_FromUnsignedLong(value
);
226 values
= PyDict_GetItemString(((PyTypeObject
*)pyclass
)->tp_dict
,
228 pyint
= PYGLIB_PyLong_FromUnsignedLong(value
);
229 retval
= PyDict_GetItem(values
, pyint
);
233 retval
= pyg_flags_val_new(pyclass
, gtype
, pyint
);
234 g_assert(retval
!= NULL
);
245 * Dynamically create a class derived from PyGFlags based on the given GType.
248 pyg_flags_add (PyObject
* module
,
249 const char * typename
,
250 const char * strip_prefix
,
253 PyGILState_STATE state
;
254 PyObject
*instance_dict
, *stub
, *values
, *o
;
258 g_return_val_if_fail(typename
!= NULL
, NULL
);
259 if (!g_type_is_a(gtype
, G_TYPE_FLAGS
)) {
260 g_warning("Trying to register gtype '%s' as flags when in fact it is of type '%s'",
261 g_type_name(gtype
), g_type_name(G_TYPE_FUNDAMENTAL(gtype
)));
265 state
= PyGILState_Ensure();
267 /* Create a new type derived from GFlags. This is the same as:
268 * >>> stub = type(typename, (GFlags,), {})
270 instance_dict
= PyDict_New();
271 stub
= PyObject_CallFunction((PyObject
*)&PyType_Type
, "s(O)O",
272 typename
, (PyObject
*)&PyGFlags_Type
,
274 Py_DECREF(instance_dict
);
276 PyErr_SetString(PyExc_RuntimeError
, "can't create GFlags subtype");
277 PyGILState_Release(state
);
281 ((PyTypeObject
*)stub
)->tp_flags
&= ~Py_TPFLAGS_BASETYPE
;
284 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
,
286 PYGLIB_PyUnicode_FromString(PyModule_GetName(module
)));
288 /* Add it to the module name space */
289 PyModule_AddObject(module
, (char*)typename
, stub
);
292 g_type_set_qdata(gtype
, pygflags_class_key
, stub
);
294 o
= pyg_type_wrapper_new(gtype
);
295 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
, "__gtype__", o
);
298 /* Register flag values */
299 eclass
= G_FLAGS_CLASS(g_type_class_ref(gtype
));
301 values
= PyDict_New();
302 for (i
= 0; i
< eclass
->n_values
; i
++) {
303 PyObject
*item
, *intval
;
305 intval
= PYGLIB_PyLong_FromUnsignedLong(eclass
->values
[i
].value
);
306 g_assert(PyErr_Occurred() == NULL
);
307 item
= pyg_flags_val_new(stub
, gtype
, intval
);
308 PyDict_SetItem(values
, intval
, item
);
314 prefix
= g_strdup(pyg_constant_strip_prefix(eclass
->values
[i
].value_name
, strip_prefix
));
316 PyModule_AddObject(module
, prefix
, item
);
322 PyDict_SetItemString(((PyTypeObject
*)stub
)->tp_dict
,
323 "__flags_values__", values
);
326 g_type_class_unref(eclass
);
328 PyGILState_Release(state
);
334 pyg_flags_and(PyGFlags
*a
, PyGFlags
*b
)
336 if (!PyGFlags_Check(a
) || !PyGFlags_Check(b
))
337 return PYGLIB_PyLong_Type
.tp_as_number
->nb_and((PyObject
*)a
,
340 return pyg_flags_from_gtype(a
->gtype
,
341 (guint
)(PYGLIB_PyLong_AsUnsignedLong(a
) & PYGLIB_PyLong_AsUnsignedLong(b
)));
345 pyg_flags_or(PyGFlags
*a
, PyGFlags
*b
)
347 if (!PyGFlags_Check(a
) || !PyGFlags_Check(b
))
348 return PYGLIB_PyLong_Type
.tp_as_number
->nb_or((PyObject
*)a
,
351 return pyg_flags_from_gtype(a
->gtype
, (guint
)(PYGLIB_PyLong_AsUnsignedLong(a
) | PYGLIB_PyLong_AsUnsignedLong(b
)));
355 pyg_flags_xor(PyGFlags
*a
, PyGFlags
*b
)
357 if (!PyGFlags_Check(a
) || !PyGFlags_Check(b
))
358 return PYGLIB_PyLong_Type
.tp_as_number
->nb_xor((PyObject
*)a
,
361 return pyg_flags_from_gtype(a
->gtype
,
362 (guint
)(PYGLIB_PyLong_AsUnsignedLong(a
) ^ PYGLIB_PyLong_AsUnsignedLong(b
)));
367 pyg_flags_warn (PyObject
*self
, PyObject
*args
)
369 if (PyErr_Warn(PyExc_Warning
, "unsupported arithmetic operation for flags type"))
377 pyg_flags_get_first_value_name(PyGFlags
*self
, void *closure
)
379 GFlagsClass
*flags_class
;
380 GFlagsValue
*flags_value
;
383 flags_class
= g_type_class_ref(self
->gtype
);
384 g_assert(G_IS_FLAGS_CLASS(flags_class
));
385 flags_value
= g_flags_get_first_value(flags_class
, (guint
)PYGLIB_PyLong_AsUnsignedLong(self
));
387 retval
= PYGLIB_PyUnicode_FromString(flags_value
->value_name
);
392 g_type_class_unref(flags_class
);
398 pyg_flags_get_first_value_nick(PyGFlags
*self
, void *closure
)
400 GFlagsClass
*flags_class
;
401 GFlagsValue
*flags_value
;
404 flags_class
= g_type_class_ref(self
->gtype
);
405 g_assert(G_IS_FLAGS_CLASS(flags_class
));
407 flags_value
= g_flags_get_first_value(flags_class
, (guint
)PYGLIB_PyLong_AsUnsignedLong(self
));
409 retval
= PYGLIB_PyUnicode_FromString(flags_value
->value_nick
);
414 g_type_class_unref(flags_class
);
420 pyg_flags_get_value_names(PyGFlags
*self
, void *closure
)
422 GFlagsClass
*flags_class
;
426 flags_class
= g_type_class_ref(self
->gtype
);
427 g_assert(G_IS_FLAGS_CLASS(flags_class
));
429 retval
= PyList_New(0);
430 for (i
= 0; i
< flags_class
->n_values
; i
++) {
431 PyObject
*value_name
;
433 if ((PYGLIB_PyLong_AsUnsignedLong (self
) & flags_class
->values
[i
].value
) == flags_class
->values
[i
].value
) {
434 value_name
= PYGLIB_PyUnicode_FromString (flags_class
->values
[i
].value_name
);
435 PyList_Append (retval
, value_name
);
436 Py_DECREF (value_name
);
440 g_type_class_unref(flags_class
);
446 pyg_flags_get_value_nicks(PyGFlags
*self
, void *closure
)
448 GFlagsClass
*flags_class
;
452 flags_class
= g_type_class_ref(self
->gtype
);
453 g_assert(G_IS_FLAGS_CLASS(flags_class
));
455 retval
= PyList_New(0);
456 for (i
= 0; i
< flags_class
->n_values
; i
++)
457 if ((PYGLIB_PyLong_AsUnsignedLong(self
) & flags_class
->values
[i
].value
) == flags_class
->values
[i
].value
) {
458 PyObject
*py_nick
= PYGLIB_PyUnicode_FromString(flags_class
->values
[i
].value_nick
);
459 PyList_Append(retval
, py_nick
);
463 g_type_class_unref(flags_class
);
468 static PyGetSetDef pyg_flags_getsets
[] = {
469 { "first_value_name", (getter
)pyg_flags_get_first_value_name
, (setter
)0 },
470 { "first_value_nick", (getter
)pyg_flags_get_first_value_nick
, (setter
)0 },
471 { "value_names", (getter
)pyg_flags_get_value_names
, (setter
)0 },
472 { "value_nicks", (getter
)pyg_flags_get_value_nicks
, (setter
)0 },
476 static PyNumberMethods pyg_flags_as_number
= {
477 (binaryfunc
)pyg_flags_warn
, /* nb_add */
478 (binaryfunc
)pyg_flags_warn
, /* nb_subtract */
479 (binaryfunc
)pyg_flags_warn
, /* nb_multiply */
480 (binaryfunc
)pyg_flags_warn
, /* nb_divide */
481 (binaryfunc
)pyg_flags_warn
, /* nb_remainder */
482 #if PY_VERSION_HEX < 0x03000000
483 (binaryfunc
)pyg_flags_warn
, /* nb_divmod */
485 (ternaryfunc
)pyg_flags_warn
, /* nb_power */
493 (binaryfunc
)pyg_flags_and
, /* nb_and */
494 (binaryfunc
)pyg_flags_xor
, /* nb_xor */
495 (binaryfunc
)pyg_flags_or
, /* nb_or */
499 * Returns 0 on success, or -1 and sets an exception.
502 pygi_flags_register_types(PyObject
*d
)
504 pygflags_class_key
= g_quark_from_static_string("PyGFlags::class");
506 PyGFlags_Type
.tp_base
= &PYGLIB_PyLong_Type
;
507 PyGFlags_Type
.tp_new
= pyg_flags_new
;
508 PyGFlags_Type
.tp_hash
= PYGLIB_PyLong_Type
.tp_hash
;
509 PyGFlags_Type
.tp_repr
= (reprfunc
)pyg_flags_repr
;
510 PyGFlags_Type
.tp_as_number
= &pyg_flags_as_number
;
511 PyGFlags_Type
.tp_str
= (reprfunc
)pyg_flags_repr
;
512 PyGFlags_Type
.tp_flags
= Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
;
513 PyGFlags_Type
.tp_richcompare
= (richcmpfunc
)pyg_flags_richcompare
;
514 PyGFlags_Type
.tp_getset
= pyg_flags_getsets
;
515 PYGOBJECT_REGISTER_GTYPE(d
, PyGFlags_Type
, "GFlags", G_TYPE_FLAGS
);