[telepathy-mission-control/master] tools: update from telepathy-glib

Simon McVittie simon.mcvittie at collabora.co.uk
Wed Jun 10 08:32:14 PDT 2009


This requires a minor change to the invocation: when making docs,
explicitly allow dangling references to interfaces.
---
 doc/Makefile.am                |    4 +-
 tools/doc-generator.xsl        |  432 ++++++++++++++++++++++++++---
 tools/glib-client-gen.py       |  597 ++++++++++++++++-----------------------
 tools/glib-ginterface-gen.py   |  101 +++++---
 tools/glib-gtypes-generator.py |   82 +++++-
 tools/libglibcodegen.py        |    9 +-
 tools/libtpcodegen.py          |   67 +++--
 7 files changed, 824 insertions(+), 468 deletions(-)

diff --git a/doc/Makefile.am b/doc/Makefile.am
index b6c81ab..41c97bc 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -5,7 +5,9 @@ SPECS_DOC = mc-dbus-iface.html
 all-local: $(SPECS_DOC)
 
 $(SPECS_DOC): $(top_srcdir)/xml/all.xml $(wildcard $(top_srcdir)/xml/*.xml) $(top_srcdir)/tools/doc-generator.xsl
-	$(XSLTPROC) --xinclude --novalid $(top_srcdir)/tools/doc-generator.xsl $< > $@
+	$(XSLTPROC) --xinclude --novalid \
+		--param allow-undefined-interfaces "true()" \
+		$(top_srcdir)/tools/doc-generator.xsl $< > $@
 
 clean-local:
 	rm -f $(SPECS_DOC)
diff --git a/tools/doc-generator.xsl b/tools/doc-generator.xsl
index 24e8545..76fc969 100644
--- a/tools/doc-generator.xsl
+++ b/tools/doc-generator.xsl
@@ -23,10 +23,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
   xmlns:html="http://www.w3.org/1999/xhtml"
   exclude-result-prefixes="tp html">
-  <!--Don't move the declaration of the HTML namespace up here - XMLNSs
+  <!--Don't move the declaration of the HTML namespace up here — XMLNSs
   don't work ideally in the presence of two things that want to use the
   absence of a prefix, sadly. -->
 
+  <xsl:param name="allow-undefined-interfaces" select="false()"/>
+
   <xsl:template match="html:* | @*" mode="html">
     <xsl:copy>
       <xsl:apply-templates mode="html"/>
@@ -39,6 +41,86 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     </xsl:call-template>
   </xsl:template>
 
+  <!-- tp:dbus-ref: reference a D-Bus interface, signal, method or property -->
+  <xsl:template match="tp:dbus-ref" mode="html">
+    <xsl:variable name="name">
+      <xsl:choose>
+        <xsl:when test="@namespace">
+          <xsl:value-of select="@namespace"/>
+          <xsl:text>.</xsl:text>
+        </xsl:when>
+      </xsl:choose>
+      <xsl:value-of select="string(.)"/>
+    </xsl:variable>
+
+    <xsl:choose>
+      <xsl:when test="//interface[@name=$name]
+        or //interface/method[concat(../@name, '.', @name)=$name]
+        or //interface/signal[concat(../@name, '.', @name)=$name]
+        or //interface/property[concat(../@name, '.', @name)=$name]
+        or //interface[@name=concat($name, '.DRAFT')]
+        or //interface/method[
+          concat(../@name, '.', @name)=concat($name, '.DRAFT')]
+        or //interface/signal[
+          concat(../@name, '.', @name)=concat($name, '.DRAFT')]
+        or //interface/property[
+          concat(../@name, '.', @name)=concat($name, '.DRAFT')]
+        ">
+        <a xmlns="http://www.w3.org/1999/xhtml" href="#{$name}">
+          <xsl:value-of select="string(.)"/>
+        </a>
+      </xsl:when>
+
+      <xsl:when test="$allow-undefined-interfaces">
+        <span xmlns="http://www.w3.org/1999/xhtml" title="defined elsewhere">
+          <xsl:value-of select="string(.)"/>
+        </span>
+      </xsl:when>
+
+      <xsl:otherwise>
+        <xsl:message terminate="yes">
+          <xsl:text>ERR: cannot find D-Bus interface, method, </xsl:text>
+          <xsl:text>signal or property called '</xsl:text>
+          <xsl:value-of select="$name"/>
+          <xsl:text>'&#10;</xsl:text>
+        </xsl:message>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- tp:member-ref: reference a property of the current interface -->
+  <xsl:template match="tp:member-ref" mode="html">
+    <xsl:variable name="prefix" select="concat(ancestor::interface/@name,
+      '.')"/>
+    <xsl:variable name="name" select="string(.)"/>
+
+    <xsl:if test="not(ancestor::interface)">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: Cannot use tp:member-ref when not in an</xsl:text>
+        <xsl:text> &lt;interface&gt;&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:choose>
+      <xsl:when test="ancestor::interface/signal[@name=$name]"/>
+      <xsl:when test="ancestor::interface/method[@name=$name]"/>
+      <xsl:when test="ancestor::interface/property[@name=$name]"/>
+      <xsl:otherwise>
+        <xsl:message terminate="yes">
+          <xsl:text>ERR: interface </xsl:text>
+          <xsl:value-of select="ancestor::interface/@name"/>
+          <xsl:text> has no signal/method/property called </xsl:text>
+          <xsl:value-of select="$name"/>
+          <xsl:text>&#10;</xsl:text>
+        </xsl:message>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <a xmlns="http://www.w3.org/1999/xhtml" href="#{$prefix}{$name}">
+      <xsl:value-of select="$name"/>
+    </a>
+  </xsl:template>
+
   <xsl:template match="*" mode="identity">
     <xsl:copy>
       <xsl:apply-templates mode="identity"/>
@@ -46,18 +128,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   </xsl:template>
 
   <xsl:template match="tp:docstring">
-    <xsl:apply-templates select="text() | html:* | tp:rationale" mode="html"/>
+    <xsl:apply-templates mode="html"/>
   </xsl:template>
 
   <xsl:template match="tp:added">
-    <p class="added">Added in version <xsl:value-of select="@version"/>.
+    <p class="added" xmlns="http://www.w3.org/1999/xhtml">Added in
+      version <xsl:value-of select="@version"/>.
       <xsl:apply-templates select="node()" mode="html"/></p>
   </xsl:template>
 
   <xsl:template match="tp:changed">
     <xsl:choose>
       <xsl:when test="node()">
-        <p class="changed">Changed in version <xsl:value-of select="@version"/>:
+        <p class="changed" xmlns="http://www.w3.org/1999/xhtml">Changed in
+          version <xsl:value-of select="@version"/>:
           <xsl:apply-templates select="node()" mode="html"/></p>
       </xsl:when>
       <xsl:otherwise>
@@ -68,8 +152,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   </xsl:template>
 
   <xsl:template match="tp:deprecated">
-    <p class="deprecated">Deprecated since version
-      <xsl:value-of select="@version"/>.
+    <p class="deprecated" xmlns="http://www.w3.org/1999/xhtml">Deprecated
+      since version <xsl:value-of select="@version"/>.
       <xsl:apply-templates select="node()" mode="html"/></p>
   </xsl:template>
 
@@ -131,7 +215,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
   <xsl:template match="/tp:spec/tp:copyright">
     <div xmlns="http://www.w3.org/1999/xhtml">
-      <xsl:apply-templates/>
+      <xsl:apply-templates mode="text"/>
     </div>
   </xsl:template>
   <xsl:template match="/tp:spec/tp:license">
@@ -224,6 +308,21 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   </xsl:template>
 
   <xsl:template match="tp:flags">
+
+    <xsl:if test="not(@name) or @name = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @name on a tp:flags type&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="not(@type) or @type = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @type on tp:flags type</xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
     <h3>
       <a name="type-{@name}">
         <xsl:value-of select="@name"/>
@@ -264,6 +363,21 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   </xsl:template>
 
   <xsl:template match="tp:enum">
+
+    <xsl:if test="not(@name) or @name = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @name on a tp:enum type&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="not(@type) or @type = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @type on tp:enum type</xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
     <h3 xmlns="http://www.w3.org/1999/xhtml">
       <a name="type-{@name}">
         <xsl:value-of select="@name"/>
@@ -304,11 +418,38 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   </xsl:template>
 
   <xsl:template match="property">
+
+    <xsl:if test="not(parent::interface)">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: property </xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:text> does not have an interface as parent&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="not(@name) or @name = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @name on a property of </xsl:text>
+        <xsl:value-of select="../@name"/>
+        <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="not(@type) or @type = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @type on property </xsl:text>
+        <xsl:value-of select="concat(../@name, '.', @name)"/>
+        <xsl:text>: '</xsl:text>
+        <xsl:value-of select="@access"/>
+        <xsl:text>'&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
     <dt xmlns="http://www.w3.org/1999/xhtml">
       <a name="{concat(../@name, '.', @name)}">
         <code><xsl:value-of select="@name"/></code>
       </a>
-      <xsl:text> - </xsl:text>
+      <xsl:text> − </xsl:text>
       <code><xsl:value-of select="@type"/></code>
       <xsl:call-template name="parenthesized-tp-type"/>
       <xsl:text>, </xsl:text>
@@ -323,8 +464,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
           <xsl:text>read/write</xsl:text>
         </xsl:when>
         <xsl:otherwise>
-          <xsl:text>access: </xsl:text>
-          <code><xsl:value-of select="@access"/></code>
+          <xsl:message terminate="yes">
+            <xsl:text>ERR: unknown or missing value for </xsl:text>
+            <xsl:text>@access on property </xsl:text>
+            <xsl:value-of select="concat(../@name, '.', @name)"/>
+            <xsl:text>: '</xsl:text>
+            <xsl:value-of select="@access"/>
+            <xsl:text>'&#10;</xsl:text>
+          </xsl:message>
         </xsl:otherwise>
       </xsl:choose>
     </dt>
@@ -339,7 +486,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   <xsl:template match="tp:property">
     <dt xmlns="http://www.w3.org/1999/xhtml">
       <xsl:if test="@name">
-        <code><xsl:value-of select="@name"/></code> -
+        <code><xsl:value-of select="@name"/></code> −
       </xsl:if>
       <code><xsl:value-of select="@type"/></code>
     </dt>
@@ -356,7 +503,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       <h3>
         <a name="type-{@name}">
           <xsl:value-of select="@name"/>
-        </a> - a{
+        </a> − a{
         <xsl:for-each select="tp:member">
           <xsl:value-of select="@type"/>
           <xsl:text>: </xsl:text>
@@ -386,15 +533,30 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
   <xsl:template match="tp:simple-type | tp:enum | tp:flags | tp:external-type"
     mode="in-index">
-    - <xsl:value-of select="@type"/>
+    − <xsl:value-of select="@type"/>
   </xsl:template>
 
   <xsl:template match="tp:simple-type">
+
+    <xsl:if test="not(@name) or @name = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @name on a tp:simple-type&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="not(@type) or @type = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @type on tp:simple-type</xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
     <div xmlns="http://www.w3.org/1999/xhtml" class="simple-type">
       <h3>
         <a name="type-{@name}">
           <xsl:value-of select="@name"/>
-        </a> - <xsl:value-of select="@type"/>
+        </a> − <xsl:value-of select="@type"/>
       </h3>
       <div class="docstring">
         <xsl:apply-templates select="tp:docstring"/>
@@ -406,25 +568,40 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   </xsl:template>
 
   <xsl:template match="tp:external-type">
+
+    <xsl:if test="not(@name) or @name = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @name on a tp:external-type&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="not(@type) or @type = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @type on tp:external-type</xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
     <div xmlns="http://www.w3.org/1999/xhtml" class="external-type">
       <dt>
         <a name="type-{@name}">
           <xsl:value-of select="@name"/>
-        </a> - <xsl:value-of select="@type"/>
+        </a> − <xsl:value-of select="@type"/>
       </dt>
       <dd>Defined by: <xsl:value-of select="@from"/></dd>
     </div>
   </xsl:template>
 
   <xsl:template match="tp:struct" mode="in-index">
-    - ( <xsl:for-each select="tp:member">
+    − ( <xsl:for-each select="tp:member">
           <xsl:value-of select="@type"/>
           <xsl:if test="position() != last()">, </xsl:if>
         </xsl:for-each> )
   </xsl:template>
 
   <xsl:template match="tp:mapping" mode="in-index">
-    - a{ <xsl:for-each select="tp:member">
+    − a{ <xsl:for-each select="tp:member">
           <xsl:value-of select="@type"/>
           <xsl:if test="position() != last()"> &#x2192; </xsl:if>
         </xsl:for-each> }
@@ -435,7 +612,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       <h3>
         <a name="type-{@name}">
           <xsl:value-of select="@name"/>
-        </a> - (
+        </a> − (
         <xsl:for-each select="tp:member">
           <xsl:value-of select="@type"/>
           <xsl:text>: </xsl:text>
@@ -471,6 +648,64 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   </xsl:template>
 
   <xsl:template match="method">
+
+    <xsl:if test="not(parent::interface)">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: method </xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:text> does not have an interface as parent&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="not(@name) or @name = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @name on a method of </xsl:text>
+        <xsl:value-of select="../@name"/>
+        <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:for-each select="arg">
+      <xsl:if test="not(@type) or @type = ''">
+        <xsl:message terminate="yes">
+          <xsl:text>ERR: an arg of method </xsl:text>
+          <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+          <xsl:text> has no type</xsl:text>
+        </xsl:message>
+      </xsl:if>
+      <xsl:choose>
+        <xsl:when test="@direction='in'">
+          <xsl:if test="not(@name) or @name = ''">
+            <xsl:message terminate="yes">
+              <xsl:text>ERR: an 'in' arg of method </xsl:text>
+              <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+              <xsl:text> has no name</xsl:text>
+            </xsl:message>
+          </xsl:if>
+        </xsl:when>
+        <xsl:when test="@direction='out'">
+          <!-- FIXME: This is commented out until someone with a lot of time
+          on their hands goes through the spec adding names to all the "out"
+          arguments
+
+          <xsl:if test="not(@name) or @name = ''">
+            <xsl:message terminate="no">
+              <xsl:text>INFO: an 'out' arg of method </xsl:text>
+              <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+              <xsl:text> has no name</xsl:text>
+            </xsl:message>
+          </xsl:if>-->
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:message terminate="yes">
+            <xsl:text>ERR: an arg of method </xsl:text>
+            <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+            <xsl:text> has direction neither 'in' nor 'out'</xsl:text>
+          </xsl:message>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:for-each>
+
     <div xmlns="http://www.w3.org/1999/xhtml" class="method">
       <h3 xmlns="http://www.w3.org/1999/xhtml">
         <a name="{concat(../@name, concat('.', @name))}">
@@ -532,6 +767,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
   <xsl:template name="tp-type">
     <xsl:param name="tp-type"/>
+    <xsl:param name="type"/>
 
     <xsl:variable name="single-type">
       <xsl:choose>
@@ -544,30 +780,73 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       </xsl:choose>
     </xsl:variable>
 
-    <xsl:choose>
-      <xsl:when test="//tp:simple-type[@name=$single-type]" />
-      <xsl:when test="//tp:struct[@name=$single-type]" />
-      <xsl:when test="//tp:enum[@name=$single-type]" />
-      <xsl:when test="//tp:flags[@name=$single-type]" />
-      <xsl:when test="//tp:mapping[@name=$single-type]" />
-      <xsl:when test="//tp:external-type[@name=$single-type]" />
-      <xsl:otherwise>
-        <xsl:message terminate="yes">
-          <xsl:text>ERR: Unable to find type '</xsl:text>
-          <xsl:value-of select="$tp-type"/>
-          <xsl:text>'&#10;</xsl:text>
-        </xsl:message>
-      </xsl:otherwise>
-    </xsl:choose>
+    <xsl:variable name="type-of-tp-type">
+      <xsl:if test="contains($tp-type, '[]')">
+        <!-- one 'a', plus one for each [ after the [], and delete all ] -->
+        <xsl:value-of select="concat('a',
+          translate(substring-after($tp-type, '[]'), '[]', 'a'))"/>
+      </xsl:if>
+
+      <xsl:choose>
+        <xsl:when test="//tp:simple-type[@name=$single-type]">
+          <xsl:value-of select="string(//tp:simple-type[@name=$single-type]/@type)"/>
+        </xsl:when>
+        <xsl:when test="//tp:struct[@name=$single-type]">
+          <xsl:text>(</xsl:text>
+          <xsl:for-each select="//tp:struct[@name=$single-type]/tp:member">
+            <xsl:value-of select="@type"/>
+          </xsl:for-each>
+          <xsl:text>)</xsl:text>
+        </xsl:when>
+        <xsl:when test="//tp:enum[@name=$single-type]">
+          <xsl:value-of select="string(//tp:enum[@name=$single-type]/@type)"/>
+        </xsl:when>
+        <xsl:when test="//tp:flags[@name=$single-type]">
+          <xsl:value-of select="string(//tp:flags[@name=$single-type]/@type)"/>
+        </xsl:when>
+        <xsl:when test="//tp:mapping[@name=$single-type]">
+          <xsl:text>a{</xsl:text>
+          <xsl:for-each select="//tp:mapping[@name=$single-type]/tp:member">
+            <xsl:value-of select="@type"/>
+          </xsl:for-each>
+          <xsl:text>}</xsl:text>
+        </xsl:when>
+        <xsl:when test="//tp:external-type[@name=$single-type]">
+          <xsl:value-of select="string(//tp:external-type[@name=$single-type]/@type)"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:message terminate="yes">
+            <xsl:text>ERR: Unable to find type '</xsl:text>
+            <xsl:value-of select="$tp-type"/>
+            <xsl:text>'&#10;</xsl:text>
+          </xsl:message>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:if test="string($type) != '' and
+      string($type-of-tp-type) != string($type)">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: tp:type '</xsl:text>
+        <xsl:value-of select="$tp-type"/>
+        <xsl:text>' has D-Bus type '</xsl:text>
+        <xsl:value-of select="$type-of-tp-type"/>
+        <xsl:text>' but has been used with type='</xsl:text>
+        <xsl:value-of select="$type"/>
+        <xsl:text>'&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
     <a href="#type-{$single-type}"><xsl:value-of select="$tp-type"/></a>
 
   </xsl:template>
 
   <xsl:template name="parenthesized-tp-type">
     <xsl:if test="@tp:type">
-      <xsl:text>(</xsl:text>
+      <xsl:text> (</xsl:text>
       <xsl:call-template name="tp-type">
         <xsl:with-param name="tp-type" select="@tp:type"/>
+        <xsl:with-param name="type" select="@type"/>
       </xsl:call-template>
       <xsl:text>)</xsl:text>
     </xsl:if>
@@ -575,7 +854,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
   <xsl:template match="tp:member" mode="members-in-docstring">
     <dt xmlns="http://www.w3.org/1999/xhtml">
-      <code><xsl:value-of select="@name"/></code> -
+      <code><xsl:value-of select="@name"/></code> −
       <code><xsl:value-of select="@type"/></code>
       <xsl:call-template name="parenthesized-tp-type"/>
     </dt>
@@ -593,7 +872,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
   <xsl:template match="arg" mode="parameters-in-docstring">
     <dt xmlns="http://www.w3.org/1999/xhtml">
-      <code><xsl:value-of select="@name"/></code> -
+      <code><xsl:value-of select="@name"/></code> −
       <code><xsl:value-of select="@type"/></code>
       <xsl:call-template name="parenthesized-tp-type"/>
     </dt>
@@ -605,7 +884,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   <xsl:template match="arg" mode="returns-in-docstring">
     <dt xmlns="http://www.w3.org/1999/xhtml">
       <xsl:if test="@name">
-        <code><xsl:value-of select="@name"/></code> -
+        <code><xsl:value-of select="@name"/></code> −
       </xsl:if>
       <code><xsl:value-of select="@type"/></code>
       <xsl:call-template name="parenthesized-tp-type"/>
@@ -636,6 +915,57 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   </xsl:template>
 
   <xsl:template match="signal">
+
+    <xsl:if test="not(parent::interface)">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: signal </xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:text> does not have an interface as parent&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="not(@name) or @name = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>ERR: missing @name on a signal of </xsl:text>
+        <xsl:value-of select="../@name"/>
+        <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:for-each select="arg">
+      <xsl:if test="not(@type) or @type = ''">
+        <xsl:message terminate="yes">
+          <xsl:text>ERR: an arg of signal </xsl:text>
+          <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+          <xsl:text> has no type</xsl:text>
+        </xsl:message>
+      </xsl:if>
+      <xsl:if test="not(@name) or @name = ''">
+        <xsl:message terminate="yes">
+          <xsl:text>ERR: an arg of signal </xsl:text>
+          <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+          <xsl:text> has no name</xsl:text>
+        </xsl:message>
+      </xsl:if>
+      <xsl:choose>
+        <xsl:when test="not(@direction)"/>
+        <xsl:when test="@direction='in'">
+          <xsl:message terminate="no">
+            <xsl:text>INFO: an arg of signal </xsl:text>
+            <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+            <xsl:text> has unnecessary direction 'in'</xsl:text>
+          </xsl:message>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:message terminate="yes">
+            <xsl:text>ERR: an arg of signal </xsl:text>
+            <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+            <xsl:text> has direction other than 'in'</xsl:text>
+          </xsl:message>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:for-each>
+
     <div xmlns="http://www.w3.org/1999/xhtml" class="signal">
       <h3 xmlns="http://www.w3.org/1999/xhtml">
         <a name="{concat(../@name, concat('.', @name))}">
@@ -788,6 +1118,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
             color: #ff0000;
             background: #ffffff;
           }
+          table, tr, td, th {
+            border: 1px solid #666;
+          }
 
         </style>
       </head>
@@ -796,7 +1129,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
           <xsl:value-of select="tp:title" />
         </h1>
         <xsl:if test="tp:version">
-          <h2>Version <xsl:apply-templates select="tp:version"/></h2>
+          <h2>Version <xsl:value-of select="string(tp:version)"/></h2>
         </xsl:if>
         <xsl:apply-templates select="tp:copyright"/>
         <xsl:apply-templates select="tp:license"/>
@@ -838,6 +1171,29 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     </html>
   </xsl:template>
 
+  <xsl:template match="node">
+      <xsl:apply-templates />
+  </xsl:template>
+
+  <xsl:template match="text()">
+    <xsl:if test="normalize-space(.) != ''">
+      <xsl:message terminate="yes">
+        <xsl:text>Stray text: {{{</xsl:text>
+        <xsl:value-of select="." />
+        <xsl:text>}}}&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="*">
+      <xsl:message terminate="yes">
+         <xsl:text>Unrecognised element: {</xsl:text>
+         <xsl:value-of select="namespace-uri(.)" />
+         <xsl:text>}</xsl:text>
+         <xsl:value-of select="local-name(.)" />
+         <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+  </xsl:template>
 </xsl:stylesheet>
 
 <!-- vim:set sw=2 sts=2 et: -->
diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py
index b4e9de3..6988596 100644
--- a/tools/glib-client-gen.py
+++ b/tools/glib-client-gen.py
@@ -28,7 +28,7 @@ import xml.dom.minidom
 from getopt import gnu_getopt
 
 from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
-        camelcase_to_lower, get_docstring, xml_escape
+        get_docstring, xml_escape
 
 
 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
@@ -55,8 +55,9 @@ class Generator(object):
             % opts.get('--subclass', 'TpProxy'))
         if self.proxy_arg == 'void *':
             self.proxy_arg = 'gpointer '
-        self.generate_reentrant = '--generate-reentrant' in opts
-        self.generate_blocking = '--generate-blocking' in opts
+        self.generate_reentrant = ('--generate-reentrant' in opts or
+                '--deprecate-reentrant' in opts)
+        self.deprecate_reentrant = opts.get('--deprecate-reentrant', None)
 
     def h(self, s):
         if isinstance(s, unicode):
@@ -80,7 +81,11 @@ class Generator(object):
         iface_lc = iface.lower()
 
         member = signal.getAttribute('name')
-        member_lc = camelcase_to_lower(member)
+        member_lc = signal.getAttribute('tp:name-for-bindings')
+        if member != member_lc.replace('_', ''):
+            raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
+                    'not match' % (member, member_lc))
+        member_lc = member_lc.lower()
         member_uc = member_lc.upper()
 
         arg_count = 0
@@ -356,353 +361,15 @@ class Generator(object):
 
         self.h('')
 
-    def do_method_reentrant(self, method, iface_lc, member, member_lc,
-                            in_args, out_args, collect_callback):
-        # Reentrant blocking calls
-        # Example:
-        # gboolean tp_cli_properties_interface_run_get_properties
-        #   (gpointer proxy,
-        #       gint timeout_ms,
-        #       const GArray *in_properties,
-        #       GPtrArray **out0,
-        #       GError **error,
-        #       GMainLoop **loop);
-
-        self.b('typedef struct {')
-        self.b('    GMainLoop *loop;')
-        self.b('    GError **error;')
-
-        for arg in out_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.b('    %s*%s;' % (ctype, name))
-
-        self.b('    unsigned success:1;')
-        self.b('    unsigned completed:1;')
-        self.b('} _%s_%s_run_state_%s;'
-               % (self.prefix_lc, iface_lc, member_lc))
-
-        reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
-                                                         iface_lc,
-                                                         member_lc)
-
-        self.b('static void')
-        self.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke)
-        self.b('    GError *error,')
-        self.b('    GValueArray *args,')
-        self.b('    GCallback unused G_GNUC_UNUSED,')
-        self.b('    gpointer user_data G_GNUC_UNUSED,')
-        self.b('    GObject *unused2 G_GNUC_UNUSED)')
-        self.b('{')
-        self.b('  _%s_%s_run_state_%s *state = user_data;'
-               % (self.prefix_lc, iface_lc, member_lc))
-        self.b('')
-        self.b('  state->success = (error == NULL);')
-        self.b('  state->completed = TRUE;')
-        self.b('  g_main_loop_quit (state->loop);')
-        self.b('')
-        self.b('  if (error != NULL)')
-        self.b('    {')
-        self.b('      if (state->error != NULL)')
-        self.b('        *state->error = error;')
-        self.b('      else')
-        self.b('        g_error_free (error);')
-        self.b('')
-        self.b('      return;')
-        self.b('    }')
-        self.b('')
-
-        for i, arg in enumerate(out_args):
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.b('  if (state->%s != NULL)' % name)
-            if marshaller == 'BOXED':
-                self.b('    *state->%s = g_value_dup_boxed ('
-                       'args->values + %d);' % (name, i))
-            elif marshaller == 'STRING':
-                self.b('    *state->%s = g_value_dup_string '
-                       '(args->values + %d);' % (name, i))
-            elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
-                    'INT64', 'UINT64', 'DOUBLE'):
-                self.b('    *state->%s = g_value_get_%s (args->values + %d);'
-                       % (name, marshaller.lower(), i))
-            else:
-                assert False, "Don't know how to copy %s" % gtype
-
-            self.b('')
-
-        if len(out_args) > 0:
-            self.b('  g_value_array_free (args);')
-        else:
-            self.b('  if (args != NULL)')
-            self.b('    g_value_array_free (args);')
-
-        self.b('}')
-        self.b('')
-
-        self.h('gboolean %s_%s_run_%s (%sproxy,'
-               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
-        self.h('    gint timeout_ms,')
-
-        self.b('/**')
-        self.b(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc))
-        self.b(' * @proxy: %s' % self.proxy_doc)
-        self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default')
-
-        for arg in in_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.b(' * @%s: Used to pass an \'in\' argument: %s'
-                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
-
-        for arg in out_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is '
-                   'returned: %s'
-                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
-
-        self.b(' * @error: If not %NULL, used to return errors if %FALSE ')
-        self.b(' *  is returned')
-        self.b(' * @loop: If not %NULL, set before re-entering ')
-        self.b(' *  the main loop, to point to a #GMainLoop ')
-        self.b(' *  which can be used to cancel this call with ')
-        self.b(' *  g_main_loop_quit(), causing a return of ')
-        self.b(' *  %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
-        self.b(' *')
-        self.b(' * Call the method %s and run the main loop' % member)
-        self.b(' * until it returns. Before calling this method, you must')
-        self.b(' * add a reference to any borrowed objects you need to keep,')
-        self.b(' * and generally ensure that everything is in a consistent')
-        self.b(' * state.')
-        self.b(' *')
-        self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
-        self.b(' *')
-        self.b(' * Returns: TRUE on success, FALSE and sets @error on error')
-        self.b(' */')
-        self.b('gboolean\n%s_%s_run_%s (%sproxy,'
-               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
-        self.b('    gint timeout_ms,')
-
-        for arg in in_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            const = pointer and 'const ' or ''
-
-            self.h('    %s%s%s,' % (const, ctype, name))
-            self.b('    %s%s%s,' % (const, ctype, name))
-
-        for arg in out_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.h('    %s*%s,' % (ctype, name))
-            self.b('    %s*%s,' % (ctype, name))
-
-        self.h('    GError **error,')
-        self.h('    GMainLoop **loop);')
-        self.h('')
-
-        self.b('    GError **error,')
-        self.b('    GMainLoop **loop)')
-        self.b('{')
-        self.b('  DBusGProxy *iface;')
-        self.b('  GQuark interface = %s;' % self.get_iface_quark())
-        self.b('  TpProxyPendingCall *pc;')
-        self.b('  _%s_%s_run_state_%s state = {'
-               % (self.prefix_lc, iface_lc, member_lc))
-        self.b('      NULL /* loop */, error,')
-
-        for arg in out_args:
-            name, info, tp_type, elt = arg
-
-            self.b('    %s,' % name)
-
-        self.b('      FALSE /* completed */, FALSE /* success */ };')
-        self.b('')
-        self.b('  g_return_val_if_fail (%s (proxy), FALSE);'
-               % self.proxy_assert)
-        self.b('')
-        self.b('  iface = tp_proxy_borrow_interface_by_id')
-        self.b('       ((TpProxy *) proxy, interface, error);')
-        self.b('')
-        self.b('  if (iface == NULL)')
-        self.b('    return FALSE;')
-        self.b('')
-        self.b('  state.loop = g_main_loop_new (NULL, FALSE);')
-        self.b('')
-        self.b('  pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
-        self.b('      interface, "%s", iface,' % member)
-        self.b('      %s,' % reentrant_invoke)
-        self.b('      NULL, &state, NULL, NULL, TRUE);')
-        self.b('')
-        self.b('  if (loop != NULL)')
-        self.b('    *loop = state.loop;')
-        self.b('')
-        self.b('  tp_proxy_pending_call_v0_take_pending_call (pc,')
-        self.b('      dbus_g_proxy_begin_call_with_timeout (iface,')
-        self.b('          "%s",' % member)
-        self.b('          %s,' % collect_callback)
-        self.b('          pc,')
-        self.b('          tp_proxy_pending_call_v0_completed,')
-        self.b('          timeout_ms,')
-
-        for arg in in_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            const = pointer and 'const ' or ''
-
-            self.b('              %s, %s,' % (gtype, name))
-
-        self.b('          G_TYPE_INVALID));')
-        self.b('')
-        self.b('  if (!state.completed)')
-        self.b('    g_main_loop_run (state.loop);')
-        self.b('')
-        self.b('  if (!state.completed)')
-        self.b('    tp_proxy_pending_call_cancel (pc);')
-        self.b('')
-        self.b('  if (loop != NULL)')
-        self.b('    *loop = NULL;')
-        self.b('')
-        self.b('  g_main_loop_unref (state.loop);')
-        self.b('')
-        self.b('  return state.success;')
-        self.b('}')
-        self.b('')
-
-    def do_method_blocking(self, method, iface_lc, member, member_lc,
-                           in_args, out_args):
-        # Non reentrant blocking calls
-        # Example:
-        # gboolean tp_cli_properties_interface_do_get_properties
-        #   (gpointer proxy,
-        #       gint timeout_ms,
-        #       const GArray *in_properties,
-        #       GPtrArray **out0,
-        #       GError **error);
-
-        self.h('gboolean %s_%s_do_%s (%sproxy,'
-               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
-        self.h('    gint timeout_ms,')
-
-        self.b('/**')
-        self.b(' * %s_%s_do_%s:' % (self.prefix_lc, iface_lc, member_lc))
-        self.b(' * @proxy: %s' % self.proxy_doc)
-        self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default')
-
-        for arg in in_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.b(' * @%s: Used to pass an \'in\' argument: %s'
-                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
-
-        for arg in out_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is '
-                   'returned: %s'
-                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
-
-        self.b(' * @error: If not %NULL, used to return errors if %FALSE ')
-        self.b(' *  is returned')
-        self.b(' *')
-        self.b(' * Call the method %s and block' % member)
-        self.b(' * until it returns.')
-        self.b(' *')
-        self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
-        self.b(' *')
-        self.b(' * Returns: TRUE on success, FALSE and sets @error on error')
-        self.b(' */')
-        self.b('gboolean\n%s_%s_do_%s (%sproxy,'
-               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
-        self.b('    gint timeout_ms,')
-
-        for arg in in_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            const = pointer and 'const ' or ''
-
-            self.h('    %s%s%s,' % (const, ctype, name))
-            self.b('    %s%s%s,' % (const, ctype, name))
-
-        for arg in out_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.h('    %s*%s,' % (ctype, name))
-            self.b('    %s*%s,' % (ctype, name))
-
-        self.h('    GError **error);')
-        self.h('')
-
-        self.b('    GError **error)')
-        self.b('{')
-        self.b('  DBusGProxy *iface;')
-        self.b('  GQuark interface = %s;' % self.get_iface_quark())
-        for arg in out_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.b('  %si_%s;' % (ctype, name))
-        self.b('')
-        self.b('  g_return_val_if_fail (%s (proxy), FALSE);'
-               % self.proxy_assert)
-        self.b('')
-        self.b('  iface = tp_proxy_borrow_interface_by_id')
-        self.b('       ((TpProxy *) proxy, interface, error);')
-        self.b('')
-        self.b('  if (iface == NULL)')
-        self.b('    return FALSE;')
-        self.b('')
-        self.b('  if (dbus_g_proxy_call_with_timeout (iface,')
-        self.b('      "%s",' % member)
-        self.b('      timeout_ms,')
-        self.b('      error,')
-
-        for arg in in_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            const = pointer and 'const ' or ''
-
-            self.b('      %s, %s,' % (gtype, name))
-
-        self.b('      G_TYPE_INVALID,')
-
-        for arg in out_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.b('      %s, &i_%s,' % (gtype, name))
-        self.b('      G_TYPE_INVALID))')
-        self.b('  {')
-        for arg in out_args:
-            name, info, tp_type, elt = arg
-            ctype, gtype, marshaller, pointer = info
-
-            self.b('      *%s = i_%s;' % (name, name))
-        self.b('      return TRUE;')
-        self.b('  }')
-        self.b('  else')
-        self.b('      return FALSE;')
-        self.b('}')
-        self.b('')
-
     def do_method(self, iface, method):
         iface_lc = iface.lower()
 
         member = method.getAttribute('name')
-        member_lc = camelcase_to_lower(member)
+        member_lc = method.getAttribute('tp:name-for-bindings')
+        if member != member_lc.replace('_', ''):
+            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+                    'not match' % (member, member_lc))
+        member_lc = member_lc.lower()
         member_uc = member_lc.upper()
 
         in_count = 0
@@ -1141,14 +808,240 @@ class Generator(object):
             self.do_method_reentrant(method, iface_lc, member, member_lc,
                                      in_args, out_args, collect_callback)
 
-        if self.generate_blocking:
-            self.do_method_blocking(method, iface_lc, member, member_lc,
-                                    in_args, out_args)
-
         # leave a gap for the end of the method
         self.b('')
         self.h('')
 
+    def do_method_reentrant(self, method, iface_lc, member, member_lc, in_args,
+            out_args, collect_callback):
+        # Reentrant blocking calls
+        # Example:
+        # gboolean tp_cli_properties_interface_run_get_properties
+        #   (gpointer proxy,
+        #       gint timeout_ms,
+        #       const GArray *in_properties,
+        #       GPtrArray **out0,
+        #       GError **error,
+        #       GMainLoop **loop);
+
+        self.b('typedef struct {')
+        self.b('    GMainLoop *loop;')
+        self.b('    GError **error;')
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b('    %s*%s;' % (ctype, name))
+
+        self.b('    unsigned success:1;')
+        self.b('    unsigned completed:1;')
+        self.b('} _%s_%s_run_state_%s;'
+               % (self.prefix_lc, iface_lc, member_lc))
+
+        reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
+                                                         iface_lc,
+                                                         member_lc)
+
+        self.b('static void')
+        self.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke)
+        self.b('    GError *error,')
+        self.b('    GValueArray *args,')
+        self.b('    GCallback unused G_GNUC_UNUSED,')
+        self.b('    gpointer user_data G_GNUC_UNUSED,')
+        self.b('    GObject *unused2 G_GNUC_UNUSED)')
+        self.b('{')
+        self.b('  _%s_%s_run_state_%s *state = user_data;'
+               % (self.prefix_lc, iface_lc, member_lc))
+        self.b('')
+        self.b('  state->success = (error == NULL);')
+        self.b('  state->completed = TRUE;')
+        self.b('  g_main_loop_quit (state->loop);')
+        self.b('')
+        self.b('  if (error != NULL)')
+        self.b('    {')
+        self.b('      if (state->error != NULL)')
+        self.b('        *state->error = error;')
+        self.b('      else')
+        self.b('        g_error_free (error);')
+        self.b('')
+        self.b('      return;')
+        self.b('    }')
+        self.b('')
+
+        for i, arg in enumerate(out_args):
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b('  if (state->%s != NULL)' % name)
+            if marshaller == 'BOXED':
+                self.b('    *state->%s = g_value_dup_boxed ('
+                       'args->values + %d);' % (name, i))
+            elif marshaller == 'STRING':
+                self.b('    *state->%s = g_value_dup_string '
+                       '(args->values + %d);' % (name, i))
+            elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
+                    'INT64', 'UINT64', 'DOUBLE'):
+                self.b('    *state->%s = g_value_get_%s (args->values + %d);'
+                       % (name, marshaller.lower(), i))
+            else:
+                assert False, "Don't know how to copy %s" % gtype
+
+            self.b('')
+
+        if len(out_args) > 0:
+            self.b('  g_value_array_free (args);')
+        else:
+            self.b('  if (args != NULL)')
+            self.b('    g_value_array_free (args);')
+
+        self.b('}')
+        self.b('')
+
+        if self.deprecate_reentrant:
+            self.h('#ifndef %s' % self.deprecate_reentrant)
+
+        self.h('gboolean %s_%s_run_%s (%sproxy,'
+               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+        self.h('    gint timeout_ms,')
+
+        self.b('/**')
+        self.b(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc))
+        self.b(' * @proxy: %s' % self.proxy_doc)
+        self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default')
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b(' * @%s: Used to pass an \'in\' argument: %s'
+                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is '
+                   'returned: %s'
+                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+        self.b(' * @error: If not %NULL, used to return errors if %FALSE ')
+        self.b(' *  is returned')
+        self.b(' * @loop: If not %NULL, set before re-entering ')
+        self.b(' *  the main loop, to point to a #GMainLoop ')
+        self.b(' *  which can be used to cancel this call with ')
+        self.b(' *  g_main_loop_quit(), causing a return of ')
+        self.b(' *  %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
+        self.b(' *')
+        self.b(' * Call the method %s and run the main loop' % member)
+        self.b(' * until it returns. Before calling this method, you must')
+        self.b(' * add a reference to any borrowed objects you need to keep,')
+        self.b(' * and generally ensure that everything is in a consistent')
+        self.b(' * state.')
+        self.b(' *')
+        self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
+        self.b(' *')
+        self.b(' * Returns: TRUE on success, FALSE and sets @error on error')
+        self.b(' */')
+        self.b('gboolean\n%s_%s_run_%s (%sproxy,'
+               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+        self.b('    gint timeout_ms,')
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            const = pointer and 'const ' or ''
+
+            self.h('    %s%s%s,' % (const, ctype, name))
+            self.b('    %s%s%s,' % (const, ctype, name))
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.h('    %s*%s,' % (ctype, name))
+            self.b('    %s*%s,' % (ctype, name))
+
+        self.h('    GError **error,')
+
+        if self.deprecate_reentrant:
+            self.h('    GMainLoop **loop) G_GNUC_DEPRECATED;')
+            self.h('#endif /* not %s */' % self.deprecate_reentrant)
+        else:
+            self.h('    GMainLoop **loop);')
+
+        self.h('')
+
+        self.b('    GError **error,')
+        self.b('    GMainLoop **loop)')
+        self.b('{')
+        self.b('  DBusGProxy *iface;')
+        self.b('  GQuark interface = %s;' % self.get_iface_quark())
+        self.b('  TpProxyPendingCall *pc;')
+        self.b('  _%s_%s_run_state_%s state = {'
+               % (self.prefix_lc, iface_lc, member_lc))
+        self.b('      NULL /* loop */, error,')
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+
+            self.b('    %s,' % name)
+
+        self.b('      FALSE /* completed */, FALSE /* success */ };')
+        self.b('')
+        self.b('  g_return_val_if_fail (%s (proxy), FALSE);'
+               % self.proxy_assert)
+        self.b('')
+        self.b('  iface = tp_proxy_borrow_interface_by_id')
+        self.b('       ((TpProxy *) proxy, interface, error);')
+        self.b('')
+        self.b('  if (iface == NULL)')
+        self.b('    return FALSE;')
+        self.b('')
+        self.b('  state.loop = g_main_loop_new (NULL, FALSE);')
+        self.b('')
+        self.b('  pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
+        self.b('      interface, "%s", iface,' % member)
+        self.b('      %s,' % reentrant_invoke)
+        self.b('      NULL, &state, NULL, NULL, TRUE);')
+        self.b('')
+        self.b('  if (loop != NULL)')
+        self.b('    *loop = state.loop;')
+        self.b('')
+        self.b('  tp_proxy_pending_call_v0_take_pending_call (pc,')
+        self.b('      dbus_g_proxy_begin_call_with_timeout (iface,')
+        self.b('          "%s",' % member)
+        self.b('          %s,' % collect_callback)
+        self.b('          pc,')
+        self.b('          tp_proxy_pending_call_v0_completed,')
+        self.b('          timeout_ms,')
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            const = pointer and 'const ' or ''
+
+            self.b('              %s, %s,' % (gtype, name))
+
+        self.b('          G_TYPE_INVALID));')
+        self.b('')
+        self.b('  if (!state.completed)')
+        self.b('    g_main_loop_run (state.loop);')
+        self.b('')
+        self.b('  if (!state.completed)')
+        self.b('    tp_proxy_pending_call_cancel (pc);')
+        self.b('')
+        self.b('  if (loop != NULL)')
+        self.b('    *loop = NULL;')
+        self.b('')
+        self.b('  g_main_loop_unref (state.loop);')
+        self.b('')
+        self.b('  return state.success;')
+        self.b('}')
+        self.b('')
+
     def do_signal_add(self, signal):
         marshaller_items = []
         gtypes = []
@@ -1279,7 +1172,7 @@ if __name__ == '__main__':
     options, argv = gnu_getopt(sys.argv[1:], '',
                                ['group=', 'subclass=', 'subclass-assert=',
                                 'iface-quark-prefix=', 'tp-proxy-api=',
-                                'generate-reentrant', 'generate-blocking'])
+                                'generate-reentrant', 'deprecate-reentrant='])
 
     opts = {}
 
diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py
index 7e288c3..b361c7f 100644
--- a/tools/glib-ginterface-gen.py
+++ b/tools/glib-ginterface-gen.py
@@ -27,7 +27,7 @@ import os.path
 import xml.dom.minidom
 
 from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
-        camelcase_to_lower, NS_TP, dbus_gutils_wincaps_to_uscore, \
+        NS_TP, dbus_gutils_wincaps_to_uscore, \
         signal_to_marshal_name, method_to_glue_marshal_name
 
 
@@ -37,7 +37,7 @@ class Generator(object):
 
     def __init__(self, dom, prefix, basename, signal_marshal_prefix,
                  headers, end_headers, not_implemented_func,
-                 allow_havoc, write_properties):
+                 allow_havoc):
         self.dom = dom
         self.__header = []
         self.__body = []
@@ -66,12 +66,12 @@ class Generator(object):
         self.prefix_ = prefix.lower()
         self.PREFIX_ = prefix.upper()
 
+        self.basename = basename
         self.signal_marshal_prefix = signal_marshal_prefix
         self.headers = headers
         self.end_headers = end_headers
         self.not_implemented_func = not_implemented_func
         self.allow_havoc = allow_havoc
-        self.write_properties = write_properties
 
     def h(self, s):
         self.__header.append(s)
@@ -208,7 +208,8 @@ class Generator(object):
         self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)'
                % (self.prefix_, node_name_lc))
         self.b('{')
-        if self.write_properties:
+
+        if properties:
             self.b('  static TpDBusPropertiesMixinPropInfo properties[%d] = {'
                    % (len(properties) + 1))
 
@@ -225,34 +226,38 @@ class Generator(object):
                              'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE')
 
                 self.b('      { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
-                       % (flags, m.getAttribute('type'),
-                          m.getAttribute('name')))
+                       % (flags, m.getAttribute('type'), m.getAttribute('name')))
 
             self.b('      { 0, 0, NULL, 0, NULL, NULL }')
             self.b('  };')
             self.b('  static TpDBusPropertiesMixinIfaceInfo interface =')
             self.b('      { 0, properties, NULL, NULL };')
             self.b('')
