2 ### Code to generate "Reverse Wrappers", i.e. C->Python wrappers
3 ### (C) 2004 Gustavo Carneiro <gjc@gnome.org>
7 DEBUG_MODE = ('PYGTK_CODEGEN_DEBUG' in os.environ)
9 def join_ctype_name(ctype, name):
10 '''Joins a C type and a variable name into a single string'''
12 return " ".join((ctype, name))
14 return "".join((ctype, name))
17 class CodeSink(object):
19 self.indent_level = 0 # current indent level
20 self.indent_stack = [] # previous indent levels
22 def _format_code(self, code):
23 assert isinstance(code, str)
25 for line in code.split('\n'):
26 l.append(' '*self.indent_level + line)
31 def writeln(self, line=''):
32 raise NotImplementedError
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
41 '''Revert indentation level to the value before last indent() call'''
42 self.indent_level = self.indent_stack.pop()
45 class FileCodeSink(CodeSink):
46 def __init__(self, fp):
47 CodeSink.__init__(self)
48 assert isinstance(fp, file)
51 def writeln(self, line=''):
52 self.fp.write(self._format_code(line))
54 class MemoryCodeSink(CodeSink):
56 CodeSink.__init__(self)
59 def writeln(self, line=''):
60 self.lines.append(self._format_code(line))
62 def flush_to(self, sink):
63 assert isinstance(sink, CodeSink)
64 for line in self.lines:
65 sink.writeln(line.rstrip())
70 for line in self.lines:
71 l.append(self._format_code(line))
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)
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
88 self.declarations = MemoryCodeSink()
89 self.post_return_code = MemoryCodeSink()
90 self.body = MemoryCodeSink()
91 self.cleanup_actions = []
92 self.pyargv_items = []
93 self.pyargv_optional_items = []
94 self.pyret_parse_items = [] # list of (format_spec, parameter)
96 def set_call_target(self, called_pyobj, method_name=None):
97 assert called_pyobj is not None
98 assert self.called_pyobj is None
99 self.called_pyobj = called_pyobj
100 self.method_name = method_name
102 def set_return_type(self, return_type):
103 assert isinstance(return_type, ReturnType)
104 self.return_type = return_type
106 def add_parameter(self, param):
107 assert isinstance(param, Parameter)
108 self.parameters.append(param)
110 def add_declaration(self, decl_code):
111 self.declarations.writeln(decl_code)
113 def add_pyargv_item(self, variable, optional=False):
115 self.pyargv_optional_items.append(variable)
117 self.pyargv_items.append(variable)
119 def add_pyret_parse_item(self, format_specifier, parameter, prepend=False):
121 self.pyret_parse_items.insert(0, (format_specifier, parameter))
123 self.pyret_parse_items.append((format_specifier, parameter))
125 def write_code(self, code,
127 failure_expression=None,
128 failure_cleanup=None,
129 failure_exception=None,
131 '''Add a chunk of code with cleanup and error handling
133 This method is to be used by TypeHandlers when generating code
137 cleanup -- code to cleanup any dynamic resources created by @code
138 (except in case of failure) (default None)
139 failure_expression -- C boolean expression to indicate
140 if anything failed (default None)
141 failure_cleanup -- code to cleanup any dynamic resources
142 created by @code in case of failure (default None)
143 failure_exception -- code to raise an exception in case of
144 failure (which will be immediately
145 printed and cleared), (default None)
146 code_sink -- "code sink" to use; by default,
147 ReverseWrapper.body is used, which writes the
148 main body of the wrapper, before calling the
149 python method. Alternatively,
150 ReverseWrapper.after_pyret_parse can be used, to
151 write code after the PyArg_ParseTuple that
152 parses the python method return value.
154 if code_sink is None:
155 code_sink = self.body
157 code_sink.writeln(code)
158 if failure_expression is not None:
159 code_sink.writeln("if (%s) {" % (failure_expression,))
161 if failure_exception is None:
162 code_sink.writeln("if (PyErr_Occurred())")
164 code_sink.writeln("PyErr_Print();")
167 code_sink.writeln(failure_exception)
168 code_sink.writeln("PyErr_Print();")
169 if failure_cleanup is not None:
170 code_sink.writeln(failure_cleanup)
171 for cleanup_action in self.cleanup_actions:
172 code_sink.writeln(cleanup_action)
173 self.return_type.write_error_return()
175 code_sink.writeln("}")
176 if cleanup is not None:
177 self.cleanup_actions.insert(0, cleanup)
179 def generate(self, sink):
180 '''Generate the code into a CodeSink object'''
181 assert isinstance(sink, CodeSink)
184 self.declarations.writeln("/* begin declarations */")
185 self.body.writeln("/* begin main body */")
186 self.post_return_code.writeln("/* begin post-return code */")
188 self.add_declaration("PyGILState_STATE __py_state;")
189 self.write_code(code="__py_state = pyg_gil_state_ensure();",
190 cleanup="pyg_gil_state_release(__py_state);")
192 for param in self.parameters:
195 assert self.called_pyobj is not None,\
196 "Parameters failed to provide a target function or method."
199 sink.writeln('static %s' % self.return_type.get_c_type())
201 sink.writeln(self.return_type.get_c_type())
202 c_proto_params = map(Parameter.format_for_c_proto, self.parameters)
203 sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params)))
205 self.return_type.write_decl()
206 self.add_declaration("PyObject *py_retval;")
208 ## Handle number of arguments
209 if self.pyargv_items:
210 self.add_declaration("PyObject *py_args;")
212 if self.pyargv_optional_items:
213 self.add_declaration("int argc = %i;" % len(self.pyargv_items))
215 for arg in self.pyargv_optional_items:
216 self.body.writeln("if (%s)" % arg)
218 self.body.writeln("++argc;")
221 argc = str(len(self.pyargv_items))
223 if self.pyargv_optional_items:
224 self.add_declaration("PyObject *py_args;")
226 self.add_declaration("int argc = 0;")
228 for arg in self.pyargv_optional_items:
229 self.body.writeln("if (%s)" % arg)
231 self.body.writeln("++argc;")
239 if py_args != "NULL":
240 self.write_code("py_args = PyTuple_New(%s);" % argc,
241 cleanup="Py_DECREF(py_args);")
243 for arg in self.pyargv_items:
244 try: # try to remove the Py_DECREF cleanup action, if we can
245 self.cleanup_actions.remove("Py_DECREF(%s);" % arg)
246 except ValueError: # otherwise we have to Py_INCREF..
247 self.body.writeln("Py_INCREF(%s);" % arg)
248 self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
250 for arg in self.pyargv_optional_items:
251 self.body.writeln("if (%s) {" % arg)
253 try: # try to remove the Py_DECREF cleanup action, if we can
254 self.cleanup_actions.remove("Py_XDECREF(%s);" % arg)
255 except ValueError: # otherwise we have to Py_INCREF..
256 self.body.writeln("Py_INCREF(%s);" % arg)
257 self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
259 self.body.writeln("}")
264 ## Call the python method
265 if self.method_name is None:
266 self.write_code("py_retval = PyObject_Call(%s, %s);"
267 % (self.called_pyobj, py_args),
268 cleanup="Py_DECREF(py_retval);",
269 failure_expression="!py_retval")
271 self.add_declaration("PyObject *py_method;")
272 self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");"
273 % (self.called_pyobj, self.method_name),
274 cleanup="Py_DECREF(py_method);",
275 failure_expression="!py_method")
276 self.write_code("py_retval = PyObject_CallObject(py_method, %s);"
278 cleanup="Py_DECREF(py_retval);",
279 failure_expression="!py_retval")
281 ## -- Handle the return value --
283 ## we need to check if the return_type object is prepared to cooperate with multiple return values
284 len_before = len(self.pyret_parse_items)
285 self.return_type.write_conversion()
286 len_after = len(self.pyret_parse_items)
287 assert (self.return_type.get_c_type() == 'void'
288 or not (len_before == len_after and len_after > 0)),\
289 ("Bug in reverse wrappers: return type handler %s"
290 " is not prepared to cooperate multiple return values") % (type(self.return_type),)
294 if len(self.pyret_parse_items) == 1:
295 ## if retval is one item only, pack it in a tuple so we
296 ## can use PyArg_ParseTuple as usual..
297 self.write_code('py_retval = Py_BuildValue("(N)", py_retval);')
298 if len(self.pyret_parse_items) > 0:
299 ## Parse return values using PyArg_ParseTuple
300 self.write_code(code=None, failure_expression=(
301 '!PyArg_ParseTuple(py_retval, "%s", %s)' % (
302 "".join([format for format, param in self.pyret_parse_items]),
303 ", ".join([param for format, param in self.pyret_parse_items]))))
306 self.declarations.writeln("/* end declarations */")
307 self.declarations.flush_to(sink)
310 self.body.writeln("/* end main body */")
311 self.body.flush_to(sink)
314 self.post_return_code.writeln("/* end post-return code */")
315 self.post_return_code.flush_to(sink)
318 for cleanup_action in self.cleanup_actions:
319 sink.writeln(cleanup_action)
320 if self.return_type.get_c_type() != 'void':
322 sink.writeln("return retval;")
326 class TypeHandler(object):
327 def __init__(self, wrapper, **props):
328 assert isinstance(wrapper, ReverseWrapper)
329 self.wrapper = wrapper
332 class ReturnType(TypeHandler):
334 def get_c_type(self):
335 raise NotImplementedError
337 def write_decl(self):
338 raise NotImplementedError
340 def write_error_return(self):
341 '''Write "return <value>" code in case of error'''
342 raise NotImplementedError
344 def write_conversion(self):
345 '''Writes code to convert Python return value in 'py_retval'
346 into C 'retval'. Returns a string with C boolean expression
347 that determines if anything went wrong. '''
348 raise NotImplementedError
350 class Parameter(TypeHandler):
352 def __init__(self, wrapper, name, **props):
353 TypeHandler.__init__(self, wrapper, **props)
356 def get_c_type(self):
357 raise NotImplementedError
359 def convert_c2py(self):
360 '''Write some code before calling the Python method.'''
363 def format_for_c_proto(self):
364 return join_ctype_name(self.get_c_type(), self.name)
368 class StringParam(Parameter):
370 def get_c_type(self):
371 return self.props.get('c_type', 'char *').replace('const-', 'const ')
373 def convert_c2py(self):
374 if self.props.get('optional', False):
375 self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
376 self.wrapper.write_code(code=("if (%s)\n"
377 " py_%s = PyString_FromString(%s);\n"
378 % (self.name, self.name, self.name)),
379 cleanup=("Py_XDECREF(py_%s);" % self.name))
380 self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True)
382 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
383 self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
384 (self.name, self.name)),
385 cleanup=("Py_DECREF(py_%s);" % self.name),
386 failure_expression=("!py_%s" % self.name))
387 self.wrapper.add_pyargv_item("py_%s" % self.name)
389 for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*',
390 'gchar-const*', 'string', 'static_string'):
391 argtypes.matcher.register_reverse(ctype, StringParam)
394 class StringReturn(ReturnType):
396 def get_c_type(self):
399 def write_decl(self):
400 self.wrapper.add_declaration("char *retval;")
402 def write_error_return(self):
403 self.wrapper.write_code("return NULL;")
405 def write_conversion(self):
406 self.wrapper.add_pyret_parse_item("s", "&retval", prepend=True)
407 self.wrapper.write_code("retval = g_strdup(retval);", code_sink=self.wrapper.post_return_code)
409 for ctype in ('char*', 'gchar*'):
410 argtypes.matcher.register_reverse_ret(ctype, StringReturn)
414 class VoidReturn(ReturnType):
416 def get_c_type(self):
419 def write_decl(self):
422 def write_error_return(self):
423 self.wrapper.write_code("return;")
425 def write_conversion(self):
426 self.wrapper.write_code(
428 failure_expression="py_retval != Py_None",
429 failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be None");')
431 argtypes.matcher.register_reverse_ret('void', VoidReturn)
432 argtypes.matcher.register_reverse_ret('none', VoidReturn)
434 class GObjectParam(Parameter):
436 def get_c_type(self):
437 return self.props.get('c_type', 'GObject *')
439 def convert_c2py(self):
440 self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
441 self.wrapper.write_code(code=("if (%s)\n"
442 " py_%s = pygobject_new((GObject *) %s);\n"
444 " Py_INCREF(Py_None);\n"
445 " py_%s = Py_None;\n"
447 % (self.name, self.name, self.name, self.name)),
448 cleanup=("Py_DECREF(py_%s);" % self.name))
449 self.wrapper.add_pyargv_item("py_%s" % self.name)
451 argtypes.matcher.register_reverse('GObject*', GObjectParam)
453 class GObjectReturn(ReturnType):
455 def get_c_type(self):
456 return self.props.get('c_type', 'GObject *')
458 def write_decl(self):
459 self.wrapper.add_declaration("%s retval;" % self.get_c_type())
461 def write_error_return(self):
462 self.wrapper.write_code("return NULL;")
464 def write_conversion(self):
465 self.wrapper.write_code(
467 failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)",
468 failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");')
469 self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
471 self.wrapper.write_code("g_object_ref((GObject *) retval);")
473 argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
477 class IntParam(Parameter):
479 def get_c_type(self):
480 return self.props.get('c_type', 'int')
482 def convert_c2py(self):
483 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
484 self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" %
485 (self.name, self.name)),
486 cleanup=("Py_DECREF(py_%s);" % self.name))
487 self.wrapper.add_pyargv_item("py_%s" % self.name)
489 class IntReturn(ReturnType):
490 def get_c_type(self):
491 return self.props.get('c_type', 'int')
492 def write_decl(self):
493 self.wrapper.add_declaration("%s retval;" % self.get_c_type())
494 def write_error_return(self):
495 self.wrapper.write_code("return -G_MAXINT;")
496 def write_conversion(self):
497 self.wrapper.add_pyret_parse_item("i", "&retval", prepend=True)
499 for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long',
500 'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16',
501 'gint16', 'gint32', 'GTime'):
502 argtypes.matcher.register_reverse(argtype, IntParam)
503 argtypes.matcher.register_reverse_ret(argtype, IntReturn)
506 class IntPtrParam(Parameter):
507 def __init__(self, wrapper, name, **props):
508 if "direction" not in props:
509 raise ValueError("cannot use int* parameter without direction")
510 if props["direction"] not in ("out", "inout"):
511 raise ValueError("cannot use int* parameter with direction '%s'" % (props["direction"],))
512 Parameter.__init__(self, wrapper, name, **props)
513 def get_c_type(self):
514 return self.props.get('c_type', 'int*')
515 def convert_c2py(self):
516 if self.props["direction"] == "inout":
517 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
518 self.wrapper.write_code(code=("py_%s = PyInt_FromLong(*%s);" %
519 (self.name, self.name)),
520 cleanup=("Py_DECREF(py_%s);" % self.name))
521 self.wrapper.add_pyargv_item("py_%s" % self.name)
522 self.wrapper.add_pyret_parse_item("i", self.name)
523 for argtype in ('int*', 'gint*'):
524 argtypes.matcher.register_reverse(argtype, IntPtrParam)
528 class GEnumReturn(IntReturn):
529 def write_conversion(self):
530 self.wrapper.write_code(
532 failure_expression=("pyg_enum_get_value(%s, py_retval, (gint *)&retval)" %
533 self.props['typecode']))
535 argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
537 class GEnumParam(IntParam):
538 def convert_c2py(self):
539 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
540 self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" %
541 (self.name, self.props['typecode'], self.name)),
542 cleanup=("Py_DECREF(py_%s);" % self.name),
543 failure_expression=("!py_%s" % self.name))
544 self.wrapper.add_pyargv_item("py_%s" % self.name)
546 argtypes.matcher.register_reverse("GEnum", GEnumParam)
548 class GFlagsReturn(IntReturn):
549 def write_conversion(self):
550 self.wrapper.write_code(
552 failure_expression=("pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
553 self.props['typecode']))
555 argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn)
557 class GFlagsParam(IntParam):
558 def convert_c2py(self):
559 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
560 self.wrapper.write_code(code=("py_%s = pyg_flags_from_gtype(%s, %s);" %
561 (self.name, self.props['typecode'], self.name)),
562 cleanup=("Py_DECREF(py_%s);" % self.name),
563 failure_expression=("!py_%s" % self.name))
564 self.wrapper.add_pyargv_item("py_%s" % self.name)
566 argtypes.matcher.register_reverse("GFlags", GFlagsParam)
569 class GtkTreePathParam(IntParam):
570 def convert_c2py(self):
571 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
572 self.wrapper.write_code(code=("py_%s = pygtk_tree_path_to_pyobject(%s);" %
573 (self.name, self.name)),
574 cleanup=("Py_DECREF(py_%s);" % self.name),
575 failure_expression=("!py_%s" % self.name))
576 self.wrapper.add_pyargv_item("py_%s" % self.name)
578 argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam)
581 class BooleanReturn(ReturnType):
582 def get_c_type(self):
584 def write_decl(self):
585 self.wrapper.add_declaration("gboolean retval;")
586 self.wrapper.add_declaration("PyObject *py_main_retval;")
587 def write_error_return(self):
588 self.wrapper.write_code("return FALSE;")
589 def write_conversion(self):
590 self.wrapper.add_pyret_parse_item("O", "&py_main_retval", prepend=True)
591 self.wrapper.write_code("retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;",
592 code_sink=self.wrapper.post_return_code)
593 argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
595 class BooleanParam(Parameter):
596 def get_c_type(self):
598 def convert_c2py(self):
599 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
600 self.wrapper.write_code("py_%s = %s? Py_True : Py_False;"
601 % (self.name, self.name))
602 self.wrapper.add_pyargv_item("py_%s" % self.name)
604 argtypes.matcher.register_reverse("gboolean", BooleanParam)
607 class DoubleParam(Parameter):
608 def get_c_type(self):
609 return self.props.get('c_type', 'gdouble')
610 def convert_c2py(self):
611 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
612 self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" %
613 (self.name, self.name)),
614 cleanup=("Py_DECREF(py_%s);" % self.name))
615 self.wrapper.add_pyargv_item("py_%s" % self.name)
617 class DoublePtrParam(Parameter):
618 def __init__(self, wrapper, name, **props):
619 if "direction" not in props:
620 raise ValueError("cannot use double* parameter without direction")
621 if props["direction"] not in ("out", ): # inout not yet implemented
622 raise ValueError("cannot use double* parameter with direction '%s'" % (props["direction"],))
623 Parameter.__init__(self, wrapper, name, **props)
624 def get_c_type(self):
625 return self.props.get('c_type', 'double*')
626 def convert_c2py(self):
627 self.wrapper.add_pyret_parse_item("d", self.name)
628 for argtype in ('double*', 'gdouble*'):
629 argtypes.matcher.register_reverse(argtype, DoublePtrParam)
632 class DoubleReturn(ReturnType):
633 def get_c_type(self):
634 return self.props.get('c_type', 'gdouble')
635 def write_decl(self):
636 self.wrapper.add_declaration("%s retval;" % self.get_c_type())
637 def write_error_return(self):
638 self.wrapper.write_code("return -G_MAXFLOAT;")
639 def write_conversion(self):
640 self.wrapper.write_code(
642 failure_expression="!PyFloat_AsDouble(py_retval)",
643 failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a float");')
644 self.wrapper.write_code("retval = PyFloat_AsDouble(py_retval);")
646 for argtype in ('float', 'double', 'gfloat', 'gdouble'):
647 argtypes.matcher.register_reverse(argtype, DoubleParam)
648 argtypes.matcher.register_reverse_ret(argtype, DoubleReturn)
651 class GBoxedParam(Parameter):
652 def get_c_type(self):
653 return self.props.get('c_type').replace('const-', 'const ')
654 def convert_c2py(self):
655 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
656 ctype = self.get_c_type()
657 if ctype.startswith('const '):
658 ctype_no_const = ctype[len('const '):]
659 self.wrapper.write_code(
660 code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' %
661 (self.name, self.props['typecode'],
662 ctype_no_const, self.name)),
663 cleanup=("Py_DECREF(py_%s);" % self.name))
665 self.wrapper.write_code(
666 code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' %
667 (self.name, self.props['typecode'], self.name)),
668 cleanup=("Py_DECREF(py_%s);" % self.name))
669 self.wrapper.add_pyargv_item("py_%s" % self.name)
671 argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
673 class GBoxedReturn(ReturnType):
674 def get_c_type(self):
675 return self.props.get('c_type')
676 def write_decl(self):
677 self.wrapper.add_declaration("%s retval;" % self.get_c_type())
678 def write_error_return(self):
679 self.wrapper.write_code("return retval;")
680 def write_conversion(self):
681 self.wrapper.write_code(
682 failure_expression=("!pyg_boxed_check(py_retval, %s)" %
683 (self.props['typecode'],)),
684 failure_cleanup=('PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
685 % (self.props['typename'],)))
686 self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
687 self.props['typename'])
689 argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
692 class GdkRectanglePtrParam(Parameter):
693 def get_c_type(self):
694 return self.props.get('c_type').replace('const-', 'const ')
695 def convert_c2py(self):
696 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
697 self.wrapper.write_code(
698 code=('py_%s = pyg_boxed_new(GDK_TYPE_RECTANGLE, %s, TRUE, TRUE);' %
699 (self.name, self.name)),
700 cleanup=("Py_DECREF(py_%s);" % self.name))
701 self.wrapper.add_pyargv_item("py_%s" % self.name)
703 argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
704 argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam)
707 class PyGObjectMethodParam(Parameter):
708 def __init__(self, wrapper, name, method_name, **props):
709 Parameter.__init__(self, wrapper, name, **props)
710 self.method_name = method_name
712 def get_c_type(self):
713 return self.props.get('c_type', 'GObject *')
715 def convert_c2py(self):
716 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
717 self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
718 (self.name, self.name)),
719 cleanup=("Py_DECREF(py_%s);" % self.name),
720 failure_expression=("!py_%s" % self.name))
721 self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
723 class CallbackInUserDataParam(Parameter):
724 def __init__(self, wrapper, name, free_it, **props):
725 Parameter.__init__(self, wrapper, name, **props)
726 self.free_it = free_it
728 def get_c_type(self):
731 def convert_c2py(self):
732 self.wrapper.add_declaration("PyObject **_user_data;")
733 cleanup = self.free_it and ("g_free(%s);" % self.name) or None
734 self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
738 self.wrapper.add_declaration("PyObject *py_func;")
739 cleanup = self.free_it and "Py_DECREF(py_func);" or None
740 self.wrapper.write_code(code="py_func = _user_data[0];",
742 self.wrapper.set_call_target("py_func")
744 self.wrapper.add_declaration("PyObject *py_user_data;")
745 cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
746 self.wrapper.write_code(code="py_user_data = _user_data[1];",
748 self.wrapper.add_pyargv_item("py_user_data", optional=True)
754 wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
755 wrapper.set_return_type(StringReturn(wrapper))
756 wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
757 wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
758 wrapper.add_parameter(GObjectParam(wrapper, "param3"))
759 #wrapper.add_parameter(InoutIntParam(wrapper, "param4"))
760 wrapper.generate(FileCodeSink(sys.stderr))
763 wrapper = ReverseWrapper("this_a_callback_wrapper")
764 wrapper.set_return_type(VoidReturn(wrapper))
765 wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
766 wrapper.add_parameter(GObjectParam(wrapper, "param2"))
767 wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
768 wrapper.generate(FileCodeSink(sys.stderr))
770 if __name__ == '__main__':