Imported Upstream version 3.7.91.1
[platform/upstream/pygobject2.git] / gi / _gobject / pygflags.c
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
5  *
6  *   pygflags.c: GFlags wrapper
7  *
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.
12  *
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.
17  *
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
21  * USA
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <pyglib.h>
29 #include "pygobject-private.h"
30 #include "pygflags.h"
31
32 #include "pygi.h"
33
34 GQuark pygflags_class_key;
35
36 PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags);
37
38 static PyObject *
39 pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval)
40 {
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);
45     Py_DECREF(args);
46     if (!item)
47         return NULL;
48     ((PyGFlags*)item)->gtype = gtype;
49
50     return item;
51 }
52
53 static PyObject *
54 pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op)
55 {
56     static char warning[256];
57
58     if (!PYGLIB_PyLong_Check(other)) {
59         Py_INCREF(Py_NotImplemented);
60         return Py_NotImplemented;
61     }
62
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))
67             return NULL;
68     }
69
70     return pyg_integer_richcompare((PyObject *)self, other, op);
71 }
72
73 static char *
74 generate_repr(GType gtype, guint value)
75 {
76     GFlagsClass *flags_class;
77     char *retval = NULL, *tmp;
78     int i;
79
80     flags_class = g_type_class_ref(gtype);
81     g_assert(G_IS_FLAGS_CLASS(flags_class));
82
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
86          */
87         if (flags_class->values[i].value == 0)
88             continue;
89
90         if ((value & flags_class->values[i].value) == flags_class->values[i].value) {
91             if (retval) {
92                 tmp = g_strdup_printf("%s | %s", retval, flags_class->values[i].value_name);
93                 g_free(retval);
94                 retval = tmp;
95             } else {
96                 retval = g_strdup_printf("%s", flags_class->values[i].value_name);
97             }
98         }
99     }
100
101     g_type_class_unref(flags_class);
102
103     return retval;
104 }
105
106 static PyObject *
107 pyg_flags_repr(PyGFlags *self)
108 {
109     char *tmp, *retval;
110     PyObject *pyretval;
111
112     tmp = generate_repr(self->gtype, PYGLIB_PyLong_AsUnsignedLong(self));
113
114     if (tmp)
115         retval = g_strdup_printf("<flags %s of type %s>", tmp,
116                                  g_type_name(self->gtype));
117     else
118         retval = g_strdup_printf("<flags %ld of type %s>", PYGLIB_PyLong_AsUnsignedLong(self),
119                                  g_type_name(self->gtype));
120     g_free(tmp);
121
122     pyretval = PYGLIB_PyUnicode_FromString(retval);
123     g_free(retval);
124
125     return pyretval;
126 }
127
128 static PyObject *
129 pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
130 {
131     static char *kwlist[] = { "value", NULL };
132     guint value;
133     PyObject *pytc, *values, *ret, *pyint;
134     GType gtype;
135     GFlagsClass *eclass;
136
137     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value))
138         return NULL;
139
140     pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__");
141     if (!pytc)
142         return NULL;
143
144     if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) {
145         Py_DECREF(pytc);
146         PyErr_SetString(PyExc_TypeError,
147                         "__gtype__ attribute not a typecode");
148         return NULL;
149     }
150
151     gtype = pyg_type_from_object(pytc);
152     Py_DECREF(pytc);
153
154     eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
155
156     values = PyObject_GetAttrString((PyObject *)type, "__flags_values__");
157     if (!values) {
158         g_type_class_unref(eclass);
159         return NULL;
160     }
161
162     if (!PyDict_Check(values)) {
163         PyErr_SetString(PyExc_TypeError, "__flags_values__ badly formed");
164         Py_DECREF(values);
165         g_type_class_unref(eclass);
166         return NULL;
167     }
168
169     g_type_class_unref(eclass);
170
171     pyint = PYGLIB_PyLong_FromUnsignedLong(value);
172     ret = PyDict_GetItem(values, pyint);
173     if (!ret) {
174         PyErr_Clear();
175
176         ret = pyg_flags_val_new((PyObject *)type, gtype, pyint);
177         g_assert(ret != NULL);
178     } else {
179         Py_INCREF(ret);
180     }
181
182     Py_DECREF(pyint);
183     Py_DECREF(values);
184
185     return ret;
186 }
187
188 PyObject*
189 pyg_flags_from_gtype (GType gtype, guint value)
190 {
191     PyObject *pyclass, *values, *retval, *pyint;
192
193     if (PyErr_Occurred())
194         return PYGLIB_PyLong_FromUnsignedLong(0);
195
196     g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL);
197
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
202      */
203     pyclass = (PyObject*)g_type_get_qdata(gtype, pygflags_class_key);
204     if (!pyclass)
205         pyclass = pygi_type_import_by_g_type(gtype);
206     if (!pyclass)
207         pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype);
208     if (!pyclass)
209         return PYGLIB_PyLong_FromUnsignedLong(value);
210
211     values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict,
212                                   "__flags_values__");
213     pyint = PYGLIB_PyLong_FromUnsignedLong(value);
214     retval = PyDict_GetItem(values, pyint);
215     if (!retval) {
216         PyErr_Clear();
217
218         retval = pyg_flags_val_new(pyclass, gtype, pyint);
219         g_assert(retval != NULL);
220     } else {
221         Py_INCREF(retval);
222     }
223     Py_DECREF(pyint);
224     
225     return retval;
226 }
227
228 /*
229  * pyg_flags_add
230  * Dynamically create a class derived from PyGFlags based on the given GType.
231  */
232 PyObject *
233 pyg_flags_add (PyObject *   module,
234                const char * typename,
235                const char * strip_prefix,
236                GType        gtype)
237 {
238     PyGILState_STATE state;
239     PyObject *instance_dict, *stub, *values, *o;
240     GFlagsClass *eclass;
241     int i;
242
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)));
247         return NULL;
248     }
249
250     state = pyglib_gil_state_ensure();
251
252     /* Create a new type derived from GFlags. This is the same as:
253      * >>> stub = type(typename, (GFlags,), {})
254      */
255     instance_dict = PyDict_New();
256     stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O",
257                                  typename, (PyObject *)&PyGFlags_Type,
258                                  instance_dict);
259     Py_DECREF(instance_dict);
260     if (!stub) {
261         PyErr_SetString(PyExc_RuntimeError, "can't create GFlags subtype");
262         pyglib_gil_state_release(state);
263         return NULL;
264     }
265
266     ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE;
267     ((PyTypeObject *)stub)->tp_new = pyg_flags_new;
268
269     if (module) {
270         PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
271                              "__module__",
272                              PYGLIB_PyUnicode_FromString(PyModule_GetName(module)));
273
274           /* Add it to the module name space */
275         PyModule_AddObject(module, (char*)typename, stub);
276         Py_INCREF(stub);
277     }
278     g_type_set_qdata(gtype, pygflags_class_key, stub);
279
280     o = pyg_type_wrapper_new(gtype);
281     PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o);
282     Py_DECREF(o);
283
284     /* Register flag values */
285     eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
286
287     values = PyDict_New();
288     for (i = 0; i < eclass->n_values; i++) {
289       PyObject *item, *intval;
290       
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);
295       Py_DECREF(intval);
296
297       if (module) {
298           char *prefix;
299
300           prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix));
301           Py_INCREF(item);
302           PyModule_AddObject(module, prefix, item);
303           g_free(prefix);
304       }
305       Py_DECREF(item);
306     }
307
308     PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
309                          "__flags_values__", values);
310     Py_DECREF(values);
311
312     g_type_class_unref(eclass);
313
314     pyglib_gil_state_release(state);
315
316     return stub;
317 }
318
319 static PyObject *
320 pyg_flags_and(PyGFlags *a, PyGFlags *b)
321 {
322         if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
323                 return PYGLIB_PyLong_Type.tp_as_number->nb_and((PyObject*)a,
324                                                        (PyObject*)b);
325
326         return pyg_flags_from_gtype(a->gtype,
327                                     PYGLIB_PyLong_AsUnsignedLong(a) & PYGLIB_PyLong_AsUnsignedLong(b));
328 }
329
330 static PyObject *
331 pyg_flags_or(PyGFlags *a, PyGFlags *b)
332 {
333         if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
334                 return PYGLIB_PyLong_Type.tp_as_number->nb_or((PyObject*)a,
335                                                       (PyObject*)b);
336
337         return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AsUnsignedLong(a) | PYGLIB_PyLong_AsUnsignedLong(b));
338 }
339
340 static PyObject *
341 pyg_flags_xor(PyGFlags *a, PyGFlags *b)
342 {
343         if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
344                 return PYGLIB_PyLong_Type.tp_as_number->nb_xor((PyObject*)a,
345                                                        (PyObject*)b);
346
347         return pyg_flags_from_gtype(a->gtype,
348                                     PYGLIB_PyLong_AsUnsignedLong(a) ^ PYGLIB_PyLong_AsUnsignedLong(b));
349
350 }
351
352 static PyObject *
353 pyg_flags_warn (PyObject *self, PyObject *args)
354 {
355     if (PyErr_Warn(PyExc_Warning, "unsupported arithmetic operation for flags type"))
356         return NULL;
357
358     Py_INCREF(Py_None);
359     return Py_None;
360 }
361
362 static PyObject *
363 pyg_flags_get_first_value_name(PyGFlags *self, void *closure)
364 {
365   GFlagsClass *flags_class;
366   GFlagsValue *flags_value;
367   PyObject *retval;
368
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));
372   if (flags_value)
373       retval = PYGLIB_PyUnicode_FromString(flags_value->value_name);
374   else {
375       retval = Py_None;
376       Py_INCREF(Py_None);
377   }
378   g_type_class_unref(flags_class);
379
380   return retval;
381 }
382
383 static PyObject *
384 pyg_flags_get_first_value_nick(PyGFlags *self, void *closure)
385 {
386   GFlagsClass *flags_class;
387   GFlagsValue *flags_value;
388   PyObject *retval;
389
390   flags_class = g_type_class_ref(self->gtype);
391   g_assert(G_IS_FLAGS_CLASS(flags_class));
392
393   flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self));
394   if (flags_value)
395       retval = PYGLIB_PyUnicode_FromString(flags_value->value_nick);
396   else {
397       retval = Py_None;
398       Py_INCREF(Py_None);
399   }
400   g_type_class_unref(flags_class);
401
402   return retval;
403 }
404
405 static PyObject *
406 pyg_flags_get_value_names(PyGFlags *self, void *closure)
407 {
408   GFlagsClass *flags_class;
409   PyObject *retval;
410   int i;
411
412   flags_class = g_type_class_ref(self->gtype);
413   g_assert(G_IS_FLAGS_CLASS(flags_class));
414
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));
419
420   g_type_class_unref(flags_class);
421
422   return retval;
423 }
424
425 static PyObject *
426 pyg_flags_get_value_nicks(PyGFlags *self, void *closure)
427 {
428   GFlagsClass *flags_class;
429   PyObject *retval;
430   int i;
431
432   flags_class = g_type_class_ref(self->gtype);
433   g_assert(G_IS_FLAGS_CLASS(flags_class));
434
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);
440           Py_DECREF (py_nick);
441       }
442
443   g_type_class_unref(flags_class);
444
445   return retval;
446 }
447
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 },
453     { NULL, 0, 0 }
454 };
455
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 */
464 #endif
465         (ternaryfunc)pyg_flags_warn,            /* nb_power */
466         0,                                      /* nb_negative */
467         0,                                      /* nb_positive */
468         0,                                      /* nb_absolute */
469         0,                                      /* nb_nonzero */
470         0,                                      /* nb_invert */
471         0,                                      /* nb_lshift */
472         0,                                      /* nb_rshift */
473         (binaryfunc)pyg_flags_and,              /* nb_and */
474         (binaryfunc)pyg_flags_xor,              /* nb_xor */
475         (binaryfunc)pyg_flags_or,               /* nb_or */
476 };
477
478 void
479 pygobject_flags_register_types(PyObject *d)
480 {
481     pygflags_class_key = g_quark_from_static_string("PyGFlags::class");
482
483     PyGFlags_Type.tp_base = &PYGLIB_PyLong_Type;
484 #if PY_VERSION_HEX < 0x03000000
485     PyGFlags_Type.tp_new = pyg_flags_new;
486 #else
487     PyGFlags_Type.tp_new = PyLong_Type.tp_new;
488     PyGFlags_Type.tp_hash = PyLong_Type.tp_hash;    
489 #endif
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);
497 }