+
+
+        self.b('  dbus_g_object_type_install_info (%s%s_get_type (),'
+               % (self.prefix_, node_name_lc))
+        self.b('      &_%s%s_object_info);'
+               % (self.prefix_, node_name_lc))
+        self.b('')
+
+        if properties:
             self.b('  interface.dbus_interface = g_quark_from_static_string '
                    '("%s");' % self.iface_name)
 
             for i, m in enumerate(properties):
-                self.b('  properties[%d].name = g_quark_from_static_string '
-                       '("%s");' % (i, m.getAttribute('name')))
+                self.b('  properties[%d].name = g_quark_from_static_string ("%s");'
+                       % (i, m.getAttribute('name')))
                 self.b('  properties[%d].type = %s;'
-                       % (i, type_to_gtype(m.getAttribute('type'))[1]))
+                           % (i, type_to_gtype(m.getAttribute('type'))[1]))
 
-            self.b('  tp_svc_interface_set_dbus_properties_info (%s, '
-                   '&interface);' % self.current_gtype)
+            self.b('  tp_svc_interface_set_dbus_properties_info (%s, &interface);'
+                   % self.current_gtype)
 
             self.b('')
 
         for s in base_init_code:
             self.b(s)
-        self.b('  dbus_g_object_type_install_info (%s%s_get_type (),'
-               % (self.prefix_, node_name_lc))
-        self.b('      &_%s%s_object_info);'
-               % (self.prefix_, node_name_lc))
         self.b('}')
 
         self.b('static void')
