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
.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):
117 self
.pyargv_optional_items
.append(variable
)
119 self
.pyargv_items
.append(variable
)
121 def add_pyret_parse_item(self
, format_specifier
, parameter
, prepend
=False):
123 self
.pyret_parse_items
.insert(0, (format_specifier
, parameter
))
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
,
137 failure_expression
=None,
138 failure_cleanup
=None,
139 failure_exception
=None,
141 '''Add a chunk of code with cleanup and error handling
143 This method is to be used by TypeHandlers when generating code
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]
167 code_sink
.writeln(code
)
168 if failure_expression
is not None:
169 code_sink
.writeln("if (%s) {" % (failure_expression
,))
171 if failure_exception
is None:
172 code_sink
.writeln("if (PyErr_Occurred())")
174 code_sink
.writeln("PyErr_Print();")
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
)
186 self
.return_type
.write_error_return()
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
)
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
:
211 assert self
.called_pyobj
is not None,\
212 "Parameters failed to provide a target function or method."
215 sink
.writeln('static %s' % self
.return_type
.get_c_type())
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;")
228 if self
.pyargv_optional_items
:
229 self
.add_declaration("int argc = %i;" % len(self
.pyargv_items
))
231 for arg
in self
.pyargv_optional_items
:
232 self
.body
.writeln("if (%s)" % arg
)
234 self
.body
.writeln("++argc;")
237 argc
= str(len(self
.pyargv_items
))
239 if self
.pyargv_optional_items
:
240 self
.add_declaration("PyObject *py_args;")
242 self
.add_declaration("int argc = 0;")
244 for arg
in self
.pyargv_optional_items
:
245 self
.body
.writeln("if (%s)" % arg
)
247 self
.body
.writeln("++argc;")
255 if py_args
!= "NULL":
256 self
.write_code("py_args = PyTuple_New(%s);" % argc
,
257 cleanup
="Py_DECREF(py_args);")
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
))
266 for arg
in self
.pyargv_optional_items
:
267 self
.body
.writeln("if (%s) {" % arg
)
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
))
275 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")
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);"
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
),)
313 if self
.pyret_parse_items
== [("", "")]:
314 ## special case when there are no return parameters
317 failure_expression
='py_retval != Py_None',
318 failure_exception
=('PyErr_SetString(PyExc_TypeError, '
319 '"virtual method should return None");'))
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
),)))
334 self
.declarations
.writeln("/* end declarations */")
335 self
.declarations
.flush_to(sink
)
338 self
.body
.writeln("/* end main body */")
339 self
.body
.flush_to(sink
)
342 self
.post_return_code
.writeln("/* end post-return code */")
343 self
.post_return_code
.flush_to(sink
)
346 for cleanup_action
in self
.cleanup_actions
:
347 sink
.writeln(cleanup_action
)
348 if self
.return_type
.get_c_type() != 'void':
350 sink
.writeln("return retval;")
354 class TypeHandler(object):
355 def __init__(self
, wrapper
, **props
):
356 assert isinstance(wrapper
, ReverseWrapper
)
357 self
.wrapper
= wrapper
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
)
386 def get_c_type(self
):
387 raise NotImplementedError
389 def convert_c2py(self
):
390 '''Write some code before calling the Python method.'''
393 def format_for_c_proto(self
):
394 return join_ctype_name(self
.get_c_type(), self
.name
)
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)
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
)
424 class StringReturn(ReturnType
):
426 def get_c_type(self
):
427 return self
.props
.get('c_type', 'char *').replace('const-', 'const ')
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
)
446 class VoidReturn(ReturnType
):
448 def get_c_type(self
):
451 def write_decl(self
):
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"
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())
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(
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);"
506 self
.wrapper
.write_code("g_object_ref((GObject *) retval);")
508 self
.wrapper
.write_code(
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"
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
)
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
)
576 class GEnumReturn(IntReturn
):
577 def write_conversion(self
):
578 self
.wrapper
.write_code(
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(
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'),
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
):
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
):
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
)
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
))
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'],)),
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
):
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;"
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];",
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];",
877 self
.wrapper
.add_pyargv_item("py_user_data", optional
=True)
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
))
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__':