dbus/glib dbus-gproxy.c,1.31,1.32 dbus-gobject.c,1.35,1.36

Colin Walters walters at freedesktop.org
Wed Jun 29 09:59:02 PDT 2005


Update of /cvs/dbus/dbus/glib
In directory gabe:/tmp/cvs-serv19565/glib

Modified Files:
	dbus-gproxy.c dbus-gobject.c 
Log Message:
2005-06-29  Colin Walters  <walters at verbum.org>

	* glib/dbus-gproxy.c (struct _DBusGProxy): Add new member
	name_call for keeping track of any outgoing GetNameOwner call.
	Also add for_owner and associated.
	(struct _DBusGProxyManager): Add owner_names, which is hash table
	that maps a base name to a list of names it owns (that we're
	interested in).  Add pending_nameowner_calls which is a list of
	all outstanding GetNameOwner; avoids us having to iterate over
	every proxy.  Add unassociated_proxies which keeps track of name
	proxies with no associated name owner.
	(dbus_g_proxy_manager_unref): Destroy owner_names.
	(struct DBusGProxyNameOwnerInfo): New struct for keeping track of
	name refcounts.
	(find_name_in_info, name_owner_foreach)
	(dbus_g_proxy_manager_lookup_name_owner, insert_nameinfo)
	(dbus_g_proxy_manager_monitor_name_owner)
	(dbus_g_proxy_manager_unmonitor_name_owner)
	(unassociate_proxies, dbus_g_proxy_manager_replace_name_owner):
	New functions; they manipulate the owner_names mapping.
	(got_name_owner_cb): New function.
	(get_name_owner): New function, extracted from
	dbus_g_proxy_new_for_name_owner.
	(dbus_g_proxy_manager_register): For now we need to keep track of
	all NameOwnerChanged.  Also if the proxy is for a name, if we
	don't already know the name owner, queue a new GetNameOwner
	request and add it to our list of unassociated proxies.  Otherwise
	inc the refcount.
	(dbus_g_proxy_manager_unregister): If this proxy is for a name,
	cancel any pending GetNameOwner call, etc.
	(dbus_g_proxy_manager_filter): Handle NameOwnerChanged.  Also use
	the owner_names mapping to look up the current names for the
	signal source, and dispatch to any proxies for that name.
	(dbus_g_proxy_new): Initialize new members.
	(dbus_g_proxy_new_for_name): Delete unused proxy variable.
	(dbus_g_proxy_new_for_name_owner): Use get_name_owner.
	(dbus_g_pending_call_end_valist): New function, extracted from
	dbus_g_proxy_end_call_internal.  Useful when we don't have a proxy
	but want to use the GLib infrastructure.  Also note how many
	arguments in reply were over.
	(dbus_g_pending_call_end): New function, just call
	dbus_g_pending_call_end_valist.
	(dbus_g_proxy_end_call_internal): Just call
	dbus_g_pending_call_end_valist.

	* glib/dbus-gobject.c (_dbus_gobject_lookup_marshaller): Fix lookup
	of builtin marshaller for STRING_STRING_STRING.

	* test/glib/test-dbus-glib.c: 
	* test/glib/test-service-glib.c:
	* test/glib/test-service-glib.xml:
	Extend tests to cover name proxies, destruction of owner proxies,
	etc.
	
	* glib/examples/example-signal-recipient.c
	(dbus_g_proxy_new_for_name_owner): Create a name proxy.
	
	* tools/dbus-send.c (main): Print D-BUS error name in addition
	to message.


Index: dbus-gproxy.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gproxy.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- dbus-gproxy.c	26 Jun 2005 17:02:09 -0000	1.31
+++ dbus-gproxy.c	29 Jun 2005 16:58:59 -0000	1.32
@@ -56,6 +56,10 @@
   char *path;                 /**< Path messages go to or NULL */
   char *interface;            /**< Interface messages go to or NULL */
 