@@ -280,6 +285,10 @@ class Generator(object):
         for method, offset in zip(methods, offsets):
             self.do_method_glue(method, offset)
 
+        if len(methods) == 0:
+            # empty arrays are a gcc extension, so put in a dummy member
+            self.b("  { NULL, NULL, 0 }")
+
         self.b('};')
         self.b('')
 
@@ -339,7 +348,11 @@ class Generator(object):
         return ''.join(info) + '\0', offsets
 
     def do_method_glue(self, method, offset):
-        lc_name = camelcase_to_lower(method.getAttribute('name'))
+        lc_name = method.getAttribute('tp:name-for-bindings')
+        if method.getAttribute('name') != lc_name.replace('_', ''):
+            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+                    'not match' % (method.getAttribute('name'), lc_name))
+        lc_name = lc_name.lower()
 
         marshaller = method_to_glue_marshal_name(method,
                 self.signal_marshal_prefix)
@@ -361,7 +374,13 @@ class Generator(object):
 
     def get_method_impl_names(self, method):
         dbus_method_name = method.getAttribute('name')
-        class_member_name = camelcase_to_lower(dbus_method_name)
+
+        class_member_name = method.getAttribute('tp:name-for-bindings')
+        if dbus_method_name != class_member_name.replace('_', ''):
+            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+                    'not match' % (dbus_method_name, class_member_name))
+        class_member_name = class_member_name.lower()
+
         stub_name = (self.prefix_ + self.node_name_lc + '_' +
                      class_member_name)
         return (stub_name + '_impl', class_member_name)
