From beb9cd2eb219e04f9872c6a4dd743d5d1c36b4b1 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 13 Jun 2005 03:01:30 +0000 Subject: 2005-06-12 Colin Walters Async signals and various bugfixes and testing by Ross Burton . * glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete. (dbus_gvalue_genmarshal_name_from_type) (dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c. (dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature. (dbus_g_value_types_init, dbus_gtype_from_signature) (dbus_gtype_from_signature_iter, dbus_gtype_to_signature) (dbus_gtypes_from_arg_signature): New function prototypes. (dbus_gvalue_demarshal): Take context and error arguments. (dbus_gvalue_demarshal_variant): New function. (dbus_gvalue_demarshal_message): New function. (dbus_gvalue_store): Delete. * glib/dbus-gvalue.c: File has been almost entirely rewritten; now we special-case more types such as DBUS_TYPE_SIGNATURE, handle arrays and hash tables correctly, etc. Full support for recursive values is not yet complete. * glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last argument of signal to G_TYPE_POINTER since we now pass a structure. (lookup_g_marshaller): Delete in favor of _dbus_gobject_lookup_marshaller. (marshal_dbus_message_to_g_marshaller): Use _dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message to handle remote signal callbacks. (dbus_g_proxy_new_from_proxy): New function; creates a new DBusGProxy by copying an existing one. (dbus_g_proxy_get_interface, dbus_g_proxy_set_interface) (dbus_g_proxy_get_path): New functions. (dbus_g_proxy_marshal_args_to_message): New function; factored out of existing code. (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments from a varargs array. (dbus_g_proxy_begin_call_internal): New function. (dbus_g_proxy_end_call_internal): New function. (dbus_g_proxy_begin_call): Take GTypes instead of DBus types as arguments; simply invoke dbus_g_proxy_begin_call_internal after collecting args into value array. (dbus_g_proxy_end_call): Take GTypes instead of DBus types; invoke dbus_g_proxy_end_call_internal. (dbus_g_proxy_invoke): Simply invoke begin_call_interanl and end_call_internal. (dbus_g_proxy_call_no_reply): Take GTypes instead of DBus types. (array_free_all): New function. (dbus_g_proxy_add_signal): Take GTypes. * glib/dbus-gobject.h: (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller): Prototype. * glib/dbus-gobject.c: Add a global marshal_table hash which stores mappings from type signatures to marshallers. Change lots of invocations of dbus_gtype_to_dbus_type to dbus_gtype_to_signature. (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (introspect_signals): Fix test for query.return_type. (set_object_property): Update invocation of dbus_gvalue_demarshal. (invoke_object_method): Many changes. Handle asynchronous invocations. Convert arguments with dbus_gvalue_demarshal_message. Handle errors. Use DBusSignatureIter instead of strlen on args. Handle all arguments generically. Special-case variants. (dbus_g_method_return, dbus_g_method_return_error): New function. (DBusGSignalClosure): New structure, closes over signal information. (dbus_g_signal_closure_new): New function. (dbus_g_signal_closure_finalize): New function. (signal_emitter_marshaller): New function; is special marshaller which emits signals on bus. (export_signals): New function; introspects object signals and connects to them. (dbus_g_object_type_install_info): Take GType instead of GObjectClass. (dbus_g_connection_register_g_object): Invoke export_signals. (dbus_g_connection_lookup_g_object): New function. (DBusGFuncSignature) New structure; used for mapping type signatures to marshallers. (funcsig_hash): New function; hashes DBusGFuncSignature. (funcsig_equal): New function; compares DBusGFuncSignature. (_dbus_gobject_lookup_marshaller): New function. (dbus_g_object_register_marshaller): New function; used to register a marshaller at runtime for a particular signature. * glib/dbus-gmain.c (_dbus_gmain_test): Add various tests. * glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC which notes a server method implementation should be asynchronous. * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Call dbus_g_value_types_init. (write_formal_parameters): Use dbus_gtype_from_signature. Handle variants specially. (dbus_g_type_get_lookup_function): Turn GType into an invocation of a lookup function. (write_args_for_direction): Use dbus_g_type_get_lookup_function. (write_untyped_out_args): New method; write output arguments. (write_formal_declarations_for_direction): Function for writing prototypes. (write_formal_parameters_for_direction): Function for writing implementations. (write_typed_args_for_direction): Function for writing arguments prefixed with GTypes. (write_async_method_client): Write out async version of method. * glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h. (dbus_g_type_get_marshal_name): Move mapping from GType to marshal name into here. (dbus_g_type_get_c_name): Move into here. (compute_marshaller): Convert signature to type with dbus_gtype_from_signature, use dbus_g_type_get_marshal_name. (compute_marshaller_name): Ditto. (compute_marshaller): Handle async signal annotations. (gather_marshallers): Return if we don't have a known prefix. (generate_glue): Collect introspection blob here, and write all of the blob at the end. This allows an object with multiple interfaces to work. Mark async methods in introspection blob. * glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add dbus-gtype-specialized.c, dbus-gtype-specialized.h, dbus-gvalue-utils.h, dbus-gvalue-utils.c. * dbus/dbus-glib.h: Don't include dbus-protocol.h; this avoids people accidentally using DBUS_TYPE_* which should not be necessary anymore. Do include dbus-gtype-specialized.h, which are utilities for GLib container types. Add various #defines for types such as DBUS_TYPE_G_BOOLEAN_ARRAY. (DBusGValueIterator, DBusGValue): Define, not fully used yet. (dbus_g_value_get_g_type): Type for recursive value. (dbus_g_value_open, dbus_g_value_iterator_get_value) (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) (dbus_g_value_free): Prototypes. (dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype. (dbus_g_proxy_set_interface): Prototype. (dbus_g_proxy_begin_call, dbus_g_proxy_end_call) (dbus_g_proxy_call_no_reply): Take GLib types instead of DBus types. (dbus_g_proxy_get_path, dbus_g_proxy_get_interface): Accessors. (DBusGAsyncData, DBusGMethodInvocation): Structures for doing async invocations. (dbus_g_method_return, dbus_g_method_return_error): Prototypes. * doc/dbus-tutorial.xml: Update GLib section. * tools/dbus-viewer.c (load_child_nodes): Update for new invocation type of dbus_g_proxy_end_call. (load_from_service_thread_func): Ditto. * tools/print-introspect.c (main): Ditto. * tools/dbus-names-model.c (have_names_notify) (names_model_reload, names_model_set_connection) Use GTypes. * python/Makefile.am (INCLUDES): Define DBUS_COMPILATION, needed since Python bindings use GLib bindings. * test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION. Add --prefix argument. * tools/Makefile.am: Define DBUS_COMPILATION. Remove unneeded --ignore-unsupported arg. * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: * test/glib/test-dbus-glib.c: Add many more tests. --- glib/dbus-binding-tool-glib.c | 642 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 549 insertions(+), 93 deletions(-) (limited to 'glib/dbus-binding-tool-glib.c') diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c index 3c86d81f..76536aad 100644 --- a/glib/dbus-binding-tool-glib.c +++ b/glib/dbus-binding-tool-glib.c @@ -26,6 +26,7 @@ #include "dbus-gparser.h" #include "dbus-gutils.h" #include "dbus-gvalue.h" +#include "dbus-gvalue-utils.h" #include "dbus-glib-tool.h" #include "dbus-binding-tool-glib.h" #include @@ -45,12 +46,67 @@ typedef struct GError **error; GHashTable *generated; + GString *blob; + guint count; } DBusBindingToolCData; static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error); static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error); static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error); +static const char * +dbus_g_type_get_marshal_name (GType gtype) +{ + switch (G_TYPE_FUNDAMENTAL (gtype)) + { + case G_TYPE_BOOLEAN: + return "BOOLEAN"; + case G_TYPE_UCHAR: + return "UCHAR"; + case G_TYPE_INT: + return "INT"; + case G_TYPE_UINT: + return "UINT"; + case G_TYPE_INT64: + return "INT64"; + case G_TYPE_UINT64: + return "UINT64"; + case G_TYPE_DOUBLE: + return "DOUBLE"; + case G_TYPE_STRING: + return "STRING"; + case G_TYPE_POINTER: + return "POINTER"; + case G_TYPE_BOXED: + return "BOXED"; + case G_TYPE_OBJECT: + return "OBJECT"; + default: + return NULL; + } +} + +/* This entire function is kind of...ugh. */ +static const char * +dbus_g_type_get_c_name (GType gtype) +{ + if (dbus_g_type_is_collection (gtype)) + return "GArray"; + if (dbus_g_type_is_map (gtype)) + return "GHashTable"; + + if (g_type_is_a (gtype, G_TYPE_STRING)) + return "char *"; + + /* This one is even more hacky...we get an extra * + * because G_TYPE_STRV is a G_TYPE_BOXED + */ + if (g_type_is_a (gtype, G_TYPE_STRV)) + return "char *"; + + return g_type_name (gtype); +} + static char * compute_marshaller (MethodInfo *method, GError **error) { @@ -71,9 +127,10 @@ compute_marshaller (MethodInfo *method, GError **error) if (arg_info_get_direction (arg) == ARG_IN) { const char *marshal_name; + GType gtype; - marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg)); - if (!marshal_name) + gtype = dbus_gtype_from_signature (arg_info_get_type (arg), FALSE); + if (gtype == G_TYPE_INVALID) { g_set_error (error, DBUS_BINDING_TOOL_ERROR, @@ -83,6 +140,10 @@ compute_marshaller (MethodInfo *method, GError **error) g_string_free (ret, TRUE); return NULL; } + + marshal_name = dbus_g_type_get_marshal_name (gtype); + g_assert (marshal_name); + if (!first) g_string_append (ret, ","); else @@ -91,6 +152,12 @@ compute_marshaller (MethodInfo *method, GError **error) } } + if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) { + if (!first) + g_string_append (ret, ","); + g_string_append (ret, "POINTER"); + first = FALSE; + } else { /* Append pointer for each out arg storage */ for (elt = method_info_get_args (method); elt; elt = elt->next) { @@ -105,12 +172,13 @@ compute_marshaller (MethodInfo *method, GError **error) g_string_append (ret, "POINTER"); } } - /* Final GError parameter */ if (!first) g_string_append (ret, ","); g_string_append (ret, "POINTER"); + } + return g_string_free (ret, FALSE); } @@ -136,25 +204,31 @@ compute_marshaller_name (MethodInfo *method, const char *prefix, GError **error) { const char *marshal_name; const char *type; + GType gtype; type = arg_info_get_type (arg); - marshal_name = dbus_gvalue_genmarshal_name_from_type (type); - if (!marshal_name) + gtype = dbus_gtype_from_signature (type, FALSE); + if (gtype == G_TYPE_INVALID) { g_set_error (error, DBUS_BINDING_TOOL_ERROR, DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, - _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"), + _("Unsupported conversion from D-BUS type %s to glib type"), type); g_string_free (ret, TRUE); return NULL; } + marshal_name = dbus_g_type_get_marshal_name (gtype); + g_assert (marshal_name != NULL); g_string_append (ret, "_"); - g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (type)); + g_string_append (ret, marshal_name); } } + if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) { + g_string_append (ret, "_POINTER"); + } else { /* Append pointer for each out arg storage */ for (elt = method_info_get_args (method); elt; elt = elt->next) { @@ -165,9 +239,9 @@ compute_marshaller_name (MethodInfo *method, const char *prefix, GError **error) g_string_append (ret, "_POINTER"); } } - /* Final GError parameter */ g_string_append (ret, "_POINTER"); + } return g_string_free (ret, FALSE); } @@ -210,7 +284,8 @@ gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error) interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL); if (interface_c_name == NULL) { - return TRUE; + if (!data->prefix) + return TRUE; } methods = interface_info_get_methods (interface); @@ -223,10 +298,6 @@ gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error) char *marshaller_name; method = (MethodInfo *) tmp->data; - if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL) == NULL) - { - continue; - } marshaller_name = compute_marshaller (method, error); if (!marshaller_name) @@ -291,12 +362,56 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) { if (base_info_get_type (base) == INFO_TYPE_NODE) { + GString *object_introspection_data_blob; + GIOChannel *channel; + guint i; + + channel = data->channel; + + object_introspection_data_blob = g_string_new_len ("", 0); + + data->blob = object_introspection_data_blob; + data->count = 0; + + if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, data->prefix)) + goto io_lose; + if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base), data, error)) return FALSE; if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base), data, error)) return FALSE; + + WRITE_OR_LOSE ("};\n\n"); + + /* Information about the object. */ + + if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n", + channel, error, data->prefix)) + goto io_lose; + WRITE_OR_LOSE (" 0,\n"); + if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, data->prefix)) + goto io_lose; + if (!write_printf_to_iochannel (" %d,\n", channel, error, data->count)) + goto io_lose; + WRITE_OR_LOSE(" \""); + for (i = 0; i < object_introspection_data_blob->len; i++) + { + if (object_introspection_data_blob->str[i] != '\0') + { + if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error)) + return FALSE; + } + else + { + if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error)) + return FALSE; + } + } + WRITE_OR_LOSE ("\"\n};\n\n"); + + g_string_free (object_introspection_data_blob, TRUE); } else { @@ -304,41 +419,43 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) InterfaceInfo *interface; GSList *methods; GSList *tmp; - gsize i; - int count; const char *interface_c_name; GString *object_introspection_data_blob; channel = data->channel; + object_introspection_data_blob = data->blob; interface = (InterfaceInfo *) base; interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL); if (interface_c_name == NULL) { - return TRUE; + if (data->prefix == NULL) + return TRUE; + interface_c_name = data->prefix; } - object_introspection_data_blob = g_string_new_len ("", 0); - methods = interface_info_get_methods (interface); - count = 0; /* Table of marshalled methods. */ - if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL))) - goto io_lose; for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp)) { MethodInfo *method; char *marshaller_name; - const char *method_c_name; + char *method_c_name; + gboolean async = FALSE; GSList *args; method = (MethodInfo *) tmp->data; - method_c_name = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL); + method_c_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL)); if (method_c_name == NULL) - { - continue; + { + char *method_name_uscored; + method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method)); + method_c_name = g_strdup_printf ("%s_%s", + interface_c_name, + method_name_uscored); + g_free (method_name_uscored); } if (!write_printf_to_iochannel (" { (GCallback) %s, ", channel, error, @@ -357,6 +474,9 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) goto io_lose; } + if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) + async = TRUE; + /* Object method data blob format: * \0\0(\0\0\0)*\0 */ @@ -367,6 +487,9 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) g_string_append (object_introspection_data_blob, method_info_get_name (method)); g_string_append_c (object_introspection_data_blob, '\0'); + g_string_append_c (object_introspection_data_blob, async ? 'A' : 'S'); + g_string_append_c (object_introspection_data_blob, '\0'); + for (args = method_info_get_args (method); args; args = args->next) { ArgInfo *arg; @@ -400,37 +523,8 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) g_string_append_c (object_introspection_data_blob, '\0'); - count++; + data->count++; } - WRITE_OR_LOSE ("};\n\n"); - - /* Information about the object. */ - - if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n", - channel, error, interface_c_name)) - goto io_lose; - WRITE_OR_LOSE (" 0,\n"); - if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, interface_c_name)) - goto io_lose; - if (!write_printf_to_iochannel (" %d,\n", channel, error, count)) - goto io_lose; - WRITE_OR_LOSE(" \""); - for (i = 0; i < object_introspection_data_blob->len; i++) - { - if (object_introspection_data_blob->str[i] != '\0') - { - if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error)) - return FALSE; - } - else - { - if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error)) - return FALSE; - } - } - WRITE_OR_LOSE ("\"\n};\n\n"); - - g_string_free (object_introspection_data_blob, TRUE); } return TRUE; io_lose: @@ -471,6 +565,8 @@ dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, const memset (&data, 0, sizeof (data)); + dbus_g_value_types_init (); + data.prefix = prefix; data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); data.error = error; @@ -607,6 +703,8 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c { ArgInfo *arg; const char *type_str; + const char *type_suffix; + GType gtype; int direction; arg = args->data; @@ -615,9 +713,8 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c direction = arg_info_get_direction (arg); - type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN); - - if (!type_str) + gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); + if (gtype == G_TYPE_INVALID) { g_set_error (error, DBUS_BINDING_TOOL_ERROR, @@ -628,18 +725,37 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c interface_info_get_name (iface)); return FALSE; } + type_str = dbus_g_type_get_c_name (gtype); + g_assert (type_str); + /* Variants are special...*/ + if (gtype == G_TYPE_VALUE) + { + if (direction == ARG_IN) + type_suffix = "*"; + else + type_suffix = ""; + } + else if ((g_type_is_a (gtype, G_TYPE_BOXED) + || g_type_is_a (gtype, G_TYPE_OBJECT) + || g_type_is_a (gtype, G_TYPE_POINTER))) + type_suffix = "*"; + else + type_suffix = ""; + switch (direction) { case ARG_IN: - if (!write_printf_to_iochannel ("%s IN_%s", channel, error, + if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error, type_str, + type_suffix, arg_info_get_name (arg))) goto io_lose; break; case ARG_OUT: - if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error, + if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error, type_str, + type_suffix, arg_info_get_name (arg))) goto io_lose; break; @@ -653,32 +769,71 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c return FALSE; } -static gboolean -write_args_sig_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error) +#define MAP_FUNDAMENTAL(NAME) \ + case G_TYPE_ ## NAME: \ + return g_strdup ("G_TYPE_" #NAME); +#define MAP_KNOWN(NAME) \ + if (gtype == NAME) \ + return g_strdup (#NAME) +static char * +dbus_g_type_get_lookup_function (GType gtype) { - GSList *args; - - WRITE_OR_LOSE ("\""); - - for (args = method_info_get_args (method); args; args = args->next) + char *type_lookup; + switch (gtype) { - ArgInfo *arg; - - arg = args->data; - - if (direction != arg_info_get_direction (arg)) - continue; - - if (!write_printf_to_iochannel ("%s", channel, error, arg_info_get_type (arg))) - goto io_lose; + MAP_FUNDAMENTAL(CHAR); + MAP_FUNDAMENTAL(UCHAR); + MAP_FUNDAMENTAL(BOOLEAN); + MAP_FUNDAMENTAL(LONG); + MAP_FUNDAMENTAL(ULONG); + MAP_FUNDAMENTAL(INT); + MAP_FUNDAMENTAL(UINT); + MAP_FUNDAMENTAL(INT64); + MAP_FUNDAMENTAL(UINT64); + MAP_FUNDAMENTAL(FLOAT); + MAP_FUNDAMENTAL(DOUBLE); + MAP_FUNDAMENTAL(STRING); } - - WRITE_OR_LOSE ("\", "); - - return TRUE; - io_lose: - return FALSE; + if (dbus_g_type_is_collection (gtype)) + { + GType elt_gtype; + char *sublookup; + + elt_gtype = dbus_g_type_get_collection_specialization (gtype); + sublookup = dbus_g_type_get_lookup_function (elt_gtype); + g_assert (sublookup); + type_lookup = g_strdup_printf ("dbus_g_type_get_collection (\"GArray\", %s)", + sublookup); + g_free (sublookup); + return type_lookup; + } + else if (dbus_g_type_is_map (gtype)) + { + GType key_gtype; + char *key_lookup; + GType value_gtype; + char *value_lookup; + + key_gtype = dbus_g_type_get_map_key_specialization (gtype); + value_gtype = dbus_g_type_get_map_value_specialization (gtype); + key_lookup = dbus_g_type_get_lookup_function (key_gtype); + g_assert (key_lookup); + value_lookup = dbus_g_type_get_lookup_function (value_gtype); + g_assert (value_lookup); + type_lookup = g_strdup_printf ("dbus_g_type_get_map (\"GHashTable\", %s, %s)", + key_lookup, value_lookup); + g_free (key_lookup); + g_free (value_lookup); + return type_lookup; + } + MAP_KNOWN(G_TYPE_VALUE); + MAP_KNOWN(G_TYPE_STRV); + MAP_KNOWN(DBUS_TYPE_G_PROXY); + MAP_KNOWN(DBUS_TYPE_G_PROXY_ARRAY); + return NULL; } +#undef MAP_FUNDAMENTAL +#undef MAP_KNOWN static gboolean write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error) @@ -688,25 +843,38 @@ write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel * for (args = method_info_get_args (method); args; args = args->next) { ArgInfo *arg; + GType gtype; + char *type_lookup; arg = args->data; if (direction != arg_info_get_direction (arg)) continue; + gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); + g_assert (gtype != G_TYPE_INVALID); + type_lookup = dbus_g_type_get_lookup_function (gtype); + g_assert (type_lookup != NULL); + switch (direction) { + case ARG_IN: - if (!write_printf_to_iochannel ("IN_%s, ", channel, error, arg_info_get_name (arg))) + if (!write_printf_to_iochannel ("%s, IN_%s, ", channel, error, + type_lookup, + arg_info_get_name (arg))) goto io_lose; break; case ARG_OUT: - if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, arg_info_get_name (arg))) + if (!write_printf_to_iochannel ("%s, OUT_%s, ", channel, error, + type_lookup, + arg_info_get_name (arg))) goto io_lose; break; case ARG_INVALID: break; } + g_free (type_lookup); } return TRUE; @@ -722,14 +890,302 @@ check_supported_parameters (MethodInfo *method) for (args = method_info_get_args (method); args; args = args->next) { ArgInfo *arg; + GType gtype; + arg = args->data; - if (!dbus_gvalue_ctype_from_type (arg_info_get_type (arg), - arg_info_get_direction (arg))) + gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); + if (gtype == G_TYPE_INVALID) return FALSE; } return TRUE; } +static gboolean +write_untyped_out_args (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error) +{ + GSList *args; + + for (args = method_info_get_args (method); args; args = args->next) + { + ArgInfo *arg; + + arg = args->data; + if (arg_info_get_direction (arg) != ARG_OUT) + continue; + + if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, + arg_info_get_name (arg))) + goto io_lose; + } + + return TRUE; + io_lose: + return FALSE; +} + +static gboolean +write_formal_declarations_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error) + { + GSList *args; + + for (args = method_info_get_args (method); args; args = args->next) + { + ArgInfo *arg; + GType gtype; + const char *type_str, *type_suffix; + int dir; + + arg = args->data; + + dir = arg_info_get_direction (arg); + + gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); + type_str = dbus_g_type_get_c_name (gtype); + + if (!type_str) + { + g_set_error (error, + DBUS_BINDING_TOOL_ERROR, + DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, + _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""), + arg_info_get_type (arg), + method_info_get_name (method), + interface_info_get_name (iface)); + return FALSE; + } + + /* Variants are special...*/ + if (gtype == G_TYPE_VALUE) + { + if (direction == ARG_IN) + type_suffix = "*"; + else + type_suffix = ""; + } + else if ((g_type_is_a (gtype, G_TYPE_BOXED) + || g_type_is_a (gtype, G_TYPE_OBJECT) + || g_type_is_a (gtype, G_TYPE_POINTER))) + type_suffix = "*"; + else + type_suffix = ""; + + if (direction != dir) + continue; + + switch (dir) + { + case ARG_IN: + if (!write_printf_to_iochannel (" %s%s IN_%s;\n", channel, error, + type_str, type_suffix, + arg_info_get_name (arg))) + goto io_lose; + break; + case ARG_OUT: + if (!write_printf_to_iochannel (" %s%s OUT_%s;\n", channel, error, + type_str, type_suffix, + arg_info_get_name (arg))) + goto io_lose; + break; + case ARG_INVALID: + break; + } + } + return TRUE; + io_lose: + return FALSE; + } + +static gboolean +write_formal_parameters_for_direction (InterfaceInfo *iface, MethodInfo *method, int dir, GIOChannel *channel, GError **error) +{ + GSList *args; + + for (args = method_info_get_args (method); args; args = args->next) + { + ArgInfo *arg; + const char *type_str; + const char *type_suffix; + GType gtype; + int direction; + + arg = args->data; + + direction = arg_info_get_direction (arg); + if (dir != direction) continue; + + WRITE_OR_LOSE (", "); + + gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); + type_str = dbus_g_type_get_c_name (gtype); + /* Variants are special...*/ + if (gtype == G_TYPE_VALUE) + { + if (direction == ARG_IN) + type_suffix = "*"; + else + type_suffix = ""; + } + else if ((g_type_is_a (gtype, G_TYPE_BOXED) + || g_type_is_a (gtype, G_TYPE_OBJECT) + || g_type_is_a (gtype, G_TYPE_POINTER))) + type_suffix = "*"; + else + type_suffix = ""; + + if (!type_str) + { + g_set_error (error, + DBUS_BINDING_TOOL_ERROR, + DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, + _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""), + arg_info_get_type (arg), + method_info_get_name (method), + interface_info_get_name (iface)); + return FALSE; + } + + switch (direction) + { + case ARG_IN: + if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error, + type_str, + type_suffix, + arg_info_get_name (arg))) + goto io_lose; + break; + case ARG_OUT: + if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error, + type_str, + type_suffix, + arg_info_get_name (arg))) + goto io_lose; + break; + case ARG_INVALID: + break; + } + } + return TRUE; + io_lose: + return FALSE; +} + +static gboolean +write_typed_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error) + { + GSList *args; + + for (args = method_info_get_args (method); args; args = args->next) + { + ArgInfo *arg; + int dir; + GType gtype; + const char *type_lookup; + + arg = args->data; + + dir = arg_info_get_direction (arg); + + if (dir != direction) + continue; + + gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); + type_lookup = dbus_g_type_get_lookup_function (gtype); + + if (!write_printf_to_iochannel ("%s, &%s_%s, ", channel, error, type_lookup, direction == ARG_IN ? "IN" : "OUT", arg_info_get_name (arg))) + goto io_lose; + } + return TRUE; + io_lose: + return FALSE; +} + +static gboolean +write_async_method_client (GIOChannel *channel, InterfaceInfo *interface, MethodInfo *method, GError **error) +{ + char *method_name, *iface_prefix; + iface_prefix = iface_to_c_prefix (interface_info_get_name (interface)); + method_name = compute_client_method_name (iface_prefix, method); + + /* Write the typedef for the client callback */ + if (!write_printf_to_iochannel ("typedef void (*%s_reply) (", channel, error, method_name)) + goto io_lose; + { + GSList *args; + for (args = method_info_get_args (method); args; args = args->next) + { + ArgInfo *arg; + const char *type_suffix, *type_str; + GType gtype; + + arg = args->data; + + if (arg_info_get_direction (arg) != ARG_OUT) + continue; + gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); + if (gtype != G_TYPE_VALUE && (g_type_is_a (gtype, G_TYPE_BOXED) + || g_type_is_a (gtype, G_TYPE_OBJECT) + || g_type_is_a (gtype, G_TYPE_POINTER))) + type_suffix = "*"; + else + type_suffix = ""; + type_str = dbus_g_type_get_c_name (dbus_gtype_from_signature (arg_info_get_type (arg), TRUE)); + if (!write_printf_to_iochannel ("%s %sOUT_%s, ", channel, error, type_str, type_suffix, arg_info_get_name (arg))) + goto io_lose; + } + } + WRITE_OR_LOSE ("GError *error, gpointer userdata);\n\n"); + + + /* Write the callback when the call returns */ + WRITE_OR_LOSE ("static void\n"); + if (!write_printf_to_iochannel ("%s_async_callback (DBusGPendingCall *pending, DBusGAsyncData *data)\n", channel, error, method_name)) + goto io_lose; + WRITE_OR_LOSE ("{\n"); + WRITE_OR_LOSE (" GError *error = NULL;\n"); + if (!write_formal_declarations_for_direction (interface, method, channel, ARG_OUT, error)) + goto io_lose; + WRITE_OR_LOSE (" dbus_g_proxy_end_call (data->proxy, pending, &error, "); + if (!write_typed_args_for_direction (interface, method, channel, ARG_OUT, error)) + goto io_lose; + WRITE_OR_LOSE("G_TYPE_INVALID);\n"); + if (!write_printf_to_iochannel (" (*(%s_reply)data->cb) (", channel, error, method_name)) + goto io_lose; + if (!write_untyped_out_args (interface, method, channel, error)) + goto io_lose; + WRITE_OR_LOSE ("error, data->userdata);\n"); + WRITE_OR_LOSE (" return;\n}\n\n"); + + + /* Write the main wrapper function */ + WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n"); + if (!write_printf_to_iochannel ("%s_async (DBusGProxy *proxy", channel, error, + method_name)) + goto io_lose; + if (!write_formal_parameters_for_direction (interface, method, ARG_IN, channel, error)) + goto io_lose; + + if (!write_printf_to_iochannel (", %s_reply callback, gpointer userdata)\n\n", channel, error, method_name)) + goto io_lose; + + WRITE_OR_LOSE ("{\n"); + WRITE_OR_LOSE (" DBusGPendingCall *pending;\n DBusGAsyncData *stuff;\n stuff = g_new (DBusGAsyncData, 1);\n stuff->proxy = proxy;\n stuff->cb = callback;\n stuff->userdata = userdata;\n"); + if (!write_printf_to_iochannel (" pending = dbus_g_proxy_begin_call (proxy, \"%s\", ", channel, error, method_info_get_name (method))) + goto io_lose; + if (!write_args_for_direction (interface, method, channel, ARG_IN, error)) + goto io_lose; + WRITE_OR_LOSE ("G_TYPE_INVALID);\n"); + + if (!write_printf_to_iochannel (" dbus_g_pending_call_set_notify(pending, (DBusGPendingCallNotify)%s_async_callback, stuff, g_free);\n", channel, error, method_name)) + goto io_lose; + + WRITE_OR_LOSE (" return TRUE;\n}\n\n"); + + g_free (method_name); + return TRUE; + io_lose: + return FALSE; + } + static gboolean generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error) { @@ -818,21 +1274,19 @@ generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error method_info_get_name (method))) goto io_lose; - if (!write_args_sig_for_direction (interface, method, channel, ARG_IN, error)) - goto io_lose; - - if (!write_args_sig_for_direction (interface, method, channel, ARG_OUT, error)) - goto io_lose; - WRITE_OR_LOSE ("error, "); if (!write_args_for_direction (interface, method, channel, ARG_IN, error)) goto io_lose; + WRITE_OR_LOSE ("G_TYPE_INVALID, "); + if (!write_args_for_direction (interface, method, channel, ARG_OUT, error)) goto io_lose; - WRITE_OR_LOSE ("NULL);\n}\n\n"); + WRITE_OR_LOSE ("G_TYPE_INVALID);\n}\n\n"); + + write_async_method_client (channel, interface, method, error); } if (!write_printf_to_iochannel ("#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_%s */\n\n", channel, error, iface_prefix)) @@ -853,6 +1307,8 @@ dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gbool DBusBindingToolCData data; gboolean ret; + dbus_g_value_types_init (); + memset (&data, 0, sizeof (data)); data.channel = channel; -- cgit