+  DBusGPendingCall *name_call;/**< Pending call to retrieve name owner */
+  guint for_owner : 1;        /**< Whether or not this proxy is for a name owner */
+  guint associated : 1;       /**< Whether or not this proxy is associated (for name proxies) */
+
   GData *signal_signatures;   /**< D-BUS signatures for each signal */
 };
 
@@ -75,6 +79,13 @@
 static void dbus_g_proxy_emit_remote_signal (DBusGProxy      *proxy,
                                              DBusMessage     *message);
 
+static gboolean dbus_g_pending_call_end (DBusGConnection   *connection,
+					 DBusGProxy        *proxycon,
+					 DBusGPendingCall  *pending,
+					 GError           **error,
+					 GType              first_arg_type,
+					 ...);
+
 /**
  * A list of proxies with a given name+path+interface, used to
  * route incoming signals.
@@ -104,7 +115,17 @@
   GHashTable *proxy_lists; /**< Hash used to route incoming signals
                             *   and iterate over proxies
                             */
-
+  GHashTable *owner_names; /**< Hash to keep track of mapping from
+			    *   base name -> [name,name,...] for proxies which
+			    *   are for names.
+			    */
+  GSList *pending_nameowner_calls;  /**< List to keep track of pending
+				     *   GetNameOwner calls
+				     */
+  GSList *unassociated_proxies;     /**< List of name proxies for which
+				     *   there was no result for
+				     *   GetNameOwner
+				     */
 };
 
 static DBusGProxyManager *dbus_g_proxy_manager_ref    (DBusGProxyManager *manager);
@@ -203,7 +224,22 @@
           
           g_hash_table_destroy (manager->proxy_lists);
           manager->proxy_lists = NULL;
+
         }
+
+      if (manager->owner_names)
+	{
+	  /* Since we destroyed all proxies, none can be tracking
+	   * name owners
+	   */
+          g_assert (g_hash_table_size (manager->owner_names) == 0);
+
+	  g_hash_table_destroy (manager->owner_names);
+	  manager->owner_names = NULL;
+	}
+
+      g_assert (manager->pending_nameowner_calls == NULL);
+      g_assert (manager->unassociated_proxies == NULL);
       
       g_static_mutex_free (&manager->lock);
 
@@ -412,6 +448,389 @@
                             proxy->path, proxy->interface);
 }
 