@@ -376,7 +395,12 @@ class Generator(object):
         # DoStuff
         dbus_method_name = method.getAttribute('name')
         # do_stuff
-        class_member_name = camelcase_to_lower(dbus_method_name)
+        class_member_name = method.getAttribute('tp:name-for-bindings')
+        if dbus_method_name != class_member_name.replace('_', ''):
+            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+                    'not match' % (dbus_method_name, class_member_name))
+        class_member_name = class_member_name.lower()
+
         # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint,
         #   DBusGMethodInvocation *);
         stub_name = (self.prefix_ + self.node_name_lc + '_' +
@@ -537,8 +561,15 @@ class Generator(object):
         #    const char *arg0, guint arg1);
 
         dbus_name = signal.getAttribute('name')
+
+        ugly_name = signal.getAttribute('tp:name-for-bindings')
+        if dbus_name != ugly_name.replace('_', ''):
+            raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
+                    'not match' % (dbus_name, ugly_name))
+
         stub_name = (self.prefix_ + self.node_name_lc + '_emit_' +
-                     camelcase_to_lower(dbus_name))
+                     ugly_name.lower())
+
         const_name = self.get_signal_const_entry(signal)
 
         # Gather arguments
@@ -620,24 +651,33 @@ class Generator(object):
 
         return in_base_init
 
