diff --git a/docs/reference/gio/gdbus-codegen.xml b/docs/reference/gio/gdbus-codegen.xml
index b1145e5ef..3e1a9d668 100644
--- a/docs/reference/gio/gdbus-codegen.xml
+++ b/docs/reference/gio/gdbus-codegen.xml
@@ -39,6 +39,8 @@
FILE
+
+
OUTFILE
@@ -69,7 +71,11 @@
arguments on the command line and generates output files.
It currently supports generating C source code (via
) or header (via )
- and Docbook XML (via ).
+ and Docbook XML (via ). Alternatively,
+ more restricted C source code and headers can be generated, which just
+ contain the interface information (as GDBusInterfaceInfo
+ structures) using and
+ .
@@ -90,8 +96,11 @@
For C code generation either that
- generates source code, or that
- generates headers, can be used. These options must be used along with
+ generates source code, that
+ generates headers, that generates
+ interface information source code, or
+ that generates interface information
+ headers, can be used. These options must be used along with
, which is used to specify the file to output to.
@@ -282,8 +291,10 @@
Directory to output generated source to. Equivalent to changing directory before generation.
- This option cannot be used with neither nor
- , and must be used.
+ This option cannot be used with ,
+ , or
+ ; and
+ must be used.
@@ -321,12 +332,52 @@
+
+
+
+
+ If this option is passed, it will generate the header code for the
+ GDBusInterfaceInfo structures only and will write it to
+ the disk by using the path and file name provided by
+ .
+
+
+ Using , or
+ are not allowed to be used along with
+ the and
+ options, because these options
+ are used to generate only one file.
+
+
+
+
+
+
+
+
+ If this option is passed, it will generate the source code for the
+ GDBusInterfaceInfo structures only and will write it to
+ the disk by using the path and file name provided by
+ .
+
+
+ Using , or
+ are not allowed to be used along with
+ the and
+ options, because these options
+ are used to generate only one file.
+
+
+
+
OUTFILE
- The full path where the header () or the source code
- () will be written, using the path and filename provided by
+ The full path where the header (,
+ ) or the source code
+ (, ) will
+ be written, using the path and filename provided by
. The full path could be something like
$($OUTFILE).{c,h}.
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index 032a29ed5..307018571 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -613,6 +613,286 @@ class HeaderCodeGenerator:
# ----------------------------------------------------------------------------------------------------
+class InterfaceInfoHeaderCodeGenerator:
+ def __init__(self, ifaces, namespace, header_name, use_pragma, outfile):
+ self.ifaces = ifaces
+ self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
+ self.header_guard = header_name.upper().replace('.', '_').replace('-', '_').replace('/', '_').replace(':', '_')
+ self.use_pragma = use_pragma
+ self.outfile = outfile
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_header_preamble(self):
+ self.outfile.write(LICENSE_STR.format(config.VERSION))
+ self.outfile.write('\n')
+
+ if self.use_pragma:
+ self.outfile.write('#pragma once\n')
+ else:
+ self.outfile.write('#ifndef __{!s}__\n'.format(self.header_guard))
+ self.outfile.write('#define __{!s}__\n'.format(self.header_guard))
+
+ self.outfile.write('\n')
+ self.outfile.write('#include \n')
+ self.outfile.write('\n')
+ self.outfile.write('G_BEGIN_DECLS\n')
+ self.outfile.write('\n')
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def declare_infos(self):
+ for i in self.ifaces:
+ self.outfile.write('extern const GDBusInterfaceInfo %s_interface;\n' % i.name_lower)
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_header_postamble(self):
+ self.outfile.write('\n')
+ self.outfile.write('G_END_DECLS\n')
+
+ if not self.use_pragma:
+ self.outfile.write('\n')
+ self.outfile.write('#endif /* __{!s}__ */\n'.format(self.header_guard))
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate(self):
+ self.generate_header_preamble()
+ self.declare_infos()
+ self.generate_header_postamble()
+
+# ----------------------------------------------------------------------------------------------------
+
+class InterfaceInfoBodyCodeGenerator:
+ def __init__(self, ifaces, namespace, header_name, outfile):
+ self.ifaces = ifaces
+ self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
+ self.header_name = header_name
+ self.outfile = outfile
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_body_preamble(self):
+ self.outfile.write(LICENSE_STR.format(config.VERSION))
+ self.outfile.write('\n')
+ self.outfile.write('#ifdef HAVE_CONFIG_H\n'
+ '# include "config.h"\n'
+ '#endif\n'
+ '\n'
+ '#include "%s"\n'
+ '\n'
+ '#include \n'
+ % (self.header_name))
+ self.outfile.write('\n')
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_array(self, array_name_lower, element_type, elements):
+ self.outfile.write('const %s * const %s[] =\n' % (element_type, array_name_lower))
+ self.outfile.write('{\n')
+ for (_, name) in sorted(elements, key=utils.version_cmp_key):
+ self.outfile.write(' &%s,\n' % name)
+ self.outfile.write(' NULL,\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ def define_annotations(self, array_name_lower, annotations):
+ if len(annotations) == 0:
+ return
+
+ annotation_pointers = []
+
+ for a in annotations:
+ # Skip internal annotations.
+ if a.key.startswith('org.gtk.GDBus'):
+ continue
+
+ self.define_annotations('%s__%s_annotations' % (array_name_lower, a.key_lower), a.annotations)
+
+ self.outfile.write('const GDBusAnnotationInfo %s__%s_annotation =\n' % (array_name_lower, a.key_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % a.key)
+ self.outfile.write(' (gchar *) "%s",\n' % a.value)
+ if len(a.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s__%s_annotations,\n' % (array_name_lower, a.key_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (a.since, '%s__%s_annotation' % (array_name_lower, a.key_lower))
+ annotation_pointers.append(key)
+
+ self.generate_array(array_name_lower, 'GDBusAnnotationInfo',
+ annotation_pointers)
+
+ def define_args(self, array_name_lower, args):
+ if len(args) == 0:
+ return
+
+ arg_pointers = []
+
+ for a in args:
+ self.define_annotations('%s__%s_arg_annotations' % (array_name_lower, a.name), a.annotations)
+
+ self.outfile.write('const GDBusArgInfo %s__%s_arg =\n' % (array_name_lower, a.name))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % a.name)
+ self.outfile.write(' (gchar *) "%s",\n' % a.signature)
+ if len(a.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s__%s_arg_annotations,\n' % (array_name_lower, a.name))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (a.since, '%s__%s_arg' % (array_name_lower, a.name))
+ arg_pointers.append(key)
+
+ self.generate_array(array_name_lower, 'GDBusArgInfo', arg_pointers)
+
+ def define_infos(self):
+ for i in self.ifaces:
+ self.outfile.write('/* ------------------------------------------------------------------------ */\n')
+ self.outfile.write('/* Definitions for %s */\n' % i.name)
+ self.outfile.write('\n')
+
+ # GDBusMethodInfos.
+ if len(i.methods) > 0:
+ method_pointers = []
+
+ for m in i.methods:
+ self.define_args('%s_interface__%s_method_in_args' % (i.name_lower, m.name_lower), m.in_args)
+ self.define_args('%s_interface__%s_method_out_args' % (i.name_lower, m.name_lower), m.out_args)
+ self.define_annotations('%s_interface__%s_method_annotations' % (i.name_lower, m.name_lower), m.annotations)
+
+ self.outfile.write('const GDBusMethodInfo %s_interface__%s_method =\n' % (i.name_lower, m.name_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % m.name)
+ if len(m.in_args) > 0:
+ self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_method_in_args,\n' % (i.name_lower, m.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no in args */\n')
+ if len(m.out_args) > 0:
+ self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_method_out_args,\n' % (i.name_lower, m.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no out args */\n')
+ if len(m.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_method_annotations,\n' % (i.name_lower, m.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (m.since, '%s_interface__%s_method' % (i.name_lower, m.name_lower))
+ method_pointers.append(key)
+
+ self.generate_array('%s_interface_methods' % i.name_lower,
+ 'GDBusMethodInfo', method_pointers)
+
+ # GDBusSignalInfos.
+ if len(i.signals) > 0:
+ signal_pointers = []
+
+ for s in i.signals:
+ self.define_args('%s_interface__%s_signal_args' % (i.name_lower, s.name_lower), s.args)
+ self.define_annotations('%s_interface__%s_signal_annotations' % (i.name_lower, s.name_lower), s.annotations)
+
+ self.outfile.write('const GDBusSignalInfo %s_interface__%s_signal =\n' % (i.name_lower, s.name_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % s.name)
+ if len(s.args) > 0:
+ self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_signal_args,\n' % (i.name_lower, s.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no args */\n')
+ if len(s.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_signal_annotations,\n' % (i.name_lower, s.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (m.since, '%s_interface__%s_signal' % (i.name_lower, s.name_lower))
+ signal_pointers.append(key)
+
+ self.generate_array('%s_interface_signals' % i.name_lower,
+ 'GDBusSignalInfo', signal_pointers)
+
+ # GDBusPropertyInfos.
+ if len(i.properties) > 0:
+ property_pointers = []
+
+ for p in i.properties:
+ if p.readable and p.writable:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
+ elif p.readable:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE'
+ elif p.writable:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
+ else:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_NONE'
+
+ self.define_annotations('%s_interface__%s_property_annotations' % (i.name_lower, p.name_lower), p.annotations)
+
+ self.outfile.write('const GDBusPropertyInfo %s_interface__%s_property =\n' % (i.name_lower, p.name_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % p.name)
+ self.outfile.write(' (gchar *) "%s",\n' % p.signature)
+ self.outfile.write(' %s,\n' % flags)
+ if len(p.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_property_annotations,\n' % (i.name_lower, p.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (m.since, '%s_interface__%s_property' % (i.name_lower, p.name_lower))
+ property_pointers.append(key)
+
+ self.generate_array('%s_interface_properties' % i.name_lower,
+ 'GDBusPropertyInfo', property_pointers)
+
+ # Finally the GDBusInterfaceInfo.
+ self.define_annotations('%s_interface_annotations' % i.name_lower,
+ i.annotations)
+
+ self.outfile.write('const GDBusInterfaceInfo %s_interface =\n' % i.name_lower)
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % i.name)
+ if len(i.methods) > 0:
+ self.outfile.write(' (GDBusMethodInfo **) %s_interface_methods,\n' % i.name_lower)
+ else:
+ self.outfile.write(' NULL, /* no methods */\n')
+ if len(i.signals) > 0:
+ self.outfile.write(' (GDBusSignalInfo **) %s_interface_signals,\n' % i.name_lower)
+ else:
+ self.outfile.write(' NULL, /* no signals */\n')
+ if len(i.properties) > 0:
+ self.outfile.write(' (GDBusPropertyInfo **) %s_interface_properties,\n' % i.name_lower)
+ else:
+ self.outfile.write( 'NULL, /* no properties */\n')
+ if len(i.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface_annotations,\n' % i.name_lower)
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate(self):
+ self.generate_body_preamble()
+ self.define_infos()
+
+# ----------------------------------------------------------------------------------------------------
+
class CodeGenerator:
def __init__(self, ifaces, namespace, generate_objmanager, header_name,
input_files_basenames, docbook_gen, outfile):
diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py
index 65876a2e8..10ecf7785 100755
--- a/gio/gdbus-2.0/codegen/codegen_main.py
+++ b/gio/gdbus-2.0/codegen/codegen_main.py
@@ -152,7 +152,7 @@ def codegen_main():
arg_parser.add_argument('files', metavar='FILE', nargs='*',
help='D-Bus introspection XML file')
arg_parser.add_argument('--xml-files', metavar='FILE', action='append', default=[],
- help='D-Bus introspection XML file')
+ help=argparse.SUPPRESS)
arg_parser.add_argument('--interface-prefix', metavar='PREFIX', default='',
help='String to strip from D-Bus interface names for code and docs')
arg_parser.add_argument('--c-namespace', metavar='NAMESPACE', default='',
@@ -175,6 +175,10 @@ def codegen_main():
help='Generate C headers')
group.add_argument('--body', action='store_true',
help='Generate C code')
+ group.add_argument('--interface-info-header', action='store_true',
+ help='Generate GDBusInterfaceInfo C header')
+ group.add_argument('--interface-info-body', action='store_true',
+ help='Generate GDBusInterfaceInfo C code')
group = arg_parser.add_mutually_exclusive_group()
group.add_argument('--output', metavar='FILE',
@@ -210,6 +214,24 @@ def codegen_main():
c_file = args.output
header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h'
+ elif args.interface_info_header:
+ if args.output is None:
+ print_error('Using --interface-info-header requires --output')
+ if args.c_generate_object_manager:
+ print_error('--c-generate-object-manager is incompatible with '
+ '--interface-info-header')
+
+ h_file = args.output
+ header_name = os.path.basename(h_file)
+ elif args.interface_info_body:
+ if args.output is None:
+ print_error('Using --interface-info-body requires --output')
+ if args.c_generate_object_manager:
+ print_error('--c-generate-object-manager is incompatible with '
+ '--interface-info-body')
+
+ c_file = args.output
+ header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h'
all_ifaces = []
input_files_basenames = []
@@ -220,7 +242,7 @@ def codegen_main():
all_ifaces.extend(parsed_ifaces)
input_files_basenames.append(os.path.basename(fname))
- if args.annotate != None:
+ if args.annotate is not None:
apply_annotations(all_ifaces, args.annotate)
for i in all_ifaces:
@@ -254,6 +276,23 @@ def codegen_main():
outfile)
gen.generate()
+ if args.interface_info_header:
+ with open(h_file, 'w') as outfile:
+ gen = codegen.InterfaceInfoHeaderCodeGenerator(all_ifaces,
+ args.c_namespace,
+ header_name,
+ args.pragma_once,
+ outfile)
+ gen.generate()
+
+ if args.interface_info_body:
+ with open(c_file, 'w') as outfile:
+ gen = codegen.InterfaceInfoBodyCodeGenerator(all_ifaces,
+ args.c_namespace,
+ header_name,
+ outfile)
+ gen.generate()
+
sys.exit(0)
if __name__ == "__main__":
diff --git a/gio/gdbus-2.0/codegen/dbustypes.py b/gio/gdbus-2.0/codegen/dbustypes.py
index bfc69f596..2b721bfbf 100644
--- a/gio/gdbus-2.0/codegen/dbustypes.py
+++ b/gio/gdbus-2.0/codegen/dbustypes.py
@@ -27,6 +27,25 @@ class Annotation:
self.key = key
self.value = value
self.annotations = []
+ self.since = ''
+
+ def post_process(self, interface_prefix, cns, cns_upper, cns_lower, container):
+ key = self.key
+ overridden_key = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name')
+ if utils.is_ugly_case(overridden_key):
+ self.key_lower = overridden_key.lower()
+ else:
+ if overridden_key:
+ key = overridden_key
+ self.key_lower = utils.camel_case_to_uscore(key).lower().replace('-', '_').replace('.', '_')
+
+ if len(self.since) == 0:
+ self.since = utils.lookup_since(self.annotations)
+ if len(self.since) == 0:
+ self.since = container.since
+
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
class Arg:
def __init__(self, name, signature):
@@ -229,6 +248,8 @@ class Arg:
self.gvalue_get = 'g_value_get_boxed'
self.array_annotation = '(array zero-terminated=1)'
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
class Method:
def __init__(self, name):
@@ -270,6 +291,9 @@ class Method:
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
class Signal:
def __init__(self, name):
self.name = name
@@ -305,6 +329,9 @@ class Signal:
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
class Property:
def __init__(self, name, signature, access):
self.name = name
@@ -356,6 +383,9 @@ class Property:
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
class Interface:
def __init__(self, name):
self.name = name
@@ -429,3 +459,6 @@ class Interface:
for p in self.properties:
p.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)