[vala/wip/dbusgen: 37/60] Initial commit of dbusgen



commit 057211253e408f802a3d3f5b7634e8701d4e81d9
Author: Chris Daley <chebizarro gmail com>
Date:   Mon Nov 20 13:49:16 2017 -0800

    Initial commit of dbusgen

 Makefile.am                            |    1 +
 configure.ac                           |    2 +
 dbusgen/.gitignore                     |    1 +
 dbusgen/Makefile.am                    |   72 ++
 dbusgen/vala-dbus-binding-tool.vala    | 1153 ++++++++++++++++++++++++++++++++
 dbusgen/valadbusgen.pc.in              |   14 +
 dbusgen/valadbusgen.vala               |  201 ++++++
 dbusgen/valadbusnamespacestrategy.vala |   28 +
 dbusgen/valadbusparser.vala            |  406 +++++++++++
 dbusgen/valadbusvariantmodule.vala     |  205 ++++++
 10 files changed, 2083 insertions(+)
---
diff --git a/Makefile.am b/Makefile.am
index e4d46741f..d2313ac07 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,6 +19,7 @@ if ENABLE_VALADOC
 SUBDIRS += \
        libvaladoc \
        valadoc \
+       dbusgen \
        $(NULL)
 endif
 
diff --git a/configure.ac b/configure.ac
index 9d1c97417..4fd9d768a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -178,6 +178,8 @@ AC_CONFIG_FILES([Makefile
            doc/manual/Makefile
            doc/manual/version.xml
            gobject-introspection/Makefile
+           dbusgen/valadbusgen.pc
+           dbusgen/Makefile
            vapigen/vapigen.pc
            vapigen/Makefile
            vapigen/vala-gen-introspect/Makefile
diff --git a/dbusgen/.gitignore b/dbusgen/.gitignore
new file mode 100644
index 000000000..a5294aa13
--- /dev/null
+++ b/dbusgen/.gitignore
@@ -0,0 +1 @@
+valadbusgen
diff --git a/dbusgen/Makefile.am b/dbusgen/Makefile.am
new file mode 100644
index 000000000..d5175eb80
--- /dev/null
+++ b/dbusgen/Makefile.am
@@ -0,0 +1,72 @@
+include $(top_srcdir)/Makefile.common
+
+NULL =
+
+AM_CPPFLAGS = \
+       $(GLIB_CFLAGS) \
+       -I$(top_srcdir)/gee \
+       -I$(top_srcdir)/vala \
+       $(NULL)
+
+bin_PROGRAMS = \
+       valadbusgen \
+       $(NULL)
+
+BUILT_SOURCES = valadbusgen.vala.stamp
+
+valadbusgen_VALASOURCES = \
+       valadbusgen.vala \
+       valadbusparser.vala \
+       valadbusvariantmodule.vala \
+       valadbusnamespacestrategy.vala \
+       $(NULL)
+
+valadbusgen_SOURCES = \
+       valadbusgen.vala.stamp \
+       $(valadbusgen_VALASOURCES:.vala=.c) \
+       $(NULL)
+
+
+valadbusgen.vala.stamp: $(valadbusgen_VALASOURCES)
+       $(VALA_V)$(VALAC) \
+               $(VALAFLAGS) \
+               -C \
+               --vapidir $(top_srcdir)/vapi \
+               --vapidir $(top_srcdir)/gee --pkg gee \
+               --vapidir $(top_srcdir)/vala --pkg vala \
+               --pkg config \
+               $^
+       @touch $@
+
+
+valadbusgen_LDADD = \
+       $(GLIB_LIBS) \
+       $(top_builddir)/vala/libvala@PACKAGE_SUFFIX@.la \
+       $(NULL)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = valadbusgen@PACKAGE_SUFFIX@.pc
+
+valadbusgen@PACKAGE_SUFFIX@.pc: valadbusgen.pc
+       cp $< $@
+
+EXTRA_DIST = \
+       $(valadbusgen_VALASOURCES) \
+       valadbusgen.vala.stamp \
+       $(NULL)
+
+CLEANFILES = \
+       valadbusgen@PACKAGE_SUFFIX@.pc
+       $(NULL)
+
+if ENABLE_UNVERSIONED
+install-exec-hook:
+       cd $(DESTDIR)$(bindir) && $(LN_S) -f valadbusgen@PACKAGE_SUFFIX@$(EXEEXT) valadbusgen$(EXEEXT)
+
+install-data-hook:
+       cd $(DESTDIR)$(pkgconfigdir) && $(LN_S) -f valadbusgen@PACKAGE_SUFFIX@.pc valadbusgen.pc
+endif
+
+MAINTAINERCLEANFILES = \
+       $(valadbusgen_VALASOURCES:.vala=.c) \
+       $(NULL)
diff --git a/dbusgen/vala-dbus-binding-tool.vala b/dbusgen/vala-dbus-binding-tool.vala
new file mode 100644
index 000000000..8a560db67
--- /dev/null
+++ b/dbusgen/vala-dbus-binding-tool.vala
@@ -0,0 +1,1153 @@
+/*
+ * vala-dbus-binding-tool.vala
+ *
+ * (C) 2009 by Didier "Ptitjes" <ptitjes free fr>
+ * (C) 2009-2015 the freesmartphone.org team <fso openphoenux org>
+ *
+ * GPLv3
+ */
+using GLib;
+using Xml;
+using Gee;
+
+public errordomain GeneratorError {
+       FILE_NOT_FOUND,
+       CANT_CREATE_FILE,
+       UNKNOWN_DBUS_TYPE
+}
+
+public enum Synchrony {
+       AUTO,
+       FORCE_SYNC,
+       FORCE_ASYNC
+}
+
+internal class GeneratedNamespace {
+       public GeneratedNamespace parent;
+       public string name;
+       public Gee.Map<string, Xml.Node*> members = new Gee.HashMap<string, Xml.Node*>();
+       public Gee.Map<string, GeneratedNamespace> namespaces = new Gee.HashMap<string, GeneratedNamespace>();
+}
+
+public class BindingGenerator : Object {
+
+       private static Set<string> registered_names = new HashSet<string>();
+       private static int verbosity;
+       private static int errors;
+       private static bool synced;
+
+       static construct {
+               registered_names.add("using");
+               registered_names.add("namespace");
+               registered_names.add("public");
+               registered_names.add("private");
+               registered_names.add("register");
+               registered_names.add("internal");
+               registered_names.add("errordomain");
+               registered_names.add("class");
+               registered_names.add("struct");
+               registered_names.add("new");
+               registered_names.add("for");
+               registered_names.add("while");
+               registered_names.add("foreach");
+               registered_names.add("switch");
+               registered_names.add("catch");
+               registered_names.add("case");
+               registered_names.add("static");
+               registered_names.add("unowned");
+               registered_names.add("weak");
+               registered_names.add("message");
+               registered_names.add("get_type");
+               registered_names.add("dispose");
+               registered_names.add("result");
+       }
+
+       public static void INFO(string msg) {
+               if (verbosity >= 1)
+                       stdout.printf(@"[INFO]  $msg\n");
+       }
+
+       public static void DEBUG(string msg) {
+               if (verbosity >= 2)
+                       stdout.printf(@"[DEBUG] $msg\n");
+       }
+
+       public static void WARN(string msg) {
+               stderr.printf(@"[WARN]  $msg\n");
+       }
+
+       public static void ERROR(string msg) {
+               stderr.printf(@"[ERROR] $msg\n");
+               errors++;
+       }
+
+       public static int main(string[] args) {
+               //FIXME: Convert to OptionEntry
+               string[] split_name = args[0].split("/");
+               string program_name = split_name[split_name.length - 1];
+               string command = string.joinv(" ", args);
+
+               string api_path = null;
+               string output_directory = null;
+               uint dbus_timeout = 120000;
+               synced = true;
+
+               Map<string,string> namespace_renaming = new HashMap<string,string>();
+
+               for (int i = 1; i < args.length; i++) {
+                       string arg = args[i];
+
+                       string[] split_arg = arg.split("=");
+                       switch (split_arg[0]) {
+                       case "-h":
+                       case "--help":
+                               show_usage(program_name);
+                               return 0;
+                       case "-v":
+                               verbosity++;
+                               break;
+                       case "--version":
+                               show_version();
+                               return 0;
+                       case "--api-path":
+                               api_path = split_arg[1];
+                               break;
+                       case "-d":
+                       case "--directory":
+                               output_directory = split_arg[1];
+                               break;
+                       case "--strip-namespace":
+                               namespace_renaming.set(split_arg[1], "");
+                               break;
+                       case "--rename-namespace":
+                               string[] ns_split = split_arg[1].split(":");
+                               namespace_renaming.set(ns_split[0], ns_split[1]);
+                               break;
+                       case "--dbus-timeout":
+                               dbus_timeout = int.parse( split_arg[1] );
+                               break;
+                       case "--no-synced":
+                               synced = false;
+                               break;
+                       default:
+                               stdout.printf("%s: Unknown option %s\n", program_name, arg);
+                               show_usage(program_name);
+                               return 1;
+                       }
+               }
+
+               if (api_path == null)
+                       api_path = "./";
+               if (output_directory == null)
+                       output_directory = ".";
+
+               try {
+                       generate(api_path, output_directory, namespace_renaming, command, dbus_timeout);
+               } catch (GLib.FileError ex) {
+                       ERROR(ex.message);
+                       return 1;
+               } catch (GeneratorError ex) {
+                       ERROR(ex.message);
+                       return 1;
+               }
+
+               if (errors > 0) {
+                       stdout.printf( @"\n$errors errors detected in API files. The generated files will not 
be usable.\n" );
+                       return 1;
+               }
+               return 0;
+       }
+
+       private static void show_version() {
+               stdout.printf(@"Vala D-Bus Binding Tool $(Config.PACKAGE_VERSION)\n");
+               stdout.printf("Written by Didier \"Ptitjes\" and the freesmartphone.org team\n");
+               stdout.printf("This is free software; see the source for copying conditions.\n");
+               stdout.printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR 
PURPOSE.\n");
+       }
+
+       private static void show_usage(string program_name) {
+               stdout.printf("Usage:\n");
+               stdout.printf("  %s [-v] [--version] [--help]\n", program_name);
+               stdout.printf("  %s [--api-path=PATH] [--no-synced] [--dbus-timeout=TIMEOUT] 
[--directory=DIR] [--strip-namespace=NS]* [--rename-namespace=OLD_NS:NEW_NS]*\n", program_name);
+       }
+
+       public static void generate(string api_path, string output_directory,
+                       Map<string,string> namespace_renaming, string command, uint dbus_timeout)
+                       throws GeneratorError, GLib.FileError {
+
+               Parser.init();
+
+               BindingGenerator generator = new BindingGenerator(output_directory, namespace_renaming, 
command, dbus_timeout);
+               generator.generate_bindings(api_path);
+
+               Parser.cleanup();
+       }
+
+       private BindingGenerator(string output_directory, Map<string,string> namespace_renaming, string 
command, uint dbus_timeout) {
+               this.output_directory = output_directory;
+               this.namespace_renaming = namespace_renaming;
+               this.command = command;
+               this.dbus_timeout = dbus_timeout;
+       }
+
+       private string output_directory;
+       private Map<string,string> namespace_renaming;
+       private string command;
+       private uint dbus_timeout;
+       private bool inner_interface_strategy_concat = true;
+
+       private const string FSO_NAMESPACE = "http://www.freesmartphone.org/schemas/DBusSpecExtension";;
+
+       private const string INTERFACE_ELTNAME = "interface";
+       private const string METHOD_ELTNAME = "method";
+       private const string SIGNAL_ELTNAME = "signal";
+       private const string PROPERTY_ELTNAME = "property";
+       private const string ARG_ELTNAME = "arg";
+       private const string NAME_ATTRNAME = "name";
+       private const string TYPE_ATTRNAME = "type";
+       private const string DIRECTION_ATTRNAME = "direction";
+       private const string REPLACED_BY_ATTRNAME = "replaced-by";
+       private const string IN_ATTRVALUE = "in";
+       private const string OUT_ATTRVALUE = "out";
+       private const string ENUMERATION_ELTNAME = "enumeration";
+       private const string MEMBER_ELTNAME = "member";
+       private const string VALUE_ATTRNAME = "value";
+       private const string ERRORDOMAIN_ELTNAME = "errordomain";
+       private const string ERROR_ELTNAME = "error";
+       private const string NO_CONTAINER_ATTRNAME = "no-container";
+       private const string THROWS_ELTNAME = "throws";
+       private const string STRUCT_ELTNAME = "struct";
+       private const string FIELD_ELTNAME = "field";
+       private const string ANNOTATION_ELTNAME = "annotation";
+       private const string DEPRECATED_ELTNAME = "deprecated";
+
+       private void generate_bindings(string api_path)
+                       throws GeneratorError, GLib.FileError {
+
+               if (api_path.has_suffix(".xml")) {
+                       add_api_file(api_path);
+               } else {
+                       GLib.Dir dir = GLib.Dir.open(api_path);
+                       string name;
+                       while ((name = dir.read_name()) != null) {
+                               if (name.has_suffix(".xml")) {
+                                       add_api_file(Path.build_filename(api_path, name));
+                               }
+                       }
+               }
+
+               index_names(root_namespace);
+               generate_namespace(root_namespace);
+       }
+
+       private void add_api_file(string api_file) throws GeneratorError {
+               INFO(@"Adding API file $api_file");
+               // Parse the API document from path
+               Xml.Doc* api_doc = Parser.parse_file(api_file);
+               if (api_doc == null) {
+                       throw new GeneratorError.FILE_NOT_FOUND(api_file);
+               }
+
+               api_docs.add(api_doc);
+
+               preprocess_binding_names(api_doc);
+       }
+
+       private FileStream output;
+
+       private void create_binding_file(string name) throws GeneratorError {
+               output = FileStream.open(name, "w");
+               if (output == null) {
+                       throw new GeneratorError.CANT_CREATE_FILE(name);
+               }
+
+               output.printf(@"/* Generated by vala-dbus-binding-tool $(Config.PACKAGE_VERSION). Do not 
modify! */\n");
+               output.printf(@"/* Generated with: $command */\n");
+               output.printf("using GLib;\n");
+       }
+
+       private Gee.List<Xml.Doc*> api_docs = new Gee.ArrayList<Xml.Doc*>();
+
+       private void preprocess_binding_names(Xml.Doc* api_doc) {
+               for (Xml.Node* iter = api_doc->get_root_element()->children; iter != null; iter = iter->next) 
{
+                       //FIXME: Use $(iter->type) when enum to_string works
+                       DEBUG(@"   Processing $(iter->name) as type %d".printf(iter->type));
+                       if (iter->type != ElementType.ELEMENT_NODE) {
+                               DEBUG(@"      not a node; continuing");
+                               continue;
+                       }
+
+                       if (iter->name != INTERFACE_ELTNAME
+                               && iter->name != ENUMERATION_ELTNAME
+                               && iter->name != ERRORDOMAIN_ELTNAME
+                               && iter->name != STRUCT_ELTNAME) {
+                               DEBUG(@"      not interface or enumeration or errordomain or struct; 
continuing");
+                               continue;
+                       }
+
+                       string no_error_container_string = iter->get_ns_prop(NO_CONTAINER_ATTRNAME, 
FSO_NAMESPACE);
+                       bool no_error_container = (no_error_container_string != null && 
no_error_container_string == "true");
+
+                       string dbus_interface_name = iter->get_prop(NAME_ATTRNAME);
+                       string[] split_name = dbus_interface_name.split(".");
+                       string short_name;
+                       int last_part;
+                       if (iter->name == ERRORDOMAIN_ELTNAME && no_error_container) {
+                               short_name = "Error";
+                               last_part = split_name.length;
+                       } else {
+                               short_name = split_name[split_name.length - 1];
+                               last_part = split_name.length - 1;
+                       }
+
+                       // Removing stripped root namespaces
+                       int i = 0;
+                       for (; i < last_part; i++) {
+                               string part = split_name[i];
+                               if (namespace_renaming.get(part) != "") break;
+                       }
+
+                       // Traversing inner namespaces
+                       GeneratedNamespace ns = root_namespace;
+                       for (; i < last_part; i++) {
+                               string part = split_name[i];
+
+                               if (namespace_renaming.has_key(part) && namespace_renaming.get(part) != "") {
+                                       part = namespace_renaming.get(part);
+                               }
+
+                               if (ns.members.has_key(part) && inner_interface_strategy_concat) {
+                                       if (ns.namespaces.has_key(part)) {
+                                               GeneratedNamespace child = ns.namespaces.get(part);
+                                               foreach (string interf_name in child.members.keys) {
+                                                       Xml.Node* interf = child.members.get(interf_name);
+                                                       ns.members.set(part + interf_name, interf);
+                                               }
+                                               ns.namespaces.unset(part);
+                                               child.parent = null;
+                                       }
+
+                                       break;
+                               }
+
+                               GeneratedNamespace child = null;
+                               if (ns.namespaces.has_key(part)) {
+                                       child = ns.namespaces.get(part);
+                               } else {
+                                       child = new GeneratedNamespace();
+                                       child.parent = ns;
+                                       child.name = part;
+                                       ns.namespaces.set(part, child);
+                               }
+
+                               if (ns.members.has_key(part)) {
+                                               child.members.set(part, ns.members.get(part));
+                                               ns.members.unset(part);
+                               }
+
+                               ns = child;
+                       }
+
+                       string interface_name = null;
+                       if (inner_interface_strategy_concat) {
+                               StringBuilder name_builder = new StringBuilder();
+                               // Concatenating last inner namespaces
+                               for (; i < last_part; i++) {
+                                       name_builder.append(split_name[i]);
+                               }
+                               name_builder.append(short_name);
+                               interface_name = name_builder.str;
+
+                               if (ns.namespaces.has_key(short_name)) {
+                                       GeneratedNamespace child = ns.namespaces.get(short_name);
+                                       foreach (string interf_name in child.members.keys) {
+                                               Xml.Node* interf = child.members.get(interf_name);
+                                               ns.members.set(short_name + interf_name, interf);
+                                       }
+                                       ns.namespaces.unset(short_name);
+                                       child.parent = null;
+                               }
+                       } else {
+                               if (ns.namespaces.has_key(short_name)) {
+                                       ns = ns.namespaces.get(short_name);
+                               }
+                               interface_name = short_name;
+                       }
+
+                       if (!ns.members.has_key(interface_name)) {
+                               ns.members.set(interface_name, iter);
+                       } else {
+                               Xml.Node* iter2 = ns.members.get(interface_name);
+                               var name = iter2->get_prop(NAME_ATTRNAME);
+                               ERROR(@"$interface_name has been added already as namespace $name");
+                       }
+               }
+       }
+
+       private void index_names(GeneratedNamespace ns) {
+               if (ns.members.size > 0) {
+                       string namespace_name = string.joinv(".", get_namespace_path(ns));
+
+                       foreach (string name in ns.members.keys) {
+                               Xml.Node* api = ns.members.get(name);
+                               string dbus_name = api->get_prop(NAME_ATTRNAME);
+                               if (api->name == ERRORDOMAIN_ELTNAME) {
+                                       INFO(@"Registering new errordomain $dbus_name");
+                                       error_name_index.set(dbus_name, namespace_name + "." + name);
+                               } else {
+                                       name_index.set(dbus_name, namespace_name + "." + name);
+                               }
+                       }
+               }
+
+               foreach (string name in ns.namespaces.keys) {
+                       GeneratedNamespace child = ns.namespaces.get(name);
+
+                       index_names(child);
+               }
+       }
+
+       private string[] get_namespace_path(GeneratedNamespace ns) {
+               string[] reversed_namespace_names = new string[0];
+               GeneratedNamespace a_namespace = ns;
+               while (a_namespace.name != null) {
+                       reversed_namespace_names += a_namespace.name;
+                       a_namespace = a_namespace.parent;
+               }
+
+               string[] namespace_names = new string[0];
+               for (int i = reversed_namespace_names.length - 1; i >= 0; i--) {
+                       namespace_names += reversed_namespace_names[i];
+               }
+
+               return namespace_names;
+       }
+
+       private GeneratedNamespace root_namespace = new GeneratedNamespace();
+
+       private Map<string, string> name_index = new HashMap<string, string>();
+       private Map<string, string> error_name_index = new HashMap<string, string>();
+
+       private void generate_namespace(GeneratedNamespace ns)
+                       throws GeneratorError {
+               if (ns.members.size > 0) {
+                       string[] namespace_names = get_namespace_path(ns);
+
+                       create_binding_file(output_directory + "/" + string.joinv("-", 
namespace_names).down() + ".vala");
+
+                       foreach (string name in namespace_names) {
+                               output.printf("\n");
+                               output.printf("%snamespace %s {\n", get_indent(), name);
+                               update_indent(+1);
+                       }
+
+                       foreach (string name in ns.members.keys) {
+                               Xml.Node* api = ns.members.get(name);
+
+                               switch (api->name) {
+                               case INTERFACE_ELTNAME:
+                                       generate_interface(name, api, Synchrony.AUTO);
+                                       generate_proxy_getter(api, name);
+                                       if ( synced )
+                                               generate_interface(name, api, Synchrony.FORCE_SYNC);
+                                               generate_proxy_getter(api, name, Synchrony.FORCE_SYNC);
+                                       break;
+                               case ENUMERATION_ELTNAME:
+                                       generate_enumeration(name, api);
+                                       break;
+                               case ERRORDOMAIN_ELTNAME:
+                                       generate_errordomain(name, api);
+                                       break;
+                               case STRUCT_ELTNAME:
+                                       generate_explicit_struct(name, api);
+                                       break;
+                               }
+                       }
+
+                       foreach (string name in namespace_names) {
+                               update_indent(-1);
+                               output.printf("%s}\n", get_indent());
+                       }
+
+                       output = null;
+               }
+
+               foreach (string name in ns.namespaces.keys) {
+                       GeneratedNamespace child = ns.namespaces.get(name);
+
+                       generate_namespace(child);
+               }
+       }
+
+       private Gee.Map<string, string> structs_to_generate = new Gee.HashMap<string, string>();
+
+       private void generate_interface(string interface_name, Xml.Node* node, Synchrony synchrony = 
Synchrony.AUTO)
+                       throws GeneratorError {
+               string dbus_name = node->get_prop(NAME_ATTRNAME);
+               string namespace_name = get_namespace_name(interface_name);
+
+               assert( synchrony != Synchrony.FORCE_ASYNC ); // not supported yet, maybe never
+
+               var iface_name = ( synchrony == Synchrony.FORCE_SYNC ) ? interface_name + "Sync" : 
interface_name;
+
+               INFO(@"Generating interface $dbus_name");
+
+               output.printf("\n");
+               output.printf("%s[DBus (name = \"%s\", timeout = %u)]\n", get_indent(), dbus_name, 
dbus_timeout);
+               output.printf("%spublic interface %s : GLib.Object {\n", get_indent(), iface_name);
+               update_indent(+1);
+
+               generate_members(node, iface_name, get_namespace_name(dbus_name), synchrony);
+
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+
+               while (structs_to_generate.size != 0) {
+                       Gee.Map<string, string> structs_to_generate_now = new Gee.HashMap<string, string>();
+                       structs_to_generate_now.set_all(structs_to_generate);
+                       foreach (var entry in structs_to_generate_now.entries) {
+                               generate_struct(entry.key, entry.value, namespace_name);
+                       }
+                       structs_to_generate.unset_all(structs_to_generate_now);
+               }
+       }
+
+       private void generate_enumeration(string enumeration_name, Xml.Node* node) throws GeneratorError {
+               string dbus_name = node->get_prop(NAME_ATTRNAME);
+               string type = node->get_prop(TYPE_ATTRNAME);
+               bool string_enum = type == "s";
+
+               INFO(@"Generating enumeration $type for $dbus_name");
+
+               output.printf("\n");
+               output.printf("%s[DBus%s]\n", get_indent(), string_enum ? " (use_string_marshalling = true)" 
: "");
+               output.printf("%spublic enum %s {\n", get_indent(), enumeration_name);
+               update_indent(+1);
+
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case MEMBER_ELTNAME:
+                               string member_name = normalized_to_upper_case(iter->get_prop(NAME_ATTRNAME));
+                               string member_value = iter->get_prop(VALUE_ATTRNAME);
+                               if (string_enum) {
+                                       output.printf("%s[DBus (value=\"%s\")]\n", get_indent(), 
member_value);
+                               }
+                               output.printf("%s%s%s%s\n", get_indent(), member_name, string_enum ? "" : " = 
%s".printf(member_value), iter->next == null ? "" : ",");
+                               break;
+                       }
+               }
+
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+       }
+
+       private void generate_errordomain(string errordomain_name, Xml.Node* node)
+                       throws GeneratorError {
+               string dbus_name = node->get_prop(NAME_ATTRNAME);
+
+               INFO(@"Generating errordomain $errordomain_name for $dbus_name");
+
+               output.printf("\n");
+               output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), dbus_name);
+               output.printf("%spublic errordomain %s {\n", get_indent(), errordomain_name);
+               update_indent(+1);
+
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case ERROR_ELTNAME:
+                               string dbus_error_name = iter->get_prop(NAME_ATTRNAME);
+                               string error_name = camel_case_to_upper_case(dbus_error_name);
+
+                               output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), dbus_error_name);
+                               output.printf("%s%s%s\n", get_indent(), error_name, iter->next == null ? "" : 
",");
+                               break;
+                       }
+               }
+
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+       }
+
+       private void generate_explicit_struct(string struct_name, Xml.Node* node)
+                       throws GeneratorError {
+               string dbus_name = node->get_prop(NAME_ATTRNAME);
+
+               INFO(@"Generating explicit struct $struct_name for $dbus_name");
+
+               output.printf("\n");
+               output.printf("%spublic struct %s {\n", get_indent(), struct_name);
+               update_indent(+1);
+
+               string ctor_signature = "%spublic %s (".printf(get_indent(), struct_name);
+               string ctor_body = "";
+
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case FIELD_ELTNAME:
+                               string field_name = transform_registered_name(iter->get_prop(NAME_ATTRNAME));
+                               string field_type = "unknown";
+                               try {
+                                       field_type = translate_type(iter->get_prop(TYPE_ATTRNAME),
+                                               iter->get_ns_prop(TYPE_ATTRNAME, FSO_NAMESPACE),
+                                               struct_name, get_namespace_name(dbus_name));
+                               } catch (GeneratorError.UNKNOWN_DBUS_TYPE ex) {
+                                       ERROR(@"In struct $struct_name field $field_name : Unknown dbus type 
$(ex.message)");
+                               }
+
+                               output.printf("%spublic %s %s;\n", get_indent(), field_type, field_name);
+                                       ctor_signature += "%s %s, ".printf(field_type, field_name);
+                                       ctor_body += "%sthis.%s = %s;\n".printf(get_indent(+1), field_name, 
field_name);
+                                       break;
+                               }
+                       }
+               string constructor = "%s ) {\n%s%s}".printf( ctor_signature.substring( 0, 
ctor_signature.length-2 ), ctor_body, get_indent() );
+
+               output.printf("\n%s\n", constructor);
+
+               INFO(@"Generating from_variant method for $struct_name");
+               output.printf("\n%spublic static %s from_variant (Variant v) {\n", get_indent(), struct_name);
+               update_indent(1);
+               output.printf("%sreturn v as %s;\n", get_indent(), struct_name);
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+               update_indent(-1);
+               output.printf("%s}", get_indent());
+       }
+
+       private void generate_struct(string name, string content_signature, string dbus_namespace)
+                                       throws GeneratorError {
+               INFO(@"Generating struct $name w/ signature $content_signature in dbus namespace 
$dbus_namespace");
+
+               output.printf("\n");
+               output.printf("%spublic struct %s {\n", get_indent(), name);
+               update_indent(+1);
+
+               int attribute_number = 1;
+               string signature = content_signature;
+               string tail = null;
+               while (signature != "") {
+                       string type = parse_type(signature, out tail, "", dbus_namespace);
+                       output.printf("%spublic %s attr%d;\n", get_indent(), type, attribute_number);
+                       attribute_number++;
+                       signature = tail;
+               }
+
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+       }
+
+       private void generate_members(Xml.Node* node, string interface_name, string dbus_namespace, Synchrony 
synchrony)
+                                       throws GeneratorError {
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case METHOD_ELTNAME:
+                               generate_method(iter, interface_name, dbus_namespace, synchrony);
+                               break;
+                       case SIGNAL_ELTNAME:
+                               generate_signal(iter, interface_name, dbus_namespace);
+                               break;
+                       case PROPERTY_ELTNAME:
+                               generate_property(iter, interface_name, dbus_namespace);
+                               break;
+                       case ERROR_ELTNAME:
+                               generate_error(iter, interface_name);
+                               break;
+                       }
+               }
+       }
+
+       private void generate_method(Xml.Node* node, string interface_name, string dbus_namespace, Synchrony 
synchrony)
+                                       throws GeneratorError {
+
+               string realname = node->get_prop(NAME_ATTRNAME);
+               string name = transform_registered_name(uncapitalize(node->get_prop(NAME_ATTRNAME)));
+
+               INFO(@"   Generating method $name (originally $realname) for $interface_name");
+
+               int unknown_param_count = 0;
+
+               int out_param_count = get_out_parameter_count(node);
+
+               bool first_param = true;
+               bool first_error = true;
+               StringBuilder args_builder = new StringBuilder();
+               StringBuilder throws_builder = new StringBuilder();
+               string return_value_type = "void";
+               bool async_method = false;
+               bool noreply_method = false;
+               bool deprecated_method = false;
+               string deprecated_method_replaced_by = "";
+
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case ARG_ELTNAME:
+                               string? param_name = transform_registered_name(iter->get_prop(NAME_ATTRNAME));
+                               if(param_name == null || param_name == "") {
+                                       param_name = "param%i".printf(unknown_param_count);
+                                       unknown_param_count++;
+                               }
+                               string param_type = "unknown";
+                               try {
+                                       param_type = translate_type(iter->get_prop(TYPE_ATTRNAME),
+                                               iter->get_ns_prop(TYPE_ATTRNAME, FSO_NAMESPACE),
+                                               get_struct_name(interface_name, param_name),
+                                               dbus_namespace);
+                               } catch (GeneratorError.UNKNOWN_DBUS_TYPE ex) {
+                                       ERROR(@"In interface $interface_name method $name : Unknown dbus type 
$(ex.message)");
+                               }
+                               string? param_dir = iter->get_prop(DIRECTION_ATTRNAME);
+
+                               switch (param_dir) {
+                               case OUT_ATTRVALUE:
+                                       if (param_type == null) {
+                                               param_type = "void";
+                                       }
+                                       if (out_param_count != 1) {
+                                               if (!first_param) {
+                                                       args_builder.append(", ");
+                                               }
+
+                                               args_builder.append("out ");
+                                               args_builder.append(param_type);
+                                               args_builder.append(" ");
+                                               args_builder.append(param_name);
+                                               first_param = false;
+                                       } else {
+                                               return_value_type = param_type;
+                                       }
+                                       break;
+                               case IN_ATTRVALUE:
+                               default:
+                                       if (!first_param) {
+                                               args_builder.append(", ");
+                                       }
+
+                                       args_builder.append(param_type);
+                                       args_builder.append(" ");
+                                       args_builder.append(param_name);
+                                       first_param = false;
+                                       break;
+                               }
+                               break;
+                       case THROWS_ELTNAME:
+                               string errordomain_name = null;
+                               string fso_type = iter->get_prop(TYPE_ATTRNAME);
+                               if (fso_type != null) {
+                                       errordomain_name = error_name_index.get(fso_type);
+                               }
+                               if (errordomain_name == null) {
+                                       ERROR(@"In interface $interface_name method $name : Unknown dbus 
error $(fso_type)");
+                                       errordomain_name = "<unknown>";
+                               }
+
+                               if (!first_error) {
+                                       throws_builder.append(", ");
+                               }
+                               throws_builder.append(errordomain_name);
+                               first_error = false;
+                               break;
+                       case ANNOTATION_ELTNAME:
+                               string annotation_name = iter->get_prop(NAME_ATTRNAME);
+                               if (annotation_name == "org.freedesktop.DBus.GLib.Async") {
+                                       async_method = true;
+                               }
+                               if (annotation_name == "org.freedesktop.DBus.GLib.NoReply") {
+                                       noreply_method = true;
+                               }
+                               break;
+                       case DEPRECATED_ELTNAME:
+                               deprecated_method = true;
+                               deprecated_method_replaced_by = iter->get_prop(REPLACED_BY_ATTRNAME);
+                               break;
+                       }
+               }
+
+               if (async_method && noreply_method) {
+                       WARN(@"In interface $interface_name method $name : Requested both async and noreply; 
which is not supported by Vala. Will force sync.");
+                       async_method = false;
+               }
+
+               if (noreply_method && out_param_count > 0) {
+                       ERROR(@"In interface $interface_name method $name : noreply methods are not allowed 
to have out parameters!");
+               }
+
+               if (!first_error) {
+                       throws_builder.append(", ");
+               }
+               throws_builder.append("DBusError, IOError");
+
+               switch ( synchrony )
+               {
+                       case Synchrony.FORCE_SYNC:
+                               async_method = false;
+                               break;
+                       case Synchrony.FORCE_ASYNC:
+                               async_method = true;
+                               break;
+                       default:
+                               /* AUTO, leave it like it is */
+                               break;
+               }
+
+               output.printf("\n");
+               if (noreply_method) {
+                       output.printf("%s[DBus (name = \"%s\", no_reply = true)]\n", get_indent(), realname);
+               } else {
+                       output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), realname);
+               }
+               if (deprecated_method) {
+                       if (deprecated_method_replaced_by.length == 0)
+                               output.printf("[Version (deprecated = true)]\n");
+                       else output.printf("[Version (deprecated = true, replacement = 
\"%s\")]".printf(deprecated_method_replaced_by));
+               }
+               output.printf("%spublic abstract%s %s %s(%s) throws %s;\n",
+                       get_indent(), (async_method ? " async" : ""), return_value_type, name, 
args_builder.str, throws_builder.str);
+       }
+
+       private int get_out_parameter_count(Xml.Node* node) {
+               int out_param_count = 0;
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+                       if (iter->name != ARG_ELTNAME)
+                               continue;
+                       if (iter->get_prop(DIRECTION_ATTRNAME) != OUT_ATTRVALUE)
+                               continue;
+
+                       out_param_count++;
+               }
+               return out_param_count;
+       }
+
+       private void generate_signal(Xml.Node* node, string interface_name, string dbus_namespace)
+                                       throws GeneratorError {
+               string realname = node->get_prop(NAME_ATTRNAME);
+               string name = transform_registered_name(uncapitalize(node->get_prop(NAME_ATTRNAME)));
+
+               INFO(@"   Generating signal $name (originally $realname) for $interface_name");
+
+               int unknown_param_count = 0;
+
+               bool first_param = true;
+               StringBuilder args_builder = new StringBuilder();
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       if (iter->name != ARG_ELTNAME)
+                               continue;
+
+                       string param_name = transform_registered_name(iter->get_prop(NAME_ATTRNAME));
+                       if(param_name == null || param_name == "") {
+                               param_name = "param%i".printf(unknown_param_count);
+                               unknown_param_count++;
+                       }
+                       string param_type = "unknown";
+                       try {
+                               param_type = translate_type(iter->get_prop(TYPE_ATTRNAME),
+                                       iter->get_ns_prop(TYPE_ATTRNAME, FSO_NAMESPACE),
+                                       interface_name + capitalize(param_name),
+                                       dbus_namespace);
+                       } catch (GeneratorError.UNKNOWN_DBUS_TYPE ex) {
+                               ERROR(@"In interface $interface_name signal $name : Unknown dbus type 
$(ex.message)");
+                       }
+
+                       if (!first_param) {
+                               args_builder.append(", ");
+                       }
+
+                       args_builder.append(param_type);
+                       args_builder.append(" ");
+                       args_builder.append(param_name);
+                       first_param = false;
+               }
+
+               output.printf("\n");
+               output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), realname);
+               output.printf("%spublic signal void %s(%s);\n",
+                       get_indent(), name, args_builder.str);
+       }
+
+       private void generate_property(Xml.Node* node, string interface_name, string dbus_namespace)
+       {
+               string realname = node->get_prop(NAME_ATTRNAME);
+               string name = transform_registered_name(uncapitalize(node->get_prop(NAME_ATTRNAME)));
+
+               string typename = "unknown";
+               string rawtype = "";
+               try {
+                       rawtype = node->get_prop(TYPE_ATTRNAME);
+                       typename = translate_type(rawtype,
+                               node->get_ns_prop(TYPE_ATTRNAME, FSO_NAMESPACE),
+                               interface_name + capitalize(name),
+                               dbus_namespace);
+               } catch (GeneratorError ex) {
+                       if (ex is GeneratorError.UNKNOWN_DBUS_TYPE) {
+                               ERROR(@"In interface $interface_name property $name : Unknown dbus type 
$(ex.message)");
+                       } else {
+                               ERROR(@"In interface $interface_name property $name : Error $(ex.message)");
+                       }
+               }
+
+               string accesstype = "readwrite";
+               if (node->has_prop("access") != null) {
+                       accesstype = node->get_prop("access");
+                       if (accesstype != "readwrite" && accesstype != "readonly" && accesstype != "read") {
+                               ERROR(@"In interface $interface_name property $name : Unknown access type: 
$accesstype");
+                       }
+               }
+
+               INFO(@"   Generating property $name (originally $realname) of type $typename for 
$interface_name");
+
+               string owned_specifier = is_simple_type(rawtype) ? "" : "owned";
+               string accessimpl = (accesstype == "readonly" || accesstype == "read") ? @"$owned_specifier 
get;" : @"$owned_specifier get; set;";
+
+               output.printf("\n");
+               output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), realname);
+               output.printf("%spublic abstract %s %s { %s }\n", get_indent(), typename, name, accessimpl);
+       }
+
+       private void generate_error(Xml.Node* node, string interface_name)
+                                       throws GeneratorError {
+       }
+
+       private void generate_proxy_getter(Xml.Node* node, owned string interface_name, Synchrony synchrony = 
Synchrony.AUTO)
+                                       throws GeneratorError {
+                       bool async_method = true;
+                       switch ( synchrony )
+                       {
+                               case Synchrony.FORCE_SYNC:
+                                       async_method = false;
+                                       break;
+                               case Synchrony.FORCE_ASYNC:
+                                       async_method = true;
+                                       break;
+                               default:
+                                       /* AUTO, leave it like it is */
+                                       break;
+                       }
+                       if ( !async_method ) {
+                               interface_name = interface_name + "Sync";
+                       }
+       }
+
+       private string translate_type(string type, string? fso_type, string type_name, string dbus_namespace)
+                                       throws GeneratorError {
+               string tail = null;
+               if (fso_type != null) {
+                       var vala_type = name_index.get(fso_type);
+                       if (vala_type == null) {
+                               throw new GeneratorError.UNKNOWN_DBUS_TYPE(fso_type);
+                       }
+                       return vala_type + (type.has_prefix("a") ? "[]" : "");
+               }
+               return parse_type(type, out tail, type_name, dbus_namespace).replace("][", ",");
+       }
+
+       private bool is_simple_type(string type)
+       {
+               switch (type) {
+                       case "b":
+                       case "i":
+                       case "n":
+                       case "q":
+                       case "t":
+                       case "u":
+                       case "x":
+                       case "d":
+                               return true;
+               }
+               return false;
+       }
+
+       private string parse_type(string type, out string tail, string type_name, string dbus_namespace)
+                                       throws GeneratorError {
+               tail = type.substring(1);
+               if (type.has_prefix("y")) {
+                       return "uint8"; // uchar only works since post-vala 0.8.0 (see 
c4cf64b6590e5cce21febf98b1f3ff935d921fd5)
+               } else if (type.has_prefix("b")) {
+                       return "bool";
+               } else if (type.has_prefix("n") || type.has_prefix("i")) {
+                       return "int";
+               } else if (type.has_prefix("q") || type.has_prefix("u")) {
+                       return "uint";
+               } else if (type.has_prefix("x")) {
+                       return "int64";
+               } else if (type.has_prefix("t")) {
+                       return "uint64";
+               } else if (type.has_prefix("d")) {
+                       return "double";
+               } else if (type.has_prefix("s")) {
+                       return "string";
+               } else if (type.has_prefix("o")) {
+                       return "GLib.ObjectPath"; // needs to be prefixed post vala 0.9.2 (see 
142ca8fe0e5b4b8058d4913e909ccc820b6f7768 and 9a650b7f3bb796c36e31a7c649c7f59e8292631e)
+               } else if (type.has_prefix("v")) {
+                       return "GLib.Variant";
+               } else if (type.has_prefix("a{") && type.has_suffix("}")) {
+                       string tmp_type = get_subsignature(type, '{', '}', out tail);
+                       string tail2 = null;
+                       string tail3 = null;
+
+                       StringBuilder vala_type = new StringBuilder();
+                       vala_type.append("GLib.HashTable<");
+                       string foo = parse_type(tmp_type, out tail2, plural_to_singular(type_name) + "Key", 
dbus_namespace);
+                       vala_type.append(foo);
+                       vala_type.append(", ");
+
+                       string value_type = parse_type(tail2, out tail3, plural_to_singular(type_name), 
dbus_namespace);
+                       if (value_type == "GLib.Value") {
+                               value_type += "?";
+                       }
+                       vala_type.append(value_type);
+                       vala_type.append(">");
+
+                       return vala_type.str;
+               } else if (type.has_prefix("a")) {
+                       string tail2 = null;
+                       return parse_type(tail, out tail2, plural_to_singular(type_name), dbus_namespace) + 
"[]";
+               } else if (type.has_prefix("(") && type.has_suffix(")")) {
+                       string sub_type = get_subsignature(type, '(', ')', out tail);
+                       int number = 2;
+                       string unique_type_name = type_name +"Struct";
+                       while (structs_to_generate.has_key(unique_type_name)) {
+                               unique_type_name = "%s%d".printf(unique_type_name, number++);
+                       }
+
+                       if (!name_index.has_key(dbus_namespace + "." + unique_type_name)) {
+                               structs_to_generate.set(unique_type_name, sub_type);
+                       }
+                       return unique_type_name;
+               }
+               throw new GeneratorError.UNKNOWN_DBUS_TYPE(@"dbustype: '$type' unknown");
+       }
+
+       private string get_struct_name(string interface_name, string param_name) {
+               string striped_interface_name = strip_namespace(interface_name);
+               string name = capitalize(param_name);
+               return name.has_prefix(striped_interface_name) ? name : striped_interface_name + name;
+       }
+
+       private string get_namespace_name(string interface_name) {
+               long last_dot = interface_name.length - 1;
+               while (last_dot >= 0 && interface_name[last_dot] != '.') {
+                       last_dot--;
+               }
+               return interface_name.substring(0, last_dot);
+       }
+
+       private string strip_namespace(string interface_name) {
+               long last_dot = interface_name.length - 1;
+               while (last_dot >= 0 && interface_name[last_dot] != '.') {
+                       last_dot--;
+               }
+               return interface_name.substring(last_dot + 1, interface_name.length - last_dot - 1);
+       }
+
+       private string capitalize(string type_name) {
+               string[] parts = type_name.split("_");
+               StringBuilder capitalized_name = new StringBuilder();
+               foreach (string part in parts) {
+                       if (part != "") {
+                               capitalized_name.append(part.substring(0, 1).up());
+                               capitalized_name.append(part.substring(1, part.length - 1));
+                       }
+               }
+               return capitalized_name.str;
+       }
+
+       private string uncapitalize(string name) {
+               StringBuilder uncapitalized_name = new StringBuilder();
+               for (int i = 0; i < name.length; i++) {
+                       unichar c = name[i];
+                       if (c.isupper()) {
+                               if (i > 0)
+                                       uncapitalized_name.append_unichar('_');
+                               uncapitalized_name.append_unichar(c.tolower());
+                       } else {
+                               uncapitalized_name.append_unichar(c);
+                       }
+               }
+               return transform_registered_name(uncapitalized_name.str);
+       }
+
+       private string normalized_to_upper_case(string name) {
+               return name.replace("-", "_").up();
+       }
+
+       private string camel_case_to_upper_case(string name) {
+               return uncapitalize(name).up();
+       }
+
+       private string transform_registered_name(string? name) {
+               if (name != null && registered_names.contains(name)) {
+                       return name + "_";
+               }
+               return name;
+       }
+
+       private string plural_to_singular(string type_name) {
+               if (type_name.has_suffix("ies"))
+                       return type_name.substring(0, type_name.length - 3) + "y";
+               else if (type_name.has_suffix("ses"))
+                       return type_name.substring(0, type_name.length - 2);
+               else if (type_name.has_suffix("us"))
+                       return type_name;
+               else if (type_name.has_suffix("i"))
+                       return type_name.substring(0, type_name.length - 1) + "o";
+               else if (type_name.has_suffix("s"))
+                       return type_name.substring(0, type_name.length - 1);
+               else return type_name;
+       }
+
+       private int indentSize = 0;
+
+       private string get_indent(int offset = 0) {
+               return string.nfill(indentSize + offset, '\t');
+       }
+
+       private void update_indent(int increment) {
+               indentSize += increment;
+       }
+
+       private string get_subsignature( string s, char start, char end, out string tail ) {
+               unowned char[] data = (char[])s;
+               int iter = 0;
+               int counter = 0;
+               int begin = 0;
+               char c;
+
+               for(iter = 0; iter < s.length; iter++) {
+                       c = data[iter];
+                       if(c == start) {
+                               if( counter == 0 ) {
+                                       begin = iter;
+                               }
+                               counter ++;
+                       }
+                       else if(c == end) {
+                               counter --;
+                               if(counter == 0) {
+                                       break;
+                               }
+                       }
+               }
+               tail = s.substring( iter + 1, -1 );
+               var tmp = s.substring( begin + 1, iter - begin - 1);
+               return tmp;
+    }
+}
diff --git a/dbusgen/valadbusgen.pc.in b/dbusgen/valadbusgen.pc.in
new file mode 100644
index 000000000..3ce60dbff
--- /dev/null
+++ b/dbusgen/valadbusgen.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+bindir=@bindir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+includedir=@includedir@
+
+vapidir=${datadir}/vala/vapi
+vapidir_versioned=${datadir}/vala@PACKAGE_SUFFIX@/vapi
+
+Name: valadbusgen
+Description: Vala DBus Interface Generator
+Version: @VERSION@
diff --git a/dbusgen/valadbusgen.vala b/dbusgen/valadbusgen.vala
new file mode 100644
index 000000000..71f847660
--- /dev/null
+++ b/dbusgen/valadbusgen.vala
@@ -0,0 +1,201 @@
+/* valadbusigen.vala
+ *
+ * Copyright (C) 2017 Chris Daley
+ * Copyright (C) 2006-2010  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Chris Daley <chebizarro gmail com>
+ *     Jürg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+public class Vala.DBusGen {
+
+       public class ConcatenationStrategy : NamespaceStrategy {
+
+               public override string? get_namespace (string ns) {
+                       return null;
+               }
+
+               public override string get_name (string ns) {
+
+                       string[] parts = ns.split(".");
+                       StringBuilder capitalized_name = new StringBuilder();
+                       foreach (string part in parts) {
+                               if (part != "") {
+                                       capitalized_name.append(part.substring(0, 1).up());
+                                       capitalized_name.append(part.substring(1, part.length - 1));
+                               }
+                       }
+                       return capitalized_name.str;
+               }
+
+       }
+
+       static string directory;
+       static bool version;
+       static bool quiet_mode = false;
+       static bool disable_warnings;
+       [CCode (array_length = false, array_null_terminated = true)]
+       static string[] sources;
+       [CCode (array_length = false, array_null_terminated = true)]
+       static string[] vapi_directories;
+       [CCode (array_length = false, array_null_terminated = true)]
+       static string[] packages;
+       static bool nostdpkg;
+       static int dbus_timeout = 120000;
+
+       CodeContext context;
+
+       const OptionEntry[] options = {
+               { "vapidir", 0, 0, OptionArg.FILENAME_ARRAY, ref vapi_directories, "Look for package bindings 
in DIRECTORY", "DIRECTORY..." },
+               { "nostdpkg", 0, 0, OptionArg.NONE, ref nostdpkg, "Do not include standard packages", null },
+               { "pkg", 0, 0, OptionArg.STRING_ARRAY, ref packages, "Include binding for PACKAGE", 
"PACKAGE..." },
+               { "directory", 'd', 0, OptionArg.FILENAME, ref directory, "Output directory", "DIRECTORY" },
+               { "disable-warnings", 0, 0, OptionArg.NONE, ref disable_warnings, "Disable warnings", null },
+               { "dbus-timeout", 0, 0, OptionArg.INT, ref dbus_timeout, "DBus timeout", null },
+               { "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null },
+               { "quiet", 'q', 0, OptionArg.NONE, ref quiet_mode, "Do not print messages to the console", 
null },
+               { OPTION_REMAINING, 0, 0, OptionArg.FILENAME_ARRAY, ref sources, null, "FILE..." },
+               { null }
+       };
+
+       private int quit () {
+               if (context.report.get_errors () == 0) {
+                       if (!quiet_mode) {
+                               stdout.printf ("Generation succeeded - %d warning(s)\n", 
context.report.get_warnings ());
+                       }
+                       return 0;
+               } else {
+                       if (!quiet_mode) {
+                               stdout.printf ("Generation failed: %d error(s), %d warning(s)\n", 
context.report.get_errors (), context.report.get_warnings ());
+                       }
+                       return 1;
+               }
+       }
+
+       private int run () {
+               context = new CodeContext ();
+
+               context.report.enable_warnings = !disable_warnings;
+               context.vapi_directories = vapi_directories;
+               context.report.set_verbose_errors (!quiet_mode);
+               CodeContext.push (context);
+
+               context.profile = Profile.GOBJECT;
+               context.add_define ("GOBJECT");
+               context.target_glib_major = 2;
+               context.target_glib_minor = 40;
+
+               for (int i = 16; i <= 40; i += 2) {
+                       context.add_define ("GLIB_2_%d".printf (i));
+               }
+
+               context.add_external_package ("glib-2.0");
+               context.add_external_package ("gobject-2.0");
+
+               if (packages != null) {
+                       foreach (string package in packages) {
+                               context.add_external_package (package);
+                       }
+                       packages = null;
+               }
+
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+
+               var valaparser = new Parser ();
+               valaparser.parse (context);
+
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+
+               foreach (string source in sources) {
+                       if (FileUtils.test (source, FileTest.EXISTS) && source.has_suffix (".xml")) {
+                               var source_file = new SourceFile (context, SourceFileType.SOURCE, source);
+                               source_file.explicit = true;
+                               context.add_source_file (source_file);
+                       } else {
+                               Report.error (null, "%s not found".printf (source));
+                       }
+               }
+
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+
+               var parser = new DBusParser ();
+               parser.dbus_timeout = dbus_timeout;
+               parser.namespace_strategy = new ConcatenationStrategy ();
+               parser.parse (context);
+
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+
+               context.check ();
+
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+
+               var interface_writer = new CodeWriter (CodeWriterType.FAST);
+
+               foreach (SourceFile source in context.get_source_files ()) {
+                       string filename = Path.get_basename (source.filename);
+
+                       if (filename.has_suffix (".xml")) {
+                               if (directory != null) {
+                                       filename = Path.build_path ("/", directory, filename + ".vala");
+                               }
+                               interface_writer.write_file (context, filename + ".vala");
+                       }
+               }
+
+               return quit ();
+       }
+
+       static int main (string[] args) {
+               Intl.setlocale (LocaleCategory.ALL, "");
+               try {
+                       var opt_context = new OptionContext ("- Vala DBus Interface Generator");
+                       opt_context.set_help_enabled (true);
+                       opt_context.add_main_entries (options, null);
+                       opt_context.parse (ref args);
+               } catch (OptionError e) {
+                       stdout.printf ("%s\n", e.message);
+                       stdout.printf ("Run '%s --help' to see a full list of available command line 
options.\n", args[0]);
+                       return 1;
+               }
+
+               if (version) {
+                       stdout.printf ("Vala DBus Interface Generator %s\n", Vala.BUILD_VERSION);
+                       return 0;
+               }
+
+               if (sources == null) {
+                       stderr.printf ("No source file specified.\n");
+                       return 1;
+               }
+
+               var DBusGen = new DBusGen ();
+               return DBusGen.run ();
+       }
+}
diff --git a/dbusgen/valadbusnamespacestrategy.vala b/dbusgen/valadbusnamespacestrategy.vala
new file mode 100644
index 000000000..3c95f1b6e
--- /dev/null
+++ b/dbusgen/valadbusnamespacestrategy.vala
@@ -0,0 +1,28 @@
+/* valadbusnamespacestrategy.vala
+ *
+ * Copyright (C) 2017 Chris Daley
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Chris Daley <chebizarro gmail com>
+ */
+
+public abstract class Vala.NamespaceStrategy {
+
+       public abstract string? get_namespace (string ns);
+
+       public abstract string get_name (string ns);
+}
diff --git a/dbusgen/valadbusparser.vala b/dbusgen/valadbusparser.vala
new file mode 100644
index 000000000..b1649bd5d
--- /dev/null
+++ b/dbusgen/valadbusparser.vala
@@ -0,0 +1,406 @@
+/* valadbusparser.vala
+ *
+ * Copyright (C) 2017 Chris Daley
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Chris Daley <chebizarro gmail com>
+ */
+
+using GLib;
+
+/**
+ * Code visitor parsing all DBus Interface files.
+ */
+public class Vala.DBusParser : CodeVisitor {
+
+       private CodeContext context;
+
+       private DBusVariantModule dbus_module;
+
+       private SourceFile current_source_file;
+
+       private CodeNode current_node;
+       private Namespace current_ns;
+       private Interface current_iface;
+       private Callable current_method;
+       private Parameter current_param;
+       private Property current_property;
+
+       private MarkupReader reader;
+
+       private MarkupTokenType current_token;
+       private SourceLocation begin;
+       private SourceLocation end;
+
+       public int dbus_timeout { get; set; }
+
+       public NamespaceStrategy namespace_strategy { get; set; }
+
+       /**
+        * Parse all DBus Interface files in the specified code context and
+        * build a code tree.
+        *
+        * @param context a code context
+        */
+       public void parse (CodeContext context) {
+
+               this.context = context;
+               current_ns = context.root;
+
+               dbus_module = new DBusVariantModule (context);
+
+               context.accept (this);
+       }
+
+       public override void visit_source_file (SourceFile source_file) {
+               if (source_file.filename.has_suffix (".xml")) {
+                       parse_file (source_file);
+               }
+       }
+
+       private void parse_file (SourceFile source_file) {
+
+               this.current_source_file = source_file;
+               this.reader = new MarkupReader (source_file.filename);
+
+               current_source_file.add_node (context.root);
+
+               next ();
+               next ();
+               next ();
+
+               parse_node ();
+               this.current_source_file = null;
+
+               this.reader = null;
+
+       }
+
+       private void parse_node () {
+               start_element ("node");
+
+               next ();
+
+               while (current_token == MarkupTokenType.START_ELEMENT) {
+
+                       switch (reader.name) {
+                               case "interface":
+                                       parse_namespace ();
+                                       parse_interface ();
+                                       break;
+                               //case "node":
+                               //      parse_node ();
+                                       //break;
+                               default:
+                                       parse_extension ();
+                                       break;
+                       }
+               }
+
+               end_element ("node");
+       }
+
+       private void parse_namespace () {
+               string? name = reader.get_attribute ("name");
+
+               if (name == null) {
+                       Report.error (get_current_src (), "Interface declarations require a name attribute");
+                       return;
+               }
+
+               string? ns_name = namespace_strategy.get_namespace (name);
+
+               if (ns_name != null) {
+                       var ns = new Namespace (ns_name, get_current_src ());
+                       current_ns.add_namespace (ns);
+                       current_ns = ns;
+               }
+       }
+
+       private void parse_interface () {
+               start_element ("interface");
+
+               string? name = reader.get_attribute ("name");
+
+               if (name == null) {
+                       Report.error (get_current_src (), "Interface declarations require a name attribute");
+                       return;
+               }
+
+               string iface_name = namespace_strategy.get_name (name);
+
+               current_node = current_iface = new Interface (iface_name, get_current_src ());
+
+               current_iface.access = SymbolAccessibility.PUBLIC;
+               current_iface.add_prerequisite (new ObjectType ((ObjectTypeSymbol) dbus_module.gobject_type));
+               current_iface.set_attribute_string ("DBus", "name", name);
+               current_iface.set_attribute_integer ("DBus", "timeout", dbus_timeout);
+
+               current_ns.add_interface (current_iface);
+
+               next ();
+
+               parse_interface_body ();
+
+               end_element ("interface");
+
+       }
+
+       private void parse_interface_body () {
+
+               while (current_token == MarkupTokenType.START_ELEMENT) {
+
+                       switch (reader.name) {
+                               case "annotation":
+                                       parse_annotation ();
+                                       break;
+                               case "method":
+                                       parse_method ();
+                                       break;
+                               case "signal":
+                                       parse_signal ();
+                                       break;
+                               case "property":
+                                       parse_property ();
+                                       break;
+                               default:
+                                       parse_extension ();
+                                       break;
+                       }
+               }
+       }
+
+       private void parse_annotation () {
+               start_element ("annotation");
+
+               string? anno = reader.get_attribute ("name");
+
+               if (anno == null) {
+                       Report.error (get_current_src (), "Annotations require a name attribute");
+                       return;
+               }
+
+               switch (anno) {
+
+                       case "org.freedesktop.DBus.Deprecated":
+                               current_node.set_attribute_bool ("Version", "deprecated", true);
+                               string? replaced_by = reader.get_attribute ("replaced-by");
+                               if (replaced_by != null) {
+                                       current_node.set_attribute_string ("Version", "replacement", 
replaced_by);
+                               }
+                               break;
+                       case "org.freedesktop.DBus.GLib.Async":
+                               if (current_node is Method) {
+                                       ((Method)current_method).is_async_callback = true;
+                               }
+                               break;
+                       case "org.freedesktop.DBus.GLib.NoReply":
+                               if (current_node is Method) {
+                                       current_node.set_attribute_bool ("DBus", "no_reply", true);
+                               }
+                               break;
+                       default:
+                               break;
+               }
+
+               next ();
+
+               end_element ("annotation");
+       }
+
+       private void parse_method () {
+               start_element ("method");
+               string? name = reader.get_attribute ("name");
+
+               SourceReference src = new SourceReference (current_source_file, begin, end);
+
+               if (name == null) {
+                       Report.error (src, "Interface method declarations require a name attribute");
+                       return;
+               }
+
+               DataType return_type = new VoidType ();
+
+               current_node = current_method = new Method (name, return_type, src);
+               current_iface.add_method ((Method)current_method);
+               ((Method)current_method).is_abstract = true;
+               ((Method)current_method).access = SymbolAccessibility.PUBLIC;
+
+               next ();
+
+               parse_method_body ();
+
+               end_element ("method");
+       }
+
+       private void parse_property () {
+
+               start_element ("property");
+
+               Map<string,string> attribs = reader.get_attributes ();
+
+               if (attribs["name"] == null) {
+                       Report.error (get_current_src (), "Interface property declarations require a name 
attribute");
+                       return;
+               }
+
+               if (attribs["type"] == null) {
+                       Report.error (get_current_src (), "Interface property declarations require a type 
attribute");
+                       return;
+               }
+
+               DataType type = dbus_module.get_dbus_type (attribs["type"]);
+
+               PropertyAccessor get_access = null;
+               PropertyAccessor set_access = null;
+
+               if (attribs["access"] == "read" || attribs["access"] == "readwrite") {
+                       get_access = new PropertyAccessor (true, false, false, type, null, get_current_src 
());
+               }
+               if (attribs["access"] == "write" || attribs["access"] == "readwrite") {
+                       set_access = new PropertyAccessor (false, true, false, type, null, get_current_src 
());
+               }
+
+               current_node = current_property = new Property (attribs["name"], type, get_access, 
set_access, get_current_src ());
+               current_property.is_abstract = true;
+               current_iface.add_property (current_property);
+
+               next ();
+
+               while (current_token == MarkupTokenType.START_ELEMENT) {
+                       if (reader.name == "annotation") {
+                               parse_annotation ();
+                       }
+               }
+
+               end_element ("property");
+
+       }
+
+       private void parse_method_body () {
+
+               while (current_token == MarkupTokenType.START_ELEMENT) {
+
+                       switch (reader.name) {
+                               case "annotation":
+                                       parse_annotation ();
+                                       break;
+                               case "arg":
+                                       parse_arg ();
+                                       break;
+                               default:
+                                       parse_extension ();
+                                       break;
+                       }
+               }
+       }
+
+       private void parse_arg () {
+               start_element ("arg");
+
+               Map<string,string> attribs = reader.get_attributes ();
+
+               if (attribs["name"] == null) {
+                       Report.error (get_current_src () , "Formal Parameters require names");
+                       return;
+               }
+
+               var type = dbus_module.get_dbus_type (attribs["type"]);
+               type.value_owned = false;
+
+               current_node = current_param = new Parameter (attribs["name"], type, get_current_src ());
+
+               current_method.add_parameter (current_param);
+
+               if (current_method is Method) {
+                       if (attribs["direction"] != null && attribs["direction"] == "out") {
+                               current_param.direction = ParameterDirection.OUT;
+                               type.value_owned = true;
+                       }
+               }
+
+               next ();
+               end_element ("arg");
+       }
+
+       private void parse_extension () {
+               next ();
+       }
+
+       private void parse_signal () {
+               start_element ("signal");
+
+               string? name = reader.get_attribute ("name");
+
+               if (name == null) {
+                       Report.error (get_current_src (), "Interface signal declarations require a name 
attribute");
+                       return;
+               }
+
+               current_node = current_method = new Signal (name, new VoidType ());
+               current_iface.add_signal ((Signal)current_node);
+               ((Signal)current_node).access = SymbolAccessibility.PUBLIC;
+
+               next ();
+
+               parse_method_body ();
+
+               end_element ("signal");
+       }
+
+       private void next () {
+               current_token = reader.read_token (out begin, out end);
+       }
+
+       private void start_element (string name) {
+
+               if (current_token != MarkupTokenType.START_ELEMENT || reader.name != name) {
+                       // error
+                       Report.error (get_current_src (), "expected start element of `%s'".printf (name));
+               }
+       }
+
+       private void end_element (string name) {
+               while (current_token != MarkupTokenType.END_ELEMENT || reader.name != name) {
+                       Report.warning (get_current_src (), "expected end element of `%s'".printf (name));
+                       skip_element ();
+               }
+               next ();
+       }
+
+       private SourceReference get_current_src () {
+               return new SourceReference (this.current_source_file, begin, end);
+       }
+
+       private void skip_element () {
+               next ();
+
+               int level = 1;
+               while (level > 0) {
+                       if (current_token == MarkupTokenType.START_ELEMENT) {
+                               level++;
+                       } else if (current_token == MarkupTokenType.END_ELEMENT) {
+                               level--;
+                       } else if (current_token == MarkupTokenType.EOF) {
+                               Report.error (get_current_src (), "unexpected end of file");
+                               break;
+                       }
+                       next ();
+               }
+       }
+
+}
diff --git a/dbusgen/valadbusvariantmodule.vala b/dbusgen/valadbusvariantmodule.vala
new file mode 100644
index 000000000..d4f2046d2
--- /dev/null
+++ b/dbusgen/valadbusvariantmodule.vala
@@ -0,0 +1,205 @@
+/* valadbusvariantmodule.vala
+ *
+ * Copyright (C) 2017 Chris Daley
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Chris Daley <chebizarro gmail com>
+ */
+
+public class Vala.DBusVariantModule {
+
+       private CodeContext context;
+
+       public Symbol root_symbol;
+
+       public DataType void_type = new VoidType ();
+       public DataType bool_type;
+       public DataType char_type;
+       public DataType uchar_type;
+       public DataType? unichar_type;
+       public DataType short_type;
+       public DataType ushort_type;
+       public DataType int_type;
+       public DataType uint_type;
+       public DataType long_type;
+       public DataType ulong_type;
+       public DataType int8_type;
+       public DataType uint8_type;
+       public DataType int16_type;
+       public DataType uint16_type;
+       public DataType int32_type;
+       public DataType uint32_type;
+       public DataType int64_type;
+       public DataType uint64_type;
+       public DataType string_type;
+       public DataType regex_type;
+       public DataType float_type;
+       public DataType double_type;
+       public TypeSymbol gtype_type;
+       public TypeSymbol gobject_type;
+       public ErrorType gerror_type;
+       public Class glist_type;
+       public Class gslist_type;
+       public Class gnode_type;
+       public Class gqueue_type;
+       public Class gvaluearray_type;
+       public TypeSymbol gstringbuilder_type;
+       public TypeSymbol garray_type;
+       public TypeSymbol gbytearray_type;
+       public TypeSymbol gptrarray_type;
+       public TypeSymbol gthreadpool_type;
+       public DataType gdestroynotify_type;
+       public DataType gquark_type;
+       public Struct gvalue_type;
+       public Class gvariant_type;
+       public Struct mutex_type;
+       public Struct gmutex_type;
+       public Struct grecmutex_type;
+       public Struct grwlock_type;
+       public Struct gcond_type;
+       public Class gsource_type;
+       public TypeSymbol type_module_type;
+       public TypeSymbol dbus_proxy_type;
+
+       public DBusVariantModule (CodeContext context) {
+
+               this.context = context;
+
+               root_symbol = context.root;
+
+               bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
+               char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
+               uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
+               short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
+               ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
+               int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
+               uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
+               long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
+               ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
+               int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
+               uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
+               int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
+               uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
+               int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
+               uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
+               int64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int64"));
+               uint64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint64"));
+               float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
+               double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
+               string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
+               var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
+               if (unichar_struct != null) {
+                       unichar_type = new IntegerType (unichar_struct);
+               }
+               var glib_ns = root_symbol.scope.lookup ("GLib");
+
+               gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
+               gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
+               gerror_type = new ErrorType (null, null);
+               glist_type = (Class) glib_ns.scope.lookup ("List");
+               gslist_type = (Class) glib_ns.scope.lookup ("SList");
+               gnode_type = (Class) glib_ns.scope.lookup ("Node");
+               gqueue_type = (Class) glib_ns.scope.lookup ("Queue");
+               gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray");
+               gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
+               garray_type = (TypeSymbol) glib_ns.scope.lookup ("Array");
+               gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
+               gptrarray_type = (TypeSymbol) glib_ns.scope.lookup ("PtrArray");
+               gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
+               gdestroynotify_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("DestroyNotify"));
+
+               gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
+               gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
+               gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
+               gsource_type = (Class) glib_ns.scope.lookup ("Source");
+
+               gmutex_type = (Struct) glib_ns.scope.lookup ("Mutex");
+               grecmutex_type = (Struct) glib_ns.scope.lookup ("RecMutex");
+               grwlock_type = (Struct) glib_ns.scope.lookup ("RWLock");
+               gcond_type = (Struct) glib_ns.scope.lookup ("Cond");
+
+               mutex_type = grecmutex_type;
+       }
+
+       public DataType? get_dbus_type (string type) {
+               if (VariantType.string_is_valid (type)) {
+                       VariantType vrnt = new VariantType (type);
+                       return get_variant_type (vrnt);
+
+               } else {
+                       string emessage = "The Variant Type string: %s is invalid".printf (type);
+                       Report.error (null, emessage);
+                       return null;
+               }
+       }
+
+       private DataType get_variant_type (VariantType type) {
+
+               if (type.equal (VariantType.BOOLEAN)) {
+                       return bool_type;
+               } else if (type.equal (VariantType.BYTE)) {
+                       return char_type;
+               } else if (type.equal (VariantType.INT16)) {
+                       return int16_type;
+               } else if (type.equal (VariantType.UINT16)) {
+                       return uint16_type;
+               } else if (type.equal (VariantType.INT32)) {
+                       return int32_type;
+               } else if (type.equal (VariantType.UINT32)) {
+                       return uint32_type;
+               } else if (type.equal (VariantType.INT64)) {
+                       return int64_type;
+               } else if (type.equal (VariantType.UINT64)) {
+                       return uint64_type;
+               } else if (type.equal (VariantType.DOUBLE)) {
+                       return double_type;
+               } else if (type.equal (VariantType.STRING)) {
+                       return string_type.copy ();
+               } else if (type.equal (VariantType.OBJECT_PATH)) {
+                       return string_type;
+               } else if (type.equal (VariantType.SIGNATURE)) {
+                       return string_type;
+               } else if (type.equal (VariantType.VARIANT) || type.equal (VariantType.ANY) || type.equal 
(VariantType.BASIC) || type.equal (VariantType.MAYBE) || type.equal (VariantType.TUPLE)) {
+                       return new ObjectType ((ObjectTypeSymbol) gvariant_type);
+               }
+
+               return new ObjectType ((ObjectTypeSymbol) gvariant_type);
+
+               if (type.equal (VariantType.UNIT)) {
+                       return string_type;
+               } else if (type.equal (VariantType.MAYBE)) {
+                       return string_type;
+               } else if (type.equal (VariantType.OBJECT_PATH_ARRAY) || type.equal (VariantType.ARRAY) || 
type.equal (VariantType.STRING_ARRAY) || type.equal (VariantType.BYTESTRING_ARRAY)) {
+
+                       var element = new ObjectType ((ObjectTypeSymbol) gvariant_type); //get_variant_type 
(type.element ());
+                       return new ArrayType (element, 0, null);
+
+               } else if (type.equal (VariantType.DICT_ENTRY)) {
+                       return string_type;
+               } else if (type.equal (VariantType.DICTIONARY)) {
+                       return string_type;
+               } else if (type.equal (VariantType.BYTESTRING)) {
+                       return string_type;
+               } else if (type.equal (VariantType.VARDICT)) {
+                       return string_type;
+               } else if (type.equal (VariantType.HANDLE)) {
+                       return string_type;
+               }
+
+       }
+
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]