+    def have_properties(self, nodes):
+        for node in nodes:
+            interface =  node.getElementsByTagName('interface')[0]
+            if interface.getElementsByTagName('property'):
+                return True
+        return False
+
     def __call__(self):
+        nodes = self.dom.getElementsByTagName('node')
+        nodes.sort(cmp_by_name)
+
         self.h('#include <glib-object.h>')
         self.h('#include <dbus/dbus-glib.h>')
-        if self.write_properties:
+
+        if self.have_properties(nodes):
             self.h('#include <telepathy-glib/dbus-properties-mixin.h>')
+
         self.h('')
         self.h('G_BEGIN_DECLS')
         self.h('')
 
-        self.b('#include "%s.h"' % basename)
+        self.b('#include "%s.h"' % self.basename)
         self.b('')
         for header in self.headers:
             self.b('#include %s' % header)
         self.b('')
 
-        nodes = self.dom.getElementsByTagName('node')
-        nodes.sort(cmp_by_name)
-
         for node in nodes:
             self.do_node(node)
 
@@ -650,8 +690,8 @@ class Generator(object):
 
         self.h('')
         self.b('')
-        open(basename + '.h', 'w').write('\n'.join(self.__header))
-        open(basename + '.c', 'w').write('\n'.join(self.__body))
+        open(self.basename + '.h', 'w').write('\n'.join(self.__header))
+        open(self.basename + '.c', 'w').write('\n'.join(self.__body))
 
 
 def cmdline_error():
