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
27 import xml
.dom
.minidom
29 from libtpcodegen
import file_set_contents
, key_by_name
, u
30 from libglibcodegen
import Signature
, type_to_gtype
, \
31 NS_TP
, dbus_gutils_wincaps_to_uscore
34 NS_TP
= "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
36 def get_emits_changed(node
):
39 annotation
.getAttribute('value')
40 for annotation
in node
.getElementsByTagName('annotation')
41 if annotation
.getAttribute('name') == 'org.freedesktop.DBus.Property.EmitsChangedSignal'
46 class Generator(object):
48 def __init__(self
, dom
, prefix
, basename
, signal_marshal_prefix
,
49 headers
, end_headers
, not_implemented_func
,
56 assert prefix
.endswith('_')
57 assert not signal_marshal_prefix
.endswith('_')
59 # The main_prefix, sub_prefix thing is to get:
61 # FOO_SVC_ -> (FOO_, _SVC_)
63 # FOO_BAR/ -> (FOO_BAR_, _)
64 # FOO_BAR/SVC_ -> (FOO_BAR_, _SVC_)
67 main_prefix
, sub_prefix
= prefix
.upper().split('/', 1)
68 prefix
= prefix
.replace('/', '_')
70 main_prefix
, sub_prefix
= prefix
.upper().split('_', 1)
72 self
.MAIN_PREFIX_
= main_prefix
+ '_'
73 self
._SUB
_PREFIX
_ = '_' + sub_prefix
76 self
.Prefix
= prefix
.replace('_', '')
77 self
.prefix_
= prefix
.lower()
78 self
.PREFIX_
= prefix
.upper()
80 self
.basename
= basename
81 self
.signal_marshal_prefix
= signal_marshal_prefix
82 self
.headers
= headers
83 self
.end_headers
= end_headers
84 self
.not_implemented_func
= not_implemented_func
85 self
.allow_havoc
= allow_havoc
88 self
.__header
.append(s
)
96 def do_node(self
, node
):
97 node_name
= node
.getAttribute('name').replace('/', '')
98 node_name_mixed
= self
.node_name_mixed
= node_name
.replace('_', '')
99 node_name_lc
= self
.node_name_lc
= node_name
.lower()
100 node_name_uc
= self
.node_name_uc
= node_name
.upper()
102 interfaces
= node
.getElementsByTagName('interface')
103 assert len(interfaces
) == 1, interfaces
104 interface
= interfaces
[0]
105 self
.iface_name
= interface
.getAttribute('name')
107 tmp
= interface
.getAttribute('tp:implement-service')
111 tmp
= interface
.getAttribute('tp:causes-havoc')
112 if tmp
and not self
.allow_havoc
:
113 raise AssertionError('%s is %s' % (self
.iface_name
, tmp
))
115 iface_emits_changed
= get_emits_changed(interface
)
117 self
.b('static const DBusGObjectInfo _%s%s_object_info;'
118 % (self
.prefix_
, node_name_lc
))
121 methods
= interface
.getElementsByTagName('method')
122 signals
= interface
.getElementsByTagName('signal')
123 properties
= interface
.getElementsByTagName('property')
124 # Don't put properties in dbus-glib glue
127 self
.b('struct _%s%sClass {' % (self
.Prefix
, node_name_mixed
))
128 self
.b(' GTypeInterface parent_class;')
129 for method
in methods
:
130 self
.b(' %s %s;' % self
.get_method_impl_names(method
))
136 for signal
in signals
:
137 self
.b(' %s,' % self
.get_signal_const_entry(signal
))
138 self
.b(' N_%s_SIGNALS' % node_name_uc
)
140 self
.b('static guint %s_signals[N_%s_SIGNALS] = {0};'
141 % (node_name_lc
, node_name_uc
))
144 self
.b('static void %s%s_base_init (gpointer klass);'
145 % (self
.prefix_
, node_name_lc
))
149 self
.b('%s%s_get_type (void)'
150 % (self
.prefix_
, node_name_lc
))
152 self
.b(' static GType type = 0;')
154 self
.b(' if (G_UNLIKELY (type == 0))')
156 self
.b(' static const GTypeInfo info = {')
157 self
.b(' sizeof (%s%sClass),' % (self
.Prefix
, node_name_mixed
))
158 self
.b(' %s%s_base_init, /* base_init */'
159 % (self
.prefix_
, node_name_lc
))
160 self
.b(' NULL, /* base_finalize */')
161 self
.b(' NULL, /* class_init */')
162 self
.b(' NULL, /* class_finalize */')
163 self
.b(' NULL, /* class_data */')
165 self
.b(' 0, /* n_preallocs */')
166 self
.b(' NULL /* instance_init */')
169 self
.b(' type = g_type_register_static (G_TYPE_INTERFACE,')
170 self
.b(' "%s%s", &info, 0);' % (self
.Prefix
, node_name_mixed
))
173 self
.b(' return type;')
178 self
.d(' * %s%s:' % (self
.Prefix
, node_name_mixed
))
180 self
.d(' * Dummy typedef representing any implementation of this '
184 self
.h('typedef struct _%s%s %s%s;'
185 % (self
.Prefix
, node_name_mixed
, self
.Prefix
, node_name_mixed
))
189 self
.d(' * %s%sClass:' % (self
.Prefix
, node_name_mixed
))
191 self
.d(' * The class of %s%s.' % (self
.Prefix
, node_name_mixed
))
195 self
.d(' * In a full implementation of this interface (i.e. all')
196 self
.d(' * methods implemented), the interface initialization')
197 self
.d(' * function used in G_IMPLEMENT_INTERFACE() would')
198 self
.d(' * typically look like this:')
200 self
.d(' * <programlisting>')
201 self
.d(' * static void')
202 self
.d(' * implement_%s (gpointer klass,' % self
.node_name_lc
)
203 self
.d(' * gpointer unused G_GNUC_UNUSED)')
205 self
.d(' * #define IMPLEMENT(x) %s%s_implement_##x (\\'
206 % (self
.prefix_
, self
.node_name_lc
))
207 self
.d(' * klass, my_object_##x)')
209 for method
in methods
:
210 class_member_name
= method
.getAttribute('tp:name-for-bindings')
211 class_member_name
= class_member_name
.lower()
212 self
.d(' * IMPLEMENT (%s);' % class_member_name
)
214 self
.d(' * #undef IMPLEMENT')
216 self
.d(' * </programlisting>')
218 self
.d(' * This interface has no D-Bus methods, so an')
219 self
.d(' * implementation can typically pass %NULL to')
220 self
.d(' * G_IMPLEMENT_INTERFACE() as the interface')
221 self
.d(' * initialization function.')
226 self
.h('typedef struct _%s%sClass %s%sClass;'
227 % (self
.Prefix
, node_name_mixed
, self
.Prefix
, node_name_mixed
))
229 self
.h('GType %s%s_get_type (void);'
230 % (self
.prefix_
, node_name_lc
))
232 gtype
= self
.current_gtype
= \
233 self
.MAIN_PREFIX_
+ 'TYPE' + self
._SUB
_PREFIX
_ + node_name_uc
234 classname
= self
.Prefix
+ node_name_mixed
236 self
.h('#define %s \\\n (%s%s_get_type ())'
237 % (gtype
, self
.prefix_
, node_name_lc
))
238 self
.h('#define %s%s(obj) \\\n'
239 ' (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))'
240 % (self
.PREFIX_
, node_name_uc
, gtype
, classname
))
241 self
.h('#define %sIS%s%s(obj) \\\n'
242 ' (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))'
243 % (self
.MAIN_PREFIX_
, self
._SUB
_PREFIX
_, node_name_uc
, gtype
))
244 self
.h('#define %s%s_GET_CLASS(obj) \\\n'
245 ' (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))'
246 % (self
.PREFIX_
, node_name_uc
, gtype
, classname
))
252 for method
in methods
:
253 self
.do_method(method
)
255 for signal
in signals
:
256 base_init_code
.extend(self
.do_signal(signal
))
258 self
.b('static inline void')
259 self
.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)'
260 % (self
.prefix_
, node_name_lc
))
264 self
.b(' static TpDBusPropertiesMixinPropInfo properties[%d] = {'
265 % (len(properties
) + 1))
268 access
= m
.getAttribute('access')
269 assert access
in ('read', 'write', 'readwrite')
272 flags
= 'TP_DBUS_PROPERTIES_MIXIN_FLAG_READ'
273 elif access
== 'write':
274 flags
= 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE'
276 flags
= ('TP_DBUS_PROPERTIES_MIXIN_FLAG_READ | '
277 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE')
279 prop_emits_changed
= get_emits_changed(m
)
281 if prop_emits_changed
is None:
282 prop_emits_changed
= iface_emits_changed
284 if prop_emits_changed
== 'true':
285 flags
+= ' | TP_DBUS_PROPERTIES_MIXIN_FLAG_EMITS_CHANGED'
286 elif prop_emits_changed
== 'invalidates':
287 flags
+= ' | TP_DBUS_PROPERTIES_MIXIN_FLAG_EMITS_INVALIDATED'
289 self
.b(' { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
290 % (flags
, m
.getAttribute('type'), m
.getAttribute('name')))
292 self
.b(' { 0, 0, NULL, 0, NULL, NULL }')
294 self
.b(' static TpDBusPropertiesMixinIfaceInfo interface =')
295 self
.b(' { 0, properties, NULL, NULL };')
299 self
.b(' dbus_g_object_type_install_info (%s%s_get_type (),'
300 % (self
.prefix_
, node_name_lc
))
301 self
.b(' &_%s%s_object_info);'
302 % (self
.prefix_
, node_name_lc
))
306 self
.b(' interface.dbus_interface = g_quark_from_static_string '
307 '("%s");' % self
.iface_name
)
309 for i
, m
in enumerate(properties
):
310 self
.b(' properties[%d].name = g_quark_from_static_string ("%s");'
311 % (i
, m
.getAttribute('name')))
312 self
.b(' properties[%d].type = %s;'
313 % (i
, type_to_gtype(m
.getAttribute('type'))[1]))
315 self
.b(' tp_svc_interface_set_dbus_properties_info (%s, &interface);'
316 % self
.current_gtype
)
320 for s
in base_init_code
:
324 self
.b('static void')
325 self
.b('%s%s_base_init (gpointer klass)'
326 % (self
.prefix_
, node_name_lc
))
328 self
.b(' static gboolean initialized = FALSE;')
330 self
.b(' if (!initialized)')
332 self
.b(' initialized = TRUE;')
333 self
.b(' %s%s_base_init_once (klass);'
334 % (self
.prefix_
, node_name_lc
))
336 # insert anything we need to do per implementation here
341 self
.b('static const DBusGMethodInfo _%s%s_methods[] = {'
342 % (self
.prefix_
, node_name_lc
))
344 method_blob
, offsets
= self
.get_method_glue(methods
)
346 for method
, offset
in zip(methods
, offsets
):
347 self
.do_method_glue(method
, offset
)
349 if len(methods
) == 0:
350 # empty arrays are a gcc extension, so put in a dummy member
351 self
.b(" { NULL, NULL, 0 }")
356 self
.b('static const DBusGObjectInfo _%s%s_object_info = {'
357 % (self
.prefix_
, node_name_lc
))
358 self
.b(' 0,') # version
359 self
.b(' _%s%s_methods,' % (self
.prefix_
, node_name_lc
))
360 self
.b(' %d,' % len(methods
))
361 self
.b('"' + method_blob
.replace('\0', '\\0') + '",')
362 self
.b('"' + self
.get_signal_glue(signals
).replace('\0', '\\0') + '",')
364 self
.get_property_glue(glue_properties
).replace('\0', '\\0') +
369 self
.node_name_mixed
= None
370 self
.node_name_lc
= None
371 self
.node_name_uc
= None
373 def get_method_glue(self
, methods
):
377 for method
in methods
:
378 offsets
.append(len(''.join(info
)))
380 info
.append(self
.iface_name
+ '\0')
381 info
.append(method
.getAttribute('name') + '\0')
383 info
.append('A\0') # async
386 for arg
in method
.getElementsByTagName('arg'):
387 out
= arg
.getAttribute('direction') == 'out'
389 name
= arg
.getAttribute('name')
392 name
= 'arg%u' % counter
395 info
.append(name
+ '\0')
403 info
.append('F\0') # not const
404 info
.append('N\0') # not error or return
405 info
.append(arg
.getAttribute('type') + '\0')
409 return ''.join(info
) + '\0', offsets
411 def do_method_glue(self
, method
, offset
):
412 lc_name
= method
.getAttribute('tp:name-for-bindings')
413 if method
.getAttribute('name') != lc_name
.replace('_', ''):
414 raise AssertionError('Method %s tp:name-for-bindings (%s) does '
415 'not match' % (method
.getAttribute('name'), lc_name
))
416 lc_name
= lc_name
.lower()
418 marshaller
= 'g_cclosure_marshal_generic'
419 wrapper
= self
.prefix_
+ self
.node_name_lc
+ '_' + lc_name
421 self
.b(" { (GCallback) %s, %s, %d }," % (wrapper
, marshaller
, offset
))
423 def get_signal_glue(self
, signals
):
426 for signal
in signals
:
427 info
.append(self
.iface_name
)
428 info
.append(signal
.getAttribute('name'))
430 return '\0'.join(info
) + '\0\0'
432 # the implementation can be the same
433 get_property_glue
= get_signal_glue
435 def get_method_impl_names(self
, method
):
436 dbus_method_name
= method
.getAttribute('name')
438 class_member_name
= method
.getAttribute('tp:name-for-bindings')
439 if dbus_method_name
!= class_member_name
.replace('_', ''):
440 raise AssertionError('Method %s tp:name-for-bindings (%s) does '
441 'not match' % (dbus_method_name
, class_member_name
))
442 class_member_name
= class_member_name
.lower()
444 stub_name
= (self
.prefix_
+ self
.node_name_lc
+ '_' +
446 return (stub_name
+ '_impl', class_member_name
+ '_cb')
448 def do_method(self
, method
):
449 assert self
.node_name_mixed
is not None
453 # Examples refer to Thing.DoStuff (su) -> ii
456 dbus_method_name
= method
.getAttribute('name')
458 class_member_name
= method
.getAttribute('tp:name-for-bindings')
459 if dbus_method_name
!= class_member_name
.replace('_', ''):
460 raise AssertionError('Method %s tp:name-for-bindings (%s) does '
461 'not match' % (dbus_method_name
, class_member_name
))
462 class_member_name
= class_member_name
.lower()
464 # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint,
465 # DBusGMethodInvocation *);
466 stub_name
= (self
.prefix_
+ self
.node_name_lc
+ '_' +
468 # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *,
469 # const char *, guint, DBusGMethodInvocation);
470 impl_name
= stub_name
+ '_impl'
471 # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *,
473 ret_name
= (self
.prefix_
+ self
.node_name_lc
+ '_return_from_' +
479 for i
in method
.getElementsByTagName('arg'):
480 name
= i
.getAttribute('name')
481 direction
= i
.getAttribute('direction') or 'in'
482 dtype
= i
.getAttribute('type')
484 assert direction
in ('in', 'out')
487 name
= direction
+ '_' + name
488 elif direction
== 'in':
489 name
= direction
+ str(len(in_args
))
491 name
= direction
+ str(len(out_args
))
493 ctype
, gtype
, marshaller
, pointer
= type_to_gtype(dtype
)
496 ctype
= 'const ' + ctype
498 struct
= (ctype
, name
)
500 if direction
== 'in':
501 in_args
.append(struct
)
503 out_args
.append(struct
)
505 # Implementation type declaration (in header, docs separated)
507 self
.d(' * %s:' % impl_name
)
508 self
.d(' * @self: The object implementing this interface')
509 for (ctype
, name
) in in_args
:
510 self
.d(' * @%s: %s (FIXME, generate documentation)'
512 self
.d(' * @context: Used to return values or throw an error')
514 self
.d(' * The signature of an implementation of the D-Bus method')
515 self
.d(' * %s on interface %s.' % (dbus_method_name
, self
.iface_name
))
518 self
.h('typedef void (*%s) (%s%s *self,'
519 % (impl_name
, self
.Prefix
, self
.node_name_mixed
))
520 for (ctype
, name
) in in_args
:
521 self
.h(' %s%s,' % (ctype
, name
))
522 self
.h(' DBusGMethodInvocation *context);')
524 # Class member (in class definition)
525 in_class
.append(' %s %s;' % (impl_name
, class_member_name
))
527 # Stub definition (in body only - it's static)
528 self
.b('static void')
529 self
.b('%s (%s%s *self,'
530 % (stub_name
, self
.Prefix
, self
.node_name_mixed
))
531 for (ctype
, name
) in in_args
:
532 self
.b(' %s%s,' % (ctype
, name
))
533 self
.b(' DBusGMethodInvocation *context)')
535 self
.b(' %s impl = (%s%s_GET_CLASS (self)->%s_cb);'
536 % (impl_name
, self
.PREFIX_
, self
.node_name_uc
, class_member_name
))
538 self
.b(' if (impl != NULL)')
539 tmp
= ['self'] + [name
for (ctype
, name
) in in_args
] + ['context']
541 self
.b(' (impl) (%s);' % ',\n '.join(tmp
))
545 if self
.not_implemented_func
:
546 self
.b(' %s (context);' % self
.not_implemented_func
)
548 self
.b(' GError e = { DBUS_GERROR, ')
549 self
.b(' DBUS_GERROR_UNKNOWN_METHOD,')
550 self
.b(' "Method not implemented" };')
552 self
.b(' dbus_g_method_return_error (context, &e);')
557 # Implementation registration (in both header and body)
558 self
.h('void %s%s_implement_%s (%s%sClass *klass, %s impl);'
559 % (self
.prefix_
, self
.node_name_lc
, class_member_name
,
560 self
.Prefix
, self
.node_name_mixed
, impl_name
))
563 self
.d(' * %s%s_implement_%s:'
564 % (self
.prefix_
, self
.node_name_lc
, class_member_name
))
565 self
.d(' * @klass: A class whose instances implement this interface')
566 self
.d(' * @impl: A callback used to implement the %s D-Bus method'
569 self
.d(' * Register an implementation for the %s method in the vtable'
571 self
.d(' * of an implementation of this interface. To be called from')
572 self
.d(' * the interface init function.')
576 self
.b('%s%s_implement_%s (%s%sClass *klass, %s impl)'
577 % (self
.prefix_
, self
.node_name_lc
, class_member_name
,
578 self
.Prefix
, self
.node_name_mixed
, impl_name
))
580 self
.b(' klass->%s_cb = impl;' % class_member_name
)
584 # Return convenience function (static inline, in header)
586 self
.d(' * %s:' % ret_name
)
587 self
.d(' * @context: The D-Bus method invocation context')
588 for (ctype
, name
) in out_args
:
589 self
.d(' * @%s: %s (FIXME, generate documentation)'
592 self
.d(' * Return successfully by calling dbus_g_method_return().')
593 self
.d(' * This inline function exists only to provide type-safety.')
597 tmp
= (['DBusGMethodInvocation *context'] +
598 [ctype
+ name
for (ctype
, name
) in out_args
])
599 self
.h('static inline')
600 self
.h('/* this comment is to stop gtkdoc realising this is static */')
601 self
.h(('void %s (' % ret_name
) + (',\n '.join(tmp
)) + ');')
602 self
.h('static inline void')
603 self
.h(('%s (' % ret_name
) + (',\n '.join(tmp
)) + ')')
605 tmp
= ['context'] + [name
for (ctype
, name
) in out_args
]
606 self
.h(' dbus_g_method_return (' + ',\n '.join(tmp
) + ');')
612 def get_signal_const_entry(self
, signal
):
613 assert self
.node_name_uc
is not None
614 return ('SIGNAL_%s_%s'
615 % (self
.node_name_uc
, signal
.getAttribute('name')))
617 def do_signal(self
, signal
):
618 assert self
.node_name_mixed
is not None
622 # for signal: Thing::StuffHappened (s, u)
624 # void tp_svc_thing_emit_stuff_happened (gpointer instance,
625 # const char *arg0, guint arg1);
627 dbus_name
= signal
.getAttribute('name')
629 ugly_name
= signal
.getAttribute('tp:name-for-bindings')
630 if dbus_name
!= ugly_name
.replace('_', ''):
631 raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
632 'not match' % (dbus_name
, ugly_name
))
634 stub_name
= (self
.prefix_
+ self
.node_name_lc
+ '_emit_' +
637 const_name
= self
.get_signal_const_entry(signal
)
641 for i
in signal
.getElementsByTagName('arg'):
642 name
= i
.getAttribute('name')
643 dtype
= i
.getAttribute('type')
644 tp_type
= i
.getAttribute('tp:type')
649 name
= 'arg' + str(len(args
))
651 ctype
, gtype
, marshaller
, pointer
= type_to_gtype(dtype
)
654 ctype
= 'const ' + ctype
656 struct
= (ctype
, name
, gtype
)
659 tmp
= (['gpointer instance'] +
660 [ctype
+ name
for (ctype
, name
, gtype
) in args
])
662 self
.h(('void %s (' % stub_name
) + (',\n '.join(tmp
)) + ');')
667 self
.d(' * %s:' % stub_name
)
668 self
.d(' * @instance: The object implementing this interface')
669 for (ctype
, name
, gtype
) in args
:
670 self
.d(' * @%s: %s (FIXME, generate documentation)'
673 self
.d(' * Type-safe wrapper around g_signal_emit to emit the')
674 self
.d(' * %s signal on interface %s.'
675 % (dbus_name
, self
.iface_name
))
679 self
.b(('%s (' % stub_name
) + (',\n '.join(tmp
)) + ')')
681 self
.b(' g_assert (instance != NULL);')
682 self
.b(' g_assert (G_TYPE_CHECK_INSTANCE_TYPE (instance, %s));'
683 % (self
.current_gtype
))
684 tmp
= (['instance', '%s_signals[%s]' % (self
.node_name_lc
, const_name
),
685 '0'] + [name
for (ctype
, name
, gtype
) in args
])
686 self
.b(' g_signal_emit (' + ',\n '.join(tmp
) + ');')
690 signal_name
= dbus_gutils_wincaps_to_uscore(dbus_name
).replace('_',
694 self
.d(' * %s%s::%s:'
695 % (self
.Prefix
, self
.node_name_mixed
, signal_name
))
696 self
.d(' * @self: an object')
697 for (ctype
, name
, gtype
) in args
:
698 self
.d(' * @%s: %s (FIXME, generate documentation)'
701 self
.d(' * The %s D-Bus signal is emitted whenever '
702 'this GObject signal is.' % dbus_name
)
706 in_base_init
.append(' %s_signals[%s] ='
707 % (self
.node_name_lc
, const_name
))
708 in_base_init
.append(' g_signal_new ("%s",' % signal_name
)
709 in_base_init
.append(' G_OBJECT_CLASS_TYPE (klass),')
710 in_base_init
.append(' G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,')
711 in_base_init
.append(' 0,')
712 in_base_init
.append(' NULL, NULL,')
713 in_base_init
.append(' g_cclosure_marshal_generic,')
714 in_base_init
.append(' G_TYPE_NONE,')
715 tmp
= ['%d' % len(args
)] + [gtype
for (ctype
, name
, gtype
) in args
]
716 in_base_init
.append(' %s);' % ',\n '.join(tmp
))
717 in_base_init
.append('')
721 def have_properties(self
, nodes
):
723 interface
= node
.getElementsByTagName('interface')[0]
724 if interface
.getElementsByTagName('property'):
729 nodes
= self
.dom
.getElementsByTagName('node')
730 nodes
.sort(key
=key_by_name
)
732 self
.h('#include <glib-object.h>')
733 self
.h('#include <dbus/dbus-glib.h>')
735 for header
in self
.headers
:
736 self
.h('#include %s' % header
)
740 self
.h('G_BEGIN_DECLS')
743 self
.b('#include "%s.h"' % self
.basename
)
750 self
.h('G_END_DECLS')
753 for header
in self
.end_headers
:
754 self
.b('#include %s' % header
)
758 file_set_contents(self
.basename
+ '.h', u('\n').join(self
.__header
).encode('utf-8'))
759 file_set_contents(self
.basename
+ '.c', u('\n').join(self
.__body
).encode('utf-8'))
760 file_set_contents(self
.basename
+ '-gtk-doc.h', u('\n').join(self
.__docs
).encode('utf-8'))
765 gen-ginterface [OPTIONS] xmlfile Prefix_
767 --include='<header.h>' (may be repeated)
768 --include='"header.h"' (ditto)
769 --include-end='"header.h"' (ditto)
770 Include extra headers in the generated .c file
771 --signal-marshal-prefix='prefix'
772 Use the given prefix on generated signal marshallers (default is
774 --filename='BASENAME'
775 Set the basename for the output files (default is prefix.lower()
777 --not-implemented-func='symbol'
778 Set action when methods not implemented in the interface vtable are
779 called. symbol must have signature
780 void symbol (DBusGMethodInvocation *context)
781 and return some sort of "not implemented" error via
782 dbus_g_method_return_error (context, ...)
787 if __name__
== '__main__':
788 from getopt
import gnu_getopt
790 options
, argv
= gnu_getopt(sys
.argv
[1:], '',
791 ['filename=', 'signal-marshal-prefix=',
792 'include=', 'include-end=',
794 'not-implemented-func='])
801 basename
= prefix
.lower() + 'ginterfaces'
802 signal_marshal_prefix
= prefix
.lower().rstrip('_')
805 not_implemented_func
= ''
808 for option
, value
in options
:
809 if option
== '--filename':
811 elif option
== '--signal-marshal-prefix':
812 signal_marshal_prefix
= value
813 elif option
== '--include':
814 if value
[0] not in '<"':
815 value
= '"%s"' % value
816 headers
.append(value
)
817 elif option
== '--include-end':
818 if value
[0] not in '<"':
819 value
= '"%s"' % value
820 end_headers
.append(value
)
821 elif option
== '--not-implemented-func':
822 not_implemented_func
= value
823 elif option
== '--allow-unstable':
827 dom
= xml
.dom
.minidom
.parse(argv
[0])
831 Generator(dom
, prefix
, basename
, signal_marshal_prefix
, headers
,
832 end_headers
, not_implemented_func
, allow_havoc
)()