def do_signal_add(self, signal): marshaller_items = [] gtypes = [] for i in signal.getElementsByTagName('arg'): name = i.getAttribute('name') type = i.getAttribute('type') info = type_to_gtype(type) # type, GType, STRING, is a pointer gtypes.append(info[1]) self.b(' dbus_g_proxy_add_signal (proxy, "%s",' % signal.getAttribute('name')) for gtype in gtypes: self.b(' %s,' % gtype) self.b(' G_TYPE_INVALID);')
def types_to_gtypes(types): return [type_to_gtype(t)[1] for t in types]
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('')
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_##x (\\' % (self.prefix_, self.node_name_lc)) self.d(' * klass, my_object_##x)') for method in methods: class_member_name = method.getAttribute('tp:name-for-bindings') class_member_name = class_member_name.lower() self.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
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('')
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('')
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('')