@@ -686,8 +726,7 @@ if __name__ == '__main__':
                                ['filename=', 'signal-marshal-prefix=',
                                 'include=', 'include-end=',
                                 'allow-unstable',
-                                'not-implemented-func=',
-                                'no-properties'])
+                                'not-implemented-func='])
 
     try:
         prefix = argv[1]
@@ -700,7 +739,6 @@ if __name__ == '__main__':
     end_headers = []
     not_implemented_func = ''
     allow_havoc = False
-    write_properties = True
 
     for option, value in options:
         if option == '--filename':
@@ -719,8 +757,6 @@ if __name__ == '__main__':
             not_implemented_func = value
         elif option == '--allow-unstable':
             allow_havoc = True
-        elif option == '--no-properties':
-            write_properties = False
 
     try:
         dom = xml.dom.minidom.parse(argv[0])
@@ -728,5 +764,4 @@ if __name__ == '__main__':
         cmdline_error()
 
     Generator(dom, prefix, basename, signal_marshal_prefix, headers,
-              end_headers, not_implemented_func, allow_havoc,
-              write_properties)()
+              end_headers, not_implemented_func, allow_havoc)()
diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py
index a73ec8f..29debf1 100644
--- a/tools/glib-gtypes-generator.py
+++ b/tools/glib-gtypes-generator.py
@@ -27,7 +27,8 @@ from libglibcodegen import escape_as_identifier, \
                            get_docstring, \
                            NS_TP, \
                            Signature, \
