use tp_strdiff
[empathy-mirror.git] / tools / glib-client-gen.py
blob701fcafeb24cba428d8d2502add470fc96ddd615
1 #!/usr/bin/python
3 # glib-client-gen.py: "I Can't Believe It's Not dbus-binding-tool"
5 # Generate GLib client wrappers from the Telepathy specification.
6 # The master copy of this program is in the telepathy-glib repository -
7 # please make any changes there.
9 # Copyright (C) 2006-2008 Collabora Ltd. <http://www.collabora.co.uk/>
11 # This library is free software; you can redistribute it and/or
12 # modify it under the terms of the GNU Lesser General Public
13 # License as published by the Free Software Foundation; either
14 # version 2.1 of the License, or (at your option) any later version.
16 # This library is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 # Lesser General Public License for more details.
21 # You should have received a copy of the GNU Lesser General Public
22 # License along with this library; if not, write to the Free Software
23 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 import sys
26 import os.path
27 import xml.dom.minidom
28 from getopt import gnu_getopt
30 from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
31 camelcase_to_lower, get_docstring, xml_escape
34 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
36 class Generator(object):
38 def __init__(self, dom, prefix, basename, opts):
39 self.dom = dom
40 self.__header = []
41 self.__body = []
43 self.prefix_lc = prefix.lower()
44 self.prefix_uc = prefix.upper()
45 self.prefix_mc = prefix.replace('_', '')
46 self.basename = basename
47 self.group = opts.get('--group', None)
48 self.iface_quark_prefix = opts.get('--iface-quark-prefix', None)
49 self.tp_proxy_api = tuple(map(int,
50 opts.get('--tp-proxy-api', '0').split('.')))
51 self.proxy_cls = opts.get('--subclass', 'TpProxy') + ' *'
52 self.proxy_arg = opts.get('--subclass', 'void') + ' *'
53 self.proxy_assert = opts.get('--subclass-assert', 'TP_IS_PROXY')
54 self.proxy_doc = ('A #%s or subclass'
55 % opts.get('--subclass', 'TpProxy'))
56 if self.proxy_arg == 'void *':
57 self.proxy_arg = 'gpointer '
59 def h(self, s):
60 if isinstance(s, unicode):
61 s = s.encode('utf-8')
62 self.__header.append(s)
64 def b(self, s):
65 if isinstance(s, unicode):
66 s = s.encode('utf-8')
67 self.__body.append(s)
69 def get_iface_quark(self):
70 assert self.iface_dbus is not None
71 assert self.iface_uc is not None
72 if self.iface_quark_prefix is None:
73 return 'g_quark_from_static_string (\"%s\")' % self.iface_dbus
74 else:
75 return '%s_%s' % (self.iface_quark_prefix, self.iface_uc)
77 def do_signal(self, iface, signal):
78 iface_lc = iface.lower()
80 member = signal.getAttribute('name')
81 member_lc = camelcase_to_lower(member)
82 member_uc = member_lc.upper()
84 arg_count = 0
85 args = []
86 out_args = []
88 for arg in signal.getElementsByTagName('arg'):
89 name = arg.getAttribute('name')
90 type = arg.getAttribute('type')
91 tp_type = arg.getAttribute('tp:type')
93 if not name:
94 name = 'arg%u' % arg_count
95 arg_count += 1
96 else:
97 name = 'arg_%s' % name
99 info = type_to_gtype(type)
100 args.append((name, info, tp_type, arg))
102 callback_name = ('%s_%s_signal_callback_%s'
103 % (self.prefix_lc, iface_lc, member_lc))
104 collect_name = ('_%s_%s_collect_args_of_%s'
105 % (self.prefix_lc, iface_lc, member_lc))
106 invoke_name = ('_%s_%s_invoke_callback_for_%s'
107 % (self.prefix_lc, iface_lc, member_lc))
109 # Example:
111 # typedef void (*tp_cli_connection_signal_callback_new_channel)
112 # (TpConnection *proxy, const gchar *arg_object_path,
113 # const gchar *arg_channel_type, guint arg_handle_type,
114 # guint arg_handle, gboolean arg_suppress_handler,
115 # gpointer user_data, GObject *weak_object);
117 self.b('/**')
118 self.b(' * %s:' % callback_name)
119 self.b(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
120 % (self.prefix_lc, iface_lc, member_lc))
121 self.b(' * was called')
123 for arg in args:
124 name, info, tp_type, elt = arg
125 ctype, gtype, marshaller, pointer = info
127 self.b(' * @%s: %s' % (name,
128 xml_escape(get_docstring(elt) or '(Undocumented)')))
130 self.b(' * @user_data: User-supplied data')
131 self.b(' * @weak_object: User-supplied weakly referenced object')
132 self.b(' *')
133 self.b(' * Represents the signature of a callback for the signal %s.'
134 % member)
135 self.b(' */')
136 self.h('typedef void (*%s) (%sproxy,'
137 % (callback_name, self.proxy_cls))
139 for arg in args:
140 name, info, tp_type, elt = arg
141 ctype, gtype, marshaller, pointer = info
143 const = pointer and 'const ' or ''
145 self.h(' %s%s%s,' % (const, ctype, name))
147 self.h(' gpointer user_data, GObject *weak_object);')
149 if args:
150 self.b('static void')
151 self.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name)
153 for arg in args:
154 name, info, tp_type, elt = arg
155 ctype, gtype, marshaller, pointer = info
157 const = pointer and 'const ' or ''
159 self.b(' %s%s%s,' % (const, ctype, name))
161 self.b(' TpProxySignalConnection *sc)')
162 self.b('{')
163 self.b(' GValueArray *args = g_value_array_new (%d);' % len(args))
164 self.b(' GValue blank = { 0 };')
165 self.b(' guint i;')
166 self.b('')
167 self.b(' g_value_init (&blank, G_TYPE_INT);')
168 self.b('')
169 self.b(' for (i = 0; i < %d; i++)' % len(args))
170 self.b(' g_value_array_append (args, &blank);')
171 self.b('')
173 for i, arg in enumerate(args):
174 name, info, tp_type, elt = arg
175 ctype, gtype, marshaller, pointer = info
177 self.b(' g_value_unset (args->values + %d);' % i)
178 self.b(' g_value_init (args->values + %d, %s);' % (i, gtype))
180 if gtype == 'G_TYPE_STRING':
181 self.b(' g_value_set_string (args->values + %d, %s);'
182 % (i, name))
183 elif marshaller == 'BOXED':
184 self.b(' g_value_set_boxed (args->values + %d, %s);'
185 % (i, name))
186 elif gtype == 'G_TYPE_UCHAR':
187 self.b(' g_value_set_uchar (args->values + %d, %s);'
188 % (i, name))
189 elif gtype == 'G_TYPE_BOOLEAN':
190 self.b(' g_value_set_boolean (args->values + %d, %s);'
191 % (i, name))
192 elif gtype == 'G_TYPE_INT':
193 self.b(' g_value_set_int (args->values + %d, %s);'
194 % (i, name))
195 elif gtype == 'G_TYPE_UINT':
196 self.b(' g_value_set_uint (args->values + %d, %s);'
197 % (i, name))
198 elif gtype == 'G_TYPE_INT64':
199 self.b(' g_value_set_int (args->values + %d, %s);'
200 % (i, name))
201 elif gtype == 'G_TYPE_UINT64':
202 self.b(' g_value_set_uint64 (args->values + %d, %s);'
203 % (i, name))
204 elif gtype == 'G_TYPE_DOUBLE':
205 self.b(' g_value_set_double (args->values + %d, %s);'
206 % (i, name))
207 else:
208 assert False, ("Don't know how to put %s in a GValue"
209 % gtype)
210 self.b('')
212 self.b(' tp_proxy_signal_connection_v0_take_results (sc, args);')
213 self.b('}')
215 self.b('static void')
216 self.b('%s (TpProxy *tpproxy,' % invoke_name)
217 self.b(' GError *error G_GNUC_UNUSED,')
218 self.b(' GValueArray *args,')
219 self.b(' GCallback generic_callback,')
220 self.b(' gpointer user_data,')
221 self.b(' GObject *weak_object)')
222 self.b('{')
223 self.b(' %s callback =' % callback_name)
224 self.b(' (%s) generic_callback;' % callback_name)
225 self.b('')
226 self.b(' if (callback != NULL)')
227 self.b(' callback (g_object_ref (tpproxy),')
229 # FIXME: factor out into a function
230 for i, arg in enumerate(args):
231 name, info, tp_type, elt = arg
232 ctype, gtype, marshaller, pointer = info
234 if marshaller == 'BOXED':
235 self.b(' g_value_get_boxed (args->values + %d),' % i)
236 elif gtype == 'G_TYPE_STRING':
237 self.b(' g_value_get_string (args->values + %d),' % i)
238 elif gtype == 'G_TYPE_UCHAR':
239 self.b(' g_value_get_uchar (args->values + %d),' % i)
240 elif gtype == 'G_TYPE_BOOLEAN':
241 self.b(' g_value_get_boolean (args->values + %d),' % i)
242 elif gtype == 'G_TYPE_UINT':
243 self.b(' g_value_get_uint (args->values + %d),' % i)
244 elif gtype == 'G_TYPE_INT':
245 self.b(' g_value_get_int (args->values + %d),' % i)
246 elif gtype == 'G_TYPE_UINT64':
247 self.b(' g_value_get_uint64 (args->values + %d),' % i)
248 elif gtype == 'G_TYPE_INT64':
249 self.b(' g_value_get_int64 (args->values + %d),' % i)
250 elif gtype == 'G_TYPE_DOUBLE':
251 self.b(' g_value_get_double (args->values + %d),' % i)
252 else:
253 assert False, "Don't know how to get %s from a GValue" % gtype
255 self.b(' user_data,')
256 self.b(' weak_object);')
257 self.b('')
259 if len(args) > 0:
260 self.b(' g_value_array_free (args);')
261 else:
262 self.b(' if (args != NULL)')
263 self.b(' g_value_array_free (args);')
264 self.b('')
266 self.b(' g_object_unref (tpproxy);')
267 self.b('}')
269 # Example:
271 # TpProxySignalConnection *
272 # tp_cli_connection_connect_to_new_channel
273 # (TpConnection *proxy,
274 # tp_cli_connection_signal_callback_new_channel callback,
275 # gpointer user_data,
276 # GDestroyNotify destroy);
278 # destroy is invoked when the signal becomes disconnected. This
279 # is either because the signal has been disconnected explicitly
280 # by the user, because the TpProxy has become invalid and
281 # emitted the 'invalidated' signal, or because the weakly referenced
282 # object has gone away.
284 self.b('/**')
285 self.b(' * %s_%s_connect_to_%s:'
286 % (self.prefix_lc, iface_lc, member_lc))
287 self.b(' * @proxy: %s' % self.proxy_doc)
288 self.b(' * @callback: Callback to be called when the signal is')
289 self.b(' * received')
290 self.b(' * @user_data: User-supplied data for the callback')
291 self.b(' * @destroy: Destructor for the user-supplied data, which')
292 self.b(' * will be called when this signal is disconnected, or')
293 self.b(' * before this function returns %NULL')
294 self.b(' * @weak_object: A #GObject which will be weakly referenced; ')
295 self.b(' * if it is destroyed, this callback will automatically be')
296 self.b(' * disconnected')
297 self.b(' * @error: If not %NULL, used to raise an error if %NULL is')
298 self.b(' * returned')
299 self.b(' *')
300 self.b(' * Connect a handler to the signal %s.' % member)
301 self.b(' *')
302 self.b(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
303 self.b(' *')
304 self.b(' * Returns: a #TpProxySignalConnection containing all of the')
305 self.b(' * above, which can be used to disconnect the signal; or')
306 self.b(' * %NULL if the proxy does not have the desired interface')
307 self.b(' * or has become invalid.')
308 self.b(' */')
309 self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,'
310 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
311 self.h(' %s callback,' % callback_name)
312 self.h(' gpointer user_data,')
313 self.h(' GDestroyNotify destroy,')
314 self.h(' GObject *weak_object,')
315 self.h(' GError **error);')
317 self.b('TpProxySignalConnection *')
318 self.b('%s_%s_connect_to_%s (%sproxy,'
319 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
320 self.b(' %s callback,' % callback_name)
321 self.b(' gpointer user_data,')
322 self.b(' GDestroyNotify destroy,')
323 self.b(' GObject *weak_object,')
324 self.b(' GError **error)')
325 self.b('{')
326 self.b(' GType expected_types[%d] = {' % (len(args) + 1))
328 for arg in args:
329 name, info, tp_type, elt = arg
330 ctype, gtype, marshaller, pointer = info
332 self.b(' %s,' % gtype)
334 self.b(' G_TYPE_INVALID };')
335 self.b('')
336 self.b(' g_return_val_if_fail (%s (proxy), NULL);'
337 % self.proxy_assert)
338 self.b(' g_return_val_if_fail (callback != NULL, NULL);')
339 self.b('')
340 self.b(' return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,')
341 self.b(' %s, \"%s\",' % (self.get_iface_quark(), member))
342 self.b(' expected_types,')
344 if args:
345 self.b(' G_CALLBACK (%s),' % collect_name)
346 else:
347 self.b(' NULL, /* no args => no collector function */')
349 self.b(' %s,' % invoke_name)
350 self.b(' G_CALLBACK (callback), user_data, destroy,')
351 self.b(' weak_object, error);')
352 self.b('}')
353 self.b('')
355 self.h('')
357 def do_method(self, iface, method):
358 iface_lc = iface.lower()
360 member = method.getAttribute('name')
361 member_lc = camelcase_to_lower(member)
362 member_uc = member_lc.upper()
364 in_count = 0
365 ret_count = 0
366 in_args = []
367 out_args = []
369 for arg in method.getElementsByTagName('arg'):
370 name = arg.getAttribute('name')
371 direction = arg.getAttribute('direction')
372 type = arg.getAttribute('type')
373 tp_type = arg.getAttribute('tp:type')
375 if direction != 'out':
376 if not name:
377 name = 'in%u' % in_count
378 in_count += 1
379 else:
380 name = 'in_%s' % name
381 else:
382 if not name:
383 name = 'out%u' % ret_count
384 ret_count += 1
385 else:
386 name = 'out_%s' % name
388 info = type_to_gtype(type)
389 if direction != 'out':
390 in_args.append((name, info, tp_type, arg))
391 else:
392 out_args.append((name, info, tp_type, arg))
394 # Async reply callback type
396 # Example:
397 # void (*tp_cli_properties_interface_callback_for_get_properties)
398 # (TpProxy *proxy,
399 # const GPtrArray *out0,
400 # const GError *error,
401 # gpointer user_data,
402 # GObject *weak_object);
404 self.b('/**')
405 self.b(' * %s_%s_callback_for_%s:'
406 % (self.prefix_lc, iface_lc, member_lc))
407 self.b(' * @proxy: the proxy on which the call was made')
409 for arg in out_args:
410 name, info, tp_type, elt = arg
411 ctype, gtype, marshaller, pointer = info
413 self.b(' * @%s: Used to return an \'out\' argument if @error is '
414 '%%NULL: %s'
415 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
417 self.b(' * @error: %NULL on success, or an error on failure')
418 self.b(' * @user_data: user-supplied data')
419 self.b(' * @weak_object: user-supplied object')
420 self.b(' *')
421 self.b(' * Signature of the callback called when a %s method call'
422 % member)
423 self.b(' * succeeds or fails.')
424 self.b(' */')
426 callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
427 member_lc)
429 self.h('typedef void (*%s) (%sproxy,'
430 % (callback_name, self.proxy_cls))
432 for arg in out_args:
433 name, info, tp_type, elt = arg
434 ctype, gtype, marshaller, pointer = info
435 const = pointer and 'const ' or ''
437 self.h(' %s%s%s,' % (const, ctype, name))
439 self.h(' const GError *error, gpointer user_data,')
440 self.h(' GObject *weak_object);')
441 self.h('')
443 # Async callback implementation
445 invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
446 iface_lc,
447 member_lc)
449 collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
450 iface_lc,
451 member_lc)
453 # The callback called by dbus-glib; this ends the call and collects
454 # the results into a GValueArray.
455 self.b('static void')
456 self.b('%s (DBusGProxy *proxy,' % collect_callback)
457 self.b(' DBusGProxyCall *call,')
458 self.b(' gpointer user_data)')
459 self.b('{')
460 self.b(' GError *error = NULL;')
462 if len(out_args) > 0:
463 self.b(' GValueArray *args;')
464 self.b(' GValue blank = { 0 };')
465 self.b(' guint i;')
467 for arg in out_args:
468 name, info, tp_type, elt = arg
469 ctype, gtype, marshaller, pointer = info
471 # "We handle variants specially; the caller is expected to
472 # have already allocated storage for them". Thanks,
473 # dbus-glib...
474 if gtype == 'G_TYPE_VALUE':
475 self.b(' GValue *%s = g_new0 (GValue, 1);' % name)
476 else:
477 self.b(' %s%s;' % (ctype, name))
479 self.b('')
480 self.b(' dbus_g_proxy_end_call (proxy, call, &error,')
482 for arg in out_args:
483 name, info, tp_type, elt = arg
484 ctype, gtype, marshaller, pointer = info
486 if gtype == 'G_TYPE_VALUE':
487 self.b(' %s, %s,' % (gtype, name))
488 else:
489 self.b(' %s, &%s,' % (gtype, name))
491 self.b(' G_TYPE_INVALID);')
493 if len(out_args) == 0:
494 self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,'
495 'NULL);')
496 else:
497 self.b('')
498 self.b(' if (error != NULL)')
499 self.b(' {')
500 self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,')
501 self.b(' NULL);')
503 for arg in out_args:
504 name, info, tp_type, elt = arg
505 ctype, gtype, marshaller, pointer = info
506 if gtype == 'G_TYPE_VALUE':
507 self.b(' g_free (%s);' % name)
509 self.b(' return;')
510 self.b(' }')
511 self.b('')
512 self.b(' args = g_value_array_new (%d);' % len(out_args))
513 self.b(' g_value_init (&blank, G_TYPE_INT);')
514 self.b('')
515 self.b(' for (i = 0; i < %d; i++)' % len(out_args))
516 self.b(' g_value_array_append (args, &blank);')
518 for i, arg in enumerate(out_args):
519 name, info, tp_type, elt = arg
520 ctype, gtype, marshaller, pointer = info
522 self.b('')
523 self.b(' g_value_unset (args->values + %d);' % i)
524 self.b(' g_value_init (args->values + %d, %s);' % (i, gtype))
526 if gtype == 'G_TYPE_STRING':
527 self.b(' g_value_take_string (args->values + %d, %s);'
528 % (i, name))
529 elif marshaller == 'BOXED':
530 self.b(' g_value_take_boxed (args->values + %d, %s);'
531 % (i, name))
532 elif gtype == 'G_TYPE_UCHAR':
533 self.b(' g_value_set_uchar (args->values + %d, %s);'
534 % (i, name))
535 elif gtype == 'G_TYPE_BOOLEAN':
536 self.b(' g_value_set_boolean (args->values + %d, %s);'
537 % (i, name))
538 elif gtype == 'G_TYPE_INT':
539 self.b(' g_value_set_int (args->values + %d, %s);'
540 % (i, name))
541 elif gtype == 'G_TYPE_UINT':
542 self.b(' g_value_set_uint (args->values + %d, %s);'
543 % (i, name))
544 elif gtype == 'G_TYPE_INT64':
545 self.b(' g_value_set_int (args->values + %d, %s);'
546 % (i, name))
547 elif gtype == 'G_TYPE_UINT64':
548 self.b(' g_value_set_uint (args->values + %d, %s);'
549 % (i, name))
550 elif gtype == 'G_TYPE_DOUBLE':
551 self.b(' g_value_set_double (args->values + %d, %s);'
552 % (i, name))
553 else:
554 assert False, ("Don't know how to put %s in a GValue"
555 % gtype)
557 self.b(' tp_proxy_pending_call_v0_take_results (user_data, '
558 'NULL, args);')
560 self.b('}')
562 self.b('static void')
563 self.b('%s (TpProxy *self,' % invoke_callback)
564 self.b(' GError *error,')
565 self.b(' GValueArray *args,')
566 self.b(' GCallback generic_callback,')
567 self.b(' gpointer user_data,')
568 self.b(' GObject *weak_object)')
569 self.b('{')
570 self.b(' %s callback = (%s) generic_callback;'
571 % (callback_name, callback_name))
572 self.b('')
573 self.b(' if (error != NULL)')
574 self.b(' {')
575 self.b(' callback ((%s) self,' % self.proxy_cls)
577 for arg in out_args:
578 name, info, tp_type, elt = arg
579 ctype, gtype, marshaller, pointer = info
581 if marshaller == 'BOXED' or pointer:
582 self.b(' NULL,')
583 elif gtype == 'G_TYPE_DOUBLE':
584 self.b(' 0.0,')
585 else:
586 self.b(' 0,')
588 self.b(' error, user_data, weak_object);')
589 self.b(' g_error_free (error);')
590 self.b(' return;')
591 self.b(' }')
593 self.b(' callback ((%s) self,' % self.proxy_cls)
595 # FIXME: factor out into a function
596 for i, arg in enumerate(out_args):
597 name, info, tp_type, elt = arg
598 ctype, gtype, marshaller, pointer = info
600 if marshaller == 'BOXED':
601 self.b(' g_value_get_boxed (args->values + %d),' % i)
602 elif gtype == 'G_TYPE_STRING':
603 self.b(' g_value_get_string (args->values + %d),' % i)
604 elif gtype == 'G_TYPE_UCHAR':
605 self.b(' g_value_get_uchar (args->values + %d),' % i)
606 elif gtype == 'G_TYPE_BOOLEAN':
607 self.b(' g_value_get_boolean (args->values + %d),' % i)
608 elif gtype == 'G_TYPE_UINT':
609 self.b(' g_value_get_uint (args->values + %d),' % i)
610 elif gtype == 'G_TYPE_INT':
611 self.b(' g_value_get_int (args->values + %d),' % i)
612 elif gtype == 'G_TYPE_UINT64':
613 self.b(' g_value_get_uint64 (args->values + %d),' % i)
614 elif gtype == 'G_TYPE_INT64':
615 self.b(' g_value_get_int64 (args->values + %d),' % i)
616 elif gtype == 'G_TYPE_DOUBLE':
617 self.b(' g_value_get_double (args->values + %d),' % i)
618 else:
619 assert False, "Don't know how to get %s from a GValue" % gtype
621 self.b(' error, user_data, weak_object);')
622 self.b('')
624 if len(out_args) > 0:
625 self.b(' g_value_array_free (args);')
626 else:
627 self.b(' if (args != NULL)')
628 self.b(' g_value_array_free (args);')
630 self.b('}')
631 self.b('')
633 # Async stub
635 # Example:
636 # TpProxyPendingCall *
637 # tp_cli_properties_interface_call_get_properties
638 # (gpointer proxy,
639 # gint timeout_ms,
640 # const GArray *in_properties,
641 # tp_cli_properties_interface_callback_for_get_properties callback,
642 # gpointer user_data,
643 # GDestroyNotify *destructor);
645 self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
646 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
647 self.h(' gint timeout_ms,')
649 self.b('/**')
650 self.b(' * %s_%s_call_%s:'
651 % (self.prefix_lc, iface_lc, member_lc))
652 self.b(' * @proxy: the #TpProxy')
653 self.b(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
654 self.b(' * default')
656 for arg in in_args:
657 name, info, tp_type, elt = arg
658 ctype, gtype, marshaller, pointer = info
660 self.b(' * @%s: Used to pass an \'in\' argument: %s'
661 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
663 self.b(' * @callback: called when the method call succeeds or fails;')
664 self.b(' * may be %NULL to make a "fire and forget" call with no ')
665 self.b(' * reply tracking')
666 self.b(' * @user_data: user-supplied data passed to the callback;')
667 self.b(' * must be %NULL if @callback is %NULL')
668 self.b(' * @destroy: called with the user_data as argument, after the')
669 self.b(' * call has succeeded, failed or been cancelled;')
670 self.b(' * must be %NULL if @callback is %NULL')
671 self.b(' * @weak_object: If not %NULL, a #GObject which will be ')
672 self.b(' * weakly referenced; if it is destroyed, this call ')
673 self.b(' * will automatically be cancelled. Must be %NULL if ')
674 self.b(' * @callback is %NULL')
675 self.b(' *')
676 self.b(' * Start a %s method call.' % member)
677 self.b(' *')
678 self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
679 self.b(' *')
680 self.b(' * Returns: a #TpProxyPendingCall representing the call in')
681 self.b(' * progress. It is borrowed from the object, and will become')
682 self.b(' * invalid when the callback is called, the call is')
683 self.b(' * cancelled or the #TpProxy becomes invalid.')
684 self.b(' */')
685 self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
686 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
687 self.b(' gint timeout_ms,')
689 for arg in in_args:
690 name, info, tp_type, elt = arg
691 ctype, gtype, marshaller, pointer = info
693 const = pointer and 'const ' or ''
695 self.h(' %s%s%s,' % (const, ctype, name))
696 self.b(' %s%s%s,' % (const, ctype, name))
698 self.h(' %s callback,' % callback_name)
699 self.h(' gpointer user_data,')
700 self.h(' GDestroyNotify destroy,')
701 self.h(' GObject *weak_object);')
702 self.h('')
704 self.b(' %s callback,' % callback_name)
705 self.b(' gpointer user_data,')
706 self.b(' GDestroyNotify destroy,')
707 self.b(' GObject *weak_object)')
708 self.b('{')
709 self.b(' GError *error = NULL;')
710 self.b(' GQuark interface = %s;' % self.get_iface_quark())
711 self.b(' DBusGProxy *iface;')
712 self.b('')
713 self.b(' g_return_val_if_fail (%s (proxy), NULL);'
714 % self.proxy_assert)
715 self.b(' g_return_val_if_fail (callback != NULL || '
716 'user_data == NULL, NULL);')
717 self.b(' g_return_val_if_fail (callback != NULL || '
718 'destroy == NULL, NULL);')
719 self.b(' g_return_val_if_fail (callback != NULL || '
720 'weak_object == NULL, NULL);')
721 self.b('')
722 self.b(' iface = tp_proxy_borrow_interface_by_id (')
723 self.b(' (TpProxy *) proxy,')
724 self.b(' interface, &error);')
725 self.b('')
726 self.b(' if (iface == NULL)')
727 self.b(' {')
728 self.b(' if (callback != NULL)')
729 self.b(' callback (proxy,')
731 for arg in out_args:
732 name, info, tp_type, elt = arg
733 ctype, gtype, marshaller, pointer = info
735 if pointer:
736 self.b(' NULL,')
737 else:
738 self.b(' 0,')
740 self.b(' error, user_data, weak_object);')
741 self.b('')
742 self.b(' if (destroy != NULL)')
743 self.b(' destroy (user_data);')
744 self.b('')
745 self.b(' g_error_free (error);')
746 self.b(' return NULL;')
747 self.b(' }')
748 self.b('')
749 self.b(' if (callback == NULL)')
750 self.b(' {')
751 self.b(' dbus_g_proxy_call_no_reply (iface, "%s",' % member)
753 for arg in in_args:
754 name, info, tp_type, elt = arg
755 ctype, gtype, marshaller, pointer = info
757 const = pointer and 'const ' or ''
759 self.b(' %s, %s,' % (gtype, name))
761 self.b(' G_TYPE_INVALID);')
762 self.b(' return NULL;')
763 self.b(' }')
764 self.b(' else')
765 self.b(' {')
766 self.b(' TpProxyPendingCall *data;')
767 self.b('')
768 self.b(' data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
769 self.b(' interface, "%s", iface,' % member)
770 self.b(' %s,' % invoke_callback)
771 self.b(' G_CALLBACK (callback), user_data, destroy,')
772 self.b(' weak_object, FALSE);')
773 self.b(' tp_proxy_pending_call_v0_take_pending_call (data,')
774 self.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
775 self.b(' "%s",' % member)
776 self.b(' %s,' % collect_callback)
777 self.b(' data,')
778 self.b(' tp_proxy_pending_call_v0_completed,')
779 self.b(' timeout_ms,')
781 for arg in in_args:
782 name, info, tp_type, elt = arg
783 ctype, gtype, marshaller, pointer = info
785 const = pointer and 'const ' or ''
787 self.b(' %s, %s,' % (gtype, name))
789 self.b(' G_TYPE_INVALID));')
790 self.b('')
791 self.b(' return data;')
792 self.b(' }')
793 self.b('}')
794 self.b('')
796 # Reentrant blocking calls
797 # Example:
798 # gboolean tp_cli_properties_interface_run_get_properties
799 # (gpointer proxy,
800 # gint timeout_ms,
801 # const GArray *in_properties,
802 # GPtrArray **out0,
803 # GError **error,
804 # GMainLoop **loop);
806 self.b('typedef struct {')
807 self.b(' GMainLoop *loop;')
808 self.b(' GError **error;')
810 for arg in out_args:
811 name, info, tp_type, elt = arg
812 ctype, gtype, marshaller, pointer = info
814 self.b(' %s*%s;' % (ctype, name))
816 self.b(' unsigned success:1;')
817 self.b(' unsigned completed:1;')
818 self.b('} _%s_%s_run_state_%s;'
819 % (self.prefix_lc, iface_lc, member_lc))
821 reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
822 iface_lc,
823 member_lc)
825 self.b('static void')
826 self.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke)
827 self.b(' GError *error,')
828 self.b(' GValueArray *args,')
829 self.b(' GCallback unused G_GNUC_UNUSED,')
830 self.b(' gpointer user_data G_GNUC_UNUSED,')
831 self.b(' GObject *unused2 G_GNUC_UNUSED)')
832 self.b('{')
833 self.b(' _%s_%s_run_state_%s *state = user_data;'
834 % (self.prefix_lc, iface_lc, member_lc))
835 self.b('')
836 self.b(' state->success = (error == NULL);')
837 self.b(' state->completed = TRUE;')
838 self.b(' g_main_loop_quit (state->loop);')
839 self.b('')
840 self.b(' if (error != NULL)')
841 self.b(' {')
842 self.b(' if (state->error != NULL)')
843 self.b(' *state->error = error;')
844 self.b(' else')
845 self.b(' g_error_free (error);')
846 self.b('')
847 self.b(' return;')
848 self.b(' }')
849 self.b('')
851 for i, arg in enumerate(out_args):
852 name, info, tp_type, elt = arg
853 ctype, gtype, marshaller, pointer = info
855 self.b(' if (state->%s != NULL)' % name)
856 if marshaller == 'BOXED':
857 self.b(' *state->%s = g_value_dup_boxed ('
858 'args->values + %d);' % (name, i))
859 elif marshaller == 'STRING':
860 self.b(' *state->%s = g_value_dup_string '
861 '(args->values + %d);' % (name, i))
862 elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
863 'INT64', 'UINT64', 'DOUBLE'):
864 self.b(' *state->%s = g_value_get_%s (args->values + %d);'
865 % (name, marshaller.lower(), i))
866 else:
867 assert False, "Don't know how to copy %s" % gtype
869 self.b('')
871 if len(out_args) > 0:
872 self.b(' g_value_array_free (args);')
873 else:
874 self.b(' if (args != NULL)')
875 self.b(' g_value_array_free (args);')
877 self.b('}')
878 self.b('')
880 self.h('gboolean %s_%s_run_%s (%sproxy,'
881 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
882 self.h(' gint timeout_ms,')
884 self.b('/**')
885 self.b(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc))
886 self.b(' * @proxy: %s' % self.proxy_doc)
887 self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default')
889 for arg in in_args:
890 name, info, tp_type, elt = arg
891 ctype, gtype, marshaller, pointer = info
893 self.b(' * @%s: Used to pass an \'in\' argument: %s'
894 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
896 for arg in out_args:
897 name, info, tp_type, elt = arg
898 ctype, gtype, marshaller, pointer = info
900 self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is '
901 'returned: %s'
902 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
904 self.b(' * @error: If not %NULL, used to return errors if %FALSE ')
905 self.b(' * is returned')
906 self.b(' * @loop: If not %NULL, set before re-entering ')
907 self.b(' * the main loop, to point to a #GMainLoop ')
908 self.b(' * which can be used to cancel this call with ')
909 self.b(' * g_main_loop_quit(), causing a return of ')
910 self.b(' * %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
911 self.b(' *')
912 self.b(' * Call the method %s and run the main loop' % member)
913 self.b(' * until it returns. Before calling this method, you must')
914 self.b(' * add a reference to any borrowed objects you need to keep,')
915 self.b(' * and generally ensure that everything is in a consistent')
916 self.b(' * state.')
917 self.b(' *')
918 self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
919 self.b(' *')
920 self.b(' * Returns: TRUE on success, FALSE and sets @error on error')
921 self.b(' */')
922 self.b('gboolean\n%s_%s_run_%s (%sproxy,'
923 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
924 self.b(' gint timeout_ms,')
926 for arg in in_args:
927 name, info, tp_type, elt = arg
928 ctype, gtype, marshaller, pointer = info
930 const = pointer and 'const ' or ''
932 self.h(' %s%s%s,' % (const, ctype, name))
933 self.b(' %s%s%s,' % (const, ctype, name))
935 for arg in out_args:
936 name, info, tp_type, elt = arg
937 ctype, gtype, marshaller, pointer = info
939 self.h(' %s*%s,' % (ctype, name))
940 self.b(' %s*%s,' % (ctype, name))
942 self.h(' GError **error,')
943 self.h(' GMainLoop **loop);')
944 self.h('')
946 self.b(' GError **error,')
947 self.b(' GMainLoop **loop)')
948 self.b('{')
949 self.b(' DBusGProxy *iface;')
950 self.b(' GQuark interface = %s;' % self.get_iface_quark())
951 self.b(' TpProxyPendingCall *pc;')
952 self.b(' _%s_%s_run_state_%s state = {'
953 % (self.prefix_lc, iface_lc, member_lc))
954 self.b(' NULL /* loop */, error,')
956 for arg in out_args:
957 name, info, tp_type, elt = arg
959 self.b(' %s,' % name)
961 self.b(' FALSE /* completed */, FALSE /* success */ };')
962 self.b('')
963 self.b(' g_return_val_if_fail (%s (proxy), FALSE);'
964 % self.proxy_assert)
965 self.b('')
966 self.b(' iface = tp_proxy_borrow_interface_by_id')
967 self.b(' ((TpProxy *) proxy, interface, error);')
968 self.b('')
969 self.b(' if (iface == NULL)')
970 self.b(' return FALSE;')
971 self.b('')
972 self.b(' state.loop = g_main_loop_new (NULL, FALSE);')
973 self.b('')
974 self.b(' pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
975 self.b(' interface, "%s", iface,' % member)
976 self.b(' %s,' % reentrant_invoke)
977 self.b(' NULL, &state, NULL, NULL, TRUE);')
978 self.b('')
979 self.b(' if (loop != NULL)')
980 self.b(' *loop = state.loop;')
981 self.b('')
982 self.b(' tp_proxy_pending_call_v0_take_pending_call (pc,')
983 self.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
984 self.b(' "%s",' % member)
985 self.b(' %s,' % collect_callback)
986 self.b(' pc,')
987 self.b(' tp_proxy_pending_call_v0_completed,')
988 self.b(' timeout_ms,')
990 for arg in in_args:
991 name, info, tp_type, elt = arg
992 ctype, gtype, marshaller, pointer = info
994 const = pointer and 'const ' or ''
996 self.b(' %s, %s,' % (gtype, name))
998 self.b(' G_TYPE_INVALID));')
999 self.b('')
1000 self.b(' if (!state.completed)')
1001 self.b(' g_main_loop_run (state.loop);')
1002 self.b('')
1003 self.b(' if (!state.completed)')
1004 self.b(' tp_proxy_pending_call_cancel (pc);')
1005 self.b('')
1006 self.b(' if (loop != NULL)')
1007 self.b(' *loop = NULL;')
1008 self.b('')
1009 self.b(' g_main_loop_unref (state.loop);')
1010 self.b('')
1011 self.b(' return state.success;')
1012 self.b('}')
1013 self.b('')
1015 # leave a gap for the end of the method
1016 self.b('')
1017 self.h('')
1019 def do_signal_add(self, signal):
1020 marshaller_items = []
1021 gtypes = []
1023 for i in signal.getElementsByTagName('arg'):
1024 name = i.getAttribute('name')
1025 type = i.getAttribute('type')
1026 info = type_to_gtype(type)
1027 # type, GType, STRING, is a pointer
1028 gtypes.append(info[1])
1030 self.b(' dbus_g_proxy_add_signal (proxy, "%s",'
1031 % signal.getAttribute('name'))
1032 for gtype in gtypes:
1033 self.b(' %s,' % gtype)
1034 self.b(' G_TYPE_INVALID);')
1036 def do_interface(self, node):
1037 ifaces = node.getElementsByTagName('interface')
1038 assert len(ifaces) == 1
1039 iface = ifaces[0]
1040 name = node.getAttribute('name').replace('/', '')
1042 self.iface = name
1043 self.iface_lc = name.lower()
1044 self.iface_uc = name.upper()
1045 self.iface_mc = name.replace('_', '')
1046 self.iface_dbus = iface.getAttribute('name')
1048 signals = node.getElementsByTagName('signal')
1049 methods = node.getElementsByTagName('method')
1051 if signals:
1052 self.b('static inline void')
1053 self.b('%s_add_signals_for_%s (DBusGProxy *proxy)'
1054 % (self.prefix_lc, name.lower()))
1055 self.b('{')
1057 if self.tp_proxy_api >= (0, 7, 6):
1058 self.b(' if (!tp_proxy_dbus_g_proxy_claim_for_signal_adding '
1059 '(proxy))')
1060 self.b(' return;')
1062 for signal in signals:
1063 self.do_signal_add(signal)
1065 self.b('}')
1066 self.b('')
1067 self.b('')
1069 for signal in signals:
1070 self.do_signal(name, signal)
1072 for method in methods:
1073 self.do_method(name, method)
1075 self.iface_dbus = None
1077 def __call__(self):
1079 self.h('G_BEGIN_DECLS')
1080 self.h('')
1082 self.b('/* We don\'t want gtkdoc scanning this file, it\'ll get')
1083 self.b(' * confused by seeing function definitions, so mark it as: */')
1084 self.b('/*<private_header>*/')
1085 self.b('')
1087 nodes = self.dom.getElementsByTagName('node')
1088 nodes.sort(cmp_by_name)
1090 for node in nodes:
1091 self.do_interface(node)
1093 if self.group is not None:
1095 self.b('/*')
1096 self.b(' * %s_%s_add_signals:' % (self.prefix_lc, self.group))
1097 self.b(' * @self: the #TpProxy')
1098 self.b(' * @quark: a quark whose string value is the interface')
1099 self.b(' * name whose signals should be added')
1100 self.b(' * @proxy: the D-Bus proxy to which to add the signals')
1101 self.b(' * @unused: not used for anything')
1102 self.b(' *')
1103 self.b(' * Tell dbus-glib that @proxy has the signatures of all')
1104 self.b(' * signals on the given interface, if it\'s one we')
1105 self.b(' * support.')
1106 self.b(' *')
1107 self.b(' * This function should be used as a signal handler for')
1108 self.b(' * #TpProxy::interface-added.')
1109 self.b(' */')
1110 self.b('static void')
1111 self.b('%s_%s_add_signals (TpProxy *self G_GNUC_UNUSED,'
1112 % (self.prefix_lc, self.group))
1113 self.b(' guint quark,')
1114 self.b(' DBusGProxy *proxy,')
1115 self.b(' gpointer unused G_GNUC_UNUSED)')
1117 self.b('{')
1119 for node in nodes:
1120 iface = node.getElementsByTagName('interface')[0]
1121 self.iface_dbus = iface.getAttribute('name')
1122 signals = node.getElementsByTagName('signal')
1123 if not signals:
1124 continue
1125 name = node.getAttribute('name').replace('/', '').lower()
1126 self.iface_uc = name.upper()
1127 self.b(' if (quark == %s)' % self.get_iface_quark())
1128 self.b(' %s_add_signals_for_%s (proxy);'
1129 % (self.prefix_lc, name))
1131 self.b('}')
1132 self.b('')
1134 self.h('G_END_DECLS')
1135 self.h('')
1137 open(self.basename + '.h', 'w').write('\n'.join(self.__header))
1138 open(self.basename + '-body.h', 'w').write('\n'.join(self.__body))
1141 def types_to_gtypes(types):
1142 return [type_to_gtype(t)[1] for t in types]
1145 if __name__ == '__main__':
1146 options, argv = gnu_getopt(sys.argv[1:], '',
1147 ['group=', 'subclass=', 'subclass-assert=',
1148 'iface-quark-prefix=', 'tp-proxy-api='])
1150 opts = {}
1152 for option, value in options:
1153 opts[option] = value
1155 dom = xml.dom.minidom.parse(argv[0])
1157 Generator(dom, argv[1], argv[2], opts)()