summaryrefslogtreecommitdiff
path: root/gobject/pygflags.c
diff options
context:
space:
mode:
Diffstat (limited to 'gobject/pygflags.c')
-rw-r--r--gobject/pygflags.c491
1 files changed, 491 insertions, 0 deletions
diff --git a/gobject/pygflags.c b/gobject/pygflags.c
new file mode 100644
index 0000000..1865abb
--- /dev/null
+++ b/gobject/pygflags.c
@@ -0,0 +1,491 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * pygtk- Python bindings for the GTK toolkit.
+ * Copyright (C) 1998-2003 James Henstridge
+ * Copyright (C) 2004 Johan Dahlin
+ *
+ * pygenum.c: GFlags wrapper
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pyglib.h>
+#include "pygobject-private.h"
+#include "pygflags.h"
+
+#include "pygi-external.h"
+
+GQuark pygflags_class_key;
+
+PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags);
+
+static PyObject *
+pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op)
+{
+ static char warning[256];
+
+ if (!_PyLong_Check(other)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ if (PyObject_TypeCheck(other, &PyGFlags_Type) && ((PyGFlags*)other)->gtype != self->gtype) {
+ g_snprintf(warning, sizeof(warning), "comparing different flags types: %s and %s",
+ g_type_name(self->gtype), g_type_name(((PyGFlags*)other)->gtype));
+ if (PyErr_Warn(PyExc_Warning, warning))
+ return NULL;
+ }
+
+ return pyg_integer_richcompare((PyObject *)self, other, op);
+}
+
+static char *
+generate_repr(GType gtype, int value)
+{
+ GFlagsClass *flags_class;
+ char *retval = NULL, *tmp;
+ int i;
+
+ flags_class = g_type_class_ref(gtype);
+ g_assert(G_IS_FLAGS_CLASS(flags_class));
+
+ for (i = 0; i < flags_class->n_values; i++) {
+ /* Some types (eg GstElementState in GStreamer 0.8) has flags with 0 values,
+ * we're just ignore them for now otherwise they'll always show up
+ */
+ if (flags_class->values[i].value == 0)
+ continue;
+
+ if ((value & flags_class->values[i].value) == flags_class->values[i].value) {
+ if (retval) {
+ tmp = g_strdup_printf("%s | %s", retval, flags_class->values[i].value_name);
+ g_free(retval);
+ retval = tmp;
+ } else {
+ retval = g_strdup_printf("%s", flags_class->values[i].value_name);
+ }
+ }
+ }
+
+ g_type_class_unref(flags_class);
+
+ return retval;
+}
+
+static PyObject *
+pyg_flags_repr(PyGFlags *self)
+{
+ char *tmp, *retval;
+ PyObject *pyretval;
+
+ tmp = generate_repr(self->gtype, _PyLong_AS_LONG(self));
+
+ if (tmp)
+ retval = g_strdup_printf("<flags %s of type %s>", tmp,
+ g_type_name(self->gtype));
+ else
+ retval = g_strdup_printf("<flags %ld of type %s>", _PyLong_AS_LONG(self),
+ g_type_name(self->gtype));
+ g_free(tmp);
+
+ pyretval = _PyUnicode_FromString(retval);
+ g_free(retval);
+
+ return pyretval;
+}
+
+static PyObject *
+pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "value", NULL };
+ long value;
+ PyObject *pytc, *values, *ret, *pyint;
+ GType gtype;
+ GFlagsClass *eclass;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value))
+ return NULL;
+
+ pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__");
+ if (!pytc)
+ return NULL;
+
+ if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) {
+ Py_DECREF(pytc);
+ PyErr_SetString(PyExc_TypeError,
+ "__gtype__ attribute not a typecode");
+ return NULL;
+ }
+
+ gtype = pyg_type_from_object(pytc);
+ Py_DECREF(pytc);
+
+ eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
+
+ values = PyObject_GetAttrString((PyObject *)type, "__flags_values__");
+ if (!values) {
+ g_type_class_unref(eclass);
+ return NULL;
+ }
+
+ if (!PyDict_Check(values) || PyDict_Size(values) != eclass->n_values) {
+ PyErr_SetString(PyExc_TypeError, "__flags_values__ badly formed");
+ Py_DECREF(values);
+ g_type_class_unref(eclass);
+ return NULL;
+ }
+
+ g_type_class_unref(eclass);
+
+ pyint = _PyLong_FromLong(value);
+ ret = PyDict_GetItem(values, pyint);
+ Py_DECREF(pyint);
+ Py_DECREF(values);
+
+ if (ret)
+ Py_INCREF(ret);
+ else
+ PyErr_Format(PyExc_ValueError, "invalid flag value: %ld", value);
+ return ret;
+}
+
+PyObject*
+pyg_flags_from_gtype (GType gtype, int value)
+{
+ PyObject *pyclass, *values, *retval, *pyint;
+
+ g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL);
+
+ /* Get a wrapper class by:
+ * 1. check for one attached to the gtype
+ * 2. lookup one in a typelib
+ * 3. creating a new one
+ */
+ pyclass = (PyObject*)g_type_get_qdata(gtype, pygflags_class_key);
+ if (!pyclass)
+ pyclass = pygi_type_import_by_g_type(gtype);
+ if (!pyclass)
+ pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype);
+ if (!pyclass)
+ return _PyLong_FromLong(value);
+
+ values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict,
+ "__flags_values__");
+ pyint = _PyLong_FromLong(value);
+ retval = PyDict_GetItem(values, pyint);
+ Py_DECREF(pyint);
+
+ if (!retval) {
+ PyErr_Clear();
+
+ retval = ((PyTypeObject *)pyclass)->tp_alloc((PyTypeObject *)pyclass, 0);
+ g_assert(retval != NULL);
+
+#if PY_VERSION_HEX >= 0x03000000
+# warning "FIXME: figure out how to subclass long"
+#else
+ ((_PyLongObject*)retval)->ob_ival = value;
+#endif
+ ((PyGFlags*)retval)->gtype = gtype;
+ } else {
+ Py_INCREF(retval);
+ }
+ return retval;
+}
+
+PyObject *
+pyg_flags_add (PyObject * module,
+ const char * typename,
+ const char * strip_prefix,
+ GType gtype)
+{
+ PyGILState_STATE state;
+ PyObject *instance_dict, *stub, *values, *o;
+ GFlagsClass *eclass;
+ int i;
+
+ g_return_val_if_fail(typename != NULL, NULL);
+ if (!g_type_is_a(gtype, G_TYPE_FLAGS)) {
+ g_warning("Trying to register gtype '%s' as flags when in fact it is of type '%s'",
+ g_type_name(gtype), g_type_name(G_TYPE_FUNDAMENTAL(gtype)));
+ return NULL;
+ }
+
+ state = pyglib_gil_state_ensure();
+
+ instance_dict = PyDict_New();
+ stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O",
+ typename, (PyObject *)&PyGFlags_Type,
+ instance_dict);
+ Py_DECREF(instance_dict);
+ if (!stub) {
+ PyErr_SetString(PyExc_RuntimeError, "can't create const");
+ pyglib_gil_state_release(state);
+ return NULL;
+ }
+
+ ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE;
+ ((PyTypeObject *)stub)->tp_new = pyg_flags_new;
+
+ if (module) {
+ PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
+ "__module__",
+ _PyUnicode_FromString(PyModule_GetName(module)));
+
+ /* Add it to the module name space */
+ PyModule_AddObject(module, (char*)typename, stub);
+ Py_INCREF(stub);
+ }
+ g_type_set_qdata(gtype, pygflags_class_key, stub);
+
+ o = pyg_type_wrapper_new(gtype);
+ PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o);
+ Py_DECREF(o);
+
+ /* Register flag values */
+ eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
+
+ values = PyDict_New();
+ for (i = 0; i < eclass->n_values; i++) {
+ PyObject *item, *intval;
+
+ item = ((PyTypeObject *)stub)->tp_alloc((PyTypeObject *)stub, 0);
+#if PY_VERSION_HEX >= 0x03000000
+# warning "FIXME: figure out how to subclass long"
+#else
+ ((_PyLongObject*)item)->ob_ival = eclass->values[i].value;
+#endif
+ ((PyGFlags*)item)->gtype = gtype;
+
+ intval = _PyLong_FromLong(eclass->values[i].value);
+ PyDict_SetItem(values, intval, item);
+ Py_DECREF(intval);
+
+ if (module) {
+ char *prefix;
+
+ prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix));
+ PyModule_AddObject(module, prefix, item);
+ g_free(prefix);
+
+ Py_INCREF(item);
+ }
+ }
+
+ PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
+ "__flags_values__", values);
+ Py_DECREF(values);
+
+ g_type_class_unref(eclass);
+
+ pyglib_gil_state_release(state);
+
+ return stub;
+}
+
+static PyObject *
+pyg_flags_and(PyGFlags *a, PyGFlags *b)
+{
+ if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
+ return _PyLong_Type.tp_as_number->nb_and((PyObject*)a,
+ (PyObject*)b);
+
+ return pyg_flags_from_gtype(a->gtype,
+ _PyLong_AS_LONG(a) & _PyLong_AS_LONG(b));
+}
+
+static PyObject *
+pyg_flags_or(PyGFlags *a, PyGFlags *b)
+{
+ if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
+ return _PyLong_Type.tp_as_number->nb_or((PyObject*)a,
+ (PyObject*)b);
+
+ return pyg_flags_from_gtype(a->gtype, _PyLong_AS_LONG(a) | _PyLong_AS_LONG(b));
+}
+
+static PyObject *
+pyg_flags_xor(PyGFlags *a, PyGFlags *b)
+{
+ if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
+ return _PyLong_Type.tp_as_number->nb_xor((PyObject*)a,
+ (PyObject*)b);
+
+ return pyg_flags_from_gtype(a->gtype,
+ _PyLong_AS_LONG(a) ^ _PyLong_AS_LONG(b));
+
+}
+
+static PyObject *
+pyg_flags_warn (PyObject *self, PyObject *args)
+{
+ if (PyErr_Warn(PyExc_Warning, "unsupported arithmetic operation for flags type"))
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+pyg_flags_get_first_value_name(PyGFlags *self, void *closure)
+{
+ GFlagsClass *flags_class;
+ GFlagsValue *flags_value;
+ PyObject *retval;
+
+ flags_class = g_type_class_ref(self->gtype);
+ g_assert(G_IS_FLAGS_CLASS(flags_class));
+ flags_value = g_flags_get_first_value(flags_class, _PyLong_AS_LONG(self));
+ if (flags_value)
+ retval = _PyUnicode_FromString(flags_value->value_name);
+ else {
+ retval = Py_None;
+ Py_INCREF(Py_None);
+ }
+ g_type_class_unref(flags_class);
+
+ return retval;
+}
+
+static PyObject *
+pyg_flags_get_first_value_nick(PyGFlags *self, void *closure)
+{
+ GFlagsClass *flags_class;
+ GFlagsValue *flags_value;
+ PyObject *retval;
+
+ flags_class = g_type_class_ref(self->gtype);
+ g_assert(G_IS_FLAGS_CLASS(flags_class));
+
+ flags_value = g_flags_get_first_value(flags_class, _PyLong_AS_LONG(self));
+ if (flags_value)
+ retval = _PyUnicode_FromString(flags_value->value_nick);
+ else {
+ retval = Py_None;
+ Py_INCREF(Py_None);
+ }
+ g_type_class_unref(flags_class);
+
+ return retval;
+}
+
+static PyObject *
+pyg_flags_get_value_names(PyGFlags *self, void *closure)
+{
+ GFlagsClass *flags_class;
+ PyObject *retval;
+ int i;
+
+ flags_class = g_type_class_ref(self->gtype);
+ g_assert(G_IS_FLAGS_CLASS(flags_class));
+
+ retval = PyList_New(0);
+ for (i = 0; i < flags_class->n_values; i++)
+ if ((_PyLong_AS_LONG(self) & flags_class->values[i].value) == flags_class->values[i].value)
+ PyList_Append(retval, _PyUnicode_FromString(flags_class->values[i].value_name));
+
+ g_type_class_unref(flags_class);
+
+ return retval;
+}
+
+static PyObject *
+pyg_flags_get_value_nicks(PyGFlags *self, void *closure)
+{
+ GFlagsClass *flags_class;
+ PyObject *retval;
+ int i;
+
+ flags_class = g_type_class_ref(self->gtype);
+ g_assert(G_IS_FLAGS_CLASS(flags_class));
+
+ retval = PyList_New(0);
+ for (i = 0; i < flags_class->n_values; i++)
+ if ((_PyLong_AS_LONG(self) & flags_class->values[i].value) == flags_class->values[i].value)
+ PyList_Append(retval, _PyUnicode_FromString(flags_class->values[i].value_nick));
+
+ g_type_class_unref(flags_class);
+
+ return retval;
+}
+
+static PyGetSetDef pyg_flags_getsets[] = {
+ { "first_value_name", (getter)pyg_flags_get_first_value_name, (setter)0 },
+ { "first_value_nick", (getter)pyg_flags_get_first_value_nick, (setter)0 },
+ { "value_names", (getter)pyg_flags_get_value_names, (setter)0 },
+ { "value_nicks", (getter)pyg_flags_get_value_nicks, (setter)0 },
+ { NULL, 0, 0 }
+};
+
+static PyNumberMethods pyg_flags_as_number = {
+ (binaryfunc)pyg_flags_warn, /* nb_add */
+ (binaryfunc)pyg_flags_warn, /* nb_subtract */
+ (binaryfunc)pyg_flags_warn, /* nb_multiply */
+ (binaryfunc)pyg_flags_warn, /* nb_divide */
+ (binaryfunc)pyg_flags_warn, /* nb_remainder */
+ (binaryfunc)pyg_flags_warn, /* nb_divmod */
+ (ternaryfunc)pyg_flags_warn, /* nb_power */
+ 0, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+ 0, /* nb_nonzero */
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ (binaryfunc)pyg_flags_and, /* nb_and */
+ (binaryfunc)pyg_flags_xor, /* nb_xor */
+ (binaryfunc)pyg_flags_or, /* nb_or */
+ 0, /* nb_coerce */
+ 0, /* nb_int */
+ 0, /* nb_long */
+ 0, /* nb_float */
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+ 0, /* nb_inplace_divide */
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ 0, /* nb_floor_divide */
+ 0, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+};
+
+void
+pygobject_flags_register_types(PyObject *d)
+{
+ pygflags_class_key = g_quark_from_static_string("PyGFlags::class");
+
+ PyGFlags_Type.tp_base = &_PyLong_Type;
+ PyGFlags_Type.tp_repr = (reprfunc)pyg_flags_repr;
+ PyGFlags_Type.tp_as_number = &pyg_flags_as_number;
+ PyGFlags_Type.tp_str = (reprfunc)pyg_flags_repr;
+ PyGFlags_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
+ PyGFlags_Type.tp_richcompare = (richcmpfunc)pyg_flags_richcompare;
+ PyGFlags_Type.tp_getset = pyg_flags_getsets;
+ PyGFlags_Type.tp_new = pyg_flags_new;
+ PYGOBJECT_REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS);
+}