Add more remainders on missing methods of gio.Socket and related types
[pygobject.git] / codegen / reversewrapper.py
blobed48629dc076160e98b03e3cd62ebd49f927afd3
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
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'''
11 if ctype[-1] != '*':
12 return " ".join((ctype, name))
13 else:
14 return "".join((ctype, name))
17 class CodeSink(object):
18 def __init__(self):
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)
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)
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
40 def unindent(self):
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)
49 self.fp = fp
51 def writeln(self, line=''):
52 self.fp.write(self._format_code(line))
54 class MemoryCodeSink(CodeSink):
55 def __init__(self):
56 CodeSink.__init__(self)
57 self.lines = []
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())
66 self.lines = []
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)
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)
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
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]
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
104 def set_return_type(self, return_type):
105 assert isinstance(return_type, ReturnType)
106 self.return_type = return_type
108 def add_parameter(self, param):
109 assert isinstance(param, Parameter)
110 self.parameters.append(param)
112 def add_declaration(self, decl_code):
113 self.declarations.writeln(decl_code)
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)
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))
128 def push_code_sink(self, code_sink):
129 self.code_sinks_stack.insert(0, code_sink)
131 def pop_code_sink(self):
132 return self.code_sinks_stack.pop(0)
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
143 This method is to be used by TypeHandlers when generating code
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.
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)
184 self.push_code_sink(code_sink)
185 try:
186 self.return_type.write_error_return()
187 finally:
188 self.pop_code_sink()
190 code_sink.unindent()
191 code_sink.writeln("}")
192 if cleanup is not None:
193 self.cleanup_actions.insert(0, cleanup)
195 def generate(self, sink):
196 '''Generate the code into a CodeSink object'''
197 assert isinstance(sink, CodeSink)
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 */")
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);")
208 for param in self.parameters:
209 param.convert_c2py()
211 assert self.called_pyobj is not None,\
212 "Parameters failed to provide a target function or method."
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)))
221 self.return_type.write_decl()
222 self.add_declaration("PyObject *py_retval;")
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
253 self.body.writeln()
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
278 self.body.writeln()
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")
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")
300 ## -- Handle the return value --
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),)
311 sink.indent()
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),)))
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()
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("}")
354 class TypeHandler(object):
355 def __init__(self, wrapper, **props):
356 assert isinstance(wrapper, ReverseWrapper)
357 self.wrapper = wrapper
358 self.props = props
360 class ReturnType(TypeHandler):
362 supports_optional = False
364 def get_c_type(self):
365 raise NotImplementedError
367 def write_decl(self):
368 raise NotImplementedError
370 def write_error_return(self):
371 '''Write "return <value>" code in case of error'''
372 raise NotImplementedError
374 def write_conversion(self):
375 '''Writes code to convert Python return value in 'py_retval'
376 into C 'retval'. Returns a string with C boolean expression
377 that determines if anything went wrong. '''
378 raise NotImplementedError
380 class Parameter(TypeHandler):
382 def __init__(self, wrapper, name, **props):
383 TypeHandler.__init__(self, wrapper, **props)
384 self.name = name
386 def get_c_type(self):
387 raise NotImplementedError
389 def convert_c2py(self):
390 '''Write some code before calling the Python method.'''
391 pass
393 def format_for_c_proto(self):
394 return join_ctype_name(self.get_c_type(), self.name)
397 ###---
398 class StringParam(Parameter):
400 def get_c_type(self):
401 return self.props.get('c_type', 'char *').replace('const-', 'const ')
403 def convert_c2py(self):
404 if self.props.get('optional', False):
405 self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
406 self.wrapper.write_code(code=("if (%s)\n"
407 " py_%s = PyString_FromString(%s);\n"
408 % (self.name, self.name, self.name)),
409 cleanup=("Py_XDECREF(py_%s);" % self.name))
410 self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True)
411 else:
412 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
413 self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
414 (self.name, self.name)),
415 cleanup=("Py_DECREF(py_%s);" % self.name),
416 failure_expression=("!py_%s" % self.name))
417 self.wrapper.add_pyargv_item("py_%s" % self.name)
419 for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*',
420 'gchar-const*', 'string', 'static_string'):
421 argtypes.matcher.register_reverse(ctype, StringParam)
422 del ctype
424 class StringReturn(ReturnType):
426 def get_c_type(self):
427 return self.props.get('c_type', 'char *').replace('const-', 'const ')
428 #return "char *"
430 def write_decl(self):
431 self.wrapper.add_declaration("%s retval;" % self.get_c_type())
432 #self.wrapper.add_declaration("char *retval;")
434 def write_error_return(self):
435 self.wrapper.write_code("return NULL;")
437 def write_conversion(self):
438 self.wrapper.add_pyret_parse_item("s", "&retval", prepend=True)
439 self.wrapper.write_code("retval = g_strdup(retval);", code_sink=self.wrapper.post_return_code)
441 for ctype in ('char*', 'gchar*', 'const-gchar*'):
442 argtypes.matcher.register_reverse_ret(ctype, StringReturn)
443 del ctype
446 class VoidReturn(ReturnType):
448 def get_c_type(self):
449 return "void"
451 def write_decl(self):
452 pass
454 def write_error_return(self):
455 self.wrapper.write_code("return;")
457 def write_conversion(self):
458 self.wrapper.add_pyret_parse_item("", "", prepend=True)
460 argtypes.matcher.register_reverse_ret('void', VoidReturn)
461 argtypes.matcher.register_reverse_ret('none', VoidReturn)
463 class GObjectParam(Parameter):
465 def get_c_type(self):
466 return self.props.get('c_type', 'GObject *')
468 def convert_c2py(self):
469 self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
470 self.wrapper.write_code(code=("if (%s)\n"
471 " py_%s = pygobject_new((GObject *) %s);\n"
472 "else {\n"
473 " Py_INCREF(Py_None);\n"
474 " py_%s = Py_None;\n"
476 % (self.name, self.name, self.name, self.name)),
477 cleanup=("Py_DECREF(py_%s);" % self.name))
478 self.wrapper.add_pyargv_item("py_%s" % self.name)
480 argtypes.matcher.register_reverse('GObject*', GObjectParam)
482 class GObjectReturn(ReturnType):
484 supports_optional = True
486 def get_c_type(self):
487 return self.props.get('c_type', 'GObject *')
489 def write_decl(self):
490 if not self.props.get('optional'):
491 self.wrapper.add_declaration("%s retval;" % self.get_c_type())
492 else:
493 self.wrapper.add_declaration("%s retval = NULL;" % self.get_c_type())
495 def write_error_return(self):
496 self.wrapper.write_code("return NULL;")
498 def write_conversion(self):
499 if not self.props.get('optional'):
500 self.wrapper.write_code(
501 code=None,
502 failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)",
503 failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");')
504 self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
505 % self.get_c_type())
506 self.wrapper.write_code("g_object_ref((GObject *) retval);")
507 else:
508 self.wrapper.write_code(
509 code=None,
510 failure_expression="py_retval != Py_None && !PyObject_TypeCheck(py_retval, &PyGObject_Type)",
511 failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be None or a GObject");')
512 self.wrapper.write_code("if (py_retval != Py_None) {\n"
513 " retval = (%s) pygobject_get(py_retval);\n"
514 " g_object_ref((GObject *) retval);\n"
515 "}\n"
516 % self.get_c_type())
518 argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
522 class IntParam(Parameter):
524 def get_c_type(self):
525 return self.props.get('c_type', 'int')
527 def convert_c2py(self):
528 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
529 self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" %
530 (self.name, self.name)),
531 cleanup=("Py_DECREF(py_%s);" % self.name))
532 self.wrapper.add_pyargv_item("py_%s" % self.name)
534 class IntReturn(ReturnType):
535 def get_c_type(self):
536 return self.props.get('c_type', 'int')
537 def write_decl(self):
538 self.wrapper.add_declaration("%s retval;" % self.get_c_type())
539 def write_error_return(self):
540 self.wrapper.write_code("return -G_MAXINT;")
541 def write_conversion(self):
542 self.wrapper.add_pyret_parse_item("i", "&retval", prepend=True)
544 for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long',
545 'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16',
546 'gint16', 'gint32', 'GTime'):
547 argtypes.matcher.register_reverse(argtype, IntParam)
548 argtypes.matcher.register_reverse_ret(argtype, IntReturn)
549 del argtype
551 class IntPtrParam(Parameter):
552 def __init__(self, wrapper, name, **props):
553 if "direction" not in props:
554 raise argtypes.ArgTypeConfigurationError(
555 "cannot use int* parameter without direction")
556 if props["direction"] not in ("out", "inout"):
557 raise argtypes.ArgTypeConfigurationError(
558 "cannot use int* parameter with direction '%s'"
559 % (props["direction"],))
560 Parameter.__init__(self, wrapper, name, **props)
561 def get_c_type(self):
562 return self.props.get('c_type', 'int*')
563 def convert_c2py(self):
564 if self.props["direction"] == "inout":
565 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
566 self.wrapper.write_code(code=("py_%s = PyInt_FromLong(*%s);" %
567 (self.name, self.name)),
568 cleanup=("Py_DECREF(py_%s);" % self.name))
569 self.wrapper.add_pyargv_item("py_%s" % self.name)
570 self.wrapper.add_pyret_parse_item("i", self.name)
571 for argtype in ('int*', 'gint*'):
572 argtypes.matcher.register_reverse(argtype, IntPtrParam)
573 del argtype
576 class GEnumReturn(IntReturn):
577 def write_conversion(self):
578 self.wrapper.write_code(
579 code=None,
580 failure_expression=(
581 "pyg_enum_get_value(%s, py_retval, (gint *)&retval)"
582 % (self.props['typecode'],)))
584 argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
586 class GEnumParam(IntParam):
587 def convert_c2py(self):
588 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
589 self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" %
590 (self.name, self.props['typecode'], self.name)),
591 cleanup=("Py_DECREF(py_%s);" % self.name),
592 failure_expression=("!py_%s" % self.name))
593 self.wrapper.add_pyargv_item("py_%s" % self.name)
595 argtypes.matcher.register_reverse("GEnum", GEnumParam)
597 class GFlagsReturn(IntReturn):
598 def write_conversion(self):
599 self.wrapper.write_code(
600 code=None,
601 failure_expression=(
602 "pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
603 self.props['typecode']))
605 argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn)
607 class GFlagsParam(IntParam):
608 def convert_c2py(self):
609 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
610 self.wrapper.write_code(code=(
611 "py_%s = pyg_flags_from_gtype(%s, %s);" %
612 (self.name, self.props['typecode'], self.name)),
613 cleanup=("Py_DECREF(py_%s);" % self.name),
614 failure_expression=("!py_%s" % self.name))
615 self.wrapper.add_pyargv_item("py_%s" % self.name)
617 argtypes.matcher.register_reverse("GFlags", GFlagsParam)
620 class GtkTreePathParam(IntParam):
621 def convert_c2py(self):
622 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
623 self.wrapper.write_code(code=(
624 "py_%s = pygtk_tree_path_to_pyobject(%s);" %
625 (self.name, self.name)),
626 cleanup=("Py_DECREF(py_%s);" % self.name),
627 failure_expression=("!py_%s" % self.name))
628 self.wrapper.add_pyargv_item("py_%s" % self.name)
630 argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam)
633 class GtkTreePathReturn(ReturnType):
634 def get_c_type(self):
635 return self.props.get('c_type', 'GtkTreePath *')
636 def write_decl(self):
637 self.wrapper.add_declaration("GtkTreePath * retval;")
638 def write_error_return(self):
639 self.wrapper.write_code("return NULL;")
640 def write_conversion(self):
641 self.wrapper.write_code(
642 "retval = pygtk_tree_path_from_pyobject(py_retval);\n",
643 failure_expression=('!retval'),
644 failure_exception=(
645 'PyErr_SetString(PyExc_TypeError, "retval should be a GtkTreePath");'))
647 argtypes.matcher.register_reverse_ret("GtkTreePath*", GtkTreePathReturn)
650 class BooleanReturn(ReturnType):
651 def get_c_type(self):
652 return "gboolean"
653 def write_decl(self):
654 self.wrapper.add_declaration("gboolean retval;")
655 self.wrapper.add_declaration("PyObject *py_main_retval;")
656 def write_error_return(self):
657 self.wrapper.write_code("return FALSE;")
658 def write_conversion(self):
659 self.wrapper.add_pyret_parse_item("O", "&py_main_retval", prepend=True)
660 self.wrapper.write_code(
661 "retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;",
662 code_sink=self.wrapper.post_return_code)
663 argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
665 class BooleanParam(Parameter):
666 def get_c_type(self):
667 return "gboolean"
668 def convert_c2py(self):
669 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
670 self.wrapper.write_code("py_%s = %s? Py_True : Py_False;"
671 % (self.name, self.name))
672 self.wrapper.add_pyargv_item("py_%s" % self.name)
674 argtypes.matcher.register_reverse("gboolean", BooleanParam)
677 class DoubleParam(Parameter):
678 def get_c_type(self):
679 return self.props.get('c_type', 'gdouble')
680 def convert_c2py(self):
681 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
682 self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" %
683 (self.name, self.name)),
684 cleanup=("Py_DECREF(py_%s);" % self.name))
685 self.wrapper.add_pyargv_item("py_%s" % self.name)
687 class DoublePtrParam(Parameter):
688 def __init__(self, wrapper, name, **props):
689 if "direction" not in props:
690 raise argtypes.ArgTypeConfigurationError(
691 "cannot use double* parameter without direction")
692 if props["direction"] not in ("out", ): # inout not yet implemented
693 raise argtypes.ArgTypeConfigurationError(
694 "cannot use double* parameter with direction '%s'"
695 % (props["direction"],))
696 Parameter.__init__(self, wrapper, name, **props)
697 def get_c_type(self):
698 return self.props.get('c_type', 'double*')
699 def convert_c2py(self):
700 self.wrapper.add_pyret_parse_item("d", self.name)
701 for argtype in ('double*', 'gdouble*'):
702 argtypes.matcher.register_reverse(argtype, DoublePtrParam)
703 del argtype
705 class DoubleReturn(ReturnType):
706 def get_c_type(self):
707 return self.props.get('c_type', 'gdouble')
708 def write_decl(self):
709 self.wrapper.add_declaration("%s retval;" % self.get_c_type())
710 def write_error_return(self):
711 self.wrapper.write_code("return -G_MAXFLOAT;")
712 def write_conversion(self):
713 self.wrapper.add_pyret_parse_item("d", "&retval", prepend=True)
715 for argtype in ('float', 'double', 'gfloat', 'gdouble'):
716 argtypes.matcher.register_reverse(argtype, DoubleParam)
717 argtypes.matcher.register_reverse_ret(argtype, DoubleReturn)
720 class GBoxedParam(Parameter):
721 def get_c_type(self):
722 return self.props.get('c_type').replace('const-', 'const ')
723 def convert_c2py(self):
724 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
725 ctype = self.get_c_type()
726 if ctype.startswith('const '):
727 ctype_no_const = ctype[len('const '):]
728 self.wrapper.write_code(
729 code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' %
730 (self.name, self.props['typecode'],
731 ctype_no_const, self.name)),
732 cleanup=("Py_DECREF(py_%s);" % self.name))
733 else:
734 self.wrapper.write_code(
735 code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' %
736 (self.name, self.props['typecode'], self.name)),
737 cleanup=("Py_DECREF(py_%s);" % self.name))
738 self.wrapper.add_pyargv_item("py_%s" % self.name)
740 argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
743 class GBoxedReturn(ReturnType):
744 def get_c_type(self):
745 return self.props.get('c_type')
746 def write_decl(self):
747 self.wrapper.add_declaration("%s retval;" % self.get_c_type())
748 def write_error_return(self):
749 self.wrapper.write_code("return retval;")
750 def write_conversion(self):
751 self.wrapper.write_code(code = None,
752 failure_expression=("!pyg_boxed_check(py_retval, %s)" %
753 (self.props['typecode'],)),
754 failure_exception=(
755 'PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
756 % (self.props['typename'],)))
757 self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
758 self.props['typename'])
760 argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
763 class GdkRegionPtrReturn(GBoxedReturn):
764 def write_error_return(self):
765 self.wrapper.write_code("return gdk_region_new();")
766 def write_conversion(self):
767 self.props['typecode'] = 'PYGDK_TYPE_REGION'
768 self.props['typename'] = 'GdkRegion'
769 super(GdkRegionPtrReturn, self).write_conversion()
771 argtypes.matcher.register_reverse_ret("GdkRegion*", GdkRegionPtrReturn)
774 class PangoFontDescriptionReturn(GBoxedReturn):
775 def write_error_return(self):
776 self.wrapper.write_code("return pango_font_description_new();")
777 def write_conversion(self):
778 self.props['typecode'] = 'PANGO_TYPE_FONT_DESCRIPTION'
779 self.props['typename'] = 'PangoFontDescription'
780 super(PangoFontDescriptionReturn, self).write_conversion()
782 argtypes.matcher.register_reverse_ret("PangoFontDescription*",
783 PangoFontDescriptionReturn)
786 class PangoFontMetricsReturn(GBoxedReturn):
787 def write_error_return(self):
788 self.wrapper.write_code("return pango_font_metrics_new();")
789 def write_conversion(self):
790 self.props['typecode'] = 'PANGO_TYPE_FONT_METRICS'
791 self.props['typename'] = 'PangoFontMetrics'
792 super(PangoFontMetricsReturn, self).write_conversion()
794 argtypes.matcher.register_reverse_ret("PangoFontMetrics*",
795 PangoFontMetricsReturn)
798 class PangoLanguageReturn(GBoxedReturn):
799 def write_error_return(self):
800 self.wrapper.write_code("return pango_language_from_string(\"\");")
801 def write_conversion(self):
802 self.props['typecode'] = 'PANGO_TYPE_LANGUAGE'
803 self.props['typename'] = 'PangoLanguage'
804 super(PangoLanguageReturn, self).write_conversion()
806 argtypes.matcher.register_reverse_ret("PangoLanguage*", PangoLanguageReturn)
809 class GdkRectanglePtrParam(Parameter):
810 def get_c_type(self):
811 return self.props.get('c_type').replace('const-', 'const ')
812 def convert_c2py(self):
813 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
814 self.wrapper.write_code(
815 code=('py_%s = pyg_boxed_new(GDK_TYPE_RECTANGLE, %s, TRUE, TRUE);' %
816 (self.name, self.name)),
817 cleanup=("Py_DECREF(py_%s);" % self.name))
818 self.wrapper.add_pyargv_item("py_%s" % self.name)
820 argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
821 argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam)
824 class GErrorParam(Parameter):
825 def get_c_type(self):
826 return self.props.get('c_type').replace('**', ' **')
827 def convert_c2py(self):
828 self.wrapper.write_code(code=None,
829 failure_expression=("pyg_gerror_exception_check(%s)" % self.name),
830 code_sink=self.wrapper.check_exception_code)
832 argtypes.matcher.register_reverse('GError**', GErrorParam)
835 class PyGObjectMethodParam(Parameter):
836 def __init__(self, wrapper, name, method_name, **props):
837 Parameter.__init__(self, wrapper, name, **props)
838 self.method_name = method_name
840 def get_c_type(self):
841 return self.props.get('c_type', 'GObject *')
843 def convert_c2py(self):
844 self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
845 self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
846 (self.name, self.name)),
847 cleanup=("Py_DECREF(py_%s);" % self.name),
848 failure_expression=("!py_%s" % self.name))
849 self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
852 class CallbackInUserDataParam(Parameter):
853 def __init__(self, wrapper, name, free_it, **props):
854 Parameter.__init__(self, wrapper, name, **props)
855 self.free_it = free_it
857 def get_c_type(self):
858 return "gpointer"
860 def convert_c2py(self):
861 self.wrapper.add_declaration("PyObject **_user_data;")
862 cleanup = self.free_it and ("g_free(%s);" % self.name) or None
863 self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
864 % self.name),
865 cleanup=cleanup)
867 self.wrapper.add_declaration("PyObject *py_func;")
868 cleanup = self.free_it and "Py_DECREF(py_func);" or None
869 self.wrapper.write_code(code="py_func = _user_data[0];",
870 cleanup=cleanup)
871 self.wrapper.set_call_target("py_func")
873 self.wrapper.add_declaration("PyObject *py_user_data;")
874 cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
875 self.wrapper.write_code(code="py_user_data = _user_data[1];",
876 cleanup=cleanup)
877 self.wrapper.add_pyargv_item("py_user_data", optional=True)
879 def _test():
880 import sys
882 if 1:
883 wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
884 wrapper.set_return_type(StringReturn(wrapper))
885 wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
886 wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
887 wrapper.add_parameter(GObjectParam(wrapper, "param3"))
888 #wrapper.add_parameter(InoutIntParam(wrapper, "param4"))
889 wrapper.generate(FileCodeSink(sys.stderr))
891 if 0:
892 wrapper = ReverseWrapper("this_a_callback_wrapper")
893 wrapper.set_return_type(VoidReturn(wrapper))
894 wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
895 wrapper.add_parameter(GObjectParam(wrapper, "param2"))
896 wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
897 wrapper.generate(FileCodeSink(sys.stderr))
899 if __name__ == '__main__':
900 _test()