+typedef struct
+{
+  char *name;
+  guint refcount;
+} DBusGProxyNameOwnerInfo;
+
+static gint
+find_name_in_info (gconstpointer a, gconstpointer b)
+{
+  const DBusGProxyNameOwnerInfo *info = a;
+  const char *name = b;
+
+  return strcmp (info->name, name);
+}
+
+typedef struct
+{
+  const char *name;
+  const char *owner;
+  DBusGProxyNameOwnerInfo *info;
+} DBusGProxyNameOwnerForeachData;
+
+static void
+name_owner_foreach (gpointer key, gpointer val, gpointer data)
+{
+  const char *owner;
+  DBusGProxyNameOwnerForeachData *foreach_data;
+  GSList *names;
+  GSList *link;
+
+  owner = key;
+  names = val;
+  foreach_data = data;
+
+  if (foreach_data->owner != NULL)
+    return;
+
+  g_assert (foreach_data->info == NULL);
+
+  link = g_slist_find_custom (names, foreach_data->name, find_name_in_info);
+  if (link)
+    {
+      foreach_data->owner = owner;
+      foreach_data->info = link->data;
+    }
+}
+
+static gboolean
+dbus_g_proxy_manager_lookup_name_owner (DBusGProxyManager        *manager,
+					const char               *name,
+					DBusGProxyNameOwnerInfo **info,
+					const char              **owner)
+{
+  DBusGProxyNameOwnerForeachData foreach_data;
+
+  foreach_data.name = name;
+  foreach_data.owner = NULL;
+  foreach_data.info = NULL;
+  
+  g_hash_table_foreach (manager->owner_names, name_owner_foreach, &foreach_data);
+
+  *info = foreach_data.info;
+  *owner = foreach_data.owner;
+  return *info != NULL;
+}
+
+static void
+insert_nameinfo (DBusGProxyManager       *manager,
+		 const char              *owner,
+		 DBusGProxyNameOwnerInfo *info)
+{
+  GSList *names;
+  gboolean insert;
+
+  names = g_hash_table_lookup (manager->owner_names, owner);
+
+  /* Only need to g_hash_table_insert the first time */
+  insert = (names == NULL);
+
+  names = g_slist_append (names, info); 
+
+  if (insert)
+    g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
+}
+
+static void
+dbus_g_proxy_manager_monitor_name_owner (DBusGProxyManager  *manager,
+					 const char         *owner,
+					 const char         *name)
+{
+  GSList *names;
+  GSList *link;
+  DBusGProxyNameOwnerInfo *nameinfo;
+
+  names = g_hash_table_lookup (manager->owner_names, owner);
+  link = g_slist_find_custom (names, name, find_name_in_info);
+  
+  if (!link)
+    {
+      nameinfo = g_new0 (DBusGProxyNameOwnerInfo, 1);
+      nameinfo->name = g_strdup (name);
+      nameinfo->refcount = 1;
+
+      insert_nameinfo (manager, owner, nameinfo);
+    }
+  else
+    {
+      nameinfo = link->data;
+      nameinfo->refcount++;
+    }
+}
+
+static void
+dbus_g_proxy_manager_unmonitor_name_owner (DBusGProxyManager  *manager,
+					   const char         *name)
+{
+  DBusGProxyNameOwnerInfo *info;
+  const char *owner;
+  gboolean ret;
+
+  ret = dbus_g_proxy_manager_lookup_name_owner (manager, name, &info, &owner);
+  g_assert (ret);
+  g_assert (info != NULL);
+  g_assert (owner != NULL);
+
+  info->refcount--;
+  if (info->refcount == 0)
+    {
+      GSList *names;
+      GSList *link;
+
+      names = g_hash_table_lookup (manager->owner_names, owner);
+      link = g_slist_find_custom (names, name, find_name_in_info);
+      names = g_slist_delete_link (names, link);
+      if (names != NULL)
+	g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
+      else
+	g_hash_table_remove (manager->owner_names, owner);
+
+      g_free (info->name);
+      g_free (info);
+    }
+}
+
+typedef struct
+{
+  const char *name;
+  GSList *destroyed;
+} DBusGProxyUnassociateData;
+
+static void
+unassociate_proxies (gpointer key, gpointer val, gpointer user_data)
+{
+  const char *tri;
+  DBusGProxyList *list;
+  const char *name;
+  GSList *tmp;
+  DBusGProxyUnassociateData *data;
+
+  tri = key;
+  list = val;
+  data = user_data;
+  name = data->name;
+  
+  for (tmp = list->proxies; tmp; tmp = tmp->next)
+    {
+      DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
+      DBusGProxyManager *manager;
+
+      manager = proxy->manager;
+
+      if (!strcmp (proxy->name, name))
+	{
+	  if (!proxy->for_owner)
+	    {
+	      g_assert (proxy->associated);
+	      g_assert (proxy->name_call == NULL);
+
+	      proxy->associated = FALSE;
+	      manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
+	    }
+	  else
+	    {
+	      data->destroyed = g_slist_prepend (data->destroyed, proxy);
+	    }
+	}
+    }
+}
+
+static void
+dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager  *manager,
+					 const char         *name,
+					 const char         *prev_owner,
+					 const char         *new_owner)
+{
+  GSList *names;
+	  
+  if (prev_owner[0] == '\0')
+    {
+      GSList *tmp;
+      GSList *removed;
+
+      /* We have a new service, look at unassociated proxies */
+
+      removed = NULL;
+
+      for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
+	{
+	  DBusGProxy *proxy;
+
+	  proxy = tmp->data;
+
+	  if (!strcmp (proxy->name, name))
+	    {
+	      removed = g_slist_prepend (removed, tmp);
+	      
+	      dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
+	      proxy->associated = TRUE;
+	    }
+	}
+
+      for (tmp = removed; tmp; tmp = tmp->next)
+	manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
+      g_slist_free (removed);
+    }
+  else
+    {
+      DBusGProxyNameOwnerInfo *info;
+      GSList *link;
+
+      /* Name owner changed or deleted */ 
+
+      names = g_hash_table_lookup (manager->owner_names, prev_owner);
+
+      link = g_slist_find_custom (names, name, find_name_in_info);
+
+      info = NULL;
+      if (link != NULL)
+	{
+	  info = link->data;
+	  
+	  names = g_slist_delete_link (names, link);
+
+	  if (names == NULL)
+	    g_hash_table_remove (manager->owner_names, prev_owner);
+	}
+
+      if (new_owner[0] == '\0')
+	{
+	  DBusGProxyUnassociateData data;
+	  GSList *tmp;
+
+	  data.name = name;
+	  data.destroyed = NULL;
+
+	  /* A service went away, we need to unassociate proxies */
+	  g_hash_table_foreach (manager->proxy_lists,
+				unassociate_proxies, &data);
+
+	  UNLOCK_MANAGER (manager);
+
+	  for (tmp = data.destroyed; tmp; tmp = tmp->next)
+	    dbus_g_proxy_destroy (tmp->data);
+	  g_slist_free (data.destroyed);
+
+	  LOCK_MANAGER (manager);
+	}
+      else
+	{
+	  insert_nameinfo (manager, new_owner, info);
+	}
+    }
+}
+
+static void
+got_name_owner_cb (DBusGPendingCall *pending,
+		   void             *user_data)
+{
+  DBusGProxy *proxy;
+  GError *error;
+  char *owner;
+  GSList *link;
+
+  proxy = user_data;
+  error = NULL;
+  owner = NULL;
+
+  LOCK_MANAGER (proxy->manager);
+
+  link = g_slist_find (proxy->manager->pending_nameowner_calls, pending);
+  g_assert (link != NULL);
+  
+  if (!dbus_g_pending_call_end (DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection),
+				NULL,
+				pending,
+				&error,
+				G_TYPE_STRING, &owner,
+				G_TYPE_INVALID))
+    {
+      if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
+	{
+	  proxy->manager->unassociated_proxies = g_slist_prepend (proxy->manager->unassociated_proxies, proxy);
+	}
+      else
+	g_warning ("Couldn't get name owner (%s): %s",
+		   dbus_g_error_get_name (error),
+		   error->message);
+
+      g_clear_error (&error);
+      goto out;
+    }
+  else
+    {
+      dbus_g_proxy_manager_monitor_name_owner (proxy->manager, owner, proxy->name);
+      proxy->associated = TRUE;
+    }
+
+ out:
+  proxy->name_call = NULL;
+  proxy->manager->pending_nameowner_calls = g_slist_delete_link (proxy->manager->pending_nameowner_calls, link);
+  UNLOCK_MANAGER (proxy->manager);
+  g_free (owner);
+}
+
+static char *
+get_name_owner (DBusConnection     *connection,
+		const char         *name,
+		GError            **error)
+{
+  DBusError derror;
+  DBusMessage *request, *reply;
+  char *base_name;
+  
+  dbus_error_init (&derror);
+
+  base_name = NULL;
+  reply = NULL;
+
+  request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+					  DBUS_PATH_DBUS,
+					  DBUS_INTERFACE_DBUS,
+					  "GetNameOwner");
+  if (request == NULL)
+    g_error ("Out of memory");
+  
+  if (!dbus_message_append_args (request, 
+				 DBUS_TYPE_STRING, &name, 
+				 DBUS_TYPE_INVALID))
+    g_error ("Out of memory");
+
+  reply =
+    dbus_connection_send_with_reply_and_block (connection,
+                                               request,
+                                               2000, &derror);
+  if (reply == NULL)
+    goto error;
+
+  if (dbus_set_error_from_message (&derror, reply))
+    goto error;
+
+  if (!dbus_message_get_args (reply, &derror, 
+			      DBUS_TYPE_STRING, &base_name, 
+			      DBUS_TYPE_INVALID))
+    goto error;
+
+  base_name = g_strdup (base_name);
+  goto out;
+
+ error:
+  g_assert (dbus_error_is_set (&derror));
+  dbus_g_error_set (error, derror.name, derror.message);
+  dbus_error_free (&derror);
+
+ out:
+  if (request)
+    dbus_message_unref (request);
+  if (reply)
+    dbus_message_unref (reply);
+
+  return base_name;
+}
+
+
 static void
 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
                                DBusGProxy        *proxy)
