From b934ad8c18e8190f85aa5346a630eb723f0cce2a Mon Sep 17 00:00:00 2001 From: Yevgen Muntyan <17531749+muntyan@users.noreply.github.com> Date: Sat, 29 Apr 2006 11:10:57 -0500 Subject: [PATCH] Updated codegen to pygtk-2.8 --- m4/moo-pygtk.m4 | 38 ++++++++++ moo/mooedit/mooedit-actions.c | 2 +- moo/moopython/codegen/argtypes.py | 96 +++++++++++++++++-------- moo/moopython/codegen/codegen.py | 87 ++++++++++++++++++---- moo/moopython/codegen/definitions.py | 13 ++-- moo/moopython/codegen/override.py | 49 +++++++++++-- moo/moopython/codegen/reversewrapper.py | 32 ++++++--- moo/moopython/plugins/pytest.py | 6 +- moo/moopython/pygtk/Makefile.incl | 18 ++--- moo/moopython/pygtk/mooedit-pygtk.defs | 6 ++ moo/moopython/pygtk/mooutils-pygtk.defs | 6 ++ 11 files changed, 281 insertions(+), 72 deletions(-) diff --git a/m4/moo-pygtk.m4 b/m4/moo-pygtk.m4 index 4bf3603d..a5db2ed9 100644 --- a/m4/moo-pygtk.m4 +++ b/m4/moo-pygtk.m4 @@ -1,3 +1,37 @@ +############################################################################## +# _MOO_AC_PYGTK_CODEGEN +# +AC_DEFUN([_MOO_AC_PYGTK_CODEGEN],[ + AC_ARG_WITH([custom-codegen], AC_HELP_STRING([--with-custom-codegen], [whether to use custom copy of pygtk codegen (default = autodetect)]),[ + if test x$with_custom_codegen = "xno"; then + MOO_USE_CUSTOM_CODEGEN="no" + AC_MSG_NOTICE([using installed codegen]) + else + MOO_USE_CUSTOM_CODEGEN="yes" + AC_MSG_NOTICE([using patched codegen]) + fi + ],[ + if $PKG_CONFIG "pygtk-2.0 >= 2.8"; then + AC_MSG_NOTICE([pygtk >= 2.8, using patched codegen]) + MOO_USE_CUSTOM_CODEGEN=yes + else + AC_MSG_NOTICE([pygtk < 2.8, using installed codegen]) + MOO_USE_CUSTOM_CODEGEN=no + fi + + ]) + + PYGTK_CODEGEN_DIR=`$PKG_CONFIG --variable=codegendir pygtk-2.0` + AC_SUBST(PYGTK_CODEGEN_DIR) + + if test x$MOO_USE_CUSTOM_CODEGEN != xyes; then + AC_MSG_NOTICE([pygtk codegen dir: $PYGTK_CODEGEN_DIR]) + fi + + AM_CONDITIONAL(MOO_USE_CUSTOM_CODEGEN, test x$MOO_USE_CUSTOM_CODEGEN = "xyes") +]) + + ############################################################################## # _MOO_AC_CHECK_PYGTK_MINGW(version,action-if-found,action-if-not-found) # checks pygtk stuff for mingw, it's broken @@ -35,8 +69,11 @@ AC_DEFUN([_MOO_AC_CHECK_PYGTK_MINGW],[ AC_SUBST(PYGTK_CFLAGS) PYGTK_DEFS_DIR=$PYTHON_PREFIX/share/pygtk/2.0/defs AC_SUBST(PYGTK_DEFS_DIR) + PYGTK_CODEGEN_DIR=`$PKG_CONFIG --variable=codegendir pygtk-2.0` + AC_SUBST(PYGTK_CODEGEN_DIR) AC_MSG_NOTICE([pygtk defs dir: $PYGTK_DEFS_DIR]) $2 + _MOO_AC_PYGTK_CODEGEN ],[ AC_MSG_RESULT([not found]) $3 @@ -76,6 +113,7 @@ AC_DEFUN([_MOO_AC_CHECK_PYGTK_UNIX],[ PYGTK_DEFS_DIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0` AC_SUBST(PYGTK_DEFS_DIR) AC_MSG_NOTICE([pygtk defs dir: $PYGTK_DEFS_DIR]) + _MOO_AC_PYGTK_CODEGEN ],[ AC_MSG_RESULT(no) $3 diff --git a/moo/mooedit/mooedit-actions.c b/moo/mooedit/mooedit-actions.c index a9dbebd1..0af8c93f 100644 --- a/moo/mooedit/mooedit-actions.c +++ b/moo/mooedit/mooedit-actions.c @@ -802,7 +802,7 @@ moo_edit_action_class_init (MooEditActionClass *klass) G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (MooEditActionClass, check_state), g_signal_accumulator_true_handled, NULL, - _moo_marshal_VOID__VOID, + _moo_marshal_BOOLEAN__VOID, G_TYPE_BOOLEAN, 0); } diff --git a/moo/moopython/codegen/argtypes.py b/moo/moopython/codegen/argtypes.py index 3970d445..b8134a4f 100644 --- a/moo/moopython/codegen/argtypes.py +++ b/moo/moopython/codegen/argtypes.py @@ -199,16 +199,36 @@ class IntArg(ArgType): info.codeafter.append(' return PyInt_FromLong(ret);') class UIntArg(ArgType): + dflt = (' if (py_%(name)s) {\n' + ' if (PyLong_Check(py_%(name)s))\n' + ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' + ' else if (PyInt_Check(py_%(name)s))\n' + ' %(name)s = PyInt_AsLong(py_%(name)s);\n' + ' else\n' + ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n' + ' if (PyErr_Occurred())\n' + ' return NULL;\n' + ' }\n') + before = (' if (PyLong_Check(py_%(name)s))\n' + ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' + ' else if (PyInt_Check(py_%(name)s))\n' + ' %(name)s = PyInt_AsLong(py_%(name)s);\n' + ' else\n' + ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n' + ' if (PyErr_Occurred())\n' + ' return NULL;\n') def write_param(self, ptype, pname, pdflt, pnull, info): - if pdflt: - info.varlist.add(ptype, pname + ' = ' + pdflt) - else: - info.varlist.add(ptype, pname) - info.arglist.append(pname) - info.add_parselist('I', ['&' + pname], [pname]) + if not pdflt: + pdflt = '0'; + + info.varlist.add(ptype, pname + ' = ' + pdflt) + info.codebefore.append(self.dflt % {'name':pname}) + info.varlist.add('PyObject', "*py_" + pname + ' = NULL') + info.arglist.append(pname) + info.add_parselist('O', ['&py_' + pname], [pname]) def write_return(self, ptype, ownsreturn, info): info.varlist.add(ptype, 'ret') - info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n') + info.codeafter.append(' return PyLong_FromUnsignedLong(ret);') class SizeArg(ArgType): @@ -288,22 +308,30 @@ class TimeTArg(ArgType): info.codeafter.append(' return PyInt_FromLong(ret);') class ULongArg(ArgType): - dflt = ' if (py_%(name)s)\n' \ - ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' - before = ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' def write_param(self, ptype, pname, pdflt, pnull, info): - if pdflt: - info.varlist.add('gulong', pname + ' = ' + pdflt) - info.codebefore.append(self.dflt % {'name':pname}) - else: - info.varlist.add('gulong', pname) - info.codebefore.append(self.before % {'name':pname}) - info.varlist.add('PyObject', "*py_" + pname + ' = NULL') - info.arglist.append(pname) - info.add_parselist('O!', ['&PyLong_Type', '&py_' + pname], [pname]) + if pdflt: + info.varlist.add('unsigned long', pname + ' = ' + pdflt) + else: + info.varlist.add('unsigned long', pname) + info.arglist.append(pname) + info.add_parselist('k', ['&' + pname], [pname]) def write_return(self, ptype, ownsreturn, info): - info.varlist.add('gulong', 'ret') - info.codeafter.append(' return PyLong_FromUnsignedLong(ret);') + info.varlist.add(ptype, 'ret') + info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n') + +class UInt32Arg(ULongArg): + def write_param(self, ptype, pname, pdflt, pnull, info): + ULongArg.write_param(self, ptype, pname, pdflt, pnull, info) + ## if sizeof(unsigned long) > sizeof(unsigned int), we need to + ## check the value is within guint32 range + if struct.calcsize('L') > struct.calcsize('I'): + info.codebefore.append(( + ' if (%(pname)s > G_MAXUINT32) {\n' + ' PyErr_SetString(PyExc_ValueError,\n' + ' "Value out of range in conversion of"\n' + ' " %(pname)s parameter to unsigned 32 bit integer");\n' + ' return NULL;\n' + ' }\n') % vars()) class Int64Arg(ArgType): def write_param(self, ptype, pname, pdflt, pnull, info): @@ -555,7 +583,7 @@ class BoxedArg(ArgType): info.varlist.add('const ' + self.typename, '*ret') else: info.varlist.add(self.typename, '*ret') - ret = 'ret' + ret = 'ret' else: info.varlist.add(self.typename, 'ret') ret = '&ret' @@ -786,6 +814,20 @@ class PyObjectArg(ArgType): ' Py_INCREF(ret);\n' ' return ret;') +class CairoArg(ArgType): + def write_param(self, ptype, pname, pdflt, pnull, info): + info.varlist.add('PycairoContext', '*' + pname) + info.add_parselist('O!', ['&PycairoContext_Type', '&' + pname], [pname]) + info.arglist.append('%s->ctx' % pname) + def write_return(self, ptype, ownsreturn, info): + info.varlist.add("cairo_t", "*ret") + if ownsreturn: + info.codeafter.append(' return PycairoContext_FromContext(ret, NULL, NULL);') + else: + info.codeafter.append(' cairo_reference(ret);\n' + ' return PycairoContext_FromContext(ret, NULL, NULL);') + + class ArgMatcher: def __init__(self): self.argtypes = {} @@ -937,13 +979,7 @@ matcher.register('gboolean', arg) arg = TimeTArg() matcher.register('time_t', arg) -# If the system maxint is smaller than unsigned int, we need to use -# Long objects with PyLong_AsUnsignedLong -if sys.maxint >= (1L << 32): - matcher.register('guint32', arg) -else: - arg = ULongArg() - matcher.register('guint32', arg) +matcher.register('guint32', UInt32Arg()) arg = ULongArg() matcher.register('gulong', arg) @@ -984,3 +1020,5 @@ matcher.register('GdkNativeWindow', ULongArg()) matcher.register_object('GObject', None, 'G_TYPE_OBJECT') del arg + +matcher.register('cairo_t*', CairoArg()) diff --git a/moo/moopython/codegen/codegen.py b/moo/moopython/codegen/codegen.py index 74a56bcd..058a5c4c 100755 --- a/moo/moopython/codegen/codegen.py +++ b/moo/moopython/codegen/codegen.py @@ -340,6 +340,8 @@ class Wrapper: if self.overrides.is_overriden(funcname): data = self.overrides.override(funcname) self.write_function(funcname, data) + self.objinfo.has_new_constructor_api = ( + self.objinfo.typecode in self.overrides.newstyle_constructors) else: # ok, a hack to determine if we should use new-style constructores :P if getattr(self, 'write_property_based_constructor', None) is not None: @@ -379,11 +381,18 @@ class Wrapper: def get_methflags(self, funcname): if self.overrides.wants_kwargs(funcname): - return 'METH_VARARGS|METH_KEYWORDS' + flags = 'METH_VARARGS|METH_KEYWORDS' elif self.overrides.wants_noargs(funcname): - return 'METH_NOARGS' + flags = 'METH_NOARGS' + elif self.overrides.wants_onearg(funcname): + flags = 'METH_O' else: - return 'METH_VARARGS' + flags = 'METH_VARARGS' + if self.overrides.is_staticmethod(funcname): + flags += '|METH_STATIC' + elif self.overrides.is_classmethod(funcname): + flags += '|METH_CLASS' + return flags def write_function(self, funcname, data): lineno, filename = self.overrides.getstartline(funcname) @@ -563,6 +572,7 @@ class Wrapper: self.fp.write(' PyObject *o;\n') self.fp.write( ' %(klass)sClass *klass = %(class_cast_macro)s(gclass);\n' + ' PyObject *gsignals = PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");\n' % vars()) for name, cname in virtuals: @@ -572,8 +582,9 @@ class Wrapper: 'is currently not supported */\n' % vars()) else: self.fp.write(''' - if ((o = PyDict_GetItemString(pyclass->tp_dict, (char*)"%(do_name)s")) - && !PyObject_TypeCheck(o, &PyCFunction_Type)) + if ((o = PyDict_GetItemString(pyclass->tp_dict, "%(do_name)s")) + && !PyObject_TypeCheck(o, &PyCFunction_Type) + && !(gsignals && PyDict_GetItemString(gsignals, "%(name)s"))) klass->%(name)s = %(cname)s;\n''' % vars()) self.fp.write(' return 0;\n}\n') @@ -587,7 +598,8 @@ class Wrapper: if not self.objinfo.fields: return '0' getsets = [] - for ftype, fname in self.objinfo.fields: + for ftype, cfname in self.objinfo.fields: + fname = cfname.replace('.', '_') gettername = '0' settername = '0' attrname = self.objinfo.c_name + '.' + fname @@ -608,7 +620,7 @@ class Wrapper: self.fp.write(self.getter_tmpl % { 'funcname': funcname, 'varlist': info.varlist, - 'field': self.get_field_accessor(fname), + 'field': self.get_field_accessor(cfname), 'codeafter': info.get_codeafter() }) gettername = funcname except: @@ -741,14 +753,25 @@ class GObjectWrapper(Wrapper): return substdict def write_default_constructor(self): + try: + parent = self.parser.find_object(self.objinfo.parent) + except ValueError: + parent = None + if parent is not None: + ## just like the constructor is inheritted, we should inherit the new API compatibility flag + self.objinfo.has_new_constructor_api = parent.has_new_constructor_api + elif self.objinfo.parent == 'GObject': + self.objinfo.has_new_constructor_api = True return '0' def write_property_based_constructor(self, constructor): + self.objinfo.has_new_constructor_api = True out = self.fp print >> out, "static int" print >> out, '_wrap_%s(PyGObject *self, PyObject *args,'\ ' PyObject *kwargs)\n{' % constructor.c_name - print >> out, " GType obj_type = pyg_type_from_object((PyObject *) self);" + if constructor.params: + print >> out, " GType obj_type = pyg_type_from_object((PyObject *) self);" def py_str_list_to_c(arg): if arg: @@ -794,7 +817,7 @@ class GObjectWrapper(Wrapper): print >> out, " if (!pyg_parse_constructor_args(obj_type, arg_names, prop_names," print >> out, " params, &nparams, parsed_args))" print >> out, " return -1;" - print >> out, " self->obj = g_object_newv(obj_type, nparams, params);" + print >> out, " pygobject_constructv(self, nparams, params);\n" print >> out, " for (i = 0; i < nparams; ++i)" print >> out, " g_value_unset(¶ms[i].value);" else: @@ -808,7 +831,7 @@ class GObjectWrapper(Wrapper): print >> out, ' if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char*)":%s.__init__", kwlist))' % classname print >> out, " return -1;" print >> out - print >> out, " self->obj = g_object_newv(obj_type, 0, NULL);" + print >> out, " pygobject_constructv(self, 0, NULL);\n" print >> out, \ ' if (!self->obj) {\n' \ @@ -820,7 +843,6 @@ class GObjectWrapper(Wrapper): print >> out, " g_object_ref(self->obj);\n" print >> out, \ - ' pygobject_register_wrapper((PyObject *)self);\n' \ ' return 0;\n' \ '}\n\n' % { 'typename': classname } return "_wrap_%s" % constructor.c_name @@ -997,6 +1019,11 @@ def write_headers(data, fp): fp.resetline() fp.write('\n\n') +def write_body(data, fp): + fp.write(data) + fp.resetline() + fp.write('\n\n') + def write_imports(overrides, fp): fp.write('/* ---------- types from other modules ---------- */\n') for module, pyname, cname in overrides.get_imports(): @@ -1014,10 +1041,39 @@ def write_type_declarations(parser, fp): fp.write('PyTypeObject Py' + interface.c_name + '_Type;\n') fp.write('\n') + +def sort_parent_children(objects): + objects = list(objects) + modified = True + while modified: + modified = False + parent_index = None + child_index = None + for i, obj in enumerate(objects): + if obj.parent == 'GObject': + continue + if obj.parent not in [info.c_name for info in objects[:i]]: + for j, info in enumerate(objects[i+1:]): + if info.c_name == obj.parent: + parent_index = i + 1 + j + child_index = i + break + else: + continue + break + if child_index is not None and parent_index is not None: + if child_index != parent_index: + objects.insert(child_index, objects.pop(parent_index)) + modified = True + return objects + def write_classes(parser, overrides, fp): + ## Sort the objects, so that we generate code for the parent types + ## before their children. + objects = sort_parent_children(parser.objects) for klass, items in ((GBoxedWrapper, parser.boxes), (GPointerWrapper, parser.pointers), - (GObjectWrapper, parser.objects), + (GObjectWrapper, objects), (GInterfaceWrapper, parser.interfaces)): for item in items: instance = klass(parser, item, overrides, fp) @@ -1116,6 +1172,12 @@ def write_registers(parser, fp): fp.write(' pygobject_register_class(d, "' + obj.c_name + '", ' + obj.typecode + ', &Py' + obj.c_name + '_Type, NULL);\n') + if obj.has_new_constructor_api: + fp.write(' pyg_set_object_has_new_constructor(%s);\n' % obj.typecode) + else: + print >> sys.stderr, ("Warning: Constructor for %s needs to be updated to new API\n" + " See http://live.gnome.org/PyGTK_2fWhatsNew28" + "#update-constructors") % obj.c_name if obj.class_init_func is not None: fp.write(' pyg_register_class_init(%s, %s);\n' % (obj.typecode, obj.class_init_func)) @@ -1125,6 +1187,7 @@ def write_source(parser, overrides, prefix, fp=FileOutput(sys.stdout)): write_headers(overrides.get_headers(), fp) write_imports(overrides, fp) write_type_declarations(parser, fp) + write_body(overrides.get_body(), fp) write_classes(parser, overrides, fp) wrapper = Wrapper(parser, None, overrides, fp) diff --git a/moo/moopython/codegen/definitions.py b/moo/moopython/codegen/definitions.py index 3b4247e9..73be6dba 100644 --- a/moo/moopython/codegen/definitions.py +++ b/moo/moopython/codegen/definitions.py @@ -19,7 +19,7 @@ class Parameter(object): self.pname = pname self.pdflt = pdflt self.pnull = pnull - + def __len__(self): return 4 def __getitem__(self, i): return (self.ptype, self.pname, self.pdflt, self.pnull)[i] @@ -77,6 +77,7 @@ class ObjectDef(Definition): self.fields = [] self.implements = [] self.class_init_func = None + self.has_new_constructor_api = False for arg in get_valid_scheme_definitions(args): if arg[0] == 'in-module': self.module = arg[1] @@ -103,7 +104,7 @@ class ObjectDef(Definition): fp.write('(define-object ' + self.name + '\n') if self.module: fp.write(' (in-module "' + self.module + '")\n') - if self.parent != (None, None): + if self.parent != (None, None): fp.write(' (parent "' + self.parent + '")\n') for interface in self.implements: fp.write(' (implements "' + interface + '")\n') @@ -315,7 +316,7 @@ class MethodDefBase(Definition): elif arg[0] == 'deprecated': self.deprecated = arg[1] else: - sys.stderr.write("Warning: %s argument unsupported.\n" + sys.stderr.write("Warning: %s argument unsupported.\n" % (arg[0])) dump = 1 if dump: @@ -323,7 +324,7 @@ class MethodDefBase(Definition): if self.caller_owns_return is None and self.ret is not None: self.guess_return_value_ownership() - + def merge(self, old, parmerge): self.caller_owns_return = old.caller_owns_return self.varargs = old.varargs @@ -370,7 +371,7 @@ class MethodDef(MethodDefBase): if self.__dict__[item] == None: self.write_defs(sys.stderr) raise RuntimeError, "definition missing required %s" % (item,) - + def write_defs(self, fp=sys.stdout): fp.write('(define-method ' + self.name + '\n') self._write_defs(fp) @@ -480,7 +481,7 @@ class FunctionDef(Definition): # parameter names changed and we can't find a match; it's # safer to keep the old parameter list untouched. self.params = deepcopy(old.params) - + if not self.is_constructor_of: try: self.is_constructor_of = old.is_constructor_of diff --git a/moo/moopython/codegen/override.py b/moo/moopython/codegen/override.py index da84c388..8c47d728 100644 --- a/moo/moopython/codegen/override.py +++ b/moo/moopython/codegen/override.py @@ -30,14 +30,19 @@ class Overrides: self.overridden = {} self.kwargs = {} self.noargs = {} + self.onearg = {} + self.staticmethod = {} + self.classmethod = {} self.startlines = {} self.override_attrs = {} self.override_slots = {} self.headers = '' + self.body = '' self.init = '' self.imports = [] self.defines = {} self.functions = {} + self.newstyle_constructors = {} if filename: self.handle_file(filename) @@ -99,12 +104,20 @@ class Overrides: for func in string.split(rest): self.glob_ignores.append(func) elif command == 'override': - "override function/method [kwargs,noargs]" + "override function/method [kwargs|noargs|onearg] [staticmethod|classmethod]" func = words[1] if 'kwargs' in words[1:]: self.kwargs[func] = 1 elif 'noargs' in words[1:]: self.noargs[func] = 1 + elif 'onearg' in words[1:]: + self.onearg[func] = True + + if 'staticmethod' in words[1:]: + self.staticmethod[func] = True + elif 'classmethod' in words[1:]: + self.classmethod[func] = True + self.overrides[func] = rest self.startlines[func] = (startline + 1, filename) elif command == 'override-attr': @@ -121,6 +134,10 @@ class Overrides: "headers" self.headers = '%s\n#line %d "%s"\n%s' % \ (self.headers, startline + 1, filename, rest) + elif command == 'body': + "body" + self.body = '%s\n#line %d "%s"\n%s' % \ + (self.body, startline + 1, filename, rest) elif command == 'init': "init" self.init = '%s\n#line %d "%s"\n%s' % \ @@ -141,8 +158,8 @@ class Overrides: if match: self.imports.append(match.groups()) elif command == 'define': - "define funcname [kwargs,noargs]" - "define Class.method [kwargs,noargs]" + "define funcname [kwargs|noargs|onearg] [classmethod|staticmethod]" + "define Class.method [kwargs|noargs|onearg] [classmethod|staticmethod]" func = words[1] klass = None if func.find('.') != -1: @@ -158,8 +175,20 @@ class Overrides: self.kwargs[func] = 1 elif 'noargs' in words[1:]: self.noargs[func] = 1 + elif 'onearg' in words[1:]: + self.onearg[func] = 1 + + if 'staticmethod' in words[1:]: + self.staticmethod[func] = True + elif 'classmethod' in words[1:]: + self.classmethod[func] = True self.startlines[func] = (startline + 1, filename) + + elif command == 'new-constructor': + "new-constructor GType" + gtype, = words[1:] + self.newstyle_constructors[gtype] = True def is_ignored(self, name): if self.ignores.has_key(name): @@ -194,7 +223,16 @@ class Overrides: def wants_noargs(self, name): return self.noargs.has_key(name) - + + def wants_onearg(self, name): + return self.onearg.has_key(name) + + def is_staticmethod(self, name): + return self.staticmethod.has_key(name) + + def is_classmethod(self, name): + return self.classmethod.has_key(name) + def attr_is_overriden(self, attr): return self.override_attrs.has_key(attr) @@ -209,6 +247,9 @@ class Overrides: def get_headers(self): return self.headers + + def get_body(self): + return self.body def get_init(self): return self.init diff --git a/moo/moopython/codegen/reversewrapper.py b/moo/moopython/codegen/reversewrapper.py index 3f0fb4fb..4290e848 100644 --- a/moo/moopython/codegen/reversewrapper.py +++ b/moo/moopython/codegen/reversewrapper.py @@ -112,9 +112,10 @@ class ReverseWrapper(object): self.pyargv_items.append(variable) def write_code(self, code, - cleanup=None, - failure_expression=None, - failure_cleanup=None): + cleanup=None, + failure_expression=None, + failure_cleanup=None, + failure_exception=None): '''Add a chunk of code with cleanup and error handling This method is to be used by TypeHandlers when generating code @@ -127,16 +128,23 @@ class ReverseWrapper(object): if anything failed (default None) failure_cleanup -- code to cleanup any dynamic resources created by @code in case of failure (default None) + failure_exception -- code to raise an exception in case of + failure (which will be immediately + printed and cleared), (default None) ''' if code is not None: self.body.writeln(code) if failure_expression is not None: self.body.writeln("if (%s) {" % failure_expression) self.body.indent() - self.body.writeln("if (PyErr_Occurred())") - self.body.indent() - self.body.writeln("PyErr_Print();") - self.body.unindent() + if failure_exception is None: + self.body.writeln("if (PyErr_Occurred())") + self.body.indent() + self.body.writeln("PyErr_Print();") + self.body.unindent() + else: + self.body.writeln(failure_exception) + self.body.writeln("PyErr_Print();") if failure_cleanup is not None: self.body.writeln(failure_cleanup) for cleanup_action in self.cleanup_actions: @@ -401,6 +409,10 @@ class GObjectReturn(ReturnType): self.wrapper.write_code("return NULL;") def write_conversion(self): + self.wrapper.write_code( + code=None, + failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)", + failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");') self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);" % self.get_c_type()) self.wrapper.write_code("g_object_ref((GObject *) retval);") @@ -594,13 +606,13 @@ class GdkRectanglePtrParam(Parameter): def convert_c2py(self): self.wrapper.add_declaration("PyObject *py_%s;" % self.name) self.wrapper.write_code( - code=('py_%(name)s = Py_BuildValue("(ffff)", %(name)s->x, %(name)s->y,\n' - ' %(name)s->width, %(name)s->height);' - % dict(name=self.name)), + code=('py_%s = pyg_boxed_new(GDK_TYPE_RECTANGLE, %s, TRUE, TRUE);' % + (self.name, self.name)), cleanup=("Py_DECREF(py_%s);" % self.name)) self.wrapper.add_pyargv_item("py_%s" % self.name) argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam) +argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam) class PyGObjectMethodParam(Parameter): diff --git a/moo/moopython/plugins/pytest.py b/moo/moopython/plugins/pytest.py index 849ae3db..fdfea563 100644 --- a/moo/moopython/plugins/pytest.py +++ b/moo/moopython/plugins/pytest.py @@ -1,15 +1,17 @@ import moo import gobject +UIInfo = moo.edit.Plugin.UIInfo + PLUGIN_ID = "TestPythonPlugin" class Action(moo.edit.Action): def __init__(self): moo.edit.Action.__init__(self) + self.set_property("label", "AnAction") print "__init__" def do_check_state(self): - self.set_property("label", "AnAction") print "check_state" return True @@ -29,7 +31,7 @@ class Plugin(moo.edit.Plugin): } moo.edit.edit_class_add_action(moo.edit.Edit, "AnAction", Action) - self.ui.append(moo.edit.Plugin.UIInfo("Editor/Popup", "AnAction")) + self.ui.append(UIInfo("Editor/Popup", "AnAction")) def attach_doc(self, doc, window): print "attaching to", doc diff --git a/moo/moopython/pygtk/Makefile.incl b/moo/moopython/pygtk/Makefile.incl index a031f767..f0efd2bb 100644 --- a/moo/moopython/pygtk/Makefile.incl +++ b/moo/moopython/pygtk/Makefile.incl @@ -87,10 +87,15 @@ if MOO_OS_MINGW codegen_platform = --platform win32 endif +if MOO_USE_CUSTOM_CODEGEN +codegen = $(PYTHON) $(moopython_srcdir)/codegen/codegen.py $(codegen_platform) +else +codegen = $(PYTHON) $(PYGTK_CODEGEN_DIR)/codegen.py $(codegen_platform) +endif + $(moopygtk)/mooutils-pygtk.c: $(moopygtk)/mooutils-pygtk.defs $(moopygtk)/mooutils-pygtk.override $(mooutils_override_files) mkdir -p $(moopygtk) - $(PYTHON) $(moopython_srcdir)/codegen/codegen.py \ - --prefix _moo_utils $(codegen_platform) \ + $(codegen) --prefix _moo_utils \ --register $(PYGTK_DEFS_DIR)/gtk-types.defs \ --register $(PYGTK_DEFS_DIR)/gdk-types.defs \ --override $(moopygtk_srcdir)/mooutils-pygtk.override \ @@ -99,8 +104,7 @@ $(moopygtk)/mooutils-pygtk.c: $(moopygtk)/mooutils-pygtk.defs $(moopygtk)/moouti $(moopygtk)/mooterm-pygtk.c: $(moopygtk)/mooterm-pygtk.defs $(moopygtk)/mooterm-pygtk.override mkdir -p $(moopygtk) - $(PYTHON) $(moopython_srcdir)/codegen/codegen.py \ - --prefix _moo_term $(codegen_platform) \ + $(codegen) --prefix _moo_term \ --register $(PYGTK_DEFS_DIR)/gtk-types.defs \ --register $(PYGTK_DEFS_DIR)/gdk-types.defs \ --register $(moopygtk_srcdir)/mooutils-pygtk.defs \ @@ -110,8 +114,7 @@ $(moopygtk)/mooterm-pygtk.c: $(moopygtk)/mooterm-pygtk.defs $(moopygtk)/mooterm- $(moopygtk)/mooedit-pygtk.c: $(moopygtk)/mooedit-pygtk.defs $(moopygtk)/mooedit-pygtk.override $(mooedit_defs_files) mkdir -p $(moopygtk) - $(PYTHON) $(moopython_srcdir)/codegen/codegen.py \ - --prefix _moo_edit $(codegen_platform) \ + $(codegen) --prefix _moo_edit \ --register $(PYGTK_DEFS_DIR)/gtk-types.defs \ --register $(PYGTK_DEFS_DIR)/gdk-types.defs \ --register $(moopygtk_srcdir)/mooutils-pygtk.defs \ @@ -121,8 +124,7 @@ $(moopygtk)/mooedit-pygtk.c: $(moopygtk)/mooedit-pygtk.defs $(moopygtk)/mooedit- $(moopygtk)/mooapp-pygtk.c: $(moopygtk)/mooapp-pygtk.defs $(moopygtk)/mooapp-pygtk.override mkdir -p $(moopygtk) - $(PYTHON) $(moopython_srcdir)/codegen/codegen.py \ - --prefix _moo_app $(codegen_platform) \ + $(codegen) --prefix _moo_app \ --register $(PYGTK_DEFS_DIR)/gtk-types.defs \ --register $(PYGTK_DEFS_DIR)/gdk-types.defs \ --register $(moopygtk_srcdir)/mooedit-pygtk.defs \ diff --git a/moo/moopython/pygtk/mooedit-pygtk.defs b/moo/moopython/pygtk/mooedit-pygtk.defs index f49cdd8d..90863c74 100644 --- a/moo/moopython/pygtk/mooedit-pygtk.defs +++ b/moo/moopython/pygtk/mooedit-pygtk.defs @@ -1398,6 +1398,12 @@ ;; From moo/mooedit/mooedit-actions.h +(define-function moo_edit_action_new + (c-name "moo_edit_action_new") + (is-constructor-of "MooEditAction") + (return-type "MooAction*") +) + (define-function _edit_class_add_action (c-name "moo_edit_class_add_action") (return-type "none") diff --git a/moo/moopython/pygtk/mooutils-pygtk.defs b/moo/moopython/pygtk/mooutils-pygtk.defs index e858aad2..4eb6ca39 100644 --- a/moo/moopython/pygtk/mooutils-pygtk.defs +++ b/moo/moopython/pygtk/mooutils-pygtk.defs @@ -2194,6 +2194,12 @@ ;; From ./ggap/moo/mooutils/mooaction.h +(define-function moo_action_new + (c-name "moo_action_new") + (is-constructor-of "MooAction") + (return-type "MooAction*") +) + (define-method activate (of-object "MooAction") (c-name "moo_action_activate")