summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.co.uk>2012-09-10 17:47:10 +0200
committerXavier Claessens <xavier.claessens@collabora.co.uk>2012-09-11 16:00:02 +0200
commit9801e21b3489f20f8f6c88e2e40154e8e7da726a (patch)
tree05fc6c0a5c71400b23e467df529600bf3556ba90
parentc7fd1d5ef73cf7ef64b54b378ae7940bb5ba369c (diff)
Update tools from telepathy-glib
I know this adds useless tools, but it's easier to have a raw copy of tp-glib's directory. We should consider using a git submodule tbh.
-rw-r--r--extensions/Makefile.am20
-rw-r--r--tools/Makefile.am59
-rw-r--r--tools/c-constants-gen.py37
-rw-r--r--tools/check-c-style.sh7
-rw-r--r--tools/flymake.mk4
-rw-r--r--tools/git-which-branch.sh25
-rw-r--r--tools/glib-client-gen.py1269
-rw-r--r--tools/glib-client-marshaller-gen.py60
-rw-r--r--tools/glib-errors-check-gen.py58
-rw-r--r--tools/glib-errors-str-gen.py83
-rw-r--r--tools/glib-ginterface-gen.py25
-rw-r--r--tools/glib-gtypes-generator.py28
-rw-r--r--tools/glib-interfaces-gen.py22
-rw-r--r--tools/glib-signals-marshal-gen.py55
-rw-r--r--tools/gobject-foo.py90
-rw-r--r--tools/lcov.am1
-rw-r--r--tools/libtpcodegen.py14
-rw-r--r--tools/make-version-script.py208
-rw-r--r--tools/manager-file.py187
-rw-r--r--tools/shave.mk1
-rw-r--r--tools/telepathy-glib-env.in9
-rw-r--r--tools/telepathy-glib.supp390
-rwxr-xr-xtools/test-wrapper.sh30
-rw-r--r--tools/valgrind.mk13
-rwxr-xr-xtools/with-session-bus.sh100
25 files changed, 2660 insertions, 135 deletions
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index 8e50ffbce..ecb02ef5f 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -20,9 +20,6 @@ libgabble_extensions_la_SOURCES = \
extensions.h
nodist_libgabble_extensions_la_SOURCES = \
- _gen/signals-marshal.c \
- _gen/signals-marshal.h \
- _gen/signals-marshal.list \
_gen/enums.h \
_gen/enums-gtk-doc.h \
_gen/gtypes.h \
@@ -65,25 +62,12 @@ extensions.html: _gen/all.xml $(tools_dir)/doc-generator.xsl Makefile.am
_gen/svc.c _gen/svc.h _gen/svc-gtk-doc.h: _gen/all.xml $(tools_dir)/glib-ginterface-gen.py \
Makefile.am
$(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-ginterface-gen.py \
- --filename=_gen/svc --signal-marshal-prefix=_gabble_ext \
- --include='<telepathy-glib/dbus.h>' \
- --include='"_gen/signals-marshal.h"' \
+ --filename=_gen/svc \
+ --include='<telepathy-glib/telepathy-glib.h>' \
--allow-unstable \
--not-implemented-func='tp_dbus_g_method_return_not_implemented' \
$< Gabble_Svc_
-_gen/signals-marshal.list: _gen/all.xml \
- $(tools_dir)/glib-signals-marshal-gen.py \
- Makefile.am
- $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-signals-marshal-gen.py $< > $@
-
-_gen/signals-marshal.h: _gen/signals-marshal.list Makefile.am
- $(AM_V_GEN)$(GLIB_GENMARSHAL) --header --prefix=_gabble_ext_marshal $< > $@
-
-_gen/signals-marshal.c: _gen/signals-marshal.list Makefile.am
- $(AM_V_GEN){ echo '#include "_gen/signals-marshal.h"' && \
- $(GLIB_GENMARSHAL) --body --prefix=_gabble_ext_marshal $< ; } > $@
-
_gen/enums.h _gen/enums-gtk-doc.h: _gen/all.xml $(tools_dir)/c-constants-gen.py \
Makefile.am
$(AM_V_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py Gabble $< _gen/enums
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 3cfcfe923..5b78d699c 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,3 +1,21 @@
+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 $@
+
+if ENABLE_INSTALLED_TESTS
+toolsdir = @tpglibtestsdir@/tools
+tools_SCRIPTS = \
+ with-session-bus.sh \
+ test-wrapper.sh \
+ libglibcodegen.py \
+ libtpcodegen.py \
+ $(NULL)
+endif
+
EXTRA_DIST = \
c-constants-gen.py \
check-coding-style.mk \
@@ -5,29 +23,50 @@ EXTRA_DIST = \
check-misc.sh \
check-whitespace.sh \
doc-generator.xsl \
+ flymake.mk \
+ git-which-branch.sh \
+ glib-client-gen.py \
+ glib-client-marshaller-gen.py \
+ glib-errors-check-gen.py \
+ glib-errors-str-gen.py \
glib-ginterface-gen.py \
glib-gtypes-generator.py \
glib-interfaces-gen.py \
- glib-signals-marshal-gen.py \
+ gobject-foo.py \
lcov.am \
- libglibcodegen.py \
libtpcodegen.py \
+ libglibcodegen.py \
make-release-mail.py \
+ make-version-script.py \
+ manager-file.py \
+ shave.mk \
telepathy.am \
+ telepathy-glib.supp \
+ telepathy-glib-env.in \
+ test-wrapper.sh \
+ with-session-bus.sh \
xincludator.py
-CLEANFILES = *.pyc *.pyo
+CLEANFILES = libtpcodegen.pyc libtpcodegen.pyo libglibcodegen.pyc libglibcodegen.pyo $(noinst_SCRIPTS)
all: $(EXTRA_DIST)
libglibcodegen.py: libtpcodegen.py
- test -e $<
- $(AM_V_GEN)touch $@
-
-glib-ginterface-gen.py glib-gtypes-generator.py glib-interfaces-gen.py \
-glib-signals-marshal-gen.py c-constants-gen.py: %: libglibcodegen.py
- test -e $<
- $(AM_V_GEN)touch $@
+ $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@
+c-constants-gen.py: libglibcodegen.py
+ $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@
+glib-client-marshaller-gen.py: libglibcodegen.py
+ $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@
+glib-errors-enum-body-gen.py: libglibcodegen.py
+ $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@
+glib-errors-enum-header-gen.py: libglibcodegen.py
+ $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@
+glib-ginterface-gen.py: libglibcodegen.py
+ $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@
+glib-gtypes-generator.py: libglibcodegen.py
+ $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@
+glib-interfaces-gen.py: libglibcodegen.py
+ $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@
TELEPATHY_GLIB_SRCDIR = $(top_srcdir)/../telepathy-glib
maintainer-update-from-telepathy-glib:
diff --git a/tools/c-constants-gen.py b/tools/c-constants-gen.py
index ff2a24d47..c7a93d371 100644
--- a/tools/c-constants-gen.py
+++ b/tools/c-constants-gen.py
@@ -3,6 +3,7 @@
from sys import argv, stdout, stderr
import xml.dom.minidom
+from libtpcodegen import file_set_contents
from libglibcodegen import NS_TP, get_docstring, \
get_descendant_text, get_by_path
@@ -11,19 +12,23 @@ class Generator(object):
self.prefix = prefix + '_'
self.spec = get_by_path(dom, "spec")[0]
- self.__header = open(output_base + '.h', 'w')
- self.__docs = open(output_base + '-gtk-doc.h', 'w')
+ self.output_base = output_base
+ self.__header = []
+ self.__docs = []
def __call__(self):
self.do_header()
self.do_body()
self.do_footer()
+ file_set_contents(self.output_base + '.h', ''.join(self.__header))
+ file_set_contents(self.output_base + '-gtk-doc.h', ''.join(self.__docs))
+
def write(self, code):
- self.__header.write(code.encode('utf-8'))
+ self.__header.append(code.encode('utf-8'))
def d(self, code):
- self.__docs.write(code.encode('utf-8'))
+ self.__docs.append(code.encode('utf-8'))
# Header
def do_header(self):
@@ -62,8 +67,7 @@ extern "C" {
flags.getAttribute('name')
self.d("""\
/**
- *
-%s:
+ * %s:
""" % (self.prefix + name).replace('_', ''))
for flag in get_by_path(flags, 'flag'):
self.do_gtkdoc(flag, value_prefix)
@@ -97,8 +101,7 @@ extern "C" {
enum.getAttribute('name') + 's'
self.d("""\
/**
- *
-%s:
+ * %s:
""" % (self.prefix + name).replace('_', ''))
vals = get_by_path(enum, 'enumvalue')
for val in vals:
@@ -123,19 +126,29 @@ extern "C" {
self.d("""\
/**
- * NUM_%(upper-plural)s: (skip)
+ * %(upper-prefix)sNUM_%(upper-plural)s:
+ *
+ * 1 higher than the highest valid value of #%(mixed-name)s.
+ */
+
+/**
+ * NUM_%(upper-prefix)s%(upper-plural)s: (skip)
*
* 1 higher than the highest valid value of #%(mixed-name)s.
+ * In new code, use %(upper-prefix)sNUM_%(upper-plural)s instead.
*/
""" % {'mixed-name' : (self.prefix + name).replace('_', ''),
- 'upper-plural' : (self.prefix + name_plural).upper(),
+ 'upper-prefix' : self.prefix.upper(),
+ 'upper-plural' : name_plural.upper(),
'last-val' : vals[-1].getAttribute('value')})
self.write("""\
-#define NUM_%(upper-plural)s (%(last-val)s+1)
+#define %(upper-prefix)sNUM_%(upper-plural)s (%(last-val)s+1)
+#define NUM_%(upper-prefix)s%(upper-plural)s %(upper-prefix)sNUM_%(upper-plural)s
""" % {'mixed-name' : (self.prefix + name).replace('_', ''),
- 'upper-plural' : (self.prefix + name_plural).upper(),
+ 'upper-prefix' : self.prefix.upper(),
+ 'upper-plural' : name_plural.upper(),
'last-val' : vals[-1].getAttribute('value')})
def do_val(self, val, value_prefix):
diff --git a/tools/check-c-style.sh b/tools/check-c-style.sh
index 4330b1479..55834207a 100644
--- a/tools/check-c-style.sh
+++ b/tools/check-c-style.sh
@@ -3,13 +3,6 @@ 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).
diff --git a/tools/flymake.mk b/tools/flymake.mk
new file mode 100644
index 000000000..020a7bfbf
--- /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/git-which-branch.sh b/tools/git-which-branch.sh
new file mode 100644
index 000000000..b96b5d5e2
--- /dev/null
+++ b/tools/git-which-branch.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# git-which-branch.sh - output the name of the current git branch
+#
+# The canonical location of this program is the telepathy-spec tools/
+# directory, please synchronize any changes with that copy.
+#
+# Copyright (C) 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.
+
+default="$1"
+if { ref="`git symbolic-ref HEAD 2>/dev/null`"; }; then
+ echo ${ref#refs/heads/}
+ exit 0
+fi
+
+if test -n "$default"; then
+ echo "$default" >/dev/null
+ exit 0
+fi
+
+echo "no git branch found" >&2
+exit 1
diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py
new file mode 100644
index 000000000..f8465a62b
--- /dev/null
+++ b/tools/glib-client-gen.py
@@ -0,0 +1,1269 @@
+#!/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 libtpcodegen import file_set_contents
+from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
+ get_docstring, xml_escape, get_deprecated
+
+
+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.__docs = []
+
+ 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 '
+
+ self.reentrant_symbols = set()
+ try:
+ filename = opts['--generate-reentrant']
+ with open(filename, 'r') as f:
+ for line in f.readlines():
+ self.reentrant_symbols.add(line.strip())
+ except KeyError:
+ pass
+
+ self.deprecate_reentrant = opts.get('--deprecate-reentrant', None)
+ self.deprecation_attribute = opts.get('--deprecation-attribute',
+ 'G_GNUC_DEPRECATED')
+
+ self.guard = opts.get('--guard', None)
+
+ 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 d(self, s):
+ if isinstance(s, unicode):
+ s = s.encode('utf-8')
+ self.__docs.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 = signal.getAttribute('tp:name-for-bindings')
+ if member != member_lc.replace('_', ''):
+ raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
+ 'not match' % (member, member_lc))
+ member_lc = member_lc.lower()
+ member_uc = member_lc.upper()
+
+ arg_count = 0
+ 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.d('/**')
+ self.d(' * %s:' % callback_name)
+ self.d(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.d(' * was called')
+
+ for arg in args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ docs = get_docstring(elt) or '(Undocumented)'
+
+ if ctype == 'guint ' and tp_type != '':
+ docs += ' (#%s)' % ('Tp' + tp_type.replace('_', ''))
+
+ self.d(' * @%s: %s' % (name, xml_escape(docs)))
+
+ self.d(' * @user_data: User-supplied data')
+ self.d(' * @weak_object: User-supplied weakly referenced object')
+ self.d(' *')
+ self.d(' * Represents the signature of a callback for the signal %s.'
+ % member)
+ self.d(' */')
+ self.d('')
+
+ 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.d('/**')
+ self.d(' * %s_%s_connect_to_%s:'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.d(' * @proxy: %s' % self.proxy_doc)
+ self.d(' * @callback: Callback to be called when the signal is')
+ self.d(' * received')
+ self.d(' * @user_data: User-supplied data for the callback')
+ self.d(' * @destroy: Destructor for the user-supplied data, which')
+ self.d(' * will be called when this signal is disconnected, or')
+ self.d(' * before this function returns %NULL')
+ self.d(' * @weak_object: A #GObject which will be weakly referenced; ')
+ self.d(' * if it is destroyed, this callback will automatically be')
+ self.d(' * disconnected')
+ self.d(' * @error: If not %NULL, used to raise an error if %NULL is')
+ self.d(' * returned')
+ self.d(' *')
+ self.d(' * Connect a handler to the signal %s.' % member)
+ self.d(' *')
+ self.d(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
+ self.d(' *')
+ self.d(' * Returns: a #TpProxySignalConnection containing all of the')
+ self.d(' * above, which can be used to disconnect the signal; or')
+ self.d(' * %NULL if the proxy does not have the desired interface')
+ self.d(' * or has become invalid.')
+ self.d(' */')
+ self.d('')
+
+ 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.h('')
+
+ 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('')
+
+ def do_method(self, iface, method):
+ iface_lc = iface.lower()
+
+ member = method.getAttribute('name')
+ member_lc = method.getAttribute('tp:name-for-bindings')
+ if member != member_lc.replace('_', ''):
+ raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+ 'not match' % (member, member_lc))
+ member_lc = member_lc.lower()
+ member_uc = member_lc.upper()
+
+ in_count = 0
+ 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.d('/**')
+ self.d(' * %s_%s_callback_for_%s:'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.d(' * @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
+
+ docs = xml_escape(get_docstring(elt) or '(Undocumented)')
+
+ if ctype == 'guint ' and tp_type != '':
+ docs += ' (#%s)' % ('Tp' + tp_type.replace('_', ''))
+
+ self.d(' * @%s: Used to return an \'out\' argument if @error is '
+ '%%NULL: %s'
+ % (name, docs))
+
+ self.d(' * @error: %NULL on success, or an error on failure')
+ self.d(' * @user_data: user-supplied data')
+ self.d(' * @weak_object: user-supplied object')
+ self.d(' *')
+ self.d(' * Signature of the callback called when a %s method call'
+ % member)
+ self.d(' * succeeds or fails.')
+
+ deprecated = method.getElementsByTagName('tp:deprecated')
+ if deprecated:
+ d = deprecated[0]
+ self.d(' *')
+ self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
+
+ self.d(' */')
+ self.d('')
+
+ 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.d('/**')
+ self.d(' * %s_%s_call_%s:'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.d(' * @proxy: the #TpProxy')
+ self.d(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
+ self.d(' * default')
+
+ for arg in in_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ docs = xml_escape(get_docstring(elt) or '(Undocumented)')
+
+ if ctype == 'guint ' and tp_type != '':
+ docs += ' (#%s)' % ('Tp' + tp_type.replace('_', ''))
+
+ self.d(' * @%s: Used to pass an \'in\' argument: %s'
+ % (name, docs))
+
+ self.d(' * @callback: called when the method call succeeds or fails;')
+ self.d(' * may be %NULL to make a "fire and forget" call with no ')
+ self.d(' * reply tracking')
+ self.d(' * @user_data: user-supplied data passed to the callback;')
+ self.d(' * must be %NULL if @callback is %NULL')
+ self.d(' * @destroy: called with the user_data as argument, after the')
+ self.d(' * call has succeeded, failed or been cancelled;')
+ self.d(' * must be %NULL if @callback is %NULL')
+ self.d(' * @weak_object: If not %NULL, a #GObject which will be ')
+ self.d(' * weakly referenced; if it is destroyed, this call ')
+ self.d(' * will automatically be cancelled. Must be %NULL if ')
+ self.d(' * @callback is %NULL')
+ self.d(' *')
+ self.d(' * Start a %s method call.' % member)
+ self.d(' *')
+ self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
+ self.d(' *')
+ self.d(' * Returns: a #TpProxyPendingCall representing the call in')
+ self.d(' * progress. It is borrowed from the object, and will become')
+ self.d(' * invalid when the callback is called, the call is')
+ self.d(' * cancelled or the #TpProxy becomes invalid.')
+
+ deprecated = method.getElementsByTagName('tp:deprecated')
+ if deprecated:
+ d = deprecated[0]
+ self.d(' *')
+ self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
+
+ self.d(' */')
+ self.d('')
+
+ 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(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
+ self.b(' iface = tp_proxy_borrow_interface_by_id (')
+ self.b(' (TpProxy *) proxy,')
+ self.b(' interface, &error);')
+ self.b(' G_GNUC_END_IGNORE_DEPRECATIONS')
+ 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('')
+
+ self.do_method_reentrant(method, iface_lc, member, member_lc,
+ in_args, out_args, collect_callback)
+
+ # leave a gap for the end of the method
+ self.d('')
+ self.b('')
+ self.h('')
+
+ def do_method_reentrant(self, method, iface_lc, member, member_lc, in_args,
+ out_args, collect_callback):
+ # Reentrant blocking calls
+ # Example:
+ # gboolean tp_cli_properties_interface_run_get_properties
+ # (gpointer proxy,
+ # gint timeout_ms,
+ # const GArray *in_properties,
+ # GPtrArray **out0,
+ # GError **error,
+ # GMainLoop **loop);
+
+ run_method_name = '%s_%s_run_%s' % (self.prefix_lc, iface_lc, member_lc)
+ if run_method_name not in self.reentrant_symbols:
+ return
+
+ self.b('typedef struct {')
+ self.b(' GMainLoop *loop;')
+ self.b(' GError **error;')
+
+ for arg in out_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ self.b(' %s*%s;' % (ctype, name))
+
+ self.b(' unsigned success:1;')
+ self.b(' unsigned completed:1;')
+ self.b('} _%s_%s_run_state_%s;'
+ % (self.prefix_lc, iface_lc, member_lc))
+
+ reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
+ iface_lc,
+ member_lc)
+
+ self.b('static void')
+ self.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke)
+ self.b(' GError *error,')
+ self.b(' GValueArray *args,')
+ self.b(' GCallback unused G_GNUC_UNUSED,')
+ self.b(' gpointer user_data G_GNUC_UNUSED,')
+ self.b(' GObject *unused2 G_GNUC_UNUSED)')
+ self.b('{')
+ self.b(' _%s_%s_run_state_%s *state = user_data;'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.b('')
+ self.b(' state->success = (error == NULL);')
+ self.b(' state->completed = TRUE;')
+ self.b(' g_main_loop_quit (state->loop);')
+ self.b('')
+ self.b(' if (error != NULL)')
+ self.b(' {')
+ self.b(' if (state->error != NULL)')
+ self.b(' *state->error = error;')
+ self.b(' else')
+ self.b(' g_error_free (error);')
+ self.b('')
+ self.b(' return;')
+ self.b(' }')
+ self.b('')
+
+ for i, arg in enumerate(out_args):
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ self.b(' if (state->%s != NULL)' % name)
+ if marshaller == 'BOXED':
+ self.b(' *state->%s = g_value_dup_boxed ('
+ 'args->values + %d);' % (name, i))
+ elif marshaller == 'STRING':
+ self.b(' *state->%s = g_value_dup_string '
+ '(args->values + %d);' % (name, i))
+ elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
+ 'INT64', 'UINT64', 'DOUBLE'):
+ self.b(' *state->%s = g_value_get_%s (args->values + %d);'
+ % (name, marshaller.lower(), i))
+ else:
+ assert False, "Don't know how to copy %s" % gtype
+
+ self.b('')
+
+ if len(out_args) > 0:
+ self.b(' g_value_array_free (args);')
+ else:
+ self.b(' if (args != NULL)')
+ self.b(' g_value_array_free (args);')
+
+ self.b('}')
+ self.b('')
+
+ if self.deprecate_reentrant:
+ self.h('#ifndef %s' % self.deprecate_reentrant)
+
+ self.h('gboolean %s (%sproxy,'
+ % (run_method_name, self.proxy_arg))
+ self.h(' gint timeout_ms,')
+
+ self.d('/**')
+ self.d(' * %s:' % run_method_name)
+ self.d(' * @proxy: %s' % self.proxy_doc)
+ self.d(' * @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
+
+ docs = xml_escape(get_docstring(elt) or '(Undocumented)')
+
+ if ctype == 'guint ' and tp_type != '':
+ docs += ' (#%s)' % ('Tp' + tp_type.replace('_', ''))
+
+ self.d(' * @%s: Used to pass an \'in\' argument: %s'
+ % (name, docs))
+
+ for arg in out_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ self.d(' * @%s: Used to return an \'out\' argument if %%TRUE is '
+ 'returned: %s'
+ % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+ self.d(' * @error: If not %NULL, used to return errors if %FALSE ')
+ self.d(' * is returned')
+ self.d(' * @loop: If not %NULL, set before re-entering ')
+ self.d(' * the main loop, to point to a #GMainLoop ')
+ self.d(' * which can be used to cancel this call with ')
+ self.d(' * g_main_loop_quit(), causing a return of ')
+ self.d(' * %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
+ self.d(' *')
+ self.d(' * Call the method %s and run the main loop' % member)
+ self.d(' * until it returns. Before calling this method, you must')
+ self.d(' * add a reference to any borrowed objects you need to keep,')
+ self.d(' * and generally ensure that everything is in a consistent')
+ self.d(' * state.')
+ self.d(' *')
+ self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
+ self.d(' *')
+ self.d(' * Returns: TRUE on success, FALSE and sets @error on error')
+
+ deprecated = method.getElementsByTagName('tp:deprecated')
+ if deprecated:
+ d = deprecated[0]
+ self.d(' *')
+ self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
+
+ self.d(' */')
+ self.d('')
+
+ self.b('gboolean\n%s (%sproxy,'
+ % (run_method_name, self.proxy_arg))
+ self.b(' gint timeout_ms,')
+
+ for arg in in_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ const = pointer and 'const ' or ''
+
+ self.h(' %s%s%s,' % (const, ctype, name))
+ self.b(' %s%s%s,' % (const, ctype, name))
+
+ for arg in out_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ self.h(' %s*%s,' % (ctype, name))
+ self.b(' %s*%s,' % (ctype, name))
+
+ self.h(' GError **error,')
+
+ if self.deprecate_reentrant:
+ self.h(' GMainLoop **loop) %s;' % self.deprecation_attribute)
+ self.h('#endif /* not %s */' % self.deprecate_reentrant)
+ else:
+ self.h(' GMainLoop **loop);')
+
+ self.h('')
+
+ self.b(' GError **error,')
+ self.b(' GMainLoop **loop)')
+ self.b('{')
+ self.b(' DBusGProxy *iface;')
+ self.b(' GQuark interface = %s;' % self.get_iface_quark())
+ self.b(' TpProxyPendingCall *pc;')
+ self.b(' _%s_%s_run_state_%s state = {'
+ % (self.prefix_lc, iface_lc, member_lc))
+ self.b(' NULL /* loop */, error,')
+
+ for arg in out_args:
+ name, info, tp_type, elt = arg
+
+ self.b(' %s,' % name)
+
+ self.b(' FALSE /* completed */, FALSE /* success */ };')
+ self.b('')
+ self.b(' g_return_val_if_fail (%s (proxy), FALSE);'
+ % self.proxy_assert)
+ self.b('')
+ self.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
+ self.b(' iface = tp_proxy_borrow_interface_by_id')
+ self.b(' ((TpProxy *) proxy, interface, error);')
+ self.b(' G_GNUC_END_IGNORE_DEPRECATIONS')
+ self.b('')
+ self.b(' if (iface == NULL)')
+ self.b(' return FALSE;')
+ self.b('')
+ self.b(' state.loop = g_main_loop_new (NULL, FALSE);')
+ self.b('')
+ self.b(' pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
+ self.b(' interface, "%s", iface,' % member)
+ self.b(' %s,' % reentrant_invoke)
+ self.b(' NULL, &state, NULL, NULL, TRUE);')
+ self.b('')
+ self.b(' if (loop != NULL)')
+ self.b(' *loop = state.loop;')
+ self.b('')
+ self.b(' tp_proxy_pending_call_v0_take_pending_call (pc,')
+ self.b(' dbus_g_proxy_begin_call_with_timeout (iface,')
+ self.b(' "%s",' % member)
+ self.b(' %s,' % collect_callback)
+ self.b(' pc,')
+ self.b(' tp_proxy_pending_call_v0_completed,')
+ self.b(' timeout_ms,')
+
+ for arg in in_args:
+ name, info, tp_type, elt = arg
+ ctype, gtype, marshaller, pointer = info
+
+ const = pointer and 'const ' or ''
+
+ self.b(' %s, %s,' % (gtype, name))
+
+ self.b(' G_TYPE_INVALID));')
+ self.b('')
+ self.b(' if (!state.completed)')
+ self.b(' g_main_loop_run (state.loop);')
+ self.b('')
+ self.b(' if (!state.completed)')
+ self.b(' tp_proxy_pending_call_cancel (pc);')
+ self.b('')
+ self.b(' if (loop != NULL)')
+ self.b(' *loop = NULL;')
+ self.b('')
+ self.b(' g_main_loop_unref (state.loop);')
+ self.b('')
+ self.b(' return state.success;')
+ self.b('}')
+ self.b('')
+
+ def do_signal_add(self, signal):
+ marshaller_items = []
+ gtypes = []
+
+ 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):
+
+ if self.guard is not None:
+ self.h('#ifndef %s' % self.guard)
+ self.h('#define %s' % self.guard)
+ self.h('')
+
+ 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('')
+
+ if self.guard is not None:
+ self.h('#endif /* defined (%s) */' % self.guard)
+ self.h('')
+
+ file_set_contents(self.basename + '.h', '\n'.join(self.__header))
+ file_set_contents(self.basename + '-body.h', '\n'.join(self.__body))
+ file_set_contents(self.basename + '-gtk-doc.h', '\n'.join(self.__docs))
+
+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=',
+ 'generate-reentrant=', 'deprecate-reentrant=',
+ 'deprecation-attribute=', 'guard='])
+
+ 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 000000000..cb27d638a
--- /dev/null
+++ b/tools/glib-client-marshaller-gen.py
@@ -0,0 +1,60 @@
+#!/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 ('
+ print ' g_cclosure_marshal_generic,'
+ 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-check-gen.py b/tools/glib-errors-check-gen.py
new file mode 100644
index 000000000..553fc9caf
--- /dev/null
+++ b/tools/glib-errors-check-gen.py
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, 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 __call__(self):
+
+ print '{'
+ print ' GEnumClass *klass;'
+ print ' GEnumValue *value_by_name;'
+ print ' GEnumValue *value_by_nick;'
+ print ''
+ print ' g_type_init ();'
+ print ' klass = g_type_class_ref (TP_TYPE_ERROR);'
+
+ for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'):
+ ns = error.parentNode.getAttribute('namespace')
+ nick = error.getAttribute('name').replace(' ', '')
+ enum = ('TP_ERROR_' +
+ error.getAttribute('name').replace(' ', '_').replace('.', '_').upper())
+ s = ('TP_ERROR_STR_' +
+ error.getAttribute('name').replace(' ', '_').replace('.', '_').upper())
+
+ print ''
+ print ' /* %s.%s */' % (ns, nick)
+ print (' value_by_name = g_enum_get_value_by_name (klass, "%s");'
+ % enum)
+ print (' value_by_nick = g_enum_get_value_by_nick (klass, "%s");'
+ % nick)
+ print (' g_assert (value_by_name != NULL);')
+ print (' g_assert (value_by_nick != NULL);')
+ print (' g_assert_cmpint (value_by_name->value, ==, %s);'
+ % enum)
+ print (' g_assert_cmpint (value_by_nick->value, ==, %s);'
+ % enum)
+ print (' g_assert_cmpstr (value_by_name->value_name, ==, "%s");'
+ % enum)
+ print (' g_assert_cmpstr (value_by_nick->value_name, ==, "%s");'
+ % enum)
+ print (' g_assert_cmpstr (value_by_name->value_nick, ==, "%s");'
+ % nick)
+ print (' g_assert_cmpstr (value_by_nick->value_nick, ==, "%s");'
+ % nick)
+ print (' g_assert_cmpstr (%s, ==, TP_ERROR_PREFIX ".%s");'
+ % (s, nick))
+
+ print '}'
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+ Generator(xml.dom.minidom.parse(argv[0]))()
diff --git a/tools/glib-errors-str-gen.py b/tools/glib-errors-str-gen.py
new file mode 100644
index 000000000..b2cf520bd
--- /dev/null
+++ b/tools/glib-errors-str-gen.py
@@ -0,0 +1,83 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+
+from libtpcodegen import file_set_contents
+from libglibcodegen import NS_TP, get_docstring, xml_escape
+
+class Generator(object):
+ def __init__(self, dom, basename):
+ self.dom = dom
+ self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0]
+ self.basename = basename
+
+ self.__header = []
+ self.__body = []
+ self.__docs = []
+
+ 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 d(self, s):
+ if isinstance(s, unicode):
+ s = s.encode('utf-8')
+ self.__docs.append(s)
+
+ def __call__(self):
+ errors = self.errors.getElementsByTagNameNS(NS_TP, 'error')
+
+ self.b('#include <telepathy-glib/errors.h>')
+ self.b('')
+ self.b('const gchar *')
+ self.b('tp_error_get_dbus_name (TpError error)')
+ self.b('{')
+ self.b(' switch (error)')
+ self.b(' {')
+
+ for error in errors:
+ ns = error.parentNode.getAttribute('namespace')
+ nick = error.getAttribute('name').replace(' ', '')
+ uc_nick = error.getAttribute('name').replace(' ', '_').replace('.', '_').upper()
+ name = 'TP_ERROR_STR_' + uc_nick
+ error_name = '%s.%s' % (ns, nick)
+
+ self.d('/**')
+ self.d(' * %s:' % name)
+ self.d(' *')
+ self.d(' * The D-Bus error name %s' % error_name)
+ self.d(' *')
+ self.d(' * %s' % xml_escape(get_docstring(error)))
+ self.d(' */')
+ self.d('')
+
+ self.h('#define %s "%s"' % (name, error_name))
+
+ self.b(' case TP_ERROR_%s:' % uc_nick)
+ self.b(' return %s;' % name)
+
+ self.b(' default:')
+ self.b(' g_return_val_if_reached (NULL);')
+ self.b(' }')
+ self.b('}')
+
+ # make both files end with a newline
+ self.h('')
+ self.b('')
+
+ file_set_contents(self.basename + '.h', '\n'.join(self.__header))
+ file_set_contents(self.basename + '.c', '\n'.join(self.__body))
+ file_set_contents(self.basename + '-gtk-doc.h', '\n'.join(self.__docs))
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+ basename = argv[0]
+
+ Generator(xml.dom.minidom.parse(argv[1]), basename)()
diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py
index e277b91f4..6fec0d3c4 100644
--- a/tools/glib-ginterface-gen.py
+++ b/tools/glib-ginterface-gen.py
@@ -26,9 +26,9 @@ import sys
import os.path
import xml.dom.minidom
+from libtpcodegen import file_set_contents
from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
- NS_TP, dbus_gutils_wincaps_to_uscore, \
- signal_to_marshal_name, method_to_glue_marshal_name
+ NS_TP, dbus_gutils_wincaps_to_uscore
NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
@@ -421,8 +421,7 @@ class Generator(object):
'not match' % (method.getAttribute('name'), lc_name))
lc_name = lc_name.lower()
- marshaller = method_to_glue_marshal_name(method,
- self.signal_marshal_prefix)
+ marshaller = 'g_cclosure_marshal_generic'
wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name
self.b(" { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset))
@@ -717,8 +716,7 @@ class Generator(object):
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_cclosure_marshal_generic,')
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))
@@ -740,8 +738,9 @@ class Generator(object):
self.h('#include <glib-object.h>')
self.h('#include <dbus/dbus-glib.h>')
- if self.have_properties(nodes):
- self.h('#include <telepathy-glib/dbus-properties-mixin.h>')
+ for header in self.headers:
+ self.h('#include %s' % header)
+ self.h('')
self.h('')
self.h('G_BEGIN_DECLS')
@@ -749,9 +748,6 @@ class Generator(object):
self.b('#include "%s.h"' % self.basename)
self.b('')
- for header in self.headers:
- self.b('#include %s' % header)
- self.b('')
for node in nodes:
self.do_node(node)
@@ -765,10 +761,9 @@ class Generator(object):
self.h('')
self.b('')
- open(self.basename + '.h', 'w').write('\n'.join(self.__header))
- open(self.basename + '.c', 'w').write('\n'.join(self.__body))
- open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs))
-
+ file_set_contents(self.basename + '.h', '\n'.join(self.__header))
+ file_set_contents(self.basename + '.c', '\n'.join(self.__body))
+ file_set_contents(self.basename + '-gtk-doc.h', '\n'.join(self.__docs))
def cmdline_error():
print """\
diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py
index a49c36e7f..21dfc6aa7 100644
--- a/tools/glib-gtypes-generator.py
+++ b/tools/glib-gtypes-generator.py
@@ -23,6 +23,7 @@
import sys
import xml.dom.minidom
+from libtpcodegen import file_set_contents
from libglibcodegen import escape_as_identifier, \
get_docstring, \
NS_TP, \
@@ -42,15 +43,16 @@ class GTypesGenerator(object):
self.PREFIX_ = self.Prefix.upper() + '_'
self.prefix_ = self.Prefix.lower() + '_'
- self.header = open(output + '.h', 'w')
- self.body = open(output + '-body.h', 'w')
- self.docs = open(output + '-gtk-doc.h', 'w')
+ self.header = []
+ self.body = []
+ self.docs = []
+ self.output = output
for f in (self.header, self.body, self.docs):
- 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')
+ f.append('/* 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')
# keys are e.g. 'sv', values are the key escaped
self.need_mappings = {}
@@ -66,13 +68,13 @@ class GTypesGenerator(object):
self.need_other_arrays = {}
def h(self, code):
- self.header.write(code.encode("utf-8"))
+ self.header.append(code.encode("utf-8"))
def c(self, code):
- self.body.write(code.encode("utf-8"))
+ self.body.append(code.encode("utf-8"))
def d(self, code):
- self.docs.write(code.encode('utf-8'))
+ self.docs.append(code.encode('utf-8'))
def do_mapping_header(self, mapping):
members = mapping.getElementsByTagNameNS(NS_TP, 'member')
@@ -89,7 +91,7 @@ class GTypesGenerator(object):
docstring = get_docstring(mapping) or '(Undocumented)'
- self.d('/**\n * %s:\n *\n' % name)
+ self.d('/**\n * %s:\n *\n' % name.strip())
self.d(' * %s\n' % xml_escape(docstring))
self.d(' *\n')
self.d(' * This macro expands to a call to a function\n')
@@ -290,6 +292,10 @@ class GTypesGenerator(object):
self.c(' return t;\n')
self.c('}\n\n')
+ file_set_contents(self.output + '.h', ''.join(self.header))
+ file_set_contents(self.output + '-body.h', ''.join(self.body))
+ file_set_contents(self.output + '-gtk-doc.h', ''.join(self.docs))
+
if __name__ == '__main__':
argv = sys.argv[1:]
diff --git a/tools/glib-interfaces-gen.py b/tools/glib-interfaces-gen.py
index 69c721be3..410762cde 100644
--- a/tools/glib-interfaces-gen.py
+++ b/tools/glib-interfaces-gen.py
@@ -3,6 +3,7 @@
from sys import argv, stdout, stderr
import xml.dom.minidom
+from libtpcodegen import file_set_contents
from libglibcodegen import NS_TP, get_docstring, \
get_descendant_text, get_by_path
@@ -13,25 +14,33 @@ class Generator(object):
assert declfile.endswith('.h')
docfile = declfile[:-2] + '-gtk-doc.h'
- self.impls = open(implfile, 'w')
- self.decls = open(declfile, 'w')
- self.docs = open(docfile, 'w')
+ self.implfile = implfile
+ self.declfile = declfile
+ self.docfile = docfile
+
+ self.impls = []
+ self.decls = []
+ self.docs = []
self.spec = get_by_path(dom, "spec")[0]
def h(self, code):
- self.decls.write(code.encode('utf-8'))
+ self.decls.append(code.encode('utf-8'))
def c(self, code):
- self.impls.write(code.encode('utf-8'))
+ self.impls.append(code.encode('utf-8'))
def d(self, code):
- self.docs.write(code.encode('utf-8'))
+ self.docs.append(code.encode('utf-8'))
def __call__(self):
for f in self.h, self.c:
self.do_header(f)
self.do_body()
+ file_set_contents(self.implfile, ''.join(self.impls))
+ file_set_contents(self.declfile, ''.join(self.decls))
+ file_set_contents(self.docfile, ''.join(self.docs))
+
# Header
def do_header(self, f):
f('/* Generated from: ')
@@ -49,6 +58,7 @@ class Generator(object):
f("""
*/
+#include <glib.h>
""")
# Body
diff --git a/tools/glib-signals-marshal-gen.py b/tools/glib-signals-marshal-gen.py
deleted file mode 100644
index 0d02c1341..000000000
--- a/tools/glib-signals-marshal-gen.py
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/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 000000000..002a290ba
--- /dev/null
+++ b/tools/gobject-foo.py
@@ -0,0 +1,90 @@
+#!/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-2010 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))
+
+ if as_interface:
+ o("typedef struct _%sInterface %sInterface;" % (MixedCase, MixedCase))
+ else:
+ 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 as_interface:
+ o("#define %s_GET_IFACE(obj) \\" % UPPER_CASE)
+ o(" (G_TYPE_INSTANCE_GET_INTERFACE ((obj), %s, \\" % gtype)
+ o(" %sInterface))" % MixedCase)
+ else:
+ 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/lcov.am b/tools/lcov.am
index 7384f1b99..80023cb78 100644
--- a/tools/lcov.am
+++ b/tools/lcov.am
@@ -8,6 +8,7 @@ lcov-report:
--remove @top_builddir@/lcov.info.tmp telepathy-glib-scan.c
rm @top_builddir@/lcov.info.tmp
$(mkdir_p) @top_builddir@/lcov.html
+ echo "Coming soon!" > @top_builddir@/lcov.html/index.html
git_commit=`GIT_DIR=@top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`;\
genhtml --title "@PACKAGE_STRING@ $$git_commit" \
--output-directory @top_builddir@/lcov.html lcov.info
diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py
index 837ff2f74..7e9eb9a50 100644
--- a/tools/libtpcodegen.py
+++ b/tools/libtpcodegen.py
@@ -20,7 +20,7 @@ please make any changes there.
# 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 os
from string import ascii_letters, digits
@@ -28,6 +28,18 @@ NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
_ASCII_ALNUM = ascii_letters + digits
+def file_set_contents(filename, contents):
+ try:
+ os.remove(filename)
+ except OSError:
+ pass
+ try:
+ os.remove(filename + '.tmp')
+ except OSError:
+ pass
+
+ open(filename + '.tmp', 'w').write(contents)
+ os.rename(filename + '.tmp', filename)
def cmp_by_name(node1, node2):
return cmp(node1.getAttributeNode("name").nodeValue,
diff --git a/tools/make-version-script.py b/tools/make-version-script.py
new file mode 100644
index 000000000..0d30aa323
--- /dev/null
+++ b/tools/make-version-script.py
@@ -0,0 +1,208 @@
+#!/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-2010 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
+
+
+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))
+
+ if symbol in versioned_symbols:
+ raise AssertionError('Symbol %s is in version %s and an '
+ 'earlier version' % (symbol, version))
+
+ 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/manager-file.py b/tools/manager-file.py
new file mode 100644
index 000000000..e1b51a616
--- /dev/null
+++ b/tools/manager-file.py
@@ -0,0 +1,187 @@
+#!/usr/bin/python
+
+# manager-file.py: generate .manager files and TpCMParamSpec arrays from the
+# same data (should be suitable for all connection managers that don't have
+# plugins)
+#
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (c) 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 re
+import sys
+
+_NOT_C_STR = re.compile(r'[^A-Za-z0-9_-]')
+
+def c_string(x):
+ # whitelist-based brute force and ignorance - escape nearly all punctuation
+ return '"' + _NOT_C_STR.sub(lambda c: r'\x%02x' % ord(c), x) + '"'
+
+def desktop_string(x):
+ return x.replace(' ', r'\s').replace('\n', r'\n').replace('\r', r'\r').replace('\t', r'\t')
+
+supported = list('sbuiqn')
+
+fdefaultencoders = {
+ 's': desktop_string,
+ 'b': (lambda b: b and '1' or '0'),
+ 'u': (lambda n: '%u' % n),
+ 'i': (lambda n: '%d' % n),
+ 'q': (lambda n: '%u' % n),
+ 'n': (lambda n: '%d' % n),
+ }
+for x in supported: assert x in fdefaultencoders
+
+gtypes = {
+ 's': 'G_TYPE_STRING',
+ 'b': 'G_TYPE_BOOLEAN',
+ 'u': 'G_TYPE_UINT',
+ 'i': 'G_TYPE_INT',
+ 'q': 'G_TYPE_UINT',
+ 'n': 'G_TYPE_INT',
+}
+for x in supported: assert x in gtypes
+
+gdefaultencoders = {
+ 's': c_string,
+ 'b': (lambda b: b and 'GINT_TO_POINTER (TRUE)' or 'GINT_TO_POINTER (FALSE)'),
+ 'u': (lambda n: 'GUINT_TO_POINTER (%u)' % n),
+ 'i': (lambda n: 'GINT_TO_POINTER (%d)' % n),
+ 'q': (lambda n: 'GUINT_TO_POINTER (%u)' % n),
+ 'n': (lambda n: 'GINT_TO_POINTER (%d)' % n),
+ }
+for x in supported: assert x in gdefaultencoders
+
+gdefaultdefaults = {
+ 's': 'NULL',
+ 'b': 'GINT_TO_POINTER (FALSE)',
+ 'u': 'GUINT_TO_POINTER (0)',
+ 'i': 'GINT_TO_POINTER (0)',
+ 'q': 'GUINT_TO_POINTER (0)',
+ 'n': 'GINT_TO_POINTER (0)',
+ }
+for x in supported: assert x in gdefaultdefaults
+
+gflags = {
+ 'has-default': 'TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT',
+ 'register': 'TP_CONN_MGR_PARAM_FLAG_REGISTER',
+ 'required': 'TP_CONN_MGR_PARAM_FLAG_REQUIRED',
+ 'secret': 'TP_CONN_MGR_PARAM_FLAG_SECRET',
+ 'dbus-property': 'TP_CONN_MGR_PARAM_FLAG_DBUS_PROPERTY',
+}
+
+def write_manager(f, manager, protos):
+ # pointless backwards compat section
+ print >> f, '[ConnectionManager]'
+ print >> f, 'BusName=org.freedesktop.Telepathy.ConnectionManager.' + manager
+ print >> f, 'ObjectPath=/org/freedesktop/Telepathy/ConnectionManager/' + manager
+
+ # protocols
+ for proto, params in protos.iteritems():
+ print >> f
+ print >> f, '[Protocol %s]' % proto
+
+ defaults = {}
+
+ for param, info in params.iteritems():
+ dtype = info['dtype']
+ flags = info.get('flags', '').split()
+ struct_field = info.get('struct_field', param.replace('-', '_'))
+ filter = info.get('filter', 'NULL')
+ filter_data = info.get('filter_data', 'NULL')
+ setter_data = 'NULL'
+
+ if 'default' in info:
+ default = fdefaultencoders[dtype](info['default'])
+ defaults[param] = default
+
+ if flags:
+ flags = ' ' + ' '.join(flags)
+ else:
+ flags = ''
+
+ print >> f, 'param-%s=%s%s' % (param, desktop_string(dtype), flags)
+
+ for param, default in defaults.iteritems():
+ print >> f, 'default-%s=%s' % (param, default)
+
+def write_c_params(f, manager, proto, struct, params):
+ print >> f, "static const TpCMParamSpec %s_%s_params[] = {" % (manager, proto)
+
+ for param, info in params.iteritems():
+ dtype = info['dtype']
+ flags = info.get('flags', '').split()
+ struct_field = info.get('struct_field', param.replace('-', '_'))
+ filter = info.get('filter', 'NULL')
+ filter_data = info.get('filter_data', 'NULL')
+ setter_data = 'NULL'
+
+ if 'default' in info:
+ default = gdefaultencoders[dtype](info['default'])
+ else:
+ default = gdefaultdefaults[dtype]
+
+ if flags:
+ flags = ' | '.join([gflags[flag] for flag in flags])
+ else:
+ flags = '0'
+
+ if struct is None or struct_field is None:
+ struct_offset = '0'
+ else:
+ struct_offset = 'G_STRUCT_OFFSET (%s, %s)' % (struct, struct_field)
+
+ print >> f, (''' { %s, %s, %s,
+ %s,
+ %s, /* default */
+ %s, /* struct offset */
+ %s, /* filter */
+ %s, /* filter data */
+ %s /* setter data */ },''' %
+ (c_string(param), c_string(dtype), gtypes[dtype], flags,
+ default, struct_offset, filter, filter_data, setter_data))
+
+ print >> f, " { NULL }"
+ print >> f, "};"
+
+if __name__ == '__main__':
+ environment = {}
+ execfile(sys.argv[1], environment)
+
+ filename = '%s/%s.manager' % (sys.argv[2], environment['MANAGER'])
+ try:
+ os.remove(filename)
+ except OSError:
+ pass
+ f = open(filename + '.tmp', 'w')
+ write_manager(f, environment['MANAGER'], environment['PARAMS'])
+ f.close()
+ os.rename(filename + '.tmp', filename)
+
+ filename = '%s/param-spec-struct.h' % sys.argv[2]
+ try:
+ os.remove(filename)
+ except OSError:
+ pass
+ f = open(filename + '.tmp', 'w')
+ for protocol in environment['PARAMS']:
+ write_c_params(f, environment['MANAGER'], protocol,
+ environment['STRUCTS'][protocol],
+ environment['PARAMS'][protocol])
+ f.close()
+ os.rename(filename + '.tmp', filename)
diff --git a/tools/shave.mk b/tools/shave.mk
new file mode 100644
index 000000000..53cb3bf5e
--- /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 000000000..ddc47bfd8
--- /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-glib.supp b/tools/telepathy-glib.supp
new file mode 100644
index 000000000..28bd5a06a
--- /dev/null
+++ b/tools/telepathy-glib.supp
@@ -0,0 +1,390 @@
+# Valgrind error suppression file
+
+# ============================= libc ==================================
+
+{
+ ld.so initialization + selinux
+ Memcheck:Leak
+ ...
+ fun:_dl_init
+ obj:/lib/ld-*.so
+}
+
+{
+ dlopen initialization, triggered by handle-leak-debug code
+ Memcheck:Leak
+ ...
+ fun:__libc_dlopen_mode
+ fun:init
+ fun:backtrace
+ fun:handle_leak_debug_bt
+ fun:dynamic_ensure_handle
+ fun:tp_handle_ensure
+}
+
+# default.supp has these for 2.10, but they're too specific
+{
+ Debian libc6 (2.10.x, 2.11.x) stripped dynamic linker
+ Memcheck:Cond
+ fun:index
+ fun:expand_dynamic_string_token
+ fun:_dl_map_object
+ fun:map_doit
+ fun:_dl_catch_error
+ fun:do_preload
+ fun:dl_main
+ fun:_dl_sysdep_start
+ fun:_dl_start
+ obj:/lib/ld-*.so
+}
+{
+ Debian libc6 (2.9.x - 2.11.x) stripped dynamic linker
+ Memcheck:Cond
+ fun:_dl_relocate_object
+ fun:dl_main
+ fun:_dl_sysdep_start
+ fun:_dl_start
+ obj:/lib/ld-*.so
+}
+
+{
+ ld.so initialization on glibc 2.9
+ Memcheck:Cond
+ fun:strlen
+ fun:_dl_init_paths
+ fun:dl_main
+ fun:_dl_sysdep_start
+ fun:_dl_start
+ obj:/lib/ld-2.9.so
+}
+
+# ======================= libselinux on Debian amd64 =====================
+
+{
+ I have no idea what SELinux is doing but it's not my problem
+ Memcheck:Cond
+ ...
+ obj:/lib/libselinux.so.1
+ obj:/lib/libselinux.so.1
+ obj:/lib/libselinux.so.1
+}
+
+{
+ I have no idea what SELinux is doing but it's not my problem
+ Memcheck:Value8
+ ...
+ obj:/lib/libselinux.so.1
+ obj:/lib/libselinux.so.1
+ obj:/lib/libselinux.so.1
+}
+
+{
+ I have no idea what SELinux is doing but it's not my problem
+ Memcheck:Leak
+ ...
+ obj:/lib/libselinux.so.1
+ obj:/lib/libselinux.so.1
+ obj:/lib/libselinux.so.1
+}
+
+# ============================= GLib ==================================
+
+{
+ g_set_prgname copies its argument
+ Memcheck:Leak
+ ...
+ fun:g_set_prgname
+}
+
+{
+ one g_get_charset per child^Wprocess
+ Memcheck:Leak
+ ...
+ fun:g_get_charset
+}
+
+{
+ one g_get_home_dir per process
+ Memcheck:Leak
+ ...
+ fun:g_get_home_dir
+}
+
+{
+ GQuarks can't be freed
+ Memcheck:Leak
+ ...
+ fun:g_quark_from_static_string
+}
+
+{
+ GQuarks can't be freed
+ Memcheck:Leak
+ ...
+ fun:g_quark_from_string
+}
+
+{
+ interned strings can't be freed
+ Memcheck:Leak
+ ...
+ fun:g_intern_string
+}
+
+{
+ interned strings can't be freed
+ Memcheck:Leak
+ ...
+ fun:g_intern_static_string
+}
+
+{
+ shared global default g_main_context
+ Memcheck:Leak
+ ...
+ fun:g_main_context_new
+ fun:g_main_context_default
+}
+
+{
+ GTest initialization
+ Memcheck:Leak
+ ...
+ fun:g_test_init
+ fun:main
+}
+
+{
+ GTest admin
+ Memcheck:Leak
+ ...
+ fun:g_test_add_vtable
+}
+
+{
+ GTest pseudorandomness
+ Memcheck:Leak
+ ...
+ fun:g_rand_new_with_seed_array
+ fun:test_run_seed
+ ...
+ fun:g_test_run
+}
+
+{
+ GSLice initialization
+ Memcheck:Leak
+ ...
+ fun:g_malloc0
+ fun:g_slice_init_nomessage
+ fun:g_slice_alloc
+}
+
+# ============================= GObject ===============================
+
+{
+ g_type_init
+ Memcheck:Leak
+ ...
+ fun:g_type_init
+}
+
+{
+ g_type_init_with_debug_flags
+ Memcheck:Leak
+ ...
+ fun:g_type_init_with_debug_flags
+}
+
+{
+ g_type_register_static
+ Memcheck:Leak
+ ...
+ fun:g_type_register_static
+}
+
+{
+ g_type_add_interface_static
+ Memcheck:Leak
+ ...
+ fun:g_type_add_interface_static
+}
+
+{
+ initialization of interfaces
+ Memcheck:Leak
+ ...
+ fun:type_iface_vtable_base_init_Wm
+ fun:g_type_class_ref
+}
+
+# ============================= GIO ===================================
+
+{
+ GIO init
+ Memcheck:Leak
+ ...
+ fun:g_inet_address_class_intern_init
+}
+
+{
+ g_simple_async_result class
+ Memcheck:Leak
+ ...
+ fun:g_type_class_ref
+ ...
+ fun:g_simple_async_result_new
+}
+
+# ============================= dbus-glib =============================
+
+{
+ registering marshallers is permanent
+ Memcheck:Leak
+ ...
+ fun:dbus_g_object_register_marshaller_array
+ fun:dbus_g_object_register_marshaller
+}
+
+{
+ dbus-glib specialized GTypes are permanent
+ Memcheck:Leak
+ ...
+ fun:dbus_g_type_specialized_init
+}
+
+{
+ libdbus shared connection
+ Memcheck:Leak
+ ...
+ fun:dbus_g_bus_get
+}
+
+{
+ dbus-gobject registrations aren't freed unless we fall off the bus
+ Memcheck:Leak
+ ...
+ fun:g_slist_append
+ fun:dbus_g_connection_register_g_object
+}
+
+{
+ DBusGProxy slots aren't freed unless we fall off the bus
+ Memcheck:Leak
+ ...
+ fun:dbus_connection_allocate_data_slot
+ ...
+ fun:dbus_g_proxy_constructor
+}
+
+{
+ error registrations are for life, not just for Christmas
+ Memcheck:Leak
+ ...
+ fun:dbus_g_error_domain_register
+}
+
+{
+ DBusGProxy class init
+ Memcheck:Leak
+ ...
+ fun:dbus_g_proxy_class_init
+}
+
+# ============================= telepathy-glib ========================
+
+{
+ tp_dbus_daemon_constructor @daemons once per DBusConnection
+ Memcheck:Leak
+ ...
+ fun:g_slice_alloc
+ fun:tp_dbus_daemon_constructor
+}
+
+{
+ tp_proxy_subclass_add_error_mapping refs the enum
+ Memcheck:Leak
+ ...
+ fun:g_type_class_ref
+ fun:tp_proxy_subclass_add_error_mapping
+}
+
+{
+ tp_proxy_or_subclass_hook_on_interface_add never frees its list
+ Memcheck:Leak
+ ...
+ fun:tp_proxy_or_subclass_hook_on_interface_add
+}
+
+{
+ tp_dbus_daemon_constructor filter not freed til we fall off the bus
+ Memcheck:Leak
+ ...
+ fun:dbus_connection_add_filter
+ fun:tp_dbus_daemon_constructor
+}
+
+{
+ tp_g_socket_address_from_variant reffing GNIO types
+ Memcheck:Leak
+ ...
+ fun:g_type_class_ref
+ ...
+ fun:tp_g_socket_address_from_variant
+}
+
+{
+ creating classes for DBusGProxy
+ Memcheck:Leak
+ ...
+ fun:g_type_class_ref
+ ...
+ fun:g_object_new
+ ...
+ fun:tp_proxy_borrow_interface_by_id
+}
+
+{
+ creating classes for tp_dbus_daemon_new
+ Memcheck:Leak
+ ...
+ fun:g_type_class_ref
+ ...
+ fun:g_object_new
+ ...
+ fun:tp_dbus_daemon_new
+}
+
+{
+ creating classes for TpCHannel
+ Memcheck:Leak
+ ...
+ fun:g_type_class_ref
+ ...
+ fun:g_object_new
+ ...
+ fun:tp_channel_new
+}
+
+{
+ creating a boxed type to use in TpCapabilities
+ Memcheck:Leak
+ ...
+ fun:g_type_class_ref
+ ...
+ fun:g_param_spec_boxed
+ fun:tp_capabilities_class_intern_init
+}
+
+# ============================= questionable ==========================
+
+{
+ creating classes for instances (this is a pretty big hammer)
+ Memcheck:Leak
+ ...
+ fun:g_type_class_ref
+ ...
+ fun:g_type_create_instance
+ ...
+ fun:g_param_spec_string
+}
diff --git a/tools/test-wrapper.sh b/tools/test-wrapper.sh
new file mode 100755
index 000000000..94900674a
--- /dev/null
+++ b/tools/test-wrapper.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Make tests shut up. On success, if stdout is a tty, we only output messages
+# about skipped tests; on failure, or if stdout is a file or pipe, we output
+# the lot.
+#
+# Usage: test-wrapper.sh PROGRAM [ARGS...]
+
+set -e
+
+if test -t 1 && test "z$CHECK_VERBOSE" = z; then
+ : # continue with the output-suppressed code path, below
+else
+ "$@" || e=$?
+ exit $e
+fi
+
+e=0
+"$@" > capture-$$.log 2>&1 || e=$?
+if test z$e = z0; then
+ grep -i skipped capture-$$.log || true
+ rm -f capture-$$.log
+else
+ cat capture-$$.log
+ exit $e
+fi
+
+# Copyright © 2010 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. There is no warranty.
diff --git a/tools/valgrind.mk b/tools/valgrind.mk
new file mode 100644
index 000000000..25a3488cd
--- /dev/null
+++ b/tools/valgrind.mk
@@ -0,0 +1,13 @@
+VALGRIND = valgrind --tool=memcheck \
+ --verbose \
+ --leak-check=full \
+ --leak-resolution=high \
+ --suppressions=$(top_srcdir)/tools/telepathy-glib.supp \
+ --child-silent-after-fork=yes \
+ --num-callers=20 \
+ --gen-suppressions=all
+
+# other potentially interesting options:
+# --show-reachable=yes reachable objects (many!)
+# --read-var-info=yes better diagnostics from DWARF3 info
+# --track-origins=yes better diagnostics for uninit values (slow)
diff --git a/tools/with-session-bus.sh b/tools/with-session-bus.sh
new file mode 100755
index 000000000..b3038cd9e
--- /dev/null
+++ b/tools/with-session-bus.sh
@@ -0,0 +1,100 @@
+#!/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"
+sleep=0
+
+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
+ --sleep=*)
+ sleep="$1"
+ sleep="${sleep#--sleep=}"
+ shift
+ ;;
+ --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
+ if [ -n "$VERBOSE_TESTS" ]; then
+ echo "Killing temporary bus daemon: $pid" >&2
+ fi
+ kill -INT "$pid"
+ fi
+ rm -f $me-$$.address
+ rm -f $me-$$.pid
+}
+
+trap cleanup INT HUP TERM
+dbus-daemon $dbus_daemon_args
+
+if [ -n "$VERBOSE_TESTS" ]; then
+ { echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2
+ { echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2
+fi
+
+e=0
+DBUS_SESSION_BUS_ADDRESS="`cat $me-$$.address`"
+export DBUS_SESSION_BUS_ADDRESS
+DBUS_SESSION_BUS_PID="`cat $me-$$.pid`"
+export DBUS_SESSION_BUS_PID
+
+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 2>&1 &
+fi
+
+"$@" || e=$?
+
+if test $sleep != 0; then
+ sleep $sleep
+fi
+
+trap - INT HUP TERM
+cleanup
+
+exit $e