@@ -422,11 +841,26 @@
 
   if (manager->proxy_lists == NULL)
     {
+      g_assert (manager->owner_names == NULL);
+
       list = NULL;
       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
                                                     tristring_equal,
                                                     NULL,
                                                     (GFreeFunc) g_proxy_list_free);
+      manager->owner_names = g_hash_table_new_full (g_str_hash,
+                                                    g_str_equal,
+                                                    g_free,
+                                                    NULL);
+      /* FIXME - for now we listen for all NameOwnerChanged; once
+       * Anders' detail patch lands we should add individual rules
+       */
+      dbus_bus_add_match (manager->connection,
+                          "type='signal',sender='" DBUS_SERVICE_DBUS
+			  "',path='" DBUS_PATH_DBUS
+			  "',interface='" DBUS_INTERFACE_DBUS
+			  "',member='NameOwnerChanged'",
+			  NULL);
     }
   else
     {
@@ -469,6 +903,61 @@
   g_assert (g_slist_find (list->proxies, proxy) == NULL);
   
   list->proxies = g_slist_prepend (list->proxies, proxy);
+
+  if (!proxy->for_owner)
+    {
+      const char *owner;
+      DBusGProxyNameOwnerInfo *info;
+
+      if (!dbus_g_proxy_manager_lookup_name_owner (manager, proxy->name, &info, &owner))
+	{
+	  DBusPendingCall *pending;
+	  DBusGPendingCall *gpending;
+	  DBusMessage *request, *reply;
+
+	  g_assert (owner == NULL);
+  
+	  reply = NULL;
+	  
+	  request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+						  DBUS_PATH_DBUS,
+						  DBUS_INTERFACE_DBUS,
+						  "GetNameOwner");
+	  if (request == NULL)
+	    g_error ("Out of memory");
+	  
+	  if (!dbus_message_append_args (request, 
+					 DBUS_TYPE_STRING, &(proxy->name), 
+					 DBUS_TYPE_INVALID))
+	    g_error ("Out of memory");
+
+	  if (!dbus_connection_send_with_reply (manager->connection,
+						request,
+						&pending,
+						-1))
+	    g_error ("Out of memory");
+	  g_assert (pending != NULL);
+
+	  gpending = DBUS_G_PENDING_CALL_FROM_PENDING_CALL (pending);
+
+	  /* It's safe to keep a reference to proxy here;
+	   * when the proxy is unreffed we cancel the call
+	   */
+	  dbus_g_pending_call_set_notify (gpending,
+					  got_name_owner_cb,
+					  proxy,
+					  NULL);
+	  
+	  proxy->associated = FALSE;
+	  proxy->name_call = gpending;
+	  manager->pending_nameowner_calls = g_slist_prepend (manager->pending_nameowner_calls, gpending);
+	}
+      else
+	{
+	  info->refcount++;
+	  proxy->associated = TRUE;
+	}
+    }
   
   UNLOCK_MANAGER (manager);
 }
