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
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):
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 '
60 self.__header.append(s)
65 def get_iface_quark(self):
66 assert self.iface_dbus is not None
67 assert self.iface_uc is not None
68 if self.iface_quark_prefix is None:
69 return 'g_quark_from_static_string (\"%s\")' % self.iface_dbus
71 return '%s_%s' % (self.iface_quark_prefix, self.iface_uc)
73 def do_signal(self, iface, signal):
74 iface_lc = iface.lower()
76 member = signal.getAttribute('name')
77 member_lc = camelcase_to_lower(member)
78 member_uc = member_lc.upper()
84 for arg in signal.getElementsByTagName('arg'):
85 name = arg.getAttribute('name')
86 type = arg.getAttribute('type')
87 tp_type = arg.getAttribute('tp:type')
90 name = 'arg%u' % arg_count
93 name = 'arg_%s' % name
95 info = type_to_gtype(type)
96 args.append((name, info, tp_type, arg))
98 callback_name = ('%s_%s_signal_callback_%s'
99 % (self.prefix_lc, iface_lc, member_lc))
100 collect_name = ('_%s_%s_collect_args_of_%s'
101 % (self.prefix_lc, iface_lc, member_lc))
102 invoke_name = ('_%s_%s_invoke_callback_for_%s'
103 % (self.prefix_lc, iface_lc, member_lc))
107 # typedef void (*tp_cli_connection_signal_callback_new_channel)
108 # (TpConnection *proxy, const gchar *arg_object_path,
109 # const gchar *arg_channel_type, guint arg_handle_type,
110 # guint arg_handle, gboolean arg_suppress_handler,
111 # gpointer user_data, GObject *weak_object);
114 self.b(' * %s:' % callback_name)
115 self.b(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
116 % (self.prefix_lc, iface_lc, member_lc))
117 self.b(' * was called')
120 name, info, tp_type, elt = arg
121 ctype, gtype, marshaller, pointer = info
123 self.b(' * @%s: %s' % (name,
124 xml_escape(get_docstring(elt) or '(Undocumented)')))
126 self.b(' * @user_data: User-supplied data')
127 self.b(' * @weak_object: User-supplied weakly referenced object')
129 self.b(' * Represents the signature of a callback for the signal %s.'
132 self.h('typedef void (*%s) (%sproxy,'
133 % (callback_name, self.proxy_cls))
136 name, info, tp_type, elt = arg
137 ctype, gtype, marshaller, pointer = info
139 const = pointer and 'const ' or ''
141 self.h(' %s%s%s,' % (const, ctype, name))
143 self.h(' gpointer user_data, GObject *weak_object);')
146 self.b('static void')
147 self.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name)
150 name, info, tp_type, elt = arg
151 ctype, gtype, marshaller, pointer = info
153 const = pointer and 'const ' or ''
155 self.b(' %s%s%s,' % (const, ctype, name))
157 self.b(' TpProxySignalConnection *sc)')
159 self.b(' GValueArray *args = g_value_array_new (%d);' % len(args))
160 self.b(' GValue blank = { 0 };')
163 self.b(' g_value_init (&blank, G_TYPE_INT);')
165 self.b(' for (i = 0; i < %d; i++)' % len(args))
166 self.b(' g_value_array_append (args, &blank);')
169 for i, arg in enumerate(args):
170 name, info, tp_type, elt = arg
171 ctype, gtype, marshaller, pointer = info
173 self.b(' g_value_unset (args->values + %d);' % i)
174 self.b(' g_value_init (args->values + %d, %s);' % (i, gtype))
176 if gtype == 'G_TYPE_STRING':
177 self.b(' g_value_set_string (args->values + %d, %s);'
179 elif marshaller == 'BOXED':
180 self.b(' g_value_set_boxed (args->values + %d, %s);'
182 elif gtype == 'G_TYPE_UCHAR':
183 self.b(' g_value_set_uchar (args->values + %d, %s);'
185 elif gtype == 'G_TYPE_BOOLEAN':
186 self.b(' g_value_set_boolean (args->values + %d, %s);'
188 elif gtype == 'G_TYPE_INT':
189 self.b(' g_value_set_int (args->values + %d, %s);'
191 elif gtype == 'G_TYPE_UINT':
192 self.b(' g_value_set_uint (args->values + %d, %s);'
194 elif gtype == 'G_TYPE_INT64':
195 self.b(' g_value_set_int (args->values + %d, %s);'
197 elif gtype == 'G_TYPE_UINT64':
198 self.b(' g_value_set_uint (args->values + %d, %s);'
200 elif gtype == 'G_TYPE_DOUBLE':
201 self.b(' g_value_set_double (args->values + %d, %s);'
204 assert False, ("Don't know how to put %s in a GValue"
208 self.b(' tp_proxy_signal_connection_v0_take_results (sc, args);')
211 self.b('static void')
212 self.b('%s (TpProxy *tpproxy,' % invoke_name)
213 self.b(' GError *error G_GNUC_UNUSED,')
214 self.b(' GValueArray *args,')
215 self.b(' GCallback generic_callback,')
216 self.b(' gpointer user_data,')
217 self.b(' GObject *weak_object)')
219 self.b(' %s callback =' % callback_name)
220 self.b(' (%s) generic_callback;' % callback_name)
222 self.b(' if (callback != NULL)')
223 self.b(' callback (g_object_ref (tpproxy),')
225 # FIXME: factor out into a function
226 for i, arg in enumerate(args):
227 name, info, tp_type, elt = arg
228 ctype, gtype, marshaller, pointer = info
230 if marshaller == 'BOXED':
231 self.b(' g_value_get_boxed (args->values + %d),' % i)
232 elif gtype == 'G_TYPE_STRING':
233 self.b(' g_value_get_string (args->values + %d),' % i)
234 elif gtype == 'G_TYPE_UCHAR':
235 self.b(' g_value_get_uchar (args->values + %d),' % i)
236 elif gtype == 'G_TYPE_BOOLEAN':
237 self.b(' g_value_get_boolean (args->values + %d),' % i)
238 elif gtype == 'G_TYPE_UINT':
239 self.b(' g_value_get_uint (args->values + %d),' % i)
240 elif gtype == 'G_TYPE_INT':
241 self.b(' g_value_get_int (args->values + %d),' % i)
242 elif gtype == 'G_TYPE_UINT64':
243 self.b(' g_value_get_uint64 (args->values + %d),' % i)
244 elif gtype == 'G_TYPE_INT64':
245 self.b(' g_value_get_int64 (args->values + %d),' % i)
246 elif gtype == 'G_TYPE_DOUBLE':
247 self.b(' g_value_get_double (args->values + %d),' % i)
249 assert False, "Don't know how to get %s from a GValue" % gtype
251 self.b(' user_data,')
252 self.b(' weak_object);')
256 self.b(' g_value_array_free (args);')
258 self.b(' if (args != NULL)')
259 self.b(' g_value_array_free (args);')
262 self.b(' g_object_unref (tpproxy);')
267 # TpProxySignalConnection *
268 # tp_cli_connection_connect_to_new_channel
269 # (TpConnection *proxy,
270 # tp_cli_connection_signal_callback_new_channel callback,
271 # gpointer user_data,
272 # GDestroyNotify destroy);
274 # destroy is invoked when the signal becomes disconnected. This
275 # is either because the signal has been disconnected explicitly
276 # by the user, because the TpProxy has become invalid and
277 # emitted the 'invalidated' signal, or because the weakly referenced
278 # object has gone away.
281 self.b(' * %s_%s_connect_to_%s:'
282 % (self.prefix_lc, iface_lc, member_lc))
283 self.b(' * @proxy: %s' % self.proxy_doc)
284 self.b(' * @callback: Callback to be called when the signal is')
285 self.b(' * received')
286 self.b(' * @user_data: User-supplied data for the callback')
287 self.b(' * @destroy: Destructor for the user-supplied data, which')
288 self.b(' * will be called when this signal is disconnected, or')
289 self.b(' * before this function returns %NULL')
290 self.b(' * @weak_object: A #GObject which will be weakly referenced; ')
291 self.b(' * if it is destroyed, this callback will automatically be')
292 self.b(' * disconnected')
293 self.b(' * @error: If not %NULL, used to raise an error if %NULL is')
294 self.b(' * returned')
296 self.b(' * Connect a handler to the signal %s.' % member)
298 self.b(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
300 self.b(' * Returns: a #TpProxySignalConnection containing all of the')
301 self.b(' * above, which can be used to disconnect the signal; or')
302 self.b(' * %NULL if the proxy does not have the desired interface')
303 self.b(' * or has become invalid.')
305 self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,'
306 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
307 self.h(' %s callback,' % callback_name)
308 self.h(' gpointer user_data,')
309 self.h(' GDestroyNotify destroy,')
310 self.h(' GObject *weak_object,')
311 self.h(' GError **error);')
313 self.b('TpProxySignalConnection *')
314 self.b('%s_%s_connect_to_%s (%sproxy,'
315 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
316 self.b(' %s callback,' % callback_name)
317 self.b(' gpointer user_data,')
318 self.b(' GDestroyNotify destroy,')
319 self.b(' GObject *weak_object,')
320 self.b(' GError **error)')
322 self.b(' GType expected_types[%d] = {' % (len(args) + 1))
325 name, info, tp_type, elt = arg
326 ctype, gtype, marshaller, pointer = info
328 self.b(' %s,' % gtype)
330 self.b(' G_TYPE_INVALID };')
332 self.b(' g_return_val_if_fail (%s (proxy), NULL);'
334 self.b(' g_return_val_if_fail (callback != NULL, NULL);')
336 self.b(' return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,')
337 self.b(' %s, \"%s\",' % (self.get_iface_quark(), member))
338 self.b(' expected_types,')
341 self.b(' G_CALLBACK (%s),' % collect_name)
343 self.b(' NULL, /* no args => no collector function */')
345 self.b(' %s,' % invoke_name)
346 self.b(' G_CALLBACK (callback), user_data, destroy,')
347 self.b(' weak_object, error);')
353 def do_method(self, iface, method):
354 iface_lc = iface.lower()
356 member = method.getAttribute('name')
357 member_lc = camelcase_to_lower(member)
358 member_uc = member_lc.upper()
365 for arg in method.getElementsByTagName('arg'):
366 name = arg.getAttribute('name')
367 direction = arg.getAttribute('direction')
368 type = arg.getAttribute('type')
369 tp_type = arg.getAttribute('tp:type')
371 if direction != 'out':
373 name = 'in%u' % in_count
376 name = 'in_%s' % name
379 name = 'out%u' % ret_count
382 name = 'out_%s' % name
384 info = type_to_gtype(type)
385 if direction != 'out':
386 in_args.append((name, info, tp_type, arg))
388 out_args.append((name, info, tp_type, arg))
390 # Async reply callback type
393 # void (*tp_cli_properties_interface_callback_for_get_properties)
395 # const GPtrArray *out0,
396 # const GError *error,
397 # gpointer user_data,
398 # GObject *weak_object);
401 self.b(' * %s_%s_callback_for_%s:'
402 % (self.prefix_lc, iface_lc, member_lc))
403 self.b(' * @proxy: the proxy on which the call was made')
406 name, info, tp_type, elt = arg
407 ctype, gtype, marshaller, pointer = info
409 self.b(' * @%s: Used to return an \'out\' argument if @error is '
411 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
413 self.b(' * @error: %NULL on success, or an error on failure')
414 self.b(' * @user_data: user-supplied data')
415 self.b(' * @weak_object: user-supplied object')
417 self.b(' * Signature of the callback called when a %s method call'
419 self.b(' * succeeds or fails.')
422 callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
425 self.h('typedef void (*%s) (%sproxy,'
426 % (callback_name, self.proxy_cls))
429 name, info, tp_type, elt = arg
430 ctype, gtype, marshaller, pointer = info
431 const = pointer and 'const ' or ''
433 self.h(' %s%s%s,' % (const, ctype, name))
435 self.h(' const GError *error, gpointer user_data,')
436 self.h(' GObject *weak_object);')
439 # Async callback implementation
441 invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
445 collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
449 # The callback called by dbus-glib; this ends the call and collects
450 # the results into a GValueArray.
451 self.b('static void')
452 self.b('%s (DBusGProxy *proxy,' % collect_callback)
453 self.b(' DBusGProxyCall *call,')
454 self.b(' gpointer user_data)')
456 self.b(' GError *error = NULL;')
458 if len(out_args) > 0:
459 self.b(' GValueArray *args;')
460 self.b(' GValue blank = { 0 };')
464 name, info, tp_type, elt = arg
465 ctype, gtype, marshaller, pointer = info
467 # "We handle variants specially; the caller is expected to
468 # have already allocated storage for them". Thanks,
470 if gtype == 'G_TYPE_VALUE':
471 self.b(' GValue *%s = g_new0 (GValue, 1);' % name)
473 self.b(' %s%s;' % (ctype, name))
476 self.b(' dbus_g_proxy_end_call (proxy, call, &error,')
479 name, info, tp_type, elt = arg
480 ctype, gtype, marshaller, pointer = info
482 if gtype == 'G_TYPE_VALUE':
483 self.b(' %s, %s,' % (gtype, name))
485 self.b(' %s, &%s,' % (gtype, name))
487 self.b(' G_TYPE_INVALID);')
489 if len(out_args) == 0:
490 self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,'
494 self.b(' if (error != NULL)')
496 self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,')
500 name, info, tp_type, elt = arg
501 ctype, gtype, marshaller, pointer = info
502 if gtype == 'G_TYPE_VALUE':
503 self.b(' g_free (%s);' % name)
508 self.b(' args = g_value_array_new (%d);' % len(out_args))
509 self.b(' g_value_init (&blank, G_TYPE_INT);')
511 self.b(' for (i = 0; i < %d; i++)' % len(out_args))
512 self.b(' g_value_array_append (args, &blank);')
514 for i, arg in enumerate(out_args):
515 name, info, tp_type, elt = arg
516 ctype, gtype, marshaller, pointer = info
519 self.b(' g_value_unset (args->values + %d);' % i)
520 self.b(' g_value_init (args->values + %d, %s);' % (i, gtype))
522 if gtype == 'G_TYPE_STRING':
523 self.b(' g_value_take_string (args->values + %d, %s);'
525 elif marshaller == 'BOXED':
526 self.b(' g_value_take_boxed (args->values + %d, %s);'
528 elif gtype == 'G_TYPE_UCHAR':
529 self.b(' g_value_set_uchar (args->values + %d, %s);'
531 elif gtype == 'G_TYPE_BOOLEAN':
532 self.b(' g_value_set_boolean (args->values + %d, %s);'
534 elif gtype == 'G_TYPE_INT':
535 self.b(' g_value_set_int (args->values + %d, %s);'
537 elif gtype == 'G_TYPE_UINT':
538 self.b(' g_value_set_uint (args->values + %d, %s);'
540 elif gtype == 'G_TYPE_INT64':
541 self.b(' g_value_set_int (args->values + %d, %s);'
543 elif gtype == 'G_TYPE_UINT64':
544 self.b(' g_value_set_uint (args->values + %d, %s);'
546 elif gtype == 'G_TYPE_DOUBLE':
547 self.b(' g_value_set_double (args->values + %d, %s);'
550 assert False, ("Don't know how to put %s in a GValue"
553 self.b(' tp_proxy_pending_call_v0_take_results (user_data, '
558 self.b('static void')
559 self.b('%s (TpProxy *self,' % invoke_callback)
560 self.b(' GError *error,')
561 self.b(' GValueArray *args,')
562 self.b(' GCallback generic_callback,')
563 self.b(' gpointer user_data,')
564 self.b(' GObject *weak_object)')
566 self.b(' %s callback = (%s) generic_callback;'
567 % (callback_name, callback_name))
569 self.b(' if (error != NULL)')
571 self.b(' callback ((%s) self,' % self.proxy_cls)
574 name, info, tp_type, elt = arg
575 ctype, gtype, marshaller, pointer = info
577 if marshaller == 'BOXED' or pointer:
579 elif gtype == 'G_TYPE_DOUBLE':
584 self.b(' error, user_data, weak_object);')
585 self.b(' g_error_free (error);')
589 self.b(' callback ((%s) self,' % self.proxy_cls)
591 # FIXME: factor out into a function
592 for i, arg in enumerate(out_args):
593 name, info, tp_type, elt = arg
594 ctype, gtype, marshaller, pointer = info
596 if marshaller == 'BOXED':
597 self.b(' g_value_get_boxed (args->values + %d),' % i)
598 elif gtype == 'G_TYPE_STRING':
599 self.b(' g_value_get_string (args->values + %d),' % i)
600 elif gtype == 'G_TYPE_UCHAR':
601 self.b(' g_value_get_uchar (args->values + %d),' % i)
602 elif gtype == 'G_TYPE_BOOLEAN':
603 self.b(' g_value_get_boolean (args->values + %d),' % i)
604 elif gtype == 'G_TYPE_UINT':
605 self.b(' g_value_get_uint (args->values + %d),' % i)
606 elif gtype == 'G_TYPE_INT':
607 self.b(' g_value_get_int (args->values + %d),' % i)
608 elif gtype == 'G_TYPE_UINT64':
609 self.b(' g_value_get_uint64 (args->values + %d),' % i)
610 elif gtype == 'G_TYPE_INT64':
611 self.b(' g_value_get_int64 (args->values + %d),' % i)
612 elif gtype == 'G_TYPE_DOUBLE':
613 self.b(' g_value_get_double (args->values + %d),' % i)
615 assert False, "Don't know how to get %s from a GValue" % gtype
617 self.b(' error, user_data, weak_object);')
620 if len(out_args) > 0:
621 self.b(' g_value_array_free (args);')
623 self.b(' if (args != NULL)')
624 self.b(' g_value_array_free (args);')
632 # TpProxyPendingCall *
633 # tp_cli_properties_interface_call_get_properties
636 # const GArray *in_properties,
637 # tp_cli_properties_interface_callback_for_get_properties callback,
638 # gpointer user_data,
639 # GDestroyNotify *destructor);
641 self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
642 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
643 self.h(' gint timeout_ms,')
646 self.b(' * %s_%s_call_%s:'
647 % (self.prefix_lc, iface_lc, member_lc))
648 self.b(' * @proxy: the #TpProxy')
649 self.b(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
653 name, info, tp_type, elt = arg
654 ctype, gtype, marshaller, pointer = info
656 self.b(' * @%s: Used to pass an \'in\' argument: %s'
657 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
659 self.b(' * @callback: called when the method call succeeds or fails')
660 self.b(' * @user_data: user-supplied data passed to the callback')
661 self.b(' * @destroy: called with the user_data as argument, after the')
662 self.b(' * call has succeeded, failed or been cancelled')
663 self.b(' * @weak_object: A #GObject which will be weakly referenced; ')
664 self.b(' * if it is destroyed, this callback will automatically be')
665 self.b(' * disconnected')
667 self.b(' * Start a %s method call.' % member)
669 self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
671 self.b(' * Returns: a #TpProxyPendingCall representing the call in')
672 self.b(' * progress. It is borrowed from the object, and will become')
673 self.b(' * invalid when the callback is called, the call is')
674 self.b(' * cancelled or the #TpProxy becomes invalid.')
676 self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
677 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
678 self.b(' gint timeout_ms,')
681 name, info, tp_type, elt = arg
682 ctype, gtype, marshaller, pointer = info
684 const = pointer and 'const ' or ''
686 self.h(' %s%s%s,' % (const, ctype, name))
687 self.b(' %s%s%s,' % (const, ctype, name))
689 self.h(' %s callback,' % callback_name)
690 self.h(' gpointer user_data,')
691 self.h(' GDestroyNotify destroy,')
692 self.h(' GObject *weak_object);')
695 self.b(' %s callback,' % callback_name)
696 self.b(' gpointer user_data,')
697 self.b(' GDestroyNotify destroy,')
698 self.b(' GObject *weak_object)')
700 self.b(' GError *error = NULL;')
701 self.b(' GQuark interface = %s;' % self.get_iface_quark())
702 self.b(' DBusGProxy *iface;')
704 self.b(' g_return_val_if_fail (%s (proxy), NULL);'
707 self.b(' iface = tp_proxy_borrow_interface_by_id (')
708 self.b(' (TpProxy *) proxy,')
709 self.b(' interface, &error);')
711 self.b(' if (iface == NULL)')
713 self.b(' if (callback != NULL)')
714 self.b(' callback (proxy,')
717 name, info, tp_type, elt = arg
718 ctype, gtype, marshaller, pointer = info
725 self.b(' error, user_data, weak_object);')
726 self.b(' g_error_free (error);')
727 self.b(' return NULL;')
730 self.b(' if (callback == NULL)')
732 self.b(' dbus_g_proxy_call_no_reply (iface, "%s",' % member)
735 name, info, tp_type, elt = arg
736 ctype, gtype, marshaller, pointer = info
738 const = pointer and 'const ' or ''
740 self.b(' %s, %s,' % (gtype, name))
742 self.b(' G_TYPE_INVALID);')
743 self.b(' return NULL;')
747 self.b(' TpProxyPendingCall *data;')
749 self.b(' data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
750 self.b(' interface, "%s", iface,' % member)
751 self.b(' %s,' % invoke_callback)
752 self.b(' G_CALLBACK (callback), user_data, destroy,')
753 self.b(' weak_object, FALSE);')
754 self.b(' tp_proxy_pending_call_v0_take_pending_call (data,')
755 self.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
756 self.b(' "%s",' % member)
757 self.b(' %s,' % collect_callback)
759 self.b(' tp_proxy_pending_call_v0_completed,')
760 self.b(' timeout_ms,')
763 name, info, tp_type, elt = arg
764 ctype, gtype, marshaller, pointer = info
766 const = pointer and 'const ' or ''
768 self.b(' %s, %s,' % (gtype, name))
770 self.b(' G_TYPE_INVALID));')
772 self.b(' return data;')
777 # Reentrant blocking calls
779 # gboolean tp_cli_properties_interface_run_get_properties
782 # const GArray *in_properties,
787 self.b('typedef struct {')
788 self.b(' GMainLoop *loop;')
789 self.b(' GError **error;')
792 name, info, tp_type, elt = arg
793 ctype, gtype, marshaller, pointer = info
795 self.b(' %s*%s;' % (ctype, name))
797 self.b(' gboolean success:1;')
798 self.b(' gboolean completed:1;')
799 self.b('} _%s_%s_run_state_%s;'
800 % (self.prefix_lc, iface_lc, member_lc))
802 reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
806 self.b('static void')
807 self.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke)
808 self.b(' GError *error,')
809 self.b(' GValueArray *args,')
810 self.b(' GCallback unused G_GNUC_UNUSED,')
811 self.b(' gpointer user_data G_GNUC_UNUSED,')
812 self.b(' GObject *unused2 G_GNUC_UNUSED)')
814 self.b(' _%s_%s_run_state_%s *state = user_data;'
815 % (self.prefix_lc, iface_lc, member_lc))
817 self.b(' state->success = (error == NULL);')
818 self.b(' state->completed = TRUE;')
819 self.b(' g_main_loop_quit (state->loop);')
821 self.b(' if (error != NULL)')
823 self.b(' if (state->error != NULL)')
824 self.b(' *state->error = error;')
826 self.b(' g_error_free (error);')
832 for i, arg in enumerate(out_args):
833 name, info, tp_type, elt = arg
834 ctype, gtype, marshaller, pointer = info
836 self.b(' if (state->%s != NULL)' % name)
837 if marshaller == 'BOXED':
838 self.b(' *state->%s = g_value_dup_boxed ('
839 'args->values + %d);' % (name, i))
840 elif marshaller == 'STRING':
841 self.b(' *state->%s = g_value_dup_string '
842 '(args->values + %d);' % (name, i))
843 elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
844 'INT64', 'UINT64', 'DOUBLE'):
845 self.b(' *state->%s = g_value_get_%s (args->values + %d);'
846 % (name, marshaller.lower(), i))
848 assert False, "Don't know how to copy %s" % gtype
852 if len(out_args) > 0:
853 self.b(' g_value_array_free (args);')
855 self.b(' if (args != NULL)')
856 self.b(' g_value_array_free (args);')
861 self.h('gboolean %s_%s_run_%s (%sproxy,'
862 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
863 self.h(' gint timeout_ms,')
866 self.b(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc))
867 self.b(' * @proxy: %s' % self.proxy_doc)
868 self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default')
871 name, info, tp_type, elt = arg
872 ctype, gtype, marshaller, pointer = info
874 self.b(' * @%s: Used to pass an \'in\' argument: %s'
875 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
878 name, info, tp_type, elt = arg
879 ctype, gtype, marshaller, pointer = info
881 self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is '
883 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
885 self.b(' * @error: If not %NULL, used to return errors if %FALSE ')
886 self.b(' * is returned')
887 self.b(' * @loop: If not %NULL, set before re-entering ')
888 self.b(' * the main loop, to point to a #GMainLoop ')
889 self.b(' * which can be used to cancel this call with ')
890 self.b(' * g_main_loop_quit(), causing a return of ')
891 self.b(' * %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
893 self.b(' * Call the method %s and run the main loop' % member)
894 self.b(' * until it returns. Before calling this method, you must')
895 self.b(' * add a reference to any borrowed objects you need to keep,')
896 self.b(' * and generally ensure that everything is in a consistent')
899 self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
901 self.b(' * Returns: TRUE on success, FALSE and sets @error on error')
903 self.b('gboolean\n%s_%s_run_%s (%sproxy,'
904 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
905 self.b(' gint timeout_ms,')
908 name, info, tp_type, elt = arg
909 ctype, gtype, marshaller, pointer = info
911 const = pointer and 'const ' or ''
913 self.h(' %s%s%s,' % (const, ctype, name))
914 self.b(' %s%s%s,' % (const, ctype, name))
917 name, info, tp_type, elt = arg
918 ctype, gtype, marshaller, pointer = info
920 self.h(' %s*%s,' % (ctype, name))
921 self.b(' %s*%s,' % (ctype, name))
923 self.h(' GError **error,')
924 self.h(' GMainLoop **loop);')
927 self.b(' GError **error,')
928 self.b(' GMainLoop **loop)')
930 self.b(' DBusGProxy *iface;')
931 self.b(' GQuark interface = %s;' % self.get_iface_quark())
932 self.b(' TpProxyPendingCall *pc;')
933 self.b(' _%s_%s_run_state_%s state = {'
934 % (self.prefix_lc, iface_lc, member_lc))
935 self.b(' NULL /* loop */, error,')
938 name, info, tp_type, elt = arg
940 self.b(' %s,' % name)
942 self.b(' FALSE /* completed */, FALSE /* success */ };')
944 self.b(' g_return_val_if_fail (%s (proxy), FALSE);'
947 self.b(' iface = tp_proxy_borrow_interface_by_id')
948 self.b(' ((TpProxy *) proxy, interface, error);')
950 self.b(' if (iface == NULL)')
951 self.b(' return FALSE;')
953 self.b(' state.loop = g_main_loop_new (NULL, FALSE);')
955 self.b(' pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
956 self.b(' interface, "%s", iface,' % member)
957 self.b(' %s,' % reentrant_invoke)
958 self.b(' NULL, &state, NULL, NULL, TRUE);')
960 self.b(' if (loop != NULL)')
961 self.b(' *loop = state.loop;')
963 self.b(' tp_proxy_pending_call_v0_take_pending_call (pc,')
964 self.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
965 self.b(' "%s",' % member)
966 self.b(' %s,' % collect_callback)
968 self.b(' tp_proxy_pending_call_v0_completed,')
969 self.b(' timeout_ms,')
972 name, info, tp_type, elt = arg
973 ctype, gtype, marshaller, pointer = info
975 const = pointer and 'const ' or ''
977 self.b(' %s, %s,' % (gtype, name))
979 self.b(' G_TYPE_INVALID));')
981 self.b(' if (!state.completed)')
982 self.b(' g_main_loop_run (state.loop);')
984 self.b(' if (!state.completed)')
985 self.b(' tp_proxy_pending_call_cancel (pc);')
987 self.b(' if (loop != NULL)')
988 self.b(' *loop = NULL;')
990 self.b(' g_main_loop_unref (state.loop);')
992 self.b(' return state.success;')
996 # leave a gap for the end of the method
1000 def do_signal_add(self, signal):
1001 marshaller_items = []
1004 for i in signal.getElementsByTagName('arg'):
1005 name = i.getAttribute('name')
1006 type = i.getAttribute('type')
1007 info = type_to_gtype(type)
1008 # type, GType, STRING, is a pointer
1009 gtypes.append(info[1])
1011 self.b(' dbus_g_proxy_add_signal (proxy, "%s",'
1012 % signal.getAttribute('name'))
1013 for gtype in gtypes:
1014 self.b(' %s,' % gtype)
1015 self.b(' G_TYPE_INVALID);')
1017 def do_interface(self, node):
1018 ifaces = node.getElementsByTagName('interface')
1019 assert len(ifaces) == 1
1021 name = node.getAttribute('name').replace('/', '')
1024 self.iface_lc = name.lower()
1025 self.iface_uc = name.upper()
1026 self.iface_mc = name.replace('_', '')
1027 self.iface_dbus = iface.getAttribute('name')
1029 signals = node.getElementsByTagName('signal')
1030 methods = node.getElementsByTagName('method')
1033 self.b('static inline void')
1034 self.b('%s_add_signals_for_%s (DBusGProxy *proxy)'
1035 % (self.prefix_lc, name.lower()))
1038 if self.tp_proxy_api >= (0, 7, 6):
1039 self.b(' if (!tp_proxy_dbus_g_proxy_claim_for_signal_adding '
1043 for signal in signals:
1044 self.do_signal_add(signal)
1050 for signal in signals:
1051 self.do_signal(name, signal)
1053 for method in methods:
1054 self.do_method(name, method)
1056 self.iface_dbus = None
1060 self.h('G_BEGIN_DECLS')
1063 self.b('/* We don\'t want gtkdoc scanning this file, it\'ll get')
1064 self.b(' * confused by seeing function definitions, so mark it as: */')
1065 self.b('/*<private_header>*/')
1068 nodes = self.dom.getElementsByTagName('node')
1069 nodes.sort(cmp_by_name)
1072 self.do_interface(node)
1074 if self.group is not None:
1077 self.b(' * %s_%s_add_signals:' % (self.prefix_lc, self.group))
1078 self.b(' * @self: the #TpProxy')
1079 self.b(' * @quark: a quark whose string value is the interface')
1080 self.b(' * name whose signals should be added')
1081 self.b(' * @proxy: the D-Bus proxy to which to add the signals')
1082 self.b(' * @unused: not used for anything')
1084 self.b(' * Tell dbus-glib that @proxy has the signatures of all')
1085 self.b(' * signals on the given interface, if it\'s one we')
1086 self.b(' * support.')
1088 self.b(' * This function should be used as a signal handler for')
1089 self.b(' * #TpProxy::interface-added.')
1091 self.b('static void')
1092 self.b('%s_%s_add_signals (TpProxy *self G_GNUC_UNUSED,'
1093 % (self.prefix_lc, self.group))
1094 self.b(' guint quark,')
1095 self.b(' DBusGProxy *proxy,')
1096 self.b(' gpointer unused G_GNUC_UNUSED)')
1101 iface = node.getElementsByTagName('interface')[0]
1102 self.iface_dbus = iface.getAttribute('name')
1103 signals = node.getElementsByTagName('signal')
1106 name = node.getAttribute('name').replace('/', '').lower()
1107 self.iface_uc = name.upper()
1108 self.b(' if (quark == %s)' % self.get_iface_quark())
1109 self.b(' %s_add_signals_for_%s (proxy);'
1110 % (self.prefix_lc, name))
1115 self.h('G_END_DECLS')
1118 open(self.basename + '.h', 'w').write('\n'.join(self.__header))
1119 open(self.basename + '-body.h', 'w').write('\n'.join(self.__body))
1122 def types_to_gtypes(types):
1123 return [type_to_gtype(t)[1] for t in types]
1126 if __name__ == '__main__':
1127 options, argv = gnu_getopt(sys.argv[1:], '',
1128 ['group=', 'subclass=', 'subclass-assert=',
1129 'iface-quark-prefix=', 'tp-proxy-api='])
1133 for option, value in options:
1134 opts[option] = value
1136 dom = xml.dom.minidom.parse(argv[0])
1138 Generator(dom, argv[1], argv[2], opts)()