hindi update
[empathy-mirror.git] / tools / glib-client-gen.py
blobf8465a62b9bc26e53b6f63b49aed35a8c9740687
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 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):
40 self.dom = dom
41 self.__header = []
42 self.__body = []
43 self.__docs = []
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()
62 try:
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())
67 except KeyError:
68 pass
70 self.deprecate_reentrant = opts.get('--deprecate-reentrant', None)
71 self.deprecation_attribute = opts.get('--deprecation-attribute',
72 'G_GNUC_DEPRECATED')
74 self.guard = opts.get('--guard', None)
76 def h(self, s):
77 if isinstance(s, unicode):
78 s = s.encode('utf-8')
79 self.__header.append(s)
81 def b(self, s):
82 if isinstance(s, unicode):
83 s = s.encode('utf-8')
84 self.__body.append(s)
86 def d(self, s):
87 if isinstance(s, unicode):
88 s = s.encode('utf-8')
89 self.__docs.append(s)
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
96 else:
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()
110 arg_count = 0
111 args = []
112 out_args = []
114 for arg in signal.getElementsByTagName('arg'):
115 name = arg.getAttribute('name')
116 type = arg.getAttribute('type')
117 tp_type = arg.getAttribute('tp:type')
119 if not name:
120 name = 'arg%u' % arg_count
121 arg_count += 1
122 else:
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))
135 # Example:
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);
143 self.d('/**')
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')
149 for arg in args:
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')
162 self.d(' *')
163 self.d(' * Represents the signature of a callback for the signal %s.'
164 % member)
165 self.d(' */')
166 self.d('')
168 self.h('typedef void (*%s) (%sproxy,'
169 % (callback_name, self.proxy_cls))
171 for arg in args:
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);')
181 if args:
182 self.b('static void')
183 self.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name)
185 for arg in args:
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)')
194 self.b('{')
195 self.b(' GValueArray *args = g_value_array_new (%d);' % len(args))
196 self.b(' GValue blank = { 0 };')
197 self.b(' guint i;')
198 self.b('')
199 self.b(' g_value_init (&blank, G_TYPE_INT);')
200 self.b('')
201 self.b(' for (i = 0; i < %d; i++)' % len(args))
202 self.b(' g_value_array_append (args, &blank);')
203 self.b('')
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);'
214 % (i, name))
215 elif marshaller == 'BOXED':
216 self.b(' g_value_set_boxed (args->values + %d, %s);'
217 % (i, name))
218 elif gtype == 'G_TYPE_UCHAR':
219 self.b(' g_value_set_uchar (args->values + %d, %s);'
220 % (i, name))
221 elif gtype == 'G_TYPE_BOOLEAN':
222 self.b(' g_value_set_boolean (args->values + %d, %s);'
223 % (i, name))
224 elif gtype == 'G_TYPE_INT':
225 self.b(' g_value_set_int (args->values + %d, %s);'
226 % (i, name))
227 elif gtype == 'G_TYPE_UINT':
228 self.b(' g_value_set_uint (args->values + %d, %s);'
229 % (i, name))
230 elif gtype == 'G_TYPE_INT64':
231 self.b(' g_value_set_int (args->values + %d, %s);'
232 % (i, name))
233 elif gtype == 'G_TYPE_UINT64':
234 self.b(' g_value_set_uint64 (args->values + %d, %s);'
235 % (i, name))
236 elif gtype == 'G_TYPE_DOUBLE':
237 self.b(' g_value_set_double (args->values + %d, %s);'
238 % (i, name))
239 else:
240 assert False, ("Don't know how to put %s in a GValue"
241 % gtype)
242 self.b('')
244 self.b(' tp_proxy_signal_connection_v0_take_results (sc, args);')
245 self.b('}')
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)')
254 self.b('{')
255 self.b(' %s callback =' % callback_name)
256 self.b(' (%s) generic_callback;' % callback_name)
257 self.b('')
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)
284 else:
285 assert False, "Don't know how to get %s from a GValue" % gtype
287 self.b(' user_data,')
288 self.b(' weak_object);')
289 self.b('')
291 if len(args) > 0:
292 self.b(' g_value_array_free (args);')
293 else:
294 self.b(' if (args != NULL)')
295 self.b(' g_value_array_free (args);')
296 self.b('')
298 self.b(' g_object_unref (tpproxy);')
299 self.b('}')
301 # Example:
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.
316 self.d('/**')
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')
331 self.d(' *')
332 self.d(' * Connect a handler to the signal %s.' % member)
333 self.d(' *')
334 self.d(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
335 self.d(' *')
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.')
340 self.d(' */')
341 self.d('')
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);')
350 self.h('')
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)')
360 self.b('{')
361 self.b(' GType expected_types[%d] = {' % (len(args) + 1))
363 for arg in args:
364 name, info, tp_type, elt = arg
365 ctype, gtype, marshaller, pointer = info
367 self.b(' %s,' % gtype)
369 self.b(' G_TYPE_INVALID };')
370 self.b('')
371 self.b(' g_return_val_if_fail (%s (proxy), NULL);'
372 % self.proxy_assert)
373 self.b(' g_return_val_if_fail (callback != NULL, NULL);')
374 self.b('')
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,')
379 if args:
380 self.b(' G_CALLBACK (%s),' % collect_name)
381 else:
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);')
387 self.b('}')
388 self.b('')
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()
401 in_count = 0
402 ret_count = 0
403 in_args = []
404 out_args = []
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':
413 if not name:
414 name = 'in%u' % in_count
415 in_count += 1
416 else:
417 name = 'in_%s' % name
418 else:
419 if not name:
420 name = 'out%u' % ret_count
421 ret_count += 1
422 else:
423 name = 'out_%s' % name
425 info = type_to_gtype(type)
426 if direction != 'out':
427 in_args.append((name, info, tp_type, arg))
428 else:
429 out_args.append((name, info, tp_type, arg))
431 # Async reply callback type
433 # Example:
434 # void (*tp_cli_properties_interface_callback_for_get_properties)
435 # (TpProxy *proxy,
436 # const GPtrArray *out0,
437 # const GError *error,
438 # gpointer user_data,
439 # GObject *weak_object);
441 self.d('/**')
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')
446 for arg in out_args:
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 '
456 '%%NULL: %s'
457 % (name, docs))
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')
462 self.d(' *')
463 self.d(' * Signature of the callback called when a %s method call'
464 % member)
465 self.d(' * succeeds or fails.')
467 deprecated = method.getElementsByTagName('tp:deprecated')
468 if deprecated:
469 d = deprecated[0]
470 self.d(' *')
471 self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
473 self.d(' */')
474 self.d('')
476 callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
477 member_lc)
479 self.h('typedef void (*%s) (%sproxy,'
480 % (callback_name, self.proxy_cls))
482 for arg in out_args:
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);')
491 self.h('')
493 # Async callback implementation
495 invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
496 iface_lc,
497 member_lc)
499 collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
500 iface_lc,
501 member_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)')
509 self.b('{')
510 self.b(' GError *error = NULL;')
512 if len(out_args) > 0:
513 self.b(' GValueArray *args;')
514 self.b(' GValue blank = { 0 };')
515 self.b(' guint i;')
517 for arg in out_args:
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,
523 # dbus-glib...
524 if gtype == 'G_TYPE_VALUE':
525 self.b(' GValue *%s = g_new0 (GValue, 1);' % name)
526 else:
527 self.b(' %s%s;' % (ctype, name))
529 self.b('')
530 self.b(' dbus_g_proxy_end_call (proxy, call, &error,')
532 for arg in out_args:
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))
538 else:
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,'
545 'NULL);')
546 else:
547 self.b('')
548 self.b(' if (error != NULL)')
549 self.b(' {')
550 self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,')
551 self.b(' NULL);')
553 for arg in out_args:
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)
559 self.b(' return;')
560 self.b(' }')
561 self.b('')
562 self.b(' args = g_value_array_new (%d);' % len(out_args))
563 self.b(' g_value_init (&blank, G_TYPE_INT);')
564 self.b('')
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
572 self.b('')
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);'
578 % (i, name))
579 elif marshaller == 'BOXED':
580 self.b(' g_value_take_boxed (args->values + %d, %s);'
581 % (i, name))
582 elif gtype == 'G_TYPE_UCHAR':
583 self.b(' g_value_set_uchar (args->values + %d, %s);'
584 % (i, name))
585 elif gtype == 'G_TYPE_BOOLEAN':
586 self.b(' g_value_set_boolean (args->values + %d, %s);'
587 % (i, name))
588 elif gtype == 'G_TYPE_INT':
589 self.b(' g_value_set_int (args->values + %d, %s);'
590 % (i, name))
591 elif gtype == 'G_TYPE_UINT':
592 self.b(' g_value_set_uint (args->values + %d, %s);'
593 % (i, name))
594 elif gtype == 'G_TYPE_INT64':
595 self.b(' g_value_set_int (args->values + %d, %s);'
596 % (i, name))
597 elif gtype == 'G_TYPE_UINT64':
598 self.b(' g_value_set_uint (args->values + %d, %s);'
599 % (i, name))
600 elif gtype == 'G_TYPE_DOUBLE':
601 self.b(' g_value_set_double (args->values + %d, %s);'
602 % (i, name))
603 else:
604 assert False, ("Don't know how to put %s in a GValue"
605 % gtype)
607 self.b(' tp_proxy_pending_call_v0_take_results (user_data, '
608 'NULL, args);')
610 self.b('}')
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)')
619 self.b('{')
620 self.b(' %s callback = (%s) generic_callback;'
621 % (callback_name, callback_name))
622 self.b('')
623 self.b(' if (error != NULL)')
624 self.b(' {')
625 self.b(' callback ((%s) self,' % self.proxy_cls)
627 for arg in out_args:
628 name, info, tp_type, elt = arg
629 ctype, gtype, marshaller, pointer = info
631 if marshaller == 'BOXED' or pointer:
632 self.b(' NULL,')
633 elif gtype == 'G_TYPE_DOUBLE':
634 self.b(' 0.0,')
635 else:
636 self.b(' 0,')
638 self.b(' error, user_data, weak_object);')
639 self.b(' g_error_free (error);')
640 self.b(' return;')
641 self.b(' }')
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)
668 else:
669 assert False, "Don't know how to get %s from a GValue" % gtype
671 self.b(' error, user_data, weak_object);')
672 self.b('')
674 if len(out_args) > 0:
675 self.b(' g_value_array_free (args);')
676 else:
677 self.b(' if (args != NULL)')
678 self.b(' g_value_array_free (args);')
680 self.b('}')
681 self.b('')
683 # Async stub
685 # Example:
686 # TpProxyPendingCall *
687 # tp_cli_properties_interface_call_get_properties
688 # (gpointer proxy,
689 # gint timeout_ms,
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,')
699 self.d('/**')
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')
704 self.d(' * default')
706 for arg in in_args:
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'
716 % (name, docs))
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')
730 self.d(' *')
731 self.d(' * Start a %s method call.' % member)
732 self.d(' *')
733 self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
734 self.d(' *')
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')
741 if deprecated:
742 d = deprecated[0]
743 self.d(' *')
744 self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
746 self.d(' */')
747 self.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,')
753 for arg in in_args:
754 name, info, tp_type, elt = arg
755 ctype, gtype, marshaller, pointer = info
757 const = pointer and 'const ' or ''
759 self.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);')
766 self.h('')
768 self.b(' %s callback,' % callback_name)
769 self.b(' gpointer user_data,')
770 self.b(' GDestroyNotify destroy,')
771 self.b(' GObject *weak_object)')
772 self.b('{')
773 self.b(' GError *error = NULL;')
774 self.b(' GQuark interface = %s;' % self.get_iface_quark())
775 self.b(' DBusGProxy *iface;')
776 self.b('')
777 self.b(' g_return_val_if_fail (%s (proxy), NULL);'
778 % self.proxy_assert)
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);')
785 self.b('')
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')
791 self.b('')
792 self.b(' if (iface == NULL)')
793 self.b(' {')
794 self.b(' if (callback != NULL)')
795 self.b(' callback (proxy,')
797 for arg in out_args:
798 name, info, tp_type, elt = arg
799 ctype, gtype, marshaller, pointer = info
801 if pointer:
802 self.b(' NULL,')
803 else:
804 self.b(' 0,')
806 self.b(' error, user_data, weak_object);')
807 self.b('')
808 self.b(' if (destroy != NULL)')
809 self.b(' destroy (user_data);')
810 self.b('')
811 self.b(' g_error_free (error);')
812 self.b(' return NULL;')
813 self.b(' }')
814 self.b('')
815 self.b(' if (callback == NULL)')
816 self.b(' {')
817 self.b(' dbus_g_proxy_call_no_reply (iface, "%s",' % member)
819 for arg in in_args:
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;')
829 self.b(' }')
830 self.b(' else')
831 self.b(' {')
832 self.b(' TpProxyPendingCall *data;')
833 self.b('')
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)
843 self.b(' data,')
844 self.b(' tp_proxy_pending_call_v0_completed,')
845 self.b(' timeout_ms,')
847 for arg in in_args:
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));')
856 self.b('')
857 self.b(' return data;')
858 self.b(' }')
859 self.b('}')
860 self.b('')
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
866 self.d('')
867 self.b('')
868 self.h('')
870 def do_method_reentrant(self, method, iface_lc, member, member_lc, in_args,
871 out_args, collect_callback):
872 # Reentrant blocking calls
873 # Example:
874 # gboolean tp_cli_properties_interface_run_get_properties
875 # (gpointer proxy,
876 # gint timeout_ms,
877 # const GArray *in_properties,
878 # GPtrArray **out0,
879 # GError **error,
880 # GMainLoop **loop);
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:
884 return
886 self.b('typedef struct {')
887 self.b(' GMainLoop *loop;')
888 self.b(' GError **error;')
890 for arg in out_args:
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,
902 iface_lc,
903 member_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)')
912 self.b('{')
913 self.b(' _%s_%s_run_state_%s *state = user_data;'
914 % (self.prefix_lc, iface_lc, member_lc))
915 self.b('')
916 self.b(' state->success = (error == NULL);')
917 self.b(' state->completed = TRUE;')
918 self.b(' g_main_loop_quit (state->loop);')
919 self.b('')
920 self.b(' if (error != NULL)')
921 self.b(' {')
922 self.b(' if (state->error != NULL)')
923 self.b(' *state->error = error;')
924 self.b(' else')
925 self.b(' g_error_free (error);')
926 self.b('')
927 self.b(' return;')
928 self.b(' }')
929 self.b('')
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))
946 else:
947 assert False, "Don't know how to copy %s" % gtype
949 self.b('')
951 if len(out_args) > 0:
952 self.b(' g_value_array_free (args);')
953 else:
954 self.b(' if (args != NULL)')
955 self.b(' g_value_array_free (args);')
957 self.b('}')
958 self.b('')
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,')
967 self.d('/**')
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')
972 for arg in in_args:
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'
982 % (name, docs))
984 for arg in out_args:
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 '
989 'returned: %s'
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')
999 self.d(' *')
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')
1004 self.d(' * state.')
1005 self.d(' *')
1006 self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
1007 self.d(' *')
1008 self.d(' * Returns: TRUE on success, FALSE and sets @error on error')
1010 deprecated = method.getElementsByTagName('tp:deprecated')
1011 if deprecated:
1012 d = deprecated[0]
1013 self.d(' *')
1014 self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
1016 self.d(' */')
1017 self.d('')
1019 self.b('gboolean\n%s (%sproxy,'
1020 % (run_method_name, self.proxy_arg))
1021 self.b(' gint timeout_ms,')
1023 for arg in in_args:
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)
1044 else:
1045 self.h(' GMainLoop **loop);')
1047 self.h('')
1049 self.b(' GError **error,')
1050 self.b(' GMainLoop **loop)')
1051 self.b('{')
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 */ };')
1065 self.b('')
1066 self.b(' g_return_val_if_fail (%s (proxy), FALSE);'
1067 % self.proxy_assert)
1068 self.b('')
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')
1073 self.b('')
1074 self.b(' if (iface == NULL)')
1075 self.b(' return FALSE;')
1076 self.b('')
1077 self.b(' state.loop = g_main_loop_new (NULL, FALSE);')
1078 self.b('')
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);')
1083 self.b('')
1084 self.b(' if (loop != NULL)')
1085 self.b(' *loop = state.loop;')
1086 self.b('')
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)
1091 self.b(' pc,')
1092 self.b(' tp_proxy_pending_call_v0_completed,')
1093 self.b(' timeout_ms,')
1095 for arg in in_args:
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));')
1104 self.b('')
1105 self.b(' if (!state.completed)')
1106 self.b(' g_main_loop_run (state.loop);')
1107 self.b('')
1108 self.b(' if (!state.completed)')
1109 self.b(' tp_proxy_pending_call_cancel (pc);')
1110 self.b('')
1111 self.b(' if (loop != NULL)')
1112 self.b(' *loop = NULL;')
1113 self.b('')
1114 self.b(' g_main_loop_unref (state.loop);')
1115 self.b('')
1116 self.b(' return state.success;')
1117 self.b('}')
1118 self.b('')
1120 def do_signal_add(self, signal):
1121 marshaller_items = []
1122 gtypes = []
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
1140 iface = ifaces[0]
1141 name = node.getAttribute('name').replace('/', '')
1143 self.iface = name
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')
1152 if signals:
1153 self.b('static inline void')
1154 self.b('%s_add_signals_for_%s (DBusGProxy *proxy)'
1155 % (self.prefix_lc, name.lower()))
1156 self.b('{')
1158 if self.tp_proxy_api >= (0, 7, 6):
1159 self.b(' if (!tp_proxy_dbus_g_proxy_claim_for_signal_adding '
1160 '(proxy))')
1161 self.b(' return;')
1163 for signal in signals:
1164 self.do_signal_add(signal)
1166 self.b('}')
1167 self.b('')
1168 self.b('')
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
1178 def __call__(self):
1180 if self.guard is not None:
1181 self.h('#ifndef %s' % self.guard)
1182 self.h('#define %s' % self.guard)
1183 self.h('')
1185 self.h('G_BEGIN_DECLS')
1186 self.h('')
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>*/')
1191 self.b('')
1193 nodes = self.dom.getElementsByTagName('node')
1194 nodes.sort(cmp_by_name)
1196 for node in nodes:
1197 self.do_interface(node)
1199 if self.group is not None:
1201 self.b('/*')
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')
1208 self.b(' *')
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.')
1212 self.b(' *')
1213 self.b(' * This function should be used as a signal handler for')
1214 self.b(' * #TpProxy::interface-added.')
1215 self.b(' */')
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)')
1223 self.b('{')
1225 for node in nodes:
1226 iface = node.getElementsByTagName('interface')[0]
1227 self.iface_dbus = iface.getAttribute('name')
1228 signals = node.getElementsByTagName('signal')
1229 if not signals:
1230 continue
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))
1237 self.b('}')
1238 self.b('')
1240 self.h('G_END_DECLS')
1241 self.h('')
1243 if self.guard is not None:
1244 self.h('#endif /* defined (%s) */' % self.guard)
1245 self.h('')
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='])
1262 opts = {}
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)()