home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / gtk-2.0 / codegen / reversewrapper.py < prev    next >
Encoding:
Python Source  |  2007-11-01  |  34.1 KB  |  883 lines

  1. ### -*- python -*-
  2. ### Code to generate "Reverse Wrappers", i.e. C->Python wrappers
  3. ### (C) 2004 Gustavo Carneiro <gjc@gnome.org>
  4. import argtypes
  5. import os
  6.  
  7. DEBUG_MODE = ('PYGTK_CODEGEN_DEBUG' in os.environ)
  8.  
  9. def join_ctype_name(ctype, name):
  10.     '''Joins a C type and a variable name into a single string'''
  11.     if ctype[-1] != '*':
  12.         return " ".join((ctype, name))
  13.     else:
  14.         return "".join((ctype, name))
  15.  
  16.  
  17. class CodeSink(object):
  18.     def __init__(self):
  19.         self.indent_level = 0 # current indent level
  20.         self.indent_stack = [] # previous indent levels
  21.  
  22.     def _format_code(self, code):
  23.         assert isinstance(code, str)
  24.         l = []
  25.         for line in code.split('\n'):
  26.             l.append(' '*self.indent_level + line)
  27.         if l[-1]:
  28.             l.append('')
  29.         return '\n'.join(l)
  30.  
  31.     def writeln(self, line=''):
  32.         raise NotImplementedError
  33.  
  34.     def indent(self, level=4):
  35.         '''Add a certain ammount of indentation to all lines written
  36.         from now on and until unindent() is called'''
  37.         self.indent_stack.append(self.indent_level)
  38.         self.indent_level += level
  39.  
  40.     def unindent(self):
  41.         '''Revert indentation level to the value before last indent() call'''
  42.         self.indent_level = self.indent_stack.pop()
  43.  
  44.  
  45. class FileCodeSink(CodeSink):
  46.     def __init__(self, fp):
  47.         CodeSink.__init__(self)
  48.         assert isinstance(fp, file)
  49.         self.fp = fp
  50.  
  51.     def writeln(self, line=''):
  52.         self.fp.write(self._format_code(line))
  53.  
  54. class MemoryCodeSink(CodeSink):
  55.     def __init__(self):
  56.         CodeSink.__init__(self)
  57.         self.lines = []
  58.  
  59.     def writeln(self, line=''):
  60.         self.lines.append(self._format_code(line))
  61.  
  62.     def flush_to(self, sink):
  63.         assert isinstance(sink, CodeSink)
  64.         for line in self.lines:
  65.             sink.writeln(line.rstrip())
  66.         self.lines = []
  67.  
  68.     def flush(self):
  69.         l = []
  70.         for line in self.lines:
  71.             l.append(self._format_code(line))
  72.         self.lines = []
  73.         return "".join(l)
  74.  
  75. class ReverseWrapper(object):
  76.     '''Object that generates a C->Python wrapper'''
  77.     def __init__(self, cname, is_static=True):
  78.         assert isinstance(cname, str)
  79.  
  80.         self.cname = cname
  81.         ## function object we will call, or object whose method we will call
  82.         self.called_pyobj = None
  83.         ## name of method of self.called_pyobj we will call
  84.         self.method_name = None
  85.         self.is_static = is_static
  86.  
  87.         self.parameters = []
  88.         self.declarations = MemoryCodeSink()
  89.         self.post_return_code = MemoryCodeSink()
  90.         self.body = MemoryCodeSink()
  91.         self.check_exception_code = MemoryCodeSink()
  92.         self.cleanup_actions = []
  93.         self.pyargv_items = []
  94.         self.pyargv_optional_items = []
  95.         self.pyret_parse_items = [] # list of (format_spec, parameter)
  96.         self.code_sinks_stack = [self.body]
  97.  
  98.     def set_call_target(self, called_pyobj, method_name=None):
  99.         assert called_pyobj is not None
  100.         assert self.called_pyobj is None
  101.         self.called_pyobj = called_pyobj
  102.         self.method_name = method_name
  103.  
  104.     def set_return_type(self, return_type):
  105.         assert isinstance(return_type, ReturnType)
  106.         self.return_type = return_type
  107.  
  108.     def add_parameter(self, param):
  109.         assert isinstance(param, Parameter)
  110.         self.parameters.append(param)
  111.  
  112.     def add_declaration(self, decl_code):
  113.         self.declarations.writeln(decl_code)
  114.  
  115.     def add_pyargv_item(self, variable, optional=False):
  116.         if optional:
  117.             self.pyargv_optional_items.append(variable)
  118.         else:
  119.             self.pyargv_items.append(variable)
  120.  
  121.     def add_pyret_parse_item(self, format_specifier, parameter, prepend=False):
  122.         if prepend:
  123.             self.pyret_parse_items.insert(0, (format_specifier, parameter))
  124.         else:
  125.             self.pyret_parse_items.append((format_specifier, parameter))
  126.  
  127.  
  128.     def push_code_sink(self, code_sink):
  129.         self.code_sinks_stack.insert(0, code_sink)
  130.  
  131.     def pop_code_sink(self):
  132.         return self.code_sinks_stack.pop(0)
  133.  
  134.  
  135.     def write_code(self, code,
  136.                    cleanup=None,
  137.                    failure_expression=None,
  138.                    failure_cleanup=None,
  139.                    failure_exception=None,
  140.                    code_sink=None):
  141.         '''Add a chunk of code with cleanup and error handling
  142.  
  143.         This method is to be used by TypeHandlers when generating code
  144.  
  145.         Keywork arguments:
  146.         code -- code to add
  147.         cleanup -- code to cleanup any dynamic resources created by @code
  148.                    (except in case of failure) (default None)
  149.         failure_expression -- C boolean expression to indicate
  150.                               if anything failed (default None)
  151.         failure_cleanup -- code to cleanup any dynamic resources
  152.                            created by @code in case of failure (default None)
  153.         failure_exception -- code to raise an exception in case of
  154.                              failure (which will be immediately
  155.                              printed and cleared), (default None)
  156.         code_sink -- "code sink" to use; by default,
  157.                       ReverseWrapper.body is used, which writes the
  158.                       main body of the wrapper, before calling the
  159.                       python method.  Alternatively,
  160.                       ReverseWrapper.after_pyret_parse can be used, to
  161.                       write code after the PyArg_ParseTuple that
  162.                       parses the python method return value.
  163.         '''
  164.         if code_sink is None:
  165.             code_sink = self.code_sinks_stack[0]
  166.         if code is not None:
  167.             code_sink.writeln(code)
  168.         if failure_expression is not None:
  169.             code_sink.writeln("if (%s) {" % (failure_expression,))
  170.             code_sink.indent()
  171.             if failure_exception is None:
  172.                 code_sink.writeln("if (PyErr_Occurred())")
  173.                 code_sink.indent()
  174.                 code_sink.writeln("PyErr_Print();")
  175.                 code_sink.unindent()
  176.             else:
  177.                 code_sink.writeln(failure_exception)
  178.                 code_sink.writeln("PyErr_Print();")
  179.             if failure_cleanup is not None:
  180.                 code_sink.writeln(failure_cleanup)
  181.             for cleanup_action in self.cleanup_actions:
  182.                 code_sink.writeln(cleanup_action)
  183.  
  184.             self.push_code_sink(code_sink)
  185.             try:
  186.                 self.return_type.write_error_return()
  187.             finally:
  188.                 self.pop_code_sink()
  189.  
  190.             code_sink.unindent()
  191.             code_sink.writeln("}")
  192.         if cleanup is not None:
  193.             self.cleanup_actions.insert(0, cleanup)
  194.  
  195.     def generate(self, sink):
  196.         '''Generate the code into a CodeSink object'''
  197.         assert isinstance(sink, CodeSink)
  198.  
  199.         if DEBUG_MODE:
  200.             self.declarations.writeln("/* begin declarations */")
  201.             self.body.writeln("/* begin main body */")
  202.             self.post_return_code.writeln("/* begin post-return code */")
  203.  
  204.         self.add_declaration("PyGILState_STATE __py_state;")
  205.         self.write_code(code="__py_state = pyg_gil_state_ensure();",
  206.                         cleanup="pyg_gil_state_release(__py_state);")
  207.  
  208.         for param in self.parameters:
  209.             param.convert_c2py()
  210.  
  211.         assert self.called_pyobj is not None,\
  212.                "Parameters failed to provide a target function or method."
  213.  
  214.         if self.is_static:
  215.             sink.writeln('static %s' % self.return_type.get_c_type())
  216.         else:
  217.             sink.writeln(self.return_type.get_c_type())
  218.         c_proto_params = map(Parameter.format_for_c_proto, self.parameters)
  219.         sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params)))
  220.  
  221.         self.return_type.write_decl()
  222.         self.add_declaration("PyObject *py_retval;")
  223.  
  224.         ## Handle number of arguments
  225.         if self.pyargv_items:
  226.             self.add_declaration("PyObject *py_args;")
  227.             py_args = "py_args"
  228.             if self.pyargv_optional_items:
  229.                 self.add_declaration("int argc = %i;" % len(self.pyargv_items))
  230.                 argc = "argc"
  231.                 for arg in self.pyargv_optional_items:
  232.                     self.body.writeln("if (%s)" % arg)
  233.                     self.body.indent()
  234.                     self.body.writeln("++argc;")
  235.                     self.body.unindent()
  236.             else:
  237.                 argc = str(len(self.pyargv_items))
  238.         else:
  239.             if self.pyargv_optional_items:
  240.                 self.add_declaration("PyObject *py_args;")
  241.                 py_args = "py_args"
  242.                 self.add_declaration("int argc = 0;")
  243.                 argc = "argc"
  244.                 for arg in self.pyargv_optional_items:
  245.                     self.body.writeln("if (%s)" % arg)
  246.                     self.body.indent()
  247.                     self.body.writeln("++argc;")
  248.                     self.body.unindent()
  249.             else:
  250.                 py_args = "NULL"
  251.                 argc = None
  252.  
  253.         self.body.writeln()
  254.  
  255.         if py_args != "NULL":
  256.             self.write_code("py_args = PyTuple_New(%s);" % argc,
  257.                             cleanup="Py_DECREF(py_args);")
  258.             pos = 0
  259.             for arg in self.pyargv_items:
  260.                 try: # try to remove the Py_DECREF cleanup action, if we can
  261.                     self.cleanup_actions.remove("Py_DECREF(%s);" % arg)
  262.                 except ValueError: # otherwise we have to Py_INCREF..
  263.                     self.body.writeln("Py_INCREF(%s);" % arg)
  264.                 self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
  265.                 pos += 1
  266.             for arg in self.pyargv_optional_items:
  267.                 self.body.writeln("if (%s) {" % arg)
  268.                 self.body.indent()
  269.                 try: # try to remove the Py_DECREF cleanup action, if we can
  270.                     self.cleanup_actions.remove("Py_XDECREF(%s);" % arg)
  271.                 except ValueError: # otherwise we have to Py_INCREF..
  272.                     self.body.writeln("Py_INCREF(%s);" % arg)
  273.                 self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
  274.                 self.body.unindent()
  275.                 self.body.writeln("}")
  276.                 pos += 1
  277.  
  278.         self.body.writeln()
  279.  
  280.         ## Call the python method
  281.         if self.method_name is None:
  282.             self.write_code("py_retval = PyObject_Call(%s, %s);"
  283.                             % (self.called_pyobj, py_args),
  284.                             cleanup="Py_XDECREF(py_retval);")
  285.             self.check_exception_code.flush_to(self.body)
  286.             self.write_code(None, failure_expression="!py_retval")
  287.  
  288.         else:
  289.             self.add_declaration("PyObject *py_method;")
  290.             self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");"
  291.                             % (self.called_pyobj, self.method_name),
  292.                             cleanup="Py_DECREF(py_method);",
  293.                             failure_expression="!py_method")
  294.             self.write_code("py_retval = PyObject_CallObject(py_method, %s);"
  295.                             % (py_args,),
  296.                             cleanup="Py_XDECREF(py_retval);")
  297.             self.check_exception_code.flush_to(self.body)
  298.             self.write_code(None, failure_expression="!py_retval")
  299.  
  300.         ## -- Handle the return value --
  301.  
  302.         ## we need to check if the return_type object is prepared to cooperate with multiple return values
  303.         len_before = len(self.pyret_parse_items)
  304.         self.return_type.write_conversion()
  305.         len_after = len(self.pyret_parse_items)
  306.         assert (self.return_type.get_c_type() == 'void'
  307.                 or not (len_before == len_after and len_after > 0)),\
  308.                ("Bug in reverse wrappers: return type handler %s"
  309.                 " is not prepared to cooperate multiple return values") % (type(self.return_type),)
  310.  
  311.         sink.indent()
  312.  
  313.         if self.pyret_parse_items == [("", "")]:
  314.             ## special case when there are no return parameters
  315.             self.write_code(
  316.                 code=None,
  317.                 failure_expression='py_retval != Py_None',
  318.                 failure_exception=('PyErr_SetString(PyExc_TypeError, '
  319.                                    '"virtual method should return None");'))
  320.         else:    
  321.             if len(self.pyret_parse_items) == 1:
  322.                 ## if retval is one item only, pack it in a tuple so we
  323.                 ## can use PyArg_ParseTuple as usual..
  324.                 self.write_code('py_retval = Py_BuildValue("(N)", py_retval);')
  325.             if len(self.pyret_parse_items) > 0:
  326.                 ## Parse return values using PyArg_ParseTuple
  327.                 params = ["py_retval",
  328.                           '"%s"' % "".join([format for format, param in self.pyret_parse_items])]
  329.                 params.extend([param for format, param in self.pyret_parse_items if param])
  330.                 self.write_code(code=None, failure_expression=(
  331.                     '!PyArg_ParseTuple(%s)' % (', '.join(params),)))
  332.  
  333.         if DEBUG_MODE:
  334.             self.declarations.writeln("/* end declarations */")
  335.         self.declarations.flush_to(sink)
  336.         sink.writeln()
  337.         if DEBUG_MODE:
  338.             self.body.writeln("/* end main body */")
  339.         self.body.flush_to(sink)
  340.         sink.writeln()
  341.         if DEBUG_MODE:
  342.             self.post_return_code.writeln("/* end post-return code */")
  343.         self.post_return_code.flush_to(sink)
  344.         sink.writeln()
  345.  
  346.         for cleanup_action in self.cleanup_actions:
  347.             sink.writeln(cleanup_action)
  348.         if self.return_type.get_c_type() != 'void':
  349.             sink.writeln()
  350.             sink.writeln("return retval;")
  351.         sink.unindent()
  352.         sink.writeln("}")
  353.  
  354. class TypeHandler(object):
  355.     def __init__(self, wrapper, **props):
  356.         assert isinstance(wrapper, ReverseWrapper)
  357.         self.wrapper = wrapper
  358.         self.props = props
  359.  
  360. class ReturnType(TypeHandler):
  361.  
  362.     def get_c_type(self):
  363.         raise NotImplementedError
  364.  
  365.     def write_decl(self):
  366.         raise NotImplementedError
  367.  
  368.     def write_error_return(self):
  369.         '''Write "return <value>" code in case of error'''
  370.         raise NotImplementedError
  371.  
  372.     def write_conversion(self):
  373.         '''Writes code to convert Python return value in 'py_retval'
  374.         into C 'retval'.  Returns a string with C boolean expression
  375.         that determines if anything went wrong. '''
  376.         raise NotImplementedError
  377.  
  378. class Parameter(TypeHandler):
  379.  
  380.     def __init__(self, wrapper, name, **props):
  381.         TypeHandler.__init__(self, wrapper, **props)
  382.         self.name = name
  383.  
  384.     def get_c_type(self):
  385.         raise NotImplementedError
  386.  
  387.     def convert_c2py(self):
  388.         '''Write some code before calling the Python method.'''
  389.         pass
  390.  
  391.     def format_for_c_proto(self):
  392.         return join_ctype_name(self.get_c_type(), self.name)
  393.  
  394.  
  395. ###---
  396. class StringParam(Parameter):
  397.  
  398.     def get_c_type(self):
  399.         return self.props.get('c_type', 'char *').replace('const-', 'const ')
  400.  
  401.     def convert_c2py(self):
  402.         if self.props.get('optional', False):
  403.             self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
  404.             self.wrapper.write_code(code=("if (%s)\n"
  405.                                           "    py_%s = PyString_FromString(%s);\n"
  406.                                           % (self.name, self.name, self.name)),
  407.                                     cleanup=("Py_XDECREF(py_%s);" % self.name))
  408.             self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True)
  409.         else:
  410.             self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  411.             self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
  412.                                           (self.name, self.name)),
  413.                                     cleanup=("Py_DECREF(py_%s);" % self.name),
  414.                                     failure_expression=("!py_%s" % self.name))
  415.             self.wrapper.add_pyargv_item("py_%s" % self.name)
  416.  
  417. for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*',
  418.               'gchar-const*', 'string', 'static_string'):
  419.     argtypes.matcher.register_reverse(ctype, StringParam)
  420. del ctype
  421.  
  422. class StringReturn(ReturnType):
  423.  
  424.     def get_c_type(self):
  425.         return self.props.get('c_type', 'char *').replace('const-', 'const ')
  426.     #return "char *"
  427.  
  428.     def write_decl(self):
  429.         self.wrapper.add_declaration("%s retval;" % self.get_c_type())
  430.         #self.wrapper.add_declaration("char *retval;")
  431.  
  432.     def write_error_return(self):
  433.         self.wrapper.write_code("return NULL;")
  434.  
  435.     def write_conversion(self):
  436.         self.wrapper.add_pyret_parse_item("s", "&retval", prepend=True)
  437.         self.wrapper.write_code("retval = g_strdup(retval);", code_sink=self.wrapper.post_return_code)
  438.  
  439. for ctype in ('char*', 'gchar*', 'const-gchar*'):
  440.     argtypes.matcher.register_reverse_ret(ctype, StringReturn)
  441. del ctype
  442.  
  443.  
  444. class VoidReturn(ReturnType):
  445.  
  446.     def get_c_type(self):
  447.         return "void"
  448.  
  449.     def write_decl(self):
  450.         pass
  451.  
  452.     def write_error_return(self):
  453.         self.wrapper.write_code("return;")
  454.  
  455.     def write_conversion(self):
  456.         self.wrapper.add_pyret_parse_item("", "", prepend=True)
  457.  
  458. argtypes.matcher.register_reverse_ret('void', VoidReturn)
  459. argtypes.matcher.register_reverse_ret('none', VoidReturn)
  460.  
  461. class GObjectParam(Parameter):
  462.  
  463.     def get_c_type(self):
  464.         return self.props.get('c_type', 'GObject *')
  465.  
  466.     def convert_c2py(self):
  467.         self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
  468.         self.wrapper.write_code(code=("if (%s)\n"
  469.                                       "    py_%s = pygobject_new((GObject *) %s);\n"
  470.                                       "else {\n"
  471.                                       "    Py_INCREF(Py_None);\n"
  472.                                       "    py_%s = Py_None;\n"
  473.                                       "}"
  474.                                       % (self.name, self.name, self.name, self.name)),
  475.                                 cleanup=("Py_DECREF(py_%s);" % self.name))
  476.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  477.  
  478. argtypes.matcher.register_reverse('GObject*', GObjectParam)
  479.  
  480. class GObjectReturn(ReturnType):
  481.  
  482.     def get_c_type(self):
  483.         return self.props.get('c_type', 'GObject *')
  484.  
  485.     def write_decl(self):
  486.         self.wrapper.add_declaration("%s retval;" % self.get_c_type())
  487.  
  488.     def write_error_return(self):
  489.         self.wrapper.write_code("return NULL;")
  490.  
  491.     def write_conversion(self):
  492.         self.wrapper.write_code(
  493.             code=None,
  494.             failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)",
  495.             failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");')
  496.         self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
  497.                                 % self.get_c_type())
  498.         self.wrapper.write_code("g_object_ref((GObject *) retval);")
  499.  
  500. argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
  501.  
  502.  
  503.  
  504. class IntParam(Parameter):
  505.  
  506.     def get_c_type(self):
  507.         return self.props.get('c_type', 'int')
  508.  
  509.     def convert_c2py(self):
  510.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  511.         self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" %
  512.                                       (self.name, self.name)),
  513.                                 cleanup=("Py_DECREF(py_%s);" % self.name))
  514.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  515.  
  516. class IntReturn(ReturnType):
  517.     def get_c_type(self):
  518.         return self.props.get('c_type', 'int')
  519.     def write_decl(self):
  520.         self.wrapper.add_declaration("%s retval;" % self.get_c_type())
  521.     def write_error_return(self):
  522.         self.wrapper.write_code("return -G_MAXINT;")
  523.     def write_conversion(self):
  524.         self.wrapper.add_pyret_parse_item("i", "&retval", prepend=True)
  525.  
  526. for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long',
  527.                 'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16',
  528.                 'gint16', 'gint32', 'GTime'):
  529.     argtypes.matcher.register_reverse(argtype, IntParam)
  530.     argtypes.matcher.register_reverse_ret(argtype, IntReturn)
  531. del argtype
  532.  
  533. class IntPtrParam(Parameter):
  534.     def __init__(self, wrapper, name, **props):
  535.         if "direction" not in props:
  536.             raise argtypes.ArgTypeConfigurationError(
  537.                 "cannot use int* parameter without direction")
  538.         if props["direction"] not in ("out", "inout"):
  539.             raise argtypes.ArgTypeConfigurationError(
  540.                 "cannot use int* parameter with direction '%s'"
  541.                 % (props["direction"],))
  542.         Parameter.__init__(self, wrapper, name, **props)
  543.     def get_c_type(self):
  544.         return self.props.get('c_type', 'int*')
  545.     def convert_c2py(self):
  546.         if self.props["direction"] == "inout":
  547.             self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  548.             self.wrapper.write_code(code=("py_%s = PyInt_FromLong(*%s);" %
  549.                                           (self.name, self.name)),
  550.                                     cleanup=("Py_DECREF(py_%s);" % self.name))
  551.             self.wrapper.add_pyargv_item("py_%s" % self.name)
  552.         self.wrapper.add_pyret_parse_item("i", self.name)
  553. for argtype in ('int*', 'gint*'):
  554.     argtypes.matcher.register_reverse(argtype, IntPtrParam)
  555. del argtype
  556.  
  557.  
  558. class GEnumReturn(IntReturn):
  559.     def write_conversion(self):
  560.         self.wrapper.write_code(
  561.             code=None,
  562.             failure_expression=(
  563.             "pyg_enum_get_value(%s, py_retval, (gint *)&retval)"
  564.             % (self.props['typecode'],)))
  565.  
  566. argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
  567.  
  568. class GEnumParam(IntParam):
  569.     def convert_c2py(self):
  570.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  571.         self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" %
  572.                                 (self.name, self.props['typecode'], self.name)),
  573.                         cleanup=("Py_DECREF(py_%s);" % self.name),
  574.                         failure_expression=("!py_%s" % self.name))
  575.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  576.  
  577. argtypes.matcher.register_reverse("GEnum", GEnumParam)
  578.  
  579. class GFlagsReturn(IntReturn):
  580.     def write_conversion(self):
  581.         self.wrapper.write_code(
  582.             code=None,
  583.             failure_expression=(
  584.             "pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
  585.             self.props['typecode']))
  586.  
  587. argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn)
  588.  
  589. class GFlagsParam(IntParam):
  590.     def convert_c2py(self):
  591.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  592.         self.wrapper.write_code(code=(
  593.             "py_%s = pyg_flags_from_gtype(%s, %s);" %
  594.             (self.name, self.props['typecode'], self.name)),
  595.                                 cleanup=("Py_DECREF(py_%s);" % self.name),
  596.                                 failure_expression=("!py_%s" % self.name))
  597.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  598.  
  599. argtypes.matcher.register_reverse("GFlags", GFlagsParam)
  600.  
  601.  
  602. class GtkTreePathParam(IntParam):
  603.     def convert_c2py(self):
  604.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  605.         self.wrapper.write_code(code=(
  606.             "py_%s = pygtk_tree_path_to_pyobject(%s);" %
  607.             (self.name, self.name)),
  608.                                 cleanup=("Py_DECREF(py_%s);" % self.name),
  609.                                 failure_expression=("!py_%s" % self.name))
  610.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  611.  
  612. argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam)
  613.  
  614.  
  615. class GtkTreePathReturn(ReturnType):
  616.     def get_c_type(self):
  617.         return self.props.get('c_type', 'GtkTreePath *')
  618.     def write_decl(self):
  619.         self.wrapper.add_declaration("GtkTreePath * retval;")
  620.     def write_error_return(self):
  621.         self.wrapper.write_code("return NULL;")
  622.     def write_conversion(self):
  623.         self.wrapper.write_code(
  624.             "retval = pygtk_tree_path_from_pyobject(py_retval);\n",
  625.             failure_expression=('!retval'),
  626.             failure_exception=(
  627.     'PyErr_SetString(PyExc_TypeError, "retval should be a GtkTreePath");'))
  628.  
  629. argtypes.matcher.register_reverse_ret("GtkTreePath*", GtkTreePathReturn)
  630.  
  631.  
  632. class BooleanReturn(ReturnType):
  633.     def get_c_type(self):
  634.         return "gboolean"
  635.     def write_decl(self):
  636.         self.wrapper.add_declaration("gboolean retval;")
  637.         self.wrapper.add_declaration("PyObject *py_main_retval;")
  638.     def write_error_return(self):
  639.         self.wrapper.write_code("return FALSE;")
  640.     def write_conversion(self):
  641.         self.wrapper.add_pyret_parse_item("O", "&py_main_retval", prepend=True)
  642.         self.wrapper.write_code(
  643.             "retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;",
  644.             code_sink=self.wrapper.post_return_code)
  645. argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
  646.  
  647. class BooleanParam(Parameter):
  648.     def get_c_type(self):
  649.         return "gboolean"
  650.     def convert_c2py(self):
  651.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  652.         self.wrapper.write_code("py_%s = %s? Py_True : Py_False;"
  653.                                 % (self.name, self.name))
  654.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  655.  
  656. argtypes.matcher.register_reverse("gboolean", BooleanParam)
  657.  
  658.  
  659. class DoubleParam(Parameter):
  660.     def get_c_type(self):
  661.         return self.props.get('c_type', 'gdouble')
  662.     def convert_c2py(self):
  663.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  664.         self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" %
  665.                                       (self.name, self.name)),
  666.                                 cleanup=("Py_DECREF(py_%s);" % self.name))
  667.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  668.  
  669. class DoublePtrParam(Parameter):
  670.     def __init__(self, wrapper, name, **props):
  671.         if "direction" not in props:
  672.             raise argtypes.ArgTypeConfigurationError(
  673.                 "cannot use double* parameter without direction")
  674.         if props["direction"] not in ("out", ): # inout not yet implemented
  675.             raise argtypes.ArgTypeConfigurationError(
  676.                 "cannot use double* parameter with direction '%s'"
  677.                 % (props["direction"],))
  678.         Parameter.__init__(self, wrapper, name, **props)
  679.     def get_c_type(self):
  680.         return self.props.get('c_type', 'double*')
  681.     def convert_c2py(self):
  682.         self.wrapper.add_pyret_parse_item("d", self.name)
  683. for argtype in ('double*', 'gdouble*'):
  684.     argtypes.matcher.register_reverse(argtype, DoublePtrParam)
  685. del argtype
  686.  
  687. class DoubleReturn(ReturnType):
  688.     def get_c_type(self):
  689.         return self.props.get('c_type', 'gdouble')
  690.     def write_decl(self):
  691.         self.wrapper.add_declaration("%s retval;" % self.get_c_type())
  692.     def write_error_return(self):
  693.         self.wrapper.write_code("return -G_MAXFLOAT;")
  694.     def write_conversion(self):
  695.         self.wrapper.add_pyret_parse_item("d", "&retval", prepend=True)
  696.  
  697. for argtype in ('float', 'double', 'gfloat', 'gdouble'):
  698.     argtypes.matcher.register_reverse(argtype, DoubleParam)
  699.     argtypes.matcher.register_reverse_ret(argtype, DoubleReturn)
  700.  
  701.  
  702. class GBoxedParam(Parameter):
  703.     def get_c_type(self):
  704.         return self.props.get('c_type').replace('const-', 'const ')
  705.     def convert_c2py(self):
  706.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  707.         ctype = self.get_c_type()
  708.         if ctype.startswith('const '):
  709.             ctype_no_const = ctype[len('const '):]
  710.             self.wrapper.write_code(
  711.                 code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' %
  712.                       (self.name, self.props['typecode'],
  713.                        ctype_no_const, self.name)),
  714.                 cleanup=("Py_DECREF(py_%s);" % self.name))
  715.         else:
  716.             self.wrapper.write_code(
  717.                 code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' %
  718.                       (self.name, self.props['typecode'], self.name)),
  719.                 cleanup=("Py_DECREF(py_%s);" % self.name))
  720.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  721.  
  722. argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
  723.  
  724.  
  725. class GBoxedReturn(ReturnType):
  726.     def get_c_type(self):
  727.         return self.props.get('c_type')
  728.     def write_decl(self):
  729.         self.wrapper.add_declaration("%s retval;" % self.get_c_type())
  730.     def write_error_return(self):
  731.         self.wrapper.write_code("return retval;")
  732.     def write_conversion(self):
  733.         self.wrapper.write_code(code = None,
  734.             failure_expression=("!pyg_boxed_check(py_retval, %s)" %
  735.                                 (self.props['typecode'],)),
  736.             failure_exception=(
  737.             'PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
  738.             % (self.props['typename'],)))
  739.         self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
  740.                                 self.props['typename'])
  741.  
  742. argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
  743.  
  744.  
  745. class GdkRegionPtrReturn(GBoxedReturn):
  746.     def write_error_return(self):
  747.         self.wrapper.write_code("return gdk_region_new();")
  748.     def write_conversion(self):
  749.         self.props['typecode'] = 'PYGDK_TYPE_REGION'
  750.         self.props['typename'] = 'GdkRegion'
  751.         super(GdkRegionPtrReturn, self).write_conversion()
  752.  
  753. argtypes.matcher.register_reverse_ret("GdkRegion*", GdkRegionPtrReturn)
  754.  
  755.  
  756. class PangoFontDescriptionReturn(GBoxedReturn):
  757.     def write_error_return(self):
  758.         self.wrapper.write_code("return pango_font_description_new();")
  759.     def write_conversion(self):
  760.         self.props['typecode'] = 'PANGO_TYPE_FONT_DESCRIPTION'
  761.         self.props['typename'] = 'PangoFontDescription'
  762.         super(PangoFontDescriptionReturn, self).write_conversion()
  763.  
  764. argtypes.matcher.register_reverse_ret("PangoFontDescription*",
  765.                                       PangoFontDescriptionReturn)
  766.  
  767.  
  768. class PangoFontMetricsReturn(GBoxedReturn):
  769.     def write_error_return(self):
  770.         self.wrapper.write_code("return pango_font_metrics_new();")
  771.     def write_conversion(self):
  772.         self.props['typecode'] = 'PANGO_TYPE_FONT_METRICS'
  773.         self.props['typename'] = 'PangoFontMetrics'
  774.         super(PangoFontMetricsReturn, self).write_conversion()
  775.  
  776. argtypes.matcher.register_reverse_ret("PangoFontMetrics*",
  777.                                       PangoFontMetricsReturn)
  778.  
  779.  
  780. class PangoLanguageReturn(GBoxedReturn):
  781.     def write_error_return(self):
  782.         self.wrapper.write_code("return pango_language_from_string(\"\");")
  783.     def write_conversion(self):
  784.         self.props['typecode'] = 'PANGO_TYPE_LANGUAGE'
  785.         self.props['typename'] = 'PangoLanguage'
  786.         super(PangoLanguageReturn, self).write_conversion()
  787.  
  788. argtypes.matcher.register_reverse_ret("PangoLanguage*", PangoLanguageReturn)
  789.  
  790.  
  791. class GdkRectanglePtrParam(Parameter):
  792.     def get_c_type(self):
  793.         return self.props.get('c_type').replace('const-', 'const ')
  794.     def convert_c2py(self):
  795.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  796.         self.wrapper.write_code(
  797.             code=('py_%s = pyg_boxed_new(GDK_TYPE_RECTANGLE, %s, TRUE, TRUE);' %
  798.                   (self.name, self.name)),
  799.             cleanup=("Py_DECREF(py_%s);" % self.name))
  800.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  801.  
  802. argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
  803. argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam)
  804.  
  805.  
  806. class GErrorParam(Parameter):
  807.     def get_c_type(self):
  808.         return self.props.get('c_type').replace('**', ' **')
  809.     def convert_c2py(self):
  810.         self.wrapper.write_code(code=None,
  811.             failure_expression=("pyg_gerror_exception_check(%s)" % self.name),
  812.                                 code_sink=self.wrapper.check_exception_code)
  813.  
  814. argtypes.matcher.register_reverse('GError**', GErrorParam)
  815.  
  816.  
  817. class PyGObjectMethodParam(Parameter):
  818.     def __init__(self, wrapper, name, method_name, **props):
  819.         Parameter.__init__(self, wrapper, name, **props)
  820.         self.method_name = method_name
  821.  
  822.     def get_c_type(self):
  823.         return self.props.get('c_type', 'GObject *')
  824.  
  825.     def convert_c2py(self):
  826.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  827.         self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
  828.                                       (self.name, self.name)),
  829.                                 cleanup=("Py_DECREF(py_%s);" % self.name),
  830.                                 failure_expression=("!py_%s" % self.name))
  831.         self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
  832.  
  833.  
  834. class CallbackInUserDataParam(Parameter):
  835.     def __init__(self, wrapper, name, free_it, **props):
  836.         Parameter.__init__(self, wrapper, name, **props)
  837.         self.free_it = free_it
  838.  
  839.     def get_c_type(self):
  840.         return "gpointer"
  841.  
  842.     def convert_c2py(self):
  843.         self.wrapper.add_declaration("PyObject **_user_data;")
  844.         cleanup = self.free_it and ("g_free(%s);" % self.name) or None
  845.         self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
  846.                                       % self.name),
  847.                                 cleanup=cleanup)
  848.  
  849.         self.wrapper.add_declaration("PyObject *py_func;")
  850.         cleanup = self.free_it and "Py_DECREF(py_func);" or None
  851.         self.wrapper.write_code(code="py_func = _user_data[0];",
  852.                                 cleanup=cleanup)
  853.         self.wrapper.set_call_target("py_func")
  854.  
  855.         self.wrapper.add_declaration("PyObject *py_user_data;")
  856.         cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
  857.         self.wrapper.write_code(code="py_user_data = _user_data[1];",
  858.                                 cleanup=cleanup)
  859.         self.wrapper.add_pyargv_item("py_user_data", optional=True)
  860.  
  861. def _test():
  862.     import sys
  863.  
  864.     if 1:
  865.         wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
  866.         wrapper.set_return_type(StringReturn(wrapper))
  867.         wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
  868.         wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
  869.         wrapper.add_parameter(GObjectParam(wrapper, "param3"))
  870.         #wrapper.add_parameter(InoutIntParam(wrapper, "param4"))
  871.         wrapper.generate(FileCodeSink(sys.stderr))
  872.  
  873.     if 0:
  874.         wrapper = ReverseWrapper("this_a_callback_wrapper")
  875.         wrapper.set_return_type(VoidReturn(wrapper))
  876.         wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
  877.         wrapper.add_parameter(GObjectParam(wrapper, "param2"))
  878.         wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
  879.         wrapper.generate(FileCodeSink(sys.stderr))
  880.  
  881. if __name__ == '__main__':
  882.     _test()
  883.