Use help:empathy to open the help
[empathy-mirror.git] / tools / glib-client-gen.py
blob6b0bdeba1b9413f4eabe8ea2950fab4c96b6bacf
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 get_docstring, xml_escape, get_deprecated
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 = []
42 self.__docs = []
44 self.prefix_lc = prefix.lower()
45 self.prefix_uc = prefix.upper()
46 self.prefix_mc = prefix.replace('_', '')
47 self.basename = basename
48 self.group = opts.get('--group', None)
49 self.iface_quark_prefix = opts.get('--iface-quark-prefix', None)
50 self.tp_proxy_api = tuple(map(int,
51 opts.get('--tp-proxy-api', '0').split('.')))
52 self.proxy_cls = opts.get('--subclass', 'TpProxy') + ' *'
53 self.proxy_arg = opts.get('--subclass', 'void') + ' *'
54 self.proxy_assert = opts.get('--subclass-assert', 'TP_IS_PROXY')
55 self.proxy_doc = ('A #%s or subclass'
56 % opts.get('--subclass', 'TpProxy'))
57 if self.proxy_arg == 'void *':
58 self.proxy_arg = 'gpointer '
59 self.generate_reentrant = ('--generate-reentrant' in opts or
60 '--deprecate-reentrant' in opts)
61 self.deprecate_reentrant = opts.get('--deprecate-reentrant', None)
62 self.deprecation_attribute = opts.get('--deprecation-attribute',
63 'G_GNUC_DEPRECATED')
65 def h(self, s):
66 if isinstance(s, unicode):
67 s = s.encode('utf-8')
68 self.__header.append(s)
70 def b(self, s):
71 if isinstance(s, unicode):
72 s = s.encode('utf-8')
73 self.__body.append(s)
75 def d(self, s):
76 if isinstance(s, unicode):
77 s = s.encode('utf-8')
78 self.__docs.append(s)
80 def get_iface_quark(self):
81 assert self.iface_dbus is not None
82 assert self.iface_uc is not None
83 if self.iface_quark_prefix is None:
84 return 'g_quark_from_static_string (\"%s\")' % self.iface_dbus
85 else:
86 return '%s_%s' % (self.iface_quark_prefix, self.iface_uc)
88 def do_signal(self, iface, signal):
89 iface_lc = iface.lower()
91 member = signal.getAttribute('name')
92 member_lc = signal.getAttribute('tp:name-for-bindings')
93 if member != member_lc.replace('_', ''):
94 raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
95 'not match' % (member, member_lc))
96 member_lc = member_lc.lower()
97 member_uc = member_lc.upper()
99 arg_count = 0
100 args = []
101 out_args = []
103 for arg in signal.getElementsByTagName('arg'):
104 name = arg.getAttribute('name')
105 type = arg.getAttribute('type')
106 tp_type = arg.getAttribute('tp:type')
108 if not name:
109 name = 'arg%u' % arg_count
110 arg_count += 1
111 else:
112 name = 'arg_%s' % name
114 info = type_to_gtype(type)
115 args.append((name, info, tp_type, arg))
117 callback_name = ('%s_%s_signal_callback_%s'
118 % (self.prefix_lc, iface_lc, member_lc))
119 collect_name = ('_%s_%s_collect_args_of_%s'
120 % (self.prefix_lc, iface_lc, member_lc))
121 invoke_name = ('_%s_%s_invoke_callback_for_%s'
122 % (self.prefix_lc, iface_lc, member_lc))
124 # Example:
126 # typedef void (*tp_cli_connection_signal_callback_new_channel)
127 # (TpConnection *proxy, const gchar *arg_object_path,
128 # const gchar *arg_channel_type, guint arg_handle_type,
129 # guint arg_handle, gboolean arg_suppress_handler,
130 # gpointer user_data, GObject *weak_object);
132 self.d('/**')
133 self.d(' * %s:' % callback_name)
134 self.d(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
135 % (self.prefix_lc, iface_lc, member_lc))
136 self.d(' * was called')
138 for arg in args:
139 name, info, tp_type, elt = arg
140 ctype, gtype, marshaller, pointer = info
142 self.d(' * @%s: %s' % (name,
143 xml_escape(get_docstring(elt) or '(Undocumented)')))
145 self.d(' * @user_data: User-supplied data')
146 self.d(' * @weak_object: User-supplied weakly referenced object')
147 self.d(' *')
148 self.d(' * Represents the signature of a callback for the signal %s.'
149 % member)
150 self.d(' */')
151 self.d('')
153 self.h('typedef void (*%s) (%sproxy,'
154 % (callback_name, self.proxy_cls))
156 for arg in args:
157 name, info, tp_type, elt = arg
158 ctype, gtype, marshaller, pointer = info
160 const = pointer and 'const ' or ''
162 self.h(' %s%s%s,' % (const, ctype, name))
164 self.h(' gpointer user_data, GObject *weak_object);')
166 if args:
167 self.b('static void')
168 self.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name)
170 for arg in args:
171 name, info, tp_type, elt = arg
172 ctype, gtype, marshaller, pointer = info
174 const = pointer and 'const ' or ''
176 self.b(' %s%s%s,' % (const, ctype, name))
178 self.b(' TpProxySignalConnection *sc)')
179 self.b('{')
180 self.b(' GValueArray *args = g_value_array_new (%d);' % len(args))
181 self.b(' GValue blank = { 0 };')
182 self.b(' guint i;')
183 self.b('')
184 self.b(' g_value_init (&blank, G_TYPE_INT);')
185 self.b('')
186 self.b(' for (i = 0; i < %d; i++)' % len(args))
187 self.b(' g_value_array_append (args, &blank);')
188 self.b('')
190 for i, arg in enumerate(args):
191 name, info, tp_type, elt = arg
192 ctype, gtype, marshaller, pointer = info
194 self.b(' g_value_unset (args->values + %d);' % i)
195 self.b(' g_value_init (args->values + %d, %s);' % (i, gtype))
197 if gtype == 'G_TYPE_STRING':
198 self.b(' g_value_set_string (args->values + %d, %s);'
199 % (i, name))
200 elif marshaller == 'BOXED':
201 self.b(' g_value_set_boxed (args->values + %d, %s);'
202 % (i, name))
203 elif gtype == 'G_TYPE_UCHAR':
204 self.b(' g_value_set_uchar (args->values + %d, %s);'
205 % (i, name))
206 elif gtype == 'G_TYPE_BOOLEAN':
207 self.b(' g_value_set_boolean (args->values + %d, %s);'
208 % (i, name))
209 elif gtype == 'G_TYPE_INT':
210 self.b(' g_value_set_int (args->values + %d, %s);'
211 % (i, name))
212 elif gtype == 'G_TYPE_UINT':
213 self.b(' g_value_set_uint (args->values + %d, %s);'
214 % (i, name))
215 elif gtype == 'G_TYPE_INT64':
216 self.b(' g_value_set_int (args->values + %d, %s);'
217 % (i, name))
218 elif gtype == 'G_TYPE_UINT64':
219 self.b(' g_value_set_uint64 (args->values + %d, %s);'
220 % (i, name))
221 elif gtype == 'G_TYPE_DOUBLE':
222 self.b(' g_value_set_double (args->values + %d, %s);'
223 % (i, name))
224 else:
225 assert False, ("Don't know how to put %s in a GValue"
226 % gtype)
227 self.b('')
229 self.b(' tp_proxy_signal_connection_v0_take_results (sc, args);')
230 self.b('}')
232 self.b('static void')
233 self.b('%s (TpProxy *tpproxy,' % invoke_name)
234 self.b(' GError *error G_GNUC_UNUSED,')
235 self.b(' GValueArray *args,')
236 self.b(' GCallback generic_callback,')
237 self.b(' gpointer user_data,')
238 self.b(' GObject *weak_object)')
239 self.b('{')
240 self.b(' %s callback =' % callback_name)
241 self.b(' (%s) generic_callback;' % callback_name)
242 self.b('')
243 self.b(' if (callback != NULL)')
244 self.b(' callback (g_object_ref (tpproxy),')
246 # FIXME: factor out into a function
247 for i, arg in enumerate(args):
248 name, info, tp_type, elt = arg
249 ctype, gtype, marshaller, pointer = info
251 if marshaller == 'BOXED':
252 self.b(' g_value_get_boxed (args->values + %d),' % i)
253 elif gtype == 'G_TYPE_STRING':
254 self.b(' g_value_get_string (args->values + %d),' % i)
255 elif gtype == 'G_TYPE_UCHAR':
256 self.b(' g_value_get_uchar (args->values + %d),' % i)
257 elif gtype == 'G_TYPE_BOOLEAN':
258 self.b(' g_value_get_boolean (args->values + %d),' % i)
259 elif gtype == 'G_TYPE_UINT':
260 self.b(' g_value_get_uint (args->values + %d),' % i)
261 elif gtype == 'G_TYPE_INT':
262 self.b(' g_value_get_int (args->values + %d),' % i)
263 elif gtype == 'G_TYPE_UINT64':
264 self.b(' g_value_get_uint64 (args->values + %d),' % i)
265 elif gtype == 'G_TYPE_INT64':
266 self.b(' g_value_get_int64 (args->values + %d),' % i)
267 elif gtype == 'G_TYPE_DOUBLE':
268 self.b(' g_value_get_double (args->values + %d),' % i)
269 else:
270 assert False, "Don't know how to get %s from a GValue" % gtype
272 self.b(' user_data,')
273 self.b(' weak_object);')
274 self.b('')
276 if len(args) > 0:
277 self.b(' g_value_array_free (args);')
278 else:
279 self.b(' if (args != NULL)')
280 self.b(' g_value_array_free (args);')
281 self.b('')
283 self.b(' g_object_unref (tpproxy);')
284 self.b('}')
286 # Example:
288 # TpProxySignalConnection *
289 # tp_cli_connection_connect_to_new_channel
290 # (TpConnection *proxy,
291 # tp_cli_connection_signal_callback_new_channel callback,
292 # gpointer user_data,
293 # GDestroyNotify destroy);
295 # destroy is invoked when the signal becomes disconnected. This
296 # is either because the signal has been disconnected explicitly
297 # by the user, because the TpProxy has become invalid and
298 # emitted the 'invalidated' signal, or because the weakly referenced
299 # object has gone away.
301 self.d('/**')
302 self.d(' * %s_%s_connect_to_%s:'
303 % (self.prefix_lc, iface_lc, member_lc))
304 self.d(' * @proxy: %s' % self.proxy_doc)
305 self.d(' * @callback: Callback to be called when the signal is')
306 self.d(' * received')
307 self.d(' * @user_data: User-supplied data for the callback')
308 self.d(' * @destroy: Destructor for the user-supplied data, which')
309 self.d(' * will be called when this signal is disconnected, or')
310 self.d(' * before this function returns %NULL')
311 self.d(' * @weak_object: A #GObject which will be weakly referenced; ')
312 self.d(' * if it is destroyed, this callback will automatically be')
313 self.d(' * disconnected')
314 self.d(' * @error: If not %NULL, used to raise an error if %NULL is')
315 self.d(' * returned')
316 self.d(' *')
317 self.d(' * Connect a handler to the signal %s.' % member)
318 self.d(' *')
319 self.d(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
320 self.d(' *')
321 self.d(' * Returns: a #TpProxySignalConnection containing all of the')
322 self.d(' * above, which can be used to disconnect the signal; or')
323 self.d(' * %NULL if the proxy does not have the desired interface')
324 self.d(' * or has become invalid.')
325 self.d(' */')
326 self.d('')
328 self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,'
329 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
330 self.h(' %s callback,' % callback_name)
331 self.h(' gpointer user_data,')
332 self.h(' GDestroyNotify destroy,')
333 self.h(' GObject *weak_object,')
334 self.h(' GError **error);')
335 self.h('')
337 self.b('TpProxySignalConnection *')
338 self.b('%s_%s_connect_to_%s (%sproxy,'
339 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
340 self.b(' %s callback,' % callback_name)
341 self.b(' gpointer user_data,')
342 self.b(' GDestroyNotify destroy,')
343 self.b(' GObject *weak_object,')
344 self.b(' GError **error)')
345 self.b('{')
346 self.b(' GType expected_types[%d] = {' % (len(args) + 1))
348 for arg in args:
349 name, info, tp_type, elt = arg
350 ctype, gtype, marshaller, pointer = info
352 self.b(' %s,' % gtype)
354 self.b(' G_TYPE_INVALID };')
355 self.b('')
356 self.b(' g_return_val_if_fail (%s (proxy), NULL);'
357 % self.proxy_assert)
358 self.b(' g_return_val_if_fail (callback != NULL, NULL);')
359 self.b('')
360 self.b(' return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,')
361 self.b(' %s, \"%s\",' % (self.get_iface_quark(), member))
362 self.b(' expected_types,')
364 if args:
365 self.b(' G_CALLBACK (%s),' % collect_name)
366 else:
367 self.b(' NULL, /* no args => no collector function */')
369 self.b(' %s,' % invoke_name)
370 self.b(' G_CALLBACK (callback), user_data, destroy,')
371 self.b(' weak_object, error);')
372 self.b('}')
373 self.b('')
375 def do_method(self, iface, method):
376 iface_lc = iface.lower()
378 member = method.getAttribute('name')
379 member_lc = method.getAttribute('tp:name-for-bindings')
380 if member != member_lc.replace('_', ''):
381 raise AssertionError('Method %s tp:name-for-bindings (%s) does '
382 'not match' % (member, member_lc))
383 member_lc = member_lc.lower()
384 member_uc = member_lc.upper()
386 in_count = 0
387 ret_count = 0
388 in_args = []
389 out_args = []
391 for arg in method.getElementsByTagName('arg'):
392 name = arg.getAttribute('name')
393 direction = arg.getAttribute('direction')
394 type = arg.getAttribute('type')
395 tp_type = arg.getAttribute('tp:type')
397 if direction != 'out':
398 if not name:
399 name = 'in%u' % in_count
400 in_count += 1
401 else:
402 name = 'in_%s' % name
403 else:
404 if not name:
405 name = 'out%u' % ret_count
406 ret_count += 1
407 else:
408 name = 'out_%s' % name
410 info = type_to_gtype(type)
411 if direction != 'out':
412 in_args.append((name, info, tp_type, arg))
413 else:
414 out_args.append((name, info, tp_type, arg))
416 # Async reply callback type
418 # Example:
419 # void (*tp_cli_properties_interface_callback_for_get_properties)
420 # (TpProxy *proxy,
421 # const GPtrArray *out0,
422 # const GError *error,
423 # gpointer user_data,
424 # GObject *weak_object);
426 self.d('/**')
427 self.d(' * %s_%s_callback_for_%s:'
428 % (self.prefix_lc, iface_lc, member_lc))
429 self.d(' * @proxy: the proxy on which the call was made')
431 for arg in out_args:
432 name, info, tp_type, elt = arg
433 ctype, gtype, marshaller, pointer = info
435 self.d(' * @%s: Used to return an \'out\' argument if @error is '
436 '%%NULL: %s'
437 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
439 self.d(' * @error: %NULL on success, or an error on failure')
440 self.d(' * @user_data: user-supplied data')
441 self.d(' * @weak_object: user-supplied object')
442 self.d(' *')
443 self.d(' * Signature of the callback called when a %s method call'
444 % member)
445 self.d(' * succeeds or fails.')
447 deprecated = method.getElementsByTagName('tp:deprecated')
448 if deprecated:
449 d = deprecated[0]
450 self.d(' *')
451 self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
453 self.d(' */')
454 self.d('')
456 callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
457 member_lc)
459 self.h('typedef void (*%s) (%sproxy,'
460 % (callback_name, self.proxy_cls))
462 for arg in out_args:
463 name, info, tp_type, elt = arg
464 ctype, gtype, marshaller, pointer = info
465 const = pointer and 'const ' or ''
467 self.h(' %s%s%s,' % (const, ctype, name))
469 self.h(' const GError *error, gpointer user_data,')
470 self.h(' GObject *weak_object);')
471 self.h('')
473 # Async callback implementation
475 invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
476 iface_lc,
477 member_lc)
479 collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
480 iface_lc,
481 member_lc)
483 # The callback called by dbus-glib; this ends the call and collects
484 # the results into a GValueArray.
485 self.b('static void')
486 self.b('%s (DBusGProxy *proxy,' % collect_callback)
487 self.b(' DBusGProxyCall *call,')
488 self.b(' gpointer user_data)')
489 self.b('{')
490 self.b(' GError *error = NULL;')
492 if len(out_args) > 0:
493 self.b(' GValueArray *args;')
494 self.b(' GValue blank = { 0 };')
495 self.b(' guint i;')
497 for arg in out_args:
498 name, info, tp_type, elt = arg
499 ctype, gtype, marshaller, pointer = info
501 # "We handle variants specially; the caller is expected to
502 # have already allocated storage for them". Thanks,
503 # dbus-glib...
504 if gtype == 'G_TYPE_VALUE':
505 self.b(' GValue *%s = g_new0 (GValue, 1);' % name)
506 else:
507 self.b(' %s%s;' % (ctype, name))
509 self.b('')
510 self.b(' dbus_g_proxy_end_call (proxy, call, &error,')
512 for arg in out_args:
513 name, info, tp_type, elt = arg
514 ctype, gtype, marshaller, pointer = info
516 if gtype == 'G_TYPE_VALUE':
517 self.b(' %s, %s,' % (gtype, name))
518 else:
519 self.b(' %s, &%s,' % (gtype, name))
521 self.b(' G_TYPE_INVALID);')
523 if len(out_args) == 0:
524 self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,'
525 'NULL);')
526 else:
527 self.b('')
528 self.b(' if (error != NULL)')
529 self.b(' {')
530 self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,')
531 self.b(' NULL);')
533 for arg in out_args:
534 name, info, tp_type, elt = arg
535 ctype, gtype, marshaller, pointer = info
536 if gtype == 'G_TYPE_VALUE':
537 self.b(' g_free (%s);' % name)
539 self.b(' return;')
540 self.b(' }')
541 self.b('')
542 self.b(' args = g_value_array_new (%d);' % len(out_args))
543 self.b(' g_value_init (&blank, G_TYPE_INT);')
544 self.b('')
545 self.b(' for (i = 0; i < %d; i++)' % len(out_args))
546 self.b(' g_value_array_append (args, &blank);')
548 for i, arg in enumerate(out_args):
549 name, info, tp_type, elt = arg
550 ctype, gtype, marshaller, pointer = info
552 self.b('')
553 self.b(' g_value_unset (args->values + %d);' % i)
554 self.b(' g_value_init (args->values + %d, %s);' % (i, gtype))
556 if gtype == 'G_TYPE_STRING':
557 self.b(' g_value_take_string (args->values + %d, %s);'
558 % (i, name))
559 elif marshaller == 'BOXED':
560 self.b(' g_value_take_boxed (args->values + %d, %s);'
561 % (i, name))
562 elif gtype == 'G_TYPE_UCHAR':
563 self.b(' g_value_set_uchar (args->values + %d, %s);'
564 % (i, name))
565 elif gtype == 'G_TYPE_BOOLEAN':
566 self.b(' g_value_set_boolean (args->values + %d, %s);'
567 % (i, name))
568 elif gtype == 'G_TYPE_INT':
569 self.b(' g_value_set_int (args->values + %d, %s);'
570 % (i, name))
571 elif gtype == 'G_TYPE_UINT':
572 self.b(' g_value_set_uint (args->values + %d, %s);'
573 % (i, name))
574 elif gtype == 'G_TYPE_INT64':
575 self.b(' g_value_set_int (args->values + %d, %s);'
576 % (i, name))
577 elif gtype == 'G_TYPE_UINT64':
578 self.b(' g_value_set_uint (args->values + %d, %s);'
579 % (i, name))
580 elif gtype == 'G_TYPE_DOUBLE':
581 self.b(' g_value_set_double (args->values + %d, %s);'
582 % (i, name))
583 else:
584 assert False, ("Don't know how to put %s in a GValue"
585 % gtype)
587 self.b(' tp_proxy_pending_call_v0_take_results (user_data, '
588 'NULL, args);')
590 self.b('}')
592 self.b('static void')
593 self.b('%s (TpProxy *self,' % invoke_callback)
594 self.b(' GError *error,')
595 self.b(' GValueArray *args,')
596 self.b(' GCallback generic_callback,')
597 self.b(' gpointer user_data,')
598 self.b(' GObject *weak_object)')
599 self.b('{')
600 self.b(' %s callback = (%s) generic_callback;'
601 % (callback_name, callback_name))
602 self.b('')
603 self.b(' if (error != NULL)')
604 self.b(' {')
605 self.b(' callback ((%s) self,' % self.proxy_cls)
607 for arg in out_args:
608 name, info, tp_type, elt = arg
609 ctype, gtype, marshaller, pointer = info
611 if marshaller == 'BOXED' or pointer:
612 self.b(' NULL,')
613 elif gtype == 'G_TYPE_DOUBLE':
614 self.b(' 0.0,')
615 else:
616 self.b(' 0,')
618 self.b(' error, user_data, weak_object);')
619 self.b(' g_error_free (error);')
620 self.b(' return;')
621 self.b(' }')
623 self.b(' callback ((%s) self,' % self.proxy_cls)
625 # FIXME: factor out into a function
626 for i, arg in enumerate(out_args):
627 name, info, tp_type, elt = arg
628 ctype, gtype, marshaller, pointer = info
630 if marshaller == 'BOXED':
631 self.b(' g_value_get_boxed (args->values + %d),' % i)
632 elif gtype == 'G_TYPE_STRING':
633 self.b(' g_value_get_string (args->values + %d),' % i)
634 elif gtype == 'G_TYPE_UCHAR':
635 self.b(' g_value_get_uchar (args->values + %d),' % i)
636 elif gtype == 'G_TYPE_BOOLEAN':
637 self.b(' g_value_get_boolean (args->values + %d),' % i)
638 elif gtype == 'G_TYPE_UINT':
639 self.b(' g_value_get_uint (args->values + %d),' % i)
640 elif gtype == 'G_TYPE_INT':
641 self.b(' g_value_get_int (args->values + %d),' % i)
642 elif gtype == 'G_TYPE_UINT64':
643 self.b(' g_value_get_uint64 (args->values + %d),' % i)
644 elif gtype == 'G_TYPE_INT64':
645 self.b(' g_value_get_int64 (args->values + %d),' % i)
646 elif gtype == 'G_TYPE_DOUBLE':
647 self.b(' g_value_get_double (args->values + %d),' % i)
648 else:
649 assert False, "Don't know how to get %s from a GValue" % gtype
651 self.b(' error, user_data, weak_object);')
652 self.b('')
654 if len(out_args) > 0:
655 self.b(' g_value_array_free (args);')
656 else:
657 self.b(' if (args != NULL)')
658 self.b(' g_value_array_free (args);')
660 self.b('}')
661 self.b('')
663 # Async stub
665 # Example:
666 # TpProxyPendingCall *
667 # tp_cli_properties_interface_call_get_properties
668 # (gpointer proxy,
669 # gint timeout_ms,
670 # const GArray *in_properties,
671 # tp_cli_properties_interface_callback_for_get_properties callback,
672 # gpointer user_data,
673 # GDestroyNotify *destructor);
675 self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
676 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
677 self.h(' gint timeout_ms,')
679 self.d('/**')
680 self.d(' * %s_%s_call_%s:'
681 % (self.prefix_lc, iface_lc, member_lc))
682 self.d(' * @proxy: the #TpProxy')
683 self.d(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
684 self.d(' * default')
686 for arg in in_args:
687 name, info, tp_type, elt = arg
688 ctype, gtype, marshaller, pointer = info
690 self.d(' * @%s: Used to pass an \'in\' argument: %s'
691 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
693 self.d(' * @callback: called when the method call succeeds or fails;')
694 self.d(' * may be %NULL to make a "fire and forget" call with no ')
695 self.d(' * reply tracking')
696 self.d(' * @user_data: user-supplied data passed to the callback;')
697 self.d(' * must be %NULL if @callback is %NULL')
698 self.d(' * @destroy: called with the user_data as argument, after the')
699 self.d(' * call has succeeded, failed or been cancelled;')
700 self.d(' * must be %NULL if @callback is %NULL')
701 self.d(' * @weak_object: If not %NULL, a #GObject which will be ')
702 self.d(' * weakly referenced; if it is destroyed, this call ')
703 self.d(' * will automatically be cancelled. Must be %NULL if ')
704 self.d(' * @callback is %NULL')
705 self.d(' *')
706 self.d(' * Start a %s method call.' % member)
707 self.d(' *')
708 self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
709 self.d(' *')
710 self.d(' * Returns: a #TpProxyPendingCall representing the call in')
711 self.d(' * progress. It is borrowed from the object, and will become')
712 self.d(' * invalid when the callback is called, the call is')
713 self.d(' * cancelled or the #TpProxy becomes invalid.')
715 deprecated = method.getElementsByTagName('tp:deprecated')
716 if deprecated:
717 d = deprecated[0]
718 self.d(' *')
719 self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
721 self.d(' */')
722 self.d('')
724 self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
725 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
726 self.b(' gint timeout_ms,')
728 for arg in in_args:
729 name, info, tp_type, elt = arg
730 ctype, gtype, marshaller, pointer = info
732 const = pointer and 'const ' or ''
734 self.h(' %s%s%s,' % (const, ctype, name))
735 self.b(' %s%s%s,' % (const, ctype, name))
737 self.h(' %s callback,' % callback_name)
738 self.h(' gpointer user_data,')
739 self.h(' GDestroyNotify destroy,')
740 self.h(' GObject *weak_object);')
741 self.h('')
743 self.b(' %s callback,' % callback_name)
744 self.b(' gpointer user_data,')
745 self.b(' GDestroyNotify destroy,')
746 self.b(' GObject *weak_object)')
747 self.b('{')
748 self.b(' GError *error = NULL;')
749 self.b(' GQuark interface = %s;' % self.get_iface_quark())
750 self.b(' DBusGProxy *iface;')
751 self.b('')
752 self.b(' g_return_val_if_fail (%s (proxy), NULL);'
753 % self.proxy_assert)
754 self.b(' g_return_val_if_fail (callback != NULL || '
755 'user_data == NULL, NULL);')
756 self.b(' g_return_val_if_fail (callback != NULL || '
757 'destroy == NULL, NULL);')
758 self.b(' g_return_val_if_fail (callback != NULL || '
759 'weak_object == NULL, NULL);')
760 self.b('')
761 self.b(' iface = tp_proxy_borrow_interface_by_id (')
762 self.b(' (TpProxy *) proxy,')
763 self.b(' interface, &error);')
764 self.b('')
765 self.b(' if (iface == NULL)')
766 self.b(' {')
767 self.b(' if (callback != NULL)')
768 self.b(' callback (proxy,')
770 for arg in out_args:
771 name, info, tp_type, elt = arg
772 ctype, gtype, marshaller, pointer = info
774 if pointer:
775 self.b(' NULL,')
776 else:
777 self.b(' 0,')
779 self.b(' error, user_data, weak_object);')
780 self.b('')
781 self.b(' if (destroy != NULL)')
782 self.b(' destroy (user_data);')
783 self.b('')
784 self.b(' g_error_free (error);')
785 self.b(' return NULL;')
786 self.b(' }')
787 self.b('')
788 self.b(' if (callback == NULL)')
789 self.b(' {')
790 self.b(' dbus_g_proxy_call_no_reply (iface, "%s",' % member)
792 for arg in in_args:
793 name, info, tp_type, elt = arg
794 ctype, gtype, marshaller, pointer = info
796 const = pointer and 'const ' or ''
798 self.b(' %s, %s,' % (gtype, name))
800 self.b(' G_TYPE_INVALID);')
801 self.b(' return NULL;')
802 self.b(' }')
803 self.b(' else')
804 self.b(' {')
805 self.b(' TpProxyPendingCall *data;')
806 self.b('')
807 self.b(' data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
808 self.b(' interface, "%s", iface,' % member)
809 self.b(' %s,' % invoke_callback)
810 self.b(' G_CALLBACK (callback), user_data, destroy,')
811 self.b(' weak_object, FALSE);')
812 self.b(' tp_proxy_pending_call_v0_take_pending_call (data,')
813 self.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
814 self.b(' "%s",' % member)
815 self.b(' %s,' % collect_callback)
816 self.b(' data,')
817 self.b(' tp_proxy_pending_call_v0_completed,')
818 self.b(' timeout_ms,')
820 for arg in in_args:
821 name, info, tp_type, elt = arg
822 ctype, gtype, marshaller, pointer = info
824 const = pointer and 'const ' or ''
826 self.b(' %s, %s,' % (gtype, name))
828 self.b(' G_TYPE_INVALID));')
829 self.b('')
830 self.b(' return data;')
831 self.b(' }')
832 self.b('}')
833 self.b('')
835 if self.generate_reentrant:
836 self.do_method_reentrant(method, iface_lc, member, member_lc,
837 in_args, out_args, collect_callback)
839 # leave a gap for the end of the method
840 self.d('')
841 self.b('')
842 self.h('')
844 def do_method_reentrant(self, method, iface_lc, member, member_lc, in_args,
845 out_args, collect_callback):
846 # Reentrant blocking calls
847 # Example:
848 # gboolean tp_cli_properties_interface_run_get_properties
849 # (gpointer proxy,
850 # gint timeout_ms,
851 # const GArray *in_properties,
852 # GPtrArray **out0,
853 # GError **error,
854 # GMainLoop **loop);
856 self.b('typedef struct {')
857 self.b(' GMainLoop *loop;')
858 self.b(' GError **error;')
860 for arg in out_args:
861 name, info, tp_type, elt = arg
862 ctype, gtype, marshaller, pointer = info
864 self.b(' %s*%s;' % (ctype, name))
866 self.b(' unsigned success:1;')
867 self.b(' unsigned completed:1;')
868 self.b('} _%s_%s_run_state_%s;'
869 % (self.prefix_lc, iface_lc, member_lc))
871 reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
872 iface_lc,
873 member_lc)
875 self.b('static void')
876 self.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke)
877 self.b(' GError *error,')
878 self.b(' GValueArray *args,')
879 self.b(' GCallback unused G_GNUC_UNUSED,')
880 self.b(' gpointer user_data G_GNUC_UNUSED,')
881 self.b(' GObject *unused2 G_GNUC_UNUSED)')
882 self.b('{')
883 self.b(' _%s_%s_run_state_%s *state = user_data;'
884 % (self.prefix_lc, iface_lc, member_lc))
885 self.b('')
886 self.b(' state->success = (error == NULL);')
887 self.b(' state->completed = TRUE;')
888 self.b(' g_main_loop_quit (state->loop);')
889 self.b('')
890 self.b(' if (error != NULL)')
891 self.b(' {')
892 self.b(' if (state->error != NULL)')
893 self.b(' *state->error = error;')
894 self.b(' else')
895 self.b(' g_error_free (error);')
896 self.b('')
897 self.b(' return;')
898 self.b(' }')
899 self.b('')
901 for i, arg in enumerate(out_args):
902 name, info, tp_type, elt = arg
903 ctype, gtype, marshaller, pointer = info
905 self.b(' if (state->%s != NULL)' % name)
906 if marshaller == 'BOXED':
907 self.b(' *state->%s = g_value_dup_boxed ('
908 'args->values + %d);' % (name, i))
909 elif marshaller == 'STRING':
910 self.b(' *state->%s = g_value_dup_string '
911 '(args->values + %d);' % (name, i))
912 elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
913 'INT64', 'UINT64', 'DOUBLE'):
914 self.b(' *state->%s = g_value_get_%s (args->values + %d);'
915 % (name, marshaller.lower(), i))
916 else:
917 assert False, "Don't know how to copy %s" % gtype
919 self.b('')
921 if len(out_args) > 0:
922 self.b(' g_value_array_free (args);')
923 else:
924 self.b(' if (args != NULL)')
925 self.b(' g_value_array_free (args);')
927 self.b('}')
928 self.b('')
930 if self.deprecate_reentrant:
931 self.h('#ifndef %s' % self.deprecate_reentrant)
933 self.h('gboolean %s_%s_run_%s (%sproxy,'
934 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
935 self.h(' gint timeout_ms,')
937 self.d('/**')
938 self.d(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc))
939 self.d(' * @proxy: %s' % self.proxy_doc)
940 self.d(' * @timeout_ms: Timeout in milliseconds, or -1 for default')
942 for arg in in_args:
943 name, info, tp_type, elt = arg
944 ctype, gtype, marshaller, pointer = info
946 self.d(' * @%s: Used to pass an \'in\' argument: %s'
947 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
949 for arg in out_args:
950 name, info, tp_type, elt = arg
951 ctype, gtype, marshaller, pointer = info
953 self.d(' * @%s: Used to return an \'out\' argument if %%TRUE is '
954 'returned: %s'
955 % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
957 self.d(' * @error: If not %NULL, used to return errors if %FALSE ')
958 self.d(' * is returned')
959 self.d(' * @loop: If not %NULL, set before re-entering ')
960 self.d(' * the main loop, to point to a #GMainLoop ')
961 self.d(' * which can be used to cancel this call with ')
962 self.d(' * g_main_loop_quit(), causing a return of ')
963 self.d(' * %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
964 self.d(' *')
965 self.d(' * Call the method %s and run the main loop' % member)
966 self.d(' * until it returns. Before calling this method, you must')
967 self.d(' * add a reference to any borrowed objects you need to keep,')
968 self.d(' * and generally ensure that everything is in a consistent')
969 self.d(' * state.')
970 self.d(' *')
971 self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
972 self.d(' *')
973 self.d(' * Returns: TRUE on success, FALSE and sets @error on error')
975 deprecated = method.getElementsByTagName('tp:deprecated')
976 if deprecated:
977 d = deprecated[0]
978 self.d(' *')
979 self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
981 self.d(' */')
982 self.d('')
984 self.b('gboolean\n%s_%s_run_%s (%sproxy,'
985 % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
986 self.b(' gint timeout_ms,')
988 for arg in in_args:
989 name, info, tp_type, elt = arg
990 ctype, gtype, marshaller, pointer = info
992 const = pointer and 'const ' or ''
994 self.h(' %s%s%s,' % (const, ctype, name))
995 self.b(' %s%s%s,' % (const, ctype, name))
997 for arg in out_args:
998 name, info, tp_type, elt = arg
999 ctype, gtype, marshaller, pointer = info
1001 self.h(' %s*%s,' % (ctype, name))
1002 self.b(' %s*%s,' % (ctype, name))
1004 self.h(' GError **error,')
1006 if self.deprecate_reentrant:
1007 self.h(' GMainLoop **loop) %s;' % self.deprecation_attribute)
1008 self.h('#endif /* not %s */' % self.deprecate_reentrant)
1009 else:
1010 self.h(' GMainLoop **loop);')
1012 self.h('')
1014 self.b(' GError **error,')
1015 self.b(' GMainLoop **loop)')
1016 self.b('{')
1017 self.b(' DBusGProxy *iface;')
1018 self.b(' GQuark interface = %s;' % self.get_iface_quark())
1019 self.b(' TpProxyPendingCall *pc;')
1020 self.b(' _%s_%s_run_state_%s state = {'
1021 % (self.prefix_lc, iface_lc, member_lc))
1022 self.b(' NULL /* loop */, error,')
1024 for arg in out_args:
1025 name, info, tp_type, elt = arg
1027 self.b(' %s,' % name)
1029 self.b(' FALSE /* completed */, FALSE /* success */ };')
1030 self.b('')
1031 self.b(' g_return_val_if_fail (%s (proxy), FALSE);'
1032 % self.proxy_assert)
1033 self.b('')
1034 self.b(' iface = tp_proxy_borrow_interface_by_id')
1035 self.b(' ((TpProxy *) proxy, interface, error);')
1036 self.b('')
1037 self.b(' if (iface == NULL)')
1038 self.b(' return FALSE;')
1039 self.b('')
1040 self.b(' state.loop = g_main_loop_new (NULL, FALSE);')
1041 self.b('')
1042 self.b(' pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
1043 self.b(' interface, "%s", iface,' % member)
1044 self.b(' %s,' % reentrant_invoke)
1045 self.b(' NULL, &state, NULL, NULL, TRUE);')
1046 self.b('')
1047 self.b(' if (loop != NULL)')
1048 self.b(' *loop = state.loop;')
1049 self.b('')
1050 self.b(' tp_proxy_pending_call_v0_take_pending_call (pc,')
1051 self.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
1052 self.b(' "%s",' % member)
1053 self.b(' %s,' % collect_callback)
1054 self.b(' pc,')
1055 self.b(' tp_proxy_pending_call_v0_completed,')
1056 self.b(' timeout_ms,')
1058 for arg in in_args:
1059 name, info, tp_type, elt = arg
1060 ctype, gtype, marshaller, pointer = info
1062 const = pointer and 'const ' or ''
1064 self.b(' %s, %s,' % (gtype, name))
1066 self.b(' G_TYPE_INVALID));')
1067 self.b('')
1068 self.b(' if (!state.completed)')
1069 self.b(' g_main_loop_run (state.loop);')
1070 self.b('')
1071 self.b(' if (!state.completed)')
1072 self.b(' tp_proxy_pending_call_cancel (pc);')
1073 self.b('')
1074 self.b(' if (loop != NULL)')
1075 self.b(' *loop = NULL;')
1076 self.b('')
1077 self.b(' g_main_loop_unref (state.loop);')
1078 self.b('')
1079 self.b(' return state.success;')
1080 self.b('}')
1081 self.b('')
1083 def do_signal_add(self, signal):
1084 marshaller_items = []
1085 gtypes = []
1087 for i in signal.getElementsByTagName('arg'):
1088 name = i.getAttribute('name')
1089 type = i.getAttribute('type')
1090 info = type_to_gtype(type)
1091 # type, GType, STRING, is a pointer
1092 gtypes.append(info[1])
1094 self.b(' dbus_g_proxy_add_signal (proxy, "%s",'
1095 % signal.getAttribute('name'))
1096 for gtype in gtypes:
1097 self.b(' %s,' % gtype)
1098 self.b(' G_TYPE_INVALID);')
1100 def do_interface(self, node):
1101 ifaces = node.getElementsByTagName('interface')
1102 assert len(ifaces) == 1
1103 iface = ifaces[0]
1104 name = node.getAttribute('name').replace('/', '')
1106 self.iface = name
1107 self.iface_lc = name.lower()
1108 self.iface_uc = name.upper()
1109 self.iface_mc = name.replace('_', '')
1110 self.iface_dbus = iface.getAttribute('name')
1112 signals = node.getElementsByTagName('signal')
1113 methods = node.getElementsByTagName('method')
1115 if signals:
1116 self.b('static inline void')
1117 self.b('%s_add_signals_for_%s (DBusGProxy *proxy)'
1118 % (self.prefix_lc, name.lower()))
1119 self.b('{')
1121 if self.tp_proxy_api >= (0, 7, 6):
1122 self.b(' if (!tp_proxy_dbus_g_proxy_claim_for_signal_adding '
1123 '(proxy))')
1124 self.b(' return;')
1126 for signal in signals:
1127 self.do_signal_add(signal)
1129 self.b('}')
1130 self.b('')
1131 self.b('')
1133 for signal in signals:
1134 self.do_signal(name, signal)
1136 for method in methods:
1137 self.do_method(name, method)
1139 self.iface_dbus = None
1141 def __call__(self):
1143 self.h('G_BEGIN_DECLS')
1144 self.h('')
1146 self.b('/* We don\'t want gtkdoc scanning this file, it\'ll get')
1147 self.b(' * confused by seeing function definitions, so mark it as: */')
1148 self.b('/*<private_header>*/')
1149 self.b('')
1151 nodes = self.dom.getElementsByTagName('node')
1152 nodes.sort(cmp_by_name)
1154 for node in nodes:
1155 self.do_interface(node)
1157 if self.group is not None:
1159 self.b('/*')
1160 self.b(' * %s_%s_add_signals:' % (self.prefix_lc, self.group))
1161 self.b(' * @self: the #TpProxy')
1162 self.b(' * @quark: a quark whose string value is the interface')
1163 self.b(' * name whose signals should be added')
1164 self.b(' * @proxy: the D-Bus proxy to which to add the signals')
1165 self.b(' * @unused: not used for anything')
1166 self.b(' *')
1167 self.b(' * Tell dbus-glib that @proxy has the signatures of all')
1168 self.b(' * signals on the given interface, if it\'s one we')
1169 self.b(' * support.')
1170 self.b(' *')
1171 self.b(' * This function should be used as a signal handler for')
1172 self.b(' * #TpProxy::interface-added.')
1173 self.b(' */')
1174 self.b('static void')
1175 self.b('%s_%s_add_signals (TpProxy *self G_GNUC_UNUSED,'
1176 % (self.prefix_lc, self.group))
1177 self.b(' guint quark,')
1178 self.b(' DBusGProxy *proxy,')
1179 self.b(' gpointer unused G_GNUC_UNUSED)')
1181 self.b('{')
1183 for node in nodes:
1184 iface = node.getElementsByTagName('interface')[0]
1185 self.iface_dbus = iface.getAttribute('name')
1186 signals = node.getElementsByTagName('signal')
1187 if not signals:
1188 continue
1189 name = node.getAttribute('name').replace('/', '').lower()
1190 self.iface_uc = name.upper()
1191 self.b(' if (quark == %s)' % self.get_iface_quark())
1192 self.b(' %s_add_signals_for_%s (proxy);'
1193 % (self.prefix_lc, name))
1195 self.b('}')
1196 self.b('')
1198 self.h('G_END_DECLS')
1199 self.h('')
1201 open(self.basename + '.h', 'w').write('\n'.join(self.__header))
1202 open(self.basename + '-body.h', 'w').write('\n'.join(self.__body))
1203 open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs))
1206 def types_to_gtypes(types):
1207 return [type_to_gtype(t)[1] for t in types]
1210 if __name__ == '__main__':
1211 options, argv = gnu_getopt(sys.argv[1:], '',
1212 ['group=', 'subclass=', 'subclass-assert=',
1213 'iface-quark-prefix=', 'tp-proxy-api=',
1214 'generate-reentrant', 'deprecate-reentrant=',
1215 'deprecation-attribute='])
1217 opts = {}
1219 for option, value in options:
1220 opts[option] = value
1222 dom = xml.dom.minidom.parse(argv[0])
1224 Generator(dom, argv[1], argv[2], opts)()