diff options
| -rw-r--r-- | ChangeLog | 129 | ||||
| -rw-r--r-- | dbus/dbus-glib.h | 14 | ||||
| -rw-r--r-- | glib/Makefile.am | 3 | ||||
| -rw-r--r-- | glib/dbus-binding-tool-glib.c | 812 | ||||
| -rw-r--r-- | glib/dbus-binding-tool-glib.h | 33 | ||||
| -rw-r--r-- | glib/dbus-gidl.c | 73 | ||||
| -rw-r--r-- | glib/dbus-gidl.h | 14 | ||||
| -rw-r--r-- | glib/dbus-glib-tool.c | 120 | ||||
| -rw-r--r-- | glib/dbus-glib-tool.h | 37 | ||||
| -rw-r--r-- | glib/dbus-gobject.c | 596 | ||||
| -rw-r--r-- | glib/dbus-gobject.h | 35 | ||||
| -rw-r--r-- | glib/dbus-gparser.c | 8 | ||||
| -rw-r--r-- | glib/dbus-gproxy.c | 52 | ||||
| -rw-r--r-- | glib/dbus-gutils.c | 28 | ||||
| -rw-r--r-- | glib/dbus-gutils.h | 1 | ||||
| -rw-r--r-- | glib/dbus-gvalue.c | 171 | ||||
| -rw-r--r-- | glib/dbus-gvalue.h | 28 | ||||
| -rw-r--r-- | test/glib/Makefile.am | 15 | ||||
| -rw-r--r-- | test/glib/test-dbus-glib.c | 203 | ||||
| -rw-r--r-- | test/glib/test-service-glib.c | 76 | ||||
| -rw-r--r-- | test/glib/test-service-glib.xml | 33 | 
21 files changed, 2347 insertions, 134 deletions
@@ -1,3 +1,132 @@ +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. +  2005-02-15  Havoc Pennington  <hp@redhat.com>  	* dbus/dbus-connection.c (dbus_connection_dispatch): always diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h index 5c002f49..a9aad540 100644 --- a/dbus/dbus-glib.h +++ b/dbus/dbus-glib.h @@ -89,25 +89,21 @@ DBusGConnection* dbus_g_bus_get     (DBusBusType   type,  typedef struct DBusGObjectInfo DBusGObjectInfo;  typedef struct DBusGMethodInfo DBusGMethodInfo; -typedef DBusHandlerResult (* DBusGMethodMarshaller) (DBusGConnection    *connection, -                                                     DBusGMessage       *message, -                                                     void               *user_data); -  /** - * Object typically generated by dbus-glib-tool that + * Object typically generated by dbus-binding-tool that   * stores a mapping from introspection data to a   * function pointer for a C method to be invoked.   */  struct DBusGMethodInfo  {    GCallback                 function;    /**< C method to invoke */ -  DBusGMethodMarshaller     marshaller;  /**< Marshaller to go DBusGMessage to C method */ +  GClosureMarshal           marshaller;  /**< Marshaller to invoke method */    int                       data_offset; /**< Offset into the introspection data */  };  /**   * Introspection data for a GObject, normally autogenerated by - * a tool such as dbus-glib-tool. + * a tool such as dbus-binding-tool.   */  struct DBusGObjectInfo  { @@ -115,7 +111,8 @@ struct DBusGObjectInfo                                   *   by adding DBusGObjectInfo2, DBusGObjectInfo3, etc.                                   */    const DBusGMethodInfo *infos; /**< Array of method pointers */ -  const unsigned char *data;    /**< Introspection data */ +  int   n_infos;                /**< Length of the infos array */ +  const char *data;             /**< Introspection data */  };  void dbus_g_object_class_install_info    (GObjectClass          *object_class, @@ -174,6 +171,7 @@ void              dbus_g_proxy_call_no_reply         (DBusGProxy        *proxy,                                                        const char        *method,                                                        int                first_arg_type,                                                        ...); +  const char*       dbus_g_proxy_get_bus_name          (DBusGProxy        *proxy);  #undef DBUS_INSIDE_DBUS_GLIB_H 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 diff --git a/test/glib/Makefile.am b/test/glib/Makefile.am index a679bcc1..0a246252 100644 --- a/test/glib/Makefile.am +++ b/test/glib/Makefile.am @@ -40,7 +40,20 @@ test_dbus_glib_SOURCES=				\  test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la  test_service_glib_SOURCES=				\ -	test-service-glib.c +	test-service-glib.c				\ +	test-service-glib-glue.h + +BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h + +test-service-glib-glue.h: $(top_builddir)/glib/dbus-binding-tool test-service-glib.xml +	$(top_builddir)/glib/dbus-binding-tool --mode=glib-server $(srcdir)/test-service-glib.xml > test-service-glib-glue.h.tmp +	mv test-service-glib-glue.h.tmp test-service-glib-glue.h + +test-service-glib-bindings.h: $(top_builddir)/glib/dbus-binding-tool test-service-glib.xml +	$(top_builddir)/glib/dbus-binding-tool --mode=glib-client $(srcdir)/test-service-glib.xml > test-service-glib-bindings.h.tmp +	mv test-service-glib-bindings.h.tmp test-service-glib-bindings.h + +CLEANFILES = test-service-glib-glue.h test-service-glib-glue.h.tmp test-service-glib-bindings.h test-service-glib-bindings.h.tmp  test_service_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la diff --git a/test/glib/test-dbus-glib.c b/test/glib/test-dbus-glib.c index cee9316b..ca36af1f 100644 --- a/test/glib/test-dbus-glib.c +++ b/test/glib/test-dbus-glib.c @@ -3,6 +3,7 @@  #include <stdio.h>  #include <stdlib.h>  #include <string.h> +#include "test-service-glib-bindings.h"  static GMainLoop *loop = NULL;  static int n_times_foo_received = 0; @@ -37,7 +38,11 @@ main (int argc, char **argv)    int i;    guint32 result;    const char *v_STRING; +  char *v_STRING_2;    guint32 v_UINT32; +  guint32 v_UINT32_2; +  double v_DOUBLE; +  double v_DOUBLE_2;    g_type_init (); @@ -220,10 +225,204 @@ main (int argc, char **argv)                    n_times_foo_received);        exit (1);      } -   -  g_object_unref (G_OBJECT (driver)); + +  /* Activate test servie */  +  g_print ("Activating TestSuiteGLibService\n"); +  v_STRING = "org.freedesktop.DBus.TestSuiteGLibService"; +  v_UINT32 = 0; +  call = dbus_g_proxy_begin_call (driver, "StartServiceByName", +                                  DBUS_TYPE_STRING, +                                  &v_STRING, +                                  DBUS_TYPE_UINT32, +                                  &v_UINT32, +                                  DBUS_TYPE_INVALID); + +  error = NULL; +  if (!dbus_g_proxy_end_call (driver, call, &error, +                             DBUS_TYPE_UINT32, &result, +                             DBUS_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete Activate call: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } +    g_object_unref (G_OBJECT (proxy)); + +  proxy = dbus_g_proxy_new_for_name_owner (connection, +                                           "org.freedesktop.DBus.TestSuiteGLibService", +                                           "/org/freedesktop/DBus/Tests/MyTestObject", +                                           "org.freedesktop.DBus.Tests.MyObject", +                                           &error); +  if (proxy == NULL) +    { +      g_printerr ("Failed to create proxy for name owner: %s\n", +                  error->message); +      g_error_free (error); +      exit (1);       +    } + +  call = dbus_g_proxy_begin_call (proxy, "DoNothing", +                                  DBUS_TYPE_INVALID); +  error = NULL; +  if (!dbus_g_proxy_end_call (proxy, call, &error, DBUS_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete DoNothing call: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } + +  v_UINT32 = 42; +  call = dbus_g_proxy_begin_call (proxy, "Increment", +				  DBUS_TYPE_UINT32, &v_UINT32, +                                  DBUS_TYPE_INVALID); +  error = NULL; +  if (!dbus_g_proxy_end_call (proxy, call, &error, +			      DBUS_TYPE_UINT32, &v_UINT32_2, +			      DBUS_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete Increment call: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } + +  if (v_UINT32_2 != v_UINT32 + 1) +    { +      g_printerr ("Increment call returned %d, should be 43\n", v_UINT32_2); +      exit (1); +    } + +  call = dbus_g_proxy_begin_call (proxy, "ThrowError", DBUS_TYPE_INVALID); +  error = NULL; +  if (dbus_g_proxy_end_call (proxy, call, &error, DBUS_TYPE_INVALID) != FALSE) +    { +      g_printerr ("ThrowError call unexpectedly succeeded!\n"); +      exit (1); +    } + +  g_print ("ThrowError failed (as expected) returned error: %s\n", error->message); +  g_error_free (error); + +  v_STRING = "foobar"; +  call = dbus_g_proxy_begin_call (proxy, "Uppercase", +				  DBUS_TYPE_STRING, &v_STRING, +				  DBUS_TYPE_INVALID); +  error = NULL; +  if (!dbus_g_proxy_end_call (proxy, call, &error, +			      DBUS_TYPE_STRING, &v_STRING_2, +			      DBUS_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete Uppercase call: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } +  if (strcmp ("FOOBAR", v_STRING_2) != 0) +    { +      g_printerr ("Uppercase call returned unexpected string %s\n", v_STRING_2); +      exit (1); +    } + +  v_STRING = "bazwhee"; +  v_UINT32 = 26; +  v_DOUBLE = G_PI; +  call = dbus_g_proxy_begin_call (proxy, "ManyArgs", +				  DBUS_TYPE_UINT32, &v_UINT32, +				  DBUS_TYPE_STRING, &v_STRING, +				  DBUS_TYPE_DOUBLE, &v_DOUBLE, +				  DBUS_TYPE_INVALID); +  error = NULL; +  if (!dbus_g_proxy_end_call (proxy, call, &error, +			      DBUS_TYPE_DOUBLE, &v_DOUBLE_2, +			      DBUS_TYPE_STRING, &v_STRING_2, +			      DBUS_TYPE_INVALID)) +    { +      g_printerr ("Failed to complete ManyArgs call: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } +  if (v_DOUBLE_2 < 55 || v_DOUBLE_2 > 56) +    { +      g_printerr ("ManyArgs call returned unexpected double value %f\n", v_DOUBLE_2); +      exit (1); +    } +  if (strcmp ("BAZWHEE", v_STRING_2) != 0) +    { +      g_printerr ("ManyArgs call returned unexpected string %s\n", v_STRING_2); +      exit (1); +    } + +  if (!org_freedesktop_DBus_Tests_MyObject_do_nothing (proxy, &error)) +    { +      g_printerr ("Failed to complete (wrapped) DoNothing call: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } + +  if (!org_freedesktop_DBus_Tests_MyObject_increment (proxy, 42, &v_UINT32_2, &error)) +    { +      g_printerr ("Failed to complete (wrapped) Increment call: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } + +  if (v_UINT32_2 != 43) +    { +      g_printerr ("(wrapped) increment call returned %d, should be 43\n", v_UINT32_2); +      exit (1); +    } + +  if (org_freedesktop_DBus_Tests_MyObject_throw_error (proxy, &error) != FALSE) +    { +      g_printerr ("(wrapped) ThrowError call unexpectedly succeeded!\n"); +      exit (1); +    } + +  g_print ("(wrapped) ThrowError failed (as expected) returned error: %s\n", error->message); +  g_error_free (error); + +  if (!org_freedesktop_DBus_Tests_MyObject_uppercase (proxy, "foobar", &v_STRING_2, &error))  +    { +      g_printerr ("Failed to complete (wrapped) Uppercase call: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } +  if (strcmp ("FOOBAR", v_STRING_2) != 0) +    { +      g_printerr ("(wrapped) Uppercase call returned unexpected string %s\n", v_STRING_2); +      exit (1); +    } + +  if (!org_freedesktop_DBus_Tests_MyObject_many_args (proxy, 26, "bazwhee", G_PI, +						      &v_DOUBLE_2, &v_STRING_2, &error)) +    { +      g_printerr ("Failed to complete (wrapped) ManyArgs call: %s\n", +                  error->message); +      g_error_free (error); +      exit (1); +    } +  if (v_DOUBLE_2 < 55 || v_DOUBLE_2 > 56) +    { +      g_printerr ("(wrapped) ManyArgs call returned unexpected double value %f\n", v_DOUBLE_2); +      exit (1); +    } +  if (strcmp ("BAZWHEE", v_STRING_2) != 0) +    { +      g_printerr ("(wrapped) ManyArgs call returned unexpected string %s\n", v_STRING_2); +      exit (1); +    } + +  g_object_unref (G_OBJECT (proxy)); +  g_object_unref (G_OBJECT (driver)); +    g_print ("Successfully completed %s\n", argv[0]);    return 0; diff --git a/test/glib/test-service-glib.c b/test/glib/test-service-glib.c index 2fa3095c..81cb556f 100644 --- a/test/glib/test-service-glib.c +++ b/test/glib/test-service-glib.c @@ -4,6 +4,8 @@  #include <stdlib.h>  #include <string.h>  #include <glib/gi18n.h> +#include <glib-object.h> +#include <glib/gquark.h>  typedef struct MyObject MyObject;  typedef struct MyObjectClass MyObjectClass; @@ -30,6 +32,28 @@ struct MyObjectClass  G_DEFINE_TYPE(MyObject, my_object, G_TYPE_OBJECT) +typedef enum +{ +  MY_OBJECT_ERROR_FOO, +  MY_OBJECT_ERROR_BAR +} MyObjectError; + +#define MY_OBJECT_ERROR my_object_error_quark () + +gboolean my_object_do_nothing (MyObject *obj, GError **error); + +gboolean my_object_increment (MyObject *obj, gint32 x, int *ret, GError **error); + +gboolean my_object_throw_error (MyObject *obj, GError **error); + +gboolean my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error); + +gboolean my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error); + +#include "test-service-glib-glue.h" + +GQuark my_object_error_quark (void); +  /* Properties */  enum  { @@ -115,6 +139,54 @@ my_object_class_init (MyObjectClass *mobject_class)                                                          "default value",                                                          G_PARAM_READWRITE));  } + +GQuark +my_object_error_quark (void) +{ +  static GQuark quark = 0; +  if (!quark) +    quark = g_quark_from_static_string ("my_object_error"); + +  return quark; +} + +gboolean +my_object_do_nothing (MyObject *obj, GError **error) +{ +  return TRUE; +} + +gboolean +my_object_increment (MyObject *obj, gint32 x, int *ret, GError **error) +{ +  *ret = x +1; +  return TRUE; +} + +gboolean +my_object_throw_error (MyObject *obj, GError **error) +{ +  g_set_error (error, +	       MY_OBJECT_ERROR, +	       MY_OBJECT_ERROR_FOO, +	       "this method always loses"); +  return FALSE; +} + +gboolean +my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error) +{ +  *ret = g_ascii_strup (str, -1); +  return TRUE; +} + +gboolean +my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error) +{ +  *d_ret = trouble + (x * 2); +  *str_ret = g_ascii_strup (str, -1); +  return TRUE; +}  static GMainLoop *loop; @@ -148,8 +220,10 @@ main (int argc, char **argv)    obj = g_object_new (MY_TYPE_OBJECT, NULL); +  dbus_g_object_class_install_info (G_OBJECT_GET_CLASS (obj), +				    &dbus_glib_my_object_object_info);    dbus_g_connection_register_g_object (connection, -                                       "/org/freedesktop/my_test_object", +                                       "/org/freedesktop/DBus/Tests/MyTestObject",                                         obj);    driver_proxy = dbus_g_proxy_new_for_name (connection, diff --git a/test/glib/test-service-glib.xml b/test/glib/test-service-glib.xml new file mode 100644 index 00000000..223bf67f --- /dev/null +++ b/test/glib/test-service-glib.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<node name="/org/freedesktop/DBus/Tests/MyTestObject"> + +  <interface name="org.freedesktop.DBus.Tests.MyObject" c_name="my_object"> + +    <method name="DoNothing" c_name="my_object_do_nothing"> +    </method> + +    <method name="Increment" c_name="my_object_increment"> +      <arg type="uint32" name="x" /> +      <arg type="uint32" direction="out" /> +    </method> + +    <method name="ThrowError" c_name="my_object_throw_error"> +    </method> + +    <method name="Uppercase" c_name="my_object_uppercase"> +      <arg type="string" direction="in" /> +      <arg type="string" direction="out" /> +    </method> + +    <method name="ManyArgs" c_name="my_object_many_args"> +      <arg type="uint32" name="x" direction="in" /> +      <arg type="string" name="str" direction="in" /> +      <arg type="double" name="trouble" direction="in" /> +      <arg type="double" name="d_ret" direction="out" /> +      <arg type="string" name="str_ret" direction="out" /> +    </method> + +  </interface> + +</node>  | 
