summaryrefslogtreecommitdiffstats
path: root/glib
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2005-02-17 17:41:30 +0000
committerColin Walters <walters@verbum.org>2005-02-17 17:41:30 +0000
commit03f6615eaccc2c1f84d4252e5a627a2ac86d41d9 (patch)
tree6b7867f43ae7858f2aae4a208e01d10dd3d752a3 /glib
parent9e4450872a6861bd93a01dabe14d2d16f6c84d3f (diff)
2005-02-17 Colin Walters <walters@verbum.org>
This patch is based on initial work from Paul Kuliniewicz <kuliniew@purdue.edu>. * glib/dbus-gvalue.c (dbus_gvalue_init): New function; move initialization of GValue from dbus type to here. (dbus_gvalue_genmarshal_name_from_type): New function; generates a string for the "glib-genmarshal" program from a DBus type. (dbus_gvalue_binding_type_from_type): New function; turns a DBus type into the C name for it we use in the glib bindings. (dbus_gvalue_ctype_from_type): New function; maps a DBus type into a glib C type (not GValue). (dbus_gvalue_demarshal): invoke dbus_gvalue_init. * glib/dbus-gutils.c (_dbus_gutils_wincaps_to_uscore): Moved here from dbus-gobject.c. * glib/dbus-gutils.h: Prototype it. * glib/dbus-gproxy.c: Include new dbus-gobject.h. (marshal_dbus_message_to_g_marshaller): Use new shared function dbus_glib_marshal_dbus_message_to_gvalue_array. * glib/dbus-gparser.c (parse_interface, parse_method): Handle c_name attribute. Will be changed once we have annotations. * glib/dbus-gobject.c: Change info_hash_mutex from GStaticMutex to GStaticRWLock. Callers updated. (wincaps_to_uscore): Move to dbus-gutils.c. Callers updated. (string_table_next): New function for iterating over zero-terminated string value array. (string_table_lookup): New function; retrieves specific entry in array. (get_method_data): New function; look up method data in object data chunk. (object_error_domain_prefix_from_object_info) (object_error_code_from_object_info): New functions, but not implemented yet. (method_interface_from_object_info): New function; retrieve interface name. (method_name_from_object_info): New function; retrieve method name. (method_arg_info_from_object_info): New function; retrieve argument data. (arg_iterate): New function; iterates over serialized argument data. (method_dir_signature_from_object_info): New function; returns a GString holding type signature for arguments for just one direction (input or output). (method_input_signature_from_object_info) (method_output_signature_from_object_info): New functions. (dbus_glib_marshal_dbus_message_to_gvalue_array): New shared function; converts dbus message arguments into a GValue array. Used for both signal handling and method invocation. (struct DBusGlibWriteIterfaceData): New utility structure. (write_interface): New function; generate introspection XML for an interface. (introspect_interfaces): New function; gathers all interface->methods, generates introspection XML for them. (handle_introspect): Invoke introspect_interfaces. (get_object_property): Be sure to zero-initalize stack-allocated GValue. (lookup_object_and_method): New function; examines an incoming message and attempts to match it up (via interface, method name, and argument signature) with a known object and method. (gerror_domaincode_to_dbus_error_name): New function; converts a GError domain and code into a DBus error name. Needs GError data added to object introspection to work well. (gerror_to_dbus_error_message): Creates a DBusMessage error return from GError. (invoke_object_method): New function to invoke an object method looked up via lookup_object_and_method. Parses the incoming message, turns it into a GValue array, then invokes the marshaller specified in the DBusGMethodInfo. Creates a new message with either return values or error message as appropriate. (gobject_message_function): Invoke lookup_object_and_method and invoke_object_method. * glib/dbus-glib-tool.c: Include dbus-binding-tool-glib.h. (enum DBusBindingOutputMode): New enum for binding output modes. (pretty_print): Print binding names. (dbus_binding_tool_error_quark): GError bits. (version): Fix typo. (main): Create GIOChannel for output. Parse new --mode argument, possible values are "pretty-print", "glib-server", "glib-client". Use mode to invoke appropriate function. * glib/dbus-gobject.h: Prototype dbus_glib_marshal_dbus_message_to_gvalue_array. * glib/dbus-glib-tool.h: New header, just includes GError bits for now. * glib/dbus-gidl.c (struct InterfaceInfo): Add bindings hashtable; maps binding style to name. (struct MethodInfo): Ditto. (get_hash_keys, get_hash_key): Utility function, returns keys for a GHashTable. (interface_info_new, method_info_new): Initialize bindings. (interface_info_unref, method_info_unref): Destroy bindings. (method_info_get_binding_names, method_info_get_binding_name) (interface_info_get_binding_names, interface_info_get_binding_name): Functions for retrieving binding names. (method_info_set_binding_name, interface_info_set_binding_name): Functions for setting binding names. * glib/dbus-binding-tool-glib.h: New file, has prototypes for glib binding generation. * glib/dbus-binding-tool-glib.c: New file, implements server-side and client-side glib glue generation. * glib/Makefile.am (dbus_binding_tool_SOURCES): Add dbus-binding-tool-glib.c, dbus-binding-tool-glib.h, dbus-glib-tool.h. * dbus/dbus-glib.h (struct DBusGMethodMarshaller): Remove in favor of using GClosureMarshal directly. (struct DBusGObjectInfo): Add n_infos member. * test/glib/test-service-glib.xml: New file; contains introspection data for MyTestObject used in test-service-glib.c. * test/glib/test-service-glib.c (enum MyObjectError): New GError enum. (my_object_do_nothing, my_object_increment, my_object_throw_error) (my_object_uppercase, my_object_many_args): New test methods. (main): Use dbus_g_object_class_install_info to include generated object info. * test/glib/Makefile.am: Generate server-side glue for test-service-glib.c, as well as client-side bindings. * test/glib/test-dbus-glib.c: Include test-service-glib-bindings.h. (main): Activate TestSuiteGLibService; test invoke a bunch of its methods using both the dbus_gproxy stuff directly as well as the generated bindings.
Diffstat (limited to 'glib')
-rw-r--r--glib/Makefile.am3
-rw-r--r--glib/dbus-binding-tool-glib.c812
-rw-r--r--glib/dbus-binding-tool-glib.h33
-rw-r--r--glib/dbus-gidl.c73
-rw-r--r--glib/dbus-gidl.h14
-rw-r--r--glib/dbus-glib-tool.c120
-rw-r--r--glib/dbus-glib-tool.h37
-rw-r--r--glib/dbus-gobject.c596
-rw-r--r--glib/dbus-gobject.h35
-rw-r--r--glib/dbus-gparser.c8
-rw-r--r--glib/dbus-gproxy.c52
-rw-r--r--glib/dbus-gutils.c28
-rw-r--r--glib/dbus-gutils.h1
-rw-r--r--glib/dbus-gvalue.c171
-rw-r--r--glib/dbus-gvalue.h28
15 files changed, 1889 insertions, 122 deletions
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 6a42e6f9..9afe4a72 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -39,6 +39,9 @@ libdbus_gtool_la_LIBADD = libdbus-glib-1.la
bin_PROGRAMS=dbus-binding-tool
dbus_binding_tool_SOURCES = \
+ dbus-binding-tool-glib.h \
+ dbus-binding-tool-glib.c \
+ dbus-glib-tool.h \
dbus-glib-tool.c
dbus_binding_tool_LDADD= -lexpat libdbus-gtool.la
diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c
new file mode 100644
index 00000000..98c13341
--- /dev/null
+++ b/glib/dbus-binding-tool-glib.c
@@ -0,0 +1,812 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-binding-tool-glib.c: Output C glue
+ *
+ * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include "dbus-gidl.h"
+#include "dbus-gparser.h"
+#include "dbus-gutils.h"
+#include "dbus-gvalue.h"
+#include "dbus-glib-tool.h"
+#include "dbus-binding-tool-glib.h"
+#include <glib/gi18n.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MARSHAL_PREFIX "dbus_glib_marshal"
+
+typedef struct
+{
+ GIOChannel *channel;
+
+ GError **error;
+
+ GHashTable *generated;
+} 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 char *
+compute_marshaller (MethodInfo *method, GError **error)
+{
+ GSList *elt;
+ GString *ret;
+ gboolean first;
+
+ /* All methods required to return boolean for now;
+ * will be conditional on method info later */
+ ret = g_string_new ("BOOLEAN:");
+
+ first = TRUE;
+ /* Append input arguments */
+ for (elt = method_info_get_args (method); elt; elt = elt->next)
+ {
+ ArgInfo *arg = elt->data;
+
+ if (arg_info_get_direction (arg) == ARG_IN)
+ {
+ const char *marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg));
+ if (!marshal_name)
+ {
+ g_set_error (error,
+ DBUS_BINDING_TOOL_ERROR,
+ DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+ _("Unsupported conversion from D-BUS type %d to glib-genmarshal type"),
+ arg_info_get_type (arg));
+ g_string_free (ret, TRUE);
+ return NULL;
+ }
+ if (!first)
+ g_string_append (ret, ",");
+ else
+ first = FALSE;
+ g_string_append (ret, marshal_name);
+ }
+ }
+
+ /* Append pointer for each out arg storage */
+ for (elt = method_info_get_args (method); elt; elt = elt->next)
+ {
+ ArgInfo *arg = elt->data;
+
+ if (arg_info_get_direction (arg) == ARG_OUT)
+ {
+ if (!first)
+ g_string_append (ret, ",");
+ else
+ first = FALSE;
+ 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);
+
+}
+
+static char *
+compute_marshaller_name (MethodInfo *method, GError **error)
+{
+ GSList *elt;
+ GString *ret;
+
+ /* All methods required to return boolean for now;
+ * will be conditional on method info later */
+ ret = g_string_new (MARSHAL_PREFIX "_BOOLEAN_");
+
+ /* Append input arguments */
+ for (elt = method_info_get_args (method); elt; elt = elt->next)
+ {
+ ArgInfo *arg = elt->data;
+
+ if (arg_info_get_direction (arg) == ARG_IN)
+ {
+ const char *marshal_name;
+ int type;
+
+ type = arg_info_get_type (arg);
+ marshal_name = dbus_gvalue_genmarshal_name_from_type (type);
+ if (!marshal_name)
+ {
+ g_set_error (error,
+ DBUS_BINDING_TOOL_ERROR,
+ DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+ _("Unsupported conversion from D-BUS type %d to glib-genmarshal type"),
+ type);
+ g_string_free (ret, TRUE);
+ return NULL;
+ }
+
+ g_string_append (ret, "_");
+ g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg)));
+ }
+ }
+
+ /* Append pointer for each out arg storage */
+ for (elt = method_info_get_args (method); elt; elt = elt->next)
+ {
+ ArgInfo *arg = elt->data;
+
+ if (arg_info_get_direction (arg) == ARG_OUT)
+ {
+ g_string_append (ret, "_POINTER");
+ }
+ }
+
+ /* Final GError parameter */
+ g_string_append (ret, "_POINTER");
+
+ return g_string_free (ret, FALSE);
+}
+
+static gboolean
+gather_marshallers_list (GSList *list, DBusBindingToolCData *data, GError **error)
+{
+ GSList *tmp;
+
+ tmp = list;
+ while (tmp != NULL)
+ {
+ if (!gather_marshallers (tmp->data, data, error))
+ return FALSE;
+ tmp = tmp->next;
+ }
+ return TRUE;
+}
+
+static gboolean
+gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
+{
+ if (base_info_get_type (base) == INFO_TYPE_NODE)
+ {
+ if (!gather_marshallers_list (node_info_get_nodes ((NodeInfo *) base),
+ data, error))
+ return FALSE;
+ if (!gather_marshallers_list (node_info_get_interfaces ((NodeInfo *) base),
+ data, error))
+ return FALSE;
+ }
+ else
+ {
+ InterfaceInfo *interface;
+ GSList *methods;
+ GSList *tmp;
+ const char *interface_c_name;
+
+ interface = (InterfaceInfo *) base;
+ interface_c_name = interface_info_get_binding_name (interface, "C");
+ if (interface_c_name == NULL)
+ {
+ return TRUE;
+ }
+
+ methods = interface_info_get_methods (interface);
+
+ /* Generate the necessary marshallers for the methods. */
+
+ for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
+ {
+ MethodInfo *method;
+ char *marshaller_name;
+
+ method = (MethodInfo *) tmp->data;
+ if (method_info_get_binding_name (method, "C") == NULL)
+ {
+ continue;
+ }
+
+ marshaller_name = compute_marshaller (method, error);
+ if (!marshaller_name)
+ return FALSE;
+
+ if (g_hash_table_lookup (data->generated, marshaller_name))
+ {
+ g_free (marshaller_name);
+ continue;
+ }
+
+ g_hash_table_insert (data->generated, marshaller_name, NULL);
+ }
+
+ }
+ return TRUE;
+}
+
+static gboolean
+generate_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
+{
+ GSList *tmp;
+
+ tmp = list;
+ while (tmp != NULL)
+ {
+ if (!generate_glue (tmp->data, data, error))
+ return FALSE;
+ tmp = tmp->next;
+ }
+ return TRUE;
+}
+
+#define WRITE_OR_LOSE(x) do { gsize bytes_written; if (!g_io_channel_write_chars (channel, x, -1, &bytes_written, error)) goto io_lose; } while (0)
+
+static gboolean
+write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, ...)
+{
+ char *str;
+ va_list args;
+ GIOStatus status;
+ gsize written;
+ gboolean ret;
+
+ va_start (args, error);
+
+ str = g_strdup_vprintf (fmt, args);
+ if ((status = g_io_channel_write_chars (channel, str, -1, &written, error)) == G_IO_STATUS_NORMAL)
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ g_free (str);
+
+ va_end (args);
+
+ return ret;
+}
+
+static gboolean
+generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
+{
+ if (base_info_get_type (base) == INFO_TYPE_NODE)
+ {
+ 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;
+ }
+ else
+ {
+ GIOChannel *channel;
+ InterfaceInfo *interface;
+ GSList *methods;
+ GSList *tmp;
+ gsize i;
+ int count;
+ const char *interface_c_name;
+ GString *object_introspection_data_blob;
+
+ channel = data->channel;
+
+ interface = (InterfaceInfo *) base;
+ interface_c_name = interface_info_get_binding_name (interface, "C");
+ if (interface_c_name == NULL)
+ {
+ return TRUE;
+ }
+
+ 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_binding_name (interface, "C")))
+ goto io_lose;
+ for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
+ {
+ MethodInfo *method;
+ char *marshaller_name;
+ const char *method_c_name;
+ GSList *args;
+
+ method = (MethodInfo *) tmp->data;
+ method_c_name = method_info_get_binding_name (method, "C");
+ if (method_c_name == NULL)
+ {
+ continue;
+ }
+
+ if (!write_printf_to_iochannel (" { (GCallback) %s, ", channel, error,
+ method_c_name))
+ goto io_lose;
+
+ marshaller_name = compute_marshaller_name (method, error);
+ if (!marshaller_name)
+ goto io_lose;
+
+ if (!write_printf_to_iochannel ("%s, %d },\n", channel, error,
+ marshaller_name,
+ object_introspection_data_blob->len))
+ {
+ g_free (marshaller_name);
+ goto io_lose;
+ }
+
+ /* Object method data blob format:
+ * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
+ */
+
+ g_string_append (object_introspection_data_blob, interface_info_get_name (interface));
+ g_string_append_c (object_introspection_data_blob, '\0');
+
+ g_string_append (object_introspection_data_blob, method_info_get_name (method));
+ g_string_append_c (object_introspection_data_blob, '\0');
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ char direction;
+
+ arg = args->data;
+
+ g_string_append (object_introspection_data_blob, arg_info_get_name (arg));
+ g_string_append_c (object_introspection_data_blob, '\0');
+
+ switch (arg_info_get_direction (arg))
+ {
+ case ARG_IN:
+ direction = 'I';
+ break;
+ case ARG_OUT:
+ direction = 'O';
+ break;
+ case ARG_INVALID:
+ break;
+ }
+ g_string_append_c (object_introspection_data_blob, direction);
+ g_string_append_c (object_introspection_data_blob, '\0');
+
+ g_string_append_c (object_introspection_data_blob, arg_info_get_type (arg));
+ g_string_append_c (object_introspection_data_blob, '\0');
+ }
+
+ g_string_append_c (object_introspection_data_blob, '\0');
+
+ 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:
+ return FALSE;
+}
+
+static void
+write_marshaller (gpointer key, gpointer value, gpointer user_data)
+{
+ DBusBindingToolCData *data;
+ const char *marshaller;
+ gsize bytes_written;
+
+ data = user_data;
+ marshaller = key;
+
+ if (data->error && *data->error)
+ return;
+
+ if (g_io_channel_write_chars (data->channel, marshaller, -1, &bytes_written, data->error) == G_IO_STATUS_NORMAL)
+ g_io_channel_write_chars (data->channel, "\n", -1, &bytes_written, data->error);
+}
+
+gboolean
+dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, GError **error)
+{
+ gboolean ret;
+ GPtrArray *argv;
+ gint child_stdout;
+ GIOChannel *genmarshal_stdout;
+ GPid child_pid;
+ DBusBindingToolCData data;
+ char *tempfile_name;
+ gint tempfile_fd;
+ GIOStatus iostatus;
+ char buf[4096];
+ gsize bytes_read, bytes_written;
+
+ memset (&data, 0, sizeof (data));
+
+ data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+ data.error = error;
+ genmarshal_stdout = NULL;
+ tempfile_name = NULL;
+
+ if (!gather_marshallers (info, &data, error))
+ goto io_lose;
+
+ tempfile_fd = g_file_open_tmp ("dbus-binding-tool-c-marshallers.XXXXXX",
+ &tempfile_name, error);
+ if (tempfile_fd < 0)
+ goto io_lose;
+
+ data.channel = g_io_channel_unix_new (tempfile_fd);
+ if (!g_io_channel_set_encoding (data.channel, NULL, error))
+ goto io_lose;
+ g_hash_table_foreach (data.generated, write_marshaller, &data);
+ if (error && *error != NULL)
+ {
+ ret = FALSE;
+ g_io_channel_close (data.channel);
+ g_io_channel_unref (data.channel);
+ goto io_lose;
+ }
+
+ g_io_channel_close (data.channel);
+ g_io_channel_unref (data.channel);
+
+ /* Now spawn glib-genmarshal to insert all our required marshallers */
+ argv = g_ptr_array_new ();
+ g_ptr_array_add (argv, "glib-genmarshal");
+ g_ptr_array_add (argv, "--header");
+ g_ptr_array_add (argv, "--body");
+ g_ptr_array_add (argv, "--prefix=" MARSHAL_PREFIX);
+ g_ptr_array_add (argv, tempfile_name);
+ g_ptr_array_add (argv, NULL);
+ if (!g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL,
+ G_SPAWN_SEARCH_PATH,
+ NULL, NULL,
+ &child_pid,
+ NULL,
+ &child_stdout, NULL, error))
+ {
+ g_ptr_array_free (argv, TRUE);
+ goto io_lose;
+ }
+ g_ptr_array_free (argv, TRUE);
+
+ genmarshal_stdout = g_io_channel_unix_new (child_stdout);
+ if (!g_io_channel_set_encoding (genmarshal_stdout, NULL, error))
+ goto io_lose;
+
+ WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
+
+ while ((iostatus = g_io_channel_read_chars (genmarshal_stdout, buf, sizeof (buf),
+ &bytes_read, error)) == G_IO_STATUS_NORMAL)
+ if (g_io_channel_write_chars (channel, buf, bytes_read, &bytes_written, error) != G_IO_STATUS_NORMAL)
+ goto io_lose;
+ if (iostatus != G_IO_STATUS_EOF)
+ goto io_lose;
+
+ g_io_channel_close (genmarshal_stdout);
+
+ WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n");
+
+ g_io_channel_ref (data.channel);
+ data.channel = channel;
+ if (!generate_glue (info, &data, error))
+ goto io_lose;
+
+ ret = TRUE;
+ cleanup:
+ if (tempfile_name)
+ unlink (tempfile_name);
+ g_free (tempfile_name);
+ if (genmarshal_stdout)
+ g_io_channel_unref (genmarshal_stdout);
+ if (data.channel)
+ g_io_channel_unref (data.channel);
+ g_hash_table_destroy (data.generated);
+
+ return ret;
+ io_lose:
+ ret = FALSE;
+ goto cleanup;
+}
+
+static char *
+iface_to_c_prefix (const char *iface)
+{
+ char **components;
+ char **component;
+ GString *ret;
+ gboolean first;
+
+ components = g_strsplit (iface, ".", 0);
+
+ first = TRUE;
+ ret = g_string_new ("");
+ for (component = components; *component; component++)
+ {
+ if (!first)
+ g_string_append_c (ret, '_');
+ else
+ first = FALSE;
+ g_string_append (ret, *component);
+ }
+ g_strfreev (components);
+ return g_string_free (ret, FALSE);
+}
+
+static char *
+compute_client_method_name (InterfaceInfo *iface, MethodInfo *method)
+{
+ GString *ret;
+ char *method_name_uscored;
+ char *iface_prefix;
+
+ iface_prefix = iface_to_c_prefix (interface_info_get_name (iface));
+ ret = g_string_new (iface_prefix);
+ g_free (iface_prefix);
+
+ method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
+ g_string_append_c (ret, '_');
+ g_string_append (ret, method_name_uscored);
+ g_free (method_name_uscored);
+ return g_string_free (ret, FALSE);
+}
+
+static gboolean
+write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
+{
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ const char *type_str;
+ int direction;
+
+ arg = args->data;
+
+ WRITE_OR_LOSE (", ");
+
+ direction = arg_info_get_direction (arg);
+
+ /* FIXME - broken for containers */
+ type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN);
+
+ if (!type_str)
+ {
+ g_set_error (error,
+ DBUS_BINDING_TOOL_ERROR,
+ DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+ _("Unsupported conversion from D-BUS type %d to glib C type"),
+ arg_info_get_type (arg));
+ return FALSE;
+ }
+
+ switch (direction)
+ {
+ case ARG_IN:
+ if (!write_printf_to_iochannel ("%s IN_%s", channel, error,
+ type_str,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_OUT:
+ if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error,
+ type_str,
+ arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_INVALID:
+ break;
+ }
+ }
+
+ return TRUE;
+ io_lose:
+ return FALSE;
+}
+
+static gboolean
+write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
+{
+ GSList *args;
+
+ for (args = method_info_get_args (method); args; args = args->next)
+ {
+ ArgInfo *arg;
+ const char *type_str;
+
+ arg = args->data;
+
+ if (direction != arg_info_get_direction (arg))
+ continue;
+
+ /* FIXME - broken for containers */
+ type_str = dbus_gvalue_binding_type_from_type (arg_info_get_type (arg));
+ if (!type_str)
+ {
+ g_set_error (error,
+ DBUS_BINDING_TOOL_ERROR,
+ DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+ _("Unsupported conversion from D-BUS type %c"),
+ (char) arg_info_get_type (arg));
+ return FALSE;
+ }
+
+
+ switch (direction)
+ {
+ case ARG_IN:
+ if (!write_printf_to_iochannel (" %s, &IN_%s,\n", channel, error,
+ type_str, arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_OUT:
+ if (!write_printf_to_iochannel (" %s, OUT_%s,\n", channel, error,
+ type_str, arg_info_get_name (arg)))
+ goto io_lose;
+ break;
+ case ARG_INVALID:
+ break;
+ }
+ }
+
+ return TRUE;
+ io_lose:
+ return FALSE;
+}
+
+static gboolean
+generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
+{
+ GSList *tmp;
+
+ tmp = list;
+ while (tmp != NULL)
+ {
+ if (!generate_client_glue (tmp->data, data, error))
+ return FALSE;
+ tmp = tmp->next;
+ }
+ return TRUE;
+}
+
+static gboolean
+generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
+{
+ if (base_info_get_type (base) == INFO_TYPE_NODE)
+ {
+ if (!generate_client_glue_list (node_info_get_nodes ((NodeInfo *) base),
+ data, error))
+ return FALSE;
+ if (!generate_client_glue_list (node_info_get_interfaces ((NodeInfo *) base),
+ data, error))
+ return FALSE;
+ }
+ else
+ {
+ GIOChannel *channel;
+ InterfaceInfo *interface;
+ GSList *methods;
+ GSList *tmp;
+ int count;
+
+ channel = data->channel;
+
+ interface = (InterfaceInfo *) base;
+
+ methods = interface_info_get_methods (interface);
+ count = 0;
+
+ for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
+ {
+ MethodInfo *method;
+ char *method_name;
+
+ method = (MethodInfo *) tmp->data;
+
+ method_name = compute_client_method_name (interface, method);
+
+ WRITE_OR_LOSE ("static gboolean\n");
+ if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error,
+ method_name))
+ goto io_lose;
+ g_free (method_name);
+
+ if (!write_formal_parameters (interface, method, channel, error))
+ goto io_lose;
+
+ WRITE_OR_LOSE (", GError **error)\n\n");
+
+ WRITE_OR_LOSE ("{\n");
+ WRITE_OR_LOSE (" gboolean ret;\n\n");
+ WRITE_OR_LOSE (" DBusGPendingCall *call;\n\n");
+
+ if (!write_printf_to_iochannel (" call = dbus_g_proxy_begin_call (proxy, \"%s\",\n",
+ 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 (" DBUS_TYPE_INVALID);\n");
+ WRITE_OR_LOSE (" ret = dbus_g_proxy_end_call (proxy, call, error,\n");
+
+ if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
+ goto io_lose;
+
+ WRITE_OR_LOSE (" DBUS_TYPE_INVALID);\n");
+
+ WRITE_OR_LOSE (" dbus_g_pending_call_unref (call);\n");
+ WRITE_OR_LOSE (" return ret;\n");
+
+ WRITE_OR_LOSE ("}\n\n");
+ }
+ }
+ return TRUE;
+ io_lose:
+ return FALSE;
+}
+
+
+gboolean
+dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, GError **error)
+{
+ DBusBindingToolCData data;
+ gboolean ret;
+
+ memset (&data, 0, sizeof (data));
+
+ data.channel = channel;
+
+ WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
+ WRITE_OR_LOSE ("#include <glib/gtypes.h>\n");
+ WRITE_OR_LOSE ("#include <glib/gerror.h>\n");
+ WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n\n");
+
+ ret = generate_client_glue (info, &data, error);
+
+ return ret;
+ io_lose:
+ return FALSE;
+}
diff --git a/glib/dbus-binding-tool-glib.h b/glib/dbus-binding-tool-glib.h
new file mode 100644
index 00000000..d4589bc9
--- /dev/null
+++ b/glib/dbus-binding-tool-glib.h
@@ -0,0 +1,33 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-binding-tool-output-glib.h prototypes for glib output
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef DBUS_BINDING_TOOL_OUTPUT_GLIB_H
+#define DBUS_BINDING_TOOL_OUTPUT_GLIB_H
+
+G_BEGIN_DECLS
+
+gboolean dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, GError **error);
+gboolean dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c
index ec87414d..554e18c3 100644
--- a/glib/dbus-gidl.c
+++ b/glib/dbus-gidl.c
@@ -43,6 +43,7 @@ struct NodeInfo
struct InterfaceInfo
{
BaseInfo base;
+ GHashTable *bindings;
/* Since we have BaseInfo now these could be one list */
GSList *methods;
GSList *signals;
@@ -52,6 +53,7 @@ struct InterfaceInfo
struct MethodInfo
{
BaseInfo base;
+ GHashTable *bindings;
GSList *args;
};
@@ -75,6 +77,23 @@ struct ArgInfo
ArgDirection direction;
};
+static void
+get_hash_key (gpointer key, gpointer value, gpointer data)
+{
+ GSList **list = data;
+ *list = g_slist_prepend (*list, key);
+}
+
+static GSList *
+get_hash_keys (GHashTable *table)
+{
+ GSList *ret = NULL;
+
+ g_hash_table_foreach (table, get_hash_key, &ret);
+
+ return ret;
+}
+
BaseInfo *
base_info_ref (BaseInfo *info)
{
@@ -326,6 +345,9 @@ interface_info_new (const char *name)
info->base.refcount = 1;
info->base.name = g_strdup (name);
info->base.type = INFO_TYPE_INTERFACE;
+ info->bindings = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
return info;
}
@@ -344,6 +366,7 @@ interface_info_unref (InterfaceInfo *info)
info->base.refcount -= 1;
if (info->base.refcount == 0)
{
+ g_hash_table_destroy (info->bindings);
free_method_list (&info->methods);
free_signal_list (&info->signals);
free_property_list (&info->properties);
@@ -357,6 +380,19 @@ interface_info_get_name (InterfaceInfo *info)
return info->base.name;
}
+GSList *
+interface_info_get_binding_names (InterfaceInfo *info)
+{
+ return get_hash_keys (info->bindings);
+}
+
+const char*
+interface_info_get_binding_name (InterfaceInfo *info,
+ const char *binding_type)
+{
+ return g_hash_table_lookup (info->bindings, binding_type);
+}
+
GSList*
interface_info_get_methods (InterfaceInfo *info)
{
@@ -376,6 +412,16 @@ interface_info_get_properties (InterfaceInfo *info)
}
void
+interface_info_set_binding_name (InterfaceInfo *info,
+ const char *binding_type,
+ const char *bound_name)
+{
+ g_hash_table_insert (info->bindings,
+ g_strdup (binding_type),
+ g_strdup (bound_name));
+}
+
+void
interface_info_add_method (InterfaceInfo *info,
MethodInfo *method)
{
@@ -424,6 +470,9 @@ method_info_new (const char *name)
info->base.refcount = 1;
info->base.name = g_strdup (name);
info->base.type = INFO_TYPE_METHOD;
+ info->bindings = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
return info;
}
@@ -442,6 +491,7 @@ method_info_unref (MethodInfo *info)
info->base.refcount -= 1;
if (info->base.refcount == 0)
{
+ g_hash_table_destroy (info->bindings);
free_arg_list (&info->args);
base_info_free (info);
}
@@ -453,6 +503,19 @@ method_info_get_name (MethodInfo *info)
return info->base.name;
}
+GSList *
+method_info_get_binding_names (MethodInfo *info)
+{
+ return get_hash_keys (info->bindings);
+}
+
+const char*
+method_info_get_binding_name (MethodInfo *info,
+ const char *binding_type)
+{
+ return g_hash_table_lookup (info->bindings, binding_type);
+}
+
GSList*
method_info_get_args (MethodInfo *info)
{
@@ -481,6 +544,16 @@ args_sort_by_direction (const void *a,
}
void
+method_info_set_binding_name (MethodInfo *info,
+ const char *binding_type,
+ const char *bound_name)
+{
+ g_hash_table_insert (info->bindings,
+ g_strdup (binding_type),
+ g_strdup (bound_name));
+}
+
+void
method_info_add_arg (MethodInfo *info,
ArgInfo *arg)
{
diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h
index a706c4d5..917432ee 100644
--- a/glib/dbus-gidl.h
+++ b/glib/dbus-gidl.h
@@ -90,19 +90,31 @@ InterfaceInfo* interface_info_new (const char *name);
InterfaceInfo* interface_info_ref (InterfaceInfo *info);
void interface_info_unref (InterfaceInfo *info);
const char* interface_info_get_name (InterfaceInfo *info);
+GSList* interface_info_get_binding_names(InterfaceInfo *info);
+const char* interface_info_get_binding_name(InterfaceInfo*info,
+ const char *binding_type);
GSList* interface_info_get_methods (InterfaceInfo *info);
GSList* interface_info_get_signals (InterfaceInfo *info);
GSList* interface_info_get_properties (InterfaceInfo *info);
+void interface_info_set_binding_name(InterfaceInfo *info,
+ const char *name,
+ const char *value);
void interface_info_add_method (InterfaceInfo *info,
MethodInfo *method);
void interface_info_add_signal (InterfaceInfo *info,
SignalInfo *signal);
void interface_info_add_property (InterfaceInfo *info,
PropertyInfo *property);
-MethodInfo* method_info_new (const char *name);
+MethodInfo* method_info_new (const char *name);
MethodInfo* method_info_ref (MethodInfo *info);
void method_info_unref (MethodInfo *info);
const char* method_info_get_name (MethodInfo *info);
+GSList* method_info_get_binding_names (MethodInfo *info);
+const char* method_info_get_binding_name (MethodInfo *info,
+ const char *binding_type);
+void method_info_set_binding_name (MethodInfo *info,
+ const char *binding_type,
+ const char *bound_name);
GSList* method_info_get_args (MethodInfo *info);
void method_info_add_arg (MethodInfo *info,
ArgInfo *arg);
diff --git a/glib/dbus-glib-tool.c b/glib/dbus-glib-tool.c
index c8273afa..022055e6 100644
--- a/glib/dbus-glib-tool.c
+++ b/glib/dbus-glib-tool.c
@@ -25,6 +25,7 @@
#include "dbus-gidl.h"
#include "dbus-gparser.h"
#include "dbus-gutils.h"
+#include "dbus-binding-tool-glib.h"
#include <locale.h>
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
@@ -37,6 +38,13 @@
static void run_all_tests (const char *test_data_dir);
#endif
+typedef enum {
+ DBUS_BINDING_OUTPUT_NONE,
+ DBUS_BINDING_OUTPUT_PRETTY,
+ DBUS_BINDING_OUTPUT_GLIB_SERVER,
+ DBUS_BINDING_OUTPUT_GLIB_CLIENT,
+} DBusBindingOutputMode;
+
static void
indent (int depth)
{
@@ -99,11 +107,23 @@ pretty_print (BaseInfo *base,
case INFO_TYPE_INTERFACE:
{
InterfaceInfo *i = (InterfaceInfo*) base;
+ GSList *binding_types, *elt;
g_assert (name != NULL);
printf (_("interface \"%s\" {\n"), name);
+ binding_types = interface_info_get_binding_names (i);
+ for (elt = binding_types; elt; elt = elt->next)
+ {
+ const char *binding_type = elt->data;
+ const char *binding_name = interface_info_get_binding_name (i, binding_type);
+
+ printf (_(" (binding \"%s\": \"%s\") "),
+ binding_type, binding_name);
+ }
+ g_slist_free (binding_types);
+
pretty_print_list (interface_info_get_methods (i), depth + 1);
pretty_print_list (interface_info_get_signals (i), depth + 1);
pretty_print_list (interface_info_get_properties (i), depth + 1);
@@ -115,10 +135,21 @@ pretty_print (BaseInfo *base,
case INFO_TYPE_METHOD:
{
MethodInfo *m = (MethodInfo*) base;
+ GSList *binding_types, *elt;
g_assert (name != NULL);
- printf (_("method \"%s\" (\n"), name);
+ binding_types = method_info_get_binding_names (m);
+ printf (_("method \"%s\""), name);
+ for (elt = binding_types; elt; elt = elt->next)
+ {
+ const char *binding_type = elt->data;
+ const char *binding_name = method_info_get_binding_name (m, binding_type);
+
+ printf (_(" (binding \"%s\": \"%s\") "),
+ binding_type, binding_name);
+ }
+ g_slist_free (binding_types);
pretty_print_list (method_info_get_args (m), depth + 1);
@@ -174,6 +205,16 @@ pretty_print (BaseInfo *base,
}
}
+GQuark
+dbus_binding_tool_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string ("dbus_binding_tool_error");
+
+ return quark;
+}
+
static void
usage (int ecode)
{
@@ -186,7 +227,7 @@ version (void)
{
printf ("D-BUS Binding Tool %s\n"
"Copyright (C) 2003-2005 Red Hat, Inc.\n"
- "This is free software; xsee the source for copying conditions.\n"
+ "This is free software; see the source for copying conditions.\n"
"There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
VERSION);
exit (0);
@@ -198,16 +239,20 @@ main (int argc, char **argv)
const char *prev_arg;
int i;
GSList *files;
+ DBusBindingOutputMode outputmode;
gboolean end_of_args;
GSList *tmp;
- gboolean just_pretty_print;
+ GIOChannel *channel;
+ GError *error;
setlocale (LC_ALL, "");
bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
- just_pretty_print = FALSE;
+ g_type_init ();
+
+ outputmode = DBUS_BINDING_OUTPUT_NONE;
end_of_args = FALSE;
files = NULL;
prev_arg = NULL;
@@ -228,8 +273,18 @@ main (int argc, char **argv)
else if (strcmp (arg, "--self-test") == 0)
run_all_tests (NULL);
#endif /* DBUS_BUILD_TESTS */
- else if (strcmp (arg, "--pretty-print") == 0)
- just_pretty_print = TRUE;
+ else if (strncmp (arg, "--mode=", 7) == 0)
+ {
+ const char *mode = arg + 7;
+ if (!strcmp (mode, "pretty"))
+ outputmode = DBUS_BINDING_OUTPUT_PRETTY;
+ else if (!strcmp (mode, "glib-server"))
+ outputmode = DBUS_BINDING_OUTPUT_GLIB_SERVER;
+ else if (!strcmp (mode, "glib-client"))
+ outputmode = DBUS_BINDING_OUTPUT_GLIB_CLIENT;
+ else
+ usage (1);
+ }
else if (arg[0] == '-' &&
arg[1] == '-' &&
arg[2] == '\0')
@@ -251,6 +306,15 @@ main (int argc, char **argv)
++i;
}
+ error = NULL;
+ channel = g_io_channel_unix_new (fileno (stdout));
+ if (!g_io_channel_set_encoding (channel, NULL, &error))
+ {
+ fprintf (stderr, _("Couldn't set channel encoding to NULL: %s\n"),
+ error->message);
+ exit (1);
+ }
+
files = g_slist_reverse (files);
tmp = files;
@@ -273,27 +337,43 @@ main (int argc, char **argv)
g_error_free (error);
exit (1);
}
- else if (just_pretty_print)
- {
- pretty_print ((BaseInfo*) node, 0);
- }
else
- {
- /* FIXME process the file to generate metadata variable
- * definition rather than just printing it.
- * i.e. we want to create DBusGObjectInfo.
- * This probably requires extending the introspection XML format to
- * allow a "native function name":
- * <method name="Frobate" native="my_object_frobate">
- */
- pretty_print ((BaseInfo*) node, 0);
- }
+ {
+ switch (outputmode)
+ {
+ case DBUS_BINDING_OUTPUT_PRETTY:
+ pretty_print ((BaseInfo*) node, 0);
+ break;
+ case DBUS_BINDING_OUTPUT_GLIB_SERVER:
+ if (!dbus_binding_tool_output_glib_server ((BaseInfo *) node, channel, &error))
+ {
+ g_error (_("Compilation failed: %s\n"), error->message);
+ exit (1);
+ }
+ break;
+ case DBUS_BINDING_OUTPUT_GLIB_CLIENT:
+ if (!dbus_binding_tool_output_glib_client ((BaseInfo *) node, channel, &error))
+ {
+ g_error (_("Compilation failed: %s\n"), error->message);
+ exit (1);
+ }
+ break;
+ case DBUS_BINDING_OUTPUT_NONE:
+ break;
+ }
+ }
if (node)
node_info_unref (node);
tmp = tmp->next;
}
+
+ if (!g_io_channel_flush (channel, &error))
+ {
+ g_error (_("Failed to flush IO channel: %s"), error->message);
+ exit (1);
+ }
return 0;
}
diff --git a/glib/dbus-glib-tool.h b/glib/dbus-glib-tool.h
new file mode 100644
index 00000000..b56d764a
--- /dev/null
+++ b/glib/dbus-glib-tool.h
@@ -0,0 +1,37 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-glib-tool.h: Definitions used internally by binding tool
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef DBUS_BINDING_TOOL_H
+#define DBUS_BINDING_TOOL_H
+
+#include <glib/gquark.h>
+
+typedef enum
+{
+ DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION
+} DBusBindingToolError;
+
+#define DBUS_BINDING_TOOL_ERROR dbus_binding_tool_error_quark ()
+
+GQuark dbus_binding_tool_error_quark (void);
+
+#endif
diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c
index abaf2e0e..3bcd90d5 100644
--- a/glib/dbus-gobject.c
+++ b/glib/dbus-gobject.c
@@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gobject.c Exporting a GObject remotely
*
- * Copyright (C) 2003, 2004 Red Hat, Inc.
+ * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.1
*
@@ -26,6 +26,7 @@
#include <dbus/dbus-glib-lowlevel.h>
#include "dbus-gtest.h"
#include "dbus-gutils.h"
+#include "dbus-gobject.h"
#include "dbus-gvalue.h"
#include <string.h>
@@ -34,37 +35,10 @@
* @{
*/
-static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT;
+static GStaticRWLock info_hash_lock = G_STATIC_RW_LOCK_INIT;
static GHashTable *info_hash = NULL;
static char*
-wincaps_to_uscore (const char *caps)
-{
- const char *p;
- GString *str;
-
- str = g_string_new (NULL);
- p = caps;
- while (*p)
- {
- if (g_ascii_isupper (*p))
- {
- if (str->len > 0 &&
- (str->len < 2 || str->str[str->len-2] != '_'))
- g_string_append_c (str, '_');
- g_string_append_c (str, g_ascii_tolower (*p));
- }
- else
- {
- g_string_append_c (str, *p);
- }
- ++p;
- }
-
- return g_string_free (str, FALSE);
-}
-
-static char*
uscore_to_wincaps (const char *uscore)
{
const char *p;
@@ -97,6 +71,164 @@ uscore_to_wincaps (const char *uscore)
return g_string_free (str, FALSE);
}
+static const char *
+string_table_next (const char *table)
+{
+ return (table + (strlen (table) + 1));
+}
+
+static const char *
+string_table_lookup (const char *table, int index)
+{
+ const char *ret;
+
+ ret = table;
+
+ while (index--)
+ ret = string_table_next (ret);
+
+ return ret;
+}
+
+static const char *
+get_method_data (const DBusGObjectInfo *object,
+ const DBusGMethodInfo *method)
+{
+ return object->data + method->data_offset;
+}
+
+static char *
+object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
+{
+ /* FIXME */
+ return NULL;
+}
+
+static char *
+object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
+{
+ /* FIXME */
+ return NULL;
+}
+
+static const char *
+method_interface_from_object_info (const DBusGObjectInfo *object,
+ const DBusGMethodInfo *method)
+{
+ return string_table_lookup (get_method_data (object, method), 0);
+}
+
+static const char *
+method_name_from_object_info (const DBusGObjectInfo *object,
+ const DBusGMethodInfo *method)
+{
+ return string_table_lookup (get_method_data (object, method), 1);
+}
+
+static const char *
+method_arg_info_from_object_info (const DBusGObjectInfo *object,
+ const DBusGMethodInfo *method)
+{
+ return string_table_lookup (get_method_data (object, method), 2);
+}
+
+static const char *
+arg_iterate (const char *data, const char **name, gboolean *in,
+ const char **type)
+{
+ *name = data;
+
+ data = string_table_next (data);
+ switch (*data)
+ {
+ case 'I':
+ *in = TRUE;
+ break;
+ case 'O':
+ *in = FALSE;
+ break;
+ default:
+ g_warning ("invalid arg direction");
+ break;
+ }
+
+ data = string_table_next (data);
+ *type = data;
+
+ return string_table_next (data);
+}
+
+static char *
+method_dir_signature_from_object_info (const DBusGObjectInfo *object,
+ const DBusGMethodInfo *method,
+ gboolean in)
+{
+ const char *arg;
+ GString *ret;
+
+ arg = method_arg_info_from_object_info (object, method);
+
+ ret = g_string_new (NULL);
+
+ while (*arg)
+ {
+ const char *name;
+ gboolean arg_in;
+ const char *type;
+
+ arg = arg_iterate (arg, &name, &arg_in, &type);
+
+ if (arg_in == in)
+ g_string_append (ret, type);
+ }
+
+ return g_string_free (ret, FALSE);
+}
+
+static char *
+method_input_signature_from_object_info (const DBusGObjectInfo *object,
+ const DBusGMethodInfo *method)
+{
+ return method_dir_signature_from_object_info (object, method, TRUE);
+}
+
+static char *
+method_output_signature_from_object_info (const DBusGObjectInfo *object,
+ const DBusGMethodInfo *method)
+{
+ return method_dir_signature_from_object_info (object, method, FALSE);
+}
+
+GValueArray *
+dbus_glib_marshal_dbus_message_to_gvalue_array (DBusMessage *message)
+{
+ GValueArray *ret;
+ DBusMessageIter iter;
+ int dtype;
+
+ ret = g_value_array_new (6); /* 6 is a typical maximum for arguments */
+ dbus_message_iter_init (message, &iter);
+
+ while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
+ {
+ GValue value = { 0, };
+
+ if (!dbus_gvalue_demarshal (&iter, &value))
+ {
+ g_warning ("Unable to convert arg type %d to GValue", dtype);
+ g_value_array_free (ret);
+ ret = NULL;
+ goto out;
+ }
+ g_value_array_append (ret, &value);
+
+ dbus_message_iter_next (&iter);
+ }
+
+ out:
+ return ret;
+}
+
static void
gobject_unregister_function (DBusConnection *connection,
void *user_data)
@@ -272,6 +404,115 @@ introspect_signals (GType type, GString *xml)
g_string_append (xml, " </interface>\n");
}
+typedef struct
+{
+ GString *xml;
+ const DBusGObjectInfo *object_info;
+} DBusGlibWriteIterfaceData;
+
+static void
+write_interface (gpointer key, gpointer val, gpointer user_data)
+{
+ const char *name;
+ GSList *methods;
+ GString *xml;
+ const DBusGObjectInfo *object_info;
+ DBusGlibWriteIterfaceData *data;
+
+ name = key;
+ methods = val;
+ data = user_data;
+ xml = data->xml;
+ object_info = data->object_info;
+
+ g_string_append_printf (xml, " <interface name=\"%s\">\n", name);
+
+ /* FIXME: recurse to parent types ? */
+ for (; methods; methods = methods->next)
+ {
+ DBusGMethodInfo *method;
+ method = methods->data;
+ const char *args;
+
+ g_string_append_printf (xml, " <method name=\"%s\">\n",
+ method_name_from_object_info (object_info, method));
+
+ args = method_arg_info_from_object_info (object_info, method);
+
+ while (*args)
+ {
+ const char *name;
+ gboolean arg_in;
+ const char *type;
+
+ args = arg_iterate (args, &name, &arg_in, &type);
+
+ /* FIXME - handle container types */
+ g_string_append_printf (xml, " <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
+ name, _dbus_gutils_type_to_string (type[0]), arg_in ? "in" : "out");
+
+ }
+ g_string_append (xml, " </method>\n");
+ }
+
+ g_string_append (xml, " </interface>\n");
+}
+
+static void
+introspect_interfaces (GObject *object, GString *xml)
+{
+ GType classtype;
+
+ g_static_rw_lock_reader_lock (&info_hash_lock);
+
+ for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
+ {
+ const DBusGObjectInfo *info;
+ DBusGlibWriteIterfaceData data;
+
+ info = g_hash_table_lookup (info_hash,
+ g_type_class_peek (classtype));
+
+ if (info != NULL && info->format_version == 0)
+ {
+ int i;
+ GHashTable *interfaces;
+
+ /* Gather a list of all interfaces, indexed into their methods */
+ interfaces = g_hash_table_new (g_str_hash, g_str_equal);
+ for (i = 0; i < info->n_infos; i++)
+ {
+ const char *method_name;
+ const char *method_interface;
+ const char *method_args;
+ const DBusGMethodInfo *method;
+ GSList *methods;
+
+ method = &(info->infos[i]);
+
+ method_interface = method_interface_from_object_info (info, method);
+ method_name = method_name_from_object_info (info, method);
+ method_args = method_arg_info_from_object_info (info, method);
+
+ if ((methods = g_hash_table_lookup (interfaces, method_interface)) == NULL)
+ methods = g_slist_prepend (NULL, (gpointer) method);
+ else
+ methods = g_slist_prepend (methods, (gpointer) method);
+ g_hash_table_insert (interfaces, (gpointer) method_interface, methods);
+ }
+
+ memset (&data, 0, sizeof (data));
+ data.xml = xml;
+ data.object_info = info;
+ g_hash_table_foreach (interfaces, write_interface, &data);
+
+ g_hash_table_destroy (interfaces);
+ }
+ }
+
+ g_static_rw_lock_reader_lock (&info_hash_lock);
+}
+
static DBusHandlerResult
handle_introspect (DBusConnection *connection,
DBusMessage *message,
@@ -316,6 +557,7 @@ handle_introspect (DBusConnection *connection,
introspect_signals (G_OBJECT_TYPE (object), xml);
introspect_properties (object, xml);
+ introspect_interfaces (object, xml);
/* Append child nodes */
for (i = 0; children[i]; i++)
@@ -392,7 +634,7 @@ get_object_property (DBusConnection *connection,
GParamSpec *pspec)
{
GType value_type;
- GValue value;
+ GValue value = {0, };
DBusMessage *ret;
DBusMessageIter iter;
@@ -420,12 +662,275 @@ get_object_property (DBusConnection *connection,
return ret;
}
+static gboolean
+lookup_object_and_method (GObject *object,
+ DBusMessage *message,
+ const DBusGObjectInfo **object_ret,
+ const DBusGMethodInfo **method_ret)
+{
+ GType classtype;
+ const char *interface;
+ const char *member;
+ const char *signature;
+ gboolean ret;
+
+ interface = dbus_message_get_interface (message);
+ member = dbus_message_get_member (message);
+ signature = dbus_message_get_signature (message);
+ ret = FALSE;
+
+ g_static_rw_lock_reader_lock (&info_hash_lock);
+
+ if (!info_hash)
+ goto out;
+
+ for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
+ {
+ const DBusGObjectInfo *info;
+
+ info = g_hash_table_lookup (info_hash,
+ g_type_class_peek (classtype));
+
+ *object_ret = info;
+
+ if (info != NULL && info->format_version == 0)
+ {
+ int i;
+ for (i = 0; i < info->n_infos; i++)
+ {
+ const char *expected_member;
+ const char *expected_interface;
+ char *expected_signature;
+ const DBusGMethodInfo *method;
+
+ method = &(info->infos[i]);
+
+ /* Check method interface/name and input signature */
+ expected_interface = method_interface_from_object_info (*object_ret, method);
+ expected_member = method_name_from_object_info (*object_ret, method);
+ expected_signature = method_input_signature_from_object_info (*object_ret, method);
+ if ((interface == NULL
+ || strcmp (expected_interface, interface) == 0)
+ && strcmp (expected_member, member) == 0
+ && strcmp (expected_signature, signature) == 0)
+ {
+ g_free (expected_signature);
+ *method_ret = method;
+ ret = TRUE;
+ goto out;
+ }
+ g_free (expected_signature);
+ }
+ }
+ }
+ out:
+ g_static_rw_lock_reader_lock (&info_hash_lock);
+ return ret;
+}
+
+static char *
+gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
+ GQuark domain, gint code)
+{
+ const char *domain_str;
+ const char *code_str;
+ GString *dbus_error_name;
+
+ domain_str = object_error_domain_prefix_from_object_info (object_info);
+ code_str = object_error_code_from_object_info (object_info, domain, code);
+
+ if (!domain_str || !code_str)
+ {
+ /* If we can't map it sensibly, make up an error name */
+ char *domain_from_quark;
+
+ dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
+
+ domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
+ g_string_append (dbus_error_name, domain_from_quark);
+ g_free (domain_from_quark);
+
+ g_string_append_printf (dbus_error_name, ".Code%d", code);
+ }
+ else
+ {
+ dbus_error_name = g_string_new (domain_str);
+ g_string_append_c (dbus_error_name, '.');
+ g_string_append (dbus_error_name, code_str);
+ }
+
+ return g_string_free (dbus_error_name, FALSE);
+}
+
+static DBusMessage *
+gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
+ DBusMessage *message,
+ GError *error)
+{
+ DBusMessage *reply;
+
+ if (!error)
+ {
+ char *error_msg;
+
+ error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
+ reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
+ g_free (error_msg);
+ }
+ else
+ {
+ char *error_name;
+ error_name = gerror_domaincode_to_dbus_error_name (object_info, error->domain, error->code);
+ reply = dbus_message_new_error (message, error_name, error->message);
+ g_free (error_name);
+ }
+ return reply;
+}
+
+static DBusHandlerResult
+invoke_object_method (GObject *object,
+ const DBusGObjectInfo *object_info,
+ const DBusGMethodInfo *method,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ gboolean had_error;
+ GError *gerror;
+ GValueArray *value_array;
+ GValue object_value = {0,};
+ GValue error_value = {0,};
+ GValue return_value = {0,};
+ GClosure closure;
+ char *out_signature;
+ int out_signature_len;
+ GArray *out_param_values;
+ int i;
+ DBusHandlerResult result;
+ DBusMessage *reply;
+
+ gerror = NULL;
+
+ /* This is evil. We do this to work around the fact that
+ * the generated glib marshallers check a flag in the closure object
+ * which we don't care about. We don't need/want to create
+ * a new closure for each invocation.
+ */
+ memset (&closure, 0, sizeof (closure));
+
+ /* Convert method IN parameters to GValueArray */
+ value_array = dbus_glib_marshal_dbus_message_to_gvalue_array (message);
+
+ g_return_val_if_fail (value_array != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+
+ /* Prepend object as first argument */
+ g_value_init (&object_value, G_TYPE_OBJECT);
+ g_value_set_object (&object_value, object);
+ g_value_array_prepend (value_array, &object_value);
+
+ out_signature = method_output_signature_from_object_info (object_info, method);
+ out_signature_len = strlen (out_signature);
+
+ /* Create an array to store the actual values of OUT
+ * parameters. Then, create a GValue boxed POINTER
+ * to each of those values, and append to the invocation,
+ * so the method can return the OUT parameters.
+ */
+ out_param_values = g_array_new (FALSE, TRUE, sizeof (DBusBasicGValue));
+ for (i = 0; i < out_signature_len; i++)
+ {
+ GValue value = {0, };
+ DBusBasicGValue basic;
+
+ memset (&basic, 0, sizeof (basic));
+
+ /* FIXME - broken for container types */
+
+ g_array_append_val (out_param_values, basic);
+ g_value_init (&value, G_TYPE_POINTER);
+ g_value_set_pointer (&value, &(g_array_index (out_param_values, DBusBasicGValue, i)));
+ g_value_array_append (value_array, &value);
+ }
+
+ /* Append GError as final argument */
+ g_value_init (&error_value, G_TYPE_POINTER);
+ g_value_set_pointer (&error_value, &gerror);
+ g_value_array_append (value_array, &error_value);
+
+ /* Actually invoke method */
+ g_value_init (&return_value, G_TYPE_BOOLEAN);
+ method->marshaller (&closure, &return_value,
+ value_array->n_values,
+ value_array->values,
+ NULL, method->function);
+ had_error = !g_value_get_boolean (&return_value);
+
+ if (!had_error)
+ {
+ DBusMessageIter iter;
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ goto nomem;
+
+ /* Append OUT arguments to reply */
+ dbus_message_iter_init_append (reply, &iter);
+ for (i = 0; i < out_signature_len; i++)
+ {
+ DBusBasicGValue *value;
+
+ /* FIXME - broken for container types */
+
+ value = &(g_array_index (out_param_values, DBusBasicGValue, i));
+ if (!dbus_message_iter_append_basic (&iter, out_signature[i], value))
+ goto nomem;
+
+ }
+ }
+ else
+ reply = gerror_to_dbus_error_message (object_info, message, gerror);
+
+ if (reply)
+ {
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ }
+
+ /* Assume that if there was an error, no return values are
+ * set */
+ if (!had_error)
+ {
+ /* Be sure to free all returned STRING arguments for now;
+ * later this should be specified via method info parameter
+ * annotation; probably we want to support custom free funcs too */
+ for (i = 0; i < out_signature_len; i++)
+ {
+ DBusBasicGValue *value;
+
+ value = &(g_array_index (out_param_values, DBusBasicGValue, i));
+ if (out_signature[i] == DBUS_TYPE_STRING)
+ g_free (value->gpointer_val);
+ }
+ }
+
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ done:
+ g_free (out_signature);
+ g_array_free (out_param_values, TRUE);
+ g_value_array_free (value_array);
+ g_value_unset (&object_value);
+ g_value_unset (&error_value);
+ g_value_unset (&return_value);
+ return result;
+ nomem:
+ result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+ goto done;
+}
+
static DBusHandlerResult
gobject_message_function (DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
- const DBusGObjectInfo *info;
GParamSpec *pspec;
GObject *object;
gboolean setter;
@@ -434,6 +939,8 @@ gobject_message_function (DBusConnection *connection,
const char *wincaps_propname;
/* const char *wincaps_propiface; */
DBusMessageIter iter;
+ const DBusGMethodInfo *method;
+ const DBusGObjectInfo *object_info;
object = G_OBJECT (user_data);
@@ -441,23 +948,10 @@ gobject_message_function (DBusConnection *connection,
DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
"Introspect"))
return handle_introspect (connection, message, object);
-
+
/* Try the metainfo, which lets us invoke methods */
-
- g_static_mutex_lock (&info_hash_mutex);
- /* FIXME this needs to walk up the inheritance tree, not
- * just look at the most-derived class
- */
- info = g_hash_table_lookup (info_hash,
- G_OBJECT_GET_CLASS (object));
- g_static_mutex_unlock (&info_hash_mutex);
-
- if (info != NULL)
- {
-
-
-
- }
+ if (lookup_object_and_method (object, message, &object_info, &method))
+ return invoke_object_method (object, object_info, method, connection, message);
/* If no metainfo, we can still do properties and signals
* via standard GLib introspection
@@ -497,7 +991,7 @@ gobject_message_function (DBusConnection *connection,
dbus_message_iter_get_basic (&iter, &wincaps_propname);
dbus_message_iter_next (&iter);
- s = wincaps_to_uscore (wincaps_propname);
+ s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
s);
@@ -577,7 +1071,7 @@ dbus_g_object_class_install_info (GObjectClass *object_class,
{
g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
- g_static_mutex_lock (&info_hash_mutex);
+ g_static_rw_lock_writer_lock (&info_hash_lock);
if (info_hash == NULL)
{
@@ -586,7 +1080,7 @@ dbus_g_object_class_install_info (GObjectClass *object_class,
g_hash_table_replace (info_hash, object_class, (void*) info);
- g_static_mutex_unlock (&info_hash_mutex);
+ g_static_rw_lock_writer_unlock (&info_hash_lock);
}
/**
@@ -652,7 +1146,7 @@ _dbus_gobject_test (const char *test_data_dir)
char *uscore;
char *wincaps;
- uscore = wincaps_to_uscore (name_pairs[i].wincaps);
+ uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
wincaps = uscore_to_wincaps (name_pairs[i].uscore);
if (strcmp (uscore, name_pairs[i].uscore) != 0)
diff --git a/glib/dbus-gobject.h b/glib/dbus-gobject.h
new file mode 100644
index 00000000..28bba5c3
--- /dev/null
+++ b/glib/dbus-gobject.h
@@ -0,0 +1,35 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gobject.h: common functions used to map between D-BUS and GObject
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef DBUS_GLIB_OBJECT_H
+#define DBUS_GLIB_OBJECT_H
+
+#include <dbus/dbus.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+GValueArray* dbus_glib_marshal_dbus_message_to_gvalue_array (DBusMessage *message);
+
+G_END_DECLS
+
+#endif
diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c
index 680d830a..05136aa8 100644
--- a/glib/dbus-gparser.c
+++ b/glib/dbus-gparser.c
@@ -308,6 +308,7 @@ parse_interface (Parser *parser,
GError **error)
{
const char *name;
+ const char *c_name;
InterfaceInfo *iface;
NodeInfo *top;
@@ -329,6 +330,7 @@ parse_interface (Parser *parser,
if (!locate_attributes (element_name, attribute_names,
attribute_values, error,
"name", &name,
+ "c_name", &c_name,
NULL))
return FALSE;
@@ -344,6 +346,8 @@ parse_interface (Parser *parser,
top = parser->node_stack->data;
iface = interface_info_new (name);
+ if (c_name)
+ interface_info_set_binding_name (iface, "C", c_name);
node_info_add_interface (top, iface);
interface_info_unref (iface);
@@ -360,6 +364,7 @@ parse_method (Parser *parser,
GError **error)
{
const char *name;
+ const char *c_name;
MethodInfo *method;
NodeInfo *top;
@@ -381,6 +386,7 @@ parse_method (Parser *parser,
if (!locate_attributes (element_name, attribute_names,
attribute_values, error,
"name", &name,
+ "c_name", &c_name,
NULL))
return FALSE;
@@ -396,6 +402,8 @@ parse_method (Parser *parser,
top = parser->node_stack->data;
method = method_info_new (name);
+ if (c_name)
+ method_info_set_binding_name (method, "C", c_name);
interface_info_add_method (parser->interface, method);
method_info_unref (method);
diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c
index 17b76d93..364facf8 100644
--- a/glib/dbus-gproxy.c
+++ b/glib/dbus-gproxy.c
@@ -25,6 +25,7 @@
#include "dbus-gutils.h"
#include "dbus-gmarshal.h"
#include "dbus-gvalue.h"
+#include "dbus-gobject.h"
#include <string.h>
/**
@@ -900,11 +901,8 @@ marshal_dbus_message_to_g_marshaller (GClosure *closure,
* marshaller.
*/
#define MAX_SIGNATURE_ARGS 20
- GValue expanded[MAX_SIGNATURE_ARGS];
- int arg;
- int i;
- DBusMessageIter iter;
- int dtype;
+ GValueArray *value_array;
+ GValue value = {0, };
GSignalCMarshaller c_marshaller;
DBusGProxy *proxy;
DBusMessage *message;
@@ -924,44 +922,18 @@ marshal_dbus_message_to_g_marshaller (GClosure *closure,
g_return_if_fail (c_marshaller != NULL);
- memset (&expanded[0], 0, sizeof (expanded));
-
- arg = 0;
-
- g_value_init (&expanded[arg], G_TYPE_FROM_INSTANCE (proxy));
- g_value_set_instance (&expanded[arg], proxy);
- ++arg;
-
- dbus_message_iter_init (message, &iter);
+ value_array = dbus_glib_marshal_dbus_message_to_gvalue_array (message);
+
+ g_return_if_fail (value_array != NULL);
- while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
- {
- if (arg == MAX_SIGNATURE_ARGS)
- {
- g_warning ("Don't support more than %d signal args\n", MAX_SIGNATURE_ARGS);
- goto out;
- }
-
- if (!dbus_gvalue_demarshal (&iter, &expanded[arg]))
- {
- g_warning ("Unable to convert arg type %d to GValue to emit DBusGProxy signal", dtype);
- goto out;
- }
-
- ++arg;
- dbus_message_iter_next (&iter);
- }
+ g_value_init (&value, G_TYPE_FROM_INSTANCE (proxy));
+ g_value_set_instance (&value, proxy);
+ g_value_array_prepend (value_array, &value);
- (* c_marshaller) (closure, return_value, arg, &expanded[0],
- invocation_hint, marshal_data);
+ (* c_marshaller) (closure, return_value, value_array->n_values,
+ value_array->values, invocation_hint, marshal_data);
- out:
- i = 0;
- while (i < arg)
- {
- g_value_unset (&expanded[i]);
- ++i;
- }
+ g_value_array_free (value_array);
}
static void
diff --git a/glib/dbus-gutils.c b/glib/dbus-gutils.c
index cf12245c..30d00fed 100644
--- a/glib/dbus-gutils.c
+++ b/glib/dbus-gutils.c
@@ -125,6 +125,34 @@ _dbus_gutils_type_to_string (int type)
}
}
+char*
+_dbus_gutils_wincaps_to_uscore (const char *caps)
+{
+ const char *p;
+ GString *str;
+
+ str = g_string_new (NULL);
+ p = caps;
+ while (*p)
+ {
+ if (g_ascii_isupper (*p))
+ {
+ if (str->len > 0 &&
+ (str->len < 2 || str->str[str->len-2] != '_'))
+ g_string_append_c (str, '_');
+ g_string_append_c (str, g_ascii_tolower (*p));
+ }
+ else
+ {
+ g_string_append_c (str, *p);
+ }
+ ++p;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+
#ifdef DBUS_BUILD_TESTS
/**
diff --git a/glib/dbus-gutils.h b/glib/dbus-gutils.h
index fd2cac88..0356b30e 100644
--- a/glib/dbus-gutils.h
+++ b/glib/dbus-gutils.h
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
char **_dbus_gutils_split_path (const char *path);
const char *_dbus_gutils_type_to_string (int type);
+char *_dbus_gutils_wincaps_to_uscore (const char *uscore);
/* These munge the pointer to enforce that a plain cast won't work,
* accessor functions must be used; i.e. to ensure the ABI
diff --git a/glib/dbus-gvalue.c b/glib/dbus-gvalue.c
index e2bf40b2..8306be9b 100644
--- a/glib/dbus-gvalue.c
+++ b/glib/dbus-gvalue.c
@@ -2,6 +2,7 @@
/* dbus-gvalue.c GValue to-from DBusMessageIter
*
* Copyright (C) 2004 Ximian, Inc.
+ * Copyright (C) 2005 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.1
*
@@ -23,20 +24,178 @@
#include <dbus-gvalue.h>
+/* This is slightly evil, we don't use g_value_set_foo() functions */
+#define MAP_BASIC_INIT(d_t, g_t) \
+ case DBUS_TYPE_##d_t: \
+ g_value_init (value, G_TYPE_##g_t); \
+ break
+
+gboolean
+dbus_gvalue_init (int type,
+ GValue *value)
+{
+ gboolean can_convert;
+
+ can_convert = TRUE;
+
+ switch (type)
+ {
+ MAP_BASIC_INIT (BOOLEAN, BOOLEAN);
+ MAP_BASIC_INIT (BYTE, UCHAR);
+ MAP_BASIC_INIT (INT32, INT);
+ MAP_BASIC_INIT (UINT32, UINT);
+ MAP_BASIC_INIT (INT64, INT64);
+ MAP_BASIC_INIT (UINT64, UINT64);
+ MAP_BASIC_INIT (DOUBLE, DOUBLE);
+
+ case DBUS_TYPE_INT16:
+ g_value_init (value, G_TYPE_INT);
+ break;
+ case DBUS_TYPE_UINT16:
+ g_value_init (value, G_TYPE_UINT);
+ break;
+
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ g_value_init (value, G_TYPE_STRING);
+ break;
+
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_ARRAY:
+ case DBUS_TYPE_VARIANT:
+ default:
+ can_convert = FALSE;
+ }
+#undef MAP_BASIC_INIT
+ return can_convert;
+}
+
+const char *
+dbus_gvalue_genmarshal_name_from_type (int type)
+{
+ switch (type)
+ {
+ case DBUS_TYPE_BOOLEAN:
+ return "BOOLEAN";
+ case DBUS_TYPE_BYTE:
+ return "UCHAR";
+ case DBUS_TYPE_INT32:
+ return "INT";
+ case DBUS_TYPE_UINT32:
+ return "UINT";
+ case DBUS_TYPE_INT64:
+ return "INT64";
+ case DBUS_TYPE_UINT64:
+ return "UINT64";
+ case DBUS_TYPE_DOUBLE:
+ return "DOUBLE";
+ case DBUS_TYPE_INT16:
+ return "INT";
+ break;
+ case DBUS_TYPE_UINT16:
+ return "UINT";
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ return "STRING";
+
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_ARRAY:
+ case DBUS_TYPE_VARIANT:
+ return NULL;
+ }
+ return NULL;
+}
+
+const char *
+dbus_gvalue_binding_type_from_type (int type)
+{
+#define STRINGIFY(x) \
+ case x: \
+ return (#x)
+
+ switch (type)
+ {
+ STRINGIFY(DBUS_TYPE_BOOLEAN);
+ STRINGIFY(DBUS_TYPE_BYTE);
+ STRINGIFY(DBUS_TYPE_INT32);
+ STRINGIFY(DBUS_TYPE_UINT32);
+ STRINGIFY(DBUS_TYPE_INT64);
+ STRINGIFY(DBUS_TYPE_UINT64);
+ STRINGIFY(DBUS_TYPE_DOUBLE);
+ case DBUS_TYPE_INT16:
+ return "DBUS_TYPE_INT32";
+ case DBUS_TYPE_UINT16:
+ return "DBUS_TYPE_UINT32";
+ STRINGIFY(DBUS_TYPE_STRING);
+ STRINGIFY(DBUS_TYPE_OBJECT_PATH);
+ STRINGIFY(DBUS_TYPE_SIGNATURE);
+
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_ARRAY:
+ case DBUS_TYPE_VARIANT:
+ return NULL;
+ }
+#undef STRINGIFY
+ return NULL;
+}
+
+const char *
+dbus_gvalue_ctype_from_type (int type, gboolean in)
+{
+ switch (type)
+ {
+ case DBUS_TYPE_BOOLEAN:
+ return "gboolean";
+ case DBUS_TYPE_BYTE:
+ return "guchar";
+ case DBUS_TYPE_INT32:
+ return "gint32";
+ case DBUS_TYPE_UINT32:
+ return "guint32";
+ case DBUS_TYPE_INT64:
+ return "gint64";
+ case DBUS_TYPE_UINT64:
+ return "guint64";
+ case DBUS_TYPE_DOUBLE:
+ return "gdouble";
+ case DBUS_TYPE_INT16:
+ return "gint";
+ break;
+ case DBUS_TYPE_UINT16:
+ return "guint";
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ /* FIXME - kind of a hack */
+ if (in)
+ return "const char *";
+ else
+ return "char *";
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_ARRAY:
+ case DBUS_TYPE_VARIANT:
+ return NULL;
+ }
+ return NULL;
+}
+
gboolean
dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
{
gboolean can_convert = TRUE;
- /* This is slightly evil, we don't use g_value_set_foo() functions */
+ g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int));
+
+ dbus_gvalue_init (dbus_message_iter_get_arg_type (iter), value);
+
+/* This is slightly evil, we don't use g_value_set_foo() functions */
#define MAP_BASIC(d_t, g_t) \
case DBUS_TYPE_##d_t: \
- g_value_init (value, G_TYPE_##g_t); \
dbus_message_iter_get_basic (iter, &value->data[0]); \
break
- g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int));
-
switch (dbus_message_iter_get_arg_type (iter))
{
MAP_BASIC (BOOLEAN, BOOLEAN);
@@ -50,7 +209,6 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
case DBUS_TYPE_INT16:
{
dbus_int16_t v;
- g_value_init (value, G_TYPE_INT);
dbus_message_iter_get_basic (iter, &v);
g_value_set_int (value, v);
}
@@ -58,7 +216,6 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
case DBUS_TYPE_UINT16:
{
dbus_uint16_t v;
- g_value_init (value, G_TYPE_UINT);
dbus_message_iter_get_basic (iter, &v);
g_value_set_uint (value, v);
}
@@ -70,8 +227,6 @@ dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
{
const char *s;
- g_value_init (value, G_TYPE_STRING);
-
dbus_message_iter_get_basic (iter, &s);
g_value_set_string (value, s);
}
diff --git a/glib/dbus-gvalue.h b/glib/dbus-gvalue.h
index fc45f7e0..fafda585 100644
--- a/glib/dbus-gvalue.h
+++ b/glib/dbus-gvalue.h
@@ -7,8 +7,32 @@
G_BEGIN_DECLS
-gboolean dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value);
-gboolean dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value);
+/* Used for return value storage */
+typedef union
+{
+ gboolean gboolean_val;
+ guchar guchar_val;
+ gint int_val;
+ gint64 gint64_val;
+ guint64 guint64_val;
+ double double_val;
+ gpointer gpointer_val;
+ char * chararray_val;
+} DBusBasicGValue;
+
+const char * dbus_gvalue_genmarshal_name_from_type (int type);
+
+const char * dbus_gvalue_ctype_from_type (int type, gboolean in);
+
+const char * dbus_gvalue_binding_type_from_type (int type);
+
+gboolean dbus_gvalue_init (int type,
+ GValue *value);
+
+gboolean dbus_gvalue_demarshal (DBusMessageIter *iter,
+ GValue *value);
+gboolean dbus_gvalue_marshal (DBusMessageIter *iter,
+ GValue *value);
G_END_DECLS