build: remove -enumtypes rules
[empathy-mirror.git] / tools / glib-ginterface-gen.py
blob9dfdcc75d7936e4f2d46e538fe1e257cc9f98c28
1 #!/usr/bin/python
3 # glib-ginterface-gen.py: service-side interface generator
5 # Generate dbus-glib 0.x service GInterfaces 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, 2007 Collabora Limited
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
29 from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
30 NS_TP, dbus_gutils_wincaps_to_uscore, \
31 signal_to_marshal_name, method_to_glue_marshal_name
34 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
36 class Generator(object):
38 def __init__(self, dom, prefix, basename, signal_marshal_prefix,
39 headers, end_headers, not_implemented_func,
40 allow_havoc):
41 self.dom = dom
42 self.__header = []
43 self.__body = []
44 self.__docs = []
46 assert prefix.endswith('_')
47 assert not signal_marshal_prefix.endswith('_')
49 # The main_prefix, sub_prefix thing is to get:
50 # FOO_ -> (FOO_, _)
51 # FOO_SVC_ -> (FOO_, _SVC_)
52 # but
53 # FOO_BAR/ -> (FOO_BAR_, _)
54 # FOO_BAR/SVC_ -> (FOO_BAR_, _SVC_)
56 if '/' in prefix:
57 main_prefix, sub_prefix = prefix.upper().split('/', 1)
58 prefix = prefix.replace('/', '_')
59 else:
60 main_prefix, sub_prefix = prefix.upper().split('_', 1)
62 self.MAIN_PREFIX_ = main_prefix + '_'
63 self._SUB_PREFIX_ = '_' + sub_prefix
65 self.Prefix_ = prefix
66 self.Prefix = prefix.replace('_', '')
67 self.prefix_ = prefix.lower()
68 self.PREFIX_ = prefix.upper()
70 self.basename = basename
71 self.signal_marshal_prefix = signal_marshal_prefix
72 self.headers = headers
73 self.end_headers = end_headers
74 self.not_implemented_func = not_implemented_func
75 self.allow_havoc = allow_havoc
77 def h(self, s):
78 if isinstance(s, unicode):
79 s = s.encode('utf-8')
80 self.__header.append(s)
82 def b(self, s):
83 if isinstance(s, unicode):
84 s = s.encode('utf-8')
85 self.__body.append(s)
87 def d(self, s):
88 if isinstance(s, unicode):
89 s = s.encode('utf-8')
90 self.__docs.append(s)
92 def do_node(self, node):
93 node_name = node.getAttribute('name').replace('/', '')
94 node_name_mixed = self.node_name_mixed = node_name.replace('_', '')
95 node_name_lc = self.node_name_lc = node_name.lower()
96 node_name_uc = self.node_name_uc = node_name.upper()
98 interfaces = node.getElementsByTagName('interface')
99 assert len(interfaces) == 1, interfaces
100 interface = interfaces[0]
101 self.iface_name = interface.getAttribute('name')
103 tmp = interface.getAttribute('tp:implement-service')
104 if tmp == "no":
105 return
107 tmp = interface.getAttribute('tp:causes-havoc')
108 if tmp and not self.allow_havoc:
109 raise AssertionError('%s is %s' % (self.iface_name, tmp))
111 self.b('static const DBusGObjectInfo _%s%s_object_info;'
112 % (self.prefix_, node_name_lc))
113 self.b('')
115 methods = interface.getElementsByTagName('method')
116 signals = interface.getElementsByTagName('signal')
117 properties = interface.getElementsByTagName('property')
118 # Don't put properties in dbus-glib glue
119 glue_properties = []
121 self.b('struct _%s%sClass {' % (self.Prefix, node_name_mixed))
122 self.b(' GTypeInterface parent_class;')
123 for method in methods:
124 self.b(' %s %s;' % self.get_method_impl_names(method))
125 self.b('};')
126 self.b('')
128 if signals:
129 self.b('enum {')
130 for signal in signals:
131 self.b(' %s,' % self.get_signal_const_entry(signal))
132 self.b(' N_%s_SIGNALS' % node_name_uc)
133 self.b('};')
134 self.b('static guint %s_signals[N_%s_SIGNALS] = {0};'
135 % (node_name_lc, node_name_uc))
136 self.b('')
138 self.b('static void %s%s_base_init (gpointer klass);'
139 % (self.prefix_, node_name_lc))
140 self.b('')
142 self.b('GType')
143 self.b('%s%s_get_type (void)'
144 % (self.prefix_, node_name_lc))
145 self.b('{')
146 self.b(' static GType type = 0;')
147 self.b('')
148 self.b(' if (G_UNLIKELY (type == 0))')
149 self.b(' {')
150 self.b(' static const GTypeInfo info = {')
151 self.b(' sizeof (%s%sClass),' % (self.Prefix, node_name_mixed))
152 self.b(' %s%s_base_init, /* base_init */'
153 % (self.prefix_, node_name_lc))
154 self.b(' NULL, /* base_finalize */')
155 self.b(' NULL, /* class_init */')
156 self.b(' NULL, /* class_finalize */')
157 self.b(' NULL, /* class_data */')
158 self.b(' 0,')
159 self.b(' 0, /* n_preallocs */')
160 self.b(' NULL /* instance_init */')
161 self.b(' };')
162 self.b('')
163 self.b(' type = g_type_register_static (G_TYPE_INTERFACE,')
164 self.b(' "%s%s", &info, 0);' % (self.Prefix, node_name_mixed))
165 self.b(' }')
166 self.b('')
167 self.b(' return type;')
168 self.b('}')
169 self.b('')
171 self.d('/**')
172 self.d(' * %s%s:' % (self.Prefix, node_name_mixed))
173 self.d(' *')
174 self.d(' * Dummy typedef representing any implementation of this '
175 'interface.')
176 self.d(' */')
178 self.h('typedef struct _%s%s %s%s;'
179 % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
180 self.h('')
182 self.d('/**')
183 self.d(' * %s%sClass:' % (self.Prefix, node_name_mixed))
184 self.d(' *')
185 self.d(' * The class of %s%s.' % (self.Prefix, node_name_mixed))
187 if methods:
188 self.d(' *')
189 self.d(' * In a full implementation of this interface (i.e. all')
190 self.d(' * methods implemented), the interface initialization')
191 self.d(' * function used in G_IMPLEMENT_INTERFACE() would')
192 self.d(' * typically look like this:')
193 self.d(' *')
194 self.d(' * <programlisting>')
195 self.d(' * static void')
196 self.d(' * implement_%s (gpointer klass,' % self.node_name_lc)
197 self.d(' * gpointer unused G_GNUC_UNUSED)')
198 self.d(' * {')
199 self.d(' * #define IMPLEMENT(x) %s%s_implement_&num;&num;x (\\'
200 % (self.prefix_, self.node_name_lc))
201 self.d(' * klass, my_object_&num;&num;x)')
203 for method in methods:
204 class_member_name = method.getAttribute('tp:name-for-bindings')
205 class_member_name = class_member_name.lower()
206 self.d(' * IMPLEMENT (%s);' % class_member_name)
208 self.d(' * #undef IMPLEMENT')
209 self.d(' * }')
210 self.d(' * </programlisting>')
211 else:
212 self.d(' * This interface has no D-Bus methods, so an')
213 self.d(' * implementation can typically pass %NULL to')
214 self.d(' * G_IMPLEMENT_INTERFACE() as the interface')
215 self.d(' * initialization function.')
217 self.d(' */')
218 self.d('')
220 self.h('typedef struct _%s%sClass %s%sClass;'
221 % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
222 self.h('')
223 self.h('GType %s%s_get_type (void);'
224 % (self.prefix_, node_name_lc))
226 gtype = self.current_gtype = \
227 self.MAIN_PREFIX_ + 'TYPE' + self._SUB_PREFIX_ + node_name_uc
228 classname = self.Prefix + node_name_mixed
230 self.h('#define %s \\\n (%s%s_get_type ())'
231 % (gtype, self.prefix_, node_name_lc))
232 self.h('#define %s%s(obj) \\\n'
233 ' (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))'
234 % (self.PREFIX_, node_name_uc, gtype, classname))
235 self.h('#define %sIS%s%s(obj) \\\n'
236 ' (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))'
237 % (self.MAIN_PREFIX_, self._SUB_PREFIX_, node_name_uc, gtype))
238 self.h('#define %s%s_GET_CLASS(obj) \\\n'
239 ' (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))'
240 % (self.PREFIX_, node_name_uc, gtype, classname))
241 self.h('')
242 self.h('')
244 base_init_code = []
246 for method in methods:
247 self.do_method(method)
249 for signal in signals:
250 base_init_code.extend(self.do_signal(signal))
252 self.b('static inline void')
253 self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)'
254 % (self.prefix_, node_name_lc))
255 self.b('{')
257 if properties:
258 self.b(' static TpDBusPropertiesMixinPropInfo properties[%d] = {'
259 % (len(properties) + 1))
261 for m in properties:
262 access = m.getAttribute('access')
263 assert access in ('read', 'write', 'readwrite')
265 if access == 'read':
266 flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_READ'
267 elif access == 'write':
268 flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE'
269 else:
270 flags = ('TP_DBUS_PROPERTIES_MIXIN_FLAG_READ | '
271 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE')
273 self.b(' { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
274 % (flags, m.getAttribute('type'), m.getAttribute('name')))
276 self.b(' { 0, 0, NULL, 0, NULL, NULL }')
277 self.b(' };')
278 self.b(' static TpDBusPropertiesMixinIfaceInfo interface =')
279 self.b(' { 0, properties, NULL, NULL };')
280 self.b('')
283 self.b(' dbus_g_object_type_install_info (%s%s_get_type (),'
284 % (self.prefix_, node_name_lc))
285 self.b(' &_%s%s_object_info);'
286 % (self.prefix_, node_name_lc))
287 self.b('')
289 if properties:
290 self.b(' interface.dbus_interface = g_quark_from_static_string '
291 '("%s");' % self.iface_name)
293 for i, m in enumerate(properties):
294 self.b(' properties[%d].name = g_quark_from_static_string ("%s");'
295 % (i, m.getAttribute('name')))
296 self.b(' properties[%d].type = %s;'
297 % (i, type_to_gtype(m.getAttribute('type'))[1]))
299 self.b(' tp_svc_interface_set_dbus_properties_info (%s, &interface);'
300 % self.current_gtype)
302 self.b('')
304 for s in base_init_code:
305 self.b(s)
306 self.b('}')
308 self.b('static void')
309 self.b('%s%s_base_init (gpointer klass)'
310 % (self.prefix_, node_name_lc))
311 self.b('{')
312 self.b(' static gboolean initialized = FALSE;')
313 self.b('')
314 self.b(' if (!initialized)')
315 self.b(' {')
316 self.b(' initialized = TRUE;')
317 self.b(' %s%s_base_init_once (klass);'
318 % (self.prefix_, node_name_lc))
319 self.b(' }')
320 # insert anything we need to do per implementation here
321 self.b('}')
323 self.h('')
325 self.b('static const DBusGMethodInfo _%s%s_methods[] = {'
326 % (self.prefix_, node_name_lc))
328 method_blob, offsets = self.get_method_glue(methods)
330 for method, offset in zip(methods, offsets):
331 self.do_method_glue(method, offset)
333 if len(methods) == 0:
334 # empty arrays are a gcc extension, so put in a dummy member
335 self.b(" { NULL, NULL, 0 }")
337 self.b('};')
338 self.b('')
340 self.b('static const DBusGObjectInfo _%s%s_object_info = {'
341 % (self.prefix_, node_name_lc))
342 self.b(' 0,') # version
343 self.b(' _%s%s_methods,' % (self.prefix_, node_name_lc))
344 self.b(' %d,' % len(methods))
345 self.b('"' + method_blob.replace('\0', '\\0') + '",')
346 self.b('"' + self.get_signal_glue(signals).replace('\0', '\\0') + '",')
347 self.b('"' +
348 self.get_property_glue(glue_properties).replace('\0', '\\0') +
349 '",')
350 self.b('};')
351 self.b('')
353 self.node_name_mixed = None
354 self.node_name_lc = None
355 self.node_name_uc = None
357 def get_method_glue(self, methods):
358 info = []
359 offsets = []
361 for method in methods:
362 offsets.append(len(''.join(info)))
364 info.append(self.iface_name + '\0')
365 info.append(method.getAttribute('name') + '\0')
367 info.append('A\0') # async
369 counter = 0
370 for arg in method.getElementsByTagName('arg'):
371 out = arg.getAttribute('direction') == 'out'
373 name = arg.getAttribute('name')
374 if not name:
375 assert out
376 name = 'arg%u' % counter
377 counter += 1
379 info.append(name + '\0')
381 if out:
382 info.append('O\0')
383 else:
384 info.append('I\0')
386 if out:
387 info.append('F\0') # not const
388 info.append('N\0') # not error or return
389 info.append(arg.getAttribute('type') + '\0')
391 info.append('\0')
393 return ''.join(info) + '\0', offsets
395 def do_method_glue(self, method, offset):
396 lc_name = method.getAttribute('tp:name-for-bindings')
397 if method.getAttribute('name') != lc_name.replace('_', ''):
398 raise AssertionError('Method %s tp:name-for-bindings (%s) does '
399 'not match' % (method.getAttribute('name'), lc_name))
400 lc_name = lc_name.lower()
402 marshaller = method_to_glue_marshal_name(method,
403 self.signal_marshal_prefix)
404 wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name
406 self.b(" { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset))
408 def get_signal_glue(self, signals):
409 info = []
411 for signal in signals:
412 info.append(self.iface_name)
413 info.append(signal.getAttribute('name'))
415 return '\0'.join(info) + '\0\0'
417 # the implementation can be the same
418 get_property_glue = get_signal_glue
420 def get_method_impl_names(self, method):
421 dbus_method_name = method.getAttribute('name')
423 class_member_name = method.getAttribute('tp:name-for-bindings')
424 if dbus_method_name != class_member_name.replace('_', ''):
425 raise AssertionError('Method %s tp:name-for-bindings (%s) does '
426 'not match' % (dbus_method_name, class_member_name))
427 class_member_name = class_member_name.lower()
429 stub_name = (self.prefix_ + self.node_name_lc + '_' +
430 class_member_name)
431 return (stub_name + '_impl', class_member_name + '_cb')
433 def do_method(self, method):
434 assert self.node_name_mixed is not None
436 in_class = []
438 # Examples refer to Thing.DoStuff (su) -> ii
440 # DoStuff
441 dbus_method_name = method.getAttribute('name')
442 # do_stuff
443 class_member_name = method.getAttribute('tp:name-for-bindings')
444 if dbus_method_name != class_member_name.replace('_', ''):
445 raise AssertionError('Method %s tp:name-for-bindings (%s) does '
446 'not match' % (dbus_method_name, class_member_name))
447 class_member_name = class_member_name.lower()
449 # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint,
450 # DBusGMethodInvocation *);
451 stub_name = (self.prefix_ + self.node_name_lc + '_' +
452 class_member_name)
453 # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *,
454 # const char *, guint, DBusGMethodInvocation);
455 impl_name = stub_name + '_impl'
456 # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *,
457 # gint, gint);
458 ret_name = (self.prefix_ + self.node_name_lc + '_return_from_' +
459 class_member_name)
461 # Gather arguments
462 in_args = []
463 out_args = []
464 for i in method.getElementsByTagName('arg'):
465 name = i.getAttribute('name')
466 direction = i.getAttribute('direction') or 'in'
467 dtype = i.getAttribute('type')
469 assert direction in ('in', 'out')
471 if name:
472 name = direction + '_' + name
473 elif direction == 'in':
474 name = direction + str(len(in_args))
475 else:
476 name = direction + str(len(out_args))
478 ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
480 if pointer:
481 ctype = 'const ' + ctype
483 struct = (ctype, name)
485 if direction == 'in':
486 in_args.append(struct)
487 else:
488 out_args.append(struct)
490 # Implementation type declaration (in header, docs separated)
491 self.d('/**')
492 self.d(' * %s:' % impl_name)
493 self.d(' * @self: The object implementing this interface')
494 for (ctype, name) in in_args:
495 self.d(' * @%s: %s (FIXME, generate documentation)'
496 % (name, ctype))
497 self.d(' * @context: Used to return values or throw an error')
498 self.d(' *')
499 self.d(' * The signature of an implementation of the D-Bus method')
500 self.d(' * %s on interface %s.' % (dbus_method_name, self.iface_name))
501 self.d(' */')
503 self.h('typedef void (*%s) (%s%s *self,'
504 % (impl_name, self.Prefix, self.node_name_mixed))
505 for (ctype, name) in in_args:
506 self.h(' %s%s,' % (ctype, name))
507 self.h(' DBusGMethodInvocation *context);')
509 # Class member (in class definition)
510 in_class.append(' %s %s;' % (impl_name, class_member_name))
512 # Stub definition (in body only - it's static)
513 self.b('static void')
514 self.b('%s (%s%s *self,'
515 % (stub_name, self.Prefix, self.node_name_mixed))
516 for (ctype, name) in in_args:
517 self.b(' %s%s,' % (ctype, name))
518 self.b(' DBusGMethodInvocation *context)')
519 self.b('{')
520 self.b(' %s impl = (%s%s_GET_CLASS (self)->%s_cb);'
521 % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name))
522 self.b('')
523 self.b(' if (impl != NULL)')
524 tmp = ['self'] + [name for (ctype, name) in in_args] + ['context']
525 self.b(' {')
526 self.b(' (impl) (%s);' % ',\n '.join(tmp))
527 self.b(' }')
528 self.b(' else')
529 self.b(' {')
530 if self.not_implemented_func:
531 self.b(' %s (context);' % self.not_implemented_func)
532 else:
533 self.b(' GError e = { DBUS_GERROR, ')
534 self.b(' DBUS_GERROR_UNKNOWN_METHOD,')
535 self.b(' "Method not implemented" };')
536 self.b('')
537 self.b(' dbus_g_method_return_error (context, &e);')
538 self.b(' }')
539 self.b('}')
540 self.b('')
542 # Implementation registration (in both header and body)
543 self.h('void %s%s_implement_%s (%s%sClass *klass, %s impl);'
544 % (self.prefix_, self.node_name_lc, class_member_name,
545 self.Prefix, self.node_name_mixed, impl_name))
547 self.d('/**')
548 self.d(' * %s%s_implement_%s:'
549 % (self.prefix_, self.node_name_lc, class_member_name))
550 self.d(' * @klass: A class whose instances implement this interface')
551 self.d(' * @impl: A callback used to implement the %s D-Bus method'
552 % dbus_method_name)
553 self.d(' *')
554 self.d(' * Register an implementation for the %s method in the vtable'
555 % dbus_method_name)
556 self.d(' * of an implementation of this interface. To be called from')
557 self.d(' * the interface init function.')
558 self.d(' */')
560 self.b('void')
561 self.b('%s%s_implement_%s (%s%sClass *klass, %s impl)'
562 % (self.prefix_, self.node_name_lc, class_member_name,
563 self.Prefix, self.node_name_mixed, impl_name))
564 self.b('{')
565 self.b(' klass->%s_cb = impl;' % class_member_name)
566 self.b('}')
567 self.b('')
569 # Return convenience function (static inline, in header)
570 self.d('/**')
571 self.d(' * %s:' % ret_name)
572 self.d(' * @context: The D-Bus method invocation context')
573 for (ctype, name) in out_args:
574 self.d(' * @%s: %s (FIXME, generate documentation)'
575 % (name, ctype))
576 self.d(' *')
577 self.d(' * Return successfully by calling dbus_g_method_return().')
578 self.d(' * This inline function exists only to provide type-safety.')
579 self.d(' */')
580 self.d('')
582 tmp = (['DBusGMethodInvocation *context'] +
583 [ctype + name for (ctype, name) in out_args])
584 self.h('static inline')
585 self.h('/* this comment is to stop gtkdoc realising this is static */')
586 self.h(('void %s (' % ret_name) + (',\n '.join(tmp)) + ');')
587 self.h('static inline void')
588 self.h(('%s (' % ret_name) + (',\n '.join(tmp)) + ')')
589 self.h('{')
590 tmp = ['context'] + [name for (ctype, name) in out_args]
591 self.h(' dbus_g_method_return (' + ',\n '.join(tmp) + ');')
592 self.h('}')
593 self.h('')
595 return in_class
597 def get_signal_const_entry(self, signal):
598 assert self.node_name_uc is not None
599 return ('SIGNAL_%s_%s'
600 % (self.node_name_uc, signal.getAttribute('name')))
602 def do_signal(self, signal):
603 assert self.node_name_mixed is not None
605 in_base_init = []
607 # for signal: Thing::StuffHappened (s, u)
608 # we want to emit:
609 # void tp_svc_thing_emit_stuff_happened (gpointer instance,
610 # const char *arg0, guint arg1);
612 dbus_name = signal.getAttribute('name')
614 ugly_name = signal.getAttribute('tp:name-for-bindings')
615 if dbus_name != ugly_name.replace('_', ''):
616 raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
617 'not match' % (dbus_name, ugly_name))
619 stub_name = (self.prefix_ + self.node_name_lc + '_emit_' +
620 ugly_name.lower())
622 const_name = self.get_signal_const_entry(signal)
624 # Gather arguments
625 args = []
626 for i in signal.getElementsByTagName('arg'):
627 name = i.getAttribute('name')
628 dtype = i.getAttribute('type')
629 tp_type = i.getAttribute('tp:type')
631 if name:
632 name = 'arg_' + name
633 else:
634 name = 'arg' + str(len(args))
636 ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
638 if pointer:
639 ctype = 'const ' + ctype
641 struct = (ctype, name, gtype)
642 args.append(struct)
644 tmp = (['gpointer instance'] +
645 [ctype + name for (ctype, name, gtype) in args])
647 self.h(('void %s (' % stub_name) + (',\n '.join(tmp)) + ');')
649 # FIXME: emit docs
651 self.d('/**')
652 self.d(' * %s:' % stub_name)
653 self.d(' * @instance: The object implementing this interface')
654 for (ctype, name, gtype) in args:
655 self.d(' * @%s: %s (FIXME, generate documentation)'
656 % (name, ctype))
657 self.d(' *')
658 self.d(' * Type-safe wrapper around g_signal_emit to emit the')
659 self.d(' * %s signal on interface %s.'
660 % (dbus_name, self.iface_name))
661 self.d(' */')
663 self.b('void')
664 self.b(('%s (' % stub_name) + (',\n '.join(tmp)) + ')')
665 self.b('{')
666 self.b(' g_assert (instance != NULL);')
667 self.b(' g_assert (G_TYPE_CHECK_INSTANCE_TYPE (instance, %s));'
668 % (self.current_gtype))
669 tmp = (['instance', '%s_signals[%s]' % (self.node_name_lc, const_name),
670 '0'] + [name for (ctype, name, gtype) in args])
671 self.b(' g_signal_emit (' + ',\n '.join(tmp) + ');')
672 self.b('}')
673 self.b('')
675 signal_name = dbus_gutils_wincaps_to_uscore(dbus_name).replace('_',
676 '-')
678 self.d('/**')
679 self.d(' * %s%s::%s:'
680 % (self.Prefix, self.node_name_mixed, signal_name))
681 self.d(' * @self: an object')
682 for (ctype, name, gtype) in args:
683 self.d(' * @%s: %s (FIXME, generate documentation)'
684 % (name, ctype))
685 self.d(' *')
686 self.d(' * The %s D-Bus signal is emitted whenever '
687 'this GObject signal is.' % dbus_name)
688 self.d(' */')
689 self.d('')
691 in_base_init.append(' %s_signals[%s] ='
692 % (self.node_name_lc, const_name))
693 in_base_init.append(' g_signal_new ("%s",' % signal_name)
694 in_base_init.append(' G_OBJECT_CLASS_TYPE (klass),')
695 in_base_init.append(' G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,')
696 in_base_init.append(' 0,')
697 in_base_init.append(' NULL, NULL,')
698 in_base_init.append(' %s,'
699 % signal_to_marshal_name(signal, self.signal_marshal_prefix))
700 in_base_init.append(' G_TYPE_NONE,')
701 tmp = ['%d' % len(args)] + [gtype for (ctype, name, gtype) in args]
702 in_base_init.append(' %s);' % ',\n '.join(tmp))
703 in_base_init.append('')
705 return in_base_init
707 def have_properties(self, nodes):
708 for node in nodes:
709 interface = node.getElementsByTagName('interface')[0]
710 if interface.getElementsByTagName('property'):
711 return True
712 return False
714 def __call__(self):
715 nodes = self.dom.getElementsByTagName('node')
716 nodes.sort(cmp_by_name)
718 self.h('#include <glib-object.h>')
719 self.h('#include <dbus/dbus-glib.h>')
721 if self.have_properties(nodes):
722 self.h('#include <telepathy-glib/dbus-properties-mixin.h>')
724 self.h('')
725 self.h('G_BEGIN_DECLS')
726 self.h('')
728 self.b('#include "%s.h"' % self.basename)
729 self.b('')
730 for header in self.headers:
731 self.b('#include %s' % header)
732 self.b('')
734 for node in nodes:
735 self.do_node(node)
737 self.h('')
738 self.h('G_END_DECLS')
740 self.b('')
741 for header in self.end_headers:
742 self.b('#include %s' % header)
744 self.h('')
745 self.b('')
746 open(self.basename + '.h', 'w').write('\n'.join(self.__header))
747 open(self.basename + '.c', 'w').write('\n'.join(self.__body))
748 open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs))
751 def cmdline_error():
752 print """\
753 usage:
754 gen-ginterface [OPTIONS] xmlfile Prefix_
755 options:
756 --include='<header.h>' (may be repeated)
757 --include='"header.h"' (ditto)
758 --include-end='"header.h"' (ditto)
759 Include extra headers in the generated .c file
760 --signal-marshal-prefix='prefix'
761 Use the given prefix on generated signal marshallers (default is
762 prefix.lower()).
763 --filename='BASENAME'
764 Set the basename for the output files (default is prefix.lower()
765 + 'ginterfaces')
766 --not-implemented-func='symbol'
767 Set action when methods not implemented in the interface vtable are
768 called. symbol must have signature
769 void symbol (DBusGMethodInvocation *context)
770 and return some sort of "not implemented" error via
771 dbus_g_method_return_error (context, ...)
773 sys.exit(1)
776 if __name__ == '__main__':
777 from getopt import gnu_getopt
779 options, argv = gnu_getopt(sys.argv[1:], '',
780 ['filename=', 'signal-marshal-prefix=',
781 'include=', 'include-end=',
782 'allow-unstable',
783 'not-implemented-func='])
785 try:
786 prefix = argv[1]
787 except IndexError:
788 cmdline_error()
790 basename = prefix.lower() + 'ginterfaces'
791 signal_marshal_prefix = prefix.lower().rstrip('_')
792 headers = []
793 end_headers = []
794 not_implemented_func = ''
795 allow_havoc = False
797 for option, value in options:
798 if option == '--filename':
799 basename = value
800 elif option == '--signal-marshal-prefix':
801 signal_marshal_prefix = value
802 elif option == '--include':
803 if value[0] not in '<"':
804 value = '"%s"' % value
805 headers.append(value)
806 elif option == '--include-end':
807 if value[0] not in '<"':
808 value = '"%s"' % value
809 end_headers.append(value)
810 elif option == '--not-implemented-func':
811 not_implemented_func = value
812 elif option == '--allow-unstable':
813 allow_havoc = True
815 try:
816 dom = xml.dom.minidom.parse(argv[0])
817 except IndexError:
818 cmdline_error()
820 Generator(dom, prefix, basename, signal_marshal_prefix, headers,
821 end_headers, not_implemented_func, allow_havoc)()