-                           type_to_gtype
+                           type_to_gtype, \
+                           xml_escape
 
 
 def types_to_gtypes(types):
@@ -50,9 +51,18 @@ class GTypesGenerator(object):
                     ' * as the specification from which it was generated.\n'
                     ' */\n\n')
 
+        # keys are e.g. 'sv', values are the key escaped
         self.need_mappings = {}
+        # keys are the contents of the struct (e.g. 'sssu'), values are the
+        # key escaped
         self.need_structs = {}
-        self.need_arrays = {}
+        # keys are the contents of the struct (e.g. 'sssu'), values are the
+        # key escaped
+        self.need_struct_arrays = {}
+
+        # keys are the contents of the array (unlike need_struct_arrays!),
+        # values are the key escaped
+        self.need_other_arrays = {}
 
     def do_mapping_header(self, mapping):
         members = mapping.getElementsByTagNameNS(NS_TP, 'member')
@@ -70,7 +80,7 @@ class GTypesGenerator(object):
         docstring = get_docstring(mapping) or '(Undocumented)'
 
         self.header.write('/**\n * %s:\n *\n' % name)
-        self.header.write(' * <![CDATA[%s]]>\n' % docstring)
+        self.header.write(' * %s\n' % xml_escape(docstring))
         self.header.write(' *\n')
         self.header.write(' * This macro expands to a call to a function\n')
         self.header.write(' * that returns the #GType of a #GHashTable\n')
@@ -89,7 +99,7 @@ class GTypesGenerator(object):
         self.header.write(' * named <literal>%s</literal>):\n'
                           % key.getAttribute('name'))
         docstring = get_docstring(key) or '(Undocumented)'
