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 libtpcodegen
import file_set_contents
31 from libglibcodegen
import Signature
, type_to_gtype
, cmp_by_name
, \
32 get_docstring
, xml_escape
, get_deprecated
35 NS_TP
= "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
37 class Generator(object):
39 def __init__(self
, dom
, prefix
, basename
, opts
):
45 self
.prefix_lc
= prefix
.lower()
46 self
.prefix_uc
= prefix
.upper()
47 self
.prefix_mc
= prefix
.replace('_', '')
48 self
.basename
= basename
49 self
.group
= opts
.get('--group', None)
50 self
.iface_quark_prefix
= opts
.get('--iface-quark-prefix', None)
51 self
.tp_proxy_api
= tuple(map(int,
52 opts
.get('--tp-proxy-api', '0').split('.')))
53 self
.proxy_cls
= opts
.get('--subclass', 'TpProxy') + ' *'
54 self
.proxy_arg
= opts
.get('--subclass', 'void') + ' *'
55 self
.proxy_assert
= opts
.get('--subclass-assert', 'TP_IS_PROXY')
56 self
.proxy_doc
= ('A #%s or subclass'
57 % opts
.get('--subclass', 'TpProxy'))
58 if self
.proxy_arg
== 'void *':
59 self
.proxy_arg
= 'gpointer '
61 self
.reentrant_symbols
= set()
63 filename
= opts
['--generate-reentrant']
64 with
open(filename
, 'r') as f
:
65 for line
in f
.readlines():
66 self
.reentrant_symbols
.add(line
.strip())
70 self
.deprecate_reentrant
= opts
.get('--deprecate-reentrant', None)
71 self
.deprecation_attribute
= opts
.get('--deprecation-attribute',
74 self
.guard
= opts
.get('--guard', None)
77 if isinstance(s
, unicode):
79 self
.__header
.append(s
)
82 if isinstance(s
, unicode):
87 if isinstance(s
, unicode):
91 def get_iface_quark(self
):
92 assert self
.iface_dbus
is not None
93 assert self
.iface_uc
is not None
94 if self
.iface_quark_prefix
is None:
95 return 'g_quark_from_static_string (\"%s\")' % self
.iface_dbus
97 return '%s_%s' % (self
.iface_quark_prefix
, self
.iface_uc
)
99 def do_signal(self
, iface
, signal
):
100 iface_lc
= iface
.lower()
102 member
= signal
.getAttribute('name')
103 member_lc
= signal
.getAttribute('tp:name-for-bindings')
104 if member
!= member_lc
.replace('_', ''):
105 raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
106 'not match' % (member
, member_lc
))
107 member_lc
= member_lc
.lower()
108 member_uc
= member_lc
.upper()
114 for arg
in signal
.getElementsByTagName('arg'):
115 name
= arg
.getAttribute('name')
116 type = arg
.getAttribute('type')
117 tp_type
= arg
.getAttribute('tp:type')
120 name
= 'arg%u' % arg_count
123 name
= 'arg_%s' % name
125 info
= type_to_gtype(type)
126 args
.append((name
, info
, tp_type
, arg
))
128 callback_name
= ('%s_%s_signal_callback_%s'
129 % (self
.prefix_lc
, iface_lc
, member_lc
))
130 collect_name
= ('_%s_%s_collect_args_of_%s'
131 % (self
.prefix_lc
, iface_lc
, member_lc
))
132 invoke_name
= ('_%s_%s_invoke_callback_for_%s'
133 % (self
.prefix_lc
, iface_lc
, member_lc
))
137 # typedef void (*tp_cli_connection_signal_callback_new_channel)
138 # (TpConnection *proxy, const gchar *arg_object_path,
139 # const gchar *arg_channel_type, guint arg_handle_type,
140 # guint arg_handle, gboolean arg_suppress_handler,
141 # gpointer user_data, GObject *weak_object);
144 self
.d(' * %s:' % callback_name
)
145 self
.d(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
146 % (self
.prefix_lc
, iface_lc
, member_lc
))
147 self
.d(' * was called')
150 name
, info
, tp_type
, elt
= arg
151 ctype
, gtype
, marshaller
, pointer
= info
153 docs
= get_docstring(elt
) or '(Undocumented)'
155 if ctype
== 'guint ' and tp_type
!= '':
156 docs
+= ' (#%s)' % ('Tp' + tp_type
.replace('_', ''))
158 self
.d(' * @%s: %s' % (name
, xml_escape(docs
)))
160 self
.d(' * @user_data: User-supplied data')
161 self
.d(' * @weak_object: User-supplied weakly referenced object')
163 self
.d(' * Represents the signature of a callback for the signal %s.'
168 self
.h('typedef void (*%s) (%sproxy,'
169 % (callback_name
, self
.proxy_cls
))
172 name
, info
, tp_type
, elt
= arg
173 ctype
, gtype
, marshaller
, pointer
= info
175 const
= pointer
and 'const ' or ''
177 self
.h(' %s%s%s,' % (const
, ctype
, name
))
179 self
.h(' gpointer user_data, GObject *weak_object);')
182 self
.b('static void')
183 self
.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name
)
186 name
, info
, tp_type
, elt
= arg
187 ctype
, gtype
, marshaller
, pointer
= info
189 const
= pointer
and 'const ' or ''
191 self
.b(' %s%s%s,' % (const
, ctype
, name
))
193 self
.b(' TpProxySignalConnection *sc)')
195 self
.b(' GValueArray *args = g_value_array_new (%d);' % len(args
))
196 self
.b(' GValue blank = { 0 };')
199 self
.b(' g_value_init (&blank, G_TYPE_INT);')
201 self
.b(' for (i = 0; i < %d; i++)' % len(args
))
202 self
.b(' g_value_array_append (args, &blank);')
205 for i
, arg
in enumerate(args
):
206 name
, info
, tp_type
, elt
= arg
207 ctype
, gtype
, marshaller
, pointer
= info
209 self
.b(' g_value_unset (args->values + %d);' % i
)
210 self
.b(' g_value_init (args->values + %d, %s);' % (i
, gtype
))
212 if gtype
== 'G_TYPE_STRING':
213 self
.b(' g_value_set_string (args->values + %d, %s);'
215 elif marshaller
== 'BOXED':
216 self
.b(' g_value_set_boxed (args->values + %d, %s);'
218 elif gtype
== 'G_TYPE_UCHAR':
219 self
.b(' g_value_set_uchar (args->values + %d, %s);'
221 elif gtype
== 'G_TYPE_BOOLEAN':
222 self
.b(' g_value_set_boolean (args->values + %d, %s);'
224 elif gtype
== 'G_TYPE_INT':
225 self
.b(' g_value_set_int (args->values + %d, %s);'
227 elif gtype
== 'G_TYPE_UINT':
228 self
.b(' g_value_set_uint (args->values + %d, %s);'
230 elif gtype
== 'G_TYPE_INT64':
231 self
.b(' g_value_set_int (args->values + %d, %s);'
233 elif gtype
== 'G_TYPE_UINT64':
234 self
.b(' g_value_set_uint64 (args->values + %d, %s);'
236 elif gtype
== 'G_TYPE_DOUBLE':
237 self
.b(' g_value_set_double (args->values + %d, %s);'
240 assert False, ("Don't know how to put %s in a GValue"
244 self
.b(' tp_proxy_signal_connection_v0_take_results (sc, args);')
247 self
.b('static void')
248 self
.b('%s (TpProxy *tpproxy,' % invoke_name
)
249 self
.b(' GError *error G_GNUC_UNUSED,')
250 self
.b(' GValueArray *args,')
251 self
.b(' GCallback generic_callback,')
252 self
.b(' gpointer user_data,')
253 self
.b(' GObject *weak_object)')
255 self
.b(' %s callback =' % callback_name
)
256 self
.b(' (%s) generic_callback;' % callback_name
)
258 self
.b(' if (callback != NULL)')
259 self
.b(' callback (g_object_ref (tpproxy),')
261 # FIXME: factor out into a function
262 for i
, arg
in enumerate(args
):
263 name
, info
, tp_type
, elt
= arg
264 ctype
, gtype
, marshaller
, pointer
= info
266 if marshaller
== 'BOXED':
267 self
.b(' g_value_get_boxed (args->values + %d),' % i
)
268 elif gtype
== 'G_TYPE_STRING':
269 self
.b(' g_value_get_string (args->values + %d),' % i
)
270 elif gtype
== 'G_TYPE_UCHAR':
271 self
.b(' g_value_get_uchar (args->values + %d),' % i
)
272 elif gtype
== 'G_TYPE_BOOLEAN':
273 self
.b(' g_value_get_boolean (args->values + %d),' % i
)
274 elif gtype
== 'G_TYPE_UINT':
275 self
.b(' g_value_get_uint (args->values + %d),' % i
)
276 elif gtype
== 'G_TYPE_INT':
277 self
.b(' g_value_get_int (args->values + %d),' % i
)
278 elif gtype
== 'G_TYPE_UINT64':
279 self
.b(' g_value_get_uint64 (args->values + %d),' % i
)
280 elif gtype
== 'G_TYPE_INT64':
281 self
.b(' g_value_get_int64 (args->values + %d),' % i
)
282 elif gtype
== 'G_TYPE_DOUBLE':
283 self
.b(' g_value_get_double (args->values + %d),' % i
)
285 assert False, "Don't know how to get %s from a GValue" % gtype
287 self
.b(' user_data,')
288 self
.b(' weak_object);')
292 self
.b(' g_value_array_free (args);')
294 self
.b(' if (args != NULL)')
295 self
.b(' g_value_array_free (args);')
298 self
.b(' g_object_unref (tpproxy);')
303 # TpProxySignalConnection *
304 # tp_cli_connection_connect_to_new_channel
305 # (TpConnection *proxy,
306 # tp_cli_connection_signal_callback_new_channel callback,
307 # gpointer user_data,
308 # GDestroyNotify destroy);
310 # destroy is invoked when the signal becomes disconnected. This
311 # is either because the signal has been disconnected explicitly
312 # by the user, because the TpProxy has become invalid and
313 # emitted the 'invalidated' signal, or because the weakly referenced
314 # object has gone away.
317 self
.d(' * %s_%s_connect_to_%s:'
318 % (self
.prefix_lc
, iface_lc
, member_lc
))
319 self
.d(' * @proxy: %s' % self
.proxy_doc
)
320 self
.d(' * @callback: Callback to be called when the signal is')
321 self
.d(' * received')
322 self
.d(' * @user_data: User-supplied data for the callback')
323 self
.d(' * @destroy: Destructor for the user-supplied data, which')
324 self
.d(' * will be called when this signal is disconnected, or')
325 self
.d(' * before this function returns %NULL')
326 self
.d(' * @weak_object: A #GObject which will be weakly referenced; ')
327 self
.d(' * if it is destroyed, this callback will automatically be')
328 self
.d(' * disconnected')
329 self
.d(' * @error: If not %NULL, used to raise an error if %NULL is')
330 self
.d(' * returned')
332 self
.d(' * Connect a handler to the signal %s.' % member
)
334 self
.d(' * %s' % xml_escape(get_docstring(signal
) or '(Undocumented)'))
336 self
.d(' * Returns: a #TpProxySignalConnection containing all of the')
337 self
.d(' * above, which can be used to disconnect the signal; or')
338 self
.d(' * %NULL if the proxy does not have the desired interface')
339 self
.d(' * or has become invalid.')
343 self
.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,'
344 % (self
.prefix_lc
, iface_lc
, member_lc
, self
.proxy_arg
))
345 self
.h(' %s callback,' % callback_name
)
346 self
.h(' gpointer user_data,')
347 self
.h(' GDestroyNotify destroy,')
348 self
.h(' GObject *weak_object,')
349 self
.h(' GError **error);')
352 self
.b('TpProxySignalConnection *')
353 self
.b('%s_%s_connect_to_%s (%sproxy,'
354 % (self
.prefix_lc
, iface_lc
, member_lc
, self
.proxy_arg
))
355 self
.b(' %s callback,' % callback_name
)
356 self
.b(' gpointer user_data,')
357 self
.b(' GDestroyNotify destroy,')
358 self
.b(' GObject *weak_object,')
359 self
.b(' GError **error)')
361 self
.b(' GType expected_types[%d] = {' % (len(args
) + 1))
364 name
, info
, tp_type
, elt
= arg
365 ctype
, gtype
, marshaller
, pointer
= info
367 self
.b(' %s,' % gtype
)
369 self
.b(' G_TYPE_INVALID };')
371 self
.b(' g_return_val_if_fail (%s (proxy), NULL);'
373 self
.b(' g_return_val_if_fail (callback != NULL, NULL);')
375 self
.b(' return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,')
376 self
.b(' %s, \"%s\",' % (self
.get_iface_quark(), member
))
377 self
.b(' expected_types,')
380 self
.b(' G_CALLBACK (%s),' % collect_name
)
382 self
.b(' NULL, /* no args => no collector function */')
384 self
.b(' %s,' % invoke_name
)
385 self
.b(' G_CALLBACK (callback), user_data, destroy,')
386 self
.b(' weak_object, error);')
390 def do_method(self
, iface
, method
):
391 iface_lc
= iface
.lower()
393 member
= method
.getAttribute('name')
394 member_lc
= method
.getAttribute('tp:name-for-bindings')
395 if member
!= member_lc
.replace('_', ''):
396 raise AssertionError('Method %s tp:name-for-bindings (%s) does '
397 'not match' % (member
, member_lc
))
398 member_lc
= member_lc
.lower()
399 member_uc
= member_lc
.upper()
406 for arg
in method
.getElementsByTagName('arg'):
407 name
= arg
.getAttribute('name')
408 direction
= arg
.getAttribute('direction')
409 type = arg
.getAttribute('type')
410 tp_type
= arg
.getAttribute('tp:type')
412 if direction
!= 'out':
414 name
= 'in%u' % in_count
417 name
= 'in_%s' % name
420 name
= 'out%u' % ret_count
423 name
= 'out_%s' % name
425 info
= type_to_gtype(type)
426 if direction
!= 'out':
427 in_args
.append((name
, info
, tp_type
, arg
))
429 out_args
.append((name
, info
, tp_type
, arg
))
431 # Async reply callback type
434 # void (*tp_cli_properties_interface_callback_for_get_properties)
436 # const GPtrArray *out0,
437 # const GError *error,
438 # gpointer user_data,
439 # GObject *weak_object);
442 self
.d(' * %s_%s_callback_for_%s:'
443 % (self
.prefix_lc
, iface_lc
, member_lc
))
444 self
.d(' * @proxy: the proxy on which the call was made')
447 name
, info
, tp_type
, elt
= arg
448 ctype
, gtype
, marshaller
, pointer
= info
450 docs
= xml_escape(get_docstring(elt
) or '(Undocumented)')
452 if ctype
== 'guint ' and tp_type
!= '':
453 docs
+= ' (#%s)' % ('Tp' + tp_type
.replace('_', ''))
455 self
.d(' * @%s: Used to return an \'out\' argument if @error is '
459 self
.d(' * @error: %NULL on success, or an error on failure')
460 self
.d(' * @user_data: user-supplied data')
461 self
.d(' * @weak_object: user-supplied object')
463 self
.d(' * Signature of the callback called when a %s method call'
465 self
.d(' * succeeds or fails.')
467 deprecated
= method
.getElementsByTagName('tp:deprecated')
471 self
.d(' * Deprecated: %s' % xml_escape(get_deprecated(d
)))
476 callback_name
= '%s_%s_callback_for_%s' % (self
.prefix_lc
, iface_lc
,
479 self
.h('typedef void (*%s) (%sproxy,'
480 % (callback_name
, self
.proxy_cls
))
483 name
, info
, tp_type
, elt
= arg
484 ctype
, gtype
, marshaller
, pointer
= info
485 const
= pointer
and 'const ' or ''
487 self
.h(' %s%s%s,' % (const
, ctype
, name
))
489 self
.h(' const GError *error, gpointer user_data,')
490 self
.h(' GObject *weak_object);')
493 # Async callback implementation
495 invoke_callback
= '_%s_%s_invoke_callback_%s' % (self
.prefix_lc
,
499 collect_callback
= '_%s_%s_collect_callback_%s' % (self
.prefix_lc
,
503 # The callback called by dbus-glib; this ends the call and collects
504 # the results into a GValueArray.
505 self
.b('static void')
506 self
.b('%s (DBusGProxy *proxy,' % collect_callback
)
507 self
.b(' DBusGProxyCall *call,')
508 self
.b(' gpointer user_data)')
510 self
.b(' GError *error = NULL;')
512 if len(out_args
) > 0:
513 self
.b(' GValueArray *args;')
514 self
.b(' GValue blank = { 0 };')
518 name
, info
, tp_type
, elt
= arg
519 ctype
, gtype
, marshaller
, pointer
= info
521 # "We handle variants specially; the caller is expected to
522 # have already allocated storage for them". Thanks,
524 if gtype
== 'G_TYPE_VALUE':
525 self
.b(' GValue *%s = g_new0 (GValue, 1);' % name
)
527 self
.b(' %s%s;' % (ctype
, name
))
530 self
.b(' dbus_g_proxy_end_call (proxy, call, &error,')
533 name
, info
, tp_type
, elt
= arg
534 ctype
, gtype
, marshaller
, pointer
= info
536 if gtype
== 'G_TYPE_VALUE':
537 self
.b(' %s, %s,' % (gtype
, name
))
539 self
.b(' %s, &%s,' % (gtype
, name
))
541 self
.b(' G_TYPE_INVALID);')
543 if len(out_args
) == 0:
544 self
.b(' tp_proxy_pending_call_v0_take_results (user_data, error,'
548 self
.b(' if (error != NULL)')
550 self
.b(' tp_proxy_pending_call_v0_take_results (user_data, error,')
554 name
, info
, tp_type
, elt
= arg
555 ctype
, gtype
, marshaller
, pointer
= info
556 if gtype
== 'G_TYPE_VALUE':
557 self
.b(' g_free (%s);' % name
)
562 self
.b(' args = g_value_array_new (%d);' % len(out_args
))
563 self
.b(' g_value_init (&blank, G_TYPE_INT);')
565 self
.b(' for (i = 0; i < %d; i++)' % len(out_args
))
566 self
.b(' g_value_array_append (args, &blank);')
568 for i
, arg
in enumerate(out_args
):
569 name
, info
, tp_type
, elt
= arg
570 ctype
, gtype
, marshaller
, pointer
= info
573 self
.b(' g_value_unset (args->values + %d);' % i
)
574 self
.b(' g_value_init (args->values + %d, %s);' % (i
, gtype
))
576 if gtype
== 'G_TYPE_STRING':
577 self
.b(' g_value_take_string (args->values + %d, %s);'
579 elif marshaller
== 'BOXED':
580 self
.b(' g_value_take_boxed (args->values + %d, %s);'
582 elif gtype
== 'G_TYPE_UCHAR':
583 self
.b(' g_value_set_uchar (args->values + %d, %s);'
585 elif gtype
== 'G_TYPE_BOOLEAN':
586 self
.b(' g_value_set_boolean (args->values + %d, %s);'
588 elif gtype
== 'G_TYPE_INT':
589 self
.b(' g_value_set_int (args->values + %d, %s);'
591 elif gtype
== 'G_TYPE_UINT':
592 self
.b(' g_value_set_uint (args->values + %d, %s);'
594 elif gtype
== 'G_TYPE_INT64':
595 self
.b(' g_value_set_int (args->values + %d, %s);'
597 elif gtype
== 'G_TYPE_UINT64':
598 self
.b(' g_value_set_uint (args->values + %d, %s);'
600 elif gtype
== 'G_TYPE_DOUBLE':
601 self
.b(' g_value_set_double (args->values + %d, %s);'
604 assert False, ("Don't know how to put %s in a GValue"
607 self
.b(' tp_proxy_pending_call_v0_take_results (user_data, '
612 self
.b('static void')
613 self
.b('%s (TpProxy *self,' % invoke_callback
)
614 self
.b(' GError *error,')
615 self
.b(' GValueArray *args,')
616 self
.b(' GCallback generic_callback,')
617 self
.b(' gpointer user_data,')
618 self
.b(' GObject *weak_object)')
620 self
.b(' %s callback = (%s) generic_callback;'
621 % (callback_name
, callback_name
))
623 self
.b(' if (error != NULL)')
625 self
.b(' callback ((%s) self,' % self
.proxy_cls
)
628 name
, info
, tp_type
, elt
= arg
629 ctype
, gtype
, marshaller
, pointer
= info
631 if marshaller
== 'BOXED' or pointer
:
633 elif gtype
== 'G_TYPE_DOUBLE':
638 self
.b(' error, user_data, weak_object);')
639 self
.b(' g_error_free (error);')
643 self
.b(' callback ((%s) self,' % self
.proxy_cls
)
645 # FIXME: factor out into a function
646 for i
, arg
in enumerate(out_args
):
647 name
, info
, tp_type
, elt
= arg
648 ctype
, gtype
, marshaller
, pointer
= info
650 if marshaller
== 'BOXED':
651 self
.b(' g_value_get_boxed (args->values + %d),' % i
)
652 elif gtype
== 'G_TYPE_STRING':
653 self
.b(' g_value_get_string (args->values + %d),' % i
)
654 elif gtype
== 'G_TYPE_UCHAR':
655 self
.b(' g_value_get_uchar (args->values + %d),' % i
)
656 elif gtype
== 'G_TYPE_BOOLEAN':
657 self
.b(' g_value_get_boolean (args->values + %d),' % i
)
658 elif gtype
== 'G_TYPE_UINT':
659 self
.b(' g_value_get_uint (args->values + %d),' % i
)
660 elif gtype
== 'G_TYPE_INT':
661 self
.b(' g_value_get_int (args->values + %d),' % i
)
662 elif gtype
== 'G_TYPE_UINT64':
663 self
.b(' g_value_get_uint64 (args->values + %d),' % i
)
664 elif gtype
== 'G_TYPE_INT64':
665 self
.b(' g_value_get_int64 (args->values + %d),' % i
)
666 elif gtype
== 'G_TYPE_DOUBLE':
667 self
.b(' g_value_get_double (args->values + %d),' % i
)
669 assert False, "Don't know how to get %s from a GValue" % gtype
671 self
.b(' error, user_data, weak_object);')
674 if len(out_args
) > 0:
675 self
.b(' g_value_array_free (args);')
677 self
.b(' if (args != NULL)')
678 self
.b(' g_value_array_free (args);')
686 # TpProxyPendingCall *
687 # tp_cli_properties_interface_call_get_properties
690 # const GArray *in_properties,
691 # tp_cli_properties_interface_callback_for_get_properties callback,
692 # gpointer user_data,
693 # GDestroyNotify *destructor);
695 self
.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
696 % (self
.prefix_lc
, iface_lc
, member_lc
, self
.proxy_arg
))
697 self
.h(' gint timeout_ms,')
700 self
.d(' * %s_%s_call_%s:'
701 % (self
.prefix_lc
, iface_lc
, member_lc
))
702 self
.d(' * @proxy: the #TpProxy')
703 self
.d(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
707 name
, info
, tp_type
, elt
= arg
708 ctype
, gtype
, marshaller
, pointer
= info
710 docs
= xml_escape(get_docstring(elt
) or '(Undocumented)')
712 if ctype
== 'guint ' and tp_type
!= '':
713 docs
+= ' (#%s)' % ('Tp' + tp_type
.replace('_', ''))
715 self
.d(' * @%s: Used to pass an \'in\' argument: %s'
718 self
.d(' * @callback: called when the method call succeeds or fails;')
719 self
.d(' * may be %NULL to make a "fire and forget" call with no ')
720 self
.d(' * reply tracking')
721 self
.d(' * @user_data: user-supplied data passed to the callback;')
722 self
.d(' * must be %NULL if @callback is %NULL')
723 self
.d(' * @destroy: called with the user_data as argument, after the')
724 self
.d(' * call has succeeded, failed or been cancelled;')
725 self
.d(' * must be %NULL if @callback is %NULL')
726 self
.d(' * @weak_object: If not %NULL, a #GObject which will be ')
727 self
.d(' * weakly referenced; if it is destroyed, this call ')
728 self
.d(' * will automatically be cancelled. Must be %NULL if ')
729 self
.d(' * @callback is %NULL')
731 self
.d(' * Start a %s method call.' % member
)
733 self
.d(' * %s' % xml_escape(get_docstring(method
) or '(Undocumented)'))
735 self
.d(' * Returns: a #TpProxyPendingCall representing the call in')
736 self
.d(' * progress. It is borrowed from the object, and will become')
737 self
.d(' * invalid when the callback is called, the call is')
738 self
.d(' * cancelled or the #TpProxy becomes invalid.')
740 deprecated
= method
.getElementsByTagName('tp:deprecated')
744 self
.d(' * Deprecated: %s' % xml_escape(get_deprecated(d
)))
749 self
.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
750 % (self
.prefix_lc
, iface_lc
, member_lc
, self
.proxy_arg
))
751 self
.b(' gint timeout_ms,')
754 name
, info
, tp_type
, elt
= arg
755 ctype
, gtype
, marshaller
, pointer
= info
757 const
= pointer
and 'const ' or ''
759 self
.h(' %s%s%s,' % (const
, ctype
, name
))
760 self
.b(' %s%s%s,' % (const
, ctype
, name
))
762 self
.h(' %s callback,' % callback_name
)
763 self
.h(' gpointer user_data,')
764 self
.h(' GDestroyNotify destroy,')
765 self
.h(' GObject *weak_object);')
768 self
.b(' %s callback,' % callback_name
)
769 self
.b(' gpointer user_data,')
770 self
.b(' GDestroyNotify destroy,')
771 self
.b(' GObject *weak_object)')
773 self
.b(' GError *error = NULL;')
774 self
.b(' GQuark interface = %s;' % self
.get_iface_quark())
775 self
.b(' DBusGProxy *iface;')
777 self
.b(' g_return_val_if_fail (%s (proxy), NULL);'
779 self
.b(' g_return_val_if_fail (callback != NULL || '
780 'user_data == NULL, NULL);')
781 self
.b(' g_return_val_if_fail (callback != NULL || '
782 'destroy == NULL, NULL);')
783 self
.b(' g_return_val_if_fail (callback != NULL || '
784 'weak_object == NULL, NULL);')
786 self
.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
787 self
.b(' iface = tp_proxy_borrow_interface_by_id (')
788 self
.b(' (TpProxy *) proxy,')
789 self
.b(' interface, &error);')
790 self
.b(' G_GNUC_END_IGNORE_DEPRECATIONS')
792 self
.b(' if (iface == NULL)')
794 self
.b(' if (callback != NULL)')
795 self
.b(' callback (proxy,')
798 name
, info
, tp_type
, elt
= arg
799 ctype
, gtype
, marshaller
, pointer
= info
806 self
.b(' error, user_data, weak_object);')
808 self
.b(' if (destroy != NULL)')
809 self
.b(' destroy (user_data);')
811 self
.b(' g_error_free (error);')
812 self
.b(' return NULL;')
815 self
.b(' if (callback == NULL)')
817 self
.b(' dbus_g_proxy_call_no_reply (iface, "%s",' % member
)
820 name
, info
, tp_type
, elt
= arg
821 ctype
, gtype
, marshaller
, pointer
= info
823 const
= pointer
and 'const ' or ''
825 self
.b(' %s, %s,' % (gtype
, name
))
827 self
.b(' G_TYPE_INVALID);')
828 self
.b(' return NULL;')
832 self
.b(' TpProxyPendingCall *data;')
834 self
.b(' data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
835 self
.b(' interface, "%s", iface,' % member
)
836 self
.b(' %s,' % invoke_callback
)
837 self
.b(' G_CALLBACK (callback), user_data, destroy,')
838 self
.b(' weak_object, FALSE);')
839 self
.b(' tp_proxy_pending_call_v0_take_pending_call (data,')
840 self
.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
841 self
.b(' "%s",' % member
)
842 self
.b(' %s,' % collect_callback
)
844 self
.b(' tp_proxy_pending_call_v0_completed,')
845 self
.b(' timeout_ms,')
848 name
, info
, tp_type
, elt
= arg
849 ctype
, gtype
, marshaller
, pointer
= info
851 const
= pointer
and 'const ' or ''
853 self
.b(' %s, %s,' % (gtype
, name
))
855 self
.b(' G_TYPE_INVALID));')
857 self
.b(' return data;')
862 self
.do_method_reentrant(method
, iface_lc
, member
, member_lc
,
863 in_args
, out_args
, collect_callback
)
865 # leave a gap for the end of the method
870 def do_method_reentrant(self
, method
, iface_lc
, member
, member_lc
, in_args
,
871 out_args
, collect_callback
):
872 # Reentrant blocking calls
874 # gboolean tp_cli_properties_interface_run_get_properties
877 # const GArray *in_properties,
882 run_method_name
= '%s_%s_run_%s' % (self
.prefix_lc
, iface_lc
, member_lc
)
883 if run_method_name
not in self
.reentrant_symbols
:
886 self
.b('typedef struct {')
887 self
.b(' GMainLoop *loop;')
888 self
.b(' GError **error;')
891 name
, info
, tp_type
, elt
= arg
892 ctype
, gtype
, marshaller
, pointer
= info
894 self
.b(' %s*%s;' % (ctype
, name
))
896 self
.b(' unsigned success:1;')
897 self
.b(' unsigned completed:1;')
898 self
.b('} _%s_%s_run_state_%s;'
899 % (self
.prefix_lc
, iface_lc
, member_lc
))
901 reentrant_invoke
= '_%s_%s_finish_running_%s' % (self
.prefix_lc
,
905 self
.b('static void')
906 self
.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke
)
907 self
.b(' GError *error,')
908 self
.b(' GValueArray *args,')
909 self
.b(' GCallback unused G_GNUC_UNUSED,')
910 self
.b(' gpointer user_data G_GNUC_UNUSED,')
911 self
.b(' GObject *unused2 G_GNUC_UNUSED)')
913 self
.b(' _%s_%s_run_state_%s *state = user_data;'
914 % (self
.prefix_lc
, iface_lc
, member_lc
))
916 self
.b(' state->success = (error == NULL);')
917 self
.b(' state->completed = TRUE;')
918 self
.b(' g_main_loop_quit (state->loop);')
920 self
.b(' if (error != NULL)')
922 self
.b(' if (state->error != NULL)')
923 self
.b(' *state->error = error;')
925 self
.b(' g_error_free (error);')
931 for i
, arg
in enumerate(out_args
):
932 name
, info
, tp_type
, elt
= arg
933 ctype
, gtype
, marshaller
, pointer
= info
935 self
.b(' if (state->%s != NULL)' % name
)
936 if marshaller
== 'BOXED':
937 self
.b(' *state->%s = g_value_dup_boxed ('
938 'args->values + %d);' % (name
, i
))
939 elif marshaller
== 'STRING':
940 self
.b(' *state->%s = g_value_dup_string '
941 '(args->values + %d);' % (name
, i
))
942 elif marshaller
in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
943 'INT64', 'UINT64', 'DOUBLE'):
944 self
.b(' *state->%s = g_value_get_%s (args->values + %d);'
945 % (name
, marshaller
.lower(), i
))
947 assert False, "Don't know how to copy %s" % gtype
951 if len(out_args
) > 0:
952 self
.b(' g_value_array_free (args);')
954 self
.b(' if (args != NULL)')
955 self
.b(' g_value_array_free (args);')
960 if self
.deprecate_reentrant
:
961 self
.h('#ifndef %s' % self
.deprecate_reentrant
)
963 self
.h('gboolean %s (%sproxy,'
964 % (run_method_name
, self
.proxy_arg
))
965 self
.h(' gint timeout_ms,')
968 self
.d(' * %s:' % run_method_name
)
969 self
.d(' * @proxy: %s' % self
.proxy_doc
)
970 self
.d(' * @timeout_ms: Timeout in milliseconds, or -1 for default')
973 name
, info
, tp_type
, elt
= arg
974 ctype
, gtype
, marshaller
, pointer
= info
976 docs
= xml_escape(get_docstring(elt
) or '(Undocumented)')
978 if ctype
== 'guint ' and tp_type
!= '':
979 docs
+= ' (#%s)' % ('Tp' + tp_type
.replace('_', ''))
981 self
.d(' * @%s: Used to pass an \'in\' argument: %s'
985 name
, info
, tp_type
, elt
= arg
986 ctype
, gtype
, marshaller
, pointer
= info
988 self
.d(' * @%s: Used to return an \'out\' argument if %%TRUE is '
990 % (name
, xml_escape(get_docstring(elt
) or '(Undocumented)')))
992 self
.d(' * @error: If not %NULL, used to return errors if %FALSE ')
993 self
.d(' * is returned')
994 self
.d(' * @loop: If not %NULL, set before re-entering ')
995 self
.d(' * the main loop, to point to a #GMainLoop ')
996 self
.d(' * which can be used to cancel this call with ')
997 self
.d(' * g_main_loop_quit(), causing a return of ')
998 self
.d(' * %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
1000 self
.d(' * Call the method %s and run the main loop' % member
)
1001 self
.d(' * until it returns. Before calling this method, you must')
1002 self
.d(' * add a reference to any borrowed objects you need to keep,')
1003 self
.d(' * and generally ensure that everything is in a consistent')
1006 self
.d(' * %s' % xml_escape(get_docstring(method
) or '(Undocumented)'))
1008 self
.d(' * Returns: TRUE on success, FALSE and sets @error on error')
1010 deprecated
= method
.getElementsByTagName('tp:deprecated')
1014 self
.d(' * Deprecated: %s' % xml_escape(get_deprecated(d
)))
1019 self
.b('gboolean\n%s (%sproxy,'
1020 % (run_method_name
, self
.proxy_arg
))
1021 self
.b(' gint timeout_ms,')
1024 name
, info
, tp_type
, elt
= arg
1025 ctype
, gtype
, marshaller
, pointer
= info
1027 const
= pointer
and 'const ' or ''
1029 self
.h(' %s%s%s,' % (const
, ctype
, name
))
1030 self
.b(' %s%s%s,' % (const
, ctype
, name
))
1032 for arg
in out_args
:
1033 name
, info
, tp_type
, elt
= arg
1034 ctype
, gtype
, marshaller
, pointer
= info
1036 self
.h(' %s*%s,' % (ctype
, name
))
1037 self
.b(' %s*%s,' % (ctype
, name
))
1039 self
.h(' GError **error,')
1041 if self
.deprecate_reentrant
:
1042 self
.h(' GMainLoop **loop) %s;' % self
.deprecation_attribute
)
1043 self
.h('#endif /* not %s */' % self
.deprecate_reentrant
)
1045 self
.h(' GMainLoop **loop);')
1049 self
.b(' GError **error,')
1050 self
.b(' GMainLoop **loop)')
1052 self
.b(' DBusGProxy *iface;')
1053 self
.b(' GQuark interface = %s;' % self
.get_iface_quark())
1054 self
.b(' TpProxyPendingCall *pc;')
1055 self
.b(' _%s_%s_run_state_%s state = {'
1056 % (self
.prefix_lc
, iface_lc
, member_lc
))
1057 self
.b(' NULL /* loop */, error,')
1059 for arg
in out_args
:
1060 name
, info
, tp_type
, elt
= arg
1062 self
.b(' %s,' % name
)
1064 self
.b(' FALSE /* completed */, FALSE /* success */ };')
1066 self
.b(' g_return_val_if_fail (%s (proxy), FALSE);'
1067 % self
.proxy_assert
)
1069 self
.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
1070 self
.b(' iface = tp_proxy_borrow_interface_by_id')
1071 self
.b(' ((TpProxy *) proxy, interface, error);')
1072 self
.b(' G_GNUC_END_IGNORE_DEPRECATIONS')
1074 self
.b(' if (iface == NULL)')
1075 self
.b(' return FALSE;')
1077 self
.b(' state.loop = g_main_loop_new (NULL, FALSE);')
1079 self
.b(' pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
1080 self
.b(' interface, "%s", iface,' % member
)
1081 self
.b(' %s,' % reentrant_invoke
)
1082 self
.b(' NULL, &state, NULL, NULL, TRUE);')
1084 self
.b(' if (loop != NULL)')
1085 self
.b(' *loop = state.loop;')
1087 self
.b(' tp_proxy_pending_call_v0_take_pending_call (pc,')
1088 self
.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
1089 self
.b(' "%s",' % member
)
1090 self
.b(' %s,' % collect_callback
)
1092 self
.b(' tp_proxy_pending_call_v0_completed,')
1093 self
.b(' timeout_ms,')
1096 name
, info
, tp_type
, elt
= arg
1097 ctype
, gtype
, marshaller
, pointer
= info
1099 const
= pointer
and 'const ' or ''
1101 self
.b(' %s, %s,' % (gtype
, name
))
1103 self
.b(' G_TYPE_INVALID));')
1105 self
.b(' if (!state.completed)')
1106 self
.b(' g_main_loop_run (state.loop);')
1108 self
.b(' if (!state.completed)')
1109 self
.b(' tp_proxy_pending_call_cancel (pc);')
1111 self
.b(' if (loop != NULL)')
1112 self
.b(' *loop = NULL;')
1114 self
.b(' g_main_loop_unref (state.loop);')
1116 self
.b(' return state.success;')
1120 def do_signal_add(self
, signal
):
1121 marshaller_items
= []
1124 for i
in signal
.getElementsByTagName('arg'):
1125 name
= i
.getAttribute('name')
1126 type = i
.getAttribute('type')
1127 info
= type_to_gtype(type)
1128 # type, GType, STRING, is a pointer
1129 gtypes
.append(info
[1])
1131 self
.b(' dbus_g_proxy_add_signal (proxy, "%s",'
1132 % signal
.getAttribute('name'))
1133 for gtype
in gtypes
:
1134 self
.b(' %s,' % gtype
)
1135 self
.b(' G_TYPE_INVALID);')
1137 def do_interface(self
, node
):
1138 ifaces
= node
.getElementsByTagName('interface')
1139 assert len(ifaces
) == 1
1141 name
= node
.getAttribute('name').replace('/', '')
1144 self
.iface_lc
= name
.lower()
1145 self
.iface_uc
= name
.upper()
1146 self
.iface_mc
= name
.replace('_', '')
1147 self
.iface_dbus
= iface
.getAttribute('name')
1149 signals
= node
.getElementsByTagName('signal')
1150 methods
= node
.getElementsByTagName('method')
1153 self
.b('static inline void')
1154 self
.b('%s_add_signals_for_%s (DBusGProxy *proxy)'
1155 % (self
.prefix_lc
, name
.lower()))
1158 if self
.tp_proxy_api
>= (0, 7, 6):
1159 self
.b(' if (!tp_proxy_dbus_g_proxy_claim_for_signal_adding '
1163 for signal
in signals
:
1164 self
.do_signal_add(signal
)
1170 for signal
in signals
:
1171 self
.do_signal(name
, signal
)
1173 for method
in methods
:
1174 self
.do_method(name
, method
)
1176 self
.iface_dbus
= None
1180 if self
.guard
is not None:
1181 self
.h('#ifndef %s' % self
.guard
)
1182 self
.h('#define %s' % self
.guard
)
1185 self
.h('G_BEGIN_DECLS')
1188 self
.b('/* We don\'t want gtkdoc scanning this file, it\'ll get')
1189 self
.b(' * confused by seeing function definitions, so mark it as: */')
1190 self
.b('/*<private_header>*/')
1193 nodes
= self
.dom
.getElementsByTagName('node')
1194 nodes
.sort(cmp_by_name
)
1197 self
.do_interface(node
)
1199 if self
.group
is not None:
1202 self
.b(' * %s_%s_add_signals:' % (self
.prefix_lc
, self
.group
))
1203 self
.b(' * @self: the #TpProxy')
1204 self
.b(' * @quark: a quark whose string value is the interface')
1205 self
.b(' * name whose signals should be added')
1206 self
.b(' * @proxy: the D-Bus proxy to which to add the signals')
1207 self
.b(' * @unused: not used for anything')
1209 self
.b(' * Tell dbus-glib that @proxy has the signatures of all')
1210 self
.b(' * signals on the given interface, if it\'s one we')
1211 self
.b(' * support.')
1213 self
.b(' * This function should be used as a signal handler for')
1214 self
.b(' * #TpProxy::interface-added.')
1216 self
.b('static void')
1217 self
.b('%s_%s_add_signals (TpProxy *self G_GNUC_UNUSED,'
1218 % (self
.prefix_lc
, self
.group
))
1219 self
.b(' guint quark,')
1220 self
.b(' DBusGProxy *proxy,')
1221 self
.b(' gpointer unused G_GNUC_UNUSED)')
1226 iface
= node
.getElementsByTagName('interface')[0]
1227 self
.iface_dbus
= iface
.getAttribute('name')
1228 signals
= node
.getElementsByTagName('signal')
1231 name
= node
.getAttribute('name').replace('/', '').lower()
1232 self
.iface_uc
= name
.upper()
1233 self
.b(' if (quark == %s)' % self
.get_iface_quark())
1234 self
.b(' %s_add_signals_for_%s (proxy);'
1235 % (self
.prefix_lc
, name
))
1240 self
.h('G_END_DECLS')
1243 if self
.guard
is not None:
1244 self
.h('#endif /* defined (%s) */' % self
.guard
)
1247 file_set_contents(self
.basename
+ '.h', '\n'.join(self
.__header
))
1248 file_set_contents(self
.basename
+ '-body.h', '\n'.join(self
.__body
))
1249 file_set_contents(self
.basename
+ '-gtk-doc.h', '\n'.join(self
.__docs
))
1251 def types_to_gtypes(types
):
1252 return [type_to_gtype(t
)[1] for t
in types
]
1255 if __name__
== '__main__':
1256 options
, argv
= gnu_getopt(sys
.argv
[1:], '',
1257 ['group=', 'subclass=', 'subclass-assert=',
1258 'iface-quark-prefix=', 'tp-proxy-api=',
1259 'generate-reentrant=', 'deprecate-reentrant=',
1260 'deprecation-attribute=', 'guard='])
1264 for option
, value
in options
:
1265 opts
[option
] = value
1267 dom
= xml
.dom
.minidom
.parse(argv
[0])
1269 Generator(dom
, argv
[1], argv
[2], opts
)()