summaryrefslogtreecommitdiff
path: root/qt4/tools
diff options
context:
space:
mode:
Diffstat (limited to 'qt4/tools')
-rw-r--r--qt4/tools/CMakeLists.txt124
-rw-r--r--qt4/tools/c-constants-gen.py154
-rw-r--r--qt4/tools/check-misc.sh13
-rw-r--r--qt4/tools/check-whitespace.sh17
-rw-r--r--qt4/tools/git-which-branch.sh25
-rw-r--r--qt4/tools/glib-ginterface-gen.py802
-rw-r--r--qt4/tools/glib-gtypes-generator.py291
-rw-r--r--qt4/tools/glib-interfaces-gen.py119
-rw-r--r--qt4/tools/glib-signals-marshal-gen.py55
-rw-r--r--qt4/tools/libglibcodegen.py172
-rw-r--r--qt4/tools/libqt4codegen.py499
-rw-r--r--qt4/tools/libtpcodegen.py215
-rw-r--r--qt4/tools/manager-file.py175
-rw-r--r--qt4/tools/qt4-client-gen.py547
-rw-r--r--qt4/tools/qt4-constants-gen.py310
-rw-r--r--qt4/tools/qt4-types-gen.py557
-rwxr-xr-xqt4/tools/repeat-tests.sh23
-rw-r--r--qt4/tools/telepathy-glib.supp390
-rw-r--r--qt4/tools/tp-qt4-tests.supp53
-rw-r--r--qt4/tools/with-session-bus.sh94
-rw-r--r--qt4/tools/xincludator.py39
21 files changed, 4674 insertions, 0 deletions
diff --git a/qt4/tools/CMakeLists.txt b/qt4/tools/CMakeLists.txt
new file mode 100644
index 000000000..3c023216a
--- /dev/null
+++ b/qt4/tools/CMakeLists.txt
@@ -0,0 +1,124 @@
+# Some useful commands
+add_custom_command(OUTPUT FIXME.out
+
+ COMMAND egrep
+
+ ARGS -A 5 '[F]IXME|[T]ODO|[X]XX' ${CMAKE_SOURCE_DIR}/TelepathyQt4/*.[ch]*
+ ${CMAKE_SOURCE_DIR}/TelepathyQt4/*.[ch]*
+ > FIXME.out || true)
+add_custom_target(check-local DEPENDS FIXME.out)
+
+execute_process(COMMAND ${SH} tools/git-which-branch.sh misc | tr -d '\n' | tr -C "[:alnum:]" _
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_BRANCH_CURRENT)
+
+if (GIT_BRANCH_CURRENT)
+ string(LENGTH ${GIT_BRANCH_CURRENT} HAVE_GIT_BRANCH)
+
+ if (HAVE_GIT_BRANCH)
+ string(REPLACE "\n" "" GIT_BRANCH_CURRENT ${GIT_BRANCH_CURRENT})
+
+ set(UPLOAD_BRANCH_TO people.freedesktop.org:public_html/telepathy-qt4)
+
+ add_custom_target(upload-branch-docs rsync -rtzvPp --chmod=a+rX doc/html/ ${UPLOAD_BRANCH_TO}-${GIT_BRANCH_CURRENT}
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+ add_dependencies(upload-branch-docs doxygen-doc)
+ endif (HAVE_GIT_BRANCH)
+endif (GIT_BRANCH_CURRENT)
+
+if (PERL_FOUND)
+ add_custom_target(maintainer-fix-qt-links-in-docs
+ ${PERL_EXECUTABLE} doc/html/installdox -l qt.tags@http://doc.qt.nokia.com/latest/ doc/html/*.html
+
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+ add_dependencies(maintainer-fix-qt-links-in-docs doxygen-doc _maintainer-upload-release-check)
+endif (PERL_FOUND)
+
+add_custom_target(maintainer-upload-release-docs
+ rsync -rtOvzPp --chmod=Dg+s,ug+rwX,o=rX doc/html/ telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/doc/telepathy-qt4/
+
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+
+if (PERL_FOUND)
+ add_dependencies(maintainer-upload-release-docs maintainer-fix-qt-links-in-docs)
+else (PERL_FOUND)
+ add_dependencies(maintainer-upload-release-docs doxygen-doc _maintainer-upload-release-check)
+endif (PERL_FOUND)
+
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/maintainer-upload-release-check.sh "
+#!/bin/sh
+case ${PACKAGE_VERSION} in
+ (*.*.*.*)
+ echo \"${PACKAGE_VERSION} is not a release\" >&2;
+ exit 2;
+ ;;
+esac
+test -f ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz
+if ! test -f ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc; then
+ gpg --detach-sign -a ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz;
+fi;
+gpg --verify ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc
+")
+
+add_custom_target(_maintainer-upload-release-check ${SH} ${CMAKE_CURRENT_BINARY_DIR}/maintainer-upload-release-check.sh)
+
+add_custom_target(maintainer-upload-release
+ rsync -vzP ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz
+telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/${PACKAGE_NAME}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz
+ COMMAND
+ rsync -vzP ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc
+telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/${PACKAGE_NAME}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+
+add_dependencies(maintainer-upload-release _maintainer-upload-release-check maintainer-upload-release-docs)
+
+
+set(toolchain_files
+ c-constants-gen.py
+ check-misc.sh
+ check-whitespace.sh
+ git-which-branch.sh
+ glib-ginterface-gen.py
+ glib-gtypes-generator.py
+ glib-interfaces-gen.py
+ glib-signals-marshal-gen.py
+ libtpcodegen.py
+ libglibcodegen.py
+ libqt4codegen.py
+ qt4-client-gen.py
+ qt4-constants-gen.py
+ qt4-types-gen.py
+ manager-file.py
+ with-session-bus.sh
+ xincludator.py
+)
+
+string(REPLACE "." " " sh_toolchain_files ${toolchain_files})
+
+set(TELEPATHY_SPEC_SRCDIR ${CMAKE_SOURCE_DIR}/../telepathy-spec)
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-spec.sh "
+#!/bin/sh
+set -e
+cd ${CMAKE_SOURCE_DIR}
+for x in ${sh_toolchain_files}; do
+ if test -f ${TELEPATHY_SPEC_SRCDIR}/tools/$$x; then
+ cp ${TELEPATHY_SPEC_SRCDIR}/tools/$$x $$x;
+ fi;
+done
+")
+add_custom_target(maintainer-update-from-telepathy-spec ${SH} ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-spec.sh
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+
+set(TELEPATHY_GLIB_SRCDIR ${CMAKE_SOURCE_DIR}/../telepathy-glib)
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-glib.sh "
+#!/bin/sh
+set -e
+cd ${CMAKE_SOURCE_DIR}
+for x in ${sh_toolchain_files}; do
+ if test -f ${TELEPATHY_GLIB_SRCDIR}/tools/$$x; then
+ cp ${TELEPATHY_GLIB_SRCDIR}/tools/$$x $$x;
+ fi;
+done
+")
+add_custom_target(maintainer-update-from-telepathy-glib ${SH} ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-glib.sh
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
diff --git a/qt4/tools/c-constants-gen.py b/qt4/tools/c-constants-gen.py
new file mode 100644
index 000000000..8969ffdca
--- /dev/null
+++ b/qt4/tools/c-constants-gen.py
@@ -0,0 +1,154 @@
+#!/usr/bin/python
+
+from sys import argv, stdout, stderr
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, 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()
+
+ def write(self, code):
+ stdout.write(code.encode('utf-8'))
+
+ # Header
+ def do_header(self):
+ self.write('/* Generated from ')
+ self.write(get_descendant_text(get_by_path(self.spec, 'title')))
+ version = get_by_path(self.spec, "version")
+ if version:
+ self.write(', version ' + get_descendant_text(version))
+ self.write('\n\n')
+ for copyright in get_by_path(self.spec, 'copyright'):
+ self.write(get_descendant_text(copyright))
+ self.write('\n')
+ self.write(get_descendant_text(get_by_path(self.spec, 'license')))
+ self.write('\n')
+ self.write(get_descendant_text(get_by_path(self.spec, 'docstring')))
+ self.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')
+ self.write("""\
+/**
+ *
+%s:
+""" % (self.prefix + name).replace('_', ''))
+ for flag in get_by_path(flags, 'flag'):
+ self.do_gtkdoc(flag, value_prefix)
+ self.write(' *\n')
+ docstrings = get_by_path(flags, 'docstring')
+ if docstrings:
+ self.write("""\
+ * <![CDATA[%s]]>
+ *
+""" % get_descendant_text(docstrings).replace('\n', ' '))
+ self.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)
+ self.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'
+ self.write("""\
+/**
+ *
+%s:
+""" % (self.prefix + name).replace('_', ''))
+ vals = get_by_path(enum, 'enumvalue')
+ for val in vals:
+ self.do_gtkdoc(val, value_prefix)
+ self.write(' *\n')
+ docstrings = get_by_path(enum, 'docstring')
+ if docstrings:
+ self.write("""\
+ * <![CDATA[%s]]>
+ *
+""" % get_descendant_text(docstrings).replace('\n', ' '))
+ self.write("""\
+ * Bitfield/set of flags generated from the Telepathy specification.
+ */
+typedef enum {
+""")
+ for val in vals:
+ self.do_val(val, value_prefix)
+ self.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)
+ self.write(' %s = %s,\n' % (use_name, val.getAttribute('value')))
+
+ def do_gtkdoc(self, node, value_prefix):
+ self.write(' * @')
+ self.write((self.prefix + value_prefix + '_' +
+ node.getAttribute('suffix')).upper())
+ self.write(': <![CDATA[')
+ docstring = get_by_path(node, 'docstring')
+ self.write(get_descendant_text(docstring).replace('\n', ' '))
+ self.write(']]>\n')
+
+ # Footer
+ def do_footer(self):
+ self.write("""
+#ifdef __cplusplus
+}
+#endif
+""")
+
+if __name__ == '__main__':
+ argv = argv[1:]
+ Generator(argv[0], xml.dom.minidom.parse(argv[1]))()
diff --git a/qt4/tools/check-misc.sh b/qt4/tools/check-misc.sh
new file mode 100644
index 000000000..89e8e871a
--- /dev/null
+++ b/qt4/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/qt4/tools/check-whitespace.sh b/qt4/tools/check-whitespace.sh
new file mode 100644
index 000000000..534833126
--- /dev/null
+++ b/qt4/tools/check-whitespace.sh
@@ -0,0 +1,17 @@
+#!/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 tabs"
+ fail=1
+fi
+
+exit $fail
diff --git a/qt4/tools/git-which-branch.sh b/qt4/tools/git-which-branch.sh
new file mode 100644
index 000000000..b96b5d5e2
--- /dev/null
+++ b/qt4/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/qt4/tools/glib-ginterface-gen.py b/qt4/tools/glib-ginterface-gen.py
new file mode 100644
index 000000000..13f7f69eb
--- /dev/null
+++ b/qt4/tools/glib-ginterface-gen.py
@@ -0,0 +1,802 @@
+#!/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, \
+ 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.basename = basename
+ self.signal_marshal_prefix = signal_marshal_prefix
+ self.headers = headers
+ self.end_headers = end_headers
+ self.not_implemented_func = not_implemented_func
+ self.allow_havoc = allow_havoc
+
+ 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))
+
+ if methods:
+ self.h(' *')
+ self.h(' * In a full implementation of this interface (i.e. all')
+ self.h(' * methods implemented), the interface initialization')
+ self.h(' * function used in G_IMPLEMENT_INTERFACE() would')
+ self.h(' * typically look like this:')
+ self.h(' *')
+ self.h(' * <programlisting>')
+ self.h(' * static void')
+ self.h(' * implement_%s (gpointer klass,' % self.node_name_lc)
+ self.h(' * gpointer unused G_GNUC_UNUSED)')
+ self.h(' * {')
+ # "#" is special to gtkdoc under some circumstances; it appears
+ # that escaping "##" as "#<!---->#" or "&#35;&#35;" doesn't work,
+ # but adding an extra hash symbol does. Thanks, gtkdoc :-(
+ self.h(' * #define IMPLEMENT(x) %s%s_implement_###x (\\'
+ % (self.prefix_, self.node_name_lc))
+ self.h(' * klass, my_object_###x)')
+
+ for method in methods:
+ class_member_name = method.getAttribute('tp:name-for-bindings')
+ class_member_name = class_member_name.lower()
+ self.h(' * IMPLEMENT (%s);' % class_member_name)
+
+ self.h(' * #undef IMPLEMENT')
+ self.h(' * }')
+ self.h(' * </programlisting>')
+ else:
+ self.h(' * This interface has no D-Bus methods, so an')
+ self.h(' * implementation can typically pass %NULL to')
+ self.h(' * G_IMPLEMENT_INTERFACE() as the interface')
+ self.h(' * initialization function.')
+
+ 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('{')
+
+ if properties:
+ 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(' dbus_g_object_type_install_info (%s%s_get_type (),'
+ % (self.prefix_, node_name_lc))
+ self.b(' &_%s%s_object_info);'
+ % (self.prefix_, node_name_lc))
+ self.b('')
+
+ if properties:
+ self.b(' interface.dbus_interface = g_quark_from_static_string '
+ '("%s");' % self.iface_name)
+
+ for i, m in enumerate(properties):
+ self.b(' properties[%d].name = g_quark_from_static_string ("%s");'
+ % (i, m.getAttribute('name')))
+ self.b(' properties[%d].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('}')
+
+ 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)
+
+ if len(methods) == 0:
+ # empty arrays are a gcc extension, so put in a dummy member
+ self.b(" { NULL, NULL, 0 }")
+
+ self.b('};')
+ self.b('')
+
+ 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 = method.getAttribute('tp:name-for-bindings')
+ if method.getAttribute('name') != lc_name.replace('_', ''):
+ raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+ 'not match' % (method.getAttribute('name'), lc_name))
+ lc_name = lc_name.lower()
+
+ marshaller = method_to_glue_marshal_name(method,
+ self.signal_marshal_prefix)
+ 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 = method.getAttribute('tp:name-for-bindings')
+ if dbus_method_name != class_member_name.replace('_', ''):
+ raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+ 'not match' % (dbus_method_name, class_member_name))
+ class_member_name = class_member_name.lower()
+
+ stub_name = (self.prefix_ + self.node_name_lc + '_' +
+ class_member_name)
+ return (stub_name + '_impl', class_member_name)
+
+ 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 = method.getAttribute('tp:name-for-bindings')
+ if dbus_method_name != class_member_name.replace('_', ''):
+ raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+ 'not match' % (dbus_method_name, class_member_name))
+ class_member_name = class_member_name.lower()
+
+ # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint,
+ # DBusGMethodInvocation *);
+ stub_name = (self.prefix_ + self.node_name_lc + '_' +
+ 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')
+
+ ugly_name = signal.getAttribute('tp:name-for-bindings')
+ if dbus_name != ugly_name.replace('_', ''):
+ raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
+ 'not match' % (dbus_name, ugly_name))
+
+ stub_name = (self.prefix_ + self.node_name_lc + '_emit_' +
+ ugly_name.lower())
+
+ 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 have_properties(self, nodes):
+ for node in nodes:
+ interface = node.getElementsByTagName('interface')[0]
+ if interface.getElementsByTagName('property'):
+ return True
+ return False
+
+ def __call__(self):
+ nodes = self.dom.getElementsByTagName('node')
+ nodes.sort(cmp_by_name)
+
+ self.h('#include <glib-object.h>')
+ self.h('#include <dbus/dbus-glib.h>')
+
+ if self.have_properties(nodes):
+ self.h('#include <telepathy-glib/dbus-properties-mixin.h>')
+
+ self.h('')
+ self.h('G_BEGIN_DECLS')
+ self.h('')
+
+ self.b('#include "%s.h"' % self.basename)
+ self.b('')
+ for header in self.headers:
+ self.b('#include %s' % header)
+ self.b('')
+
+ 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(self.basename + '.h', 'w').write('\n'.join(self.__header))
+ open(self.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/qt4/tools/glib-gtypes-generator.py b/qt4/tools/glib-gtypes-generator.py
new file mode 100644
index 000000000..ebc2ad4c9
--- /dev/null
+++ b/qt4/tools/glib-gtypes-generator.py
@@ -0,0 +1,291 @@
+#!/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')
+
+ # keys are e.g. 'sv', values are the key escaped
+ self.need_mappings = {}
+ # keys are the contents of the struct (e.g. 'sssu'), values are the
+ # key escaped
+ self.need_structs = {}
+ # keys are the contents of the struct (e.g. 'sssu'), values are the
+ # key escaped
+ self.need_struct_arrays = {}
+
+ # keys are the contents of the array (unlike need_struct_arrays!),
+ # values are the key escaped
+ self.need_other_arrays = {}
+
+ def h(self, code):
+ self.header.write(code.encode("utf-8"))
+
+ def c(self, code):
+ self.body.write(code.encode("utf-8"))
+
+ 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.h('/**\n * %s:\n *\n' % name)
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+ self.h(' * This macro expands to a call to a function\n')
+ self.h(' * that returns the #GType of a #GHashTable\n')
+ self.h(' * appropriate for representing a D-Bus\n')
+ self.h(' * dictionary of signature\n')
+ self.h(' * <literal>a{%s}</literal>.\n' % impl_sig)
+ self.h(' *\n')
+
+ key, value = members
+
+ self.h(' * Keys (D-Bus type <literal>%s</literal>,\n'
+ % key.getAttribute('type'))
+ tp_type = key.getAttributeNS(NS_TP, 'type')
+ if tp_type:
+ self.h(' * type <literal>%s</literal>,\n' % tp_type)
+ self.h(' * named <literal>%s</literal>):\n'
+ % key.getAttribute('name'))
+ docstring = get_docstring(key) or '(Undocumented)'
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+
+ self.h(' * Values (D-Bus type <literal>%s</literal>,\n'
+ % value.getAttribute('type'))
+ tp_type = value.getAttributeNS(NS_TP, 'type')
+ if tp_type:
+ self.h(' * type <literal>%s</literal>,\n' % tp_type)
+ self.h(' * named <literal>%s</literal>):\n'
+ % value.getAttribute('name'))
+ docstring = get_docstring(value) or '(Undocumented)'
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+
+ self.h(' */\n')
+
+ self.h('#define %s (%s ())\n\n' % (name, impl))
+ self.need_mappings[impl_sig] = esc_impl_sig
+
+ array_name = mapping.getAttribute('array-name')
+ if array_name:
+ gtype_name = self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper()
+ contents_sig = 'a{' + impl_sig + '}'
+ esc_contents_sig = escape_as_identifier(contents_sig)
+ impl = self.prefix_ + 'type_dbus_array_of_' + esc_contents_sig
+ self.h('/**\n * %s:\n\n' % gtype_name)
+ self.h(' * Expands to a call to a function\n')
+ self.h(' * that returns the #GType of a #GPtrArray\n')
+ self.h(' * of #%s.\n' % name)
+ self.h(' */\n')
+ self.h('#define %s (%s ())\n\n' % (gtype_name, impl))
+ self.need_other_arrays[contents_sig] = esc_contents_sig
+
+ def do_struct_header(self, struct):
+ members = struct.getElementsByTagNameNS(NS_TP, 'member')
+ impl_sig = ''.join([elt.getAttribute('type') for elt in members])
+ 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.h('/**\n * %s:\n\n' % name)
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+ self.h(' * This macro expands to a call to a function\n')
+ self.h(' * that returns the #GType of a #GValueArray\n')
+ self.h(' * appropriate for representing a D-Bus struct\n')
+ self.h(' * with signature <literal>(%s)</literal>.\n'
+ % impl_sig)
+ self.h(' *\n')
+
+ for i, member in enumerate(members):
+ self.h(' * Member %d (D-Bus type '
+ '<literal>%s</literal>,\n'
+ % (i, member.getAttribute('type')))
+ tp_type = member.getAttributeNS(NS_TP, 'type')
+ if tp_type:
+ self.h(' * type <literal>%s</literal>,\n' % tp_type)
+ self.h(' * named <literal>%s</literal>):\n'
+ % member.getAttribute('name'))
+ docstring = get_docstring(member) or '(Undocumented)'
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+
+ self.h(' */\n')
+ self.h('#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.h('/**\n * %s:\n\n' % array_name)
+ self.h(' * Expands to a call to a function\n')
+ self.h(' * that returns the #GType of a #GPtrArray\n')
+ self.h(' * of #%s.\n' % name)
+ self.h(' */\n')
+ self.h('#define %s (%s ())\n\n' % (array_name, impl))
+ self.need_struct_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.h('GType %stype_dbus_hash_%s (void);\n\n' %
+ (self.prefix_, self.need_mappings[sig]))
+ self.c('GType\n%stype_dbus_hash_%s (void)\n{\n' %
+ (self.prefix_, self.need_mappings[sig]))
+ self.c(' static GType t = 0;\n\n')
+ self.c(' if (G_UNLIKELY (t == 0))\n')
+ # FIXME: translate sig into two GTypes
+ items = tuple(Signature(sig))
+ gtypes = types_to_gtypes(items)
+ self.c(' t = dbus_g_type_get_map ("GHashTable", '
+ '%s, %s);\n' % (gtypes[0], gtypes[1]))
+ self.c(' return t;\n')
+ self.c('}\n\n')
+
+ for struct in structs:
+ self.do_struct_header(struct)
+
+ for sig in self.need_structs:
+ self.h('GType %stype_dbus_struct_%s (void);\n\n' %
+ (self.prefix_, self.need_structs[sig]))
+ self.c('GType\n%stype_dbus_struct_%s (void)\n{\n' %
+ (self.prefix_, self.need_structs[sig]))
+ self.c(' static GType t = 0;\n\n')
+ self.c(' if (G_UNLIKELY (t == 0))\n')
+ self.c(' t = dbus_g_type_get_struct ("GValueArray",\n')
+ items = tuple(Signature(sig))
+ gtypes = types_to_gtypes(items)
+ for gtype in gtypes:
+ self.c(' %s,\n' % gtype)
+ self.c(' G_TYPE_INVALID);\n')
+ self.c(' return t;\n')
+ self.c('}\n\n')
+
+ for sig in self.need_struct_arrays:
+ self.h('GType %stype_dbus_array_%s (void);\n\n' %
+ (self.prefix_, self.need_struct_arrays[sig]))
+ self.c('GType\n%stype_dbus_array_%s (void)\n{\n' %
+ (self.prefix_, self.need_struct_arrays[sig]))
+ self.c(' static GType t = 0;\n\n')
+ self.c(' if (G_UNLIKELY (t == 0))\n')
+ self.c(' t = dbus_g_type_get_collection ("GPtrArray", '
+ '%stype_dbus_struct_%s ());\n' %
+ (self.prefix_, self.need_struct_arrays[sig]))
+ self.c(' return t;\n')
+ self.c('}\n\n')
+
+ for sig in self.need_other_arrays:
+ self.h('GType %stype_dbus_array_of_%s (void);\n\n' %
+ (self.prefix_, self.need_other_arrays[sig]))
+ self.c('GType\n%stype_dbus_array_of_%s (void)\n{\n' %
+ (self.prefix_, self.need_other_arrays[sig]))
+ self.c(' static GType t = 0;\n\n')
+ self.c(' if (G_UNLIKELY (t == 0))\n')
+
+ if sig[:2] == 'a{' and sig[-1:] == '}':
+ # array of mappings
+ self.c(' t = dbus_g_type_get_collection ('
+ '"GPtrArray", '
+ '%stype_dbus_hash_%s ());\n' %
+ (self.prefix_, escape_as_identifier(sig[2:-1])))
+ elif sig[:2] == 'a(' and sig[-1:] == ')':
+ # array of arrays of struct
+ self.c(' t = dbus_g_type_get_collection ('
+ '"GPtrArray", '
+ '%stype_dbus_array_%s ());\n' %
+ (self.prefix_, escape_as_identifier(sig[2:-1])))
+ elif sig[:1] == 'a':
+ # array of arrays of non-struct
+ self.c(' t = dbus_g_type_get_collection ('
+ '"GPtrArray", '
+ '%stype_dbus_array_of_%s ());\n' %
+ (self.prefix_, escape_as_identifier(sig[1:])))
+ else:
+ raise AssertionError("array of '%s' not supported" % sig)
+
+ self.c(' return t;\n')
+ self.c('}\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/qt4/tools/glib-interfaces-gen.py b/qt4/tools/glib-interfaces-gen.py
new file mode 100644
index 000000000..95439687e
--- /dev/null
+++ b/qt4/tools/glib-interfaces-gen.py
@@ -0,0 +1,119 @@
+#!/usr/bin/python
+
+from sys import argv, stdout, stderr
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, 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 h(self, code):
+ self.decls.write(code.encode('utf-8'))
+
+ def c(self, code):
+ self.impls.write(code.encode('utf-8'))
+
+ def __call__(self):
+ for f in self.h, self.c:
+ self.do_header(f)
+ self.do_body()
+
+ # Header
+ def do_header(self, f):
+ f('/* Generated from: ')
+ f(get_descendant_text(get_by_path(self.spec, 'title')))
+ version = get_by_path(self.spec, "version")
+ if version:
+ f(' version ' + get_descendant_text(version))
+ f('\n\n')
+ for copyright in get_by_path(self.spec, 'copyright'):
+ f(get_descendant_text(copyright))
+ f('\n')
+ f('\n')
+ f(get_descendant_text(get_by_path(self.spec, 'license')))
+ f(get_descendant_text(get_by_path(self.spec, 'docstring')))
+ f("""
+ */
+
+""")
+
+ # 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.h("""\
+/**
+ * %(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.h("""
+/**
+ * %(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.c("""\
+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')})
+
+ for prop in iface.getElementsByTagNameNS(None, 'property'):
+ self.decls.write("""
+/**
+ * %(IFACE_PREFIX)s_%(PROP_UC)s:
+ *
+ * The fully-qualified property name "%(name)s.%(prop)s"
+ */
+#define %(IFACE_PREFIX)s_%(PROP_UC)s \\
+"%(name)s.%(prop)s"
+""" % {'IFACE_PREFIX' : (self.prefix + 'PROP_' + \
+ parent_name).upper().replace('/', ''),
+ 'PROP_UC': prop.getAttributeNS(NS_TP, "name-for-bindings").upper(),
+ 'name' : iface.getAttribute('name'),
+ 'prop' : prop.getAttribute('name'),
+ })
+
+if __name__ == '__main__':
+ argv = argv[1:]
+ Generator(argv[0], argv[1], argv[2], xml.dom.minidom.parse(argv[3]))()
diff --git a/qt4/tools/glib-signals-marshal-gen.py b/qt4/tools/glib-signals-marshal-gen.py
new file mode 100644
index 000000000..0d02c1341
--- /dev/null
+++ b/qt4/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/qt4/tools/libglibcodegen.py b/qt4/tools/libglibcodegen.py
new file mode 100644
index 000000000..6a9d21485
--- /dev/null
+++ b/qt4/tools/libglibcodegen.py
@@ -0,0 +1,172 @@
+"""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, \
+ cmp_by_name, \
+ escape_as_identifier, \
+ get_by_path, \
+ get_descendant_text, \
+ get_docstring, \
+ xml_escape, \
+ get_deprecated
+
+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/qt4/tools/libqt4codegen.py b/qt4/tools/libqt4codegen.py
new file mode 100644
index 000000000..dd2237891
--- /dev/null
+++ b/qt4/tools/libqt4codegen.py
@@ -0,0 +1,499 @@
+"""Library code for Qt4 D-Bus-related code generation.
+
+The master copy of this library is in the telepathy-qt4 repository -
+please make any changes there.
+"""
+
+# Copyright (C) 2008 Collabora Limited <http://www.collabora.co.uk>
+# Copyright (C) 2008 Nokia Corporation
+#
+# 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 sys import maxint, stderr
+import re
+from libtpcodegen import get_by_path, get_descendant_text, NS_TP, xml_escape
+
+class Xzibit(Exception):
+ def __init__(self, parent, child):
+ self.parent = parent
+ self.child = child
+
+ def __str__(self):
+ print """
+ Nested <%s>s are forbidden.
+ Parent:
+ %s...
+ Child:
+ %s...
+ """ % (self.parent.nodeName, self.parent.toxml()[:100],
+ self.child.toxml()[:100])
+
+class _Qt4TypeBinding:
+ def __init__(self, val, inarg, outarg, array_val, custom_type, array_of,
+ array_depth=None):
+ self.val = val
+ self.inarg = inarg
+ self.outarg = outarg
+ self.array_val = array_val
+ self.custom_type = custom_type
+ self.array_of = array_of
+ self.array_depth = array_depth
+
+ if array_depth is None:
+ self.array_depth = int(bool(array_val))
+ elif array_depth >= 1:
+ assert array_val
+ else:
+ assert not array_val
+
+class RefTarget(object):
+ KIND_INTERFACE, KIND_METHOD, KIND_SIGNAL, KIND_PROPERTY = 'node', 'method', 'signal', 'property'
+
+ def __init__(self, el):
+ self.kind = el.localName
+ assert self.kind in (self.KIND_INTERFACE, self.KIND_METHOD, self.KIND_SIGNAL, self.KIND_PROPERTY)
+
+ if self.kind == self.KIND_INTERFACE:
+ self.dbus_text = el.getAttribute('name').lstrip('/').replace('_', '') + 'Interface'
+ else:
+ self.member_text = el.getAttribute('name')
+
+ assert el.parentNode.parentNode.localName == self.KIND_INTERFACE
+ host_class = el.parentNode.parentNode.getAttribute('name').lstrip('/').replace('_', '') + 'Interface'
+
+ if self.kind == self.KIND_PROPERTY:
+ self.member_link = 'requestProperty%s()' % (self.member_text)
+ self.dbus_link = '%s::%s' % (host_class, self.member_link)
+ else:
+ self.member_text = '%s()' % self.member_text
+
+ self.dbus_text = '%s::%s' % (host_class, self.member_text)
+
+class RefRegistry(object):
+ def __init__(self, spec):
+ self.targets = {}
+ for node in spec.getElementsByTagName('node'):
+ iface, = get_by_path(node, 'interface')
+ iface_name = iface.getAttribute('name')
+
+ self.targets[iface_name] = RefTarget(node)
+
+ for method in iface.getElementsByTagName(RefTarget.KIND_METHOD):
+ self.targets[iface_name + '.' + method.getAttribute('name')] = RefTarget(method)
+
+ for signal in iface.getElementsByTagName(RefTarget.KIND_SIGNAL):
+ self.targets[iface_name + '.' + signal.getAttribute('name')] = RefTarget(signal)
+
+ for prop in iface.getElementsByTagName(RefTarget.KIND_PROPERTY):
+ self.targets[iface_name + '.' + prop.getAttribute('name')] = RefTarget(prop)
+
+ def process(self, ref):
+ assert ref.namespaceURI == NS_TP
+
+ def get_closest_parent(el, needle):
+ node = el
+ while node is not None and node.localName != needle:
+ node = node.parentNode
+ return node
+
+ local = get_descendant_text(ref).strip()
+ if ref.localName == 'member-ref':
+ ns = get_closest_parent(ref, 'interface').getAttribute('name')
+ path = ns + '.' + local.strip()
+ else:
+ if ref.hasAttribute('namespace'):
+ ns = ref.getAttribute('namespace').replace('ofdT', 'org.freedesktop.Telepathy')
+ path = ns + '.' + local.strip()
+ else:
+ path = local
+
+ target = self.targets.get(path)
+
+ if target is None:
+ parent = get_closest_parent(ref, 'interface') or get_closest_parent(ref, 'error')
+ parent_name = parent.getAttribute('name')
+ if (path + parent_name).find('.DRAFT') == -1 and (path + parent_name).find('.FUTURE') == -1:
+ print >> stderr, 'WARNING: Failed to resolve %s to "%s" in "%s"' % (
+ ref.localName, path, parent_name)
+ return path
+
+ if ref.localName == 'member-ref':
+ if target.kind == target.KIND_PROPERTY:
+ return '\\link %s %s \\endlink' % (target.member_link, target.member_text)
+ else:
+ return target.member_text
+ else:
+ if target.kind == target.KIND_PROPERTY:
+ return '\\link %s %s \\endlink' % (target.dbus_link, target.dbus_text)
+ else:
+ return target.dbus_text
+
+def binding_from_usage(sig, tptype, custom_lists, external=False, explicit_own_ns=None):
+ # 'signature' : ('qt-type', 'pass-by-reference', 'array-type')
+ natives = {
+ 'y' : ('uchar', False, None),
+ 'b' : ('bool', False, 'BoolList'),
+ 'n' : ('short', False, 'ShortList'),
+ 'q' : ('ushort', False, 'UShortList'),
+ 'i' : ('int', False, 'IntList'),
+ 'u' : ('uint', False, 'UIntList'),
+ 'x' : ('qlonglong', False, 'LongLongList'),
+ 't' : ('qulonglong', False, 'ULongLongList'),
+ 'd' : ('double', False, 'DoubleList'),
+ 's' : ('QString', True, None),
+ 'v' : ('QDBusVariant', True, None),
+ 'o' : ('QDBusObjectPath', True, 'ObjectPathList'),
+ 'g' : ('QDBusSignature', True, 'SignatureList'),
+ 'as' : ('QStringList', True, "StringListList"),
+ 'ay' : ('QByteArray', True, "ByteArrayList"),
+ 'av' : ('QVariantList', True, "VariantListList"),
+ 'a{sv}' : ('QVariantMap', True, None)
+ }
+
+ val, inarg = None, None
+ custom_type = False
+ array_of = None
+
+ if natives.has_key(sig):
+ typename, pass_by_ref, array_name = natives[sig]
+ val = typename
+ inarg = (pass_by_ref and ('const %s&' % val)) or val
+ elif sig[0] == 'a' and natives.has_key(sig[1:]) and natives[sig[1:]][2]:
+ val = natives[sig[1:]][2]
+ if explicit_own_ns:
+ val = explicit_own_ns + '::' + val
+ inarg = 'const %s&' % val
+ array_of = natives[sig[1:]][0]
+ elif tptype:
+ tptype = tptype.replace('_', '')
+ custom_type = True
+
+ if external:
+ tptype = 'Tp::' + tptype
+ elif explicit_own_ns:
+ tptype = explicit_own_ns + '::' + tptype
+
+ if tptype.endswith('[]'):
+ tptype = tptype[:-2]
+ extra_list_nesting = 0
+
+ while tptype.endswith('[]'):
+ extra_list_nesting += 1
+ tptype = tptype[:-2]
+
+ assert custom_lists.has_key(tptype), ('No array version of custom type %s in the spec, but array version used' % tptype)
+ val = custom_lists[tptype] + 'List' * extra_list_nesting
+ else:
+ val = tptype
+
+ inarg = 'const %s&' % val
+ else:
+ assert False, 'Don\'t know how to map type (%s, %s)' % (sig, tptype)
+
+ outarg = val + '&'
+ return _Qt4TypeBinding(val, inarg, outarg, None, custom_type, array_of)
+
+def binding_from_decl(name, array_name, array_depth=None, external=False, explicit_own_ns=''):
+ val = name.replace('_', '')
+ if external:
+ val = 'Tp::' + val
+ elif explicit_own_ns:
+ val = explicit_own_ns + '::' + val
+ inarg = 'const %s&' % val
+ outarg = '%s&' % val
+ return _Qt4TypeBinding(val, inarg, outarg, array_name.replace('_', ''), True, None, array_depth)
+
+def extract_arg_or_member_info(els, custom_lists, externals, typesns, refs, docstring_indent=' * ', docstring_brackets=None, docstring_maxwidth=80):
+ names = []
+ docstrings = []
+ bindings = []
+
+ for el in els:
+ names.append(get_qt4_name(el))
+ docstrings.append(format_docstring(el, refs, docstring_indent, docstring_brackets, docstring_maxwidth))
+
+ sig = el.getAttribute('type')
+ tptype = el.getAttributeNS(NS_TP, 'type')
+ bindings.append(binding_from_usage(sig, tptype, custom_lists, (sig, tptype) in externals, typesns))
+
+ return names, docstrings, bindings
+
+def format_docstring(el, refs, indent=' * ', brackets=None, maxwidth=80):
+ docstring_el = None
+
+ for x in el.childNodes:
+ if x.namespaceURI == NS_TP and x.localName == 'docstring':
+ docstring_el = x
+
+ if not docstring_el:
+ return ''
+
+ lines = []
+
+ # escape backslashes, so they won't be interpreted starting doxygen commands and we can later
+ # insert doxygen commands we actually want
+ def escape_slashes(x):
+ if x.nodeType == x.TEXT_NODE:
+ x.data = x.data.replace('\\', '\\\\')
+ elif x.nodeType == x.ELEMENT_NODE:
+ for y in x.childNodes:
+ escape_slashes(y)
+ else:
+ return
+
+ escape_slashes(docstring_el)
+ doc = docstring_el.ownerDocument
+
+ for n in docstring_el.getElementsByTagNameNS(NS_TP, 'rationale'):
+ nested = n.getElementsByTagNameNS(NS_TP, 'rationale')
+ if nested:
+ raise Xzibit(n, nested[0])
+
+ div = doc.createElement('div')
+ div.setAttribute('class', 'rationale')
+
+ for rationale_body in n.childNodes:
+ div.appendChild(rationale_body.cloneNode(True))
+
+ n.parentNode.replaceChild(div, n)
+
+ if docstring_el.getAttribute('xmlns') == 'http://www.w3.org/1999/xhtml':
+ for ref in docstring_el.getElementsByTagNameNS(NS_TP, 'member-ref') + docstring_el.getElementsByTagNameNS(NS_TP, 'dbus-ref'):
+ nested = ref.getElementsByTagNameNS(NS_TP, 'member-ref') + ref.getElementsByTagNameNS(NS_TP, 'dbus-ref')
+ if nested:
+ raise Xzibit(n, nested[0])
+
+ text = doc.createTextNode(' \\endhtmlonly ')
+ text.data += refs.process(ref)
+ text.data += ' \\htmlonly '
+
+ ref.parentNode.replaceChild(text, ref)
+
+ splitted = ''.join([el.toxml() for el in docstring_el.childNodes]).strip(' ').strip('\n').split('\n')
+ level = min([not match and maxint or match.end() - 1 for match in [re.match('^ *[^ ]', line) for line in splitted]])
+ assert level != maxint
+ lines = ['\\htmlonly'] + [line[level:] for line in splitted] + ['\\endhtmlonly']
+ else:
+ content = xml_escape(get_descendant_text(docstring_el).replace('\n', ' ').strip())
+
+ while content.find(' ') != -1:
+ content = content.replace(' ', ' ')
+
+ left = maxwidth - len(indent) - 1
+ line = ''
+
+ while content:
+ step = (content.find(' ') + 1) or len(content)
+
+ if step > left:
+ lines.append(line)
+ line = ''
+ left = maxwidth - len(indent) - 1
+
+ left = left - step
+ line = line + content[:step]
+ content = content[step:]
+
+ if line:
+ lines.append(line)
+
+ output = []
+
+ if lines:
+ if brackets:
+ output.append(brackets[0])
+ else:
+ output.append(indent)
+
+ output.append('\n')
+
+ for line in lines:
+ output.append(indent)
+ output.append(line)
+ output.append('\n')
+
+ if lines and brackets:
+ output.append(brackets[1])
+ output.append('\n')
+
+ return ''.join(output)
+
+def gather_externals(spec):
+ externals = []
+
+ for ext in spec.getElementsByTagNameNS(NS_TP, 'external-type'):
+ sig = ext.getAttribute('type')
+ tptype = ext.getAttribute('name')
+ externals.append((sig, tptype))
+
+ return externals
+
+def gather_custom_lists(spec, typesns):
+ custom_lists = {}
+ structs = [(provider, typesns) for provider in spec.getElementsByTagNameNS(NS_TP, 'struct')]
+ mappings = [(provider, typesns) for provider in spec.getElementsByTagNameNS(NS_TP, 'mapping')]
+ exts = [(provider, 'Telepathy') for provider in spec.getElementsByTagNameNS(NS_TP, 'external-type')]
+
+ for (provider, ns) in structs + mappings + exts:
+ tptype = provider.getAttribute('name').replace('_', '')
+ array_val = provider.getAttribute('array-name').replace('_', '')
+ array_depth = provider.getAttribute('array-depth')
+ if array_depth:
+ array_depth = int(array_depth)
+ else:
+ array_depth = None
+
+ if array_val:
+ custom_lists[tptype] = array_val
+ custom_lists[ns + '::' + tptype] = ns + '::' + array_val
+ if array_depth >= 2:
+ for i in xrange(array_depth):
+ custom_lists[tptype + ('[]' * (i+1))] = (
+ array_val + ('List' * i))
+ custom_lists[ns + '::' + tptype + ('[]' * (i+1))] = (
+ ns + '::' + array_val + ('List' * i))
+
+ return custom_lists
+
+def get_headerfile_cmd(realinclude, prettyinclude, indent=' * '):
+ prettyinclude = prettyinclude or realinclude
+ if realinclude:
+ return indent + ('\\headerfile %s <%s>\n' % (realinclude, prettyinclude))
+ else:
+ return ''
+
+def get_qt4_name(el):
+ name = el.getAttribute('name')
+
+ if el.localName in ('method', 'signal', 'property'):
+ bname = el.getAttributeNS(NS_TP, 'name-for-bindings')
+
+ if bname:
+ name = bname
+
+ if not name:
+ return None
+
+ if name[0].isupper() and name[1].islower():
+ name = name[0].lower() + name[1:]
+
+ return qt4_identifier_escape(name.replace('_', ''))
+
+def qt4_identifier_escape(str):
+ built = (str[0].isdigit() and ['_']) or []
+
+ for c in str:
+ if c.isalnum():
+ built.append(c)
+ else:
+ built.append('_')
+
+ str = ''.join(built)
+
+ # List of reserved identifiers
+ # Initial list from http://cs.smu.ca/~porter/csc/ref/cpp_keywords.html
+
+ # Keywords inherited from C90
+ reserved = ['auto',
+ 'const',
+ 'double',
+ 'float',
+ 'int',
+ 'short',
+ 'struct',
+ 'unsigned',
+ 'break',
+ 'continue',
+ 'else',
+ 'for',
+ 'long',
+ 'signed',
+ 'switch',
+ 'void',
+ 'case',
+ 'default',
+ 'enum',
+ 'goto',
+ 'register',
+ 'sizeof',
+ 'typedef',
+ 'volatile',
+ 'char',
+ 'do',
+ 'extern',
+ 'if',
+ 'return',
+ 'static',
+ 'union',
+ 'while',
+ # C++-only keywords
+ 'asm',
+ 'dynamic_cast',
+ 'namespace',
+ 'reinterpret_cast',
+ 'try',
+ 'bool',
+ 'explicit',
+ 'new',
+ 'static_cast',
+ 'typeid',
+ 'catch',
+ 'false',
+ 'operator',
+ 'template',
+ 'typename',
+ 'class',
+ 'friend',
+ 'private',
+ 'this',
+ 'using',
+ 'const_cast',
+ 'inline',
+ 'public',
+ 'throw',
+ 'virtual',
+ 'delete',
+ 'mutable',
+ 'protected',
+ 'true',
+ 'wchar_t',
+ # Operator replacements
+ 'and',
+ 'bitand',
+ 'compl',
+ 'not_eq',
+ 'or_eq',
+ 'xor_eq',
+ 'and_eq',
+ 'bitor',
+ 'not',
+ 'or',
+ 'xor',
+ # Predefined identifiers
+ 'INT_MIN',
+ 'INT_MAX',
+ 'MAX_RAND',
+ 'NULL',
+ # Qt
+ 'SIGNAL',
+ 'SLOT',
+ 'signals',
+ 'slots']
+
+ while str in reserved:
+ str = str + '_'
+
+ return str
+
diff --git a/qt4/tools/libtpcodegen.py b/qt4/tools/libtpcodegen.py
new file mode 100644
index 000000000..837ff2f74
--- /dev/null
+++ b/qt4/tools/libtpcodegen.py
@@ -0,0 +1,215 @@
+"""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 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_deprecated(element):
+ text = []
+ for x in element.childNodes:
+ if hasattr(x, 'data'):
+ text.append(x.data.replace('\n', ' ').strip())
+ else:
+ # This caters for tp:dbus-ref elements, but little else.
+ if x.childNodes and hasattr(x.childNodes[0], 'data'):
+ text.append(x.childNodes[0].data.replace('\n', ' ').strip())
+ return ' '.join(text)
+
+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/qt4/tools/manager-file.py b/qt4/tools/manager-file.py
new file mode 100644
index 000000000..45f640403
--- /dev/null
+++ b/qt4/tools/manager-file.py
@@ -0,0 +1,175 @@
+#!/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)
+
+ f = open('%s/%s.manager' % (sys.argv[2], environment['MANAGER']), 'w')
+ write_manager(f, environment['MANAGER'], environment['PARAMS'])
+ f.close()
+
+ f = open('%s/param-spec-struct.h' % sys.argv[2], 'w')
+ for protocol in environment['PARAMS']:
+ write_c_params(f, environment['MANAGER'], protocol,
+ environment['STRUCTS'][protocol],
+ environment['PARAMS'][protocol])
+ f.close()
diff --git a/qt4/tools/qt4-client-gen.py b/qt4/tools/qt4-client-gen.py
new file mode 100644
index 000000000..465029be4
--- /dev/null
+++ b/qt4/tools/qt4-client-gen.py
@@ -0,0 +1,547 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2008 Collabora Limited <http://www.collabora.co.uk>
+# Copyright (C) 2008 Nokia Corporation
+#
+# 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 sys import argv
+import xml.dom.minidom
+import codecs
+from getopt import gnu_getopt
+
+from libtpcodegen import NS_TP, get_descendant_text, get_by_path
+from libqt4codegen import binding_from_usage, extract_arg_or_member_info, format_docstring, gather_externals, gather_custom_lists, get_headerfile_cmd, get_qt4_name, qt4_identifier_escape, RefRegistry
+
+class Generator(object):
+ def __init__(self, opts):
+ try:
+ self.group = opts.get('--group', '')
+ self.headerfile = opts['--headerfile']
+ self.implfile = opts['--implfile']
+ self.namespace = opts['--namespace']
+ self.typesnamespace = opts['--typesnamespace']
+ self.realinclude = opts['--realinclude']
+ self.prettyinclude = opts.get('--prettyinclude')
+ self.extraincludes = opts.get('--extraincludes', None)
+ self.mainiface = opts.get('--mainiface', None)
+ self.must_define = opts.get('--must-define', None)
+ self.dbus_proxy = opts.get('--dbus-proxy',
+ 'Tp::DBusProxy')
+ self.visibility = opts.get('--visibility', '')
+ ifacedom = xml.dom.minidom.parse(opts['--ifacexml'])
+ specdom = xml.dom.minidom.parse(opts['--specxml'])
+ except KeyError, k:
+ assert False, 'Missing required parameter %s' % k.args[0]
+
+ self.hs = []
+ self.bs = []
+ self.ifacenodes = ifacedom.getElementsByTagName('node')
+ self.spec, = get_by_path(specdom, "spec")
+ self.custom_lists = gather_custom_lists(self.spec, self.typesnamespace)
+ self.externals = gather_externals(self.spec)
+ self.refs = RefRegistry(self.spec)
+
+ def __call__(self):
+ # Output info header and includes
+ self.h("""\
+/*
+ * This file contains D-Bus client proxy classes generated by qt4-client-gen.py.
+ *
+ * This file can be distributed under the same terms as the specification from
+ * which it was generated.
+ */
+""")
+
+ if self.must_define:
+ self.h('\n')
+ self.h('#ifndef %s\n' % self.must_define)
+ self.h('#error %s\n' % self.must_define)
+ self.h('#endif\n')
+
+ self.h('\n')
+
+ if self.extraincludes:
+ for include in self.extraincludes.split(','):
+ self.h('#include %s\n' % include)
+
+ self.h("""
+#include <QtGlobal>
+
+#include <QString>
+#include <QObject>
+#include <QVariant>
+
+#include <QDBusPendingReply>
+
+#include <TelepathyQt4/AbstractInterface>
+#include <TelepathyQt4/DBusProxy>
+#include <TelepathyQt4/Global>
+
+namespace Tp
+{
+class PendingVariant;
+class PendingOperation;
+}
+
+""")
+
+ if self.must_define:
+ self.b("""#define %s\n""" % (self.must_define))
+
+ self.b("""#include "%s"
+
+""" % self.realinclude)
+
+ # Begin namespace
+ for ns in self.namespace.split('::'):
+ self.hb("""\
+namespace %s
+{
+""" % ns)
+
+ # Output interface proxies
+ def ifacenodecmp(x, y):
+ xname, yname = [self.namespace + '::' + node.getAttribute('name').replace('/', '').replace('_', '') + 'Interface' for node in x, y]
+
+ if xname == self.mainiface:
+ return -1
+ elif yname == self.mainiface:
+ return 1
+ else:
+ return cmp(xname, yname)
+
+ self.ifacenodes.sort(cmp=ifacenodecmp)
+ for ifacenode in self.ifacenodes:
+ self.do_ifacenode(ifacenode)
+
+ # End namespace
+ self.hb(''.join(['}\n' for ns in self.namespace.split('::')]))
+
+ # Add metatype declaration - otherwise QTBUG #2151 might be triggered
+ for ifacenode in self.ifacenodes:
+ classname = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Interface'
+ self.h("Q_DECLARE_METATYPE(" + self.namespace + "::" + classname + "*)\n")
+
+ # Write output to files
+ (codecs.getwriter('utf-8')(open(self.headerfile, 'w'))).write(''.join(self.hs))
+ (codecs.getwriter('utf-8')(open(self.implfile, 'w'))).write(''.join(self.bs))
+
+ def do_ifacenode(self, ifacenode):
+ # Extract info
+ name = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Interface'
+ iface, = get_by_path(ifacenode, 'interface')
+ dbusname = iface.getAttribute('name')
+
+ # Begin class, constructors
+ self.h("""
+/**
+ * \\class %(name)s
+%(headercmd)s\
+%(groupcmd)s\
+ *
+ * Proxy class providing a 1:1 mapping of the D-Bus interface "%(dbusname)s."
+ */
+class %(visibility)s %(name)s : public Tp::AbstractInterface
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Returns the name of the interface "%(dbusname)s", which this class
+ * represents.
+ *
+ * \\return The D-Bus interface name.
+ */
+ static inline QLatin1String staticInterfaceName()
+ {
+ return QLatin1String("%(dbusname)s");
+ }
+
+ /**
+ * Creates a %(name)s associated with the given object on the session bus.
+ *
+ * \\param busName Name of the service the object is on.
+ * \\param objectPath Path to the object on the service.
+ * \\param parent Passed to the parent class constructor.
+ */
+ %(name)s(
+ const QString& busName,
+ const QString& objectPath,
+ QObject* parent = 0
+ );
+
+ /**
+ * Creates a %(name)s associated with the given object on the given bus.
+ *
+ * \\param connection The bus via which the object can be reached.
+ * \\param busName Name of the service the object is on.
+ * \\param objectPath Path to the object on the service.
+ * \\param parent Passed to the parent class constructor.
+ */
+ %(name)s(
+ const QDBusConnection& connection,
+ const QString& busName,
+ const QString& objectPath,
+ QObject* parent = 0
+ );
+""" % {'name' : name,
+ 'headercmd' : get_headerfile_cmd(self.realinclude, self.prettyinclude),
+ 'groupcmd' : self.group and (' * \\ingroup %s\n' % self.group),
+ 'dbusname' : dbusname,
+ 'visibility': self.visibility,
+ })
+
+ self.b("""
+%(name)s::%(name)s(const QString& busName, const QString& objectPath, QObject *parent)
+ : Tp::AbstractInterface(busName, objectPath, staticInterfaceName(), QDBusConnection::sessionBus(), parent)
+{
+}
+
+%(name)s::%(name)s(const QDBusConnection& connection, const QString& busName, const QString& objectPath, QObject *parent)
+ : Tp::AbstractInterface(busName, objectPath, staticInterfaceName(), connection, parent)
+{
+}
+""" % {'name' : name})
+
+ # Construct from DBusProxy subclass
+ self.h("""
+ /**
+ * Creates a %(name)s associated with the same object as the given proxy.
+ *
+ * \\param proxy The proxy to use. It will also be the QObject::parent()
+ * for this object.
+ */
+ %(name)s(%(dbus_proxy)s *proxy);
+""" % {'name' : name,
+ 'dbus_proxy' : self.dbus_proxy})
+
+ self.b("""
+%(name)s::%(name)s(%(dbus_proxy)s *proxy)
+ : Tp::AbstractInterface(proxy, staticInterfaceName())
+{
+}
+""" % {'name' : name,
+ 'dbus_proxy' : self.dbus_proxy})
+
+ # Main interface
+ mainiface = self.mainiface or 'Tp::AbstractInterface'
+
+ if mainiface != self.namespace + '::' + name:
+ self.h("""
+ /**
+ * Creates a %(name)s associated with the same object as the given proxy.
+ * Additionally, the created proxy will have the same parent as the given
+ * proxy.
+ *
+ * \\param mainInterface The proxy to use.
+ */
+ explicit %(name)s(const %(mainiface)s& mainInterface);
+
+ /**
+ * Creates a %(name)s associated with the same object as the given proxy.
+ * However, a different parent object can be specified.
+ *
+ * \\param mainInterface The proxy to use.
+ * \\param parent Passed to the parent class constructor.
+ */
+ %(name)s(const %(mainiface)s& mainInterface, QObject* parent);
+""" % {'name' : name,
+ 'mainiface' : mainiface})
+
+ self.b("""
+%(name)s::%(name)s(const %(mainiface)s& mainInterface)
+ : Tp::AbstractInterface(mainInterface.service(), mainInterface.path(), staticInterfaceName(), mainInterface.connection(), mainInterface.parent())
+{
+}
+
+%(name)s::%(name)s(const %(mainiface)s& mainInterface, QObject *parent)
+ : Tp::AbstractInterface(mainInterface.service(), mainInterface.path(), staticInterfaceName(), mainInterface.connection(), parent)
+{
+}
+""" % {'name' : name,
+ 'mainiface' : mainiface})
+
+ # Properties
+ has_props = False
+ for prop in get_by_path(iface, 'property'):
+ # Skip tp:properties
+ if not prop.namespaceURI:
+ self.do_prop(prop)
+ has_props = True
+
+ self.h("""
+ /**
+ * Request all of the DBus properties on the interface.
+ *
+ * \\return A pending variant map which will emit finished when the properties have
+ * been retrieved.
+ */
+ Tp::PendingVariantMap *requestAllProperties() const
+ {
+ return internalRequestAllProperties();
+ }
+""")
+
+ # Methods
+ methods = get_by_path(iface, 'method')
+
+ if methods:
+ self.h("""
+public Q_SLOTS:\
+""")
+
+ for method in methods:
+ self.do_method(method)
+
+ # Signals
+ signals = get_by_path(iface, 'signal')
+
+ if signals:
+ self.h("""
+Q_SIGNALS:\
+""")
+
+ for signal in signals:
+ self.do_signal(signal)
+
+ # invalidated handler (already a slot in the superclass)
+ # we can't just use disconnect(this, NULL, NULL, NULL) because
+ # (a) that would disconnect QObject::destroyed() and other non-D-Bus
+ # signals, and (b) QtDBus doesn't support that usage anyway (it needs
+ # specific signals in order to remove its signal match rules)
+ self.h("""
+protected:
+ virtual void invalidate(Tp::DBusProxy *, const QString &, const QString &);
+""")
+
+ self.b("""
+void %(name)s::invalidate(Tp::DBusProxy *proxy,
+ const QString &error, const QString &message)
+{
+""" % {'name' : name})
+
+ for signal in signals:
+ self.do_signal_disconnect(signal)
+
+ self.b("""
+ Tp::AbstractInterface::invalidate(proxy, error, message);
+}
+""")
+
+ # Close class
+ self.h("""\
+};
+""")
+
+ def do_prop(self, prop):
+ name = prop.getAttribute('name')
+ access = prop.getAttribute('access')
+ gettername = name
+ settername = None
+ docstring = format_docstring(prop, self.refs, ' * ').replace('*/', '&#42;&#47;')
+
+ sig = prop.getAttribute('type')
+ tptype = prop.getAttributeNS(NS_TP, 'type')
+ binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace)
+
+ if 'write' in access:
+ settername = 'set' + name
+
+ if 'read' in access:
+ self.h("""
+ /**
+ * Asynchronous getter for the remote object property \\c %(name)s of type \\c %(val)s.
+ *
+%(docstring)s\
+ *
+ * \\return A pending variant which will emit finished when the property has been
+ * retrieved.
+ */
+ inline Tp::PendingVariant *%(gettername)s() const
+ {
+ return internalRequestProperty(QLatin1String("%(name)s"));
+ }
+""" % {'name' : name,
+ 'docstring' : docstring,
+ 'val' : binding.val,
+ 'gettername' : 'requestProperty' + name})
+
+ if 'write' in access:
+ self.h("""
+ /**
+ * Asynchronous setter for the remote object property \\c %(name)s of type \\c %(type)s.
+ *
+%(docstring)s\
+ *
+ * \\return A pending operation which will emit finished when the property has been
+ * set.
+ */
+ inline Tp::PendingOperation *%(settername)s(%(type)s newValue)
+ {
+ return internalSetProperty(QLatin1String("%(name)s"), QVariant::fromValue(newValue));
+ }
+""" % {'name' : name,
+ 'docstring' : docstring,
+ 'type' : binding.val,
+ 'name' : name,
+ 'settername' : 'setProperty' + name})
+
+ def do_method(self, method):
+ name = method.getAttribute('name')
+ args = get_by_path(method, 'arg')
+ argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists,
+ self.externals, self.typesnamespace, self.refs, ' * ')
+
+ inargs = []
+ outargs = []
+
+ for i in xrange(len(args)):
+ if args[i].getAttribute('direction') == 'out':
+ outargs.append(i)
+ else:
+ inargs.append(i)
+ assert argnames[i] != None, 'No argument name for input argument at index %d for method %s' % (i, name)
+
+ rettypes = ', '.join([argbindings[i].val for i in outargs])
+ params = ', '.join([argbindings[i].inarg + ' ' + argnames[i] for i in inargs])
+ if params:
+ params += ', int timeout = -1'
+ else:
+ params = 'int timeout = -1'
+
+ self.h("""
+ /**
+ * Begins a call to the D-Bus method \\c %s on the remote object.
+%s\
+ *
+ * Note that \\a timeout is ignored as of now. It will be used once
+ * http://bugreports.qt.nokia.com/browse/QTBUG-11775 is fixed.
+ *
+""" % (name, format_docstring(method, self.refs, ' * ')))
+
+ for i in inargs:
+ if argdocstrings[i]:
+ self.h("""\
+ *
+ * \\param %s
+%s\
+""" % (argnames[i], argdocstrings[i]))
+
+ self.h("""\
+ * \\param timeout The timeout in milliseconds.
+""")
+
+ for i in outargs:
+ if argdocstrings[i]:
+ self.h("""\
+ *
+ * \\return
+%s\
+""" % argdocstrings[i])
+
+ self.h("""\
+ */
+ inline QDBusPendingReply<%(rettypes)s> %(name)s(%(params)s)
+ {
+ if (!invalidationReason().isEmpty()) {
+ return QDBusPendingReply<%(rettypes)s>(QDBusMessage::createError(
+ invalidationReason(),
+ invalidationMessage()
+ ));
+ }
+""" % {'rettypes' : rettypes,
+ 'name' : name,
+ 'params' : params})
+
+ if inargs:
+ self.h("""
+ QDBusMessage callMessage = QDBusMessage::createMethodCall(this->service(), this->path(),
+ this->staticInterfaceName(), QLatin1String("%s"));
+ callMessage << %s;
+ return this->connection().asyncCall(callMessage, timeout);
+ }
+""" % (name, ' << '.join(['QVariant::fromValue(%s)' % argnames[i] for i in inargs])))
+ else:
+ self.h("""
+ QDBusMessage callMessage = QDBusMessage::createMethodCall(this->service(), this->path(),
+ this->staticInterfaceName(), QLatin1String("%s"));
+ return this->connection().asyncCall(callMessage, timeout);
+ }
+""" % name)
+
+ def do_signal(self, signal):
+ name = signal.getAttribute('name')
+ argnames, argdocstrings, argbindings = extract_arg_or_member_info(get_by_path(signal,
+ 'arg'), self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ')
+
+ self.h("""
+ /**
+ * Represents the signal \\c %s on the remote object.
+%s\
+""" % (name, format_docstring(signal, self.refs, ' * ')))
+
+ for i in xrange(len(argnames)):
+ assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
+ if argdocstrings[i]:
+ self.h("""\
+ *
+ * \\param %s
+%s\
+""" % (argnames[i], argdocstrings[i]))
+
+ self.h("""\
+ */
+ void %s(%s);
+""" % (name, ', '.join(['%s %s' % (binding.inarg, name) for binding, name in zip(argbindings, argnames)])))
+
+ def do_signal_disconnect(self, signal):
+ name = signal.getAttribute('name')
+ _, _, argbindings = extract_arg_or_member_info(get_by_path(signal, 'arg'),
+ self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ')
+
+ self.b("""\
+ disconnect(this, SIGNAL(%s(%s)), NULL, NULL);
+""" % (name, ', '.join([binding.inarg for binding in argbindings])))
+
+ def h(self, str):
+ self.hs.append(str)
+
+ def b(self, str):
+ self.bs.append(str)
+
+ def hb(self, str):
+ self.h(str)
+ self.b(str)
+
+
+if __name__ == '__main__':
+ options, argv = gnu_getopt(argv[1:], '',
+ ['group=',
+ 'namespace=',
+ 'typesnamespace=',
+ 'headerfile=',
+ 'implfile=',
+ 'ifacexml=',
+ 'specxml=',
+ 'realinclude=',
+ 'prettyinclude=',
+ 'extraincludes=',
+ 'mainiface=',
+ 'must-define=',
+ 'dbus-proxy=',
+ 'visibility='])
+
+ Generator(dict(options))()
diff --git a/qt4/tools/qt4-constants-gen.py b/qt4/tools/qt4-constants-gen.py
new file mode 100644
index 000000000..a28050a7a
--- /dev/null
+++ b/qt4/tools/qt4-constants-gen.py
@@ -0,0 +1,310 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2008 Collabora Limited <http://www.collabora.co.uk>
+# Copyright (C) 2008 Nokia Corporation
+#
+# 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 sys import argv, stdout, stderr
+import codecs
+import xml.dom.minidom
+from getopt import gnu_getopt
+
+from libtpcodegen import NS_TP, get_descendant_text, get_by_path
+from libqt4codegen import format_docstring, RefRegistry
+
+class Generator(object):
+ def __init__(self, opts):
+ try:
+ self.namespace = opts['--namespace']
+ self.must_define = opts.get('--must-define', None)
+ dom = xml.dom.minidom.parse(opts['--specxml'])
+ except KeyError, k:
+ assert False, 'Missing required parameter %s' % k.args[0]
+
+ self.define_prefix = None
+ if '--define-prefix' in opts:
+ self.define_prefix = opts['--define-prefix']
+
+ self.old_prefix = None
+ if '--str-constant-prefix' in opts:
+ self.old_prefix = opts['--str-constant-prefix']
+
+ self.spec = get_by_path(dom, "spec")[0]
+ self.out = codecs.getwriter('utf-8')(stdout)
+ self.refs = RefRegistry(self.spec)
+
+ def h(self, code):
+ self.out.write(code)
+
+ def __call__(self):
+ # Header
+ self.h('/* Generated from ')
+ self.h(get_descendant_text(get_by_path(self.spec, 'title')))
+ version = get_by_path(self.spec, "version")
+
+ if version:
+ self.h(', version ' + get_descendant_text(version))
+
+ self.h("""
+ */
+ """)
+
+ if self.must_define:
+ self.h("""
+#ifndef %s
+#error %s
+#endif
+""" % (self.must_define, self.must_define))
+
+ self.h("""
+#include <QFlags>
+
+/**
+ * \\addtogroup typesconstants Types and constants
+ *
+ * Enumerated, flag, structure, list and mapping types and utility constants.
+ */
+
+/**
+ * \\defgroup flagtypeconsts Flag type constants
+ * \\ingroup typesconstants
+ *
+ * Types generated from the specification representing bit flag constants and
+ * combinations of them (bitfields).
+ */
+
+/**
+ * \\defgroup enumtypeconsts Enumerated type constants
+ * \\ingroup typesconstants
+ *
+ * Types generated from the specification representing enumerated types ie.
+ * types the values of which are mutually exclusive integral constants.
+ */
+
+/**
+ * \\defgroup ifacestrconsts Interface string constants
+ * \\ingroup typesconstants
+ *
+ * D-Bus interface names of the interfaces in the specification.
+ */
+
+/**
+ * \\defgroup errorstrconsts Error string constants
+ * \\ingroup typesconstants
+ *
+ * Names of the D-Bus errors in the specification.
+ */
+""")
+
+ # Begin namespace
+ self.h("""
+namespace %s
+{
+""" % self.namespace)
+
+ # Flags
+ for flags in self.spec.getElementsByTagNameNS(NS_TP, 'flags'):
+ self.do_flags(flags)
+
+ # Enums
+ for enum in self.spec.getElementsByTagNameNS(NS_TP, 'enum'):
+ self.do_enum(enum)
+
+ # End namespace
+ self.h("""\
+}
+
+""")
+
+ # Interface names
+ for iface in self.spec.getElementsByTagName('interface'):
+ if self.old_prefix:
+ self.h("""\
+/**
+ * \\ingroup ifacestrconsts
+ *
+ * The interface name "%(name)s".
+ */
+#define %(DEFINE)s "%(name)s"
+
+""" % {'name' : iface.getAttribute('name'),
+ 'DEFINE' : self.old_prefix + 'INTERFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')})
+
+ if self.define_prefix:
+ self.h("""\
+/**
+ * \\ingroup ifacestrconsts
+ *
+ * The interface name "%(name)s" as a QLatin1String, usable in QString requiring contexts even when
+ * building with Q_NO_CAST_FROM_ASCII defined.
+ */
+#define %(DEFINE)s (QLatin1String("%(name)s"))
+
+""" % {'name' : iface.getAttribute('name'),
+ 'DEFINE' : self.define_prefix + 'IFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')})
+
+ # Error names
+ for error in get_by_path(self.spec, 'errors/error'):
+ name = error.getAttribute('name')
+ fullname = get_by_path(error, '../@namespace') + '.' + name.replace(' ', '')
+
+ if self.old_prefix:
+ define = self.old_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper()
+ self.h("""\
+/**
+ * \\ingroup errorstrconsts
+ *
+ * The error name "%(fullname)s".
+%(docstring)s\
+ */
+#define %(DEFINE)s "%(fullname)s"
+
+""" % {'fullname' : fullname,
+ 'docstring': format_docstring(error, self.refs),
+ 'DEFINE' : define})
+
+ if self.define_prefix:
+ define = self.define_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper()
+ self.h("""\
+/**
+ * \\ingroup errorstrconsts
+ *
+ * The error name "%(fullname)s" as a QLatin1String, usable in QString requiring contexts even when
+ * building with Q_NO_CAST_FROM_ASCII defined.
+%(docstring)s\
+ */
+#define %(DEFINE)s QLatin1String("%(fullname)s")
+
+""" % {'fullname' : fullname,
+ 'docstring': format_docstring(error, self.refs),
+ 'DEFINE' : define})
+
+ def do_flags(self, flags):
+ singular = flags.getAttribute('singular') or \
+ flags.getAttribute('value-prefix')
+
+ using_name = False
+ if not singular:
+ using_name = True
+ singular = flags.getAttribute('name')
+
+ if singular.endswith('lags'):
+ singular = singular[:-1]
+
+ if using_name and singular.endswith('s'):
+ singular = singular[:-1]
+
+ singular = singular.replace('_', '')
+ plural = (flags.getAttribute('plural') or flags.getAttribute('name') or singular + 's').replace('_', '')
+ self.h("""\
+/**
+ * \\ingroup flagtypeconsts
+ *
+ * Flag type generated from the specification.
+ */
+enum %(singular)s
+{
+""" % {'singular' : singular})
+
+ flagvalues = get_by_path(flags, 'flag')
+
+ for flag in flagvalues:
+ self.do_val(flag, singular, flag == flagvalues[-1])
+
+ self.h("""\
+ %s = 0xffffffffU
+""" % ("_" + singular + "Padding"))
+
+ self.h("""\
+};
+
+/**
+ * \\typedef QFlags<%(singular)s> %(plural)s
+ * \\ingroup flagtypeconsts
+ *
+ * Type representing combinations of #%(singular)s values.
+%(docstring)s\
+ */
+typedef QFlags<%(singular)s> %(plural)s;
+Q_DECLARE_OPERATORS_FOR_FLAGS(%(plural)s)
+
+""" % {'singular' : singular, 'plural' : plural, 'docstring' : format_docstring(flags, self.refs)})
+
+ def do_enum(self, enum):
+ singular = enum.getAttribute('singular') or \
+ enum.getAttribute('name')
+ value_prefix = enum.getAttribute('singular') or \
+ enum.getAttribute('value-prefix') or \
+ enum.getAttribute('name')
+
+ if singular.endswith('lags'):
+ singular = singular[:-1]
+
+ plural = enum.getAttribute('plural') or singular + 's'
+ singular = singular.replace('_', '')
+ value_prefix = value_prefix.replace('_', '')
+ vals = get_by_path(enum, 'enumvalue')
+
+ self.h("""\
+/**
+ * \\enum %(singular)s
+ * \\ingroup enumtypeconsts
+ *
+ * Enumerated type generated from the specification.
+%(docstring)s\
+ */
+enum %(singular)s
+{
+""" % {'singular' : singular, 'docstring' : format_docstring(enum, self.refs)})
+
+ for val in vals:
+ self.do_val(val, value_prefix, val == vals[-1])
+
+ self.h("""\
+ %s = 0xffffffffU
+};
+
+""" % ("_" + singular + "Padding"))
+
+ self.h("""\
+/**
+ * \\ingroup enumtypeconsts
+ *
+ * 1 higher than the highest valid value of %(singular)s.
+ */
+const int NUM_%(upper-plural)s = (%(last-val)s+1);
+
+""" % {'singular' : singular,
+ 'upper-plural' : plural.upper(),
+ 'last-val' : vals[-1].getAttribute('value')})
+
+ def do_val(self, val, prefix, last):
+ name = (val.getAttribute('suffix') or val.getAttribute('name')).replace('_', '')
+ self.h("""\
+%s\
+ %s = %s,
+
+""" % (format_docstring(val, self.refs, indent=' * ', brackets=(' /**', ' */')), prefix + name, val.getAttribute('value')))
+
+if __name__ == '__main__':
+ options, argv = gnu_getopt(argv[1:], '',
+ ['namespace=',
+ 'str-constant-prefix=',
+ 'define-prefix=',
+ 'must-define=',
+ 'specxml='])
+
+ Generator(dict(options))()
diff --git a/qt4/tools/qt4-types-gen.py b/qt4/tools/qt4-types-gen.py
new file mode 100644
index 000000000..0f5545d60
--- /dev/null
+++ b/qt4/tools/qt4-types-gen.py
@@ -0,0 +1,557 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2008 Collabora Limited <http://www.collabora.co.uk>
+# Copyright (C) 2008 Nokia Corporation
+#
+# 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 getopt import gnu_getopt
+
+from libtpcodegen import NS_TP, get_descendant_text, get_by_path
+from libqt4codegen import binding_from_usage, binding_from_decl, extract_arg_or_member_info, format_docstring, gather_externals, gather_custom_lists, get_qt4_name, get_headerfile_cmd, RefRegistry
+
+class BrokenSpecException(Exception):
+ pass
+
+class MissingTypes(BrokenSpecException):
+ def __init__(self, types):
+ super(MissingTypes, self).__init__(self)
+ self.types = types
+
+ def __str__(self):
+ typelist = ''.join([' %s' % t for t in self.types])
+ return "The following types were used, but not provided by the spec " \
+ "or by <tp:external-type/> declarations in all.xml:\n%s" % typelist
+
+class UnresolvedDependency(BrokenSpecException):
+ def __init__(self, child, parent):
+ super(UnresolvedDependency, self).__init__(self)
+ self.child = child
+ self.parent = parent
+
+ def __str__(self):
+ return 'Type %s has unresolved dependency on %s' % (
+ self.child, self.parent)
+
+class EmptyStruct(BrokenSpecException):
+ def __init__(self, struct_name):
+ super(EmptyStruct, self).__init__(self)
+ self.struct_name = struct_name
+
+ def __str__(self):
+ return 'tp:struct %s should have some members' % self.struct_name
+
+class MalformedMapping(BrokenSpecException):
+ def __init__(self, mapping_name, members):
+ super(MalformedMapping, self).__init__(self)
+ self.mapping_name = mapping_name
+ self.members = members
+
+ def __str__(self):
+ return 'tp:mapping %s should have 2 members, not %u' % (
+ self.mapping_name, self.members)
+
+class WTF(BrokenSpecException):
+ def __init__(self, element_name):
+ super(BrokenSpecException, self).__init__(self)
+ self.element_name = element_name
+
+ def __str__(self):
+ return 'What the hell is a tp:%s?' % self.element_name
+
+
+class DepInfo:
+ def __init__(self, el, externals, custom_lists):
+ self.el = el
+ name = get_by_path(el, '@name')
+ array_name = get_by_path(el, '@array-name')
+ array_depth = get_by_path(el, '@array-depth')
+ if array_depth:
+ array_depth = int(array_depth)
+ else:
+ array_depth = None
+ self.binding = binding_from_decl(name, array_name, array_depth)
+ self.deps = []
+
+ for member in get_by_path(el, 'member'):
+ sig = member.getAttribute('type')
+ tptype = member.getAttributeNS(NS_TP, 'type')
+
+ if (sig, tptype) in externals:
+ continue
+
+ if tptype.endswith('[]'):
+ tptype = tptype[:-2]
+
+ binding = binding_from_usage(sig, tptype, custom_lists)
+
+ if binding.custom_type:
+ self.deps.append(binding.val)
+
+ self.revdeps = []
+
+class Generator(object):
+ def __init__(self, opts):
+ try:
+ self.namespace = opts['--namespace']
+ self.declfile = opts['--declfile']
+ self.implfile = opts['--implfile']
+ self.realinclude = opts['--realinclude']
+ self.prettyinclude = opts.get('--prettyinclude', self.realinclude)
+ self.extraincludes = opts.get('--extraincludes', None)
+ self.must_define = opts.get('--must-define', None)
+ self.visibility = opts.get('--visibility', '')
+ dom = xml.dom.minidom.parse(opts['--specxml'])
+ except KeyError, k:
+ assert False, 'Missing required parameter %s' % k.args[0]
+
+ self.decls = []
+ self.impls = []
+ self.spec = get_by_path(dom, "spec")[0]
+ self.externals = gather_externals(self.spec)
+ self.custom_lists = gather_custom_lists(self.spec, self.namespace)
+ self.required_custom = []
+ self.required_arrays = []
+ self.to_declare = []
+ self.depinfos = {}
+ self.refs = RefRegistry(self.spec)
+
+ def __call__(self):
+ # Emit comment header
+
+ self.both('/* Generated from ')
+ self.both(get_descendant_text(get_by_path(self.spec, 'title')))
+ version = get_by_path(self.spec, "version")
+
+ if version:
+ self.both(', version ' + get_descendant_text(version))
+
+ self.both(' */\n')
+
+ # Gather info on available and required types
+
+ self.gather_required()
+
+ if self.must_define:
+ self.decl('\n')
+ self.decl('#ifndef %s\n' % self.must_define)
+ self.decl('#error %s\n' % self.must_define)
+ self.decl('#endif')
+
+ self.decl('\n')
+
+ if self.extraincludes:
+ for include in self.extraincludes.split(','):
+ self.decl('#include %s\n' % include)
+
+ self.decl("""
+#include <QtGlobal>
+
+#include <QByteArray>
+#include <QString>
+#include <QStringList>
+#include <QVariantList>
+#include <QVariantMap>
+
+#include <QDBusArgument>
+#include <QDBusMetaType>
+#include <QDBusObjectPath>
+#include <QDBusSignature>
+#include <QDBusVariant>
+
+#include <TelepathyQt4/Global>
+
+/**
+ * \\addtogroup typesconstants Types and constants
+ *
+ * Enumerated, flag, structure, list and mapping types and utility constants.
+ */
+
+/**
+ * \\defgroup struct Structure types
+ * \\ingroup typesconstants
+ *
+ * Structure types generated from the specification.
+ */
+
+/**
+ * \\defgroup list List types
+ * \\ingroup typesconstants
+ *
+ * List types generated from the specification.
+ */
+
+/**
+ * \\defgroup mapping Mapping types
+ * \\ingroup typesconstants
+ *
+ * Mapping types generated from the specification.
+ */
+
+""")
+
+ if self.must_define:
+ self.impl("""
+#define %s""" % self.must_define)
+
+ self.impl("""
+#include "%s"
+""" % self.realinclude)
+
+ self.both("""
+namespace %s
+{
+""" % self.namespace)
+
+ # Emit type definitions for types provided in the spec
+
+ self.provide_all()
+
+ # Emit type registration function
+
+ self.decl("""
+} // namespace %s
+
+""" % self.namespace)
+
+ self.impl("""\
+TELEPATHY_QT4_NO_EXPORT void _registerTypes()
+{
+ static bool registered = false;
+ if (registered)
+ return;
+ registered = true;
+
+""")
+
+ # Emit Qt4 metatype declarations
+
+ self.to_declare.sort()
+
+ for metatype in self.to_declare:
+ self.decl('Q_DECLARE_METATYPE(%s)\n' % metatype)
+ self.impl(' qDBusRegisterMetaType<%s>();\n' % ((metatype.endswith('>') and metatype + ' ') or metatype))
+
+ self.impl("""\
+}
+
+} // namespace %s
+""" % self.namespace)
+
+ # Write output to files
+
+ open(self.declfile, 'w').write(''.join(self.decls).encode("utf-8"))
+ open(self.implfile, 'w').write(''.join(self.impls).encode("utf-8"))
+
+ def decl(self, str):
+ self.decls.append(str)
+
+ def impl(self, str):
+ self.impls.append(str)
+
+ def both(self, str):
+ self.decl(str)
+ self.impl(str)
+
+ def gather_required(self):
+ members = self.spec.getElementsByTagNameNS(NS_TP, 'member')
+ args = self.spec.getElementsByTagName('arg')
+ props = self.spec.getElementsByTagName('property')
+ tp_props = self.spec.getElementsByTagNameNS(NS_TP, 'property')
+
+ for requirer in members + args + props + tp_props:
+ sig = requirer.getAttribute('type')
+ tptype = requirer.getAttributeNS(NS_TP, 'type')
+ external = (sig, tptype) in self.externals
+ binding = binding_from_usage(sig, tptype, self.custom_lists, external)
+
+ if binding.custom_type and binding.val not in self.required_custom:
+ self.required_custom.append(binding.val)
+
+ if not binding.custom_type and binding.array_of and (binding.val, binding.array_of) not in self.required_arrays:
+ self.required_arrays.append((binding.val, binding.array_of))
+
+ def provide_all(self):
+ self.required_arrays.sort()
+ for (val, array_of) in self.required_arrays:
+ real = 'QList<%s>' % array_of
+ self.decl("""\
+/**
+ * \\struct %s
+ * \\ingroup list
+%s\
+ *
+ * Generic list type with %s elements. Convertible with
+ * %s, but needed to have a discrete type in the Qt4 type system.
+ */
+""" % (val, get_headerfile_cmd(self.realinclude, self.prettyinclude), array_of, real))
+ self.decl(self.faketype(val, real))
+ self.to_declare.append(self.namespace + '::' + val)
+
+ structs = self.spec.getElementsByTagNameNS(NS_TP, 'struct')
+ mappings = self.spec.getElementsByTagNameNS(NS_TP, 'mapping')
+ exts = self.spec.getElementsByTagNameNS(NS_TP, 'external-type')
+
+ for deptype in structs + mappings:
+ info = DepInfo(deptype, self.externals, self.custom_lists)
+ self.depinfos[info.binding.val] = info
+
+ leaves = []
+ next_leaves = []
+
+ for val, depinfo in self.depinfos.iteritems():
+ leaf = True
+
+ for dep in depinfo.deps:
+ if not self.depinfos.has_key(dep):
+ raise UnresolvedDependency(val, dep)
+
+ leaf = False
+ self.depinfos[dep].revdeps.append(val)
+
+ if leaf:
+ next_leaves.append(val)
+
+ while leaves or next_leaves:
+ if not leaves:
+ leaves = next_leaves
+ leaves.sort()
+ next_leaves = []
+
+ val = leaves.pop(0)
+ depinfo = self.depinfos[val]
+ self.output_by_depinfo(depinfo)
+
+ for revdep in depinfo.revdeps:
+ revdepinfo = self.depinfos[revdep]
+ revdepinfo.deps.remove(val)
+
+ if not revdepinfo.deps:
+ next_leaves.append(revdep)
+
+ del self.depinfos[val]
+
+ for provider in structs + mappings + exts:
+ name = get_by_path(provider, '@name')
+ array_name = get_by_path(provider, '@array-name')
+ array_depth = get_by_path(provider, '@array-depth')
+ if array_depth:
+ array_depth = int(array_depth)
+ else:
+ array_depth = None
+ sig = provider.getAttribute('type')
+ tptype = provider.getAttribute('name')
+ external = (sig, tptype) in self.externals
+ binding = binding_from_decl(name, array_name, array_depth, external)
+ self.provide(binding.val)
+
+ if binding.array_val:
+ self.provide(binding.array_val)
+
+ d = binding.array_depth
+ while d > 1:
+ d -= 1
+ self.provide(binding.array_val + ('List' * d))
+
+ if self.required_custom:
+ raise MissingTypes(self.required_custom)
+
+ def provide(self, type):
+ if type in self.required_custom:
+ self.required_custom.remove(type)
+
+ def output_by_depinfo(self, depinfo):
+ names, docstrings, bindings = extract_arg_or_member_info(get_by_path(depinfo.el, 'member'), self.custom_lists, self.externals, None, self.refs, ' * ', (' /**', ' */'))
+ members = len(names)
+
+ if depinfo.el.localName == 'struct':
+ if members == 0:
+ raise EmptyStruct(depinfo.binding.val)
+
+ self.decl("""\
+/**
+ * \\struct %(name)s
+ * \\ingroup struct
+%(headercmd)s\
+ *
+ * Structure type generated from the specification.
+%(docstring)s\
+ */
+struct %(visibility)s %(name)s
+{
+""" % {
+ 'name' : depinfo.binding.val,
+ 'headercmd': get_headerfile_cmd(self.realinclude, self.prettyinclude),
+ 'docstring' : format_docstring(depinfo.el, self.refs),
+ 'visibility': self.visibility,
+ })
+
+ for i in xrange(members):
+ self.decl("""\
+%s\
+ %s %s;
+""" % (docstrings[i], bindings[i].val, names[i]))
+
+ self.decl("""\
+};
+
+""")
+
+ self.both('%s bool operator==(%s v1, %s v2)' %
+ (self.visibility,
+ depinfo.binding.inarg,
+ depinfo.binding.inarg))
+ self.decl(';\n')
+ self.impl("""
+{""")
+ if (bindings[0].val != 'QDBusVariant'):
+ self.impl("""
+ return ((v1.%s == v2.%s)""" % (names[0], names[0]))
+ else:
+ self.impl("""
+ return ((v1.%s.variant() == v2.%s.variant())""" % (names[0], names[0]))
+ for i in xrange(1, members):
+ if (bindings[i].val != 'QDBusVariant'):
+ self.impl("""
+ && (v1.%s == v2.%s)""" % (names[i], names[i]))
+ else:
+ self.impl("""
+ && (v1.%s.variant() == v2.%s.variant())""" % (names[i], names[i]))
+ self.impl("""
+ );
+}
+
+""")
+
+ self.decl('inline bool operator!=(%s v1, %s v2)' %
+ (depinfo.binding.inarg, depinfo.binding.inarg))
+ self.decl("""
+{
+ return !operator==(v1, v2);
+}
+""")
+
+ self.both('%s QDBusArgument& operator<<(QDBusArgument& arg, %s val)' %
+ (self.visibility, depinfo.binding.inarg))
+ self.decl(';\n')
+ self.impl("""
+{
+ arg.beginStructure();
+ arg << %s;
+ arg.endStructure();
+ return arg;
+}
+
+""" % ' << '.join(['val.' + name for name in names]))
+
+ self.both('%s const QDBusArgument& operator>>(const QDBusArgument& arg, %s val)' %
+ (self.visibility, depinfo.binding.outarg))
+ self.decl(';\n\n')
+ self.impl("""
+{
+ arg.beginStructure();
+ arg >> %s;
+ arg.endStructure();
+ return arg;
+}
+
+""" % ' >> '.join(['val.' + name for name in names]))
+ elif depinfo.el.localName == 'mapping':
+ if members != 2:
+ raise MalformedMapping(depinfo.binding.val, members)
+
+ realtype = 'QMap<%s, %s>' % (bindings[0].val, (bindings[1].val.endswith('>') and bindings[1].val + ' ') or bindings[1].val)
+ self.decl("""\
+/**
+ * \\struct %s
+ * \\ingroup mapping
+%s\
+ *
+ * Mapping type generated from the specification. Convertible with
+ * %s, but needed to have a discrete type in the Qt4 type system.
+%s\
+ */
+""" % (depinfo.binding.val, get_headerfile_cmd(self.realinclude, self.prettyinclude), realtype, format_docstring(depinfo.el, self.refs)))
+ self.decl(self.faketype(depinfo.binding.val, realtype))
+ else:
+ raise WTF(depinfo.el.localName)
+
+ self.to_declare.append(self.namespace + '::' + depinfo.binding.val)
+
+ if depinfo.binding.array_val:
+ self.to_declare.append('%s::%s' % (self.namespace, depinfo.binding.array_val))
+ self.decl("""\
+/**
+ * \\ingroup list
+%s\
+ *
+ * Array of %s values.
+ */
+typedef %s %s;
+
+""" % (get_headerfile_cmd(self.realinclude, self.prettyinclude), depinfo.binding.val, 'QList<%s>' % depinfo.binding.val, depinfo.binding.array_val))
+
+ i = depinfo.binding.array_depth
+ while i > 1:
+ i -= 1
+ self.to_declare.append('%s::%s%s' % (self.namespace, depinfo.binding.array_val, ('List' * i)))
+ list_of = depinfo.binding.array_val + ('List' * (i-1))
+ self.decl("""\
+/**
+ * \\ingroup list
+%s\
+ *
+ * Array of %s values.
+ */
+typedef QList<%s> %sList;
+
+""" % (get_headerfile_cmd(self.realinclude, self.prettyinclude), list_of, list_of, list_of))
+
+ def faketype(self, fake, real):
+ return """\
+struct %(visibility)s %(fake)s : public %(real)s
+{
+ inline %(fake)s() : %(real)s() {}
+ inline %(fake)s(const %(real)s& a) : %(real)s(a) {}
+
+ inline %(fake)s& operator=(const %(real)s& a)
+ {
+ *(static_cast<%(real)s*>(this)) = a;
+ return *this;
+ }
+};
+
+""" % {'fake' : fake, 'real' : real, 'visibility': self.visibility}
+
+if __name__ == '__main__':
+ options, argv = gnu_getopt(sys.argv[1:], '',
+ ['declfile=',
+ 'implfile=',
+ 'realinclude=',
+ 'prettyinclude=',
+ 'extraincludes=',
+ 'must-define=',
+ 'namespace=',
+ 'specxml=',
+ 'visibility=',
+ ])
+
+ try:
+ Generator(dict(options))()
+ except BrokenSpecException as e:
+ print >> sys.stderr, 'Your spec is broken, dear developer! %s' % e
+ sys.exit(42)
diff --git a/qt4/tools/repeat-tests.sh b/qt4/tools/repeat-tests.sh
new file mode 100755
index 000000000..8da2f9ea8
--- /dev/null
+++ b/qt4/tools/repeat-tests.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+if [ $# -ne 2 ]
+then
+ echo "usage: $0 <command> <number of repetitions>"
+ echo "example: $0 \"make check-valgrind\" 100"
+ echo " or: $0 \"make -j4 check\" 100"
+ exit 1
+fi
+
+for i in `seq 1 $2`
+do
+ echo -n "Running test iteration ${i}... "
+ log="test-round-${i}.log"
+ $1 > ${log} 2>&1
+ if grep -q "FAIL" $log
+ then
+ echo "FAILED (log in $log)"
+ else
+ echo "PASSED"
+ rm ${log}
+ fi
+done
diff --git a/qt4/tools/telepathy-glib.supp b/qt4/tools/telepathy-glib.supp
new file mode 100644
index 000000000..28bd5a06a
--- /dev/null
+++ b/qt4/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/qt4/tools/tp-qt4-tests.supp b/qt4/tools/tp-qt4-tests.supp
new file mode 100644
index 000000000..2c0f12011
--- /dev/null
+++ b/qt4/tools/tp-qt4-tests.supp
@@ -0,0 +1,53 @@
+# QDBus doesn't call dbus_shutdown, so some D-Bus internal data structures are leaked.
+# We never call any low-level dbus message creation functions ourselves - if there are leaks,
+# they're either caused by not calling dbus_shutdown, QDBus bugs or libdbus bugs - neither of which
+# are our problem.
+
+{
+ Initial session bus registration message
+ Memcheck:Leak
+ fun:malloc
+ fun:dbus_message_new_empty_header
+}
+
+# The conference test CM channel object leaks some crazy GValue boxed data which I don't have the
+# energy to investigate how to properly free now - it's not production code anyway.
+
+{
+ Conference test CM channel boxed GValue data
+ Memcheck:Leak
+ ...
+ fun:g_boxed_copy
+ ...
+ fun:_ZN18TestConferenceChan12initTestCaseEv
+}
+
+# Reported as https://bugs.freedesktop.org/show_bug.cgi?id=32116
+
+{
+ TpBaseConnectionManager legacy protocol objects
+ Memcheck:Leak
+ ...
+ fun:g_object_new
+ ...
+ fun:tp_base_connection_manager_register
+}
+
+# O(number of error domains) leak from dbus_g_method_return_error
+{
+ dbus_g_method_return_error error domain enum class
+ Memcheck:Leak
+ ...
+ fun:g_type_class_ref
+ ...
+ fun:dbus_g_method_return_error
+}
+
+# O(1) leak from tp_base_connection_manager installing the param spec for the dbus-daemon param
+{
+ tp_base_connection_manager dbus-daemon param spec
+ Memcheck:Leak
+ ...
+ fun:g_param_spec_object
+ fun:tp_base_connection_manager_class_intern_init
+}
diff --git a/qt4/tools/with-session-bus.sh b/qt4/tools/with-session-bus.sh
new file mode 100644
index 000000000..063bd7e17
--- /dev/null
+++ b/qt4/tools/with-session-bus.sh
@@ -0,0 +1,94 @@
+#!/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
+ 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 2>&1 &
+fi
+
+"$@" || e=$?
+
+if test $sleep != 0; then
+ sleep $sleep
+fi
+
+trap - INT HUP TERM
+cleanup
+
+exit $e
diff --git a/qt4/tools/xincludator.py b/qt4/tools/xincludator.py
new file mode 100644
index 000000000..63e106ace
--- /dev/null
+++ b/qt4/tools/xincludator.py
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+
+from sys import argv, stdout, stderr
+import codecs, locale
+import os
+import xml.dom.minidom
+
+stdout = codecs.getwriter('utf-8')(stdout)
+
+NS_XI = 'http://www.w3.org/2001/XInclude'
+
+def xincludate(dom, base, dropns = []):
+ remove_attrs = []
+ for i in xrange(dom.documentElement.attributes.length):
+ attr = dom.documentElement.attributes.item(i)
+ if attr.prefix == 'xmlns':
+ if attr.localName in dropns:
+ remove_attrs.append(attr)
+ else:
+ dropns.append(attr.localName)
+ for attr in remove_attrs:
+ dom.documentElement.removeAttributeNode(attr)
+ for include in dom.getElementsByTagNameNS(NS_XI, 'include'):
+ href = include.getAttribute('href')
+ # FIXME: assumes Unixy paths
+ filename = os.path.join(os.path.dirname(base), href)
+ subdom = xml.dom.minidom.parse(filename)
+ xincludate(subdom, filename, dropns)
+ if './' in href:
+ subdom.documentElement.setAttribute('xml:base', href)
+ include.parentNode.replaceChild(subdom.documentElement, include)
+
+if __name__ == '__main__':
+ argv = argv[1:]
+ dom = xml.dom.minidom.parse(argv[0])
+ xincludate(dom, argv[0])
+ xml = dom.toxml()
+ stdout.write(xml)
+ stdout.write('\n')