@@ -508,6 +997,37 @@
 
   g_assert (g_slist_find (list->proxies, proxy) == NULL);
 
+  if (!proxy->for_owner)
+    {
+      if (!proxy->associated)
+	{
+	  GSList *link;
+
+	  if (proxy->name_call != NULL)
+	    {
+	      link = g_slist_find (manager->pending_nameowner_calls, proxy->name_call);
+	      g_assert (link != NULL);
+	  
+	      dbus_g_pending_call_cancel (proxy->name_call);
+
+	      manager->pending_nameowner_calls = g_slist_delete_link (manager->pending_nameowner_calls, link);
+	    }
+	  else
+	    {
+	      link = g_slist_find (manager->unassociated_proxies, proxy);
+	      g_assert (link != NULL);
+
+	      manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, link);
+	    }
+	}
+      else
+	{
+	  g_assert (proxy->name_call == NULL);
+	  
+	  dbus_g_proxy_manager_unmonitor_name_owner (manager, proxy->name);
+	}
+    }
+
   if (list->proxies == NULL)
     {
       g_hash_table_remove (manager->proxy_lists,
@@ -620,9 +1140,45 @@
   else
     {
       char *tri;
-      DBusGProxyList *list;
+      GSList *full_list;
+      GSList *owned_names;
+      GSList *tmp;
+      const char *sender;
+
+      /* First we handle NameOwnerChanged internally */
+      if (dbus_message_is_signal (message,
+				  DBUS_INTERFACE_DBUS,
+				  "NameOwnerChanged"))
+	{
+	  const char *name;
+	  const char *prev_owner;
+	  const char *new_owner;
+	  DBusError derr;
+
+	  dbus_error_init (&derr);
+	  if (!dbus_message_get_args (message,
+				      &derr,
+				      DBUS_TYPE_STRING,
+				      &name,
+				      DBUS_TYPE_STRING,
+				      &prev_owner,
+				      DBUS_TYPE_STRING,
+				      &new_owner,
+				      DBUS_TYPE_INVALID))
+	    {
+	      /* Ignore this error */
+	      dbus_error_free (&derr);
+	    }
+	  else if (manager->owner_names != NULL)
+	    {
+	      dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
+	    }
+	}
+
+      sender = dbus_message_get_sender (message);
 
       /* dbus spec requires these, libdbus validates */
+      g_assert (sender != NULL);
       g_assert (dbus_message_get_path (message) != NULL);
       g_assert (dbus_message_get_interface (message) != NULL);
       g_assert (dbus_message_get_member (message) != NULL);
@@ -630,9 +1186,38 @@
       tri = tristring_from_message (message);
 
       if (manager->proxy_lists)
-        list = g_hash_table_lookup (manager->proxy_lists, tri);
+	{
+	  DBusGProxyList *owner_list;
+	  owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
+	  if (owner_list)
+	    full_list = g_slist_copy (owner_list->proxies);
+	  else
+	    full_list = NULL;
+	}
       else
-        list = NULL;
+	full_list = NULL;
+
+      g_free (tri);
+
+      if (manager->owner_names)
+	{
+	  owned_names = g_hash_table_lookup (manager->owner_names, sender);
+	  for (tmp = owned_names; tmp; tmp = tmp->next)
+	    {
+	      DBusGProxyList *owner_list;
+	      DBusGProxyNameOwnerInfo *nameinfo;
+
+	      nameinfo = tmp->data;
+	      g_assert (nameinfo->refcount > 0);
+	      tri = tristring_alloc_from_strings (0, nameinfo->name,
+						  dbus_message_get_path (message),
+						  dbus_message_get_interface (message));
+
+	      owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
+	      full_list = g_slist_concat (full_list, g_slist_copy (owner_list->proxies));
+	      g_free (tri);
+	    }
+	}
 
 #if 0
       g_print ("proxy got %s,%s,%s = list %p\n",
@@ -642,35 +1227,22 @@
                list);
 #endif
       
-      g_free (tri);
-
       /* Emit the signal */
       
-      if (list != NULL)
-        {
-          GSList *tmp;
-          GSList *copy;
-
-          copy = g_slist_copy (list->proxies);
-          g_slist_foreach (copy, (GFunc) g_object_ref, NULL);
-          
-          tmp = copy;
-          while (tmp != NULL)
-            {
-              DBusGProxy *proxy;
-
-              proxy = DBUS_G_PROXY (tmp->data);
-
-              UNLOCK_MANAGER (manager);
-              dbus_g_proxy_emit_remote_signal (proxy, message);
-              g_object_unref (G_OBJECT (proxy));
-              LOCK_MANAGER (manager);
-              
-              tmp = tmp->next;
-            }
-
-          g_slist_free (copy);
-        }
+      g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
+      
+      for (tmp = full_list; tmp; tmp = tmp->next)
+	{
+	  DBusGProxy *proxy;
+	  
+	  proxy = DBUS_G_PROXY (tmp->data);
+	  
+	  UNLOCK_MANAGER (manager);
+	  dbus_g_proxy_emit_remote_signal (proxy, message);
+	  g_object_unref (G_OBJECT (proxy));
+	  LOCK_MANAGER (manager);
+	}
+      g_slist_free (full_list);
     }
 
   UNLOCK_MANAGER (manager);
@@ -887,7 +1459,7 @@
   GQuark q;
 
   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
-  
+
   interface = dbus_message_get_interface (message);
   signal = dbus_message_get_member (message);
 
@@ -1004,6 +1576,10 @@
   proxy->path = g_strdup (path_name);
   proxy->interface = g_strdup (interface_name);
 
+  proxy->for_owner = (proxy->name[0] == ':');
+  proxy->name_call = NULL;
+  proxy->associated = FALSE;
+
   dbus_g_proxy_manager_register (proxy->manager, proxy);
   
   return proxy;
@@ -1041,17 +1617,13 @@
                            const char      *path_name,
                            const char      *interface_name)
 {
-  DBusGProxy *proxy;
-
   g_return_val_if_fail (connection != NULL, NULL);
   g_return_val_if_fail (name != NULL, NULL);
   g_return_val_if_fail (path_name != NULL, NULL);
   g_return_val_if_fail (interface_name != NULL, NULL);
-  
-  proxy = dbus_g_proxy_new (connection, name,
-                            path_name, interface_name);
 
-  return proxy;
+  return dbus_g_proxy_new (connection, name,
+			   path_name, interface_name);
 }
 
 /**
@@ -1085,65 +1657,19 @@
                                  GError                  **error)
 {
   DBusGProxy *proxy;
-  DBusMessage *request, *reply;
-  DBusError derror;
-  const char *unique_name;
-  
+  char *unique_name;
+
   g_return_val_if_fail (connection != NULL, NULL);
   g_return_val_if_fail (name != NULL, NULL);
   g_return_val_if_fail (path_name != NULL, NULL);
   g_return_val_if_fail (interface_name != NULL, NULL);
 
-  dbus_error_init (&derror);
-
-  proxy = NULL;
-  unique_name = NULL;
-  reply = NULL;
-
-  request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
-					  DBUS_PATH_DBUS,
-					  DBUS_INTERFACE_DBUS,
-					  "GetNameOwner");
-  if (request == NULL)
-    g_error ("Out of memory");
-  
-  if (! dbus_message_append_args (request, 
-				  DBUS_TYPE_STRING, &name, 
-				  DBUS_TYPE_INVALID))
-    g_error ("Out of memory");
-
-  reply =
-    dbus_connection_send_with_reply_and_block (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
-                                               request,
-                                               2000, &derror);
-  if (reply == NULL)
-    goto error;
-
-  if (dbus_set_error_from_message (&derror, reply))
-    goto error;
-
-  if (! dbus_message_get_args (reply, &derror, 
-			       DBUS_TYPE_STRING, &unique_name, 
-			       DBUS_TYPE_INVALID))
-    goto error;
-      
+  if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
+    return NULL;
 
   proxy = dbus_g_proxy_new (connection, unique_name,
-                            path_name, interface_name);
-
-  goto out;
-
- error:
-  g_assert (dbus_error_is_set (&derror));
-  dbus_g_error_set (error, derror.name, derror.message);
-  dbus_error_free (&derror);
-
- out:
-  if (request)
-    dbus_message_unref (request);
-  if (reply)
-    dbus_message_unref (reply);
-
+			    path_name, interface_name);
+  g_free (unique_name);
   return proxy;
 }
 
@@ -1356,16 +1882,18 @@
 }
 
 static gboolean
-dbus_g_proxy_end_call_internal (DBusGProxy       *proxy,
-				DBusGPendingCall *pending,
-				GError          **error,
-				GType             first_arg_type,
-				va_list           args)
+dbus_g_pending_call_end_valist (DBusGConnection   *connection,
+				DBusGProxy        *proxycon,
+				DBusGPendingCall  *pending,
+				GError           **error,
+				GType              first_arg_type,
+				va_list            args)
 {
   DBusMessage *reply;
   DBusMessageIter msgiter;
   DBusError derror;
   va_list args_unwind;
+  guint over;
   int n_retvals_processed;
   gboolean ret;
   GType valtype;
@@ -1373,6 +1901,7 @@
   reply = NULL;
   ret = FALSE;
   n_retvals_processed = 0;
+  over = 0;
   dbus_pending_call_block (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
   reply = dbus_pending_call_steal_reply (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
 
@@ -1393,15 +1922,18 @@
 	  GValue gvalue = { 0, };
 	  DBusGValueMarshalCtx context;
 
-	  context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
-	  context.proxy = proxy;
+	  context.gconnection = connection;
+	  context.proxy = proxycon;
 
 
 	  arg_type = dbus_message_iter_get_arg_type (&msgiter);
 	  if (arg_type == DBUS_TYPE_INVALID)
-	    g_set_error (error, DBUS_GERROR,
-			 DBUS_GERROR_INVALID_ARGS,
-			 _("Too few arguments in reply"));
+	    {
+	      g_set_error (error, DBUS_GERROR,
+			   DBUS_GERROR_INVALID_ARGS,
+			   _("Too few arguments in reply"));
+	      goto out;
+	    }
 
 	  return_storage = va_arg (args, gpointer);
 	  if (return_storage == NULL)
@@ -1459,11 +1991,19 @@
 	  dbus_message_iter_next (&msgiter);
 	  valtype = va_arg (args, GType);
 	}
-      if (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
+      
+      while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
+	{
+	  over++;
+	  dbus_message_iter_next (&msgiter);
+	}
+
+      if (over > 0)
 	{
 	  g_set_error (error, DBUS_GERROR,
 		       DBUS_GERROR_INVALID_ARGS,
-		       _("Too many arguments in reply"));
+		       _("Too many arguments in reply; expected %d, got %d"),
+		       n_retvals_processed, over);
 	  goto out;
 	}
       break;
@@ -1507,6 +2047,42 @@
   return ret;
 }
 
+static gboolean
+dbus_g_pending_call_end (DBusGConnection   *connection,
+			 DBusGProxy        *proxycon,
+			 DBusGPendingCall  *pending,
+			 GError           **error,
+			 GType              first_arg_type,
+			 ...)
+{
+  va_list args;
+  gboolean ret;
+
+  va_start (args, first_arg_type);
+
+  ret = dbus_g_pending_call_end_valist (connection, proxycon, pending,
+					error, first_arg_type, args);
+
+  va_end (args);
+
+  return ret;
+}
+
+static gboolean
+dbus_g_proxy_end_call_internal (DBusGProxy       *proxy,
+				DBusGPendingCall *pending,
+				GError          **error,
+				GType             first_arg_type,
+				va_list           args)
+{
+  return dbus_g_pending_call_end_valist (DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection),
+					 proxy,
+					 pending,
+					 error,
+					 first_arg_type,
+					 args);
+}
+
 
 /**
  * Invokes a method on a remote interface. This function does not

Index: dbus-gobject.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gobject.c,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -d -r1.35 -r1.36
--- dbus-gobject.c	27 Jun 2005 18:20:20 -0000	1.35
+++ dbus-gobject.c	29 Jun 2005 16:58:59 -0000	1.36
@@ -1484,13 +1484,13 @@
 		  break;
 		}
 	    }
-	}
-      else if (n_params == 3
-	       && params[0] == G_TYPE_STRING
-	       && params[1] == G_TYPE_STRING
-	       && params[2] == G_TYPE_STRING)
-	{
-	  ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
+	  else if (n_params == 3
+		   && params[0] == G_TYPE_STRING
+		   && params[1] == G_TYPE_STRING
+		   && params[2] == G_TYPE_STRING)
+	    {
+	      ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
+	    }
 	}
     }
 



More information about the dbus-commit mailing list