diff options
| -rw-r--r-- | ChangeLog | 62 | ||||
| -rw-r--r-- | dbus/dbus-glib.h | 19 | ||||
| -rw-r--r-- | doc/TODO | 5 | ||||
| -rw-r--r-- | glib/dbus-binding-tool-glib.c | 88 | ||||
| -rw-r--r-- | glib/dbus-gobject.c | 547 | ||||
| -rw-r--r-- | glib/dbus-gproxy.c | 3 | ||||
| -rw-r--r-- | test/glib/.cvsignore | 2 | ||||
| -rw-r--r-- | test/glib/Makefile.am | 17 | ||||
| -rw-r--r-- | test/glib/my-object-marshal.list | 2 | ||||
| -rw-r--r-- | test/glib/test-dbus-glib.c | 128 | ||||
| -rw-r--r-- | test/glib/test-service-glib.c | 38 | ||||
| -rw-r--r-- | test/glib/test-service-glib.xml | 11 | 
12 files changed, 648 insertions, 274 deletions
| @@ -1,3 +1,65 @@ +2005-06-17  Colin Walters  <walters@verbum.org> + +	* glib/dbus-gproxy.c (dbus_g_proxy_emit_remote_signal): Don't +	spew warnings if we get malformed remote signals. + +	* glib/dbus-gobject.c (propsig_iterate): New function. +	(lookup_object_info): New function, extracted from +	lookup_object_and_method. +	(introspect_properties, introspect_signals): Delete; these +	are merged into write_interface. +	(write_interface): Write out signals and properties here; +	dump the org.gtk.object stuff and use the interface given +	in the introspection data blob.  Also fix up property XML. +	(lookup_values): New function. +	(introspect_interfaces): Gather a mapping from interface to a +	list of its methods, signals, and properties, then write out +	each interface. +	(lookup_object_and_method): Use lookup_object_info. +	(struct DBusGSignalClosure): Add interface. +	(dbus_g_signal_closure_new): Add interface. Don't dup signame; +	we can just use the constant data. +	(dbus_g_signal_closure_finalize): Don't free signal name. +	(signal_emitter_marshaller): Use interface from signal closure. +	(export_signals): Only export signals mentioned in introspection +	blob. +	(dbus_g_connection_register_g_object): Warn if we have no +	introspection data for an object. +	(funcsig_equal): Remove unused variable. +	(dbus_g_object_register_marshaller): Take varargs instead of +	list. +	(dbus_g_object_register_marshaller_array): New function, +	extracted from old dbus_g_object_register_marshaller. + +	* glib/dbus-binding-tool-glib.c (struct DBusBindingToolCData): Add +	signals and property data. +	(write_quoted_string): New function, extracted from generate_glue. +	(generate_glue): Write signals and properties to introspection +	blob. + +	* dbus/dbus-glib.h (struct DBusGObjectInfo): Include +	exported_signals and exported_properties. +	(dbus_g_object_register_marshaller): Update prototype. +	(dbus_g_object_register_marshaller_array): Prototype. +	 +	* test/glib/test-dbus-glib.c: Extend testing to cover new signals. + +	* test/glib/test-service-glib.c: Add new test signals and method +	to emit them. + +	* test/glib/test-service-glib.xml: Add some test signals. + +	* test/glib/Makefile.am (BUILT_SOURCES): Add my-object-marshal.c +	and my-object-marshal.h +	(test_service_glib_SOURCES, test_dbus_glib_SOURCES): Add +	my-object-marshal.c. +	(my-object-marshal.c, my-object-marshal.h): Implement. + +	* test/glib/.cvsignore: Update. + +	* doc/TODO: Remove two GLib TODO items fixed by this +	patch. +  2005-06-16  Colin Walters  <walters@verbum.org>  	* doc/TODO: Update for GLib bindings. diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h index 80ed7f4f..4debe6fe 100644 --- a/dbus/dbus-glib.h +++ b/dbus/dbus-glib.h @@ -109,9 +109,11 @@ struct DBusGObjectInfo    int   format_version;         /**< Allows us to change the rest of this struct                                   *   by adding DBusGObjectInfo2, DBusGObjectInfo3, etc.                                   */ -  const DBusGMethodInfo *infos; /**< Array of method pointers */ -  int   n_infos;                /**< Length of the infos array */ +  const DBusGMethodInfo *method_infos; /**< Array of method pointers */ +  int   n_method_infos;                /**< Length of the infos array */    const char *data;             /**< Introspection data */ +  const char *exported_signals;  /**< Exported signals */ +  const char *exported_properties;  /**< Exported properties */  };  void dbus_g_object_type_install_info     (GType                 object_type, @@ -189,13 +191,16 @@ gboolean     dbus_g_value_iterator_get_values       (DBusGValueIterator   *iter,  void         dbus_g_value_iterator_recurse          (DBusGValueIterator   *iter,  						     DBusGValueIterator   *sub); -void         dbus_g_value_free              (DBusGValue          *value); +void         dbus_g_value_free                      (DBusGValue          *value); -void         dbus_g_object_register_marshaller  (GType             rettype, -						 guint             n_types, -						 const GType      *param_types, -						 GClosureMarshal   marshaller); +void         dbus_g_object_register_marshaller      (GClosureMarshal  marshaller, +						     GType            rettype, +						     ...); +void         dbus_g_object_register_marshaller_array(GClosureMarshal  marshaller, +						     GType            rettype, +						     guint            n_types, +						     const GType*     types);  typedef struct DBusGProxy       DBusGProxy;  typedef struct DBusGProxyClass  DBusGProxyClass; @@ -30,11 +30,6 @@ Important for 1.0 GLib Bindings   - Annotations for "do not take ownership of this return value" on server - - Fix/test signals - - - Don't autoexport signals and properties; use metadata either in -   code (preferable) or annotation in XML -   - Fix TYPE_OBJECT_PATH marshalling; see:     http://lists.freedesktop.org/archives/dbus/2005-June/002774.html diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c index b04386bc..fd849a86 100644 --- a/glib/dbus-binding-tool-glib.c +++ b/glib/dbus-binding-tool-glib.c @@ -48,6 +48,8 @@ typedef struct    GHashTable *generated;    GString *blob; +  GString *signal_blob; +  GString *property_blob;    guint count;  } DBusBindingToolCData; @@ -365,13 +367,37 @@ write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error,  }  static gboolean +write_quoted_string (GIOChannel *channel, GString *string, GError **error) +{ +  guint i; + +  WRITE_OR_LOSE ("\""); +  for (i = 0; i < string->len; i++) +    { +      if (string->str[i] != '\0') +	{ +	  if (!g_io_channel_write_chars (channel, string->str + i, 1, NULL, error)) +	    return FALSE; +	} +      else +	{ +	  if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error)) +	    return FALSE; +	} +    } +  WRITE_OR_LOSE ("\\0\""); +  return TRUE; + io_lose: +  return FALSE; +} + +static gboolean  generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)  {    if (base_info_get_type (base) == INFO_TYPE_NODE)      {        GString *object_introspection_data_blob;        GIOChannel *channel; -      guint i;        channel = data->channel; @@ -380,6 +406,9 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)        data->blob = object_introspection_data_blob;        data->count = 0; +      data->signal_blob = g_string_new_len ("", 0); +      data->property_blob = g_string_new_len ("", 0); +        if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, data->prefix))  	goto io_lose; @@ -402,29 +431,28 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)  	goto io_lose;        if (!write_printf_to_iochannel ("  %d,\n", channel, error, data->count))  	goto io_lose; -      WRITE_OR_LOSE("  \""); -      for (i = 0; i < object_introspection_data_blob->len; i++) -	{ -	  if (object_introspection_data_blob->str[i] != '\0') -	    { -	      if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error)) -		return FALSE; -	    } -	  else -	    { -	      if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error)) -		return FALSE; -	    } -	} -      WRITE_OR_LOSE ("\"\n};\n\n"); + +      if (!write_quoted_string (channel, object_introspection_data_blob, error)) +	goto io_lose; +      WRITE_OR_LOSE (",\n"); +      if (!write_quoted_string (channel, data->signal_blob, error)) +	goto io_lose; +      WRITE_OR_LOSE (",\n"); +      if (!write_quoted_string (channel, data->property_blob, error)) +	goto io_lose; +      WRITE_OR_LOSE ("\n};\n\n");        g_string_free (object_introspection_data_blob, TRUE); +      g_string_free (data->signal_blob, TRUE); +      g_string_free (data->property_blob, TRUE);      }    else      {        GIOChannel *channel;        InterfaceInfo *interface;        GSList *methods; +      GSList *signals; +      GSList *properties;        GSList *tmp;        const char *interface_c_name;        GString *object_introspection_data_blob; @@ -532,6 +560,34 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)            data->count++;          } + +      signals = interface_info_get_signals (interface); + +      for (tmp = signals; tmp != NULL; tmp = g_slist_next (tmp)) +        { +          SignalInfo *sig; +	   +	  sig = tmp->data; + +	  g_string_append (data->signal_blob, interface_info_get_name (interface)); +	  g_string_append_c (data->signal_blob, '\0'); +	  g_string_append (data->signal_blob, signal_info_get_name (sig)); +	  g_string_append_c (data->signal_blob, '\0'); +	} + +      properties = interface_info_get_properties (interface); + +      for (tmp = properties; tmp != NULL; tmp = g_slist_next (tmp)) +        { +          PropertyInfo *prop; +	   +	  prop = tmp->data; + +	  g_string_append (data->property_blob, interface_info_get_name (interface)); +	  g_string_append_c (data->property_blob, '\0'); +	  g_string_append (data->property_blob, property_info_get_name (prop)); +	  g_string_append_c (data->property_blob, '\0'); +	}      }    return TRUE;   io_lose: diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index 7a57d4ea..40d1da03 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -204,160 +204,94 @@ method_output_signature_from_object_info (const DBusGObjectInfo *object,    return method_dir_signature_from_object_info (object, method, FALSE);  } -static void -gobject_unregister_function (DBusConnection  *connection, -                             void            *user_data) +static const char * +propsig_iterate (const char *data, const char **iface, const char **name)  { -  GObject *object; - -  object = G_OBJECT (user_data); +  *iface = data; -  /* FIXME */ +  data = string_table_next (data); +  *name = data; +  return string_table_next (data);  } -static void -introspect_properties (GObject *object, GString *xml) +static const DBusGObjectInfo * +lookup_object_info (GObject *object)  { -  unsigned int i; -  unsigned int n_specs; -  GType last_type; -  GParamSpec **specs; +  const DBusGObjectInfo *ret; +  GType classtype; +   +  ret = NULL; +   +  g_static_rw_lock_reader_lock (&globals_lock); -  last_type = G_TYPE_INVALID; -  specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), -                                          &n_specs); +  if (info_hash == NULL) +    goto out; -  for (i = 0; i < n_specs; i++ ) +  for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))      { -      char *s; -      const char *dbus_type; -      gboolean can_set; -      gboolean can_get; -      GParamSpec *spec = specs[i]; -       -      dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec)); -      if (dbus_type == NULL) -	continue; -       -      if (spec->owner_type != last_type) -	{ -          if (last_type != G_TYPE_INVALID) -            g_string_append (xml, "  </interface>\n"); - +      const DBusGObjectInfo *info; -          /* FIXME what should the namespace on the interface be in -           * general?  should people be able to set it for their -           * objects? -           */ -          g_string_append (xml, "  <interface name=\"org.gtk.objects."); -          g_string_append (xml, g_type_name (spec->owner_type)); -          g_string_append (xml, "\">\n"); +      info = g_hash_table_lookup (info_hash, g_type_class_peek (classtype)); -          last_type = spec->owner_type; +      if (info != NULL && info->format_version == 0) +	{ +	  ret = info; +	  break;  	} - -      can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 && -		 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); -       -      can_get = (spec->flags & G_PARAM_READABLE) != 0; - -      s = uscore_to_wincaps (spec->name); -       -      if (can_set || can_get) -        { -          g_string_append (xml, "    <property name=\""); -          g_string_append (xml, s); -          g_string_append (xml, "\" type=\""); -          g_string_append (xml, dbus_type); -          g_string_append (xml, "\" access=\""); - -          if (can_set && can_get) -            g_string_append (xml, "readwrite"); -          else if (can_get) -            g_string_append (xml, "read"); -          else -            { -              g_assert (can_set); -              g_string_append (xml, "write"); -            } -           -          g_string_append (xml, "\"/>\n"); -        } -       -      g_free (s);      } -  if (last_type != G_TYPE_INVALID) -    g_string_append (xml, "  </interface>\n"); + out: +  g_static_rw_lock_reader_unlock (&globals_lock); -  g_free (specs); +  return ret;  }  static void -introspect_signals (GType type, GString *xml) +gobject_unregister_function (DBusConnection  *connection, +                             void            *user_data)  { -  guint i; -  guint *ids, n_ids; - -  ids = g_signal_list_ids (type, &n_ids); -  if (!n_ids) -    return; - -  g_string_append (xml, "  <interface name=\"org.gtk.objects."); -  g_string_append (xml, g_type_name (type)); -  g_string_append (xml, "\">\n"); - -  /* FIXME: recurse to parent types ? */ -  for (i = 0; i < n_ids; i++) -    { -      guint arg; -      GSignalQuery query; -       -      g_signal_query (ids[i], &query); - -      if (query.return_type != G_TYPE_NONE) -	continue; /* FIXME: these could be listed as methods ? */ - -      g_string_append (xml, "    <signal name=\""); -      g_string_append (xml, query.signal_name); -      g_string_append (xml, "\">\n"); - -      for (arg = 0; arg < query.n_params; arg++) -	{ -	  const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]); +  GObject *object; -	  if (!dbus_type) -	    continue; -	   -          g_string_append (xml, "      <arg type=\""); -          g_string_append (xml, dbus_type); -          g_string_append (xml, "\"/>\n"); -	} +  object = G_OBJECT (user_data); -      g_string_append (xml, "    </signal>\n"); -    } +  /* FIXME */ -  g_string_append (xml, "  </interface>\n");  }  typedef struct  {    GString *xml; +  GType gtype;    const DBusGObjectInfo *object_info; -} DBusGlibWriteIterfaceData; +} DBusGLibWriteIterfaceData; + +typedef struct +{ +  GSList *methods; +  GSList *signals; +  GSList *properties; +} DBusGLibWriteInterfaceValues;  static void  write_interface (gpointer key, gpointer val, gpointer user_data)  {    const char *name;    GSList *methods; +  GSList *signals; +  GSList *properties;    GString *xml;    const DBusGObjectInfo *object_info; -  DBusGlibWriteIterfaceData *data; +  DBusGLibWriteIterfaceData *data; +  DBusGLibWriteInterfaceValues *values;    name = key; -  methods = val; + +  values = val; +  methods = values->methods; +  signals = values->signals; +  properties = values->properties; +    data = user_data;    xml = data->xml;    object_info = data->object_info; @@ -390,64 +324,177 @@ write_interface (gpointer key, gpointer val, gpointer user_data)  	}        g_string_append (xml, "    </method>\n"); + +    } +  g_slist_free (values->methods); + +  for (; signals; signals = signals->next) +    { +      guint id; +      guint arg; +      const char *signame; +      GSignalQuery query; +      char *s; + +      signame = signals->data; + +      s = _dbus_gutils_wincaps_to_uscore (signame); +       +      id = g_signal_lookup (s, data->gtype); +      g_assert (id != 0); + +      g_signal_query (id, &query); +      g_assert (query.return_type == G_TYPE_NONE); + +      g_string_append_printf (xml, "    <signal name=\"%s\">\n", signame); + +      for (arg = 0; arg < query.n_params; arg++) +	{ +	  const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]); + +	  g_assert (dbus_type != NULL); + +          g_string_append (xml, "      <arg type=\""); +          g_string_append (xml, dbus_type); +          g_string_append (xml, "\"/>\n"); +	} + +      g_string_append (xml, "    </signal>\n"); +      g_free (s); +    } +  g_slist_free (values->signals); + +  for (; properties; properties = properties->next) +    { +      const char *propname; +      GParamSpec *spec; +      const char *dbus_type; +      gboolean can_set; +      gboolean can_get; +      char *s; + +      propname = properties->data; + +      s = _dbus_gutils_wincaps_to_uscore (spec->name); + +      spec = g_object_class_find_property (g_type_class_peek (data->gtype), s); +      g_assert (spec != NULL); +      g_free (s); +       +      dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec)); +      g_assert (dbus_type != NULL); +       +      can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 && +		 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); +       +      can_get = (spec->flags & G_PARAM_READABLE) != 0; +       +      if (can_set || can_get) +	{ +	  g_string_append_printf (xml, "    <property name=\"%s\" ", propname); +	  g_string_append (xml, "type=\""); +	  g_string_append (xml, dbus_type); +	  g_string_append (xml, "\" access=\""); + +	  if (can_set && can_get) +	    g_string_append (xml, "readwrite"); +	  else if (can_get) +	    g_string_append (xml, "read"); +	  else +	    { +	      g_assert (can_set); +	      g_string_append (xml, "write"); +	    } +           +	  g_string_append (xml, "\"/>\n"); +	} +       +      g_free (s); + +      g_string_append (xml, "    </property>\n");      } +  g_slist_free (values->properties); +  g_free (values);    g_string_append (xml, "  </interface>\n");  } +static DBusGLibWriteInterfaceValues * +lookup_values (GHashTable *interfaces, const char *method_interface) +{ +  DBusGLibWriteInterfaceValues *values; +  if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL) +    { +      values = g_new0 (DBusGLibWriteInterfaceValues, 1); +      g_hash_table_insert (interfaces, (gpointer) method_interface, values); +    } +  return values; +} +  static void  introspect_interfaces (GObject *object, GString *xml)  { -  GType classtype; +  const DBusGObjectInfo *info; +  DBusGLibWriteIterfaceData data; +  int i; +  GHashTable *interfaces; +  DBusGLibWriteInterfaceValues *values; +  const char *propsig; -  g_static_rw_lock_reader_lock (&globals_lock); +  info = lookup_object_info (object); -  for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype)) +  g_assert (info != NULL); + +  /* 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_method_infos; i++)      { -      const DBusGObjectInfo *info; -      DBusGlibWriteIterfaceData data; +      const char *method_name; +      const char *method_interface; +      const char *method_args; +      const DBusGMethodInfo *method; -      info = g_hash_table_lookup (info_hash, -				  g_type_class_peek (classtype)); +      method = &(info->method_infos[i]); -      if (info != NULL && info->format_version == 0) -	{ -	  int i; -	  GHashTable *interfaces; +      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); -	  /* 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); -	    } +      values = lookup_values (interfaces, method_interface); +      values->methods = g_slist_prepend (values->methods, (gpointer) method); +    } -	  memset (&data, 0, sizeof (data)); -	  data.xml = xml; -	  data.object_info = info; -	  g_hash_table_foreach (interfaces, write_interface, &data); +  propsig = info->exported_signals; +  while (*propsig) +    { +      const char *iface; +      const char *signame; -	  g_hash_table_destroy (interfaces); -	} +      propsig = propsig_iterate (propsig, &iface, &signame); + +      values = lookup_values (interfaces, iface); +      values->signals = g_slist_prepend (values->signals, (gpointer) signame);      } -  g_static_rw_lock_reader_unlock (&globals_lock); +  propsig = info->exported_properties; +  while (*propsig) +    { +      const char *iface; +      const char *propname; + +      propsig = propsig_iterate (propsig, &iface, &propname); + +      values = lookup_values (interfaces, iface); +      values->properties = g_slist_prepend (values->properties, (gpointer) propname); +    } +   +  memset (&data, 0, sizeof (data)); +  data.xml = xml; +  data.gtype = G_TYPE_FROM_INSTANCE (object); +  data.object_info = info; +  g_hash_table_foreach (interfaces, write_interface, &data); +   +  g_hash_table_destroy (interfaces);  }  static DBusHandlerResult @@ -492,8 +539,6 @@ handle_introspect (DBusConnection *connection,    g_string_append (xml, "    </method>\n");    g_string_append (xml, "  </interface>\n"); -  introspect_signals (G_OBJECT_TYPE (object), xml); -  introspect_properties (object, xml);    introspect_interfaces (object, xml);    /* Append child nodes */ @@ -605,64 +650,47 @@ lookup_object_and_method (GObject      *object,  			  const DBusGObjectInfo **object_ret,  			  const DBusGMethodInfo **method_ret)  { -  GType classtype;    const char *interface;    const char *member;    const char *signature;    gboolean ret; +  const DBusGObjectInfo *info; +  int i;    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 (&globals_lock); - -  if (!info_hash) -    goto out; +  info = lookup_object_info (object); +  *object_ret = info; -  for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype)) +  for (i = 0; i < info->n_method_infos; i++)      { -      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) +      const char *expected_member; +      const char *expected_interface; +      char *expected_signature; +      const DBusGMethodInfo *method; + +      method = &(info->method_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)  	{ -	  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); -	    } +	  g_free (expected_signature); +	  *method_ret = method; +	  return TRUE;  	} +      g_free (expected_signature);      } - out: -  g_static_rw_lock_reader_unlock (&globals_lock); +    return ret;  } @@ -1084,13 +1112,15 @@ typedef struct {    GClosure         closure;    DBusGConnection *connection;    GObject         *object; -  char            *signame; +  const char      *signame; +  const char      *sigiface;  } DBusGSignalClosure;  static GClosure *  dbus_g_signal_closure_new (DBusGConnection *connection,  			   GObject         *object, -			   const char      *signame) +			   const char      *signame, +			   const char      *sigiface)  {    DBusGSignalClosure *closure; @@ -1098,7 +1128,8 @@ dbus_g_signal_closure_new (DBusGConnection *connection,    closure->connection = dbus_g_connection_ref (connection);    closure->object = object; -  closure->signame = g_strdup (signame); +  closure->signame = signame; +  closure->sigiface = sigiface;    return (GClosure*) closure;  } @@ -1109,7 +1140,6 @@ dbus_g_signal_closure_finalize (gpointer data,    DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;    dbus_g_connection_unref (sigclosure->connection); -  g_free (sigclosure->signame);  }  static void @@ -1135,7 +1165,7 @@ signal_emitter_marshaller (GClosure        *closure,    g_assert (path != NULL);    signal = dbus_message_new_signal (path, -				    "org.gtk.objects", +				    sigclosure->sigiface,  				    sigclosure->signame);    if (!signal)      { @@ -1163,34 +1193,52 @@ signal_emitter_marshaller (GClosure        *closure,  }  static void -export_signals (DBusGConnection *connection, GObject *object) +export_signals (DBusGConnection *connection, const DBusGObjectInfo *info, GObject *object)  { -  guint i; -  guint *ids, n_ids; +  GType gtype; +  const char *sigdata; +  const char *iface; +  const char *signame; -  ids = g_signal_list_ids (G_TYPE_FROM_INSTANCE (object), &n_ids); -  if (!n_ids) -    return; +  gtype = G_TYPE_FROM_INSTANCE (object); -  /* FIXME: recurse to parent types ? */ -  for (i = 0; i < n_ids; i++) +  sigdata = info->exported_signals; +   +  while (*sigdata != '\0')      { +      guint id;        GSignalQuery query;        GClosure *closure; +      char *s; + +      sigdata = propsig_iterate (sigdata, &iface, &signame); -      g_signal_query (ids[i], &query); +      s = _dbus_gutils_wincaps_to_uscore (signame); + +      id = g_signal_lookup (s, gtype); +      if (id == 0) +	{ +	  g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"", +		     s, signame, g_type_name (gtype)); +	  g_free (s); +	  continue; +	} + +      g_signal_query (id, &query);        if (query.return_type != G_TYPE_NONE)  	{ -	  g_warning("Not exporting signal '%s' as it has a return type %s", query.signal_name, g_type_name (query.return_type)); +	  g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"", +		     s, g_type_name (gtype), g_type_name (query.return_type)); +	  g_free (s);  	  continue; /* FIXME: these could be listed as methods ? */  	} -      closure = dbus_g_signal_closure_new (connection, object, query.signal_name); +      closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);        g_closure_set_marshal (closure, signal_emitter_marshaller);        g_signal_connect_closure_by_id (object, -				      ids[i], +				      id,  				      0,  				      closure,  				      FALSE); @@ -1274,10 +1322,19 @@ dbus_g_connection_register_g_object (DBusGConnection       *connection,                                       const char            *at_path,                                       GObject               *object)  { +  const DBusGObjectInfo *info;    g_return_if_fail (connection != NULL);    g_return_if_fail (at_path != NULL);    g_return_if_fail (G_IS_OBJECT (object)); +  info = lookup_object_info (object); +  if (info == NULL) +    { +      g_warning ("No introspection data registered for object class \"%s\"", +		 g_type_name (G_TYPE_FROM_INSTANCE (object))); +      return; +    } +    if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),                                               at_path,                                               &gobject_dbus_vtable, @@ -1287,7 +1344,7 @@ dbus_g_connection_register_g_object (DBusGConnection       *connection,        return;      } -  export_signals (connection, object); +  export_signals (connection, info, object);    g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));    g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection); @@ -1337,7 +1394,7 @@ funcsig_equal (gconstpointer aval,    const DBusGFuncSignature *b = bval;    const GType *atypes;    const GType *btypes; -  guint i, j; +  guint i;    if (a->rettype != b->rettype        || a->n_params != b->n_params) @@ -1422,22 +1479,56 @@ _dbus_gobject_lookup_marshaller (GType        rettype,  }  /** - * Register a GClosureMarshal to be used for signal invocations. + * Register a GClosureMarshal to be used for signal invocations, + * giving its return type and a list of parameter types, + * followed by G_TYPE_INVALID. +   * This function will not be needed once GLib includes libffi.   * + * @param marshaller a GClosureMarshal to be used for invocation + * @param rettype a GType for the return type of the function + * @param ... The parameter GTypes, followed by G_TYPE_INVALID + */ +void +dbus_g_object_register_marshaller (GClosureMarshal  marshaller, +				   GType            rettype, +				   ...) +{ +  va_list args; +  GArray *types; +  GType gtype; + +  va_start (args, rettype); + +  types = g_array_new (TRUE, TRUE, sizeof (GType)); + +  while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID) +    g_array_append_val (types, gtype); + +  dbus_g_object_register_marshaller_array (marshaller, rettype, +					   types->len, (GType*) types->data); + +  g_array_free (types, TRUE); +  va_end (args); +} + +/** + * Register a GClosureMarshal to be used for signal invocations. + * See also #dbus_g_object_register_marshaller + * + * @param marshaller a GClosureMarshal to be used for invocation   * @param rettype a GType for the return type of the function   * @param n_types number of function parameters   * @param param_types a C array of GTypes values - * @param marshaller a GClosureMarshal to be used for invocation   */  void -dbus_g_object_register_marshaller (GType            rettype, -				   guint            n_types, -				   const GType      *param_types, -				   GClosureMarshal   marshaller) +dbus_g_object_register_marshaller_array (GClosureMarshal  marshaller, +					 GType            rettype, +					 guint            n_types, +					 const GType*     types)  {    DBusGFuncSignature *sig; -   +    g_static_rw_lock_writer_lock (&globals_lock);    if (marshal_table == NULL) @@ -1449,7 +1540,7 @@ dbus_g_object_register_marshaller (GType            rettype,    sig->rettype = rettype;    sig->n_params = n_types;    sig->params = g_new (GType, n_types); -  memcpy (sig->params, param_types, n_types * sizeof (GType)); +  memcpy (sig->params, types, n_types * sizeof (GType));    g_hash_table_insert (marshal_table, sig, marshaller); diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 836167ef..8c683af4 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -934,9 +934,12 @@ dbus_g_proxy_emit_remote_signal (DBusGProxy  *proxy,    g_free (name);    return;   mismatch: +#if 0 +  /* Don't spew on remote errors */    g_warning ("Unexpected message signature '%s' for signal '%s'\n",  	     dbus_message_get_signature (message),  	     name); +#endif    goto out;  } diff --git a/test/glib/.cvsignore b/test/glib/.cvsignore index cdaabeb9..a0cd5e95 100644 --- a/test/glib/.cvsignore +++ b/test/glib/.cvsignore @@ -11,3 +11,5 @@ run-test.conf  test-service-glib-bindings.h  test-service-glib-glue.h  run-with-tmp-session-bus.conf +my-object-marshal.h +my-object-marshal.c diff --git a/test/glib/Makefile.am b/test/glib/Makefile.am index 568dab3d..77ee1906 100644 --- a/test/glib/Makefile.am +++ b/test/glib/Makefile.am @@ -35,14 +35,16 @@ endif  noinst_PROGRAMS= test-dbus-glib test-service-glib $(THREAD_APPS)  test_dbus_glib_SOURCES=				\ +	my-object-marshal.c                             \  	test-dbus-glib.c  test_dbus_glib_LDADD= $(DBUS_GLIB_TOOL_LIBS) $(top_builddir)/glib/libdbus-glib-1.la $(top_builddir)/glib/libdbus-gtool.la -test_service_glib_SOURCES=				\ -	test-service-glib.c +BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h my-object-marshal.c my-object-marshal.h  -BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h +test_service_glib_SOURCES=				\ +	my-object-marshal.c                             \ +	test-service-glib.c   test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool  	$(top_builddir)/glib/dbus-binding-tool --prefix=my_object --mode=glib-server --output=test-service-glib-glue.h $(srcdir)/test-service-glib.xml @@ -50,7 +52,14 @@ test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/glib/dbus-bindin  test-service-glib-bindings.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool  	$(top_builddir)/glib/dbus-binding-tool --prefix=my_object --mode=glib-client --output=test-service-glib-bindings.h $(srcdir)/test-service-glib.xml -CLEANFILES = test-service-glib-glue.h test-service-glib-bindings.h +my-object-marshal.c: Makefile my-object-marshal.list +	@GLIB_GENMARSHAL@ --prefix=my_object_marshal $(srcdir)/my-object-marshal.list --header --body > my-object-marshal.c + +my-object-marshal.h: Makefile my-object-marshal.list +	@GLIB_GENMARSHAL@ --prefix=my_object_marshal $(srcdir)/my-object-marshal.list --header > my-object-marshal.h + + +CLEANFILES = $(BUILT_SOURCES)  test_service_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la diff --git a/test/glib/my-object-marshal.list b/test/glib/my-object-marshal.list new file mode 100644 index 00000000..48cbfad4 --- /dev/null +++ b/test/glib/my-object-marshal.list @@ -0,0 +1,2 @@ +NONE:STRING,INT,STRING +NONE:STRING,BOXED diff --git a/test/glib/test-dbus-glib.c b/test/glib/test-dbus-glib.c index 2fc8665b..1f979a27 100644 --- a/test/glib/test-dbus-glib.c +++ b/test/glib/test-dbus-glib.c @@ -7,10 +7,14 @@  #include <glib/dbus-gidl.h>  #include <glib/dbus-gparser.h>  #include <glib-object.h> +#include "my-object-marshal.h"  static GMainLoop *loop = NULL;  static int n_times_foo_received = 0;  static int n_times_frobnicate_received = 0; +static int n_times_sig0_received = 0; +static int n_times_sig1_received = 0; +static guint exit_timeout = 0;  static gboolean  timed_exit (gpointer loop) @@ -27,6 +31,7 @@ foo_signal_handler (DBusGProxy  *proxy,    n_times_foo_received += 1;    g_main_loop_quit (loop); +  g_source_remove (exit_timeout);  }  static void @@ -39,6 +44,44 @@ frobnicate_signal_handler (DBusGProxy  *proxy,    g_assert (val == 42);    g_main_loop_quit (loop); +  g_source_remove (exit_timeout); +} + +static void +sig0_signal_handler (DBusGProxy  *proxy, +		     const char  *str0, +		     int          val, +		     const char  *str1, +		     void        *user_data) +{ +  n_times_sig0_received += 1; + +  g_assert (!strcmp (str0, "foo")); + +  g_assert (val == 22); + +  g_assert (!strcmp (str1, "moo")); + +  g_main_loop_quit (loop); +  g_source_remove (exit_timeout); +} + +static void +sig1_signal_handler (DBusGProxy  *proxy, +		     const char  *str0, +		     GValue      *value, +		     void        *user_data) +{ +  n_times_sig1_received += 1; + +  g_assert (!strcmp (str0, "baz")); + +  g_assert (G_VALUE_HOLDS_STRING (value)); + +  g_assert (!strcmp (g_value_get_string (value), "bar")); + +  g_main_loop_quit (loop); +  g_source_remove (exit_timeout);  }  static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2); @@ -216,9 +259,7 @@ main (int argc, char **argv)                                G_TYPE_INVALID);    dbus_g_connection_flush (connection); -   -  g_timeout_add (5000, timed_exit, loop); - +  exit_timeout = g_timeout_add (5000, timed_exit, loop);    g_main_loop_run (loop);    if (n_times_foo_received != 1) @@ -643,16 +684,81 @@ main (int argc, char **argv)    dbus_g_connection_flush (connection); -   -#if 0 -  g_timeout_add (5000, timed_exit, loop); - +  exit_timeout = g_timeout_add (5000, timed_exit, loop);    g_main_loop_run (loop);    if (n_times_frobnicate_received != 1)      lose ("Frobnicate signal received %d times, should have been 1", n_times_frobnicate_received); -#endif +  if (!dbus_g_proxy_invoke (proxy, "EmitFrobnicate", &error, +			    G_TYPE_INVALID, G_TYPE_INVALID)) +    lose_gerror ("Failed to complete EmitFrobnicate call", error); +   +  dbus_g_connection_flush (connection); +  exit_timeout = g_timeout_add (5000, timed_exit, loop); +  g_main_loop_run (loop); + +  if (n_times_frobnicate_received != 2) +    lose ("Frobnicate signal received %d times, should have been 2", n_times_frobnicate_received); + +  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.FooObject", +                                           &error); +   +  if (proxy == NULL) +    lose_gerror ("Failed to create proxy for name owner", error); + +  dbus_g_object_register_marshaller (my_object_marshal_VOID__STRING_INT_STRING,  +				     G_TYPE_NONE, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID); + +  dbus_g_object_register_marshaller (my_object_marshal_VOID__STRING_BOXED,  +				     G_TYPE_NONE, G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID); + +  dbus_g_proxy_add_signal (proxy, "Sig0", G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID); +  dbus_g_proxy_add_signal (proxy, "Sig1", G_TYPE_STRING, G_TYPE_VALUE); +   +  dbus_g_proxy_connect_signal (proxy, "Sig0", +                               G_CALLBACK (sig0_signal_handler), +                               NULL, NULL); +  dbus_g_proxy_connect_signal (proxy, "Sig1", +                               G_CALLBACK (sig1_signal_handler), +                               NULL, NULL); + +  dbus_g_proxy_call_no_reply (proxy, "EmitSignals", G_TYPE_INVALID); + +  dbus_g_connection_flush (connection); +  exit_timeout = g_timeout_add (5000, timed_exit, loop); +  g_main_loop_run (loop); +  exit_timeout = g_timeout_add (5000, timed_exit, loop); +  g_main_loop_run (loop); + +  if (n_times_sig0_received != 1) +    lose ("Sig0 signal received %d times, should have been 1", n_times_sig0_received); +  if (n_times_sig1_received != 1) +    lose ("Sig1 signal received %d times, should have been 1", n_times_sig1_received); + +  dbus_g_proxy_call_no_reply (proxy, "EmitSignals", G_TYPE_INVALID); +  dbus_g_proxy_call_no_reply (proxy, "EmitSignals", G_TYPE_INVALID); + +  dbus_g_connection_flush (connection); +  exit_timeout = g_timeout_add (5000, timed_exit, loop); +  g_main_loop_run (loop); +  exit_timeout = g_timeout_add (5000, timed_exit, loop); +  g_main_loop_run (loop); +  exit_timeout = g_timeout_add (5000, timed_exit, loop); +  g_main_loop_run (loop); +  exit_timeout = g_timeout_add (5000, timed_exit, loop); +  g_main_loop_run (loop); + +  if (n_times_sig0_received != 3) +    lose ("Sig0 signal received %d times, should have been 3", n_times_sig0_received); +  if (n_times_sig1_received != 3) +    lose ("Sig1 signal received %d times, should have been 3", n_times_sig1_received); +      g_object_unref (G_OBJECT (proxy));    proxy = dbus_g_proxy_new_for_name_owner (connection, @@ -680,7 +786,6 @@ main (int argc, char **argv)      gboolean found_properties;      gboolean found_myobject;      gboolean found_fooobject; -    gboolean found_gtk_myobject;      node = description_load_from_string (v_STRING_2, strlen (v_STRING_2), &error);      if (!node) @@ -688,7 +793,6 @@ main (int argc, char **argv)      found_introspectable = FALSE;      found_properties = FALSE; -    found_gtk_myobject = FALSE;      found_myobject = FALSE;      found_fooobject = FALSE;      for (elt = node_info_get_interfaces (node); elt ; elt = elt->next) @@ -699,8 +803,6 @@ main (int argc, char **argv)  	  found_introspectable = TRUE;  	else if (!found_properties && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.Properties") == 0)  	  found_properties = TRUE; -	else if (strcmp (interface_info_get_name (iface), "org.gtk.objects.MyObject") == 0) -	  found_gtk_myobject = TRUE;  	else if (!found_myobject && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.Tests.MyObject") == 0)  	  {  	    GSList *elt; @@ -729,7 +831,7 @@ main (int argc, char **argv)  	  lose ("Unexpected or duplicate interface %s", interface_info_get_name (iface));        } -    if (!(found_introspectable && found_gtk_myobject && found_myobject && found_properties)) +    if (!(found_introspectable && found_myobject && found_properties))        lose ("Missing interface");     }    g_free (v_STRING_2); diff --git a/test/glib/test-service-glib.c b/test/glib/test-service-glib.c index 208bfb24..6089367e 100644 --- a/test/glib/test-service-glib.c +++ b/test/glib/test-service-glib.c @@ -10,6 +10,7 @@  #include <glib/gi18n.h>  #include <glib-object.h>  #include <glib/gquark.h> +#include "my-object-marshal.h"  typedef struct MyObject MyObject;  typedef struct MyObjectClass MyObjectClass; @@ -77,6 +78,8 @@ gboolean my_object_get_val (MyObject *obj, guint *ret, GError **error);  gboolean my_object_get_value (MyObject *obj, guint *ret, GError **error); +gboolean my_object_emit_signals (MyObject *obj, GError **error); +  gboolean my_object_emit_frobnicate (MyObject *obj, GError **error);  #include "test-service-glib-glue.h" @@ -93,10 +96,11 @@ enum  enum  {    FROBNICATE, +  SIG0, +  SIG1,    LAST_SIGNAL  }; -static void *parent_class;  static guint signals[LAST_SIGNAL] = { 0 };  static void @@ -185,6 +189,23 @@ my_object_class_init (MyObjectClass *mobject_class)                    g_cclosure_marshal_VOID__INT,                    G_TYPE_NONE, 1, G_TYPE_INT); +  signals[SIG0] = +    g_signal_new ("sig0", +		  G_OBJECT_CLASS_TYPE (mobject_class), +                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, +                  0, +                  NULL, NULL, +                  my_object_marshal_VOID__STRING_INT_STRING, +                  G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING); + +  signals[SIG1] = +    g_signal_new ("sig1", +		  G_OBJECT_CLASS_TYPE (mobject_class), +                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, +                  0, +                  NULL, NULL, +                  my_object_marshal_VOID__STRING_BOXED, +                  G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VALUE);  }  GQuark @@ -403,6 +424,21 @@ my_object_emit_frobnicate (MyObject *obj, GError **error)    return TRUE;  } +gboolean +my_object_emit_signals (MyObject *obj, GError **error) +{ +  GValue val = {0, }; + +  g_signal_emit (obj, signals[SIG0], 0, "foo", 22, "moo"); + +  g_value_init (&val, G_TYPE_STRING); +  g_value_set_string (&val, "bar"); +  g_signal_emit (obj, signals[SIG1], 0, "baz", &val); +  g_value_unset (&val); + +  return TRUE; +} +  static GMainLoop *loop;  #define TEST_SERVICE_NAME "org.freedesktop.DBus.TestSuiteGLibService" diff --git a/test/glib/test-service-glib.xml b/test/glib/test-service-glib.xml index f976572b..05cb5abd 100644 --- a/test/glib/test-service-glib.xml +++ b/test/glib/test-service-glib.xml @@ -84,13 +84,24 @@      <method name="EmitFrobnicate">      </method> +    <!-- Export signals --> +    <signal name="Frobnicate"/>    </interface> +  <!-- Test multiple interfaces on the same object --> +    <interface name="org.freedesktop.DBus.Tests.FooObject">      <method name="GetValue">        <arg type="u" direction="out" />      </method> +    <method name="EmitSignals"> +    </method> + +    <signal name="Sig0"/> + +    <signal name="Sig1"/> +    </interface>  </node> | 
