summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorCosimo Alfarano <cosimo.alfarano@collabora.co.uk>2009-12-04 21:14:58 -0200
committerCosimo Alfarano <cosimo.alfarano@collabora.co.uk>2009-12-04 21:14:58 -0200
commit8fb9c3d6136c533cb5f240740f357647019b22ab (patch)
treed377aa717c5df7859a962dfd051aa6a40ffb4229 /tools
parent35c657537049f36e2d6fa445008a498dde4c8423 (diff)
Completed importing and refactoring of EmpathyLogStore
* removed any call which would make TPL depending on libempathy * copied empathy-time.[hc] * added some empathy's utility function to tpl_utils.[ch] * added support for automake/autoconf using empathy's one as basis: currently TPL depends on telepathy-glib and libxmp-2.0 (and theirs deps) * added AUTHORS COPYING INSTALL README and NEWS files (empty)
Diffstat (limited to 'tools')
-rw-r--r--tools/.gitignore3
-rw-r--r--tools/Makefile.am67
-rw-r--r--tools/c-constants-gen.py151
-rw-r--r--tools/check-c-style.sh56
-rw-r--r--tools/check-coding-style.mk17
-rw-r--r--tools/check-misc.sh13
-rw-r--r--tools/check-whitespace.sh24
-rw-r--r--tools/doc-generator.xsl1199
-rw-r--r--tools/flymake.mk4
-rw-r--r--tools/glib-client-gen.py1157
-rw-r--r--tools/glib-client-marshaller-gen.py59
-rw-r--r--tools/glib-errors-enum-body-gen.py62
-rw-r--r--tools/glib-errors-enum-header-gen.py75
-rw-r--r--tools/glib-ginterface-gen.py722
-rw-r--r--tools/glib-gtypes-generator.py230
-rw-r--r--tools/glib-interfaces-gen.py97
-rw-r--r--tools/glib-signals-marshal-gen.py55
-rw-r--r--tools/gobject-foo.py81
-rw-r--r--tools/identity.xsl7
-rw-r--r--tools/lcov.am23
-rw-r--r--tools/libglibcodegen.py173
-rw-r--r--tools/libtpcodegen.py231
-rw-r--r--tools/make-version-script.py205
-rw-r--r--tools/shave.mk1
-rw-r--r--tools/telepathy-glib-env.in9
-rw-r--r--tools/telepathy.am27
-rw-r--r--tools/with-session-bus.sh84
27 files changed, 4832 insertions, 0 deletions
diff --git a/tools/.gitignore b/tools/.gitignore
new file mode 100644
index 0000000..2578e98
--- /dev/null
+++ b/tools/.gitignore
@@ -0,0 +1,3 @@
+_gen
+extensions.html
+telepathy-glib-env
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..8662b44
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,67 @@
+include $(top_srcdir)/tools/shave.mk
+
+abs_top_builddir = @abs_top_builddir@
+
+noinst_SCRIPTS = telepathy-glib-env
+
+telepathy-glib-env: telepathy-glib-env.in Makefile
+ sed -e 's![@]abs_top_builddir[@]!$(abs_top_builddir)!' $< > $@
+ chmod +x $@
+
+EXTRA_DIST = \
+ c-constants-gen.py \
+ check-coding-style.mk \
+ check-c-style.sh \
+ check-misc.sh \
+ check-whitespace.sh \
+ doc-generator.xsl \
+ flymake.mk \
+ glib-client-gen.py \
+ glib-client-marshaller-gen.py \
+ glib-errors-enum-body-gen.py \
+ glib-errors-enum-header-gen.py \
+ glib-ginterface-gen.py \
+ glib-gtypes-generator.py \
+ glib-interfaces-gen.py \
+ glib-signals-marshal-gen.py \
+ gobject-foo.py \
+ identity.xsl \
+ lcov.am \
+ libtpcodegen.py \
+ libglibcodegen.py \
+ make-version-script.py \
+ telepathy.am \
+ telepathy-glib-env.in \
+ with-session-bus.sh
+
+CLEANFILES = libtpcodegen.pyc libtpcodegen.pyo libglibcodegen.pyc libglibcodegen.pyo $(noinst_SCRIPTS)
+
+all: $(EXTRA_DIST)
+
+libglibcodegen.py: libtpcodegen.py
+ $(QUIET_GEN)touch $@
+c-constants-gen.py: libglibcodegen.py
+ $(QUIET_GEN)touch $@
+glib-client-marshaller-gen.py: libglibcodegen.py
+ $(QUIET_GEN)touch $@
+glib-errors-enum-body-gen.py: libglibcodegen.py
+ $(QUIET_GEN)touch $@
+glib-errors-enum-header-gen.py: libglibcodegen.py
+ $(QUIET_GEN)touch $@
+glib-ginterface-gen.py: libglibcodegen.py
+ $(QUIET_GEN)touch $@
+glib-gtypes-generator.py: libglibcodegen.py
+ $(QUIET_GEN)touch $@
+glib-interfaces-gen.py: libglibcodegen.py
+ $(QUIET_GEN)touch $@
+glib-signals-marshal-gen.py: libglibcodegen.py
+ $(QUIET_GEN)touch $@
+
+TELEPATHY_SPEC_SRCDIR = $(top_srcdir)/../telepathy-spec
+maintainer-update-from-telepathy-spec:
+ set -e && cd $(srcdir) && \
+ for x in $(EXTRA_DIST); do \
+ if test -f $(TELEPATHY_SPEC_SRCDIR)/tools/$$x; then \
+ cp $(TELEPATHY_SPEC_SRCDIR)/tools/$$x $$x; \
+ fi; \
+ done
diff --git a/tools/c-constants-gen.py b/tools/c-constants-gen.py
new file mode 100644
index 0000000..f338257
--- /dev/null
+++ b/tools/c-constants-gen.py
@@ -0,0 +1,151 @@
+#!/usr/bin/python
+
+from sys import argv, stdout, stderr
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \
+ get_descendant_text, get_by_path
+
+class Generator(object):
+ def __init__(self, prefix, dom):
+ self.prefix = prefix + '_'
+ self.spec = get_by_path(dom, "spec")[0]
+
+ def __call__(self):
+ self.do_header()
+ self.do_body()
+ self.do_footer()
+
+ # Header
+ def do_header(self):
+ stdout.write('/* Generated from ')
+ stdout.write(get_descendant_text(get_by_path(self.spec, 'title')))
+ version = get_by_path(self.spec, "version")
+ if version:
+ stdout.write(', version ' + get_descendant_text(version))
+ stdout.write('\n\n')
+ for copyright in get_by_path(self.spec, 'copyright'):
+ stdout.write(get_descendant_text(copyright))
+ stdout.write('\n')
+ stdout.write(get_descendant_text(get_by_path(self.spec, 'license')))
+ stdout.write('\n')
+ stdout.write(get_descendant_text(get_by_path(self.spec, 'docstring')))
+ stdout.write("""
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+\n""")
+
+ # Body
+ def do_body(self):
+ for elem in self.spec.getElementsByTagNameNS(NS_TP, '*'):
+ if elem.localName == 'flags':
+ self.do_flags(elem)
+ elif elem.localName == 'enum':
+ self.do_enum(elem)
+
+ def do_flags(self, flags):
+ name = flags.getAttribute('plural') or flags.getAttribute('name')
+ value_prefix = flags.getAttribute('singular') or \
+ flags.getAttribute('value-prefix') or \
+ flags.getAttribute('name')
+ stdout.write("""\
+/**
+ *
+%s:
+""" % (self.prefix + name).replace('_', ''))
+ for flag in get_by_path(flags, 'flag'):
+ self.do_gtkdoc(flag, value_prefix)
+ stdout.write(' *\n')
+ docstrings = get_by_path(flags, 'docstring')
+ if docstrings:
+ stdout.write("""\
+ * <![CDATA[%s]]>
+ *
+""" % get_descendant_text(docstrings).replace('\n', ' '))
+ stdout.write("""\
+ * Bitfield/set of flags generated from the Telepathy specification.
+ */
+typedef enum {
+""")
+ for flag in get_by_path(flags, 'flag'):
+ self.do_val(flag, value_prefix)
+ stdout.write("""\
+} %s;
+
+""" % (self.prefix + name).replace('_', ''))
+
+ def do_enum(self, enum):
+ name = enum.getAttribute('singular') or enum.getAttribute('name')
+ value_prefix = enum.getAttribute('singular') or \
+ enum.getAttribute('value-prefix') or \
+ enum.getAttribute('name')
+ name_plural = enum.getAttribute('plural') or \
+ enum.getAttribute('name') + 's'
+ stdout.write("""\
+/**
+ *
+%s:
+""" % (self.prefix + name).replace('_', ''))
+ vals = get_by_path(enum, 'enumvalue')
+ for val in vals:
+ self.do_gtkdoc(val, value_prefix)
+ stdout.write(' *\n')
+ docstrings = get_by_path(enum, 'docstring')
+ if docstrings:
+ stdout.write("""\
+ * <![CDATA[%s]]>
+ *
+""" % get_descendant_text(docstrings).replace('\n', ' '))
+ stdout.write("""\
+ * Bitfield/set of flags generated from the Telepathy specification.
+ */
+typedef enum {
+""")
+ for val in vals:
+ self.do_val(val, value_prefix)
+ stdout.write("""\
+} %(mixed-name)s;
+
+/**
+ * NUM_%(upper-plural)s:
+ *
+ * 1 higher than the highest valid value of #%(mixed-name)s.
+ */
+#define NUM_%(upper-plural)s (%(last-val)s+1)
+
+""" % {'mixed-name' : (self.prefix + name).replace('_', ''),
+ 'upper-plural' : (self.prefix + name_plural).upper(),
+ 'last-val' : vals[-1].getAttribute('value')})
+
+ def do_val(self, val, value_prefix):
+ name = val.getAttribute('name')
+ suffix = val.getAttribute('suffix')
+ use_name = (self.prefix + value_prefix + '_' + \
+ (suffix or name)).upper()
+ assert not (name and suffix) or name == suffix, \
+ 'Flag/enumvalue name %s != suffix %s' % (name, suffix)
+ stdout.write(' %s = %s,\n' % (use_name, val.getAttribute('value')))
+
+ def do_gtkdoc(self, node, value_prefix):
+ stdout.write(' * @')
+ stdout.write((self.prefix + value_prefix + '_' +
+ node.getAttribute('suffix')).upper())
+ stdout.write(': <![CDATA[')
+ docstring = get_by_path(node, 'docstring')
+ stdout.write(get_descendant_text(docstring).replace('\n', ' '))
+ stdout.write(']]>\n')
+
+ # Footer
+ def do_footer(self):
+ stdout.write("""
+#ifdef __cplusplus
+}
+#endif
+""")
+
+if __name__ == '__main__':
+ argv = argv[1:]
+ Generator(argv[0], xml.dom.minidom.parse(argv[1]))()
diff --git a/tools/check-c-style.sh b/tools/check-c-style.sh
new file mode 100644
index 0000000..dd62fb7
--- /dev/null
+++ b/tools/check-c-style.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+fail=0
+
+( . "${tools_dir}"/check-misc.sh ) || fail=$?
+
+if grep -n '^ *GError *\*[[:alpha:]_][[:alnum:]_]* *;' "$@"
+then
+ echo "^^^ The above files contain uninitialized GError*s - they should be"
+ echo " initialized to NULL"
+ fail=1
+fi
+
+# The first regex finds function calls like foo() (as opposed to foo ()).
+# It attempts to ignore string constants (may cause false negatives).
+# The second and third ignore block comments (gtkdoc uses foo() as markup).
+# The fourth ignores cpp so you can
+# #define foo(bar) (_real_foo (__FUNC__, bar)) (cpp insists on foo() style).
+if grep -n '^[^"]*[[:lower:]](' "$@" \
+ | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: *\*' \
+ | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: */\*' \
+ | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: *#'
+then
+ echo "^^^ Our coding style is to use function calls like foo (), not foo()"
+ fail=1
+fi
+
+if grep -En '[(][[:alnum:]_]+ ?\*[)][(]?[[:alpha:]_]' "$@"; then
+ echo "^^^ Our coding style is to have a space between a cast and the "
+ echo " thing being cast"
+ fail=1
+fi
+
+# this only spots casts
+if grep -En '[(][[:alnum:]_]+\*+[)]' "$@"; then
+ echo "^^^ Our coding style is to have a space before the * of pointer types"
+ echo " (regex 1)"
+ fail=1
+fi
+# ... and this only spots variable declarations and function return types
+if grep -En '^ *(static |const |)* *[[:alnum:]_]+\*+([[:alnum:]_]|;|$)' \
+ "$@"; then
+ echo "^^^ Our coding style is to have a space before the * of pointer types"
+ echo " (regex 2)"
+ fail=1
+fi
+
+if test -n "$CHECK_FOR_LONG_LINES"
+then
+ if egrep -n '.{80,}' "$@"
+ then
+ echo "^^^ The above files contain long lines"
+ fail=1
+ fi
+fi
+
+exit $fail
diff --git a/tools/check-coding-style.mk b/tools/check-coding-style.mk
new file mode 100644
index 0000000..3fc92fc
--- /dev/null
+++ b/tools/check-coding-style.mk
@@ -0,0 +1,17 @@
+check-coding-style:
+ @fail=0; \
+ if test -n "$(check_misc_sources)"; then \
+ tools_dir=$(top_srcdir)/tools \
+ sh $(top_srcdir)/tools/check-misc.sh \
+ $(check_misc_sources) || fail=1; \
+ fi; \
+ if test -n "$(check_c_sources)"; then \
+ tools_dir=$(top_srcdir)/tools \
+ sh $(top_srcdir)/tools/check-c-style.sh \
+ $(check_c_sources) || fail=1; \
+ fi;\
+ if test yes = "$(ENABLE_CODING_STYLE_CHECKS)"; then \
+ exit "$$fail";\
+ else \
+ exit 0;\
+ fi
diff --git a/tools/check-misc.sh b/tools/check-misc.sh
new file mode 100644
index 0000000..89e8e87
--- /dev/null
+++ b/tools/check-misc.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+fail=0
+
+( . "${tools_dir}"/check-whitespace.sh ) || fail=$?
+
+if egrep '(Free\s*Software\s*Foundation.*02139|02111-1307)' "$@"
+then
+ echo "^^^ The above files contain the FSF's old address in GPL headers"
+ fail=1
+fi
+
+exit $fail
diff --git a/tools/check-whitespace.sh b/tools/check-whitespace.sh
new file mode 100644
index 0000000..489322f
--- /dev/null
+++ b/tools/check-whitespace.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+fail=0
+
+if grep -n ' $' "$@"
+then
+ echo "^^^ The above files contain unwanted trailing spaces"
+ fail=1
+fi
+
+if grep -n ' $' "$@"
+then
+ echo "^^^ The above files contain unwanted trailing tabs"
+ fail=1
+fi
+
+# TODO: enable tab checking once all Empathy switched to TP coding style
+#if grep -n ' ' "$@"
+#then
+# echo "^^^ The above files contain tabs"
+# fail=1
+#fi
+
+exit $fail
diff --git a/tools/doc-generator.xsl b/tools/doc-generator.xsl
new file mode 100644
index 0000000..76fc969
--- /dev/null
+++ b/tools/doc-generator.xsl
@@ -0,0 +1,1199 @@
+<!-- Generate HTML documentation from the Telepathy specification.
+The master copy of this stylesheet is in the Telepathy spec repository -
+please make any changes there.
+
+Copyright (C) 2006-2008 Collabora Limited
+
+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 St, Fifth Floor, Boston, MA 02110-1301 USA
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ 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 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"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="tp:type" mode="html">
+ <xsl:call-template name="tp-type">
+ <xsl:with-param name="tp-type" select="string(.)"/>
+ </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"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="tp:docstring">
+ <xsl:apply-templates mode="html"/>
+ </xsl:template>
+
+ <xsl:template match="tp:added">
+ <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" 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>
+ <p class="changed">Changed in version
+ <xsl:value-of select="@version"/></p>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="tp:deprecated">
+ <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>
+
+ <xsl:template match="tp:rationale" mode="html">
+ <div xmlns="http://www.w3.org/1999/xhtml" class="rationale">
+ <xsl:apply-templates select="node()" mode="html"/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="tp:errors">
+ <h1 xmlns="http://www.w3.org/1999/xhtml">Errors</h1>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="tp:generic-types">
+ <h1 xmlns="http://www.w3.org/1999/xhtml">Generic types</h1>
+ <xsl:call-template name="do-types"/>
+ </xsl:template>
+
+ <xsl:template name="do-types">
+ <xsl:if test="tp:simple-type">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Simple types</h2>
+ <xsl:apply-templates select="tp:simple-type"/>
+ </xsl:if>
+
+ <xsl:if test="tp:enum">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Enumerated types:</h2>
+ <xsl:apply-templates select="tp:enum"/>
+ </xsl:if>
+
+ <xsl:if test="tp:flags">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Sets of flags:</h2>
+ <xsl:apply-templates select="tp:flags"/>
+ </xsl:if>
+
+ <xsl:if test="tp:struct">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Structure types</h2>
+ <xsl:apply-templates select="tp:struct"/>
+ </xsl:if>
+
+ <xsl:if test="tp:mapping">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Mapping types</h2>
+ <xsl:apply-templates select="tp:mapping"/>
+ </xsl:if>
+
+ <xsl:if test="tp:external-type">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Types defined elsewhere</h2>
+ <dl><xsl:apply-templates select="tp:external-type"/></dl>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="tp:error">
+ <h2 xmlns="http://www.w3.org/1999/xhtml"><a name="{concat(../@namespace, '.', translate(@name, ' ', ''))}"></a><xsl:value-of select="concat(../@namespace, '.', translate(@name, ' ', ''))"/></h2>
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </xsl:template>
+
+ <xsl:template match="/tp:spec/tp:copyright">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates mode="text"/>
+ </div>
+ </xsl:template>
+ <xsl:template match="/tp:spec/tp:license">
+ <div xmlns="http://www.w3.org/1999/xhtml" class="license">
+ <xsl:apply-templates mode="html"/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="tp:copyright"/>
+ <xsl:template match="tp:license"/>
+
+ <xsl:template match="interface">
+ <h1 xmlns="http://www.w3.org/1999/xhtml"><a name="{@name}"></a><xsl:value-of select="@name"/></h1>
+
+ <xsl:if test="@tp:causes-havoc">
+ <p xmlns="http://www.w3.org/1999/xhtml" class="causes-havoc">
+ This interface is <xsl:value-of select="@tp:causes-havoc"/>
+ and is likely to cause havoc to your API/ABI if bindings are generated.
+ Don't include it in libraries that care about compatibility.
+ </p>
+ </xsl:if>
+
+ <xsl:if test="tp:requires">
+ <p>Implementations of this interface must also implement:</p>
+ <ul xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:for-each select="tp:requires">
+ <li><code><a href="#{@interface}"><xsl:value-of select="@interface"/></a></code></li>
+ </xsl:for-each>
+ </ul>
+ </xsl:if>
+
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+
+ <xsl:choose>
+ <xsl:when test="method">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Methods:</h2>
+ <xsl:apply-templates select="method"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <p xmlns="http://www.w3.org/1999/xhtml">Interface has no methods.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="signal">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Signals:</h2>
+ <xsl:apply-templates select="signal"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <p xmlns="http://www.w3.org/1999/xhtml">Interface has no signals.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="tp:property">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Telepathy Properties:</h2>
+ <p xmlns="http://www.w3.org/1999/xhtml">Accessed using the
+ <a href="#org.freedesktop.Telepathy.Properties">Telepathy
+ Properties</a> interface.</p>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:property"/>
+ </dl>
+ </xsl:when>
+ <xsl:otherwise>
+ <p xmlns="http://www.w3.org/1999/xhtml">Interface has no Telepathy
+ properties.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="property">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">D-Bus core Properties:</h2>
+ <p xmlns="http://www.w3.org/1999/xhtml">Accessed using the
+ org.freedesktop.DBus.Properties interface.</p>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="property"/>
+ </dl>
+ </xsl:when>
+ <xsl:otherwise>
+ <p xmlns="http://www.w3.org/1999/xhtml">Interface has no D-Bus core
+ properties.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:call-template name="do-types"/>
+
+ </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"/>
+ </a>
+ </h3>
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:variable name="value-prefix">
+ <xsl:choose>
+ <xsl:when test="@value-prefix">
+ <xsl:value-of select="@value-prefix"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="tp:flag">
+ <dt xmlns="http://www.w3.org/1999/xhtml"><code><xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/></code></dt>
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </dd>
+ </xsl:when>
+ <xsl:otherwise>
+ <dd xmlns="http://www.w3.org/1999/xhtml">(Undocumented)</dd>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </dl>
+ </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"/>
+ </a>
+ </h3>
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:variable name="value-prefix">
+ <xsl:choose>
+ <xsl:when test="@value-prefix">
+ <xsl:value-of select="@value-prefix"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="tp:enumvalue">
+ <dt xmlns="http://www.w3.org/1999/xhtml"><code><xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/></code></dt>
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </dd>
+ </xsl:when>
+ <xsl:otherwise>
+ <dd xmlns="http://www.w3.org/1999/xhtml">(Undocumented)</dd>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </dl>
+ </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>
+ <code><xsl:value-of select="@type"/></code>
+ <xsl:call-template name="parenthesized-tp-type"/>
+ <xsl:text>, </xsl:text>
+ <xsl:choose>
+ <xsl:when test="@access = 'read'">
+ <xsl:text>read-only</xsl:text>
+ </xsl:when>
+ <xsl:when test="@access = 'write'">
+ <xsl:text>write-only</xsl:text>
+ </xsl:when>
+ <xsl:when test="@access = 'readwrite'">
+ <xsl:text>read/write</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <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>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="tp:property">
+ <dt xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:if test="@name">
+ <code><xsl:value-of select="@name"/></code> −
+ </xsl:if>
+ <code><xsl:value-of select="@type"/></code>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="tp:mapping">
+ <div xmlns="http://www.w3.org/1999/xhtml" class="struct">
+ <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>
+ <xsl:value-of select="@name"/>
+ <xsl:if test="position() != last()"> &#x2192; </xsl:if>
+ </xsl:for-each>
+ }
+ </h3>
+ <div class="docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:if test="string(@array-name) != ''">
+ <p>In bindings that need a separate name, arrays of
+ <xsl:value-of select="@name"/> should be called
+ <xsl:value-of select="@array-name"/>.</p>
+ </xsl:if>
+ </div>
+ <div>
+ <h4>Members</h4>
+ <dl>
+ <xsl:apply-templates select="tp:member" mode="members-in-docstring"/>
+ </dl>
+ </div>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="tp:docstring" mode="in-index"/>
+
+ <xsl:template match="tp:simple-type | tp:enum | tp:flags | tp:external-type"
+ mode="in-index">
+ − <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"/>
+ </h3>
+ <div class="docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </div>
+ </div>
+ </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"/>
+ </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: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">
+ <xsl:value-of select="@type"/>
+ <xsl:if test="position() != last()"> &#x2192; </xsl:if>
+ </xsl:for-each> }
+ </xsl:template>
+
+ <xsl:template match="tp:struct">
+ <div xmlns="http://www.w3.org/1999/xhtml" class="struct">
+ <h3>
+ <a name="type-{@name}">
+ <xsl:value-of select="@name"/>
+ </a> − (
+ <xsl:for-each select="tp:member">
+ <xsl:value-of select="@type"/>
+ <xsl:text>: </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each>
+ )
+ </h3>
+ <div class="docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </div>
+ <xsl:choose>
+ <xsl:when test="string(@array-name) != ''">
+ <p>In bindings that need a separate name, arrays of
+ <xsl:value-of select="@name"/> should be called
+ <xsl:value-of select="@array-name"/>.</p>
+ </xsl:when>
+ <xsl:otherwise>
+ <p>Arrays of <xsl:value-of select="@name"/> don't generally
+ make sense.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+ <div>
+ <h4>Members</h4>
+ <dl>
+ <xsl:apply-templates select="tp:member" mode="members-in-docstring"/>
+ </dl>
+ </div>
+ </div>
+ </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))}">
+ <xsl:value-of select="@name"/>
+ </a> (
+ <xsl:for-each xmlns="" select="arg[@direction='in']">
+ <xsl:value-of select="@type"/>: <xsl:value-of select="@name"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each>
+ ) &#x2192;
+ <xsl:choose>
+ <xsl:when test="arg[@direction='out']">
+ <xsl:for-each xmlns="" select="arg[@direction='out']">
+ <xsl:value-of select="@type"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each>
+ </xsl:when>
+ <xsl:otherwise>nothing</xsl:otherwise>
+ </xsl:choose>
+ </h3>
+ <div xmlns="http://www.w3.org/1999/xhtml" class="docstring">
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </div>
+
+ <xsl:if test="arg[@direction='in']">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <h4>Parameters</h4>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="arg[@direction='in']"
+ mode="parameters-in-docstring"/>
+ </dl>
+ </div>
+ </xsl:if>
+
+ <xsl:if test="arg[@direction='out']">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <h4>Returns</h4>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="arg[@direction='out']"
+ mode="returns-in-docstring"/>
+ </dl>
+ </div>
+ </xsl:if>
+
+ <xsl:if test="tp:possible-errors">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <h4>Possible errors</h4>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:possible-errors/tp:error"/>
+ </dl>
+ </div>
+ </xsl:if>
+
+ </div>
+ </xsl:template>
+
+ <xsl:template name="tp-type">
+ <xsl:param name="tp-type"/>
+ <xsl:param name="type"/>
+
+ <xsl:variable name="single-type">
+ <xsl:choose>
+ <xsl:when test="contains($tp-type, '[]')">
+ <xsl:value-of select="substring-before($tp-type, '[]')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$tp-type"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <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: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>
+ </xsl:template>
+
+ <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="@type"/></code>
+ <xsl:call-template name="parenthesized-tp-type"/>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <xsl:apply-templates select="tp:docstring" />
+ </xsl:when>
+ <xsl:otherwise>
+ <em>(undocumented)</em>
+ </xsl:otherwise>
+ </xsl:choose>
+ </dd>
+ </xsl:template>
+
+ <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="@type"/></code>
+ <xsl:call-template name="parenthesized-tp-type"/>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring" />
+ </dd>
+ </xsl:template>
+
+ <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> −
+ </xsl:if>
+ <code><xsl:value-of select="@type"/></code>
+ <xsl:call-template name="parenthesized-tp-type"/>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring"/>
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="tp:possible-errors/tp:error">
+ <dt xmlns="http://www.w3.org/1999/xhtml">
+ <code><xsl:value-of select="@name"/></code>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:variable name="name" select="@name"/>
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ </xsl:when>
+ <xsl:when test="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring">
+ <xsl:apply-templates select="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring"/> <em xmlns="http://www.w3.org/1999/xhtml">(generic description)</em>
+ </xsl:when>
+ <xsl:otherwise>
+ (Undocumented.)
+ </xsl:otherwise>
+ </xsl:choose>
+ </dd>
+ </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))}">
+ <xsl:value-of select="@name"/>
+ </a> (
+ <xsl:for-each xmlns="" select="arg">
+ <xsl:value-of select="@type"/>: <xsl:value-of select="@name"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each>
+ )</h3>
+
+ <div xmlns="http://www.w3.org/1999/xhtml" class="docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </div>
+
+ <xsl:if test="arg">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <h4>Parameters</h4>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="arg" mode="parameters-in-docstring"/>
+ </dl>
+ </div>
+ </xsl:if>
+ </div>
+ </xsl:template>
+
+ <xsl:output method="xml" indent="no" encoding="ascii"
+ omit-xml-declaration="yes"
+ doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
+ doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" />
+
+ <xsl:template match="/tp:spec">
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>
+ <xsl:value-of select="tp:title"/>
+ <xsl:if test="tp:version">
+ <xsl:text> version </xsl:text>
+ <xsl:value-of select="tp:version"/>
+ </xsl:if>
+ </title>
+ <style type="text/css">
+
+ body {
+ font-family: sans-serif;
+ margin: 2em;
+ height: 100%;
+ font-size: 1.2em;
+ }
+ h1 {
+ padding-top: 5px;
+ padding-bottom: 5px;
+ font-size: 1.6em;
+ background: #dadae2;
+ }
+ h2 {
+ font-size: 1.3em;
+ }
+ h3 {
+ font-size: 1.2em;
+ }
+ a:link, a:visited, a:link:hover, a:visited:hover {
+ font-weight: bold;
+ }
+ .topbox {
+ padding-top: 10px;
+ padding-left: 10px;
+ border-bottom: black solid 1px;
+ padding-bottom: 10px;
+ background: #dadae2;
+ font-size: 2em;
+ font-weight: bold;
+ color: #5c5c5c;
+ }
+ .topnavbox {
+ padding-left: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ background: #abacba;
+ border-bottom: black solid 1px;
+ font-size: 1.2em;
+ }
+ .topnavbox a{
+ color: black;
+ font-weight: normal;
+ }
+ .sidebar {
+ float: left;
+ /* width:9em;
+ border-right:#abacba solid 1px;
+ border-left: #abacba solid 1px;
+ height:100%; */
+ border: #abacba solid 1px;
+ padding-left: 10px;
+ margin-left: 10px;
+ padding-right: 10px;
+ margin-right: 10px;
+ color: #5d5d5d;
+ background: #dadae2;
+ }
+ .sidebar a {
+ text-decoration: none;
+ border-bottom: #e29625 dotted 1px;
+ color: #e29625;
+ font-weight: normal;
+ }
+ .sidebar h1 {
+ font-size: 1.2em;
+ color: black;
+ }
+ .sidebar ul {
+ padding-left: 25px;
+ padding-bottom: 10px;
+ border-bottom: #abacba solid 1px;
+ }
+ .sidebar li {
+ padding-top: 2px;
+ padding-bottom: 2px;
+ }
+ .sidebar h2 {
+ font-style:italic;
+ font-size: 0.81em;
+ padding-left: 5px;
+ padding-right: 5px;
+ font-weight: normal;
+ }
+ .date {
+ font-size: 0.6em;
+ float: right;
+ font-style: italic;
+ }
+ .method, .signal, .property {
+ margin-left: 1em;
+ margin-right: 4em;
+ }
+ .rationale {
+ font-style: italic;
+ border-left: 0.25em solid #808080;
+ padding-left: 0.5em;
+ }
+
+ .added {
+ color: #006600;
+ background: #ffffff;
+ }
+ .deprecated {
+ color: #ff0000;
+ background: #ffffff;
+ }
+ table, tr, td, th {
+ border: 1px solid #666;
+ }
+
+ </style>
+ </head>
+ <body>
+ <h1 class="topbox">
+ <xsl:value-of select="tp:title" />
+ </h1>
+ <xsl:if test="tp:version">
+ <h2>Version <xsl:value-of select="string(tp:version)"/></h2>
+ </xsl:if>
+ <xsl:apply-templates select="tp:copyright"/>
+ <xsl:apply-templates select="tp:license"/>
+ <xsl:apply-templates select="tp:docstring"/>
+
+ <h2>Interfaces</h2>
+ <ul>
+ <xsl:for-each select="//node/interface">
+ <li><code><a href="#{@name}"><xsl:value-of select="@name"/></a></code></li>
+ </xsl:for-each>
+ </ul>
+
+ <xsl:apply-templates select="//node"/>
+ <xsl:apply-templates select="tp:generic-types"/>
+ <xsl:apply-templates select="tp:errors"/>
+
+ <h1>Index</h1>
+ <h2>Index of interfaces</h2>
+ <ul>
+ <xsl:for-each select="//node/interface">
+ <li><code><a href="#{@name}"><xsl:value-of select="@name"/></a></code></li>
+ </xsl:for-each>
+ </ul>
+ <h2>Index of types</h2>
+ <ul>
+ <xsl:for-each select="//tp:simple-type | //tp:enum | //tp:flags | //tp:mapping | //tp:struct | //tp:external-type">
+ <xsl:sort select="@name"/>
+ <li>
+ <code>
+ <a href="#type-{@name}">
+ <xsl:value-of select="@name"/>
+ </a>
+ </code>
+ <xsl:apply-templates mode="in-index" select="."/>
+ </li>
+ </xsl:for-each>
+ </ul>
+ </body>
+ </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/flymake.mk b/tools/flymake.mk
new file mode 100644
index 0000000..020a7bf
--- /dev/null
+++ b/tools/flymake.mk
@@ -0,0 +1,4 @@
+check-syntax:
+ $(CC) $(AM_CPPFLAGS) $(AM_CFLAGS) -fsyntax-only $(CHK_SOURCES)
+
+.PHONY: check-syntax
diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py
new file mode 100644
index 0000000..701fcaf
--- /dev/null
+++ b/tools/glib-client-gen.py
@@ -0,0 +1,1157 @@
+#!/usr/bin/python
+
+# glib-client-gen.py: "I Can't Believe It's Not dbus-binding-tool"
+#
+# Generate GLib client wrappers from the Telepathy specification.
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (C) 2006-2008 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import os.path
+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
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+class Generator(object):
+
+ def __init__(self, dom, prefix, basename, opts):
+ self.dom = dom
+ self.__header = []
+ self.__body = []
+
+ self.prefix_lc = prefix.lower()
+ self.prefix_uc = prefix.upper()
+ self.prefix_mc = prefix.replace('_', '')
+ self.basename = basename
+ self.group = opts.get('--group', None)
+ self.iface_quark_prefix = opts.get('--iface-quark-prefix', None)
+ self.tp_proxy_api = tuple(map(int,
+ opts.get('--tp-proxy-api', '0').split('.')))
+ self.proxy_cls = opts.get('--subclass', 'TpProxy') + ' *'
+ self.proxy_arg = opts.get('--subclass', 'void') + ' *'
+ self.proxy_assert = opts.get('--subclass-assert', 'TP_IS_PROXY')
+ self.proxy_doc = ('A #%s or subclass'
+ % opts.get('--subclass', 'TpProxy'))
+ if self.proxy_arg == 'void *':
+ self.proxy_arg = 'gpointer '
+
+ def h(self, s):
+ if isinstance(s, unicode):
+ s = s.encode('utf-8')
+ self.__header.append(s)
+
+ def b(self, s):
+ if isinstance(s, unicode):
+ s = s.encode('utf-8')
+ self.__body.append(s)
+
+ def get_iface_quark(self):
+ assert self.iface_dbus is not None
+ assert self.iface_uc is not None
+ if self.iface_quark_prefix is None:
+ return 'g_quark_from_static_string (\"%s\")' % self.iface_dbus
+ else:
+ return '%s_%s' % (self.iface_quark_prefix, self.iface_uc)
+
+ def do_signal(self, iface, signal):
+ iface_lc = iface.lower()
+
+ member = signal.getAttribute('name')
+ member_lc = camelcase_to_lower(member)
+ member_uc = member_lc.upper()
+
+ arg_count = 0
+ args = []
+ out_args = []
+
+ for arg in signal.getElementsByTagName('arg'):
+ name = arg.getAttribute('name')
+ type = arg.getAttribute('type')
+ tp_type = arg.getAttribute('tp:type')
+
+ if not name:
+ name = 'arg%u' % arg_count
+ arg_count += 1
+ else:
+ name = 'arg_%s' % name
+
+ info = type_to_gtype(type)
+ args.append((name, info, tp_type, arg))
+
+ callback_name = ('%s_%s_signal_callback_%s'
+ % (self.prefix_lc, iface_lc, member_lc))
+ collect_name = ('_%s_%s_collect_args_of_%s'
+ % (self.prefix_lc, iface_lc, member_lc))
+ invoke_name = ('_%s_%s_invoke_callback_for_%s'
+ % (self.prefix_lc, iface_lc, member_lc))
+
+ # Example:
+ #
+ # typedef void (*tp_cli_connection_signal_callback_new_channel)
+ # (TpConnection *proxy, const gchar *arg_object_path,
+ # const gchar *arg_channel_type, guint arg_handle_type,
+ # guint arg_handle, gboolean arg_suppress_handler,
+ # gpointer user_data, GObject *weak_object);
+
+ self.b('/**')
+ self.b(' * %s:' % callback_name)
+ self.b(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.b(' * was called')
+
+ for arg in args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ self.b(' * @%s: %s' % (name,
+ xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+ self.b(' * @user_data: User-supplied data')
+ self.b(' * @weak_object: User-supplied weakly referenced object')
+ self.b(' *')
+ self.b(' * Represents the signature of a callback for the signal %s.'
+ % member)
+ self.b(' */')
+ self.h('typedef void (*%s) (%sproxy,'
+ % (callback_name, self.proxy_cls))
+
+ for arg 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.h(' gpointer user_data, GObject *weak_object);')
+
+ if args:
+ self.b('static void')
+ self.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name)
+
+ for arg in args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ const = pointer and 'const ' or ''
+
+ self.b(' %s%s%s,' % (const, ctype, name))
+
+ self.b(' TpProxySignalConnection *sc)')
+ self.b('{')
+ self.b(' GValueArray *args = g_value_array_new (%d);' % len(args))
+ self.b(' GValue blank = { 0 };')
+ self.b(' guint i;')
+ self.b('')
+ self.b(' g_value_init (&blank, G_TYPE_INT);')
+ self.b('')
+ self.b(' for (i = 0; i < %d; i++)' % len(args))
+ self.b(' g_value_array_append (args, &blank);')
+ self.b('')
+
+ for i, arg in enumerate(args):
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ self.b(' g_value_unset (args->values + %d);' % i)
+ self.b(' g_value_init (args->values + %d, %s);' % (i, gtype))
+
+ if gtype == 'G_TYPE_STRING':
+ self.b(' g_value_set_string (args->values + %d, %s);'
+ % (i, name))
+ elif marshaller == 'BOXED':
+ self.b(' g_value_set_boxed (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_UCHAR':
+ self.b(' g_value_set_uchar (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_BOOLEAN':
+ self.b(' g_value_set_boolean (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_INT':
+ self.b(' g_value_set_int (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_UINT':
+ self.b(' g_value_set_uint (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_INT64':
+ self.b(' g_value_set_int (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_UINT64':
+ self.b(' g_value_set_uint64 (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_DOUBLE':
+ self.b(' g_value_set_double (args->values + %d, %s);'
+ % (i, name))
+ else:
+ assert False, ("Don't know how to put %s in a GValue"
+ % gtype)
+ self.b('')
+
+ self.b(' tp_proxy_signal_connection_v0_take_results (sc, args);')
+ self.b('}')
+
+ self.b('static void')
+ self.b('%s (TpProxy *tpproxy,' % invoke_name)
+ self.b(' GError *error G_GNUC_UNUSED,')
+ self.b(' GValueArray *args,')
+ self.b(' GCallback generic_callback,')
+ self.b(' gpointer user_data,')
+ self.b(' GObject *weak_object)')
+ self.b('{')
+ self.b(' %s callback =' % callback_name)
+ self.b(' (%s) generic_callback;' % callback_name)
+ self.b('')
+ self.b(' if (callback != NULL)')
+ self.b(' callback (g_object_ref (tpproxy),')
+
+ # FIXME: factor out into a function
+ for i, arg in enumerate(args):
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ if marshaller == 'BOXED':
+ self.b(' g_value_get_boxed (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_STRING':
+ self.b(' g_value_get_string (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_UCHAR':
+ self.b(' g_value_get_uchar (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_BOOLEAN':
+ self.b(' g_value_get_boolean (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_UINT':
+ self.b(' g_value_get_uint (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_INT':
+ self.b(' g_value_get_int (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_UINT64':
+ self.b(' g_value_get_uint64 (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_INT64':
+ self.b(' g_value_get_int64 (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_DOUBLE':
+ self.b(' g_value_get_double (args->values + %d),' % i)
+ else:
+ assert False, "Don't know how to get %s from a GValue" % gtype
+
+ self.b(' user_data,')
+ self.b(' weak_object);')
+ self.b('')
+
+ if len(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(' g_object_unref (tpproxy);')
+ self.b('}')
+
+ # Example:
+ #
+ # TpProxySignalConnection *
+ # tp_cli_connection_connect_to_new_channel
+ # (TpConnection *proxy,
+ # tp_cli_connection_signal_callback_new_channel callback,
+ # gpointer user_data,
+ # GDestroyNotify destroy);
+ #
+ # destroy is invoked when the signal becomes disconnected. This
+ # is either because the signal has been disconnected explicitly
+ # by the user, because the TpProxy has become invalid and
+ # emitted the 'invalidated' signal, or because the weakly referenced
+ # object has gone away.
+
+ self.b('/**')
+ self.b(' * %s_%s_connect_to_%s:'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.b(' * @proxy: %s' % self.proxy_doc)
+ self.b(' * @callback: Callback to be called when the signal is')
+ self.b(' * received')
+ self.b(' * @user_data: User-supplied data for the callback')
+ self.b(' * @destroy: Destructor for the user-supplied data, which')
+ self.b(' * will be called when this signal is disconnected, or')
+ self.b(' * before this function returns %NULL')
+ self.b(' * @weak_object: A #GObject which will be weakly referenced; ')
+ self.b(' * if it is destroyed, this callback will automatically be')
+ self.b(' * disconnected')
+ self.b(' * @error: If not %NULL, used to raise an error if %NULL is')
+ self.b(' * returned')
+ self.b(' *')
+ self.b(' * Connect a handler to the signal %s.' % member)
+ self.b(' *')
+ self.b(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
+ self.b(' *')
+ self.b(' * Returns: a #TpProxySignalConnection containing all of the')
+ self.b(' * above, which can be used to disconnect the signal; or')
+ self.b(' * %NULL if the proxy does not have the desired interface')
+ self.b(' * or has become invalid.')
+ self.b(' */')
+ self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,'
+ % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+ self.h(' %s callback,' % callback_name)
+ self.h(' gpointer user_data,')
+ self.h(' GDestroyNotify destroy,')
+ self.h(' GObject *weak_object,')
+ self.h(' GError **error);')
+
+ self.b('TpProxySignalConnection *')
+ self.b('%s_%s_connect_to_%s (%sproxy,'
+ % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+ self.b(' %s callback,' % callback_name)
+ self.b(' gpointer user_data,')
+ self.b(' GDestroyNotify destroy,')
+ self.b(' GObject *weak_object,')
+ self.b(' GError **error)')
+ self.b('{')
+ self.b(' GType expected_types[%d] = {' % (len(args) + 1))
+
+ for arg in args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ self.b(' %s,' % gtype)
+
+ self.b(' G_TYPE_INVALID };')
+ self.b('')
+ self.b(' g_return_val_if_fail (%s (proxy), NULL);'
+ % self.proxy_assert)
+ self.b(' g_return_val_if_fail (callback != NULL, NULL);')
+ self.b('')
+ self.b(' return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,')
+ self.b(' %s, \"%s\",' % (self.get_iface_quark(), member))
+ self.b(' expected_types,')
+
+ if args:
+ self.b(' G_CALLBACK (%s),' % collect_name)
+ else:
+ self.b(' NULL, /* no args => no collector function */')
+
+ self.b(' %s,' % invoke_name)
+ self.b(' G_CALLBACK (callback), user_data, destroy,')
+ self.b(' weak_object, error);')
+ self.b('}')
+ self.b('')
+
+ self.h('')
+
+ def do_method(self, iface, method):
+ iface_lc = iface.lower()
+
+ member = method.getAttribute('name')
+ member_lc = camelcase_to_lower(member)
+ member_uc = member_lc.upper()
+
+ in_count = 0
+ ret_count = 0
+ in_args = []
+ out_args = []
+
+ for arg in method.getElementsByTagName('arg'):
+ name = arg.getAttribute('name')
+ direction = arg.getAttribute('direction')
+ type = arg.getAttribute('type')
+ tp_type = arg.getAttribute('tp:type')
+
+ if direction != 'out':
+ if not name:
+ name = 'in%u' % in_count
+ in_count += 1
+ else:
+ name = 'in_%s' % name
+ else:
+ if not name:
+ name = 'out%u' % ret_count
+ ret_count += 1
+ else:
+ name = 'out_%s' % name
+
+ info = type_to_gtype(type)
+ if direction != 'out':
+ in_args.append((name, info, tp_type, arg))
+ else:
+ out_args.append((name, info, tp_type, arg))
+
+ # Async reply callback type
+
+ # Example:
+ # void (*tp_cli_properties_interface_callback_for_get_properties)
+ # (TpProxy *proxy,
+ # const GPtrArray *out0,
+ # const GError *error,
+ # gpointer user_data,
+ # GObject *weak_object);
+
+ self.b('/**')
+ self.b(' * %s_%s_callback_for_%s:'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.b(' * @proxy: the proxy on which the call was made')
+
+ 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 @error is '
+ '%%NULL: %s'
+ % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+ self.b(' * @error: %NULL on success, or an error on failure')
+ self.b(' * @user_data: user-supplied data')
+ self.b(' * @weak_object: user-supplied object')
+ self.b(' *')
+ self.b(' * Signature of the callback called when a %s method call'
+ % member)
+ self.b(' * succeeds or fails.')
+ self.b(' */')
+
+ callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
+ member_lc)
+
+ self.h('typedef void (*%s) (%sproxy,'
+ % (callback_name, self.proxy_cls))
+
+ for arg in out_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.h(' const GError *error, gpointer user_data,')
+ self.h(' GObject *weak_object);')
+ self.h('')
+
+ # Async callback implementation
+
+ invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
+ iface_lc,
+ member_lc)
+
+ collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
+ iface_lc,
+ member_lc)
+
+ # The callback called by dbus-glib; this ends the call and collects
+ # the results into a GValueArray.
+ self.b('static void')
+ self.b('%s (DBusGProxy *proxy,' % collect_callback)
+ self.b(' DBusGProxyCall *call,')
+ self.b(' gpointer user_data)')
+ self.b('{')
+ self.b(' GError *error = NULL;')
+
+ if len(out_args) > 0:
+ self.b(' GValueArray *args;')
+ self.b(' GValue blank = { 0 };')
+ self.b(' guint i;')
+
+ for arg in out_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ # "We handle variants specially; the caller is expected to
+ # have already allocated storage for them". Thanks,
+ # dbus-glib...
+ if gtype == 'G_TYPE_VALUE':
+ self.b(' GValue *%s = g_new0 (GValue, 1);' % name)
+ else:
+ self.b(' %s%s;' % (ctype, name))
+
+ self.b('')
+ self.b(' dbus_g_proxy_end_call (proxy, call, &error,')
+
+ for arg in out_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ if gtype == 'G_TYPE_VALUE':
+ self.b(' %s, %s,' % (gtype, name))
+ else:
+ self.b(' %s, &%s,' % (gtype, name))
+
+ self.b(' G_TYPE_INVALID);')
+
+ if len(out_args) == 0:
+ self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,'
+ 'NULL);')
+ else:
+ self.b('')
+ self.b(' if (error != NULL)')
+ self.b(' {')
+ self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,')
+ self.b(' NULL);')
+
+ for arg in out_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+ if gtype == 'G_TYPE_VALUE':
+ self.b(' g_free (%s);' % name)
+
+ self.b(' return;')
+ self.b(' }')
+ self.b('')
+ self.b(' args = g_value_array_new (%d);' % len(out_args))
+ self.b(' g_value_init (&blank, G_TYPE_INT);')
+ self.b('')
+ self.b(' for (i = 0; i < %d; i++)' % len(out_args))
+ self.b(' g_value_array_append (args, &blank);')
+
+ for i, arg in enumerate(out_args):
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ self.b('')
+ self.b(' g_value_unset (args->values + %d);' % i)
+ self.b(' g_value_init (args->values + %d, %s);' % (i, gtype))
+
+ if gtype == 'G_TYPE_STRING':
+ self.b(' g_value_take_string (args->values + %d, %s);'
+ % (i, name))
+ elif marshaller == 'BOXED':
+ self.b(' g_value_take_boxed (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_UCHAR':
+ self.b(' g_value_set_uchar (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_BOOLEAN':
+ self.b(' g_value_set_boolean (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_INT':
+ self.b(' g_value_set_int (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_UINT':
+ self.b(' g_value_set_uint (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_INT64':
+ self.b(' g_value_set_int (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_UINT64':
+ self.b(' g_value_set_uint (args->values + %d, %s);'
+ % (i, name))
+ elif gtype == 'G_TYPE_DOUBLE':
+ self.b(' g_value_set_double (args->values + %d, %s);'
+ % (i, name))
+ else:
+ assert False, ("Don't know how to put %s in a GValue"
+ % gtype)
+
+ self.b(' tp_proxy_pending_call_v0_take_results (user_data, '
+ 'NULL, args);')
+
+ self.b('}')
+
+ self.b('static void')
+ self.b('%s (TpProxy *self,' % invoke_callback)
+ self.b(' GError *error,')
+ self.b(' GValueArray *args,')
+ self.b(' GCallback generic_callback,')
+ self.b(' gpointer user_data,')
+ self.b(' GObject *weak_object)')
+ self.b('{')
+ self.b(' %s callback = (%s) generic_callback;'
+ % (callback_name, callback_name))
+ self.b('')
+ self.b(' if (error != NULL)')
+ self.b(' {')
+ self.b(' callback ((%s) self,' % self.proxy_cls)
+
+ for arg in out_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ if marshaller == 'BOXED' or pointer:
+ self.b(' NULL,')
+ elif gtype == 'G_TYPE_DOUBLE':
+ self.b(' 0.0,')
+ else:
+ self.b(' 0,')
+
+ self.b(' error, user_data, weak_object);')
+ self.b(' g_error_free (error);')
+ self.b(' return;')
+ self.b(' }')
+
+ self.b(' callback ((%s) self,' % self.proxy_cls)
+
+ # FIXME: factor out into a function
+ for i, arg in enumerate(out_args):
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ if marshaller == 'BOXED':
+ self.b(' g_value_get_boxed (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_STRING':
+ self.b(' g_value_get_string (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_UCHAR':
+ self.b(' g_value_get_uchar (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_BOOLEAN':
+ self.b(' g_value_get_boolean (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_UINT':
+ self.b(' g_value_get_uint (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_INT':
+ self.b(' g_value_get_int (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_UINT64':
+ self.b(' g_value_get_uint64 (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_INT64':
+ self.b(' g_value_get_int64 (args->values + %d),' % i)
+ elif gtype == 'G_TYPE_DOUBLE':
+ self.b(' g_value_get_double (args->values + %d),' % i)
+ else:
+ assert False, "Don't know how to get %s from a GValue" % gtype
+
+ self.b(' error, user_data, weak_object);')
+ 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('')
+
+ # Async stub
+
+ # Example:
+ # TpProxyPendingCall *
+ # tp_cli_properties_interface_call_get_properties
+ # (gpointer proxy,
+ # gint timeout_ms,
+ # const GArray *in_properties,
+ # tp_cli_properties_interface_callback_for_get_properties callback,
+ # gpointer user_data,
+ # GDestroyNotify *destructor);
+
+ self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
+ % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+ self.h(' gint timeout_ms,')
+
+ self.b('/**')
+ self.b(' * %s_%s_call_%s:'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.b(' * @proxy: the #TpProxy')
+ self.b(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
+ self.b(' * 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)')))
+
+ self.b(' * @callback: called when the method call succeeds or fails;')
+ self.b(' * may be %NULL to make a "fire and forget" call with no ')
+ self.b(' * reply tracking')
+ self.b(' * @user_data: user-supplied data passed to the callback;')
+ self.b(' * must be %NULL if @callback is %NULL')
+ self.b(' * @destroy: called with the user_data as argument, after the')
+ self.b(' * call has succeeded, failed or been cancelled;')
+ self.b(' * must be %NULL if @callback is %NULL')
+ self.b(' * @weak_object: If not %NULL, a #GObject which will be ')
+ self.b(' * weakly referenced; if it is destroyed, this call ')
+ self.b(' * will automatically be cancelled. Must be %NULL if ')
+ self.b(' * @callback is %NULL')
+ self.b(' *')
+ self.b(' * Start a %s method call.' % member)
+ self.b(' *')
+ self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
+ self.b(' *')
+ self.b(' * Returns: a #TpProxyPendingCall representing the call in')
+ self.b(' * progress. It is borrowed from the object, and will become')
+ self.b(' * invalid when the callback is called, the call is')
+ self.b(' * cancelled or the #TpProxy becomes invalid.')
+ self.b(' */')
+ self.b('TpProxyPendingCall *\n%s_%s_call_%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))
+
+ self.h(' %s callback,' % callback_name)
+ self.h(' gpointer user_data,')
+ self.h(' GDestroyNotify destroy,')
+ self.h(' GObject *weak_object);')
+ self.h('')
+
+ self.b(' %s callback,' % callback_name)
+ self.b(' gpointer user_data,')
+ self.b(' GDestroyNotify destroy,')
+ self.b(' GObject *weak_object)')
+ self.b('{')
+ self.b(' GError *error = NULL;')
+ self.b(' GQuark interface = %s;' % self.get_iface_quark())
+ self.b(' DBusGProxy *iface;')
+ self.b('')
+ self.b(' g_return_val_if_fail (%s (proxy), NULL);'
+ % self.proxy_assert)
+ self.b(' g_return_val_if_fail (callback != NULL || '
+ 'user_data == NULL, NULL);')
+ self.b(' g_return_val_if_fail (callback != NULL || '
+ 'destroy == NULL, NULL);')
+ self.b(' g_return_val_if_fail (callback != NULL || '
+ 'weak_object == NULL, NULL);')
+ self.b('')
+ self.b(' iface = tp_proxy_borrow_interface_by_id (')
+ self.b(' (TpProxy *) proxy,')
+ self.b(' interface, &error);')
+ self.b('')
+ self.b(' if (iface == NULL)')
+ self.b(' {')
+ self.b(' if (callback != NULL)')
+ self.b(' callback (proxy,')
+
+ for arg in out_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ if pointer:
+ self.b(' NULL,')
+ else:
+ self.b(' 0,')
+
+ self.b(' error, user_data, weak_object);')
+ self.b('')
+ self.b(' if (destroy != NULL)')
+ self.b(' destroy (user_data);')
+ self.b('')
+ self.b(' g_error_free (error);')
+ self.b(' return NULL;')
+ self.b(' }')
+ self.b('')
+ self.b(' if (callback == NULL)')
+ self.b(' {')
+ self.b(' dbus_g_proxy_call_no_reply (iface, "%s",' % member)
+
+ 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(' return NULL;')
+ self.b(' }')
+ self.b(' else')
+ self.b(' {')
+ self.b(' TpProxyPendingCall *data;')
+ self.b('')
+ self.b(' data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
+ self.b(' interface, "%s", iface,' % member)
+ self.b(' %s,' % invoke_callback)
+ self.b(' G_CALLBACK (callback), user_data, destroy,')
+ self.b(' weak_object, FALSE);')
+ self.b(' tp_proxy_pending_call_v0_take_pending_call (data,')
+ self.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
+ self.b(' "%s",' % member)
+ self.b(' %s,' % collect_callback)
+ self.b(' data,')
+ 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(' return data;')
+ self.b(' }')
+ self.b('}')
+ self.b('')
+
+ # 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('')
+
+ # leave a gap for the end of the method
+ self.b('')
+ self.h('')
+
+ def do_signal_add(self, signal):
+ marshaller_items = []
+ gtypes = []
+
+ for i in signal.getElementsByTagName('arg'):
+ name = i.getAttribute('name')
+ type = i.getAttribute('type')
+ info = type_to_gtype(type)
+ # type, GType, STRING, is a pointer
+ gtypes.append(info[1])
+
+ self.b(' dbus_g_proxy_add_signal (proxy, "%s",'
+ % signal.getAttribute('name'))
+ for gtype in gtypes:
+ self.b(' %s,' % gtype)
+ self.b(' G_TYPE_INVALID);')
+
+ def do_interface(self, node):
+ ifaces = node.getElementsByTagName('interface')
+ assert len(ifaces) == 1
+ iface = ifaces[0]
+ name = node.getAttribute('name').replace('/', '')
+
+ self.iface = name
+ self.iface_lc = name.lower()
+ self.iface_uc = name.upper()
+ self.iface_mc = name.replace('_', '')
+ self.iface_dbus = iface.getAttribute('name')
+
+ signals = node.getElementsByTagName('signal')
+ methods = node.getElementsByTagName('method')
+
+ if signals:
+ self.b('static inline void')
+ self.b('%s_add_signals_for_%s (DBusGProxy *proxy)'
+ % (self.prefix_lc, name.lower()))
+ self.b('{')
+
+ if self.tp_proxy_api >= (0, 7, 6):
+ self.b(' if (!tp_proxy_dbus_g_proxy_claim_for_signal_adding '
+ '(proxy))')
+ self.b(' return;')
+
+ for signal in signals:
+ self.do_signal_add(signal)
+
+ self.b('}')
+ self.b('')
+ self.b('')
+
+ for signal in signals:
+ self.do_signal(name, signal)
+
+ for method in methods:
+ self.do_method(name, method)
+
+ self.iface_dbus = None
+
+ def __call__(self):
+
+ self.h('G_BEGIN_DECLS')
+ self.h('')
+
+ self.b('/* We don\'t want gtkdoc scanning this file, it\'ll get')
+ self.b(' * confused by seeing function definitions, so mark it as: */')
+ self.b('/*<private_header>*/')
+ self.b('')
+
+ nodes = self.dom.getElementsByTagName('node')
+ nodes.sort(cmp_by_name)
+
+ for node in nodes:
+ self.do_interface(node)
+
+ if self.group is not None:
+
+ self.b('/*')
+ self.b(' * %s_%s_add_signals:' % (self.prefix_lc, self.group))
+ self.b(' * @self: the #TpProxy')
+ self.b(' * @quark: a quark whose string value is the interface')
+ self.b(' * name whose signals should be added')
+ self.b(' * @proxy: the D-Bus proxy to which to add the signals')
+ self.b(' * @unused: not used for anything')
+ self.b(' *')
+ self.b(' * Tell dbus-glib that @proxy has the signatures of all')
+ self.b(' * signals on the given interface, if it\'s one we')
+ self.b(' * support.')
+ self.b(' *')
+ self.b(' * This function should be used as a signal handler for')
+ self.b(' * #TpProxy::interface-added.')
+ self.b(' */')
+ self.b('static void')
+ self.b('%s_%s_add_signals (TpProxy *self G_GNUC_UNUSED,'
+ % (self.prefix_lc, self.group))
+ self.b(' guint quark,')
+ self.b(' DBusGProxy *proxy,')
+ self.b(' gpointer unused G_GNUC_UNUSED)')
+
+ self.b('{')
+
+ for node in nodes:
+ iface = node.getElementsByTagName('interface')[0]
+ self.iface_dbus = iface.getAttribute('name')
+ signals = node.getElementsByTagName('signal')
+ if not signals:
+ continue
+ name = node.getAttribute('name').replace('/', '').lower()
+ self.iface_uc = name.upper()
+ self.b(' if (quark == %s)' % self.get_iface_quark())
+ self.b(' %s_add_signals_for_%s (proxy);'
+ % (self.prefix_lc, name))
+
+ self.b('}')
+ self.b('')
+
+ self.h('G_END_DECLS')
+ self.h('')
+
+ open(self.basename + '.h', 'w').write('\n'.join(self.__header))
+ open(self.basename + '-body.h', 'w').write('\n'.join(self.__body))
+
+
+def types_to_gtypes(types):
+ return [type_to_gtype(t)[1] for t in types]
+
+
+if __name__ == '__main__':
+ options, argv = gnu_getopt(sys.argv[1:], '',
+ ['group=', 'subclass=', 'subclass-assert=',
+ 'iface-quark-prefix=', 'tp-proxy-api='])
+
+ opts = {}
+
+ for option, value in options:
+ opts[option] = value
+
+ dom = xml.dom.minidom.parse(argv[0])
+
+ Generator(dom, argv[1], argv[2], opts)()
diff --git a/tools/glib-client-marshaller-gen.py b/tools/glib-client-marshaller-gen.py
new file mode 100644
index 0000000..5444725
--- /dev/null
+++ b/tools/glib-client-marshaller-gen.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+from string import ascii_letters, digits
+
+
+from libglibcodegen import signal_to_marshal_name
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+class Generator(object):
+
+ def __init__(self, dom, prefix):
+ self.dom = dom
+ self.marshallers = {}
+ self.prefix = prefix
+
+ def do_signal(self, signal):
+ marshaller = signal_to_marshal_name(signal, self.prefix)
+
+ assert '__' in marshaller
+ rhs = marshaller.split('__', 1)[1].split('_')
+
+ self.marshallers[marshaller] = rhs
+
+ def __call__(self):
+ signals = self.dom.getElementsByTagName('signal')
+
+ for signal in signals:
+ self.do_signal(signal)
+
+ print 'void'
+ print '%s_register_dbus_glib_marshallers (void)' % self.prefix
+ print '{'
+
+ all = self.marshallers.keys()
+ all.sort()
+ for marshaller in all:
+ rhs = self.marshallers[marshaller]
+
+ print ' dbus_g_object_register_marshaller (%s,' % marshaller
+ print ' G_TYPE_NONE, /* return */'
+ for type in rhs:
+ print ' G_TYPE_%s,' % type.replace('VOID', 'NONE')
+ print ' G_TYPE_INVALID);'
+
+ print '}'
+
+
+def types_to_gtypes(types):
+ return [type_to_gtype(t)[1] for t in types]
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+ dom = xml.dom.minidom.parse(argv[0])
+
+ Generator(dom, argv[1])()
diff --git a/tools/glib-errors-enum-body-gen.py b/tools/glib-errors-enum-body-gen.py
new file mode 100644
index 0000000..44863ee
--- /dev/null
+++ b/tools/glib-errors-enum-body-gen.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \
+ get_descendant_text
+
+class Generator(object):
+ def __init__(self, dom):
+ self.dom = dom
+ self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0]
+
+ def do_header(self):
+ print '/* Generated from the Telepathy spec\n'
+ copyrights = self.errors.getElementsByTagNameNS(NS_TP, 'copyright')
+ for copyright in copyrights:
+ print get_descendant_text(copyright)
+ license = self.errors.getElementsByTagNameNS(NS_TP, 'license')[0]
+ print '\n' + get_descendant_text(license) + '\n*/'
+
+ def do_enum_values(self):
+ for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'):
+ print ''
+ nick = error.getAttribute('name').replace(' ', '')
+ name = camelcase_to_upper(nick.replace('.', ''))
+ ns = error.parentNode.getAttribute('namespace')
+ enum = 'TP_ERROR_' + name
+ print ' /* ' + ns + '.' + name
+ print ' ' + get_docstring(error)
+ print ' */'
+ print ' { %s, "%s", "%s" },' % (enum, enum, nick)
+
+
+ def do_get_type(self):
+ print """
+#include <_gen/telepathy-errors.h>
+
+GType
+tp_error_get_type (void)
+{
+ static GType etype = 0;
+ if (G_UNLIKELY (etype == 0))
+ {
+ static const GEnumValue values[] = {"""
+ self.do_enum_values()
+ print """\
+ };
+
+ etype = g_enum_register_static ("TpError", values);
+ }
+ return etype;
+}
+"""
+
+ def __call__(self):
+ self.do_header()
+ self.do_get_type()
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+ Generator(xml.dom.minidom.parse(argv[0]))()
diff --git a/tools/glib-errors-enum-header-gen.py b/tools/glib-errors-enum-header-gen.py
new file mode 100644
index 0000000..64939b4
--- /dev/null
+++ b/tools/glib-errors-enum-header-gen.py
@@ -0,0 +1,75 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \
+ get_descendant_text
+
+class Generator(object):
+ def __init__(self, dom):
+ self.dom = dom
+ self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0]
+
+ def do_header(self):
+ print '/* Generated from the Telepathy spec\n'
+ copyrights = self.errors.getElementsByTagNameNS(NS_TP, 'copyright')
+ for copyright in copyrights:
+ print get_descendant_text(copyright)
+ license = self.errors.getElementsByTagNameNS(NS_TP, 'license')[0]
+ print '\n' + get_descendant_text(license) + '\n*/'
+
+ def do_gtkdoc(self):
+ for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'):
+ ns = error.parentNode.getAttribute('namespace')
+ nick = error.getAttribute('name').replace(' ', '')
+ enum = 'TP_ERROR_' + camelcase_to_upper(nick.replace('.', ''))
+ print ' * @' + enum + ': ' + ns + '.' + nick + ':'
+ print ' * ' + get_docstring(error) + ' '
+
+ def do_enumnames(self):
+ for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'):
+ nick = error.getAttribute('name').replace(' ', '')
+ enum = 'TP_ERROR_' + camelcase_to_upper(nick.replace('.', ''))
+ print ' ' + enum + ','
+
+ def do_get_type(self):
+ print """
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+GType tp_error_get_type (void);
+
+/**
+ * TP_TYPE_ERROR:
+ *
+ * The GType of the Telepathy error enumeration.
+ */
+#define TP_TYPE_ERROR (tp_error_get_type())
+"""
+
+ def do_enum(self):
+ print """\
+/**
+ * TpError:"""
+ self.do_gtkdoc()
+ print """\
+ *
+ * Enumerated type representing the Telepathy D-Bus errors.
+ */
+typedef enum {"""
+ self.do_enumnames()
+ print """\
+} TpError;
+
+G_END_DECLS"""
+
+ def __call__(self):
+ self.do_header()
+ self.do_get_type()
+ self.do_enum()
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+ Generator(xml.dom.minidom.parse(argv[0]))()
diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py
new file mode 100644
index 0000000..9eb7af5
--- /dev/null
+++ b/tools/glib-ginterface-gen.py
@@ -0,0 +1,722 @@
+#!/usr/bin/python
+
+# glib-ginterface-gen.py: service-side interface generator
+#
+# Generate dbus-glib 0.x service GInterfaces from the Telepathy specification.
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (C) 2006, 2007 Collabora Limited
+#
+# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+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, \
+ signal_to_marshal_name, method_to_glue_marshal_name
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+class Generator(object):
+
+ def __init__(self, dom, prefix, basename, signal_marshal_prefix,
+ headers, end_headers, not_implemented_func,
+ allow_havoc):
+ self.dom = dom
+ self.__header = []
+ self.__body = []
+
+ assert prefix.endswith('_')
+ assert not signal_marshal_prefix.endswith('_')
+
+ # The main_prefix, sub_prefix thing is to get:
+ # FOO_ -> (FOO_, _)
+ # FOO_SVC_ -> (FOO_, _SVC_)
+ # but
+ # FOO_BAR/ -> (FOO_BAR_, _)
+ # FOO_BAR/SVC_ -> (FOO_BAR_, _SVC_)
+
+ if '/' in prefix:
+ main_prefix, sub_prefix = prefix.upper().split('/', 1)
+ prefix = prefix.replace('/', '_')
+ else:
+ main_prefix, sub_prefix = prefix.upper().split('_', 1)
+
+ self.MAIN_PREFIX_ = main_prefix + '_'
+ self._SUB_PREFIX_ = '_' + sub_prefix
+
+ self.Prefix_ = prefix
+ self.Prefix = prefix.replace('_', '')
+ self.prefix_ = prefix.lower()
+ self.PREFIX_ = prefix.upper()
+
+ 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
+
+ def h(self, s):
+ self.__header.append(s)
+
+ def b(self, s):
+ self.__body.append(s)
+
+ def do_node(self, node):
+ node_name = node.getAttribute('name').replace('/', '')
+ node_name_mixed = self.node_name_mixed = node_name.replace('_', '')
+ node_name_lc = self.node_name_lc = node_name.lower()
+ node_name_uc = self.node_name_uc = node_name.upper()
+
+ interfaces = node.getElementsByTagName('interface')
+ assert len(interfaces) == 1, interfaces
+ interface = interfaces[0]
+ self.iface_name = interface.getAttribute('name')
+
+ tmp = interface.getAttribute('tp:implement-service')
+ if tmp == "no":
+ return
+
+ tmp = interface.getAttribute('tp:causes-havoc')
+ if tmp and not self.allow_havoc:
+ raise AssertionError('%s is %s' % (self.iface_name, tmp))
+
+ self.b('static const DBusGObjectInfo _%s%s_object_info;'
+ % (self.prefix_, node_name_lc))
+ self.b('')
+
+ methods = interface.getElementsByTagName('method')
+ signals = interface.getElementsByTagName('signal')
+ properties = interface.getElementsByTagName('property')
+ # Don't put properties in dbus-glib glue
+ glue_properties = []
+
+ self.b('struct _%s%sClass {' % (self.Prefix, node_name_mixed))
+ self.b(' GTypeInterface parent_class;')
+ for method in methods:
+ self.b(' %s %s;' % self.get_method_impl_names(method))
+ self.b('};')
+ self.b('')
+
+ if signals:
+ self.b('enum {')
+ for signal in signals:
+ self.b(' %s,' % self.get_signal_const_entry(signal))
+ self.b(' N_%s_SIGNALS' % node_name_uc)
+ self.b('};')
+ self.b('static guint %s_signals[N_%s_SIGNALS] = {0};'
+ % (node_name_lc, node_name_uc))
+ self.b('')
+
+ self.b('static void %s%s_base_init (gpointer klass);'
+ % (self.prefix_, node_name_lc))
+ self.b('')
+
+ self.b('GType')
+ self.b('%s%s_get_type (void)'
+ % (self.prefix_, node_name_lc))
+ self.b('{')
+ self.b(' static GType type = 0;')
+ self.b('')
+ self.b(' if (G_UNLIKELY (type == 0))')
+ self.b(' {')
+ self.b(' static const GTypeInfo info = {')
+ self.b(' sizeof (%s%sClass),' % (self.Prefix, node_name_mixed))
+ self.b(' %s%s_base_init, /* base_init */'
+ % (self.prefix_, node_name_lc))
+ self.b(' NULL, /* base_finalize */')
+ self.b(' NULL, /* class_init */')
+ self.b(' NULL, /* class_finalize */')
+ self.b(' NULL, /* class_data */')
+ self.b(' 0,')
+ self.b(' 0, /* n_preallocs */')
+ self.b(' NULL /* instance_init */')
+ self.b(' };')
+ self.b('')
+ self.b(' type = g_type_register_static (G_TYPE_INTERFACE,')
+ self.b(' "%s%s", &info, 0);' % (self.Prefix, node_name_mixed))
+ self.b(' }')
+ self.b('')
+ self.b(' return type;')
+ self.b('}')
+ self.b('')
+
+ self.h('/**')
+ self.h(' * %s%s:' % (self.Prefix, node_name_mixed))
+ self.h(' *')
+ self.h(' * Dummy typedef representing any implementation of this '
+ 'interface.')
+ self.h(' */')
+ self.h('typedef struct _%s%s %s%s;'
+ % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
+ self.h('')
+ self.h('/**')
+ self.h(' * %s%sClass:' % (self.Prefix, node_name_mixed))
+ self.h(' *')
+ self.h(' * The class of %s%s.' % (self.Prefix, node_name_mixed))
+ self.h(' */')
+ self.h('typedef struct _%s%sClass %s%sClass;'
+ % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
+ self.h('')
+ self.h('GType %s%s_get_type (void);'
+ % (self.prefix_, node_name_lc))
+
+ gtype = self.current_gtype = \
+ self.MAIN_PREFIX_ + 'TYPE' + self._SUB_PREFIX_ + node_name_uc
+ classname = self.Prefix + node_name_mixed
+
+ self.h('#define %s \\\n (%s%s_get_type ())'
+ % (gtype, self.prefix_, node_name_lc))
+ self.h('#define %s%s(obj) \\\n'
+ ' (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))'
+ % (self.PREFIX_, node_name_uc, gtype, classname))
+ self.h('#define %sIS%s%s(obj) \\\n'
+ ' (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))'
+ % (self.MAIN_PREFIX_, self._SUB_PREFIX_, node_name_uc, gtype))
+ self.h('#define %s%s_GET_CLASS(obj) \\\n'
+ ' (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))'
+ % (self.PREFIX_, node_name_uc, gtype, classname))
+ self.h('')
+ self.h('')
+
+ base_init_code = []
+
+ for method in methods:
+ self.do_method(method)
+
+ for signal in signals:
+ base_init_code.extend(self.do_signal(signal))
+
+ self.b('static inline void')
+ self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)'
+ % (self.prefix_, node_name_lc))
+ self.b('{')
+ self.b(' static TpDBusPropertiesMixinPropInfo properties[%d] = {'
+ % (len(properties) + 1))
+
+ for m in properties:
+ access = m.getAttribute('access')
+ assert access in ('read', 'write', 'readwrite')
+
+ if access == 'read':
+ flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_READ'
+ elif access == 'write':
+ flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE'
+ else:
+ flags = ('TP_DBUS_PROPERTIES_MIXIN_FLAG_READ | '
+ 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE')
+
+ self.b(' { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
+ % (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(' 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].type = %s;'
+ % (i, type_to_gtype(m.getAttribute('type'))[1]))
+
+ 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')
+ self.b('%s%s_base_init (gpointer klass)'
+ % (self.prefix_, node_name_lc))
+ self.b('{')
+ self.b(' static gboolean initialized = FALSE;')
+ self.b('')
+ self.b(' if (!initialized)')
+ self.b(' {')
+ self.b(' initialized = TRUE;')
+ self.b(' %s%s_base_init_once (klass);'
+ % (self.prefix_, node_name_lc))
+ self.b(' }')
+ # insert anything we need to do per implementation here
+ self.b('}')
+
+ self.h('')
+
+ self.b('static const DBusGMethodInfo _%s%s_methods[] = {'
+ % (self.prefix_, node_name_lc))
+
+ method_blob, offsets = self.get_method_glue(methods)
+
+ for method, offset in zip(methods, offsets):
+ self.do_method_glue(method, offset)
+
+ self.b('};')
+ self.b('')
+
+ self.b('static const DBusGObjectInfo _%s%s_object_info = {'
+ % (self.prefix_, node_name_lc))
+ self.b(' 0,') # version
+ self.b(' _%s%s_methods,' % (self.prefix_, node_name_lc))
+ self.b(' %d,' % len(methods))
+ self.b('"' + method_blob.replace('\0', '\\0') + '",')
+ self.b('"' + self.get_signal_glue(signals).replace('\0', '\\0') + '",')
+ self.b('"' +
+ self.get_property_glue(glue_properties).replace('\0', '\\0') +
+ '",')
+ self.b('};')
+ self.b('')
+
+ self.node_name_mixed = None
+ self.node_name_lc = None
+ self.node_name_uc = None
+
+ def get_method_glue(self, methods):
+ info = []
+ offsets = []
+
+ for method in methods:
+ offsets.append(len(''.join(info)))
+
+ info.append(self.iface_name + '\0')
+ info.append(method.getAttribute('name') + '\0')
+
+ info.append('A\0') # async
+
+ counter = 0
+ for arg in method.getElementsByTagName('arg'):
+ out = arg.getAttribute('direction') == 'out'
+
+ name = arg.getAttribute('name')
+ if not name:
+ assert out
+ name = 'arg%u' % counter
+ counter += 1
+
+ info.append(name + '\0')
+
+ if out:
+ info.append('O\0')
+ else:
+ info.append('I\0')
+
+ if out:
+ info.append('F\0') # not const
+ info.append('N\0') # not error or return
+ info.append(arg.getAttribute('type') + '\0')
+
+ info.append('\0')
+
+ return ''.join(info) + '\0', offsets
+
+ def do_method_glue(self, method, offset):
+ lc_name = camelcase_to_lower(method.getAttribute('name'))
+
+ marshaller = method_to_glue_marshal_name(method,
+ self.signal_marshal_prefix)
+ wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name
+
+ self.b(" { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset))
+
+ def get_signal_glue(self, signals):
+ info = []
+
+ for signal in signals:
+ info.append(self.iface_name)
+ info.append(signal.getAttribute('name'))
+
+ return '\0'.join(info) + '\0\0'
+
+ # the implementation can be the same
+ get_property_glue = get_signal_glue
+
+ def get_method_impl_names(self, method):
+ dbus_method_name = method.getAttribute('name')
+ class_member_name = camelcase_to_lower(dbus_method_name)
+ stub_name = (self.prefix_ + self.node_name_lc + '_' +
+ class_member_name)
+ return (stub_name + '_impl', class_member_name)
+
+ def do_method(self, method):
+ assert self.node_name_mixed is not None
+
+ in_class = []
+
+ # Examples refer to Thing.DoStuff (su) -> ii
+
+ # DoStuff
+ dbus_method_name = method.getAttribute('name')
+ # do_stuff
+ class_member_name = camelcase_to_lower(dbus_method_name)
+ # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint,
+ # DBusGMethodInvocation *);
+ stub_name = (self.prefix_ + self.node_name_lc + '_' +
+ class_member_name)
+ # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *,
+ # const char *, guint, DBusGMethodInvocation);
+ impl_name = stub_name + '_impl'
+ # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *,
+ # gint, gint);
+ ret_name = (self.prefix_ + self.node_name_lc + '_return_from_' +
+ class_member_name)
+
+ # Gather arguments
+ in_args = []
+ out_args = []
+ for i in method.getElementsByTagName('arg'):
+ name = i.getAttribute('name')
+ direction = i.getAttribute('direction') or 'in'
+ dtype = i.getAttribute('type')
+
+ assert direction in ('in', 'out')
+
+ if name:
+ name = direction + '_' + name
+ elif direction == 'in':
+ name = direction + str(len(in_args))
+ else:
+ name = direction + str(len(out_args))
+
+ ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
+
+ if pointer:
+ ctype = 'const ' + ctype
+
+ struct = (ctype, name)
+
+ if direction == 'in':
+ in_args.append(struct)
+ else:
+ out_args.append(struct)
+
+ # Implementation type declaration (in header, docs in body)
+ self.b('/**')
+ self.b(' * %s:' % impl_name)
+ self.b(' * @self: The object implementing this interface')
+ for (ctype, name) in in_args:
+ self.b(' * @%s: %s (FIXME, generate documentation)'
+ % (name, ctype))
+ self.b(' * @context: Used to return values or throw an error')
+ self.b(' *')
+ self.b(' * The signature of an implementation of the D-Bus method')
+ self.b(' * %s on interface %s.' % (dbus_method_name, self.iface_name))
+ self.b(' */')
+ self.h('typedef void (*%s) (%s%s *self,'
+ % (impl_name, self.Prefix, self.node_name_mixed))
+ for (ctype, name) in in_args:
+ self.h(' %s%s,' % (ctype, name))
+ self.h(' DBusGMethodInvocation *context);')
+
+ # Class member (in class definition)
+ in_class.append(' %s %s;' % (impl_name, class_member_name))
+
+ # Stub definition (in body only - it's static)
+ self.b('static void')
+ self.b('%s (%s%s *self,'
+ % (stub_name, self.Prefix, self.node_name_mixed))
+ for (ctype, name) in in_args:
+ self.b(' %s%s,' % (ctype, name))
+ self.b(' DBusGMethodInvocation *context)')
+ self.b('{')
+ self.b(' %s impl = (%s%s_GET_CLASS (self)->%s);'
+ % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name))
+ self.b('')
+ self.b(' if (impl != NULL)')
+ tmp = ['self'] + [name for (ctype, name) in in_args] + ['context']
+ self.b(' {')
+ self.b(' (impl) (%s);' % ',\n '.join(tmp))
+ self.b(' }')
+ self.b(' else')
+ self.b(' {')
+ if self.not_implemented_func:
+ self.b(' %s (context);' % self.not_implemented_func)
+ else:
+ self.b(' GError e = { DBUS_GERROR, ')
+ self.b(' DBUS_GERROR_UNKNOWN_METHOD,')
+ self.b(' "Method not implemented" };')
+ self.b('')
+ self.b(' dbus_g_method_return_error (context, &e);')
+ self.b(' }')
+ self.b('}')
+ self.b('')
+
+ # Implementation registration (in both header and body)
+ self.h('void %s%s_implement_%s (%s%sClass *klass, %s impl);'
+ % (self.prefix_, self.node_name_lc, class_member_name,
+ self.Prefix, self.node_name_mixed, impl_name))
+
+ self.b('/**')
+ self.b(' * %s%s_implement_%s:'
+ % (self.prefix_, self.node_name_lc, class_member_name))
+ self.b(' * @klass: A class whose instances implement this interface')
+ self.b(' * @impl: A callback used to implement the %s D-Bus method'
+ % dbus_method_name)
+ self.b(' *')
+ self.b(' * Register an implementation for the %s method in the vtable'
+ % dbus_method_name)
+ self.b(' * of an implementation of this interface. To be called from')
+ self.b(' * the interface init function.')
+ self.b(' */')
+ self.b('void')
+ self.b('%s%s_implement_%s (%s%sClass *klass, %s impl)'
+ % (self.prefix_, self.node_name_lc, class_member_name,
+ self.Prefix, self.node_name_mixed, impl_name))
+ self.b('{')
+ self.b(' klass->%s = impl;' % class_member_name)
+ self.b('}')
+ self.b('')
+
+ # Return convenience function (static inline, in header)
+ self.h('/**')
+ self.h(' * %s:' % ret_name)
+ self.h(' * @context: The D-Bus method invocation context')
+ for (ctype, name) in out_args:
+ self.h(' * @%s: %s (FIXME, generate documentation)'
+ % (name, ctype))
+ self.h(' *')
+ self.h(' * Return successfully by calling dbus_g_method_return().')
+ self.h(' * This inline function exists only to provide type-safety.')
+ self.h(' */')
+ tmp = (['DBusGMethodInvocation *context'] +
+ [ctype + name for (ctype, name) in out_args])
+ self.h('static inline')
+ self.h('/* this comment is to stop gtkdoc realising this is static */')
+ self.h(('void %s (' % ret_name) + (',\n '.join(tmp)) + ');')
+ self.h('static inline void')
+ self.h(('%s (' % ret_name) + (',\n '.join(tmp)) + ')')
+ self.h('{')
+ tmp = ['context'] + [name for (ctype, name) in out_args]
+ self.h(' dbus_g_method_return (' + ',\n '.join(tmp) + ');')
+ self.h('}')
+ self.h('')
+
+ return in_class
+
+ def get_signal_const_entry(self, signal):
+ assert self.node_name_uc is not None
+ return ('SIGNAL_%s_%s'
+ % (self.node_name_uc, signal.getAttribute('name')))
+
+ def do_signal(self, signal):
+ assert self.node_name_mixed is not None
+
+ in_base_init = []
+
+ # for signal: Thing::StuffHappened (s, u)
+ # we want to emit:
+ # void tp_svc_thing_emit_stuff_happened (gpointer instance,
+ # const char *arg0, guint arg1);
+
+ dbus_name = signal.getAttribute('name')
+ stub_name = (self.prefix_ + self.node_name_lc + '_emit_' +
+ camelcase_to_lower(dbus_name))
+ const_name = self.get_signal_const_entry(signal)
+
+ # Gather arguments
+ args = []
+ for i in signal.getElementsByTagName('arg'):
+ name = i.getAttribute('name')
+ dtype = i.getAttribute('type')
+ tp_type = i.getAttribute('tp:type')
+
+ if name:
+ name = 'arg_' + name
+ else:
+ name = 'arg' + str(len(args))
+
+ ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
+
+ if pointer:
+ ctype = 'const ' + ctype
+
+ struct = (ctype, name, gtype)
+ args.append(struct)
+
+ tmp = (['gpointer instance'] +
+ [ctype + name for (ctype, name, gtype) in args])
+
+ self.h(('void %s (' % stub_name) + (',\n '.join(tmp)) + ');')
+
+ # FIXME: emit docs
+
+ self.b('/**')
+ self.b(' * %s:' % stub_name)
+ self.b(' * @instance: The object implementing this interface')
+ for (ctype, name, gtype) in args:
+ self.b(' * @%s: %s (FIXME, generate documentation)'
+ % (name, ctype))
+ self.b(' *')
+ self.b(' * Type-safe wrapper around g_signal_emit to emit the')
+ self.b(' * %s signal on interface %s.'
+ % (dbus_name, self.iface_name))
+ self.b(' */')
+
+ self.b('void')
+ self.b(('%s (' % stub_name) + (',\n '.join(tmp)) + ')')
+ self.b('{')
+ self.b(' g_assert (instance != NULL);')
+ self.b(' g_assert (G_TYPE_CHECK_INSTANCE_TYPE (instance, %s));'
+ % (self.current_gtype))
+ tmp = (['instance', '%s_signals[%s]' % (self.node_name_lc, const_name),
+ '0'] + [name for (ctype, name, gtype) in args])
+ self.b(' g_signal_emit (' + ',\n '.join(tmp) + ');')
+ self.b('}')
+ self.b('')
+
+ signal_name = dbus_gutils_wincaps_to_uscore(dbus_name).replace('_',
+ '-')
+ in_base_init.append(' /**')
+ in_base_init.append(' * %s%s::%s:'
+ % (self.Prefix, self.node_name_mixed, signal_name))
+ for (ctype, name, gtype) in args:
+ in_base_init.append(' * @%s: %s (FIXME, generate documentation)'
+ % (name, ctype))
+ in_base_init.append(' *')
+ in_base_init.append(' * The %s D-Bus signal is emitted whenever '
+ 'this GObject signal is.' % dbus_name)
+ in_base_init.append(' */')
+ in_base_init.append(' %s_signals[%s] ='
+ % (self.node_name_lc, const_name))
+ in_base_init.append(' g_signal_new ("%s",' % signal_name)
+ in_base_init.append(' G_OBJECT_CLASS_TYPE (klass),')
+ in_base_init.append(' G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,')
+ in_base_init.append(' 0,')
+ in_base_init.append(' NULL, NULL,')
+ in_base_init.append(' %s,'
+ % signal_to_marshal_name(signal, self.signal_marshal_prefix))
+ in_base_init.append(' G_TYPE_NONE,')
+ tmp = ['%d' % len(args)] + [gtype for (ctype, name, gtype) in args]
+ in_base_init.append(' %s);' % ',\n '.join(tmp))
+ in_base_init.append('')
+
+ return in_base_init
+
+ def __call__(self):
+ self.h('#include <glib-object.h>')
+ self.h('#include <dbus/dbus-glib.h>')
+ 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('')
+ 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)
+
+ self.h('')
+ self.h('G_END_DECLS')
+
+ self.b('')
+ for header in self.end_headers:
+ self.b('#include %s' % header)
+
+ self.h('')
+ self.b('')
+ open(basename + '.h', 'w').write('\n'.join(self.__header))
+ open(basename + '.c', 'w').write('\n'.join(self.__body))
+
+
+def cmdline_error():
+ print """\
+usage:
+ gen-ginterface [OPTIONS] xmlfile Prefix_
+options:
+ --include='<header.h>' (may be repeated)
+ --include='"header.h"' (ditto)
+ --include-end='"header.h"' (ditto)
+ Include extra headers in the generated .c file
+ --signal-marshal-prefix='prefix'
+ Use the given prefix on generated signal marshallers (default is
+ prefix.lower()).
+ --filename='BASENAME'
+ Set the basename for the output files (default is prefix.lower()
+ + 'ginterfaces')
+ --not-implemented-func='symbol'
+ Set action when methods not implemented in the interface vtable are
+ called. symbol must have signature
+ void symbol (DBusGMethodInvocation *context)
+ and return some sort of "not implemented" error via
+ dbus_g_method_return_error (context, ...)
+"""
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ from getopt import gnu_getopt
+
+ options, argv = gnu_getopt(sys.argv[1:], '',
+ ['filename=', 'signal-marshal-prefix=',
+ 'include=', 'include-end=',
+ 'allow-unstable',
+ 'not-implemented-func='])
+
+ try:
+ prefix = argv[1]
+ except IndexError:
+ cmdline_error()
+
+ basename = prefix.lower() + 'ginterfaces'
+ signal_marshal_prefix = prefix.lower().rstrip('_')
+ headers = []
+ end_headers = []
+ not_implemented_func = ''
+ allow_havoc = False
+
+ for option, value in options:
+ if option == '--filename':
+ basename = value
+ elif option == '--signal-marshal-prefix':
+ signal_marshal_prefix = value
+ elif option == '--include':
+ if value[0] not in '<"':
+ value = '"%s"' % value
+ headers.append(value)
+ elif option == '--include-end':
+ if value[0] not in '<"':
+ value = '"%s"' % value
+ end_headers.append(value)
+ elif option == '--not-implemented-func':
+ not_implemented_func = value
+ elif option == '--allow-unstable':
+ allow_havoc = True
+
+ try:
+ dom = xml.dom.minidom.parse(argv[0])
+ except IndexError:
+ cmdline_error()
+
+ Generator(dom, prefix, basename, signal_marshal_prefix, headers,
+ end_headers, not_implemented_func, allow_havoc)()
diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py
new file mode 100644
index 0000000..fcb46e8
--- /dev/null
+++ b/tools/glib-gtypes-generator.py
@@ -0,0 +1,230 @@
+#!/usr/bin/python
+
+# Generate GLib GInterfaces from the Telepathy specification.
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (C) 2006, 2007 Collabora Limited
+#
+# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import xml.dom.minidom
+
+from libglibcodegen import escape_as_identifier, \
+ get_docstring, \
+ NS_TP, \
+ Signature, \
+ type_to_gtype, \
+ xml_escape
+
+
+def types_to_gtypes(types):
+ return [type_to_gtype(t)[1] for t in types]
+
+
+class GTypesGenerator(object):
+ def __init__(self, dom, output, mixed_case_prefix):
+ self.dom = dom
+ self.Prefix = mixed_case_prefix
+ self.PREFIX_ = self.Prefix.upper() + '_'
+ self.prefix_ = self.Prefix.lower() + '_'
+
+ self.header = open(output + '.h', 'w')
+ self.body = open(output + '-body.h', 'w')
+
+ for f in (self.header, self.body):
+ f.write('/* Auto-generated, do not edit.\n *\n'
+ ' * This file may be distributed under the same terms\n'
+ ' * as the specification from which it was generated.\n'
+ ' */\n\n')
+
+ self.need_mappings = {}
+ self.need_structs = {}
+ self.need_arrays = {}
+
+ def do_mapping_header(self, mapping):
+ members = mapping.getElementsByTagNameNS(NS_TP, 'member')
+ assert len(members) == 2
+
+ impl_sig = ''.join([elt.getAttribute('type')
+ for elt in members])
+
+ esc_impl_sig = escape_as_identifier(impl_sig)
+
+ name = (self.PREFIX_ + 'HASH_TYPE_' +
+ mapping.getAttribute('name').upper())
+ impl = self.prefix_ + 'type_dbus_hash_' + esc_impl_sig
+
+ docstring = get_docstring(mapping) or '(Undocumented)'
+
+ self.header.write('/**\n * %s:\n *\n' % name)
+ 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')
+ self.header.write(' * appropriate for representing a D-Bus\n')
+ self.header.write(' * dictionary of signature\n')
+ self.header.write(' * <literal>a{%s}</literal>.\n' % impl_sig)
+ self.header.write(' *\n')
+
+ key, value = members
+
+ self.header.write(' * Keys (D-Bus type <literal>%s</literal>,\n'
+ % key.getAttribute('type'))
+ tp_type = key.getAttributeNS(NS_TP, 'type')
+ if tp_type:
+ self.header.write(' * type <literal>%s</literal>,\n' % tp_type)
+ self.header.write(' * named <literal>%s</literal>):\n'
+ % key.getAttribute('name'))
+ docstring = get_docstring(key) or '(Undocumented)'
+ self.header.write(' * %s\n' % xml_escape(docstring))
+ self.header.write(' *\n')
+
+ self.header.write(' * Values (D-Bus type <literal>%s</literal>,\n'
+ % value.getAttribute('type'))
+ tp_type = value.getAttributeNS(NS_TP, 'type')
+ if tp_type:
+ self.header.write(' * type <literal>%s</literal>,\n' % tp_type)
+ self.header.write(' * named <literal>%s</literal>):\n'
+ % value.getAttribute('name'))
+ docstring = get_docstring(value) or '(Undocumented)'
+ self.header.write(' * %s\n' % xml_escape(docstring))
+ self.header.write(' *\n')
+
+ self.header.write(' */\n')
+
+ self.header.write('#define %s (%s ())\n\n' % (name, impl))
+ self.need_mappings[impl_sig] = esc_impl_sig
+
+ def do_struct_header(self, struct):
+ members = struct.getElementsByTagNameNS(NS_TP, 'member')
+ impl_sig = ''.join([elt.getAttribute('type') for elt in members])
+ esc_impl_sig = escape_as_identifier(impl_sig)
+
+ name = (self.PREFIX_ + 'STRUCT_TYPE_' +
+ struct.getAttribute('name').upper())
+ impl = self.prefix_ + 'type_dbus_struct_' + esc_impl_sig
+ docstring = struct.getElementsByTagNameNS(NS_TP, 'docstring')
+ if docstring:
+ docstring = docstring[0].toprettyxml()
+ if docstring.startswith('<tp:docstring>'):
+ docstring = docstring[14:]
+ if docstring.endswith('</tp:docstring>\n'):
+ 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(' * %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')
+ self.header.write(' * appropriate for representing a D-Bus struct\n')
+ self.header.write(' * with signature <literal>(%s)</literal>.\n'
+ % impl_sig)
+ self.header.write(' *\n')
+
+ for i, member in enumerate(members):
+ self.header.write(' * Member %d (D-Bus type '
+ '<literal>%s</literal>,\n'
+ % (i, member.getAttribute('type')))
+ tp_type = member.getAttributeNS(NS_TP, 'type')
+ if tp_type:
+ self.header.write(' * type <literal>%s</literal>,\n' % tp_type)
+ self.header.write(' * named <literal>%s</literal>):\n'
+ % member.getAttribute('name'))
+ docstring = get_docstring(member) or '(Undocumented)'
+ self.header.write(' * %s\n' % xml_escape(docstring))
+ self.header.write(' *\n')
+
+ self.header.write(' */\n')
+ self.header.write('#define %s (%s ())\n\n' % (name, impl))
+
+ array_name = struct.getAttribute('array-name')
+ if array_name != '':
+ array_name = (self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper())
+ impl = self.prefix_ + 'type_dbus_array_' + esc_impl_sig
+ self.header.write('/**\n * %s:\n\n' % array_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' % (array_name, impl))
+ self.need_arrays[impl_sig] = esc_impl_sig
+
+ self.need_structs[impl_sig] = esc_impl_sig
+
+ def __call__(self):
+ mappings = self.dom.getElementsByTagNameNS(NS_TP, 'mapping')
+ structs = self.dom.getElementsByTagNameNS(NS_TP, 'struct')
+
+ for mapping in mappings:
+ self.do_mapping_header(mapping)
+
+ for sig in self.need_mappings:
+ self.header.write('GType %stype_dbus_hash_%s (void);\n\n' %
+ (self.prefix_, self.need_mappings[sig]))
+ self.body.write('GType\n%stype_dbus_hash_%s (void)\n{\n' %
+ (self.prefix_, self.need_mappings[sig]))
+ self.body.write(' static GType t = 0;\n\n')
+ self.body.write(' if (G_UNLIKELY (t == 0))\n')
+ # FIXME: translate sig into two GTypes
+ items = tuple(Signature(sig))
+ gtypes = types_to_gtypes(items)
+ self.body.write(' t = dbus_g_type_get_map ("GHashTable", '
+ '%s, %s);\n' % (gtypes[0], gtypes[1]))
+ self.body.write(' return t;\n')
+ self.body.write('}\n\n')
+
+ for struct in structs:
+ self.do_struct_header(struct)
+
+ for sig in self.need_structs:
+ self.header.write('GType %stype_dbus_struct_%s (void);\n\n' %
+ (self.prefix_, self.need_structs[sig]))
+ self.body.write('GType\n%stype_dbus_struct_%s (void)\n{\n' %
+ (self.prefix_, self.need_structs[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_struct ("GValueArray",\n')
+ items = tuple(Signature(sig))
+ gtypes = types_to_gtypes(items)
+ for gtype in gtypes:
+ self.body.write(' %s,\n' % gtype)
+ self.body.write(' G_TYPE_INVALID);\n')
+ self.body.write(' return t;\n')
+ self.body.write('}\n\n')
+
+ for sig in self.need_arrays:
+ self.header.write('GType %stype_dbus_array_%s (void);\n\n' %
+ (self.prefix_, self.need_structs[sig]))
+ self.body.write('GType\n%stype_dbus_array_%s (void)\n{\n' %
+ (self.prefix_, self.need_structs[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.body.write(' return t;\n')
+ self.body.write('}\n\n')
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+
+ dom = xml.dom.minidom.parse(argv[0])
+
+ GTypesGenerator(dom, argv[1], argv[2])()
diff --git a/tools/glib-interfaces-gen.py b/tools/glib-interfaces-gen.py
new file mode 100644
index 0000000..741626c
--- /dev/null
+++ b/tools/glib-interfaces-gen.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+
+from sys import argv, stdout, stderr
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \
+ get_descendant_text, get_by_path
+
+class Generator(object):
+ def __init__(self, prefix, implfile, declfile, dom):
+ self.prefix = prefix + '_'
+ self.impls = open(implfile, 'w')
+ self.decls = open(declfile, 'w')
+ self.spec = get_by_path(dom, "spec")[0]
+
+ def __call__(self):
+ for file in self.decls, self.impls:
+ self.do_header(file)
+ self.do_body()
+
+ # Header
+ def do_header(self, file):
+ file.write('/* Generated from: ')
+ file.write(get_descendant_text(get_by_path(self.spec, 'title')))
+ version = get_by_path(self.spec, "version")
+ if version:
+ file.write(' version ' + get_descendant_text(version))
+ file.write('\n\n')
+ for copyright in get_by_path(self.spec, 'copyright'):
+ stdout.write(get_descendant_text(copyright))
+ stdout.write('\n')
+ file.write('\n')
+ file.write(get_descendant_text(get_by_path(self.spec, 'license')))
+ file.write(get_descendant_text(get_by_path(self.spec, 'docstring')))
+ file.write("""
+ */
+
+""")
+
+ # Body
+ def do_body(self):
+ for iface in self.spec.getElementsByTagName('interface'):
+ self.do_iface(iface)
+
+ def do_iface(self, iface):
+ parent_name = get_by_path(iface, '../@name')
+ self.decls.write("""\
+/**
+ * %(IFACE_DEFINE)s:
+ *
+ * The interface name "%(name)s"
+ */
+#define %(IFACE_DEFINE)s \\
+"%(name)s"
+""" % {'IFACE_DEFINE' : (self.prefix + 'IFACE_' + \
+ parent_name).upper().replace('/', ''),
+ 'name' : iface.getAttribute('name')})
+
+ self.decls.write("""
+/**
+ * %(IFACE_QUARK_DEFINE)s:
+ *
+ * Expands to a call to a function that returns a quark for the interface \
+name "%(name)s"
+ */
+#define %(IFACE_QUARK_DEFINE)s \\
+ (%(iface_quark_func)s ())
+
+GQuark %(iface_quark_func)s (void);
+
+""" % {'IFACE_QUARK_DEFINE' : (self.prefix + 'IFACE_QUARK_' + \
+ parent_name).upper().replace('/', ''),
+ 'iface_quark_func' : (self.prefix + 'iface_quark_' + \
+ parent_name).lower().replace('/', ''),
+ 'name' : iface.getAttribute('name')})
+
+ self.impls.write("""\
+GQuark
+%(iface_quark_func)s (void)
+{
+ static GQuark quark = 0;
+
+ if (G_UNLIKELY (quark == 0))
+ {
+ quark = g_quark_from_static_string ("%(name)s");
+ }
+
+ return quark;
+}
+
+""" % {'iface_quark_func' : (self.prefix + 'iface_quark_' + \
+ parent_name).lower().replace('/', ''),
+ 'name' : iface.getAttribute('name')})
+
+if __name__ == '__main__':
+ argv = argv[1:]
+ Generator(argv[0], argv[1], argv[2], xml.dom.minidom.parse(argv[3]))()
diff --git a/tools/glib-signals-marshal-gen.py b/tools/glib-signals-marshal-gen.py
new file mode 100644
index 0000000..0d02c13
--- /dev/null
+++ b/tools/glib-signals-marshal-gen.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+from string import ascii_letters, digits
+
+
+from libglibcodegen import signal_to_marshal_name, method_to_glue_marshal_name
+
+
+class Generator(object):
+
+ def __init__(self, dom):
+ self.dom = dom
+ self.marshallers = {}
+
+ def do_method(self, method):
+ marshaller = method_to_glue_marshal_name(method, 'PREFIX')
+
+ assert '__' in marshaller
+ rhs = marshaller.split('__', 1)[1].split('_')
+
+ self.marshallers[marshaller] = rhs
+
+ def do_signal(self, signal):
+ marshaller = signal_to_marshal_name(signal, 'PREFIX')
+
+ assert '__' in marshaller
+ rhs = marshaller.split('__', 1)[1].split('_')
+
+ self.marshallers[marshaller] = rhs
+
+ def __call__(self):
+ methods = self.dom.getElementsByTagName('method')
+
+ for method in methods:
+ self.do_method(method)
+
+ signals = self.dom.getElementsByTagName('signal')
+
+ for signal in signals:
+ self.do_signal(signal)
+
+ all = self.marshallers.keys()
+ all.sort()
+ for marshaller in all:
+ rhs = self.marshallers[marshaller]
+ if not marshaller.startswith('g_cclosure'):
+ print 'VOID:' + ','.join(rhs)
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+ dom = xml.dom.minidom.parse(argv[0])
+
+ Generator(dom)()
diff --git a/tools/gobject-foo.py b/tools/gobject-foo.py
new file mode 100644
index 0000000..5921cab
--- /dev/null
+++ b/tools/gobject-foo.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+
+# gobject-foo.py: generate standard GObject type macros etc.
+#
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+def gobject_header(head, tail, as_interface=False):
+ out = []
+ o = out.append
+
+ name = head + '_' + tail
+ MixedCase = name.replace('_', '')
+ lower_case = name.lower()
+ UPPER_CASE = name.upper()
+
+ gtype = head.upper() + '_TYPE_' + tail.upper()
+
+ o("typedef struct _%s %s;" % (MixedCase, MixedCase))
+ o("typedef struct _%sClass %sClass;" % (MixedCase, MixedCase))
+ o("typedef struct _%sPrivate %sPrivate;" % (MixedCase, MixedCase))
+ o("")
+ o("GType %s_get_type (void);" % lower_case)
+ o("")
+
+ o("#define %s \\" % gtype)
+ o(" (%s_get_type ())" % lower_case)
+
+ o("#define %s(obj) \\" % UPPER_CASE)
+ o(" (G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, \\" % gtype)
+ o(" %s))" % MixedCase)
+
+ if not as_interface:
+ o("#define %s_CLASS(klass) \\" % UPPER_CASE)
+ o(" (G_TYPE_CHECK_CLASS_CAST ((klass), %s, \\" % gtype)
+ o(" %sClass))" % MixedCase)
+
+ o("#define %s_IS_%s(obj) \\" % (head.upper(), tail.upper()))
+ o(" (G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))" % gtype)
+
+ if not as_interface:
+ o("#define %s_IS_%s_CLASS(klass) \\" % (head.upper(), tail.upper()))
+ o(" (G_TYPE_CHECK_CLASS_TYPE ((klass), %s))" % gtype)
+
+ o("#define %s_GET_CLASS(obj) \\" % UPPER_CASE)
+ o(" (G_TYPE_INSTANCE_GET_CLASS ((obj), %s, \\" % gtype)
+ o(" %sClass))" % MixedCase)
+
+ return out
+
+if __name__ == '__main__':
+ import sys
+ from getopt import gnu_getopt
+
+ options, argv = gnu_getopt(sys.argv[1:], '', ['interface'])
+
+ as_interface = False
+
+ for opt, val in options:
+ if opt == '--interface':
+ as_interface = True
+
+ head, tail = argv
+
+ print '\n'.join(gobject_header(head, tail, as_interface=as_interface))
diff --git a/tools/identity.xsl b/tools/identity.xsl
new file mode 100644
index 0000000..6630f84
--- /dev/null
+++ b/tools/identity.xsl
@@ -0,0 +1,7 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()"/>
+ </xsl:copy>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/tools/lcov.am b/tools/lcov.am
new file mode 100644
index 0000000..97eed8f
--- /dev/null
+++ b/tools/lcov.am
@@ -0,0 +1,23 @@
+lcov-reset:
+ lcov --directory @top_srcdir@ --zerocounters
+
+lcov-report:
+ lcov --directory @top_srcdir@ --capture \
+ --output-file @top_builddir@/lcov.info.tmp
+ lcov --directory @top_srcdir@ --output-file @top_builddir@/lcov.info \
+ --remove @top_builddir@/lcov.info.tmp telepathy-glib-scan.c
+ rm @top_builddir@/lcov.info.tmp
+ $(mkdir_p) @top_builddir@/lcov.html
+ genhtml --title telepathy-glib \
+ --output-directory @top_builddir@/lcov.html lcov.info
+ @echo
+ @echo 'lcov report can be found in:'
+ @echo 'file://@abs_top_builddir@/lcov.html/index.html'
+ @echo
+
+lcov-check:
+ $(MAKE) lcov-reset
+ $(MAKE) check
+ $(MAKE) lcov-report
+
+## vim:set ft=automake:
diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py
new file mode 100644
index 0000000..129c179
--- /dev/null
+++ b/tools/libglibcodegen.py
@@ -0,0 +1,173 @@
+"""Library code for GLib/D-Bus-related code generation.
+
+The master copy of this library is in the telepathy-glib repository -
+please make any changes there.
+"""
+
+# Copyright (C) 2006-2008 Collabora Limited
+#
+# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+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
+
+def dbus_gutils_wincaps_to_uscore(s):
+ """Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore
+ which gets sequences of capital letters wrong in the same way.
+ (e.g. in Telepathy, SendDTMF -> send_dt_mf)
+ """
+ ret = ''
+ for c in s:
+ if c >= 'A' and c <= 'Z':
+ length = len(ret)
+ if length > 0 and (length < 2 or ret[length-2] != '_'):
+ ret += '_'
+ ret += c.lower()
+ else:
+ ret += c
+ return ret
+
+
+def signal_to_marshal_type(signal):
+ """
+ return a list of strings indicating the marshalling type for this signal.
+ """
+
+ mtype=[]
+ for i in signal.getElementsByTagName("arg"):
+ name =i.getAttribute("name")
+ type = i.getAttribute("type")
+ mtype.append(type_to_gtype(type)[2])
+
+ return mtype
+
+
+_glib_marshallers = ['VOID', 'BOOLEAN', 'CHAR', 'UCHAR', 'INT',
+ 'STRING', 'UINT', 'LONG', 'ULONG', 'ENUM', 'FLAGS', 'FLOAT',
+ 'DOUBLE', 'STRING', 'PARAM', 'BOXED', 'POINTER', 'OBJECT',
+ 'UINT_POINTER']
+
+
+def signal_to_marshal_name(signal, prefix):
+
+ mtype = signal_to_marshal_type(signal)
+ if len(mtype):
+ name = '_'.join(mtype)
+ else:
+ name = 'VOID'
+
+ if name in _glib_marshallers:
+ return 'g_cclosure_marshal_VOID__' + name
+ else:
+ return prefix + '_marshal_VOID__' + name
+
+
+def method_to_glue_marshal_name(method, prefix):
+
+ mtype = []
+ for i in method.getElementsByTagName("arg"):
+ if i.getAttribute("direction") != "out":
+ type = i.getAttribute("type")
+ mtype.append(type_to_gtype(type)[2])
+
+ mtype.append('POINTER')
+
+ name = '_'.join(mtype)
+
+ if name in _glib_marshallers:
+ return 'g_cclosure_marshal_VOID__' + name
+ else:
+ return prefix + '_marshal_VOID__' + name
+
+
+def type_to_gtype(s):
+ if s == 'y': #byte
+ return ("guchar ", "G_TYPE_UCHAR","UCHAR", False)
+ elif s == 'b': #boolean
+ return ("gboolean ", "G_TYPE_BOOLEAN","BOOLEAN", False)
+ elif s == 'n': #int16
+ return ("gint ", "G_TYPE_INT","INT", False)
+ elif s == 'q': #uint16
+ return ("guint ", "G_TYPE_UINT","UINT", False)
+ elif s == 'i': #int32
+ return ("gint ", "G_TYPE_INT","INT", False)
+ elif s == 'u': #uint32
+ return ("guint ", "G_TYPE_UINT","UINT", False)
+ elif s == 'x': #int64
+ return ("gint64 ", "G_TYPE_INT64","INT64", False)
+ elif s == 't': #uint64
+ return ("guint64 ", "G_TYPE_UINT64","UINT64", False)
+ elif s == 'd': #double
+ return ("gdouble ", "G_TYPE_DOUBLE","DOUBLE", False)
+ elif s == 's': #string
+ return ("gchar *", "G_TYPE_STRING", "STRING", True)
+ elif s == 'g': #signature - FIXME
+ return ("gchar *", "DBUS_TYPE_G_SIGNATURE", "STRING", True)
+ elif s == 'o': #object path
+ return ("gchar *", "DBUS_TYPE_G_OBJECT_PATH", "BOXED", True)
+ elif s == 'v': #variant
+ return ("GValue *", "G_TYPE_VALUE", "BOXED", True)
+ elif s == 'as': #array of strings
+ return ("gchar **", "G_TYPE_STRV", "BOXED", True)
+ elif s == 'ay': #byte array
+ return ("GArray *",
+ "dbus_g_type_get_collection (\"GArray\", G_TYPE_UCHAR)", "BOXED",
+ True)
+ elif s == 'au': #uint array
+ return ("GArray *", "DBUS_TYPE_G_UINT_ARRAY", "BOXED", True)
+ elif s == 'ai': #int array
+ return ("GArray *", "DBUS_TYPE_G_INT_ARRAY", "BOXED", True)
+ elif s == 'ax': #int64 array
+ return ("GArray *", "DBUS_TYPE_G_INT64_ARRAY", "BOXED", True)
+ elif s == 'at': #uint64 array
+ return ("GArray *", "DBUS_TYPE_G_UINT64_ARRAY", "BOXED", True)
+ elif s == 'ad': #double array
+ return ("GArray *", "DBUS_TYPE_G_DOUBLE_ARRAY", "BOXED", True)
+ 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)
+ 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
+ if s[2] not in ('y', 'b', 'n', 'q', 'i', 'u', 's', 'o', 'g'):
+ raise Exception, "can't index a hashtable off non-basic type " + s
+ first = type_to_gtype(s[2])
+ second = type_to_gtype(s[3:-1])
+ return ("GHashTable *", "(dbus_g_type_get_map (\"GHashTable\", " + first[1] + ", " + second[1] + "))", "BOXED", False)
+ elif s[:2] in ('a(', 'aa'): # array of structs or arrays, recurse
+ gtype = type_to_gtype(s[1:])[1]
+ return ("GPtrArray *", "(dbus_g_type_get_collection (\"GPtrArray\", "+gtype+"))", "BOXED", True)
+ elif s[:1] == '(': #struct
+ gtype = "(dbus_g_type_get_struct (\"GValueArray\", "
+ for subsig in Signature(s[1:-1]):
+ gtype = gtype + type_to_gtype(subsig)[1] + ", "
+ gtype = gtype + "G_TYPE_INVALID))"
+ return ("GValueArray *", gtype, "BOXED", True)
+
+ # we just don't know ..
+ raise Exception, "don't know the GType for " + s
diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py
new file mode 100644
index 0000000..6391f1a
--- /dev/null
+++ b/tools/libtpcodegen.py
@@ -0,0 +1,231 @@
+"""Library code for language-independent D-Bus-related code generation.
+
+The master copy of this library is in the telepathy-glib repository -
+please make any changes there.
+"""
+
+# Copyright (C) 2006-2008 Collabora Limited
+#
+# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+from string import ascii_letters, digits
+
+
+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)
+
+
+def escape_as_identifier(identifier):
+ """Escape the given string to be a valid D-Bus object path or service
+ name component, using a reversible encoding to ensure uniqueness.
+
+ The reversible encoding is as follows:
+
+ * The empty string becomes '_'
+ * Otherwise, each non-alphanumeric character is replaced by '_' plus
+ two lower-case hex digits; the same replacement is carried out on
+ the first character, if it's a digit
+ """
+ # '' -> '_'
+ if not identifier:
+ return '_'
+
+ # A bit of a fast path for strings which are already OK.
+ # We deliberately omit '_' because, for reversibility, that must also
+ # be escaped.
+ if (identifier.strip(_ASCII_ALNUM) == '' and
+ identifier[0] in ascii_letters):
+ return identifier
+
+ # The first character may not be a digit
+ if identifier[0] not in ascii_letters:
+ ret = ['_%02x' % ord(identifier[0])]
+ else:
+ ret = [identifier[0]]
+
+ # Subsequent characters may be digits or ASCII letters
+ for c in identifier[1:]:
+ if c in _ASCII_ALNUM:
+ ret.append(c)
+ else:
+ ret.append('_%02x' % ord(c))
+
+ 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:
+ if x.namespaceURI == NS_TP and x.localName == 'docstring':
+ docstring = x
+ if docstring is not None:
+ docstring = docstring.toxml().replace('\n', ' ').strip()
+ if docstring.startswith('<tp:docstring>'):
+ docstring = docstring[14:].lstrip()
+ if docstring.endswith('</tp:docstring>'):
+ docstring = docstring[:-15].rstrip()
+ if docstring in ('<tp:docstring/>', ''):
+ docstring = ''
+ return docstring
+
+
+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_or_elements.childNodes:
+ if x.nodeType == x.TEXT_NODE:
+ parts.append(x.nodeValue)
+ elif x.nodeType == x.ELEMENT_NODE:
+ parts.append(get_descendant_text(x))
+ else:
+ pass
+ return ''.join(parts)
+
+
+class _SignatureIter:
+ """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
+ can run genginterface in a limited environment with only Python
+ (like Scratchbox).
+ """
+ def __init__(self, string):
+ self.remaining = string
+
+ def next(self):
+ if self.remaining == '':
+ raise StopIteration
+
+ signature = self.remaining
+ block_depth = 0
+ block_type = None
+ end = len(signature)
+
+ for marker in range(0, end):
+ cur_sig = signature[marker]
+
+ if cur_sig == 'a':
+ pass
+ elif cur_sig == '{' or cur_sig == '(':
+ if block_type == None:
+ block_type = cur_sig
+
+ if block_type == cur_sig:
+ block_depth = block_depth + 1
+
+ elif cur_sig == '}':
+ if block_type == '{':
+ block_depth = block_depth - 1
+
+ if block_depth == 0:
+ end = marker
+ break
+
+ elif cur_sig == ')':
+ if block_type == '(':
+ block_depth = block_depth - 1
+
+ if block_depth == 0:
+ end = marker
+ break
+
+ else:
+ if block_depth == 0:
+ end = marker
+ break
+
+ end = end + 1
+ self.remaining = signature[end:]
+ return Signature(signature[0:end])
+
+
+class Signature(str):
+ """A string, iteration over which is by D-Bus single complete types
+ rather than characters.
+ """
+ def __iter__(self):
+ return _SignatureIter(self)
+
+
+def xml_escape(s):
+ s = s.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;')
+ return s.replace('<', '&lt;').replace('>', '&gt;')
diff --git a/tools/make-version-script.py b/tools/make-version-script.py
new file mode 100644
index 0000000..91306a0
--- /dev/null
+++ b/tools/make-version-script.py
@@ -0,0 +1,205 @@
+#!/usr/bin/python
+
+"""Construct a GNU ld or Debian dpkg version-script from a set of
+RFC822-style symbol lists.
+
+Usage:
+ make-version-script.py [--symbols SYMBOLS] [--unreleased-version VER]
+ [--dpkg "LIBRARY.so.0 LIBRARY0 #MINVER#"]
+ [--dpkg-build-depends-package LIBRARY-dev]
+ [FILES...]
+
+Each FILE starts with RFC822-style headers "Version:" (the name of the
+symbol version, e.g. FOO_1.2.3) and "Extends:" (either the previous
+version, or "-" if this is the first version). Next there is a blank
+line, then a list of C symbols one per line.
+
+Comments (lines starting with whitespace + "#") are allowed and ignored.
+
+If --symbols is given, SYMBOLS lists the symbols actually exported by
+the library (one per line). If --unreleased-version is given, any symbols
+in SYMBOLS but not in FILES are assigned to that version; otherwise, any
+such symbols cause an error.
+
+If --dpkg is given, produce a Debian dpkg-gensymbols file instead of a
+GNU ld version-script. The argument to --dpkg is the first line of the
+resulting symbols file, and --dpkg-build-depends-package can optionally
+be used to set the Build-Depends-Package field.
+
+This script originates in telepathy-glib <http://telepathy.freedesktop.org/> -
+please send us any changes that are needed.
+"""
+
+# Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
+# Copyright (C) 2008 Nokia Corporation
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.
+
+import sys
+from getopt import gnu_getopt
+from sets import Set as set
+
+
+def e(format, *args):
+ sys.stderr.write((format + '\n') % args)
+
+
+def main(abifiles, symbols=None, unreleased_version=None,
+ dpkg=False, dpkg_first_line=None, dpkg_build_depends_package=None):
+
+ gnuld = not dpkg
+ symbol_set = None
+
+ if symbols is not None:
+ symbol_set = open(symbols, 'r').readlines()
+ symbol_set = map(str.strip, symbol_set)
+ symbol_set = set(symbol_set)
+
+ versioned_symbols = set()
+
+ dpkg_symbols = []
+ dpkg_versions = []
+
+ if dpkg:
+ assert dpkg_first_line is not None
+ print dpkg_first_line
+ if dpkg_build_depends_package is not None:
+ print "* Build-Depends-Package: %s" % dpkg_build_depends_package
+
+ for filename in abifiles:
+ lines = open(filename, 'r').readlines()
+
+ version = None
+ extends = None
+ release = None
+
+ for i, line in enumerate(lines):
+ line = line.strip()
+
+ if line.startswith('#'):
+ continue
+ elif not line:
+ # the transition betwen headers and symbols
+ cut = i + 1
+ break
+ elif line.lower().startswith('version:'):
+ line = line[8:].strip()
+ version = line
+ continue
+ elif line.lower().startswith('extends:'):
+ line = line[8:].strip()
+ extends = line
+ continue
+ elif line.lower().startswith('release:'):
+ release = line[8:].strip()
+ continue
+ else:
+ e('Could not understand line in %s header: %s', filename, line)
+ raise SystemExit(1)
+
+ else:
+ e('No symbols in %s', filename)
+ raise SystemExit(1)
+
+ if version is None:
+ e('No Versions: header in %s', filename)
+ raise SystemExit(1)
+
+ if extends is None:
+ e('No Extends: header in %s', filename)
+ raise SystemExit(1)
+
+ if release is None and dpkg:
+ e('No Release: header in %s', filename)
+ raise SystemExit(1)
+
+ if dpkg:
+ dpkg_versions.append('%s@%s %s' % (version, version, release))
+
+ lines = lines[cut:]
+
+ if gnuld:
+ print "%s {" % version
+ print " global:"
+
+ for symbol in lines:
+ symbol = symbol.strip()
+
+ if symbol.startswith('#'):
+ continue
+
+ if gnuld:
+ print " %s;" % symbol
+ elif dpkg:
+ dpkg_symbols.append('%s@%s %s' % (symbol, version, release))
+
+ versioned_symbols.add(symbol)
+
+ if gnuld:
+ if extends == '-':
+ print " local:"
+ print " *;"
+ print "};"
+ else:
+ print "} %s;" % extends
+ print
+
+ if dpkg:
+ dpkg_symbols.sort()
+ dpkg_versions.sort()
+
+ for x in dpkg_versions:
+ print " %s" % x
+
+ for x in dpkg_symbols:
+ print " %s" % x
+
+ if symbol_set is not None:
+ missing = versioned_symbols - symbol_set
+
+ if missing:
+ e('These symbols have disappeared:')
+
+ for symbol in missing:
+ e(' %s', symbol)
+
+ raise SystemExit(1)
+
+ unreleased = symbol_set - versioned_symbols
+
+ if unreleased:
+ if unreleased_version is None:
+ e('Unversioned symbols are not allowed in releases:')
+
+ for symbol in unreleased:
+ e(' %s', symbol)
+
+ raise SystemExit(1)
+
+ if gnuld:
+ print "%s {" % unreleased_version
+ print " global:"
+
+ for symbol in unreleased:
+ print " %s;" % symbol
+
+ print "} %s;" % version
+
+
+if __name__ == '__main__':
+ options, argv = gnu_getopt (sys.argv[1:], '',
+ ['symbols=', 'unreleased-version=',
+ 'dpkg=', 'dpkg-build-depends-package='])
+
+ opts = {'dpkg': False}
+
+ for option, value in options:
+ if option == '--dpkg':
+ opts['dpkg'] = True
+ opts['dpkg_first_line'] = value
+ else:
+ opts[option.lstrip('-').replace('-', '_')] = value
+
+ main(argv, **opts)
diff --git a/tools/shave.mk b/tools/shave.mk
new file mode 100644
index 0000000..53cb3bf
--- /dev/null
+++ b/tools/shave.mk
@@ -0,0 +1 @@
+QUIET_GEN = $(Q:@=@echo ' GEN '$@;)
diff --git a/tools/telepathy-glib-env.in b/tools/telepathy-glib-env.in
new file mode 100644
index 0000000..ddc47bf
--- /dev/null
+++ b/tools/telepathy-glib-env.in
@@ -0,0 +1,9 @@
+#!/bin/sh
+abs_top_builddir="@abs_top_builddir@"
+export abs_top_builddir
+LD_LIBRARY_PATH="${abs_top_builddir}/telepathy-glib/.libs${LD_LIBRARY_PATH:+":${LD_LIBRARY_PATH}"}"
+export LD_LIBRARY_PATH
+G_DEBUG="fatal_criticals,fatal_warnings${G_DEBUG:+",${G_DEBUG}"}"
+export G_DEBUG
+
+exec "$@"
diff --git a/tools/telepathy.am b/tools/telepathy.am
new file mode 100644
index 0000000..d061b89
--- /dev/null
+++ b/tools/telepathy.am
@@ -0,0 +1,27 @@
+## Useful top-level Makefile.am snippets for Telepathy projects.
+
+dist-hook:
+ chmod u+w ${distdir}/ChangeLog
+ if test -d ${top_srcdir}/.git; then \
+ git log --stat > ${distdir}/ChangeLog || \
+ git log > ${distdir}/ChangeLog; \
+ fi
+
+maintainer-upload-release: _maintainer-upload-release
+
+_maintainer-upload-release-check:
+ @case @VERSION@ in \
+ (*.*.*.*) \
+ echo "@VERSION@ is not a release" >&2; \
+ exit 2; \
+ ;; \
+ esac
+ test -f @PACKAGE@-@VERSION@.tar.gz
+ test -f @PACKAGE@-@VERSION@.tar.gz.asc
+ gpg --verify @PACKAGE@-@VERSION@.tar.gz.asc
+
+_maintainer-upload-release: _maintainer-upload-release-check
+ rsync -vzP @PACKAGE@-@VERSION@.tar.gz telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz
+ rsync -vzP @PACKAGE@-@VERSION@.tar.gz.asc telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz.asc
+
+## vim:set ft=automake:
diff --git a/tools/with-session-bus.sh b/tools/with-session-bus.sh
new file mode 100644
index 0000000..519b9b1
--- /dev/null
+++ b/tools/with-session-bus.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+# with-session-bus.sh - run a program with a temporary D-Bus session daemon
+#
+# The canonical location of this program is the telepathy-glib tools/
+# directory, please synchronize any changes with that copy.
+#
+# Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.
+
+set -e
+
+me=with-session-bus
+
+dbus_daemon_args="--print-address=5 --print-pid=6 --fork"
+
+usage ()
+{
+ echo "usage: $me [options] -- program [program_options]" >&2
+ echo "Requires write access to the current directory." >&2
+ echo "" >&2
+ echo "If \$WITH_SESSION_BUS_FORK_DBUS_MONITOR is set, fork dbus-monitor" >&2
+ echo "with the arguments in \$WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT." >&2
+ echo "The output of dbus-monitor is saved in $me-<pid>.dbus-monitor-logs" >&2
+ exit 2
+}
+
+while test "z$1" != "z--"; do
+ case "$1" in
+ --session)
+ dbus_daemon_args="$dbus_daemon_args --session"
+ shift
+ ;;
+ --config-file=*)
+ # FIXME: assumes config file doesn't contain any special characters
+ dbus_daemon_args="$dbus_daemon_args $1"
+ shift
+ ;;
+ *)
+ usage
+ ;;
+ esac
+done
+shift
+if test "z$1" = "z"; then usage; fi
+
+exec 5> $me-$$.address
+exec 6> $me-$$.pid
+
+cleanup ()
+{
+ pid=`head -n1 $me-$$.pid`
+ if test -n "$pid" ; then
+ echo "Killing temporary bus daemon: $pid" >&2
+ kill -INT "$pid"
+ fi
+ rm -f $me-$$.address
+ rm -f $me-$$.pid
+}
+
+trap cleanup INT HUP TERM
+dbus-daemon $dbus_daemon_args
+
+{ echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2
+{ echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2
+
+e=0
+DBUS_SESSION_BUS_ADDRESS="`cat $me-$$.address`"
+export DBUS_SESSION_BUS_ADDRESS
+
+if [ -n "$WITH_SESSION_BUS_FORK_DBUS_MONITOR" ] ; then
+ echo -n "Forking dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT" >&2
+ dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT \
+ &> $me-$$.dbus-monitor-logs &
+fi
+
+"$@" || e=$?
+
+trap - INT HUP TERM
+cleanup
+
+exit $e