-        self.header.write(' * <![CDATA[%s]]>\n' % docstring)
+        self.header.write(' * %s\n' % xml_escape(docstring))
         self.header.write(' *\n')
 
         self.header.write(' * Values (D-Bus type <literal>%s</literal>,\n'
@@ -100,7 +110,7 @@ class GTypesGenerator(object):
         self.header.write(' * named <literal>%s</literal>):\n'
                           % value.getAttribute('name'))
         docstring = get_docstring(value) or '(Undocumented)'
-        self.header.write(' * <![CDATA[%s]]>\n' % docstring)
+        self.header.write(' * %s\n' % xml_escape(docstring))
         self.header.write(' *\n')
 
         self.header.write(' */\n')
@@ -108,6 +118,20 @@ class GTypesGenerator(object):
         self.header.write('#define %s (%s ())\n\n' % (name, impl))
         self.need_mappings[impl_sig] = esc_impl_sig
 
+        array_name = mapping.getAttribute('array-name')
+        if array_name:
+            gtype_name = self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper()
+            contents_sig = 'a{' + impl_sig + '}'
+            esc_contents_sig = escape_as_identifier(contents_sig)
+            impl = self.prefix_ + 'type_dbus_array_of_' + esc_contents_sig
+            self.header.write('/**\n * %s:\n\n' % gtype_name)
+            self.header.write(' * Expands to a call to a function\n')
+            self.header.write(' * that returns the #GType of a #GPtrArray\n')
+            self.header.write(' * of #%s.\n' % name)
+            self.header.write(' */\n')
+            self.header.write('#define %s (%s ())\n\n' % (gtype_name, impl))
+            self.need_other_arrays[contents_sig] = esc_contents_sig
+
     def do_struct_header(self, struct):
         members = struct.getElementsByTagNameNS(NS_TP, 'member')
         impl_sig = ''.join([elt.getAttribute('type') for elt in members])
@@ -125,8 +149,10 @@ class GTypesGenerator(object):
                 docstring = docstring[:-16]
             if docstring.strip() in ('<tp:docstring/>', ''):
                 docstring = '(Undocumented)'
+        else:
+            docstring = '(Undocumented)'
         self.header.write('/**\n * %s:\n\n' % name)
-        self.header.write(' * <![CDATA[%s]]>\n' % docstring)
+        self.header.write(' * %s\n' % xml_escape(docstring))
         self.header.write(' *\n')
         self.header.write(' * This macro expands to a call to a function\n')
         self.header.write(' * that returns the #GType of a #GValueArray\n')
@@ -145,7 +171,7 @@ class GTypesGenerator(object):
             self.header.write(' * named <literal>%s</literal>):\n'
                               % member.getAttribute('name'))
             docstring = get_docstring(member) or '(Undocumented)'
-            self.header.write(' * <![CDATA[%s]]>\n' % docstring)
+            self.header.write(' * %s\n' % xml_escape(docstring))
             self.header.write(' *\n')
 
         self.header.write(' */\n')
@@ -161,7 +187,7 @@ class GTypesGenerator(object):
             self.header.write(' * of #%s.\n' % name)
             self.header.write(' */\n')
             self.header.write('#define %s (%s ())\n\n' % (array_name, impl))
-            self.need_arrays[impl_sig] = esc_impl_sig
+            self.need_struct_arrays[impl_sig] = esc_impl_sig
 
         self.need_structs[impl_sig] = esc_impl_sig
 
@@ -206,16 +232,48 @@ class GTypesGenerator(object):
             self.body.write('  return t;\n')
             self.body.write('}\n\n')
 
-        for sig in self.need_arrays:
+        for sig in self.need_struct_arrays:
             self.header.write('GType %stype_dbus_array_%s (void);\n\n' %
-                              (self.prefix_, self.need_structs[sig]))
+                              (self.prefix_, self.need_struct_arrays[sig]))
             self.body.write('GType\n%stype_dbus_array_%s (void)\n{\n' %
-                              (self.prefix_, self.need_structs[sig]))
+                              (self.prefix_, self.need_struct_arrays[sig]))
             self.body.write('  static GType t = 0;\n\n')
             self.body.write('  if (G_UNLIKELY (t == 0))\n')
             self.body.write('    t = dbus_g_type_get_collection ("GPtrArray", '
                             '%stype_dbus_struct_%s ());\n' %
-                            (self.prefix_, self.need_structs[sig]))
+                            (self.prefix_, self.need_struct_arrays[sig]))
+            self.body.write('  return t;\n')
+            self.body.write('}\n\n')
+
+        for sig in self.need_other_arrays:
+            self.header.write('GType %stype_dbus_array_of_%s (void);\n\n' %
+                              (self.prefix_, self.need_other_arrays[sig]))
+            self.body.write('GType\n%stype_dbus_array_of_%s (void)\n{\n' %
+                              (self.prefix_, self.need_other_arrays[sig]))
+            self.body.write('  static GType t = 0;\n\n')
+            self.body.write('  if (G_UNLIKELY (t == 0))\n')
+
+            if sig[:2] == 'a{' and sig[-1:] == '}':
+                # array of mappings
+                self.body.write('    t = dbus_g_type_get_collection ('
+                            '"GPtrArray", '
+                            '%stype_dbus_hash_%s ());\n' %
+                            (self.prefix_, escape_as_identifier(sig[2:-1])))
+            elif sig[:2] == 'a(' and sig[-1:] == ')':
+                # array of arrays of struct
+                self.body.write('    t = dbus_g_type_get_collection ('
+                            '"GPtrArray", '
+                            '%stype_dbus_array_%s ());\n' %
+                            (self.prefix_, escape_as_identifier(sig[2:-1])))
+            elif sig[:1] == 'a':
+                # array of arrays of non-struct
+                self.body.write('    t = dbus_g_type_get_collection ('
+                            '"GPtrArray", '
+                            '%stype_dbus_array_of_%s ());\n' %
+                            (self.prefix_, escape_as_identifier(sig[1:])))
+            else:
+                raise AssertionError("array of '%s' not supported" % sig)
+
             self.body.write('  return t;\n')
             self.body.write('}\n\n')
 
diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py
index 0703d92..0cf52a8 100644
--- a/tools/libglibcodegen.py
+++ b/tools/libglibcodegen.py
@@ -23,10 +23,9 @@ please make any changes there.
 
 from libtpcodegen import NS_TP, \
                          Signature, \
-                         camelcase_to_lower, \
-                         camelcase_to_upper, \
                          cmp_by_name, \
                          escape_as_identifier, \
+                         get_by_path, \
                          get_descendant_text, \
                          get_docstring, \
                          xml_escape
@@ -146,8 +145,10 @@ def type_to_gtype(s):
     elif s == 'ab': #boolean array
         return ("GArray *", "DBUS_TYPE_G_BOOLEAN_ARRAY", "BOXED", True)
     elif s == 'ao': #object path array
-        return ("GPtrArray *", "dbus_g_type_get_collection (\"GPtrArray\", "
-                "DBUS_TYPE_G_OBJECT_PATH)", "BOXED", True)
+        return ("GPtrArray *",
+                'dbus_g_type_get_collection ("GPtrArray",'
+                ' DBUS_TYPE_G_OBJECT_PATH)',
+                "BOXED", True)
     elif s == 'a{ss}': #hash table of string to string
         return ("GHashTable *", "DBUS_TYPE_G_STRING_STRING_HASHTABLE", "BOXED", False)
     elif s[:2] == 'a{':  #some arbitrary hash tables
diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py
index e7527c8..e5114b7 100644
--- a/tools/libtpcodegen.py
+++ b/tools/libtpcodegen.py
@@ -29,32 +29,6 @@ NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
 _ASCII_ALNUM = ascii_letters + digits
 
 
-def camelcase_to_lower(s):
-    out ="";
-    out += s[0].lower()
-    last_upper=False
-    if s[0].isupper():
-        last_upper=True
-    for i in range(1,len(s)):
-        if s[i].isupper():
-            if last_upper:
-                if (i+1) < len(s) and  s[i+1].islower():
-                    out += "_" + s[i].lower()
-                else:
-                    out += s[i].lower()
-            else:
-                out += "_" + s[i].lower()
-            last_upper=True
-        else:
-            out += s[i]
-            last_upper=False
-    return out
-
-
-def camelcase_to_upper(s):
-    return camelcase_to_lower(s).upper()
-
-
 def cmp_by_name(node1, node2):
     return cmp(node1.getAttributeNode("name").nodeValue,
                node2.getAttributeNode("name").nodeValue)
@@ -98,6 +72,39 @@ def escape_as_identifier(identifier):
     return ''.join(ret)
 
 
+def get_by_path(element, path):
+    branches = path.split('/')
+    branch = branches[0]
+
+    # Is the current branch an attribute, if so, return the attribute value
+    if branch[0] == '@':
+        return element.getAttribute(branch[1:])
+
+    # Find matching children for the branch
+    children = []
+    if branch == '..':
+        children.append(element.parentNode)
+    else:
+        for x in element.childNodes:
+            if x.localName == branch:
+                children.append(x)
+
+    ret = []
+    # If this is not the last path element, recursively gather results from
+    # children
+    if len(branches) > 1:
+        for x in children:
+            add = get_by_path(x, '/'.join(branches[1:]))
+            if isinstance(add, list):
+                ret += add
+            else:
+                return add
+    else:
+        ret = children
+
+    return ret
+
+
 def get_docstring(element):
     docstring = None
     for x in element.childNodes:
@@ -114,9 +121,13 @@ def get_docstring(element):
     return docstring
 
 
-def get_descendant_text(element):
+def get_descendant_text(element_or_elements):
+    if not element_or_elements:
+        return ''
+    if isinstance(element_or_elements, list):
+        return ''.join(map(get_descendant_text, element_or_elements))
     parts = []
-    for x in element.childNodes:
+    for x in element_or_elements.childNodes:
         if x.nodeType == x.TEXT_NODE:
             parts.append(x.nodeValue)
         elif x.nodeType == x.ELEMENT_NODE:
-- 
1.5.6.5




More information about the telepathy-commits mailing list