Пример #1
0
    def do_signal_add(self, signal):
        marshaller_items = []
        gtypes = []

        for i in signal.getElementsByTagName('arg'):
            name = i.getAttribute('name')
            type = i.getAttribute('type')
            info = type_to_gtype(type)
            # type, GType, STRING, is a pointer
            gtypes.append(info[1])

        self.b('  dbus_g_proxy_add_signal (proxy, "%s",'
               % signal.getAttribute('name'))
        for gtype in gtypes:
            self.b('      %s,' % gtype)
        self.b('      G_TYPE_INVALID);')
Пример #2
0
    def do_signal_add(self, signal):
        marshaller_items = []
        gtypes = []

        for i in signal.getElementsByTagName('arg'):
            name = i.getAttribute('name')
            type = i.getAttribute('type')
            info = type_to_gtype(type)
            # type, GType, STRING, is a pointer
            gtypes.append(info[1])

        self.b('  dbus_g_proxy_add_signal (proxy, "%s",' %
               signal.getAttribute('name'))
        for gtype in gtypes:
            self.b('      %s,' % gtype)
        self.b('      G_TYPE_INVALID);')
Пример #3
0
def types_to_gtypes(types):
    return [type_to_gtype(t)[1] for t in types]
Пример #4
0
    def do_signal(self, iface, signal):
        iface_lc = iface.lower()

        member = signal.getAttribute('name')
        member_lc = camelcase_to_lower(member)
        member_uc = member_lc.upper()

        arg_count = 0
        args = []
        out_args = []

        for arg in signal.getElementsByTagName('arg'):
            name = arg.getAttribute('name')
            type = arg.getAttribute('type')
            tp_type = arg.getAttribute('tp:type')

            if not name:
                name = 'arg%u' % arg_count
                arg_count += 1
            else:
                name = 'arg_%s' % name

            info = type_to_gtype(type)
            args.append((name, info, tp_type, arg))

        callback_name = ('%s_%s_signal_callback_%s' %
                         (self.prefix_lc, iface_lc, member_lc))
        collect_name = ('_%s_%s_collect_args_of_%s' %
                        (self.prefix_lc, iface_lc, member_lc))
        invoke_name = ('_%s_%s_invoke_callback_for_%s' %
                       (self.prefix_lc, iface_lc, member_lc))

        # Example:
        #
        # typedef void (*tp_cli_connection_signal_callback_new_channel)
        #   (TpConnection *proxy, const gchar *arg_object_path,
        #   const gchar *arg_channel_type, guint arg_handle_type,
        #   guint arg_handle, gboolean arg_suppress_handler,
        #   gpointer user_data, GObject *weak_object);

        self.b('/**')
        self.b(' * %s:' % callback_name)
        self.b(' * @proxy: The proxy on which %s_%s_connect_to_%s ()' %
               (self.prefix_lc, iface_lc, member_lc))
        self.b(' *  was called')

        for arg in args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b(' * @%s: %s' %
                   (name, xml_escape(get_docstring(elt) or '(Undocumented)')))

        self.b(' * @user_data: User-supplied data')
        self.b(' * @weak_object: User-supplied weakly referenced object')
        self.b(' *')
        self.b(' * Represents the signature of a callback for the signal %s.' %
               member)
        self.b(' */')
        self.h('typedef void (*%s) (%sproxy,' %
               (callback_name, self.proxy_cls))

        for arg in args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))

        self.h('    gpointer user_data, GObject *weak_object);')

        if args:
            self.b('static void')
            self.b('%s (DBusGProxy *proxy,' % collect_name)

            for arg in args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                const = pointer and 'const ' or ''

                self.b('    %s%s%s,' % (const, ctype, name))

            self.b('    TpProxySignalConnection *sc)')
            self.b('{')
            self.b('  GValueArray *args = g_value_array_new (%d);' % len(args))
            self.b('  GValue blank = { 0 };')
            self.b('  guint i;')
            self.b('')
            self.b('  g_value_init (&blank, G_TYPE_INT);')
            self.b('')
            self.b('  for (i = 0; i < %d; i++)' % len(args))
            self.b('    g_value_array_append (args, &blank);')
            self.b('')

            for i, arg in enumerate(args):
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                self.b('  g_value_unset (args->values + %d);' % i)
                self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))

                if gtype == 'G_TYPE_STRING':
                    self.b('  g_value_set_string (args->values + %d, %s);' %
                           (i, name))
                elif marshaller == 'BOXED':
                    self.b('  g_value_set_boxed (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_UCHAR':
                    self.b('  g_value_set_uchar (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_BOOLEAN':
                    self.b('  g_value_set_boolean (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_INT':
                    self.b('  g_value_set_int (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_UINT':
                    self.b('  g_value_set_uint (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_INT64':
                    self.b('  g_value_set_int (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_UINT64':
                    self.b('  g_value_set_uint (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_DOUBLE':
                    self.b('  g_value_set_double (args->values + %d, %s);' %
                           (i, name))
                else:
                    assert False, ("Don't know how to put %s in a GValue" %
                                   gtype)
                self.b('')

            self.b('  tp_proxy_signal_connection_v0_take_results (sc, args);')
            self.b('}')

        self.b('static void')
        self.b('%s (TpProxy *tpproxy,' % invoke_name)
        self.b('    GError *error,')
        self.b('    GValueArray *args,')
        self.b('    GCallback generic_callback,')
        self.b('    gpointer user_data,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  %s callback =' % callback_name)
        self.b('      (%s) generic_callback;' % callback_name)
        self.b('')
        self.b('  if (callback != NULL)')
        self.b('    callback (g_object_ref (tpproxy),')

        # FIXME: factor out into a function
        for i, arg in enumerate(args):
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED':
                self.b('      g_value_get_boxed (args->values + %d),' % i)
            elif gtype == 'G_TYPE_STRING':
                self.b('      g_value_get_string (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UCHAR':
                self.b('      g_value_get_uchar (args->values + %d),' % i)
            elif gtype == 'G_TYPE_BOOLEAN':
                self.b('      g_value_get_boolean (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT':
                self.b('      g_value_get_uint (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT':
                self.b('      g_value_get_int (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT64':
                self.b('      g_value_get_uint64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT64':
                self.b('      g_value_get_int64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('      g_value_get_double (args->values + %d),' % i)
            else:
                assert False, "Don't know how to get %s from a GValue" % gtype

        self.b('      user_data,')
        self.b('      weak_object);')
        self.b('')

        if len(args) > 0:
            self.b('  g_value_array_free (args);')
        else:
            self.b('  if (args != NULL)')
            self.b('    g_value_array_free (args);')
            self.b('')

        self.b('  g_object_unref (tpproxy);')
        self.b('}')

        # Example:
        #
        # TpProxySignalConnection *
        #   tp_cli_connection_connect_to_new_channel
        #   (TpConnection *proxy,
        #   tp_cli_connection_signal_callback_new_channel callback,
        #   gpointer user_data,
        #   GDestroyNotify destroy);
        #
        # destroy is invoked when the signal becomes disconnected. This
        # is either because the signal has been disconnected explicitly
        # by the user, because the TpProxy has become invalid and
        # emitted the 'invalidated' signal, or because the weakly referenced
        # object has gone away.

        self.b('/**')
        self.b(' * %s_%s_connect_to_%s:' %
               (self.prefix_lc, iface_lc, member_lc))
        self.b(' * @proxy: %s' % self.proxy_doc)
        self.b(' * @callback: Callback to be called when the signal is')
        self.b(' *   received')
        self.b(' * @user_data: User-supplied data for the callback')
        self.b(' * @destroy: Destructor for the user-supplied data, which')
        self.b(' *   will be called when this signal is disconnected, or')
        self.b(' *   before this function returns %NULL')
        self.b(' * @weak_object: A #GObject which will be weakly referenced; ')
        self.b(' *   if it is destroyed, this callback will automatically be')
        self.b(' *   disconnected')
        self.b(' * @error: If not %NULL, used to raise an error if %NULL is')
        self.b(' *   returned')
        self.b(' *')
        self.b(' * Connect a handler to the signal %s.' % member)
        self.b(' *')
        self.b(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
        self.b(' *')
        self.b(' * Returns: a #TpProxySignalConnection containing all of the')
        self.b(' * above, which can be used to disconnect the signal; or')
        self.b(' * %NULL if the proxy does not have the desired interface')
        self.b(' * or has become invalid.')
        self.b(' */')
        self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,' %
               (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.h('    %s callback,' % callback_name)
        self.h('    gpointer user_data,')
        self.h('    GDestroyNotify destroy,')
        self.h('    GObject *weak_object,')
        self.h('    GError **error);')

        self.b('TpProxySignalConnection *')
        self.b('%s_%s_connect_to_%s (%sproxy,' %
               (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.b('    %s callback,' % callback_name)
        self.b('    gpointer user_data,')
        self.b('    GDestroyNotify destroy,')
        self.b('    GObject *weak_object,')
        self.b('    GError **error)')
        self.b('{')
        self.b('  GType expected_types[%d] = {' % (len(args) + 1))

        for arg in args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b('      %s,' % gtype)

        self.b('      G_TYPE_INVALID };')
        self.b('')
        self.b('  g_return_val_if_fail (%s (proxy), NULL);' %
               self.proxy_assert)
        self.b('  g_return_val_if_fail (callback != NULL, NULL);')
        self.b('')
        self.b(
            '  return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,')
        self.b('      %s, \"%s\",' % (self.get_iface_quark(), member))
        self.b('      expected_types,')

        if args:
            self.b('      G_CALLBACK (%s),' % collect_name)
        else:
            self.b('      NULL, /* no args => no collector function */')

        self.b('      %s,' % invoke_name)
        self.b('      G_CALLBACK (callback), user_data, destroy,')
        self.b('      weak_object, error);')
        self.b('}')
        self.b('')

        self.h('')
Пример #5
0
    def do_method(self, iface, method):
        iface_lc = iface.lower()

        member = method.getAttribute('name')
        member_lc = camelcase_to_lower(member)
        member_uc = member_lc.upper()

        in_count = 0
        ret_count = 0
        in_args = []
        out_args = []

        for arg in method.getElementsByTagName('arg'):
            name = arg.getAttribute('name')
            direction = arg.getAttribute('direction')
            type = arg.getAttribute('type')
            tp_type = arg.getAttribute('tp:type')

            if direction != 'out':
                if not name:
                    name = 'in%u' % in_count
                    in_count += 1
                else:
                    name = 'in_%s' % name
            else:
                if not name:
                    name = 'out%u' % ret_count
                    ret_count += 1
                else:
                    name = 'out_%s' % name

            info = type_to_gtype(type)
            if direction != 'out':
                in_args.append((name, info, tp_type, arg))
            else:
                out_args.append((name, info, tp_type, arg))

        # Async reply callback type

        # Example:
        # void (*tp_cli_properties_interface_callback_for_get_properties)
        #   (TpProxy *proxy,
        #       const GPtrArray *out0,
        #       const GError *error,
        #       gpointer user_data,
        #       GObject *weak_object);

        self.b('/**')
        self.b(' * %s_%s_callback_for_%s:' %
               (self.prefix_lc, iface_lc, member_lc))
        self.b(' * @proxy: the proxy on which the call was made')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b(' * @%s: Used to return an \'out\' argument if @error is '
                   '%%NULL: %s' %
                   (name, xml_escape(get_docstring(elt) or '(Undocumented)')))

        self.b(' * @error: %NULL on success, or an error on failure')
        self.b(' * @user_data: user-supplied data')
        self.b(' * @weak_object: user-supplied object')
        self.b(' *')
        self.b(' * Signature of the callback called when a %s method call' %
               member)
        self.b(' * succeeds or fails.')
        self.b(' */')

        callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
                                                   member_lc)

        self.h('typedef void (*%s) (%sproxy,' %
               (callback_name, self.proxy_cls))

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info
            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))

        self.h('    const GError *error, gpointer user_data,')
        self.h('    GObject *weak_object);')
        self.h('')

        # Async callback implementation

        invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
                                                         iface_lc, member_lc)

        collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
                                                           iface_lc, member_lc)

        # The callback called by dbus-glib; this ends the call and collects
        # the results into a GValueArray.
        self.b('static void')
        self.b('%s (DBusGProxy *proxy,' % collect_callback)
        self.b('    DBusGProxyCall *call,')
        self.b('    gpointer user_data)')
        self.b('{')
        self.b('  GError *error = NULL;')

        if len(out_args) > 0:
            self.b('  GValueArray *args;')
            self.b('  GValue blank = { 0 };')
            self.b('  guint i;')

            for arg in out_args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                # "We handle variants specially; the caller is expected to
                # have already allocated storage for them". Thanks,
                # dbus-glib...
                if gtype == 'G_TYPE_VALUE':
                    self.b('  GValue *%s = g_new0 (GValue, 1);' % name)
                else:
                    self.b('  %s%s;' % (ctype, name))

        self.b('')
        self.b('  dbus_g_proxy_end_call (proxy, call, &error,')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if gtype == 'G_TYPE_VALUE':
                self.b('      %s, %s,' % (gtype, name))
            else:
                self.b('      %s, &%s,' % (gtype, name))

        self.b('      G_TYPE_INVALID);')

        if len(out_args) == 0:
            self.b('  tp_proxy_pending_call_v0_take_results (user_data, error,'
                   'NULL);')
        else:
            self.b('')
            self.b('  if (error != NULL)')
            self.b('    {')
            self.b(
                '      tp_proxy_pending_call_v0_take_results (user_data, error,'
            )
            self.b('          NULL);')

            for arg in out_args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info
                if gtype == 'G_TYPE_VALUE':
                    self.b('      g_free (%s);' % name)

            self.b('      return;')
            self.b('    }')
            self.b('')
            self.b('  args = g_value_array_new (%d);' % len(out_args))
            self.b('  g_value_init (&blank, G_TYPE_INT);')
            self.b('')
            self.b('  for (i = 0; i < %d; i++)' % len(out_args))
            self.b('    g_value_array_append (args, &blank);')

            for i, arg in enumerate(out_args):
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                self.b('')
                self.b('  g_value_unset (args->values + %d);' % i)
                self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))

                if gtype == 'G_TYPE_STRING':
                    self.b('  g_value_take_string (args->values + %d, %s);' %
                           (i, name))
                elif marshaller == 'BOXED':
                    self.b('  g_value_take_boxed (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_UCHAR':
                    self.b('  g_value_set_uchar (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_BOOLEAN':
                    self.b('  g_value_set_boolean (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_INT':
                    self.b('  g_value_set_int (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_UINT':
                    self.b('  g_value_set_uint (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_INT64':
                    self.b('  g_value_set_int (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_UINT64':
                    self.b('  g_value_set_uint (args->values + %d, %s);' %
                           (i, name))
                elif gtype == 'G_TYPE_DOUBLE':
                    self.b('  g_value_set_double (args->values + %d, %s);' %
                           (i, name))
                else:
                    assert False, ("Don't know how to put %s in a GValue" %
                                   gtype)

            self.b('  tp_proxy_pending_call_v0_take_results (user_data, '
                   'NULL, args);')

        self.b('}')

        self.b('static void')
        self.b('%s (TpProxy *self,' % invoke_callback)
        self.b('    GError *error,')
        self.b('    GValueArray *args,')
        self.b('    GCallback generic_callback,')
        self.b('    gpointer user_data,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  %s callback = (%s) generic_callback;' %
               (callback_name, callback_name))
        self.b('')
        self.b('  if (error != NULL)')
        self.b('    {')
        self.b('      callback ((%s) self,' % self.proxy_cls)

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED' or pointer:
                self.b('          NULL,')
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('          0.0,')
            else:
                self.b('          0,')

        self.b('          error, user_data, weak_object);')
        self.b('      g_error_free (error);')
        self.b('      return;')
        self.b('    }')

        self.b('  callback ((%s) self,' % self.proxy_cls)

        # FIXME: factor out into a function
        for i, arg in enumerate(out_args):
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED':
                self.b('      g_value_get_boxed (args->values + %d),' % i)
            elif gtype == 'G_TYPE_STRING':
                self.b('      g_value_get_string (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UCHAR':
                self.b('      g_value_get_uchar (args->values + %d),' % i)
            elif gtype == 'G_TYPE_BOOLEAN':
                self.b('      g_value_get_boolean (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT':
                self.b('      g_value_get_uint (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT':
                self.b('      g_value_get_int (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT64':
                self.b('      g_value_get_uint64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT64':
                self.b('      g_value_get_int64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('      g_value_get_double (args->values + %d),' % i)
            else:
                assert False, "Don't know how to get %s from a GValue" % gtype

        self.b('      error, user_data, weak_object);')
        self.b('')

        if len(out_args) > 0:
            self.b('  g_value_array_free (args);')
        else:
            self.b('  if (args != NULL)')
            self.b('    g_value_array_free (args);')

        self.b('}')
        self.b('')

        # Async stub

        # Example:
        # TpProxyPendingCall *
        #   tp_cli_properties_interface_call_get_properties
        #   (gpointer proxy,
        #   gint timeout_ms,
        #   const GArray *in_properties,
        #   tp_cli_properties_interface_callback_for_get_properties callback,
        #   gpointer user_data,
        #   GDestroyNotify *destructor);

        self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,' %
               (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.h('    gint timeout_ms,')

        self.b('/**')
        self.b(' * %s_%s_call_%s:' % (self.prefix_lc, iface_lc, member_lc))
        self.b(' * @proxy: the #TpProxy')
        self.b(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
        self.b(' *   default')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b(' * @%s: Used to pass an \'in\' argument: %s' %
                   (name, xml_escape(get_docstring(elt) or '(Undocumented)')))

        self.b(' * @callback: called when the method call succeeds or fails')
        self.b(' * @user_data: user-supplied data passed to the callback')
        self.b(' * @destroy: called with the user_data as argument, after the')
        self.b(' *   call has succeeded, failed or been cancelled')
        self.b(' * @weak_object: A #GObject which will be weakly referenced; ')
        self.b(' *   if it is destroyed, this callback will automatically be')
        self.b(' *   disconnected')
        self.b(' *')
        self.b(' * Start a %s method call.' % member)
        self.b(' *')
        self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
        self.b(' *')
        self.b(' * Returns: a #TpProxyPendingCall representing the call in')
        self.b(' *  progress. It is borrowed from the object, and will become')
        self.b(' *  invalid when the callback is called, the call is')
        self.b(' *  cancelled or the #TpProxy becomes invalid.')
        self.b(' */')
        self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,' %
               (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.b('    gint timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))
            self.b('    %s%s%s,' % (const, ctype, name))

        self.h('    %s callback,' % callback_name)
        self.h('    gpointer user_data,')
        self.h('    GDestroyNotify destroy,')
        self.h('    GObject *weak_object);')
        self.h('')

        self.b('    %s callback,' % callback_name)
        self.b('    gpointer user_data,')
        self.b('    GDestroyNotify destroy,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  GError *error = NULL;')
        self.b('  GQuark interface = %s;' % self.get_iface_quark())
        self.b('  DBusGProxy *iface;')
        self.b('')
        self.b('  g_return_val_if_fail (%s (proxy), NULL);' %
               self.proxy_assert)
        self.b('')
        self.b('  iface = tp_proxy_borrow_interface_by_id (')
        self.b('      (TpProxy *) proxy,')
        self.b('      interface, &error);')
        self.b('')
        self.b('  if (iface == NULL)')
        self.b('    {')
        self.b('      if (callback != NULL)')
        self.b('        callback (proxy,')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if pointer:
                self.b('            NULL,')
            else:
                self.b('            0,')

        self.b('            error, user_data, weak_object);')
        self.b('      return NULL;')
        self.b('    }')
        self.b('')
        self.b('  if (callback == NULL)')
        self.b('    {')
        self.b('      dbus_g_proxy_call_no_reply (iface, "%s",' % member)

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('          %s, %s,' % (gtype, name))

        self.b('          G_TYPE_INVALID);')
        self.b('      return NULL;')
        self.b('    }')
        self.b('  else')
        self.b('    {')
        self.b('      TpProxyPendingCall *data;')
        self.b('')
        self.b('      data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
        self.b('          interface, "%s", iface,' % member)
        self.b('          %s,' % invoke_callback)
        self.b('          G_CALLBACK (callback), user_data, destroy,')
        self.b('          weak_object, FALSE);')
        self.b('      tp_proxy_pending_call_v0_take_pending_call (data,')
        self.b('          dbus_g_proxy_begin_call_with_timeout (iface,')
        self.b('              "%s",' % member)
        self.b('              %s,' % collect_callback)
        self.b('              data,')
        self.b('              tp_proxy_pending_call_v0_completed,')
        self.b('              timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('              %s, %s,' % (gtype, name))

        self.b('              G_TYPE_INVALID));')
        self.b('')
        self.b('      return data;')
        self.b('    }')
        self.b('}')
        self.b('')

        # Reentrant blocking calls
        # Example:
        # gboolean tp_cli_properties_interface_run_get_properties
        #   (gpointer proxy,
        #       gint timeout_ms,
        #       const GArray *in_properties,
        #       GPtrArray **out0,
        #       GError **error,
        #       GMainLoop **loop);

        self.b('typedef struct {')
        self.b('    GMainLoop *loop;')
        self.b('    GError **error;')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b('    %s*%s;' % (ctype, name))

        self.b('    gboolean success:1;')
        self.b('    gboolean completed:1;')
        self.b('} _%s_%s_run_state_%s;' %
               (self.prefix_lc, iface_lc, member_lc))

        reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
                                                         iface_lc, member_lc)

        self.b('static void')
        self.b('%s (TpProxy *self,' % reentrant_invoke)
        self.b('    GError *error,')
        self.b('    GValueArray *args,')
        self.b('    GCallback unused,')
        self.b('    gpointer user_data,')
        self.b('    GObject *unused2)')
        self.b('{')
        self.b('  _%s_%s_run_state_%s *state = user_data;' %
               (self.prefix_lc, iface_lc, member_lc))
        self.b('')
        self.b('  state->success = (error == NULL);')
        self.b('  state->completed = TRUE;')
        self.b('  g_main_loop_quit (state->loop);')
        self.b('')
        self.b('  if (error != NULL)')
        self.b('    {')
        self.b('      if (state->error != NULL)')
        self.b('        *state->error = error;')
        self.b('      else')
        self.b('        g_error_free (error);')
        self.b('')
        self.b('      return;')
        self.b('    }')
        self.b('')

        for i, arg in enumerate(out_args):
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b('  if (state->%s != NULL)' % name)
            if marshaller == 'BOXED':
                self.b('    *state->%s = g_value_dup_boxed ('
                       'args->values + %d);' % (name, i))
            elif marshaller == 'STRING':
                self.b('    *state->%s = g_value_dup_string '
                       '(args->values + %d);' % (name, i))
            elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT', 'INT64',
                                'UINT64', 'DOUBLE'):
                self.b('    *state->%s = g_value_get_%s (args->values + %d);' %
                       (name, marshaller.lower(), i))
            else:
                assert False, "Don't know how to copy %s" % gtype

            self.b('')

        if len(out_args) > 0:
            self.b('  g_value_array_free (args);')
        else:
            self.b('  if (args != NULL)')
            self.b('    g_value_array_free (args);')

        self.b('}')
        self.b('')

        self.h('gboolean %s_%s_run_%s (%sproxy,' %
               (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.h('    gint timeout_ms,')

        self.b('/**')
        self.b(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc))
        self.b(' * @proxy: %s' % self.proxy_doc)
        self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b(' * @%s: Used to pass an \'in\' argument: %s' %
                   (name, xml_escape(get_docstring(elt) or '(Undocumented)')))

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is '
                   'returned: %s' %
                   (name, xml_escape(get_docstring(elt) or '(Undocumented)')))

        self.b(' * @error: If not %NULL, used to return errors if %FALSE ')
        self.b(' *  is returned')
        self.b(' * @loop: If not %NULL, set before re-entering ')
        self.b(' *  the main loop, to point to a #GMainLoop ')
        self.b(' *  which can be used to cancel this call with ')
        self.b(' *  g_main_loop_quit(), causing a return of ')
        self.b(' *  %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
        self.b(' *')
        self.b(' * Call the method %s and run the main loop' % member)
        self.b(' * until it returns. Before calling this method, you must')
        self.b(' * add a reference to any borrowed objects you need to keep,')
        self.b(' * and generally ensure that everything is in a consistent')
        self.b(' * state.')
        self.b(' *')
        self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
        self.b(' *')
        self.b(' * Returns: TRUE on success, FALSE and sets @error on error')
        self.b(' */')
        self.b('gboolean\n%s_%s_run_%s (%sproxy,' %
               (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.b('    gint timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))
            self.b('    %s%s%s,' % (const, ctype, name))

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.h('    %s*%s,' % (ctype, name))
            self.b('    %s*%s,' % (ctype, name))

        self.h('    GError **error,')
        self.h('    GMainLoop **loop);')
        self.h('')

        self.b('    GError **error,')
        self.b('    GMainLoop **loop)')
        self.b('{')
        self.b('  DBusGProxy *iface;')
        self.b('  GQuark interface = %s;' % self.get_iface_quark())
        self.b('  TpProxyPendingCall *pc;')
        self.b('  _%s_%s_run_state_%s state = {' %
               (self.prefix_lc, iface_lc, member_lc))
        self.b('      NULL /* loop */, error,')

        for arg in out_args:
            name, info, tp_type, elt = arg

            self.b('    %s,' % name)

        self.b('      FALSE /* completed */, FALSE /* success */ };')
        self.b('')
        self.b('  g_return_val_if_fail (%s (proxy), FALSE);' %
               self.proxy_assert)
        self.b('')
        self.b('  iface = tp_proxy_borrow_interface_by_id')
        self.b('       ((TpProxy *) proxy, interface, error);')
        self.b('')
        self.b('  if (iface == NULL)')
        self.b('    return FALSE;')
        self.b('')
        self.b('  state.loop = g_main_loop_new (NULL, FALSE);')
        self.b('')
        self.b('  pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
        self.b('      interface, "%s", iface,' % member)
        self.b('      %s,' % reentrant_invoke)
        self.b('      NULL, &state, NULL, NULL, TRUE);')
        self.b('')
        self.b('  if (loop != NULL)')
        self.b('    *loop = state.loop;')
        self.b('')
        self.b('  tp_proxy_pending_call_v0_take_pending_call (pc,')
        self.b('      dbus_g_proxy_begin_call_with_timeout (iface,')
        self.b('          "%s",' % member)
        self.b('          %s,' % collect_callback)
        self.b('          pc,')
        self.b('          tp_proxy_pending_call_v0_completed,')
        self.b('          timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('              %s, %s,' % (gtype, name))

        self.b('          G_TYPE_INVALID));')
        self.b('')
        self.b('  if (!state.completed)')
        self.b('    g_main_loop_run (state.loop);')
        self.b('')
        self.b('  if (!state.completed)')
        self.b('    tp_proxy_pending_call_cancel (pc);')
        self.b('')
        self.b('  if (loop != NULL)')
        self.b('    *loop = NULL;')
        self.b('')
        self.b('  g_main_loop_unref (state.loop);')
        self.b('')
        self.b('  return state.success;')
        self.b('}')
        self.b('')

        # leave a gap for the end of the method
        self.b('')
        self.h('')
    def do_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.d('/**')
        self.d(' * %s%s:' % (self.Prefix, node_name_mixed))
        self.d(' *')
        self.d(' * Dummy typedef representing any implementation of this '
               'interface.')
        self.d(' */')

        self.h('typedef struct _%s%s %s%s;'
               % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
        self.h('')

        self.d('/**')
        self.d(' * %s%sClass:' % (self.Prefix, node_name_mixed))
        self.d(' *')
        self.d(' * The class of %s%s.' % (self.Prefix, node_name_mixed))

        if methods:
            self.d(' *')
            self.d(' * In a full implementation of this interface (i.e. all')
            self.d(' * methods implemented), the interface initialization')
            self.d(' * function used in G_IMPLEMENT_INTERFACE() would')
            self.d(' * typically look like this:')
            self.d(' *')
            self.d(' * <programlisting>')
            self.d(' * static void')
            self.d(' * implement_%s (gpointer klass,' % self.node_name_lc)
            self.d(' *     gpointer unused G_GNUC_UNUSED)')
            self.d(' * {')
            self.d(' * #define IMPLEMENT(x) %s%s_implement_&num;&num;x (\\'
                   % (self.prefix_, self.node_name_lc))
            self.d(' *   klass, my_object_&num;&num;x)')

            for method in methods:
                class_member_name = method.getAttribute('tp:name-for-bindings')
                class_member_name = class_member_name.lower()
                self.d(' *   IMPLEMENT (%s);' % class_member_name)

            self.d(' * #undef IMPLEMENT')
            self.d(' * }')
            self.d(' * </programlisting>')
        else:
            self.d(' * This interface has no D-Bus methods, so an')
            self.d(' * implementation can typically pass %NULL to')
            self.d(' * G_IMPLEMENT_INTERFACE() as the interface')
            self.d(' * initialization function.')

        self.d(' */')
        self.d('')

        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 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.d('/**')
        self.d(' * %s:' % stub_name)
        self.d(' * @instance: The object implementing this interface')
        for (ctype, name, gtype) in args:
            self.d(' * @%s: %s (FIXME, generate documentation)'
                   % (name, ctype))
        self.d(' *')
        self.d(' * Type-safe wrapper around g_signal_emit to emit the')
        self.d(' * %s signal on interface %s.'
               % (dbus_name, self.iface_name))
        self.d(' */')

        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('_',
                '-')

        self.d('/**')
        self.d(' * %s%s::%s:'
                % (self.Prefix, self.node_name_mixed, signal_name))
        self.d(' * @self: an object')
        for (ctype, name, gtype) in args:
            self.d(' * @%s: %s (FIXME, generate documentation)'
                   % (name, ctype))
        self.d(' *')
        self.d(' * The %s D-Bus signal is emitted whenever '
                'this GObject signal is.' % dbus_name)
        self.d(' */')
        self.d('')

        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 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 separated)
        self.d('/**')
        self.d(' * %s:' % impl_name)
        self.d(' * @self: The object implementing this interface')
        for (ctype, name) in in_args:
            self.d(' * @%s: %s (FIXME, generate documentation)'
                   % (name, ctype))
        self.d(' * @context: Used to return values or throw an error')
        self.d(' *')
        self.d(' * The signature of an implementation of the D-Bus method')
        self.d(' * %s on interface %s.' % (dbus_method_name, self.iface_name))
        self.d(' */')

        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_cb);'
          % (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.d('/**')
        self.d(' * %s%s_implement_%s:'
               % (self.prefix_, self.node_name_lc, class_member_name))
        self.d(' * @klass: A class whose instances implement this interface')
        self.d(' * @impl: A callback used to implement the %s D-Bus method'
               % dbus_method_name)
        self.d(' *')
        self.d(' * Register an implementation for the %s method in the vtable'
               % dbus_method_name)
        self.d(' * of an implementation of this interface. To be called from')
        self.d(' * the interface init function.')
        self.d(' */')

        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_cb = impl;' % class_member_name)
        self.b('}')
        self.b('')

        # Return convenience function (static inline, in header)
        self.d('/**')
        self.d(' * %s:' % ret_name)
        self.d(' * @context: The D-Bus method invocation context')
        for (ctype, name) in out_args:
            self.d(' * @%s: %s (FIXME, generate documentation)'
                   % (name, ctype))
        self.d(' *')
        self.d(' * Return successfully by calling dbus_g_method_return().')
        self.d(' * This inline function exists only to provide type-safety.')
        self.d(' */')
        self.d('')

        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
Пример #9
0
    def do_signal(self, iface, signal):
        iface_lc = iface.lower()

        member = signal.getAttribute('name')
        member_lc = signal.getAttribute('tp:name-for-bindings')
        if member != member_lc.replace('_', ''):
            raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
                    'not match' % (member, member_lc))
        member_lc = member_lc.lower()
        member_uc = member_lc.upper()

        arg_count = 0
        args = []
        out_args = []

        for arg in signal.getElementsByTagName('arg'):
            name = arg.getAttribute('name')
            type = arg.getAttribute('type')
            tp_type = arg.getAttribute('tp:type')

            if not name:
                name = 'arg%u' % arg_count
                arg_count += 1
            else:
                name = 'arg_%s' % name

            info = type_to_gtype(type)
            args.append((name, info, tp_type, arg))

        callback_name = ('%s_%s_signal_callback_%s'
                         % (self.prefix_lc, iface_lc, member_lc))
        collect_name = ('_%s_%s_collect_args_of_%s'
                        % (self.prefix_lc, iface_lc, member_lc))
        invoke_name = ('_%s_%s_invoke_callback_for_%s'
                       % (self.prefix_lc, iface_lc, member_lc))

        # Example:
        #
        # typedef void (*tp_cli_connection_signal_callback_new_channel)
        #   (TpConnection *proxy, const gchar *arg_object_path,
        #   const gchar *arg_channel_type, guint arg_handle_type,
        #   guint arg_handle, gboolean arg_suppress_handler,
        #   gpointer user_data, GObject *weak_object);

        self.d('/**')
        self.d(' * %s:' % callback_name)
        self.d(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
               % (self.prefix_lc, iface_lc, member_lc))
        self.d(' *  was called')

        for arg in args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            docs = get_docstring(elt) or '(Undocumented)'

            if ctype == 'guint ' and tp_type != '':
                docs +=  ' (#%s)' % ('Tp' + tp_type.replace('_', ''))

            self.d(' * @%s: %s' % (name, xml_escape(docs)))

        self.d(' * @user_data: User-supplied data')
        self.d(' * @weak_object: User-supplied weakly referenced object')
        self.d(' *')
        self.d(' * Represents the signature of a callback for the signal %s.'
               % member)
        self.d(' */')
        self.d('')

        self.h('typedef void (*%s) (%sproxy,'
               % (callback_name, self.proxy_cls))

        for arg in args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))

        self.h('    gpointer user_data, GObject *weak_object);')

        if args:
            self.b('static void')
            self.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name)

            for arg in args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                const = pointer and 'const ' or ''

                self.b('    %s%s%s,' % (const, ctype, name))

            self.b('    TpProxySignalConnection *sc)')
            self.b('{')
            self.b('  G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
            self.b('  GValueArray *args = g_value_array_new (%d);' % len(args))
            self.b('  GValue blank = { 0 };')
            self.b('  guint i;')
            self.b('')
            self.b('  g_value_init (&blank, G_TYPE_INT);')
            self.b('')
            self.b('  for (i = 0; i < %d; i++)' % len(args))
            self.b('    g_value_array_append (args, &blank);')
            self.b('  G_GNUC_END_IGNORE_DEPRECATIONS')
            self.b('')

            for i, arg in enumerate(args):
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                self.b('  g_value_unset (args->values + %d);' % i)
                self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))

                self.b('  ' + copy_into_gvalue('args->values + %d' % i,
                    gtype, marshaller, name))
                self.b('')

            self.b('  tp_proxy_signal_connection_v0_take_results (sc, args);')
            self.b('}')

        self.b('static void')
        self.b('%s (TpProxy *tpproxy,' % invoke_name)
        self.b('    GError *error G_GNUC_UNUSED,')
        self.b('    GValueArray *args,')
        self.b('    GCallback generic_callback,')
        self.b('    gpointer user_data,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  %s callback =' % callback_name)
        self.b('      (%s) generic_callback;' % callback_name)
        self.b('')
        self.b('  if (callback != NULL)')
        self.b('    callback (g_object_ref (tpproxy),')

        # FIXME: factor out into a function
        for i, arg in enumerate(args):
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED':
                self.b('      g_value_get_boxed (args->values + %d),' % i)
            elif gtype == 'G_TYPE_STRING':
                self.b('      g_value_get_string (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UCHAR':
                self.b('      g_value_get_uchar (args->values + %d),' % i)
            elif gtype == 'G_TYPE_BOOLEAN':
                self.b('      g_value_get_boolean (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT':
                self.b('      g_value_get_uint (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT':
                self.b('      g_value_get_int (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT64':
                self.b('      g_value_get_uint64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT64':
                self.b('      g_value_get_int64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('      g_value_get_double (args->values + %d),' % i)
            else:
                assert False, "Don't know how to get %s from a GValue" % gtype

        self.b('      user_data,')
        self.b('      weak_object);')
        self.b('')

        self.b('  G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
        if len(args) > 0:
            self.b('  g_value_array_free (args);')
        else:
            self.b('  if (args != NULL)')
            self.b('    g_value_array_free (args);')
            self.b('')
        self.b('  G_GNUC_END_IGNORE_DEPRECATIONS')

        self.b('  g_object_unref (tpproxy);')
        self.b('}')

        # Example:
        #
        # TpProxySignalConnection *
        #   tp_cli_connection_connect_to_new_channel
        #   (TpConnection *proxy,
        #   tp_cli_connection_signal_callback_new_channel callback,
        #   gpointer user_data,
        #   GDestroyNotify destroy);
        #
        # destroy is invoked when the signal becomes disconnected. This
        # is either because the signal has been disconnected explicitly
        # by the user, because the TpProxy has become invalid and
        # emitted the 'invalidated' signal, or because the weakly referenced
        # object has gone away.

        self.d('/**')
        self.d(' * %s_%s_connect_to_%s:'
               % (self.prefix_lc, iface_lc, member_lc))
        self.d(' * @proxy: %s' % self.proxy_doc)
        self.d(' * @callback: Callback to be called when the signal is')
        self.d(' *   received')
        self.d(' * @user_data: User-supplied data for the callback')
        self.d(' * @destroy: Destructor for the user-supplied data, which')
        self.d(' *   will be called when this signal is disconnected, or')
        self.d(' *   before this function returns %NULL')
        self.d(' * @weak_object: A #GObject which will be weakly referenced; ')
        self.d(' *   if it is destroyed, this callback will automatically be')
        self.d(' *   disconnected')
        self.d(' * @error: If not %NULL, used to raise an error if %NULL is')
        self.d(' *   returned')
        self.d(' *')
        self.d(' * Connect a handler to the signal %s.' % member)
        self.d(' *')
        self.d(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
        self.d(' *')
        self.d(' * Returns: a #TpProxySignalConnection containing all of the')
        self.d(' * above, which can be used to disconnect the signal; or')
        self.d(' * %NULL if the proxy does not have the desired interface')
        self.d(' * or has become invalid.')
        self.d(' */')
        self.d('')

        self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.h('    %s callback,' % callback_name)
        self.h('    gpointer user_data,')
        self.h('    GDestroyNotify destroy,')
        self.h('    GObject *weak_object,')
        self.h('    GError **error);')
        self.h('')

        self.b('TpProxySignalConnection *')
        self.b('%s_%s_connect_to_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.b('    %s callback,' % callback_name)
        self.b('    gpointer user_data,')
        self.b('    GDestroyNotify destroy,')
        self.b('    GObject *weak_object,')
        self.b('    GError **error)')
        self.b('{')
        self.b('  GType expected_types[%d] = {' % (len(args) + 1))

        for arg in args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b('      %s,' % gtype)

        self.b('      G_TYPE_INVALID };')
        self.b('')
        self.b('  g_return_val_if_fail (%s (proxy), NULL);'
               % self.proxy_assert)
        self.b('  g_return_val_if_fail (callback != NULL, NULL);')
        self.b('')
        self.b('  return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,')
        self.b('      %s, \"%s\",' % (self.get_iface_quark(), member))
        self.b('      expected_types,')

        if args:
            self.b('      G_CALLBACK (%s),' % collect_name)
        else:
            self.b('      NULL, /* no args => no collector function */')

        self.b('      %s,' % invoke_name)
        self.b('      G_CALLBACK (callback), user_data, destroy,')
        self.b('      weak_object, error);')
        self.b('}')
        self.b('')
Пример #10
0
    def do_method(self, iface, method):
        iface_lc = iface.lower()

        member = method.getAttribute('name')
        member_lc = method.getAttribute('tp:name-for-bindings')
        if member != member_lc.replace('_', ''):
            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
                    'not match' % (member, member_lc))
        member_lc = member_lc.lower()
        member_uc = member_lc.upper()

        in_count = 0
        ret_count = 0
        in_args = []
        out_args = []

        for arg in method.getElementsByTagName('arg'):
            name = arg.getAttribute('name')
            direction = arg.getAttribute('direction')
            type = arg.getAttribute('type')
            tp_type = arg.getAttribute('tp:type')

            if direction != 'out':
                if not name:
                    name = 'in%u' % in_count
                    in_count += 1
                else:
                    name = 'in_%s' % name
            else:
                if not name:
                    name = 'out%u' % ret_count
                    ret_count += 1
                else:
                    name = 'out_%s' % name

            info = type_to_gtype(type)
            if direction != 'out':
                in_args.append((name, info, tp_type, arg))
            else:
                out_args.append((name, info, tp_type, arg))

        # Async reply callback type

        # Example:
        # void (*tp_cli_properties_interface_callback_for_get_properties)
        #   (TpProxy *proxy,
        #       const GPtrArray *out0,
        #       const GError *error,
        #       gpointer user_data,
        #       GObject *weak_object);

        self.d('/**')
        self.d(' * %s_%s_callback_for_%s:'
               % (self.prefix_lc, iface_lc, member_lc))
        self.d(' * @proxy: the proxy on which the call was made')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            docs = xml_escape(get_docstring(elt) or '(Undocumented)')

            if ctype == 'guint ' and tp_type != '':
                docs +=  ' (#%s)' % ('Tp' + tp_type.replace('_', ''))

            self.d(' * @%s: Used to return an \'out\' argument if @error is '
                   '%%NULL: %s'
                   % (name, docs))

        self.d(' * @error: %NULL on success, or an error on failure')
        self.d(' * @user_data: user-supplied data')
        self.d(' * @weak_object: user-supplied object')
        self.d(' *')
        self.d(' * Signature of the callback called when a %s method call'
               % member)
        self.d(' * succeeds or fails.')

        deprecated = method.getElementsByTagName('tp:deprecated')
        if deprecated:
            d = deprecated[0]
            self.d(' *')
            self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))

        self.d(' */')
        self.d('')

        callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
                                                   member_lc)

        self.h('typedef void (*%s) (%sproxy,'
               % (callback_name, self.proxy_cls))

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info
            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))

        self.h('    const GError *error, gpointer user_data,')
        self.h('    GObject *weak_object);')
        self.h('')

        # Async callback implementation

        invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
                                                         iface_lc,
                                                         member_lc)

        collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
                                                           iface_lc,
                                                           member_lc)

        # The callback called by dbus-glib; this ends the call and collects
        # the results into a GValueArray.
        self.b('static void')
        self.b('%s (DBusGProxy *proxy,' % collect_callback)
        self.b('    DBusGProxyCall *call,')
        self.b('    gpointer user_data)')
        self.b('{')
        self.b('  GError *error = NULL;')

        if len(out_args) > 0:
            self.b('  GValueArray *args;')
            self.b('  GValue blank = { 0 };')
            self.b('  guint i;')

            for arg in out_args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                # "We handle variants specially; the caller is expected to
                # have already allocated storage for them". Thanks,
                # dbus-glib...
                if gtype == 'G_TYPE_VALUE':
                    self.b('  GValue *%s = g_new0 (GValue, 1);' % name)
                else:
                    self.b('  %s%s;' % (ctype, name))

        self.b('')
        self.b('  dbus_g_proxy_end_call (proxy, call, &error,')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if gtype == 'G_TYPE_VALUE':
                self.b('      %s, %s,' % (gtype, name))
            else:
                self.b('      %s, &%s,' % (gtype, name))

        self.b('      G_TYPE_INVALID);')

        if len(out_args) == 0:
            self.b('  tp_proxy_pending_call_v0_take_results (user_data, error,'
                   'NULL);')
        else:
            self.b('')
            self.b('  if (error != NULL)')
            self.b('    {')
            self.b('      tp_proxy_pending_call_v0_take_results (user_data, error,')
            self.b('          NULL);')

            for arg in out_args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info
                if gtype == 'G_TYPE_VALUE':
                    self.b('      g_free (%s);' % name)

            self.b('      return;')
            self.b('    }')
            self.b('')
            self.b('  G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
            self.b('  args = g_value_array_new (%d);' % len(out_args))
            self.b('  g_value_init (&blank, G_TYPE_INT);')
            self.b('')
            self.b('  for (i = 0; i < %d; i++)' % len(out_args))
            self.b('    g_value_array_append (args, &blank);')
            self.b('  G_GNUC_END_IGNORE_DEPRECATIONS')

            for i, arg in enumerate(out_args):
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                self.b('')
                self.b('  g_value_unset (args->values + %d);' % i)
                self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))

                self.b('  ' + move_into_gvalue('args->values + %d' % i,
                    gtype, marshaller, name))

            self.b('  tp_proxy_pending_call_v0_take_results (user_data, '
                   'NULL, args);')

        self.b('}')

        self.b('static void')
        self.b('%s (TpProxy *self,' % invoke_callback)
        self.b('    GError *error,')
        self.b('    GValueArray *args,')
        self.b('    GCallback generic_callback,')
        self.b('    gpointer user_data,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  %s callback = (%s) generic_callback;'
               % (callback_name, callback_name))
        self.b('')
        self.b('  if (error != NULL)')
        self.b('    {')
        self.b('      callback ((%s) self,' % self.proxy_cls)

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED' or pointer:
                self.b('          NULL,')
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('          0.0,')
            else:
                self.b('          0,')

        self.b('          error, user_data, weak_object);')
        self.b('      g_error_free (error);')
        self.b('      return;')
        self.b('    }')

        self.b('  callback ((%s) self,' % self.proxy_cls)

        # FIXME: factor out into a function
        for i, arg in enumerate(out_args):
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED':
                self.b('      g_value_get_boxed (args->values + %d),' % i)
            elif gtype == 'G_TYPE_STRING':
                self.b('      g_value_get_string (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UCHAR':
                self.b('      g_value_get_uchar (args->values + %d),' % i)
            elif gtype == 'G_TYPE_BOOLEAN':
                self.b('      g_value_get_boolean (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT':
                self.b('      g_value_get_uint (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT':
                self.b('      g_value_get_int (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT64':
                self.b('      g_value_get_uint64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT64':
                self.b('      g_value_get_int64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('      g_value_get_double (args->values + %d),' % i)
            else:
                assert False, "Don't know how to get %s from a GValue" % gtype

        self.b('      error, user_data, weak_object);')
        self.b('')

        self.b('  G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
        if len(out_args) > 0:
            self.b('  g_value_array_free (args);')
        else:
            self.b('  if (args != NULL)')
            self.b('    g_value_array_free (args);')
        self.b('  G_GNUC_END_IGNORE_DEPRECATIONS')

        self.b('}')
        self.b('')

        # Async stub

        # Example:
        # TpProxyPendingCall *
        #   tp_cli_properties_interface_call_get_properties
        #   (gpointer proxy,
        #   gint timeout_ms,
        #   const GArray *in_properties,
        #   tp_cli_properties_interface_callback_for_get_properties callback,
        #   gpointer user_data,
        #   GDestroyNotify *destructor);

        self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.h('    gint timeout_ms,')

        self.d('/**')
        self.d(' * %s_%s_call_%s:'
               % (self.prefix_lc, iface_lc, member_lc))
        self.d(' * @proxy: the #TpProxy')
        self.d(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
        self.d(' *   default')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            docs = xml_escape(get_docstring(elt) or '(Undocumented)')

            if ctype == 'guint ' and tp_type != '':
                docs +=  ' (#%s)' % ('Tp' + tp_type.replace('_', ''))

            self.d(' * @%s: Used to pass an \'in\' argument: %s'
                   % (name, docs))

        self.d(' * @callback: called when the method call succeeds or fails;')
        self.d(' *   may be %NULL to make a "fire and forget" call with no ')
        self.d(' *   reply tracking')
        self.d(' * @user_data: user-supplied data passed to the callback;')
        self.d(' *   must be %NULL if @callback is %NULL')
        self.d(' * @destroy: called with the user_data as argument, after the')
        self.d(' *   call has succeeded, failed or been cancelled;')
        self.d(' *   must be %NULL if @callback is %NULL')
        self.d(' * @weak_object: If not %NULL, a #GObject which will be ')
        self.d(' *   weakly referenced; if it is destroyed, this call ')
        self.d(' *   will automatically be cancelled. Must be %NULL if ')
        self.d(' *   @callback is %NULL')
        self.d(' *')
        self.d(' * Start a %s method call.' % member)
        self.d(' *')
        self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
        self.d(' *')
        self.d(' * Returns: a #TpProxyPendingCall representing the call in')
        self.d(' *  progress. It is borrowed from the object, and will become')
        self.d(' *  invalid when the callback is called, the call is')
        self.d(' *  cancelled or the #TpProxy becomes invalid.')

        deprecated = method.getElementsByTagName('tp:deprecated')
        if deprecated:
            d = deprecated[0]
            self.d(' *')
            self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))

        self.d(' */')
        self.d('')

        self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.b('    gint timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))
            self.b('    %s%s%s,' % (const, ctype, name))

        self.h('    %s callback,' % callback_name)
        self.h('    gpointer user_data,')
        self.h('    GDestroyNotify destroy,')
        self.h('    GObject *weak_object);')
        self.h('')

        self.b('    %s callback,' % callback_name)
        self.b('    gpointer user_data,')
        self.b('    GDestroyNotify destroy,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  GError *error = NULL;')
        self.b('  GQuark interface = %s;' % self.get_iface_quark())
        self.b('  DBusGProxy *iface;')
        self.b('')
        self.b('  g_return_val_if_fail (%s (proxy), NULL);'
               % self.proxy_assert)
        self.b('  g_return_val_if_fail (callback != NULL || '
               'user_data == NULL, NULL);')
        self.b('  g_return_val_if_fail (callback != NULL || '
               'destroy == NULL, NULL);')
        self.b('  g_return_val_if_fail (callback != NULL || '
               'weak_object == NULL, NULL);')
        self.b('')
        self.b('  G_GNUC_BEGIN_IGNORE_DEPRECATIONS')
        self.b('  iface = tp_proxy_borrow_interface_by_id (')
        self.b('      (TpProxy *) proxy,')
        self.b('      interface, &error);')
        self.b('  G_GNUC_END_IGNORE_DEPRECATIONS')
        self.b('')
        self.b('  if (iface == NULL)')
        self.b('    {')
        self.b('      if (callback != NULL)')
        self.b('        callback (proxy,')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if pointer:
                self.b('            NULL,')
            else:
                self.b('            0,')

        self.b('            error, user_data, weak_object);')
        self.b('')
        self.b('      if (destroy != NULL)')
        self.b('        destroy (user_data);')
        self.b('')
        self.b('      g_error_free (error);')
        self.b('      return NULL;')
        self.b('    }')
        self.b('')
        self.b('  if (callback == NULL)')
        self.b('    {')
        self.b('      dbus_g_proxy_call_no_reply (iface, "%s",' % member)

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('          %s, %s,' % (gtype, name))

        self.b('          G_TYPE_INVALID);')
        self.b('      return NULL;')
        self.b('    }')
        self.b('  else')
        self.b('    {')
        self.b('      TpProxyPendingCall *data;')
        self.b('')
        self.b('      data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
        self.b('          interface, "%s", iface,' % member)
        self.b('          %s,' % invoke_callback)
        self.b('          G_CALLBACK (callback), user_data, destroy,')
        self.b('          weak_object, FALSE);')
        self.b('      tp_proxy_pending_call_v0_take_pending_call (data,')
        self.b('          dbus_g_proxy_begin_call_with_timeout (iface,')
        self.b('              "%s",' % member)
        self.b('              %s,' % collect_callback)
        self.b('              data,')
        self.b('              tp_proxy_pending_call_v0_completed,')
        self.b('              timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('              %s, %s,' % (gtype, name))

        self.b('              G_TYPE_INVALID));')
        self.b('')
        self.b('      return data;')
        self.b('    }')
        self.b('}')
        self.b('')

        self.do_method_reentrant(method, iface_lc, member, member_lc,
                                 in_args, out_args, collect_callback)

        # leave a gap for the end of the method
        self.d('')
        self.b('')
        self.h('')
Пример #11
0
def types_to_gtypes(types):
    return [type_to_gtype(t)[1] for t in types]
    def do_node(self, node):
        node_name = node.getAttribute('name').replace('/', '')
        node_name_mixed = self.node_name_mixed = node_name.replace('_', '')
        node_name_lc = self.node_name_lc = node_name.lower()
        node_name_uc = self.node_name_uc = node_name.upper()

        interfaces = node.getElementsByTagName('interface')
        assert len(interfaces) == 1, interfaces
        interface = interfaces[0]
        self.iface_name = interface.getAttribute('name')

        tmp = interface.getAttribute('tp:implement-service')
        if tmp == "no":
            return

        tmp = interface.getAttribute('tp:causes-havoc')
        if tmp and not self.allow_havoc:
            raise AssertionError('%s is %s' % (self.iface_name, tmp))

        self.b('static const DBusGObjectInfo _%s%s_object_info;' %
               (self.prefix_, node_name_lc))
        self.b('')

        methods = interface.getElementsByTagName('method')
        signals = interface.getElementsByTagName('signal')
        properties = interface.getElementsByTagName('property')
        # Don't put properties in dbus-glib glue
        glue_properties = []

        self.b('struct _%s%sClass {' % (self.Prefix, node_name_mixed))
        self.b('    GTypeInterface parent_class;')
        for method in methods:
            self.b('    %s %s;' % self.get_method_impl_names(method))
        self.b('};')
        self.b('')

        if signals:
            self.b('enum {')
            for signal in signals:
                self.b('    %s,' % self.get_signal_const_entry(signal))
            self.b('    N_%s_SIGNALS' % node_name_uc)
            self.b('};')
            self.b('static guint %s_signals[N_%s_SIGNALS] = {0};' %
                   (node_name_lc, node_name_uc))
            self.b('')

        self.b('static void %s%s_base_init (gpointer klass);' %
               (self.prefix_, node_name_lc))
        self.b('')

        self.b('GType')
        self.b('%s%s_get_type (void)' % (self.prefix_, node_name_lc))
        self.b('{')
        self.b('  static GType type = 0;')
        self.b('')
        self.b('  if (G_UNLIKELY (type == 0))')
        self.b('    {')
        self.b('      static const GTypeInfo info = {')
        self.b('        sizeof (%s%sClass),' % (self.Prefix, node_name_mixed))
        self.b('        %s%s_base_init, /* base_init */' %
               (self.prefix_, node_name_lc))
        self.b('        NULL, /* base_finalize */')
        self.b('        NULL, /* class_init */')
        self.b('        NULL, /* class_finalize */')
        self.b('        NULL, /* class_data */')
        self.b('        0,')
        self.b('        0, /* n_preallocs */')
        self.b('        NULL /* instance_init */')
        self.b('      };')
        self.b('')
        self.b('      type = g_type_register_static (G_TYPE_INTERFACE,')
        self.b('          "%s%s", &info, 0);' % (self.Prefix, node_name_mixed))
        self.b('    }')
        self.b('')
        self.b('  return type;')
        self.b('}')
        self.b('')

        self.h('/**')
        self.h(' * %s%s:' % (self.Prefix, node_name_mixed))
        self.h(' *')
        self.h(' * Dummy typedef representing any implementation of this '
               'interface.')
        self.h(' */')
        self.h('typedef struct _%s%s %s%s;' %
               (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
        self.h('')
        self.h('/**')
        self.h(' * %s%sClass:' % (self.Prefix, node_name_mixed))
        self.h(' *')
        self.h(' * The class of %s%s.' % (self.Prefix, node_name_mixed))
        self.h(' */')
        self.h('typedef struct _%s%sClass %s%sClass;' %
               (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
        self.h('')
        self.h('GType %s%s_get_type (void);' % (self.prefix_, node_name_lc))

        gtype = self.current_gtype = \
                self.MAIN_PREFIX_ + 'TYPE' + self._SUB_PREFIX_ + node_name_uc
        classname = self.Prefix + node_name_mixed

        self.h('#define %s \\\n  (%s%s_get_type ())' %
               (gtype, self.prefix_, node_name_lc))
        self.h('#define %s%s(obj) \\\n'
               '  (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))' %
               (self.PREFIX_, node_name_uc, gtype, classname))
        self.h('#define %sIS%s%s(obj) \\\n'
               '  (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))' %
               (self.MAIN_PREFIX_, self._SUB_PREFIX_, node_name_uc, gtype))
        self.h('#define %s%s_GET_CLASS(obj) \\\n'
               '  (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))' %
               (self.PREFIX_, node_name_uc, gtype, classname))
        self.h('')
        self.h('')

        base_init_code = []

        for method in methods:
            self.do_method(method)

        for signal in signals:
            base_init_code.extend(self.do_signal(signal))

        self.b('static inline void')
        self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)' %
               (self.prefix_, node_name_lc))
        self.b('{')

        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 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 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 do_method(self, iface, method):
        iface_lc = iface.lower()

        member = method.getAttribute('name')
        member_lc = method.getAttribute('tp:name-for-bindings')
        if member != member_lc.replace('_', ''):
            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
                    'not match' % (member, member_lc))
        member_lc = member_lc.lower()
        member_uc = member_lc.upper()

        in_count = 0
        ret_count = 0
        in_args = []
        out_args = []

        for arg in method.getElementsByTagName('arg'):
            name = arg.getAttribute('name')
            direction = arg.getAttribute('direction')
            type = arg.getAttribute('type')
            tp_type = arg.getAttribute('tp:type')

            if direction != 'out':
                if not name:
                    name = 'in%u' % in_count
                    in_count += 1
                else:
                    name = 'in_%s' % name
            else:
                if not name:
                    name = 'out%u' % ret_count
                    ret_count += 1
                else:
                    name = 'out_%s' % name

            info = type_to_gtype(type)
            if direction != 'out':
                in_args.append((name, info, tp_type, arg))
            else:
                out_args.append((name, info, tp_type, arg))

        # Async reply callback type

        # Example:
        # void (*tp_cli_properties_interface_callback_for_get_properties)
        #   (TpProxy *proxy,
        #       const GPtrArray *out0,
        #       const GError *error,
        #       gpointer user_data,
        #       GObject *weak_object);

        self.d('/**')
        self.d(' * %s_%s_callback_for_%s:'
               % (self.prefix_lc, iface_lc, member_lc))
        self.d(' * @proxy: the proxy on which the call was made')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            docs = xml_escape(get_docstring(elt) or '(Undocumented)')

            if ctype == 'guint ' and tp_type != '':
                docs +=  ' (#%s)' % ('Tp' + tp_type.replace('_', ''))

            self.d(' * @%s: Used to return an \'out\' argument if @error is '
                   '%%NULL: %s'
                   % (name, docs))

        self.d(' * @error: %NULL on success, or an error on failure')
        self.d(' * @user_data: user-supplied data')
        self.d(' * @weak_object: user-supplied object')
        self.d(' *')
        self.d(' * Signature of the callback called when a %s method call'
               % member)
        self.d(' * succeeds or fails.')

        deprecated = method.getElementsByTagName('tp:deprecated')
        if deprecated:
            d = deprecated[0]
            self.d(' *')
            self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))

        self.d(' */')
        self.d('')

        callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
                                                   member_lc)

        self.h('typedef void (*%s) (%sproxy,'
               % (callback_name, self.proxy_cls))

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info
            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))

        self.h('    const GError *error, gpointer user_data,')
        self.h('    GObject *weak_object);')
        self.h('')

        # Async callback implementation

        invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
                                                         iface_lc,
                                                         member_lc)

        collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
                                                           iface_lc,
                                                           member_lc)

        # The callback called by dbus-glib; this ends the call and collects
        # the results into a GValueArray.
        self.b('static void')
        self.b('%s (DBusGProxy *proxy,' % collect_callback)
        self.b('    DBusGProxyCall *call,')
        self.b('    gpointer user_data)')
        self.b('{')
        self.b('  GError *error = NULL;')

        if len(out_args) > 0:
            self.b('  GValueArray *args;')
            self.b('  GValue blank = { 0 };')
            self.b('  guint i;')

            for arg in out_args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                # "We handle variants specially; the caller is expected to
                # have already allocated storage for them". Thanks,
                # dbus-glib...
                if gtype == 'G_TYPE_VALUE':
                    self.b('  GValue *%s = g_new0 (GValue, 1);' % name)
                else:
                    self.b('  %s%s;' % (ctype, name))

        self.b('')
        self.b('  dbus_g_proxy_end_call (proxy, call, &error,')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if gtype == 'G_TYPE_VALUE':
                self.b('      %s, %s,' % (gtype, name))
            else:
                self.b('      %s, &%s,' % (gtype, name))

        self.b('      G_TYPE_INVALID);')

        if len(out_args) == 0:
            self.b('  tp_proxy_pending_call_v0_take_results (user_data, error,'
                   'NULL);')
        else:
            self.b('')
            self.b('  if (error != NULL)')
            self.b('    {')
            self.b('      tp_proxy_pending_call_v0_take_results (user_data, error,')
            self.b('          NULL);')

            for arg in out_args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info
                if gtype == 'G_TYPE_VALUE':
                    self.b('      g_free (%s);' % name)

            self.b('      return;')
            self.b('    }')
            self.b('')
            self.b('  args = g_value_array_new (%d);' % len(out_args))
            self.b('  g_value_init (&blank, G_TYPE_INT);')
            self.b('')
            self.b('  for (i = 0; i < %d; i++)' % len(out_args))
            self.b('    g_value_array_append (args, &blank);')

            for i, arg in enumerate(out_args):
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                self.b('')
                self.b('  g_value_unset (args->values + %d);' % i)
                self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))

                if gtype == 'G_TYPE_STRING':
                    self.b('  g_value_take_string (args->values + %d, %s);'
                           % (i, name))
                elif marshaller == 'BOXED':
                    self.b('  g_value_take_boxed (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_UCHAR':
                    self.b('  g_value_set_uchar (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_BOOLEAN':
                    self.b('  g_value_set_boolean (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_INT':
                    self.b('  g_value_set_int (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_UINT':
                    self.b('  g_value_set_uint (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_INT64':
                    self.b('  g_value_set_int (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_UINT64':
                    self.b('  g_value_set_uint (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_DOUBLE':
                    self.b('  g_value_set_double (args->values + %d, %s);'
                            % (i, name))
                else:
                    assert False, ("Don't know how to put %s in a GValue"
                                   % gtype)

            self.b('  tp_proxy_pending_call_v0_take_results (user_data, '
                   'NULL, args);')

        self.b('}')

        self.b('static void')
        self.b('%s (TpProxy *self,' % invoke_callback)
        self.b('    GError *error,')
        self.b('    GValueArray *args,')
        self.b('    GCallback generic_callback,')
        self.b('    gpointer user_data,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  %s callback = (%s) generic_callback;'
               % (callback_name, callback_name))
        self.b('')
        self.b('  if (error != NULL)')
        self.b('    {')
        self.b('      callback ((%s) self,' % self.proxy_cls)

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED' or pointer:
                self.b('          NULL,')
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('          0.0,')
            else:
                self.b('          0,')

        self.b('          error, user_data, weak_object);')
        self.b('      g_error_free (error);')
        self.b('      return;')
        self.b('    }')

        self.b('  callback ((%s) self,' % self.proxy_cls)

        # FIXME: factor out into a function
        for i, arg in enumerate(out_args):
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED':
                self.b('      g_value_get_boxed (args->values + %d),' % i)
            elif gtype == 'G_TYPE_STRING':
                self.b('      g_value_get_string (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UCHAR':
                self.b('      g_value_get_uchar (args->values + %d),' % i)
            elif gtype == 'G_TYPE_BOOLEAN':
                self.b('      g_value_get_boolean (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT':
                self.b('      g_value_get_uint (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT':
                self.b('      g_value_get_int (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT64':
                self.b('      g_value_get_uint64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT64':
                self.b('      g_value_get_int64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('      g_value_get_double (args->values + %d),' % i)
            else:
                assert False, "Don't know how to get %s from a GValue" % gtype

        self.b('      error, user_data, weak_object);')
        self.b('')

        if len(out_args) > 0:
            self.b('  g_value_array_free (args);')
        else:
            self.b('  if (args != NULL)')
            self.b('    g_value_array_free (args);')

        self.b('}')
        self.b('')

        # Async stub

        # Example:
        # TpProxyPendingCall *
        #   tp_cli_properties_interface_call_get_properties
        #   (gpointer proxy,
        #   gint timeout_ms,
        #   const GArray *in_properties,
        #   tp_cli_properties_interface_callback_for_get_properties callback,
        #   gpointer user_data,
        #   GDestroyNotify *destructor);

        self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.h('    gint timeout_ms,')

        self.d('/**')
        self.d(' * %s_%s_call_%s:'
               % (self.prefix_lc, iface_lc, member_lc))
        self.d(' * @proxy: the #TpProxy')
        self.d(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
        self.d(' *   default')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            docs = xml_escape(get_docstring(elt) or '(Undocumented)')

            if ctype == 'guint ' and tp_type != '':
                docs +=  ' (#%s)' % ('Tp' + tp_type.replace('_', ''))

            self.d(' * @%s: Used to pass an \'in\' argument: %s'
                   % (name, docs))

        self.d(' * @callback: called when the method call succeeds or fails;')
        self.d(' *   may be %NULL to make a "fire and forget" call with no ')
        self.d(' *   reply tracking')
        self.d(' * @user_data: user-supplied data passed to the callback;')
        self.d(' *   must be %NULL if @callback is %NULL')
        self.d(' * @destroy: called with the user_data as argument, after the')
        self.d(' *   call has succeeded, failed or been cancelled;')
        self.d(' *   must be %NULL if @callback is %NULL')
        self.d(' * @weak_object: If not %NULL, a #GObject which will be ')
        self.d(' *   weakly referenced; if it is destroyed, this call ')
        self.d(' *   will automatically be cancelled. Must be %NULL if ')
        self.d(' *   @callback is %NULL')
        self.d(' *')
        self.d(' * Start a %s method call.' % member)
        self.d(' *')
        self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
        self.d(' *')
        self.d(' * Returns: a #TpProxyPendingCall representing the call in')
        self.d(' *  progress. It is borrowed from the object, and will become')
        self.d(' *  invalid when the callback is called, the call is')
        self.d(' *  cancelled or the #TpProxy becomes invalid.')

        deprecated = method.getElementsByTagName('tp:deprecated')
        if deprecated:
            d = deprecated[0]
            self.d(' *')
            self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))

        self.d(' */')
        self.d('')

        self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.b('    gint timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))
            self.b('    %s%s%s,' % (const, ctype, name))

        self.h('    %s callback,' % callback_name)
        self.h('    gpointer user_data,')
        self.h('    GDestroyNotify destroy,')
        self.h('    GObject *weak_object);')
        self.h('')

        self.b('    %s callback,' % callback_name)
        self.b('    gpointer user_data,')
        self.b('    GDestroyNotify destroy,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  GError *error = NULL;')
        self.b('  GQuark interface = %s;' % self.get_iface_quark())
        self.b('  DBusGProxy *iface;')
        self.b('')
        self.b('  g_return_val_if_fail (%s (proxy), NULL);'
               % self.proxy_assert)
        self.b('  g_return_val_if_fail (callback != NULL || '
               'user_data == NULL, NULL);')
        self.b('  g_return_val_if_fail (callback != NULL || '
               'destroy == NULL, NULL);')
        self.b('  g_return_val_if_fail (callback != NULL || '
               'weak_object == NULL, NULL);')
        self.b('')
        self.b('  iface = tp_proxy_borrow_interface_by_id (')
        self.b('      (TpProxy *) proxy,')
        self.b('      interface, &error);')
        self.b('')
        self.b('  if (iface == NULL)')
        self.b('    {')
        self.b('      if (callback != NULL)')
        self.b('        callback (proxy,')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if pointer:
                self.b('            NULL,')
            else:
                self.b('            0,')

        self.b('            error, user_data, weak_object);')
        self.b('')
        self.b('      if (destroy != NULL)')
        self.b('        destroy (user_data);')
        self.b('')
        self.b('      g_error_free (error);')
        self.b('      return NULL;')
        self.b('    }')
        self.b('')
        self.b('  if (callback == NULL)')
        self.b('    {')
        self.b('      dbus_g_proxy_call_no_reply (iface, "%s",' % member)

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('          %s, %s,' % (gtype, name))

        self.b('          G_TYPE_INVALID);')
        self.b('      return NULL;')
        self.b('    }')
        self.b('  else')
        self.b('    {')
        self.b('      TpProxyPendingCall *data;')
        self.b('')
        self.b('      data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
        self.b('          interface, "%s", iface,' % member)
        self.b('          %s,' % invoke_callback)
        self.b('          G_CALLBACK (callback), user_data, destroy,')
        self.b('          weak_object, FALSE);')
        self.b('      tp_proxy_pending_call_v0_take_pending_call (data,')
        self.b('          dbus_g_proxy_begin_call_with_timeout (iface,')
        self.b('              "%s",' % member)
        self.b('              %s,' % collect_callback)
        self.b('              data,')
        self.b('              tp_proxy_pending_call_v0_completed,')
        self.b('              timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('              %s, %s,' % (gtype, name))

        self.b('              G_TYPE_INVALID));')
        self.b('')
        self.b('      return data;')
        self.b('    }')
        self.b('}')
        self.b('')

        self.do_method_reentrant(method, iface_lc, member, member_lc,
                                 in_args, out_args, collect_callback)

        # leave a gap for the end of the method
        self.d('')
        self.b('')
        self.h('')
    def do_method(self, iface, method):
        iface_lc = iface.lower()

        member = method.getAttribute('name')
        member_lc = camelcase_to_lower(member)
        member_uc = member_lc.upper()

        in_count = 0
        ret_count = 0
        in_args = []
        out_args = []

        for arg in method.getElementsByTagName('arg'):
            name = arg.getAttribute('name')
            direction = arg.getAttribute('direction')
            type = arg.getAttribute('type')
            tp_type = arg.getAttribute('tp:type')

            if direction != 'out':
                if not name:
                    name = 'in%u' % in_count
                    in_count += 1
                else:
                    name = 'in_%s' % name
            else:
                if not name:
                    name = 'out%u' % ret_count
                    ret_count += 1
                else:
                    name = 'out_%s' % name

            info = type_to_gtype(type)
            if direction != 'out':
                in_args.append((name, info, tp_type, arg))
            else:
                out_args.append((name, info, tp_type, arg))

        # Async reply callback type

        # Example:
        # void (*tp_cli_properties_interface_callback_for_get_properties)
        #   (TpProxy *proxy,
        #       const GPtrArray *out0,
        #       const GError *error,
        #       gpointer user_data,
        #       GObject *weak_object);

        self.b('/**')
        self.b(' * %s_%s_callback_for_%s:'
               % (self.prefix_lc, iface_lc, member_lc))
        self.b(' * @proxy: the proxy on which the call was made')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b(' * @%s: Used to return an \'out\' argument if @error is '
                   '%%NULL: %s'
                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))

        self.b(' * @error: %NULL on success, or an error on failure')
        self.b(' * @user_data: user-supplied data')
        self.b(' * @weak_object: user-supplied object')
        self.b(' *')
        self.b(' * Signature of the callback called when a %s method call'
               % member)
        self.b(' * succeeds or fails.')
        self.b(' */')

        callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
                                                   member_lc)

        self.h('typedef void (*%s) (%sproxy,'
               % (callback_name, self.proxy_cls))

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info
            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))

        self.h('    const GError *error, gpointer user_data,')
        self.h('    GObject *weak_object);')
        self.h('')

        # Async callback implementation

        invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
                                                         iface_lc,
                                                         member_lc)

        collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
                                                           iface_lc,
                                                           member_lc)

        # The callback called by dbus-glib; this ends the call and collects
        # the results into a GValueArray.
        self.b('static void')
        self.b('%s (DBusGProxy *proxy,' % collect_callback)
        self.b('    DBusGProxyCall *call,')
        self.b('    gpointer user_data)')
        self.b('{')
        self.b('  GError *error = NULL;')

        if len(out_args) > 0:
            self.b('  GValueArray *args;')
            self.b('  GValue blank = { 0 };')
            self.b('  guint i;')

            for arg in out_args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                # "We handle variants specially; the caller is expected to
                # have already allocated storage for them". Thanks,
                # dbus-glib...
                if gtype == 'G_TYPE_VALUE':
                    self.b('  GValue *%s = g_new0 (GValue, 1);' % name)
                else:
                    self.b('  %s%s;' % (ctype, name))

        self.b('')
        self.b('  dbus_g_proxy_end_call (proxy, call, &error,')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if gtype == 'G_TYPE_VALUE':
                self.b('      %s, %s,' % (gtype, name))
            else:
                self.b('      %s, &%s,' % (gtype, name))

        self.b('      G_TYPE_INVALID);')

        if len(out_args) == 0:
            self.b('  tp_proxy_pending_call_v0_take_results (user_data, error,'
                   'NULL);')
        else:
            self.b('')
            self.b('  if (error != NULL)')
            self.b('    {')
            self.b('      tp_proxy_pending_call_v0_take_results (user_data, error,')
            self.b('          NULL);')

            for arg in out_args:
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info
                if gtype == 'G_TYPE_VALUE':
                    self.b('      g_free (%s);' % name)

            self.b('      return;')
            self.b('    }')
            self.b('')
            self.b('  args = g_value_array_new (%d);' % len(out_args))
            self.b('  g_value_init (&blank, G_TYPE_INT);')
            self.b('')
            self.b('  for (i = 0; i < %d; i++)' % len(out_args))
            self.b('    g_value_array_append (args, &blank);')

            for i, arg in enumerate(out_args):
                name, info, tp_type, elt = arg
                ctype, gtype, marshaller, pointer = info

                self.b('')
                self.b('  g_value_unset (args->values + %d);' % i)
                self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))

                if gtype == 'G_TYPE_STRING':
                    self.b('  g_value_take_string (args->values + %d, %s);'
                           % (i, name))
                elif marshaller == 'BOXED':
                    self.b('  g_value_take_boxed (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_UCHAR':
                    self.b('  g_value_set_uchar (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_BOOLEAN':
                    self.b('  g_value_set_boolean (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_INT':
                    self.b('  g_value_set_int (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_UINT':
                    self.b('  g_value_set_uint (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_INT64':
                    self.b('  g_value_set_int (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_UINT64':
                    self.b('  g_value_set_uint (args->values + %d, %s);'
                            % (i, name))
                elif gtype == 'G_TYPE_DOUBLE':
                    self.b('  g_value_set_double (args->values + %d, %s);'
                            % (i, name))
                else:
                    assert False, ("Don't know how to put %s in a GValue"
                                   % gtype)

            self.b('  tp_proxy_pending_call_v0_take_results (user_data, '
                   'NULL, args);')

        self.b('}')

        self.b('static void')
        self.b('%s (TpProxy *self,' % invoke_callback)
        self.b('    GError *error,')
        self.b('    GValueArray *args,')
        self.b('    GCallback generic_callback,')
        self.b('    gpointer user_data,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  %s callback = (%s) generic_callback;'
               % (callback_name, callback_name))
        self.b('')
        self.b('  if (error != NULL)')
        self.b('    {')
        self.b('      callback ((%s) self,' % self.proxy_cls)

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED' or pointer:
                self.b('          NULL,')
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('          0.0,')
            else:
                self.b('          0,')

        self.b('          error, user_data, weak_object);')
        self.b('      g_error_free (error);')
        self.b('      return;')
        self.b('    }')

        self.b('  callback ((%s) self,' % self.proxy_cls)

        # FIXME: factor out into a function
        for i, arg in enumerate(out_args):
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if marshaller == 'BOXED':
                self.b('      g_value_get_boxed (args->values + %d),' % i)
            elif gtype == 'G_TYPE_STRING':
                self.b('      g_value_get_string (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UCHAR':
                self.b('      g_value_get_uchar (args->values + %d),' % i)
            elif gtype == 'G_TYPE_BOOLEAN':
                self.b('      g_value_get_boolean (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT':
                self.b('      g_value_get_uint (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT':
                self.b('      g_value_get_int (args->values + %d),' % i)
            elif gtype == 'G_TYPE_UINT64':
                self.b('      g_value_get_uint64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_INT64':
                self.b('      g_value_get_int64 (args->values + %d),' % i)
            elif gtype == 'G_TYPE_DOUBLE':
                self.b('      g_value_get_double (args->values + %d),' % i)
            else:
                assert False, "Don't know how to get %s from a GValue" % gtype

        self.b('      error, user_data, weak_object);')
        self.b('')

        if len(out_args) > 0:
            self.b('  g_value_array_free (args);')
        else:
            self.b('  if (args != NULL)')
            self.b('    g_value_array_free (args);')

        self.b('}')
        self.b('')

        # Async stub

        # Example:
        # TpProxyPendingCall *
        #   tp_cli_properties_interface_call_get_properties
        #   (gpointer proxy,
        #   gint timeout_ms,
        #   const GArray *in_properties,
        #   tp_cli_properties_interface_callback_for_get_properties callback,
        #   gpointer user_data,
        #   GDestroyNotify *destructor);

        self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.h('    gint timeout_ms,')

        self.b('/**')
        self.b(' * %s_%s_call_%s:'
               % (self.prefix_lc, iface_lc, member_lc))
        self.b(' * @proxy: the #TpProxy')
        self.b(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
        self.b(' *   default')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b(' * @%s: Used to pass an \'in\' argument: %s'
                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))

        self.b(' * @callback: called when the method call succeeds or fails')
        self.b(' * @user_data: user-supplied data passed to the callback')
        self.b(' * @destroy: called with the user_data as argument, after the')
        self.b(' *   call has succeeded, failed or been cancelled')
        self.b(' * @weak_object: A #GObject which will be weakly referenced; ')
        self.b(' *   if it is destroyed, this callback will automatically be')
        self.b(' *   disconnected')
        self.b(' *')
        self.b(' * Start a %s method call.' % member)
        self.b(' *')
        self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
        self.b(' *')
        self.b(' * Returns: a #TpProxyPendingCall representing the call in')
        self.b(' *  progress. It is borrowed from the object, and will become')
        self.b(' *  invalid when the callback is called, the call is')
        self.b(' *  cancelled or the #TpProxy becomes invalid.')
        self.b(' */')
        self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.b('    gint timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))
            self.b('    %s%s%s,' % (const, ctype, name))

        self.h('    %s callback,' % callback_name)
        self.h('    gpointer user_data,')
        self.h('    GDestroyNotify destroy,')
        self.h('    GObject *weak_object);')
        self.h('')

        self.b('    %s callback,' % callback_name)
        self.b('    gpointer user_data,')
        self.b('    GDestroyNotify destroy,')
        self.b('    GObject *weak_object)')
        self.b('{')
        self.b('  GError *error = NULL;')
        self.b('  GQuark interface = %s;' % self.get_iface_quark())
        self.b('  DBusGProxy *iface;')
        self.b('')
        self.b('  g_return_val_if_fail (%s (proxy), NULL);'
               % self.proxy_assert)
        self.b('')
        self.b('  iface = tp_proxy_borrow_interface_by_id (')
        self.b('      (TpProxy *) proxy,')
        self.b('      interface, &error);')
        self.b('')
        self.b('  if (iface == NULL)')
        self.b('    {')
        self.b('      if (callback != NULL)')
        self.b('        callback (proxy,')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            if pointer:
                self.b('            NULL,')
            else:
                self.b('            0,')

        self.b('            error, user_data, weak_object);')
        self.b('      return NULL;')
        self.b('    }')
        self.b('')
        self.b('  if (callback == NULL)')
        self.b('    {')
        self.b('      dbus_g_proxy_call_no_reply (iface, "%s",' % member)

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('          %s, %s,' % (gtype, name))

        self.b('          G_TYPE_INVALID);')
        self.b('      return NULL;')
        self.b('    }')
        self.b('  else')
        self.b('    {')
        self.b('      TpProxyPendingCall *data;')
        self.b('')
        self.b('      data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
        self.b('          interface, "%s", iface,' % member)
        self.b('          %s,' % invoke_callback)
        self.b('          G_CALLBACK (callback), user_data, destroy,')
        self.b('          weak_object, FALSE);')
        self.b('      tp_proxy_pending_call_v0_take_pending_call (data,')
        self.b('          dbus_g_proxy_begin_call_with_timeout (iface,')
        self.b('              "%s",' % member)
        self.b('              %s,' % collect_callback)
        self.b('              data,')
        self.b('              tp_proxy_pending_call_v0_completed,')
        self.b('              timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('              %s, %s,' % (gtype, name))

        self.b('              G_TYPE_INVALID));')
        self.b('')
        self.b('      return data;')
        self.b('    }')
        self.b('}')
        self.b('')

        # Reentrant blocking calls
        # Example:
        # gboolean tp_cli_properties_interface_run_get_properties
        #   (gpointer proxy,
        #       gint timeout_ms,
        #       const GArray *in_properties,
        #       GPtrArray **out0,
        #       GError **error,
        #       GMainLoop **loop);

        self.b('typedef struct {')
        self.b('    GMainLoop *loop;')
        self.b('    GError **error;')

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b('    %s*%s;' % (ctype, name))

        self.b('    gboolean success:1;')
        self.b('    gboolean completed:1;')
        self.b('} _%s_%s_run_state_%s;'
               % (self.prefix_lc, iface_lc, member_lc))

        reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
                                                         iface_lc,
                                                         member_lc)

        self.b('static void')
        self.b('%s (TpProxy *self,' % reentrant_invoke)
        self.b('    GError *error,')
        self.b('    GValueArray *args,')
        self.b('    GCallback unused,')
        self.b('    gpointer user_data,')
        self.b('    GObject *unused2)')
        self.b('{')
        self.b('  _%s_%s_run_state_%s *state = user_data;'
               % (self.prefix_lc, iface_lc, member_lc))
        self.b('')
        self.b('  state->success = (error == NULL);')
        self.b('  state->completed = TRUE;')
        self.b('  g_main_loop_quit (state->loop);')
        self.b('')
        self.b('  if (error != NULL)')
        self.b('    {')
        self.b('      if (state->error != NULL)')
        self.b('        *state->error = error;')
        self.b('      else')
        self.b('        g_error_free (error);')
        self.b('')
        self.b('      return;')
        self.b('    }')
        self.b('')

        for i, arg in enumerate(out_args):
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b('  if (state->%s != NULL)' % name)
            if marshaller == 'BOXED':
                self.b('    *state->%s = g_value_dup_boxed ('
                       'args->values + %d);' % (name, i))
            elif marshaller == 'STRING':
                self.b('    *state->%s = g_value_dup_string '
                       '(args->values + %d);' % (name, i))
            elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
                    'INT64', 'UINT64', 'DOUBLE'):
                self.b('    *state->%s = g_value_get_%s (args->values + %d);'
                       % (name, marshaller.lower(), i))
            else:
                assert False, "Don't know how to copy %s" % gtype

            self.b('')

        if len(out_args) > 0:
            self.b('  g_value_array_free (args);')
        else:
            self.b('  if (args != NULL)')
            self.b('    g_value_array_free (args);')

        self.b('}')
        self.b('')

        self.h('gboolean %s_%s_run_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.h('    gint timeout_ms,')

        self.b('/**')
        self.b(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc))
        self.b(' * @proxy: %s' % self.proxy_doc)
        self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b(' * @%s: Used to pass an \'in\' argument: %s'
                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is '
                   'returned: %s'
                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))

        self.b(' * @error: If not %NULL, used to return errors if %FALSE ')
        self.b(' *  is returned')
        self.b(' * @loop: If not %NULL, set before re-entering ')
        self.b(' *  the main loop, to point to a #GMainLoop ')
        self.b(' *  which can be used to cancel this call with ')
        self.b(' *  g_main_loop_quit(), causing a return of ')
        self.b(' *  %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
        self.b(' *')
        self.b(' * Call the method %s and run the main loop' % member)
        self.b(' * until it returns. Before calling this method, you must')
        self.b(' * add a reference to any borrowed objects you need to keep,')
        self.b(' * and generally ensure that everything is in a consistent')
        self.b(' * state.')
        self.b(' *')
        self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
        self.b(' *')
        self.b(' * Returns: TRUE on success, FALSE and sets @error on error')
        self.b(' */')
        self.b('gboolean\n%s_%s_run_%s (%sproxy,'
               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
        self.b('    gint timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.h('    %s%s%s,' % (const, ctype, name))
            self.b('    %s%s%s,' % (const, ctype, name))

        for arg in out_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            self.h('    %s*%s,' % (ctype, name))
            self.b('    %s*%s,' % (ctype, name))

        self.h('    GError **error,')
        self.h('    GMainLoop **loop);')
        self.h('')

        self.b('    GError **error,')
        self.b('    GMainLoop **loop)')
        self.b('{')
        self.b('  DBusGProxy *iface;')
        self.b('  GQuark interface = %s;' % self.get_iface_quark())
        self.b('  TpProxyPendingCall *pc;')
        self.b('  _%s_%s_run_state_%s state = {'
               % (self.prefix_lc, iface_lc, member_lc))
        self.b('      NULL /* loop */, error,')

        for arg in out_args:
            name, info, tp_type, elt = arg

            self.b('    %s,' % name)

        self.b('      FALSE /* completed */, FALSE /* success */ };')
        self.b('')
        self.b('  g_return_val_if_fail (%s (proxy), FALSE);'
               % self.proxy_assert)
        self.b('')
        self.b('  iface = tp_proxy_borrow_interface_by_id')
        self.b('       ((TpProxy *) proxy, interface, error);')
        self.b('')
        self.b('  if (iface == NULL)')
        self.b('    return FALSE;')
        self.b('')
        self.b('  state.loop = g_main_loop_new (NULL, FALSE);')
        self.b('')
        self.b('  pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
        self.b('      interface, "%s", iface,' % member)
        self.b('      %s,' % reentrant_invoke)
        self.b('      NULL, &state, NULL, NULL, TRUE);')
        self.b('')
        self.b('  if (loop != NULL)')
        self.b('    *loop = state.loop;')
        self.b('')
        self.b('  tp_proxy_pending_call_v0_take_pending_call (pc,')
        self.b('      dbus_g_proxy_begin_call_with_timeout (iface,')
        self.b('          "%s",' % member)
        self.b('          %s,' % collect_callback)
        self.b('          pc,')
        self.b('          tp_proxy_pending_call_v0_completed,')
        self.b('          timeout_ms,')

        for arg in in_args:
            name, info, tp_type, elt = arg
            ctype, gtype, marshaller, pointer = info

            const = pointer and 'const ' or ''

            self.b('              %s, %s,' % (gtype, name))

        self.b('          G_TYPE_INVALID));')
        self.b('')
        self.b('  if (!state.completed)')
        self.b('    g_main_loop_run (state.loop);')
        self.b('')
        self.b('  if (!state.completed)')
        self.b('    tp_proxy_pending_call_cancel (pc);')
        self.b('')
        self.b('  if (loop != NULL)')
        self.b('    *loop = NULL;')
        self.b('')
        self.b('  g_main_loop_unref (state.loop);')
        self.b('')
        self.b('  return state.success;')
        self.b('}')
        self.b('')

        # leave a gap for the end of the method
        self.b('')
        self.h('')