ce146ae2781144cffd0f0f291358b6b406364c16
[platform/upstream/python-gobject.git] / gi / 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, see <http://www.gnu.org/licenses/>.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25
26 #include <pyglib.h>
27 #include "pygobject-private.h"
28 #include "pygflags.h"
29
30 #include "pygi.h"
31 #include "pygi-type.h"
32
33 GQuark pygflags_class_key;
34
35 PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags);
36
37 static PyObject *
38 pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval)
39 {
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;
48
49     return item;
50 }
51
52 static PyObject *
53 pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op)
54 {
55     static char warning[256];
56
57     if (!PYGLIB_PyLong_Check(other)) {
58         Py_INCREF(Py_NotImplemented);
59         return Py_NotImplemented;
60     }
61
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;
67     }
68
69     return pyg_integer_richcompare((PyObject *)self, other, op);
70 }
71
72 static char *
73 generate_repr(GType gtype, guint value)
74 {
75     GFlagsClass *flags_class;
76     char *retval = NULL, *tmp;
77     int i;
78
79     flags_class = g_type_class_ref(gtype);
80     g_assert(G_IS_FLAGS_CLASS(flags_class));
81
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
85          */
86         if (flags_class->values[i].value == 0)
87             continue;
88
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);
96             }
97         }
98     }
99
100     g_type_class_unref(flags_class);
101
102     return retval;
103 }
104
105 static PyObject *
106 pyg_flags_repr(PyGFlags *self)
107 {
108     char *tmp, *retval, *module_str, *namespace;
109     PyObject *pyretval, *module;
110
111     tmp = generate_repr(self->gtype, PYGLIB_PyLong_AsUnsignedLong(self));
112
113     module = PyObject_GetAttrString ((PyObject *)self, "__module__");
114     if (module == NULL)
115         return NULL;
116
117     if (!PYGLIB_PyUnicode_Check (module)) {
118         Py_DECREF (module);
119         return NULL;
120     }
121
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;
128     }
129
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);
139
140     pyretval = PYGLIB_PyUnicode_FromString(retval);
141     g_free(retval);
142
143     return pyretval;
144 }
145
146 static PyObject *
147 pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
148 {
149     static char *kwlist[] = { "value", NULL };
150     gulong value;
151     PyObject *pytc, *values, *ret, *pyint;
152     GType gtype;
153     GFlagsClass *eclass;
154
155     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k", kwlist, &value))
156         return NULL;
157
158     pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__");
159     if (!pytc)
160         return NULL;
161
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;
167     }
168
169     gtype = pyg_type_from_object(pytc);
170     Py_DECREF(pytc);
171
172     eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
173
174     values = PyObject_GetAttrString((PyObject *)type, "__flags_values__");
175     if (!values) {
176         g_type_class_unref(eclass);
177         return NULL;
178     }
179
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;
185     }
186
187     g_type_class_unref(eclass);
188
189     pyint = PYGLIB_PyLong_FromUnsignedLong(value);
190     ret = PyDict_GetItem(values, pyint);
191     if (!ret) {
192         PyErr_Clear();
193
194         ret = pyg_flags_val_new((PyObject *)type, gtype, pyint);
195         g_assert(ret != NULL);
196     } else {
197         Py_INCREF(ret);
198     }
199
200     Py_DECREF(pyint);
201     Py_DECREF(values);
202
203     return ret;
204 }
205
206 PyObject*
207 pyg_flags_from_gtype (GType gtype, guint value)
208 {
209     PyObject *pyclass, *values, *retval, *pyint;
210
211     if (PyErr_Occurred())
212         return PYGLIB_PyLong_FromUnsignedLong(0);
213
214     g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL);
215
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
220      */
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);
228
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();
235
236         retval = pyg_flags_val_new(pyclass, gtype, pyint);
237         g_assert(retval != NULL);
238     } else {
239         Py_INCREF(retval);
240     }
241     Py_DECREF(pyint);
242     
243     return retval;
244 }
245
246 /*
247  * pyg_flags_add
248  * Dynamically create a class derived from PyGFlags based on the given GType.
249  */
250 PyObject *
251 pyg_flags_add (PyObject *   module,
252                const char * typename,
253                const char * strip_prefix,
254                GType        gtype)
255 {
256     PyGILState_STATE state;
257     PyObject *instance_dict, *stub, *values, *o;
258     GFlagsClass *eclass;
259     int i;
260
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;
266     }
267
268     state = pyglib_gil_state_ensure();
269
270     /* Create a new type derived from GFlags. This is the same as:
271      * >>> stub = type(typename, (GFlags,), {})
272      */
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         pyglib_gil_state_release(state);
281         return NULL;
282     }
283
284     ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE;
285     ((PyTypeObject *)stub)->tp_new = pyg_flags_new;
286
287     if (module) {
288         PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
289                              "__module__",
290                              PYGLIB_PyUnicode_FromString(PyModule_GetName(module)));
291
292           /* Add it to the module name space */
293         PyModule_AddObject(module, (char*)typename, stub);
294         Py_INCREF(stub);
295     }
296     g_type_set_qdata(gtype, pygflags_class_key, stub);
297
298     o = pyg_type_wrapper_new(gtype);
299     PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o);
300     Py_DECREF(o);
301
302     /* Register flag values */
303     eclass = G_FLAGS_CLASS(g_type_class_ref(gtype));
304
305     values = PyDict_New();
306     for (i = 0; i < eclass->n_values; i++) {
307       PyObject *item, *intval;
308       
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);
314
315       if (module) {
316           char *prefix;
317
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);
322       }
323       Py_DECREF(item);
324     }
325
326     PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict,
327                          "__flags_values__", values);
328     Py_DECREF(values);
329
330     g_type_class_unref(eclass);
331
332     pyglib_gil_state_release(state);
333
334     return stub;
335 }
336
337 static PyObject *
338 pyg_flags_and(PyGFlags *a, PyGFlags *b)
339 {
340         if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
341                 return PYGLIB_PyLong_Type.tp_as_number->nb_and((PyObject*)a,
342                                                        (PyObject*)b);
343
344         return pyg_flags_from_gtype(a->gtype,
345                                     PYGLIB_PyLong_AsUnsignedLong(a) & PYGLIB_PyLong_AsUnsignedLong(b));
346 }
347
348 static PyObject *
349 pyg_flags_or(PyGFlags *a, PyGFlags *b)
350 {
351         if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
352                 return PYGLIB_PyLong_Type.tp_as_number->nb_or((PyObject*)a,
353                                                       (PyObject*)b);
354
355         return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AsUnsignedLong(a) | PYGLIB_PyLong_AsUnsignedLong(b));
356 }
357
358 static PyObject *
359 pyg_flags_xor(PyGFlags *a, PyGFlags *b)
360 {
361         if (!PyGFlags_Check(a) || !PyGFlags_Check(b))
362                 return PYGLIB_PyLong_Type.tp_as_number->nb_xor((PyObject*)a,
363                                                        (PyObject*)b);
364
365         return pyg_flags_from_gtype(a->gtype,
366                                     PYGLIB_PyLong_AsUnsignedLong(a) ^ PYGLIB_PyLong_AsUnsignedLong(b));
367
368 }
369
370 static PyObject *
371 pyg_flags_warn (PyObject *self, PyObject *args)
372 {
373     if (PyErr_Warn(PyExc_Warning, "unsupported arithmetic operation for flags type"))
374         return NULL;
375
376     Py_INCREF(Py_None);
377     return Py_None;
378 }
379
380 static PyObject *
381 pyg_flags_get_first_value_name(PyGFlags *self, void *closure)
382 {
383   GFlagsClass *flags_class;
384   GFlagsValue *flags_value;
385   PyObject *retval;
386
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);
395   }
396   g_type_class_unref(flags_class);
397
398   return retval;
399 }
400
401 static PyObject *
402 pyg_flags_get_first_value_nick(PyGFlags *self, void *closure)
403 {
404   GFlagsClass *flags_class;
405   GFlagsValue *flags_value;
406   PyObject *retval;
407
408   flags_class = g_type_class_ref(self->gtype);
409   g_assert(G_IS_FLAGS_CLASS(flags_class));
410
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);
417   }
418   g_type_class_unref(flags_class);
419
420   return retval;
421 }
422
423 static PyObject *
424 pyg_flags_get_value_names(PyGFlags *self, void *closure)
425 {
426   GFlagsClass *flags_class;
427   PyObject *retval;
428   int i;
429
430   flags_class = g_type_class_ref(self->gtype);
431   g_assert(G_IS_FLAGS_CLASS(flags_class));
432
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));
437
438   g_type_class_unref(flags_class);
439
440   return retval;
441 }
442
443 static PyObject *
444 pyg_flags_get_value_nicks(PyGFlags *self, void *closure)
445 {
446   GFlagsClass *flags_class;
447   PyObject *retval;
448   int i;
449
450   flags_class = g_type_class_ref(self->gtype);
451   g_assert(G_IS_FLAGS_CLASS(flags_class));
452
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);
459       }
460
461   g_type_class_unref(flags_class);
462
463   return retval;
464 }
465
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 }
472 };
473
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 */
494 };
495
496 void
497 pygobject_flags_register_types(PyObject *d)
498 {
499     pygflags_class_key = g_quark_from_static_string("PyGFlags::class");
500
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);
515 }