From a565ad51fe4d189ed0bc85bde14bf3aa87f2f344 Mon Sep 17 00:00:00 2001 From: Johan Dahlin Date: Sat, 17 Jul 2004 16:38:46 +0000 Subject: gtk/*.override * gtk/*.override * codegen/codegen.py: * codegen/argtypes.py: Update for enums * pygtype.c (pyg_value_as_pyobject): Use new enum/flag functions * pygenum.[ch]: Handle GFlag * pygflags.[ch]: Handle GFlag * atk-types.defs: Fix gtype-id for all enums * gobjectmodule.c (initgobject): Clean up and add convinience macros * tests/enum.py: New file * tests/common.py: New file, also stole from gst-python --- ChangeLog | 19 +++ Makefile.am | 14 +- atk-types.defs | 8 + atk.override | 1 + codegen/argtypes.py | 4 +- codegen/codegen.py | 15 +- gobject/gobjectmodule.c | 84 +++++----- gobject/pygenum.c | 252 ++++++++++++++++++++++++++++++ gobject/pygenum.h | 54 +++++++ gobject/pygflags.c | 367 ++++++++++++++++++++++++++++++++++++++++++++ gobject/pygflags.h | 52 +++++++ gobject/pygobject-private.h | 3 +- gobject/pygobject.h | 29 +++- gobject/pygtype.c | 7 +- gobjectmodule.c | 84 +++++----- gtk/__init__.py | 2 + gtk/gdk.override | 26 ++-- gtk/gtk.override | 25 +-- gtk/gtktreeview.override | 9 +- pygenum.c | 252 ++++++++++++++++++++++++++++++ pygenum.h | 54 +++++++ pygflags.c | 367 ++++++++++++++++++++++++++++++++++++++++++++ pygflags.h | 52 +++++++ pygobject-private.h | 3 +- pygobject.h | 29 +++- pygtype.c | 7 +- tests/Makefile.am | 1 + tests/common.py | 16 ++ tests/conversion.py | 2 +- tests/runtests.py | 2 +- tests/signal.py | 2 +- 31 files changed, 1698 insertions(+), 144 deletions(-) create mode 100644 gobject/pygenum.c create mode 100644 gobject/pygenum.h create mode 100644 gobject/pygflags.c create mode 100644 gobject/pygflags.h create mode 100644 pygenum.c create mode 100644 pygenum.h create mode 100644 pygflags.c create mode 100644 pygflags.h create mode 100644 tests/common.py diff --git a/ChangeLog b/ChangeLog index 5bd3dabe..73ee2d2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2004-07-17 Johan Dahlin + + * codegen/codegen.py: + * codegen/argtypes.py: Update for enums + + * pygtype.c (pyg_value_as_pyobject): Use new enum/flag functions + + * pygenum.[ch]: Handle GFlag + + * pygflags.[ch]: Handle GFlag + + * atk-types.defs: Fix gtype-id for all enums + + * gobjectmodule.c (initgobject): Clean up and add convinience macros + + * tests/enum.py: New file + + * tests/common.py: New file, also stole from gst-python + 2004-07-17 Gustavo J. A. M. Carneiro * gtk/gtk.override (_wrap_gtk_table_new): Override to allow rows diff --git a/Makefile.am b/Makefile.am index c996dd30..a5dbbf57 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # require automake-1.7 AUTOMAKE_OPTIONS = 1.7 -SUBDIRS = codegen gtk docs +SUBDIRS = codegen gtk docs tests CLEANFILES = EXTRA_DIST = $(defs_DATA) @@ -53,8 +53,16 @@ endif gobject_la_LDFLAGS = $(common_ldflags) -export-symbols-regex initgobject gobject_la_LIBADD = $(GLIB_LIBS) gobject_la_SOURCES = \ - pygobject.h pygobject-private.h \ - gobjectmodule.c pygtype.c pygobject.c pygboxed.c + gobjectmodule.c \ + pygboxed.c \ + pygenum.c \ + pygenum.h \ + pygflags.c \ + pygflags.h \ + pygobject.c \ + pygobject.h \ + pygobject-private.h \ + pygtype.c # pango module pango_la_LDFLAGS = $(common_ldflags) -export-symbols-regex initpango diff --git a/atk-types.defs b/atk-types.defs index 80ac340b..222840f0 100644 --- a/atk-types.defs +++ b/atk-types.defs @@ -75,6 +75,7 @@ (define-enum Role (in-module "Atk") (c-name "AtkRole") + (gtype-id "ATK_TYPE_ROLE") (values '("invalid" "ATK_ROLE_INVALID") '("accel-label" "ATK_ROLE_ACCEL_LABEL") @@ -152,6 +153,7 @@ (define-enum Layer (in-module "Atk") (c-name "AtkLayer") + (gtype-id "ATK_TYPE_LAYER") (values '("invalid" "ATK_LAYER_INVALID") '("background" "ATK_LAYER_BACKGROUND") @@ -166,6 +168,7 @@ (define-enum RelationType (in-module "Atk") (c-name "AtkRelationType") + (gtype-id "ATK_TYPE_RELATION_TYPE") (values '("null" "ATK_RELATION_NULL") '("controlled-by" "ATK_RELATION_CONTROLLED_BY") @@ -181,6 +184,7 @@ (define-enum StateType (in-module "Atk") (c-name "AtkStateType") + (gtype-id "ATK_TYPE_STATE_TYPE") (values '("invalid" "ATK_STATE_INVALID") '("active" "ATK_STATE_ACTIVE") @@ -218,6 +222,7 @@ (define-enum TextAttribute (in-module "Atk") (c-name "AtkTextAttribute") + (gtype-id "ATK_TYPE_TEXT_ATTRIBUTE") (values '("left-margin" "ATK_TEXT_ATTR_LEFT_MARGIN") '("right-margin" "ATK_TEXT_ATTR_RIGHT_MARGIN") @@ -252,6 +257,7 @@ (define-enum TextBoundary (in-module "Atk") (c-name "AtkTextBoundary") + (gtype-id "ATK_TYPE_TEXT_BOUNDARY") (values '("char" "ATK_TEXT_BOUNDARY_CHAR") '("word-start" "ATK_TEXT_BOUNDARY_WORD_START") @@ -266,6 +272,7 @@ (define-enum KeyEventType (in-module "Atk") (c-name "AtkKeyEventType") + (gtype-id "ATK_TYPE_KEY_EVENT_TYPE") (values '("press" "ATK_KEY_EVENT_PRESS") '("release" "ATK_KEY_EVENT_RELEASE") @@ -276,6 +283,7 @@ (define-enum CoordType (in-module "Atk") (c-name "AtkCoordType") + (gtype-id "ATK_TYPE_COORD_TYPE") (values '("screen" "ATK_XY_SCREEN") '("window" "ATK_XY_WINDOW") diff --git a/atk.override b/atk.override index 7b7e0de1..5f27e3be 100644 --- a/atk.override +++ b/atk.override @@ -24,6 +24,7 @@ headers #define NO_IMPORT_PYGOBJECT #include "pygobject.h" #include +#include #include #include %% diff --git a/codegen/argtypes.py b/codegen/argtypes.py index 9d4afd48..1fe1eb27 100644 --- a/codegen/argtypes.py +++ b/codegen/argtypes.py @@ -318,7 +318,7 @@ class EnumArg(ArgType): info.add_parselist('O', ['&py_' + pname], [pname]); def write_return(self, ptype, ownsreturn, info): info.varlist.add('gint', 'ret') - info.codeafter.append(' return PyInt_FromLong(ret);') + info.codeafter.append(' return pyg_enum_from_gtype(%s, ret);' % self.typecode) class FlagsArg(ArgType): flag = (' if (%(default)spyg_flags_get_value(%(typecode)s, py_%(name)s, (gint *)&%(name)s))\n' @@ -341,7 +341,7 @@ class FlagsArg(ArgType): info.add_parselist('O', ['&py_' + pname], [pname]) def write_return(self, ptype, ownsreturn, info): info.varlist.add('guint', 'ret') - info.codeafter.append(' return PyInt_FromLong(ret);') + info.codeafter.append(' return pyg_flags_from_gtype(%s, ret);' % self.typecode) class ObjectArg(ArgType): # should change these checks to more typesafe versions that check diff --git a/codegen/codegen.py b/codegen/codegen.py index 659c6adb..f4c292d1 100644 --- a/codegen/codegen.py +++ b/codegen/codegen.py @@ -752,6 +752,7 @@ def write_enums(parser, prefix, fp=sys.stdout): return fp.write('\n/* ----------- enums and flags ----------- */\n\n') fp.write('void\n' + prefix + '_add_constants(PyObject *module, const gchar *strip_prefix)\n{\n') + for enum in parser.enums: if enum.typecode is None: for nick, value in enum.values: @@ -759,15 +760,17 @@ def write_enums(parser, prefix, fp=sys.stdout): % (value, value)) else: if enum.deftype == 'enum': - fp.write(' pyg_enum_add_constants(module, %s, strip_prefix);\n' - % (enum.typecode,)) + fp.write(' pyg_enum_add(module, "%s", strip_prefix, %s);\n' % (enum.name, enum.typecode)) else: - fp.write(' pyg_flags_add_constants(module, %s, strip_prefix);\n' - % (enum.typecode,)) + fp.write(' pyg_flags_add(module, "%s", strip_prefix, %s);\n' % (enum.name, enum.typecode)) + + fp.write('\n') + fp.write(' if (!PyErr_Occurred())\n') + fp.write(' PyErr_Print();\n') fp.write('}\n\n') def write_extension_init(overrides, prefix, fp): - fp.write('/* intialise stuff extension classes */\n') + fp.write('/* initialise stuff extension classes */\n') fp.write('void\n' + prefix + '_register_classes(PyObject *d)\n{\n') imports = overrides.get_imports()[:] if imports: @@ -905,7 +908,9 @@ def main(argv): p = defsparser.DefsParser(args[0], defines) if not outfilename: outfilename = os.path.splitext(args[0])[0] + '.c' + p.startParsing() + register_types(p) write_source(p, o, prefix, FileOutput(sys.stdout, outfilename)) diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c index ec9fcf49..6159ca90 100644 --- a/gobject/gobjectmodule.c +++ b/gobject/gobjectmodule.c @@ -26,6 +26,9 @@ #include "pygobject-private.h" +#include "pygenum.h" +#include "pygflags.h" + static PyObject *gerror_exc = NULL; static const gchar *pyginterface_type_id = "PyGInterface::type"; GQuark pyginterface_type_key = 0; @@ -1880,7 +1883,7 @@ static PyMethodDef pygobject_functions[] = { * * Returns: the stripped constant name. */ -static char * +char * pyg_constant_strip_prefix(gchar *name, const gchar *strip_prefix) { gint prefix_len; @@ -2158,12 +2161,35 @@ struct _PyGObject_Functions pygobject_api_functions = { &PyGParamSpec_Type, pyg_param_spec_new, pyg_param_spec_from_object, + pyg_pyobj_to_unichar_conv, pyg_parse_constructor_args, pyg_param_gvalue_as_pyobject, - pyg_param_gvalue_from_pyobject + pyg_param_gvalue_from_pyobject, + + &PyGEnum_Type, + pyg_enum_add, + pyg_enum_from_gtype, + + &PyGFlags_Type, + pyg_flags_add, + pyg_flags_from_gtype }; +#define REGISTER_TYPE(d, type, name) \ + type.ob_type = &PyType_Type; \ + type.tp_alloc = PyType_GenericAlloc; \ + type.tp_new = PyType_GenericNew; \ + if (PyType_Ready(&type)) \ + return; \ + PyDict_SetItemString(d, name, (PyObject *)&type); + +#define REGISTER_GTYPE(d, type, name, gtype) \ + REGISTER_TYPE(d, type, name); \ + PyDict_SetItemString(type.tp_dict, "__gtype__", \ + o=pyg_type_wrapper_new(gtype)); \ + Py_DECREF(o); + DL_EXPORT(void) initgobject(void) { @@ -2188,7 +2214,7 @@ initgobject(void) gerror_exc = PyErr_NewException("gobject.GError", PyExc_RuntimeError,NULL); PyDict_SetItemString(d, "GError", gerror_exc); - + PyGObject_Type.tp_alloc = PyType_GenericAlloc; PyGObject_Type.tp_new = PyType_GenericNew; pygobject_register_class(d, "GObject", G_TYPE_OBJECT, @@ -2196,55 +2222,23 @@ initgobject(void) PyDict_SetItemString(PyGObject_Type.tp_dict, "__gdoc__", pyg_object_descr_doc_get()); - PyGInterface_Type.ob_type = &PyType_Type; - PyGInterface_Type.tp_alloc = PyType_GenericAlloc; - PyGInterface_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGInterface_Type)) - return; - PyDict_SetItemString(d, "GInterface", (PyObject *)&PyGInterface_Type); - PyDict_SetItemString(PyGInterface_Type.tp_dict, "__gtype__", - o=pyg_type_wrapper_new(G_TYPE_INTERFACE)); - Py_DECREF(o); + REGISTER_GTYPE(d, PyGInterface_Type, "GInterface", G_TYPE_INTERFACE); PyDict_SetItemString(PyGInterface_Type.tp_dict, "__doc__", pyg_object_descr_doc_get()); PyDict_SetItemString(PyGInterface_Type.tp_dict, "__gdoc__", pyg_object_descr_doc_get()); pyginterface_type_key = g_quark_from_static_string(pyginterface_type_id); - PyGBoxed_Type.ob_type = &PyType_Type; - PyGBoxed_Type.tp_alloc = PyType_GenericAlloc; - PyGBoxed_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGBoxed_Type)) - return; - PyDict_SetItemString(d, "GBoxed", (PyObject *)&PyGBoxed_Type); - PyDict_SetItemString(PyGBoxed_Type.tp_dict, "__gtype__", - o=pyg_type_wrapper_new(G_TYPE_BOXED)); - Py_DECREF(o); + REGISTER_GTYPE(d, PyGBoxed_Type, "GBoxed", G_TYPE_BOXED); + REGISTER_GTYPE(d, PyGPointer_Type, "GPointer", G_TYPE_POINTER); + REGISTER_GTYPE(d, PyGEnum_Type, "GEnum", G_TYPE_ENUM); + PyGEnum_Type.tp_base = &PyInt_Type; + REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS); + PyGFlags_Type.tp_base = &PyInt_Type; - PyGMainLoop_Type.ob_type = &PyType_Type; - PyGMainLoop_Type.tp_alloc = PyType_GenericAlloc; - PyGMainLoop_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGMainLoop_Type)) - return; - PyDict_SetItemString(d, "MainLoop", (PyObject *)&PyGMainLoop_Type); + REGISTER_TYPE(d, PyGMainLoop_Type, "GMainLoop"); + REGISTER_TYPE(d, PyGMainContext_Type, "GMainContext"); - PyGMainContext_Type.ob_type = &PyType_Type; - PyGMainContext_Type.tp_alloc = PyType_GenericAlloc; - PyGMainContext_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGMainContext_Type)) - return; - PyDict_SetItemString(d, "MainContext", (PyObject *)&PyGMainContext_Type); - - PyGPointer_Type.ob_type = &PyType_Type; - PyGPointer_Type.tp_alloc = PyType_GenericAlloc; - PyGPointer_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGPointer_Type)) - return; - PyDict_SetItemString(d, "GPointer", (PyObject *)&PyGPointer_Type); - PyDict_SetItemString(PyGPointer_Type.tp_dict, "__gtype__", - o=pyg_type_wrapper_new(G_TYPE_POINTER)); - Py_DECREF(o); - /* glib version */ tuple = Py_BuildValue ("(iii)", glib_major_version, glib_minor_version, glib_micro_version); @@ -2281,7 +2275,7 @@ initgobject(void) PyModule_AddIntConstant(m, "PRIORITY_HIGH", G_PRIORITY_HIGH); PyModule_AddIntConstant(m, "PRIORITY_DEFAULT", G_PRIORITY_DEFAULT); PyModule_AddIntConstant(m, "PRIORITY_HIGH_IDLE", G_PRIORITY_HIGH_IDLE); - PyModule_AddIntConstant(m,"PRIORITY_DEFAULT_IDLE",G_PRIORITY_DEFAULT_IDLE); + PyModule_AddIntConstant(m, "PRIORITY_DEFAULT_IDLE",G_PRIORITY_DEFAULT_IDLE); PyModule_AddIntConstant(m, "PRIORITY_LOW", G_PRIORITY_LOW); PyModule_AddIntConstant(m, "IO_IN", G_IO_IN); diff --git a/gobject/pygenum.c b/gobject/pygenum.c new file mode 100644 index 00000000..c9444f0a --- /dev/null +++ b/gobject/pygenum.c @@ -0,0 +1,252 @@ +/* -*- 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: GEnum and GFlag wrappers + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "pygobject-private.h" +#include "pygenum.h" + +static const gchar *pygenum_class_id = "PyGEnum::class"; +static GQuark pygenum_class_key = 0; + +#define GET_INT(x) (((PyIntObject*)x)->ob_ival) +static int +pyg_enum_compare(PyGEnum *self, PyObject *other) +{ + if (!PyInt_CheckExact(other) && ((PyGEnum*)other)->gtype != self->gtype) { + PyErr_Warn(PyExc_Warning, "comparing different enum types"); + return -1; + } + + if (GET_INT(self) == GET_INT(other)) + return 0; + else if (GET_INT(self) > GET_INT(other)) + return -1; + else + return 1; +} +#undef GET_INT + +static PyObject * +pyg_enum_repr(PyGEnum *self) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + static char tmp[256]; + + enum_class = g_type_class_ref(self->gtype); + g_assert(G_IS_ENUM_CLASS(enum_class)); + + enum_value = g_enum_get_value(enum_class, self->parent.ob_ival); + g_assert(enum_value != 0); + + sprintf(tmp, "", enum_value->value_name, g_type_name(self->gtype)); + + g_type_class_unref(enum_class); + + return PyString_FromString(tmp); +} + +static PyObject * +pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "value", NULL }; + long value; + PyObject *pytc, *values, *ret; + GType gtype; + GEnumClass *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, &PyGEnum_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_ENUM_CLASS(g_type_class_ref(gtype)); + + if (value < 0 || value > eclass->n_values) { + PyErr_SetString(PyExc_ValueError, "value out of range"); + g_type_class_unref(eclass); + return NULL; + } + + values = PyObject_GetAttrString((PyObject *)type, "__enum_values__"); + if (!values) { + g_type_class_unref(eclass); + return NULL; + } + + if (!PyTuple_Check(values) || PyTuple_Size(values) != eclass->n_values) { + PyErr_SetString(PyExc_TypeError, "__enum_values__ badly formed"); + Py_DECREF(values); + g_type_class_unref(eclass); + return NULL; + } + + g_type_class_unref(eclass); + + ret = PyTuple_GetItem(values, value); + Py_INCREF(ret); + Py_DECREF(values); + return ret; +} + +PyObject* +pyg_enum_from_gtype (GType gtype, int value) +{ + PyObject *pyclass, *values, *retval; + + g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); + + pyclass = (PyObject*)g_type_get_qdata(gtype, pygenum_class_key); + g_assert(pyclass != NULL); + + values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, + "__enum_values__"); + retval = PyTuple_GetItem(values, value); + Py_INCREF(retval); + + return retval; +} + +PyObject * +pyg_enum_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype) +{ + PyObject *instance_dict, *stub, *values; + GEnumClass *eclass; + int i; + + g_return_val_if_fail(module != NULL, NULL); + g_return_val_if_fail(typename != NULL, NULL); + g_return_val_if_fail(g_type_is_a(gtype, G_TYPE_ENUM), NULL); + + instance_dict = PyDict_New(); + stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", + typename, (PyObject *)&PyGEnum_Type, + instance_dict); + Py_DECREF(instance_dict); + if (!stub) { + PyErr_SetString(PyExc_RuntimeError, "can't create const"); + return NULL; + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__module__", + PyString_FromString(PyModule_GetName(module))); + + if (!pygenum_class_key) + pygenum_class_key = g_quark_from_static_string(pygenum_class_id); + + g_type_set_qdata(gtype, pygenum_class_key, stub); + + /* Add it to the module name space */ + PyModule_AddObject(module, (char*)typename, stub); + Py_INCREF(stub); + + /* Register enum values */ + eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); + + values = PyTuple_New(eclass->n_values); + for (i = 0; i < eclass->n_values; i++) { + PyObject *item; + + item = ((PyTypeObject *)stub)->tp_alloc((PyTypeObject *)stub, 0); + ((PyIntObject*)item)->ob_ival = eclass->values[i].value; + ((PyGEnum*)item)->gtype = gtype; + + PyTuple_SetItem(values, i, item); + + PyModule_AddObject(module, + pyg_constant_strip_prefix(eclass->values[i].value_name, + strip_prefix), + item); + Py_INCREF(item); + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__enum_values__", values); + Py_DECREF(values); + + g_type_class_unref(eclass); + + return stub; +} + +PyTypeObject PyGEnum_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "gobject.GEnum", + sizeof(PyGEnum), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)pyg_enum_compare, /* tp_compare */ + (reprfunc)pyg_enum_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)pyg_enum_repr, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyInt_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + pyg_enum_new, /* tp_new */ +}; + diff --git a/gobject/pygenum.h b/gobject/pygenum.h new file mode 100644 index 00000000..cfa9a928 --- /dev/null +++ b/gobject/pygenum.h @@ -0,0 +1,54 @@ +/* -*- 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: GEnum and GFlag wrappers + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef __PYGENUM_H__ +#define __PYGENUM_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define PyGEnum_Check(x) (g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_ENUM)) + +typedef struct { + PyIntObject parent; + GType gtype; +} PyGEnum; + +PyTypeObject PyGEnum_Type; + +PyObject * pyg_enum_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype); +PyObject * pyg_enum_from_gtype (GType gtype, + int value); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PYGENUM_H__ */ diff --git a/gobject/pygflags.c b/gobject/pygflags.c new file mode 100644 index 00000000..2c37cc1e --- /dev/null +++ b/gobject/pygflags.c @@ -0,0 +1,367 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2004 Johan Dahlin + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "pygobject-private.h" +#include "pygflags.h" + +static const gchar *pygflags_class_id = "PyGFlags::class"; +static GQuark pygflags_class_key = 0; + +#define GET_INT_VALUE(x) (((PyIntObject*)x)->ob_ival) +static int +pyg_flags_compare(PyGFlags *self, PyObject *other) +{ + if (!PyInt_CheckExact(other) && ((PyGFlags*)other)->gtype != self->gtype) { + PyErr_Warn(PyExc_Warning, "comparing different flags types"); + return -1; + } + + if (GET_INT_VALUE(self) == GET_INT_VALUE(other)) + return 0; + else if (GET_INT_VALUE(self) > GET_INT_VALUE(other)) + return -1; + else + return 1; +} + +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++) { + 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, + self->parent.ob_ival); + + retval = g_strdup_printf("", tmp, + g_type_name(self->gtype)); + g_free(tmp); + + pyretval = PyString_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; + 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, &PyGFlags_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)); + + if (value < 0 || value > eclass->n_values) { + PyErr_SetString(PyExc_ValueError, "value out of range"); + g_type_class_unref(eclass); + return NULL; + } + + values = PyObject_GetAttrString((PyObject *)type, "__flags_values__"); + if (!values) { + g_type_class_unref(eclass); + return NULL; + } + + if (!PyTuple_Check(values) || PyTuple_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); + + ret = PyTuple_GetItem(values, value); + Py_INCREF(ret); + Py_DECREF(values); + return ret; +} + +PyObject* +pyg_flags_from_gtype (GType gtype, int value) +{ + PyObject *pyclass, *values, *retval; + + g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); + + pyclass = (PyObject*)g_type_get_qdata(gtype, pygflags_class_key); + g_assert(pyclass != NULL); + + values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, + "__flags_values__"); + retval = PyTuple_GetItem(values, value); + if (!retval) { + PyErr_Clear(); + + retval = ((PyTypeObject *)pyclass)->tp_alloc((PyTypeObject *)pyclass, 0); + g_assert(retval != NULL); + + ((PyIntObject*)retval)->ob_ival = value; + ((PyGFlags*)retval)->gtype = gtype; + } + + Py_INCREF(retval); + return retval; +} + +PyObject * +pyg_flags_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype) +{ + PyObject *instance_dict, *stub, *values; + GFlagsClass *eclass; + int i; + + g_return_val_if_fail(module != NULL, NULL); + g_return_val_if_fail(typename != NULL, NULL); + g_return_val_if_fail(g_type_is_a(gtype, G_TYPE_FLAGS), NULL); + + 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"); + return NULL; + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__module__", + PyString_FromString(PyModule_GetName(module))); + + /* Add it to the module name space */ + PyModule_AddObject(module, (char*)typename, stub); + Py_INCREF(stub); + + if (!pygflags_class_key) + pygflags_class_key = g_quark_from_static_string(pygflags_class_id); + + g_type_set_qdata(gtype, pygflags_class_key, stub); + + /* Register flag values */ + eclass = G_FLAGS_CLASS(g_type_class_ref(gtype)); + + values = PyTuple_New(eclass->n_values); + for (i = 0; i < eclass->n_values; i++) { + PyObject *item; + + item = ((PyTypeObject *)stub)->tp_alloc((PyTypeObject *)stub, 0); + ((PyIntObject*)item)->ob_ival = eclass->values[i].value; + ((PyGFlags*)item)->gtype = gtype; + + PyTuple_SetItem(values, i, item); + + PyModule_AddObject(module, + pyg_constant_strip_prefix(eclass->values[i].value_name, + strip_prefix), + item); + Py_INCREF(item); + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__flags_values__", values); + Py_DECREF(values); + + g_type_class_unref(eclass); + + return stub; +} + +static PyObject * +pyg_flags_and(PyGFlags *a, PyGFlags *b) +{ + if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) + return PyInt_Type.tp_as_number->nb_and((PyObject*)a, + (PyObject*)b); + + return pyg_flags_from_gtype(a->gtype, + GET_INT_VALUE(a) & GET_INT_VALUE(b)); +} + +static PyObject * +pyg_flags_or(PyGFlags *a, PyGFlags *b) +{ + if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) + return PyInt_Type.tp_as_number->nb_or((PyObject*)a, + (PyObject*)b); + + return pyg_flags_from_gtype(a->gtype, GET_INT_VALUE(a) | GET_INT_VALUE(b)); +} + +static PyObject * +pyg_flags_xor(PyGFlags *a, PyGFlags *b) +{ + if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) + return PyInt_Type.tp_as_number->nb_xor((PyObject*)a, + (PyObject*)b); + + return pyg_flags_from_gtype(a->gtype, + GET_INT_VALUE(a) ^ GET_INT_VALUE(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 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 */ +}; + +PyTypeObject PyGFlags_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "gobject.GFlags", + sizeof(PyGFlags), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)pyg_flags_compare, /* tp_compare */ + (reprfunc)pyg_flags_repr, /* tp_repr */ + &pyg_flags_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)pyg_flags_repr, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyInt_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + pyg_flags_new, /* tp_new */ +}; diff --git a/gobject/pygflags.h b/gobject/pygflags.h new file mode 100644 index 00000000..6bf93cd2 --- /dev/null +++ b/gobject/pygflags.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2004 Johan Dahlin + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef __PYGFLAGS_H__ +#define __PYGFLAGS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + PyIntObject parent; + GType gtype; +} PyGFlags; + +PyTypeObject PyGFlags_Type; + +#define PyGFlags_Check(x) (g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_FLAGS)) + +PyObject * pyg_flags_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype); +PyObject * pyg_flags_from_gtype (GType gtype, + int value); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PYGFLAGS_H__ */ diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h index 38eff227..da340c79 100644 --- a/gobject/pygobject-private.h +++ b/gobject/pygobject-private.h @@ -8,7 +8,6 @@ #define _INSIDE_PYGOBJECT_ #include "pygobject.h" - /* from gobjectmodule.c */ extern struct _PyGObject_Functions pygobject_api_functions; #define pyg_block_threads() G_STMT_START { \ @@ -108,4 +107,6 @@ PyObject * pyg_pointer_new (GType pointer_type, gpointer pointer); extern PyTypeObject PyGParamSpec_Type; PyObject *pyg_param_spec_new (GParamSpec *pspec); +extern char * pyg_constant_strip_prefix(gchar *name, const gchar *strip_prefix); + #endif diff --git a/gobject/pygobject.h b/gobject/pygobject.h index 594e2850..9292cec2 100644 --- a/gobject/pygobject.h +++ b/gobject/pygobject.h @@ -29,15 +29,15 @@ typedef struct { gboolean free_on_dealloc; } PyGBoxed; +#define pyg_boxed_get(v,t) ((t *)((PyGBoxed *)(v))->boxed) +#define pyg_boxed_check(v,typecode) (PyObject_TypeCheck(v, &PyGBoxed_Type) && ((PyGBoxed *)(v))->gtype == typecode) + typedef struct { PyObject_HEAD gpointer pointer; GType gtype; } PyGPointer; -#define pyg_boxed_get(v,t) ((t *)((PyGBoxed *)(v))->boxed) -#define pyg_boxed_check(v,typecode) (PyObject_TypeCheck(v, &PyGBoxed_Type) && ((PyGBoxed *)(v))->gtype == typecode) - #define pyg_pointer_get(v,t) ((t *)((PyGPointer *)(v))->pointer) #define pyg_pointer_check(v,typecode) (PyObject_TypeCheck(v, &PyGPointer_Type) && ((PyGPointer *)(v))->gtype == typecode) @@ -117,13 +117,25 @@ struct _PyGObject_Functions { GParameter *params, guint *nparams, PyObject **py_args); - PyObject* (* param_gvalue_as_pyobject) (const GValue* gvalue, + PyObject *(* param_gvalue_as_pyobject) (const GValue* gvalue, gboolean copy_boxed, const GParamSpec* pspec); int (* gvalue_from_param_pyobject) (GValue* value, PyObject* py_obj, const GParamSpec* pspec); - + PyTypeObject *enum_type; + PyObject *(*enum_add)(PyObject *module, + const char *typename, + const char *strip_prefix, + GType gtype); + PyObject* (*enum_from_gtype)(GType gtype, int value); + + PyTypeObject *flags_type; + PyObject *(*flags_add)(PyObject *module, + const char *typename, + const char *strip_prefix, + GType gtype); + PyObject* (*flags_from_gtype)(GType gtype, int value); }; #ifndef _INSIDE_PYGOBJECT_ @@ -168,6 +180,13 @@ struct _PyGObject_Functions *_PyGObject_API; #define pyg_parse_constructor_args (_PyGObject_API->parse_constructor_args) #define pyg_param_gvalue_from_pyobject (_PyGObject_API->value_from_pyobject) #define pyg_param_gvalue_as_pyobject (_PyGObject_API->value_as_pyobject) +#define PyGEnum_Type (*_PyGObject_API->enum_type) +#define pyg_enum_add (_PyGObject_API->enum_add) +#define pyg_enum_from_gtype (_PyGObject_API->enum_from_gtype) +#define PyGFlags_Type (*_PyGObject_API->flags_type) +#define pyg_flags_add (_PyGObject_API->flags_add) +#define pyg_flags_from_gtype (_PyGObject_API->flags_from_gtype) + #define pyg_block_threads() G_STMT_START { \ if (_PyGObject_API->block_threads != NULL) \ (* _PyGObject_API->block_threads)(); \ diff --git a/gobject/pygtype.c b/gobject/pygtype.c index e28c84c1..eff5e0df 100644 --- a/gobject/pygtype.c +++ b/gobject/pygtype.c @@ -22,6 +22,9 @@ #include "pygobject-private.h" +#include "pygenum.h" +#include "pygflags.h" + /* -------------- __gtype__ objects ---------------------------- */ typedef struct { @@ -652,9 +655,9 @@ pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed) return PyLong_FromUnsignedLongLong(val); } case G_TYPE_ENUM: - return PyInt_FromLong(g_value_get_enum(value)); + return pyg_enum_from_gtype(G_VALUE_TYPE(value), g_value_get_enum(value)); case G_TYPE_FLAGS: - return PyInt_FromLong(g_value_get_flags(value)); + return pyg_flags_from_gtype(G_VALUE_TYPE(value), g_value_get_flags(value)); case G_TYPE_FLOAT: return PyFloat_FromDouble(g_value_get_float(value)); case G_TYPE_DOUBLE: diff --git a/gobjectmodule.c b/gobjectmodule.c index ec9fcf49..6159ca90 100644 --- a/gobjectmodule.c +++ b/gobjectmodule.c @@ -26,6 +26,9 @@ #include "pygobject-private.h" +#include "pygenum.h" +#include "pygflags.h" + static PyObject *gerror_exc = NULL; static const gchar *pyginterface_type_id = "PyGInterface::type"; GQuark pyginterface_type_key = 0; @@ -1880,7 +1883,7 @@ static PyMethodDef pygobject_functions[] = { * * Returns: the stripped constant name. */ -static char * +char * pyg_constant_strip_prefix(gchar *name, const gchar *strip_prefix) { gint prefix_len; @@ -2158,12 +2161,35 @@ struct _PyGObject_Functions pygobject_api_functions = { &PyGParamSpec_Type, pyg_param_spec_new, pyg_param_spec_from_object, + pyg_pyobj_to_unichar_conv, pyg_parse_constructor_args, pyg_param_gvalue_as_pyobject, - pyg_param_gvalue_from_pyobject + pyg_param_gvalue_from_pyobject, + + &PyGEnum_Type, + pyg_enum_add, + pyg_enum_from_gtype, + + &PyGFlags_Type, + pyg_flags_add, + pyg_flags_from_gtype }; +#define REGISTER_TYPE(d, type, name) \ + type.ob_type = &PyType_Type; \ + type.tp_alloc = PyType_GenericAlloc; \ + type.tp_new = PyType_GenericNew; \ + if (PyType_Ready(&type)) \ + return; \ + PyDict_SetItemString(d, name, (PyObject *)&type); + +#define REGISTER_GTYPE(d, type, name, gtype) \ + REGISTER_TYPE(d, type, name); \ + PyDict_SetItemString(type.tp_dict, "__gtype__", \ + o=pyg_type_wrapper_new(gtype)); \ + Py_DECREF(o); + DL_EXPORT(void) initgobject(void) { @@ -2188,7 +2214,7 @@ initgobject(void) gerror_exc = PyErr_NewException("gobject.GError", PyExc_RuntimeError,NULL); PyDict_SetItemString(d, "GError", gerror_exc); - + PyGObject_Type.tp_alloc = PyType_GenericAlloc; PyGObject_Type.tp_new = PyType_GenericNew; pygobject_register_class(d, "GObject", G_TYPE_OBJECT, @@ -2196,55 +2222,23 @@ initgobject(void) PyDict_SetItemString(PyGObject_Type.tp_dict, "__gdoc__", pyg_object_descr_doc_get()); - PyGInterface_Type.ob_type = &PyType_Type; - PyGInterface_Type.tp_alloc = PyType_GenericAlloc; - PyGInterface_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGInterface_Type)) - return; - PyDict_SetItemString(d, "GInterface", (PyObject *)&PyGInterface_Type); - PyDict_SetItemString(PyGInterface_Type.tp_dict, "__gtype__", - o=pyg_type_wrapper_new(G_TYPE_INTERFACE)); - Py_DECREF(o); + REGISTER_GTYPE(d, PyGInterface_Type, "GInterface", G_TYPE_INTERFACE); PyDict_SetItemString(PyGInterface_Type.tp_dict, "__doc__", pyg_object_descr_doc_get()); PyDict_SetItemString(PyGInterface_Type.tp_dict, "__gdoc__", pyg_object_descr_doc_get()); pyginterface_type_key = g_quark_from_static_string(pyginterface_type_id); - PyGBoxed_Type.ob_type = &PyType_Type; - PyGBoxed_Type.tp_alloc = PyType_GenericAlloc; - PyGBoxed_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGBoxed_Type)) - return; - PyDict_SetItemString(d, "GBoxed", (PyObject *)&PyGBoxed_Type); - PyDict_SetItemString(PyGBoxed_Type.tp_dict, "__gtype__", - o=pyg_type_wrapper_new(G_TYPE_BOXED)); - Py_DECREF(o); + REGISTER_GTYPE(d, PyGBoxed_Type, "GBoxed", G_TYPE_BOXED); + REGISTER_GTYPE(d, PyGPointer_Type, "GPointer", G_TYPE_POINTER); + REGISTER_GTYPE(d, PyGEnum_Type, "GEnum", G_TYPE_ENUM); + PyGEnum_Type.tp_base = &PyInt_Type; + REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS); + PyGFlags_Type.tp_base = &PyInt_Type; - PyGMainLoop_Type.ob_type = &PyType_Type; - PyGMainLoop_Type.tp_alloc = PyType_GenericAlloc; - PyGMainLoop_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGMainLoop_Type)) - return; - PyDict_SetItemString(d, "MainLoop", (PyObject *)&PyGMainLoop_Type); + REGISTER_TYPE(d, PyGMainLoop_Type, "GMainLoop"); + REGISTER_TYPE(d, PyGMainContext_Type, "GMainContext"); - PyGMainContext_Type.ob_type = &PyType_Type; - PyGMainContext_Type.tp_alloc = PyType_GenericAlloc; - PyGMainContext_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGMainContext_Type)) - return; - PyDict_SetItemString(d, "MainContext", (PyObject *)&PyGMainContext_Type); - - PyGPointer_Type.ob_type = &PyType_Type; - PyGPointer_Type.tp_alloc = PyType_GenericAlloc; - PyGPointer_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyGPointer_Type)) - return; - PyDict_SetItemString(d, "GPointer", (PyObject *)&PyGPointer_Type); - PyDict_SetItemString(PyGPointer_Type.tp_dict, "__gtype__", - o=pyg_type_wrapper_new(G_TYPE_POINTER)); - Py_DECREF(o); - /* glib version */ tuple = Py_BuildValue ("(iii)", glib_major_version, glib_minor_version, glib_micro_version); @@ -2281,7 +2275,7 @@ initgobject(void) PyModule_AddIntConstant(m, "PRIORITY_HIGH", G_PRIORITY_HIGH); PyModule_AddIntConstant(m, "PRIORITY_DEFAULT", G_PRIORITY_DEFAULT); PyModule_AddIntConstant(m, "PRIORITY_HIGH_IDLE", G_PRIORITY_HIGH_IDLE); - PyModule_AddIntConstant(m,"PRIORITY_DEFAULT_IDLE",G_PRIORITY_DEFAULT_IDLE); + PyModule_AddIntConstant(m, "PRIORITY_DEFAULT_IDLE",G_PRIORITY_DEFAULT_IDLE); PyModule_AddIntConstant(m, "PRIORITY_LOW", G_PRIORITY_LOW); PyModule_AddIntConstant(m, "IO_IN", G_IO_IN); diff --git a/gtk/__init__.py b/gtk/__init__.py index a504ebcf..51090433 100644 --- a/gtk/__init__.py +++ b/gtk/__init__.py @@ -58,6 +58,8 @@ gdk.INPUT_READ = _gobject.IO_IN | _gobject.IO_HUP | _gobject.IO_ERR gdk.INPUT_WRITE = _gobject.IO_OUT | _gobject.IO_HUP gdk.INPUT_EXCEPTION = _gobject.IO_PRI +del _gobject + # Warnings class _Deprecated: from warnings import warn diff --git a/gtk/gdk.override b/gtk/gdk.override index 83652915..7684f17d 100644 --- a/gtk/gdk.override +++ b/gtk/gdk.override @@ -1261,7 +1261,7 @@ _wrap_gdk_event_tp_setattr(PyObject *self, char *attr, PyObject *value) event->scroll.state = PyInt_AsLong(value); return 0; } else if (!strcmp(attr, "direction")) { - INT_CHECK(); + INT_CHECK(); /* XXX: ENUM */ event->scroll.direction = PyInt_AsLong(value); return 0; } else if (!strcmp(attr, "device")) { @@ -1449,13 +1449,13 @@ _wrap_gdk_event_tp_getattr(PyObject *self, char *attr) if (!strcmp(attr, "y_root")) return PyFloat_FromDouble(event->crossing.y_root); if (!strcmp(attr, "mode")) - return PyInt_FromLong(event->crossing.mode); + return pyg_enum_from_gtype(GDK_TYPE_CROSSING_MODE, event->crossing.mode); if (!strcmp(attr, "detail")) return PyInt_FromLong(event->crossing.detail); if (!strcmp(attr, "focus")) return PyInt_FromLong(event->crossing.focus); if (!strcmp(attr, "state")) - return PyInt_FromLong(event->crossing.state); + return pyg_enum_from_gtype(GDK_TYPE_NOTIFY_TYPE, event->crossing.mode); break; case GDK_FOCUS_CHANGE: /*GdkEventFocus focus_change*/ if (!strcmp(attr, "__members__")) @@ -1491,7 +1491,7 @@ _wrap_gdk_event_tp_getattr(PyObject *self, char *attr) if (!strcmp(attr, "time")) return PyInt_FromLong(event->property.time); if (!strcmp(attr, "state")) - return PyInt_FromLong(event->property.state); + return pyg_enum_from_gtype(GDK_TYPE_PROPERTY_STATE, event->property.state); break; case GDK_SELECTION_CLEAR: /*GdkEventSelection selection*/ case GDK_SELECTION_REQUEST: /*GdkEventSelection selection*/ @@ -1560,7 +1560,7 @@ _wrap_gdk_event_tp_getattr(PyObject *self, char *attr) "type", "window", "send_event", "state"); if (!strcmp(attr, "state")) - return PyInt_FromLong(event->visibility.state); + return pyg_enum_from_gtype(GDK_TYPE_VISIBILITY_STATE, event->visibility.state); break; case GDK_NO_EXPOSE: /*GdkEventNoExpose no_expose*/ break; @@ -1579,7 +1579,7 @@ _wrap_gdk_event_tp_getattr(PyObject *self, char *attr) if (!strcmp(attr, "state")) return PyInt_FromLong(event->scroll.state); if (!strcmp(attr, "direction")) - return PyInt_FromLong(event->scroll.direction); + return pyg_enum_from_gtype(GDK_TYPE_SCROLL_DIRECTION, event->scroll.direction); if (!strcmp(attr, "device")) return pygobject_new((GObject *)event->scroll.device); if (!strcmp(attr, "x_root")) @@ -1603,7 +1603,7 @@ _wrap_gdk_event_tp_getattr(PyObject *self, char *attr) "type", "window", "send_event", "action", "name"); if (!strcmp(attr, "action")) - return PyInt_FromLong(event->setting.action); + return pyg_enum_from_gtype(GDK_TYPE_SETTING_ACTION, event->setting.action); if (!strcmp(attr, "name")) return PyString_FromString(event->setting.name); break; @@ -1612,7 +1612,7 @@ _wrap_gdk_event_tp_getattr(PyObject *self, char *attr) } if (!strcmp(attr, "type")) - return PyInt_FromLong(event->type); + return pyg_enum_from_gtype(GDK_TYPE_EVENT_TYPE, event->type); if (!strcmp(attr, "window")) return pygobject_new((GObject *)event->any.window); if (!strcmp(attr, "send_event")) @@ -2041,7 +2041,7 @@ _wrap_gdk_gc_tp_getattr(PyGObject *self, char *attr) if (!strcmp(attr, "clip_mask")) return pygobject_new((GObject *)gc.clip_mask); if (!strcmp(attr, "subwindow_mode")) - return PyInt_FromLong(gc.subwindow_mode); + return pyg_enum_from_gtype(GDK_TYPE_SUBWINDOW_MODE, gc.subwindow_mode); if (!strcmp(attr, "ts_x_origin")) return PyInt_FromLong(gc.ts_x_origin); if (!strcmp(attr, "ts_y_origin")) @@ -2055,11 +2055,11 @@ _wrap_gdk_gc_tp_getattr(PyGObject *self, char *attr) if (!strcmp(attr, "line_width")) return PyInt_FromLong(gc.line_width); if (!strcmp(attr, "line_style")) - return PyInt_FromLong(gc.line_style); + return pyg_enum_from_gtype(GDK_TYPE_LINE_STYLE, gc.line_style); if (!strcmp(attr, "cap_style")) - return PyInt_FromLong(gc.cap_style); + return pyg_enum_from_gtype(GDK_TYPE_CAP_STYLE, gc.cap_style); if (!strcmp(attr, "join_style")) - return PyInt_FromLong(gc.join_style); + return pyg_enum_from_gtype(GDK_TYPE_JOIN_STYLE, gc.join_style); { PyObject *name = PyString_FromString(attr); @@ -3857,7 +3857,7 @@ _wrap_gdk_window_get_decorations(PyGObject *self) gdk_window_get_decorations(GDK_WINDOW(self->obj), &decor); - return PyInt_FromLong(decor); + return pyg_enum_from_gtype(GDK_TYPE_WM_DECORATION, decor); } %% override gdk_window_get_toplevels noargs diff --git a/gtk/gtk.override b/gtk/gtk.override index d992196d..60225fcb 100644 --- a/gtk/gtk.override +++ b/gtk/gtk.override @@ -611,7 +611,8 @@ _wrap_gtk_box_query_child_packing(PyGObject *self, PyObject *args, gtk_box_query_child_packing(GTK_BOX(self->obj), child, &expand, &fill, &padding, &pack_type); - return Py_BuildValue("(iiii)", (int)expand, (int)fill, padding, pack_type); + return Py_BuildValue("(iiiO)", (int)expand, (int)fill, padding, + pyg_enum_from_gtype(GTK_TYPE_PACK_TYPE, pack_type)); } %% override gtk_combo_set_popdown_strings kwargs @@ -2113,7 +2114,8 @@ _wrap_gtk_notebook_query_tab_label_packing(PyGObject *self, PyObject *args, gtk_notebook_query_tab_label_packing(GTK_NOTEBOOK(self->obj), GTK_WIDGET(child->obj), &expand, &fill, &pack_type); - return Py_BuildValue("(iii)", expand, fill, pack_type); + return Py_BuildValue("(iiO)", expand, fill, + pyg_enum_from_gtype(GTK_TYPE_PACK_TYPE, pack_type)); } %% override gtk_list_insert_items kwargs @@ -3022,7 +3024,7 @@ _wrap_gtk_stock_lookup(PyGObject *self, PyObject *args) return Py_BuildValue("zziiz", item.stock_id, item.label, - item.modifier, + pyg_enum_from_gtype(GDK_TYPE_MODIFIER_TYPE, item.modifier), item.keyval, item.translation_domain); } @@ -3413,10 +3415,12 @@ _wrap_gtk_image_get_stock(PyGObject *self) if (stock_id) { return Py_BuildValue("(OO)", PyString_FromString(stock_id), - PyInt_FromLong(size)); + pyg_enum_from_gtype(GTK_TYPE_ICON_SIZE, size)); } else { Py_INCREF(Py_None); - return Py_BuildValue("(OO)", Py_None, PyInt_FromLong(size)); + return Py_BuildValue("(OO)", + Py_None, + pyg_enum_from_gtype(GTK_TYPE_ICON_SIZE, size)); } } %% @@ -3435,7 +3439,7 @@ _wrap_gtk_image_get_icon_set(PyGObject *self) } gtk_image_get_icon_set(GTK_IMAGE(self->obj), &icon_set, &size); return Py_BuildValue("(OO)", pygobject_new((GObject *)icon_set), - PyInt_FromLong(size)); + pyg_enum_from_gtype(GTK_TYPE_ICON_SIZE, size)); } %% override gtk_image_get noargs @@ -3561,7 +3565,9 @@ _wrap_gtk_scrolled_window_get_policy(PyGObject *self) gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(self->obj), &hscrollbar_policy, &vscrollbar_policy); - return Py_BuildValue("(ii)", hscrollbar_policy, vscrollbar_policy); + return Py_BuildValue("(OO)", + pyg_enum_from_gtype(GTK_TYPE_POLICY_TYPE, hscrollbar_policy), + pyg_enum_from_gtype(GTK_TYPE_POLICY_TYPE, vscrollbar_policy)); } %% override gtk_tooltips_data_get kwargs @@ -3616,7 +3622,7 @@ _wrap_gtk_accelerator_parse(PyGObject *self, PyObject *args, PyObject *kwargs) gtk_accelerator_parse((const gchar *)accel, &keyval, &modifier); - return Py_BuildValue("ii", keyval, modifier); + return Py_BuildValue("iO", keyval, pyg_enum_from_gtype(GDK_TYPE_MODIFIER_TYPE, modifier)); } %% override gtk_accel_map_lookup_entry kwargs @@ -3634,7 +3640,8 @@ _wrap_gtk_accel_map_lookup_entry(PyGObject *self, PyObject *args, return NULL; if (gtk_accel_map_lookup_entry((const gchar *)accel_path, &accel_key)) - return Py_BuildValue("ii", accel_key.accel_key, accel_key.accel_mods); + return Py_BuildValue("iO", accel_key.accel_key, + pyg_enum_from_gtype(GDK_TYPE_MODIFIER_TYPE, accel_key.accel_mods)); Py_INCREF(Py_None); return Py_None; diff --git a/gtk/gtktreeview.override b/gtk/gtktreeview.override index 5aff0fd3..044c8519 100644 --- a/gtk/gtktreeview.override +++ b/gtk/gtktreeview.override @@ -993,7 +993,8 @@ _wrap_gtk_tree_sortable_get_sort_column_id(PyGObject *self) /* if we don't have a sort column set, return (None, None) */ if (ret) - return Py_BuildValue("(ii)", sort_column_id, order); + return Py_BuildValue("(iO)", sort_column_id, + pyg_enum_from_gtype(GTK_TYPE_SORT_TYPE, order)); else return Py_BuildValue("(OO)", Py_None, Py_None); } @@ -2249,7 +2250,8 @@ _wrap_gtk_tree_view_get_drag_dest_row(PyGObject *self) PyObject *py_path = pygtk_tree_path_to_pyobject(path); gint py_pos = (gint) pos; gtk_tree_path_free(path); - return Py_BuildValue("(Oi)", py_path, py_pos); + return Py_BuildValue("(OO)", py_path, + pyg_enum_from_gtype(GTK_TYPE_TREE_VIEW_DROP_POSITION, py_pos)); } else { Py_INCREF(Py_None); return Py_None; @@ -2311,7 +2313,8 @@ _wrap_gtk_tree_view_get_dest_row_at_pos(PyGObject *self, PyObject *args, PyObject *py_path = pygtk_tree_path_to_pyobject(path); gint py_pos = (gint) pos; gtk_tree_path_free(path); - return Py_BuildValue("(Oi)", py_path, py_pos); + return Py_BuildValue("(OO)", py_path, + pyg_enum_from_gtype(GTK_TYPE_TREE_VIEW_DROP_POSITION, py_pos)); } Py_INCREF(Py_None); diff --git a/pygenum.c b/pygenum.c new file mode 100644 index 00000000..c9444f0a --- /dev/null +++ b/pygenum.c @@ -0,0 +1,252 @@ +/* -*- 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: GEnum and GFlag wrappers + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "pygobject-private.h" +#include "pygenum.h" + +static const gchar *pygenum_class_id = "PyGEnum::class"; +static GQuark pygenum_class_key = 0; + +#define GET_INT(x) (((PyIntObject*)x)->ob_ival) +static int +pyg_enum_compare(PyGEnum *self, PyObject *other) +{ + if (!PyInt_CheckExact(other) && ((PyGEnum*)other)->gtype != self->gtype) { + PyErr_Warn(PyExc_Warning, "comparing different enum types"); + return -1; + } + + if (GET_INT(self) == GET_INT(other)) + return 0; + else if (GET_INT(self) > GET_INT(other)) + return -1; + else + return 1; +} +#undef GET_INT + +static PyObject * +pyg_enum_repr(PyGEnum *self) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + static char tmp[256]; + + enum_class = g_type_class_ref(self->gtype); + g_assert(G_IS_ENUM_CLASS(enum_class)); + + enum_value = g_enum_get_value(enum_class, self->parent.ob_ival); + g_assert(enum_value != 0); + + sprintf(tmp, "", enum_value->value_name, g_type_name(self->gtype)); + + g_type_class_unref(enum_class); + + return PyString_FromString(tmp); +} + +static PyObject * +pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "value", NULL }; + long value; + PyObject *pytc, *values, *ret; + GType gtype; + GEnumClass *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, &PyGEnum_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_ENUM_CLASS(g_type_class_ref(gtype)); + + if (value < 0 || value > eclass->n_values) { + PyErr_SetString(PyExc_ValueError, "value out of range"); + g_type_class_unref(eclass); + return NULL; + } + + values = PyObject_GetAttrString((PyObject *)type, "__enum_values__"); + if (!values) { + g_type_class_unref(eclass); + return NULL; + } + + if (!PyTuple_Check(values) || PyTuple_Size(values) != eclass->n_values) { + PyErr_SetString(PyExc_TypeError, "__enum_values__ badly formed"); + Py_DECREF(values); + g_type_class_unref(eclass); + return NULL; + } + + g_type_class_unref(eclass); + + ret = PyTuple_GetItem(values, value); + Py_INCREF(ret); + Py_DECREF(values); + return ret; +} + +PyObject* +pyg_enum_from_gtype (GType gtype, int value) +{ + PyObject *pyclass, *values, *retval; + + g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); + + pyclass = (PyObject*)g_type_get_qdata(gtype, pygenum_class_key); + g_assert(pyclass != NULL); + + values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, + "__enum_values__"); + retval = PyTuple_GetItem(values, value); + Py_INCREF(retval); + + return retval; +} + +PyObject * +pyg_enum_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype) +{ + PyObject *instance_dict, *stub, *values; + GEnumClass *eclass; + int i; + + g_return_val_if_fail(module != NULL, NULL); + g_return_val_if_fail(typename != NULL, NULL); + g_return_val_if_fail(g_type_is_a(gtype, G_TYPE_ENUM), NULL); + + instance_dict = PyDict_New(); + stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", + typename, (PyObject *)&PyGEnum_Type, + instance_dict); + Py_DECREF(instance_dict); + if (!stub) { + PyErr_SetString(PyExc_RuntimeError, "can't create const"); + return NULL; + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__module__", + PyString_FromString(PyModule_GetName(module))); + + if (!pygenum_class_key) + pygenum_class_key = g_quark_from_static_string(pygenum_class_id); + + g_type_set_qdata(gtype, pygenum_class_key, stub); + + /* Add it to the module name space */ + PyModule_AddObject(module, (char*)typename, stub); + Py_INCREF(stub); + + /* Register enum values */ + eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); + + values = PyTuple_New(eclass->n_values); + for (i = 0; i < eclass->n_values; i++) { + PyObject *item; + + item = ((PyTypeObject *)stub)->tp_alloc((PyTypeObject *)stub, 0); + ((PyIntObject*)item)->ob_ival = eclass->values[i].value; + ((PyGEnum*)item)->gtype = gtype; + + PyTuple_SetItem(values, i, item); + + PyModule_AddObject(module, + pyg_constant_strip_prefix(eclass->values[i].value_name, + strip_prefix), + item); + Py_INCREF(item); + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__enum_values__", values); + Py_DECREF(values); + + g_type_class_unref(eclass); + + return stub; +} + +PyTypeObject PyGEnum_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "gobject.GEnum", + sizeof(PyGEnum), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)pyg_enum_compare, /* tp_compare */ + (reprfunc)pyg_enum_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)pyg_enum_repr, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyInt_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + pyg_enum_new, /* tp_new */ +}; + diff --git a/pygenum.h b/pygenum.h new file mode 100644 index 00000000..cfa9a928 --- /dev/null +++ b/pygenum.h @@ -0,0 +1,54 @@ +/* -*- 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: GEnum and GFlag wrappers + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef __PYGENUM_H__ +#define __PYGENUM_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define PyGEnum_Check(x) (g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_ENUM)) + +typedef struct { + PyIntObject parent; + GType gtype; +} PyGEnum; + +PyTypeObject PyGEnum_Type; + +PyObject * pyg_enum_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype); +PyObject * pyg_enum_from_gtype (GType gtype, + int value); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PYGENUM_H__ */ diff --git a/pygflags.c b/pygflags.c new file mode 100644 index 00000000..2c37cc1e --- /dev/null +++ b/pygflags.c @@ -0,0 +1,367 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2004 Johan Dahlin + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "pygobject-private.h" +#include "pygflags.h" + +static const gchar *pygflags_class_id = "PyGFlags::class"; +static GQuark pygflags_class_key = 0; + +#define GET_INT_VALUE(x) (((PyIntObject*)x)->ob_ival) +static int +pyg_flags_compare(PyGFlags *self, PyObject *other) +{ + if (!PyInt_CheckExact(other) && ((PyGFlags*)other)->gtype != self->gtype) { + PyErr_Warn(PyExc_Warning, "comparing different flags types"); + return -1; + } + + if (GET_INT_VALUE(self) == GET_INT_VALUE(other)) + return 0; + else if (GET_INT_VALUE(self) > GET_INT_VALUE(other)) + return -1; + else + return 1; +} + +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++) { + 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, + self->parent.ob_ival); + + retval = g_strdup_printf("", tmp, + g_type_name(self->gtype)); + g_free(tmp); + + pyretval = PyString_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; + 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, &PyGFlags_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)); + + if (value < 0 || value > eclass->n_values) { + PyErr_SetString(PyExc_ValueError, "value out of range"); + g_type_class_unref(eclass); + return NULL; + } + + values = PyObject_GetAttrString((PyObject *)type, "__flags_values__"); + if (!values) { + g_type_class_unref(eclass); + return NULL; + } + + if (!PyTuple_Check(values) || PyTuple_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); + + ret = PyTuple_GetItem(values, value); + Py_INCREF(ret); + Py_DECREF(values); + return ret; +} + +PyObject* +pyg_flags_from_gtype (GType gtype, int value) +{ + PyObject *pyclass, *values, *retval; + + g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); + + pyclass = (PyObject*)g_type_get_qdata(gtype, pygflags_class_key); + g_assert(pyclass != NULL); + + values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, + "__flags_values__"); + retval = PyTuple_GetItem(values, value); + if (!retval) { + PyErr_Clear(); + + retval = ((PyTypeObject *)pyclass)->tp_alloc((PyTypeObject *)pyclass, 0); + g_assert(retval != NULL); + + ((PyIntObject*)retval)->ob_ival = value; + ((PyGFlags*)retval)->gtype = gtype; + } + + Py_INCREF(retval); + return retval; +} + +PyObject * +pyg_flags_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype) +{ + PyObject *instance_dict, *stub, *values; + GFlagsClass *eclass; + int i; + + g_return_val_if_fail(module != NULL, NULL); + g_return_val_if_fail(typename != NULL, NULL); + g_return_val_if_fail(g_type_is_a(gtype, G_TYPE_FLAGS), NULL); + + 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"); + return NULL; + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__module__", + PyString_FromString(PyModule_GetName(module))); + + /* Add it to the module name space */ + PyModule_AddObject(module, (char*)typename, stub); + Py_INCREF(stub); + + if (!pygflags_class_key) + pygflags_class_key = g_quark_from_static_string(pygflags_class_id); + + g_type_set_qdata(gtype, pygflags_class_key, stub); + + /* Register flag values */ + eclass = G_FLAGS_CLASS(g_type_class_ref(gtype)); + + values = PyTuple_New(eclass->n_values); + for (i = 0; i < eclass->n_values; i++) { + PyObject *item; + + item = ((PyTypeObject *)stub)->tp_alloc((PyTypeObject *)stub, 0); + ((PyIntObject*)item)->ob_ival = eclass->values[i].value; + ((PyGFlags*)item)->gtype = gtype; + + PyTuple_SetItem(values, i, item); + + PyModule_AddObject(module, + pyg_constant_strip_prefix(eclass->values[i].value_name, + strip_prefix), + item); + Py_INCREF(item); + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__flags_values__", values); + Py_DECREF(values); + + g_type_class_unref(eclass); + + return stub; +} + +static PyObject * +pyg_flags_and(PyGFlags *a, PyGFlags *b) +{ + if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) + return PyInt_Type.tp_as_number->nb_and((PyObject*)a, + (PyObject*)b); + + return pyg_flags_from_gtype(a->gtype, + GET_INT_VALUE(a) & GET_INT_VALUE(b)); +} + +static PyObject * +pyg_flags_or(PyGFlags *a, PyGFlags *b) +{ + if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) + return PyInt_Type.tp_as_number->nb_or((PyObject*)a, + (PyObject*)b); + + return pyg_flags_from_gtype(a->gtype, GET_INT_VALUE(a) | GET_INT_VALUE(b)); +} + +static PyObject * +pyg_flags_xor(PyGFlags *a, PyGFlags *b) +{ + if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) + return PyInt_Type.tp_as_number->nb_xor((PyObject*)a, + (PyObject*)b); + + return pyg_flags_from_gtype(a->gtype, + GET_INT_VALUE(a) ^ GET_INT_VALUE(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 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 */ +}; + +PyTypeObject PyGFlags_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "gobject.GFlags", + sizeof(PyGFlags), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)pyg_flags_compare, /* tp_compare */ + (reprfunc)pyg_flags_repr, /* tp_repr */ + &pyg_flags_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)pyg_flags_repr, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyInt_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + pyg_flags_new, /* tp_new */ +}; diff --git a/pygflags.h b/pygflags.h new file mode 100644 index 00000000..6bf93cd2 --- /dev/null +++ b/pygflags.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2004 Johan Dahlin + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef __PYGFLAGS_H__ +#define __PYGFLAGS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + PyIntObject parent; + GType gtype; +} PyGFlags; + +PyTypeObject PyGFlags_Type; + +#define PyGFlags_Check(x) (g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_FLAGS)) + +PyObject * pyg_flags_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype); +PyObject * pyg_flags_from_gtype (GType gtype, + int value); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PYGFLAGS_H__ */ diff --git a/pygobject-private.h b/pygobject-private.h index 38eff227..da340c79 100644 --- a/pygobject-private.h +++ b/pygobject-private.h @@ -8,7 +8,6 @@ #define _INSIDE_PYGOBJECT_ #include "pygobject.h" - /* from gobjectmodule.c */ extern struct _PyGObject_Functions pygobject_api_functions; #define pyg_block_threads() G_STMT_START { \ @@ -108,4 +107,6 @@ PyObject * pyg_pointer_new (GType pointer_type, gpointer pointer); extern PyTypeObject PyGParamSpec_Type; PyObject *pyg_param_spec_new (GParamSpec *pspec); +extern char * pyg_constant_strip_prefix(gchar *name, const gchar *strip_prefix); + #endif diff --git a/pygobject.h b/pygobject.h index 594e2850..9292cec2 100644 --- a/pygobject.h +++ b/pygobject.h @@ -29,15 +29,15 @@ typedef struct { gboolean free_on_dealloc; } PyGBoxed; +#define pyg_boxed_get(v,t) ((t *)((PyGBoxed *)(v))->boxed) +#define pyg_boxed_check(v,typecode) (PyObject_TypeCheck(v, &PyGBoxed_Type) && ((PyGBoxed *)(v))->gtype == typecode) + typedef struct { PyObject_HEAD gpointer pointer; GType gtype; } PyGPointer; -#define pyg_boxed_get(v,t) ((t *)((PyGBoxed *)(v))->boxed) -#define pyg_boxed_check(v,typecode) (PyObject_TypeCheck(v, &PyGBoxed_Type) && ((PyGBoxed *)(v))->gtype == typecode) - #define pyg_pointer_get(v,t) ((t *)((PyGPointer *)(v))->pointer) #define pyg_pointer_check(v,typecode) (PyObject_TypeCheck(v, &PyGPointer_Type) && ((PyGPointer *)(v))->gtype == typecode) @@ -117,13 +117,25 @@ struct _PyGObject_Functions { GParameter *params, guint *nparams, PyObject **py_args); - PyObject* (* param_gvalue_as_pyobject) (const GValue* gvalue, + PyObject *(* param_gvalue_as_pyobject) (const GValue* gvalue, gboolean copy_boxed, const GParamSpec* pspec); int (* gvalue_from_param_pyobject) (GValue* value, PyObject* py_obj, const GParamSpec* pspec); - + PyTypeObject *enum_type; + PyObject *(*enum_add)(PyObject *module, + const char *typename, + const char *strip_prefix, + GType gtype); + PyObject* (*enum_from_gtype)(GType gtype, int value); + + PyTypeObject *flags_type; + PyObject *(*flags_add)(PyObject *module, + const char *typename, + const char *strip_prefix, + GType gtype); + PyObject* (*flags_from_gtype)(GType gtype, int value); }; #ifndef _INSIDE_PYGOBJECT_ @@ -168,6 +180,13 @@ struct _PyGObject_Functions *_PyGObject_API; #define pyg_parse_constructor_args (_PyGObject_API->parse_constructor_args) #define pyg_param_gvalue_from_pyobject (_PyGObject_API->value_from_pyobject) #define pyg_param_gvalue_as_pyobject (_PyGObject_API->value_as_pyobject) +#define PyGEnum_Type (*_PyGObject_API->enum_type) +#define pyg_enum_add (_PyGObject_API->enum_add) +#define pyg_enum_from_gtype (_PyGObject_API->enum_from_gtype) +#define PyGFlags_Type (*_PyGObject_API->flags_type) +#define pyg_flags_add (_PyGObject_API->flags_add) +#define pyg_flags_from_gtype (_PyGObject_API->flags_from_gtype) + #define pyg_block_threads() G_STMT_START { \ if (_PyGObject_API->block_threads != NULL) \ (* _PyGObject_API->block_threads)(); \ diff --git a/pygtype.c b/pygtype.c index e28c84c1..eff5e0df 100644 --- a/pygtype.c +++ b/pygtype.c @@ -22,6 +22,9 @@ #include "pygobject-private.h" +#include "pygenum.h" +#include "pygflags.h" + /* -------------- __gtype__ objects ---------------------------- */ typedef struct { @@ -652,9 +655,9 @@ pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed) return PyLong_FromUnsignedLongLong(val); } case G_TYPE_ENUM: - return PyInt_FromLong(g_value_get_enum(value)); + return pyg_enum_from_gtype(G_VALUE_TYPE(value), g_value_get_enum(value)); case G_TYPE_FLAGS: - return PyInt_FromLong(g_value_get_flags(value)); + return pyg_flags_from_gtype(G_VALUE_TYPE(value), g_value_get_flags(value)); case G_TYPE_FLOAT: return PyFloat_FromDouble(g_value_get_float(value)); case G_TYPE_DOUBLE: diff --git a/tests/Makefile.am b/tests/Makefile.am index 8324aeff..c592b968 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,6 @@ tests = \ conversion.py \ + enum.py \ signal.py check-local: diff --git a/tests/common.py b/tests/common.py new file mode 100644 index 00000000..ff2eef90 --- /dev/null +++ b/tests/common.py @@ -0,0 +1,16 @@ +import os +import sys + +# Don't insert before . (first in list) +sys.path.insert(1, os.path.join('..')) + +path = os.path.abspath(os.path.join('..', 'gtk')) +import gobject +import atk +import pango +import gtk +from gtk import gdk +from gtk import glade + +import ltihooks +ltihooks.uninstall() diff --git a/tests/conversion.py b/tests/conversion.py index 1fe8c22a..dece7bd9 100644 --- a/tests/conversion.py +++ b/tests/conversion.py @@ -2,7 +2,7 @@ import unittest -import gtk +from common import gtk class Tests(unittest.TestCase): diff --git a/tests/runtests.py b/tests/runtests.py index f3559f54..83b6013b 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -4,7 +4,7 @@ import os import sys import unittest -SKIP_FILES = ['runtests'] +SKIP_FILES = ['common', 'runtests'] dir = os.path.split(os.path.abspath(__file__))[0] os.chdir(dir) diff --git a/tests/signal.py b/tests/signal.py index ce328014..65eda262 100644 --- a/tests/signal.py +++ b/tests/signal.py @@ -2,7 +2,7 @@ import unittest -import gobject +from common import gobject class C(gobject.GObject): __gsignals__ = { 'my_signal': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, -- cgit v1.2.1