dbus-gproxy.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-gproxy.c Proxy for remote objects
00003  *
00004  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
00005  * Copyright (C) 2005 Nokia
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 #include <dbus/dbus-glib.h>
00025 #include <dbus/dbus-glib-lowlevel.h>
00026 #include <dbus/dbus-signature.h>
00027 #include "dbus-gutils.h"
00028 #include "dbus-gsignature.h"
00029 #include "dbus-gvalue.h"
00030 #include "dbus-gvalue-utils.h"
00031 #include "dbus-gobject.h"
00032 #include <string.h>
00033 #include <glib/gi18n.h>
00034 #include <gobject/gvaluecollector.h>
00035 
00036 #define DBUS_G_PROXY_CALL_TO_ID(x) (GPOINTER_TO_UINT(x))
00037 #define DBUS_G_PROXY_ID_TO_CALL(x) (GUINT_TO_POINTER(x))
00038 #define DBUS_G_PROXY_GET_PRIVATE(o)  \
00039        (G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUS_TYPE_G_PROXY, DBusGProxyPrivate))
00040 
00041 
00052 typedef struct _DBusGProxyManager DBusGProxyManager;
00053 
00054 typedef struct _DBusGProxyPrivate DBusGProxyPrivate;
00055 
00059 struct _DBusGProxyPrivate
00060 {
00061   DBusGProxyManager *manager; 
00062   char *name;                 
00063   char *path;                 
00064   char *interface;            
00066   DBusGProxyCall *name_call;  
00067   guint for_owner : 1;        
00068   guint associated : 1;       
00070   /* FIXME: make threadsafe? */
00071   guint call_id_counter;      
00073   GData *signal_signatures;   
00075   GHashTable *pending_calls;  
00076 };
00077 
00078 static void dbus_g_proxy_init               (DBusGProxy      *proxy);
00079 static void dbus_g_proxy_class_init         (DBusGProxyClass *klass);
00080 static GObject *dbus_g_proxy_constructor    (GType                  type,
00081                                              guint                  n_construct_properties,
00082                                              GObjectConstructParam *construct_properties);
00083 static void     dbus_g_proxy_set_property       (GObject               *object,
00084                                                  guint                  prop_id,
00085                                                  const GValue          *value,
00086                                                  GParamSpec            *pspec);
00087 static void     dbus_g_proxy_get_property       (GObject               *object,
00088                                                  guint                  prop_id,
00089                                                  GValue                *value,
00090                                                  GParamSpec            *pspec);
00091 
00092 static void dbus_g_proxy_finalize           (GObject         *object);
00093 static void dbus_g_proxy_dispose            (GObject         *object);
00094 static void dbus_g_proxy_destroy            (DBusGProxy      *proxy);
00095 static void dbus_g_proxy_emit_remote_signal (DBusGProxy      *proxy,
00096                                              DBusMessage     *message);
00097 
00098 static DBusGProxyCall *manager_begin_bus_call (DBusGProxyManager    *manager,
00099                                                const char          *method,
00100                                                DBusGProxyCallNotify notify,
00101                                                gpointer             data,
00102                                                GDestroyNotify       destroy,
00103                                                GType                first_arg_type,
00104                                                ...);
00105 static guint dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
00106                                                const char          *method,
00107                                                DBusGProxyCallNotify notify,
00108                                                gpointer             data,
00109                                                GDestroyNotify       destroy,
00110                                                GValueArray         *args,
00111                                                int timeout );
00112 static gboolean dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
00113                                                 guint              call_id,
00114                                                 GError           **error,
00115                                                 GType              first_arg_type,
00116                                                 va_list            args);
00117 
00122 typedef struct
00123 {
00124   GSList *proxies; 
00126   char name[4]; 
00131 } DBusGProxyList;
00132 
00138 struct _DBusGProxyManager
00139 {
00140   GStaticMutex lock; 
00141   int refcount;      
00142   DBusConnection *connection; 
00144   DBusGProxy *bus_proxy; 
00146   GHashTable *proxy_lists; 
00149   GHashTable *owner_names; 
00153   GSList *unassociated_proxies;     
00157 };
00158 
00159 static DBusGProxyManager *dbus_g_proxy_manager_ref    (DBusGProxyManager *manager);
00160 static DBusHandlerResult  dbus_g_proxy_manager_filter (DBusConnection    *connection,
00161                                                        DBusMessage       *message,
00162                                                        void              *user_data);
00163 
00164 
00166 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
00167 
00168 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
00169 
00170 static int g_proxy_manager_slot = -1;
00171 
00172 /* Lock controlling get/set manager as data on each connection */
00173 static GStaticMutex connection_g_proxy_lock = G_STATIC_MUTEX_INIT;
00174 
00175 static DBusGProxyManager*
00176 dbus_g_proxy_manager_get (DBusConnection *connection)
00177 {
00178   DBusGProxyManager *manager;
00179 
00180   dbus_connection_allocate_data_slot (&g_proxy_manager_slot);
00181   if (g_proxy_manager_slot < 0)
00182     g_error ("out of memory");
00183   
00184   g_static_mutex_lock (&connection_g_proxy_lock);
00185   
00186   manager = dbus_connection_get_data (connection, g_proxy_manager_slot);
00187   if (manager != NULL)
00188     {
00189       dbus_connection_free_data_slot (&g_proxy_manager_slot);
00190       dbus_g_proxy_manager_ref (manager);
00191       g_static_mutex_unlock (&connection_g_proxy_lock);
00192       return manager;
00193     }
00194   
00195   manager = g_new0 (DBusGProxyManager, 1);
00196 
00197   manager->refcount = 1;
00198   manager->connection = connection;
00199 
00200   g_static_mutex_init (&manager->lock);
00201 
00202   /* Proxy managers keep the connection alive, which means that
00203    * DBusGProxy indirectly does. To free a connection you have to free
00204    * all the proxies referring to it.
00205    */
00206   dbus_connection_ref (manager->connection);
00207 
00208   dbus_connection_set_data (connection, g_proxy_manager_slot,
00209                             manager, NULL);
00210 
00211   dbus_connection_add_filter (connection, dbus_g_proxy_manager_filter,
00212                               manager, NULL);
00213   
00214   g_static_mutex_unlock (&connection_g_proxy_lock);
00215   
00216   return manager;
00217 }
00218 
00219 static DBusGProxyManager * 
00220 dbus_g_proxy_manager_ref (DBusGProxyManager *manager)
00221 {
00222   g_assert (manager != NULL);
00223   g_assert (manager->refcount > 0);
00224 
00225   LOCK_MANAGER (manager);
00226   
00227   manager->refcount += 1;
00228 
00229   UNLOCK_MANAGER (manager);
00230 
00231   return manager;
00232 }
00233 
00234 static void
00235 dbus_g_proxy_manager_unref (DBusGProxyManager *manager)
00236 {
00237   g_assert (manager != NULL);
00238   g_assert (manager->refcount > 0);
00239 
00240   LOCK_MANAGER (manager);
00241   manager->refcount -= 1;
00242   if (manager->refcount == 0)
00243     {
00244       UNLOCK_MANAGER (manager);
00245 
00246       if (manager->bus_proxy)
00247         g_object_unref (manager->bus_proxy);
00248 
00249       if (manager->proxy_lists)
00250         {
00251           /* can't have any proxies left since they hold
00252            * a reference to the proxy manager.
00253            */
00254           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
00255           
00256           g_hash_table_destroy (manager->proxy_lists);
00257           manager->proxy_lists = NULL;
00258 
00259         }
00260 
00261       if (manager->owner_names)
00262         {
00263           /* Since we destroyed all proxies, none can be tracking
00264            * name owners
00265            */
00266           g_assert (g_hash_table_size (manager->owner_names) == 0);
00267 
00268           g_hash_table_destroy (manager->owner_names);
00269           manager->owner_names = NULL;
00270         }
00271 
00272       g_assert (manager->unassociated_proxies == NULL);
00273       
00274       g_static_mutex_free (&manager->lock);
00275 
00276       g_static_mutex_lock (&connection_g_proxy_lock);
00277 
00278       dbus_connection_remove_filter (manager->connection, dbus_g_proxy_manager_filter,
00279                                      manager);
00280       
00281       dbus_connection_set_data (manager->connection,
00282                                 g_proxy_manager_slot,
00283                                 NULL, NULL);
00284 
00285       g_static_mutex_unlock (&connection_g_proxy_lock);
00286       
00287       dbus_connection_unref (manager->connection);
00288       g_free (manager);
00289 
00290       dbus_connection_free_data_slot (&g_proxy_manager_slot);
00291     }
00292   else
00293     {
00294       UNLOCK_MANAGER (manager);
00295     }
00296 }
00297 
00298 static guint
00299 tristring_hash (gconstpointer key)
00300 {
00301   const char *p = key;
00302   guint h = *p;
00303 
00304   if (h)
00305     {
00306       for (p += 1; *p != '\0'; p++)
00307         h = (h << 5) - h + *p;
00308     }
00309 
00310   /* skip nul and do the next substring */
00311   for (p += 1; *p != '\0'; p++)
00312     h = (h << 5) - h + *p;
00313 
00314   /* skip nul again and another substring */
00315   for (p += 1; *p != '\0'; p++)
00316     h = (h << 5) - h + *p;
00317   
00318   return h;
00319 }
00320 
00321 static gboolean
00322 strequal_len (const char *a,
00323               const char *b,
00324               size_t     *lenp)
00325 {
00326   size_t a_len;
00327   size_t b_len;
00328 
00329   a_len = strlen (a);
00330   b_len = strlen (b);
00331 
00332   if (a_len != b_len)
00333     return FALSE;
00334 
00335   if (memcmp (a, b, a_len) != 0)
00336     return FALSE;
00337   
00338   *lenp = a_len;
00339 
00340   return TRUE;
00341 }
00342 
00343 static gboolean
00344 tristring_equal (gconstpointer  a,
00345                  gconstpointer  b)
00346 {
00347   const char *ap = a;
00348   const char *bp = b;
00349   size_t len;
00350 
00351   if (!strequal_len (ap, bp, &len))
00352     return FALSE;
00353 
00354   ap += len + 1;
00355   bp += len + 1;
00356 
00357   if (!strequal_len (ap, bp, &len))
00358     return FALSE;
00359 
00360   ap += len + 1;
00361   bp += len + 1;
00362 
00363   if (strcmp (ap, bp) != 0)
00364     return FALSE;
00365   
00366   return TRUE;
00367 }
00368 
00369 static char*
00370 tristring_alloc_from_strings (size_t      padding_before,
00371                               const char *name,
00372                               const char *path,
00373                               const char *interface)
00374 {
00375   size_t name_len, iface_len, path_len, len;
00376   char *tri;
00377   
00378   if (name)
00379     name_len = strlen (name);
00380   else
00381     name_len = 0;
00382 
00383   path_len = strlen (path);
00384   
00385   iface_len = strlen (interface);
00386 
00387   tri = g_malloc (padding_before + name_len + path_len + iface_len + 3);
00388 
00389   len = padding_before;
00390   
00391   if (name)
00392     memcpy (&tri[len], name, name_len);
00393 
00394   len += name_len;
00395   tri[len] = '\0';
00396   len += 1;
00397 
00398   g_assert (len == (padding_before + name_len + 1));
00399   
00400   memcpy (&tri[len], path, path_len);
00401   len += path_len;
00402   tri[len] = '\0';
00403   len += 1;
00404 
00405   g_assert (len == (padding_before + name_len + path_len + 2));
00406   
00407   memcpy (&tri[len], interface, iface_len);
00408   len += iface_len;
00409   tri[len] = '\0';
00410   len += 1;
00411 
00412   g_assert (len == (padding_before + name_len + path_len + iface_len + 3));
00413 
00414   return tri;
00415 }
00416 
00417 static char*
00418 tristring_from_proxy (DBusGProxy *proxy)
00419 {
00420   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00421 
00422   return tristring_alloc_from_strings (0,
00423                                        priv->name,
00424                                        priv->path,
00425                                        priv->interface);
00426 }
00427 
00428 static char*
00429 tristring_from_message (DBusMessage *message)
00430 {
00431   const char *path;
00432   const char *interface;
00433 
00434   path = dbus_message_get_path (message);
00435   interface = dbus_message_get_interface (message);
00436 
00437   g_assert (path);
00438   g_assert (interface);
00439   
00440   return tristring_alloc_from_strings (0,
00441                                        dbus_message_get_sender (message),
00442                                        path, interface);
00443 }
00444 
00445 static DBusGProxyList*
00446 g_proxy_list_new (DBusGProxy *first_proxy)
00447 {
00448   DBusGProxyList *list;
00449   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(first_proxy);
00450   
00451   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
00452                                                priv->name,
00453                                                priv->path,
00454                                                priv->interface);
00455   list->proxies = NULL;
00456 
00457   return list;
00458 }
00459 
00460 static void
00461 g_proxy_list_free (DBusGProxyList *list)
00462 {
00463   /* we don't hold a reference to the proxies in the list,
00464    * as they ref the GProxyManager
00465    */
00466   g_slist_free (list->proxies);  
00467 
00468   g_free (list);
00469 }
00470 
00471 static char*
00472 g_proxy_get_match_rule (DBusGProxy *proxy)
00473 {
00474   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00475   /* FIXME Escaping is required here */
00476   
00477   if (priv->name)
00478     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
00479                             priv->name, priv->path, priv->interface);
00480   else
00481     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
00482                             priv->path, priv->interface);
00483 }
00484 
00485 typedef struct
00486 {
00487   char *name;
00488   guint refcount;
00489 } DBusGProxyNameOwnerInfo;
00490 
00491 static gint
00492 find_name_in_info (gconstpointer a, gconstpointer b)
00493 {
00494   const DBusGProxyNameOwnerInfo *info = a;
00495   const char *name = b;
00496 
00497   if (info == NULL || info->name == NULL)
00498     return 1;
00499   return strcmp (info->name, name);
00500 }
00501 
00502 typedef struct
00503 {
00504   const char *name;
00505   const char *owner;
00506   DBusGProxyNameOwnerInfo *info;
00507 } DBusGProxyNameOwnerForeachData;
00508 
00509 static void
00510 name_owner_foreach (gpointer key, gpointer val, gpointer data)
00511 {
00512   const char *owner;
00513   DBusGProxyNameOwnerForeachData *foreach_data;
00514   GSList *names;
00515   GSList *link;
00516 
00517   owner = key;
00518   names = val;
00519   foreach_data = data;
00520 
00521   if (foreach_data->owner != NULL)
00522     return;
00523 
00524   g_assert (foreach_data->info == NULL);
00525 
00526   link = g_slist_find_custom (names, foreach_data->name, find_name_in_info);
00527   if (link)
00528     {
00529       foreach_data->owner = owner;
00530       foreach_data->info = link->data;
00531     }
00532 }
00533 
00534 static gboolean
00535 dbus_g_proxy_manager_lookup_name_owner (DBusGProxyManager        *manager,
00536                                         const char               *name,
00537                                         DBusGProxyNameOwnerInfo **info,
00538                                         const char              **owner)
00539 {
00540   DBusGProxyNameOwnerForeachData foreach_data;
00541 
00542   foreach_data.name = name;
00543   foreach_data.owner = NULL;
00544   foreach_data.info = NULL;
00545   
00546   g_hash_table_foreach (manager->owner_names, name_owner_foreach, &foreach_data);
00547 
00548   *info = foreach_data.info;
00549   *owner = foreach_data.owner;
00550   return *info != NULL;
00551 }
00552 
00553 static void
00554 insert_nameinfo (DBusGProxyManager       *manager,
00555                  const char              *owner,
00556                  DBusGProxyNameOwnerInfo *info)
00557 {
00558   GSList *names;
00559   gboolean insert;
00560 
00561   names = g_hash_table_lookup (manager->owner_names, owner);
00562 
00563   /* Only need to g_hash_table_insert the first time */
00564   insert = (names == NULL);
00565 
00566   names = g_slist_append (names, info); 
00567 
00568   if (insert)
00569     g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
00570 }
00571 
00572 static void
00573 dbus_g_proxy_manager_monitor_name_owner (DBusGProxyManager  *manager,
00574                                          const char         *owner,
00575                                          const char         *name)
00576 {
00577   GSList *names;
00578   GSList *link;
00579   DBusGProxyNameOwnerInfo *nameinfo;
00580 
00581   names = g_hash_table_lookup (manager->owner_names, owner);
00582   link = g_slist_find_custom (names, name, find_name_in_info);
00583   
00584   if (!link)
00585     {
00586       nameinfo = g_new0 (DBusGProxyNameOwnerInfo, 1);
00587       nameinfo->name = g_strdup (name);
00588       nameinfo->refcount = 1;
00589 
00590       insert_nameinfo (manager, owner, nameinfo);
00591     }
00592   else
00593     {
00594       nameinfo = link->data;
00595       nameinfo->refcount++;
00596     }
00597 }
00598 
00599 static void
00600 dbus_g_proxy_manager_unmonitor_name_owner (DBusGProxyManager  *manager,
00601                                            const char         *name)
00602 {
00603   DBusGProxyNameOwnerInfo *info;
00604   const char *owner;
00605   gboolean ret;
00606 
00607   ret = dbus_g_proxy_manager_lookup_name_owner (manager, name, &info, &owner);
00608   g_assert (ret);
00609   g_assert (info != NULL);
00610   g_assert (owner != NULL);
00611 
00612   info->refcount--;
00613   if (info->refcount == 0)
00614     {
00615       GSList *names;
00616       GSList *link;
00617 
00618       names = g_hash_table_lookup (manager->owner_names, owner);
00619       link = g_slist_find_custom (names, name, find_name_in_info);
00620       names = g_slist_delete_link (names, link);
00621       if (names != NULL)
00622         g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
00623       else
00624         g_hash_table_remove (manager->owner_names, owner);
00625 
00626       g_free (info->name);
00627       g_free (info);
00628     }
00629 }
00630 
00631 typedef struct
00632 {
00633   const char *name;
00634   GSList *destroyed;
00635 } DBusGProxyUnassociateData;
00636 
00637 static void
00638 unassociate_proxies (gpointer key, gpointer val, gpointer user_data)
00639 {
00640   DBusGProxyList *list;
00641   const char *name;
00642   GSList *tmp;
00643   DBusGProxyUnassociateData *data;
00644 
00645   list = val;
00646   data = user_data;
00647   name = data->name;
00648   
00649   for (tmp = list->proxies; tmp; tmp = tmp->next)
00650     {
00651       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
00652       DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00653       DBusGProxyManager *manager;
00654 
00655       manager = priv->manager;
00656 
00657       if (!strcmp (priv->name, name))
00658         {
00659           if (!priv->for_owner)
00660             {
00661               if (priv->name_call != NULL)
00662                 {
00663                   dbus_g_proxy_cancel_call (manager->bus_proxy,
00664                                             priv->name_call);
00665                   priv->name_call = NULL;
00666                 }
00667 
00668               priv->associated = FALSE;
00669               manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
00670             }
00671           else
00672             {
00673               data->destroyed = g_slist_prepend (data->destroyed, proxy);
00674               /* make contents of list into weak pointers in case the objects
00675                * unref each other when disposing */
00676               g_object_add_weak_pointer (G_OBJECT (proxy),
00677                   &(data->destroyed->data));
00678             }
00679         }
00680     }
00681 }
00682 
00683 static void
00684 dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager  *manager,
00685                                          const char         *name,
00686                                          const char         *prev_owner,
00687                                          const char         *new_owner)
00688 {
00689   GSList *names;
00690           
00691   if (prev_owner[0] == '\0')
00692     {
00693       GSList *tmp;
00694       GSList *removed;
00695 
00696       /* We have a new service, look at unassociated proxies */
00697 
00698       removed = NULL;
00699 
00700       for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
00701         {
00702           DBusGProxy *proxy = tmp->data;
00703           DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00704 
00705           if (!strcmp (priv->name, name))
00706             {
00707               removed = g_slist_prepend (removed, tmp);
00708               
00709               dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
00710               priv->associated = TRUE;
00711             }
00712         }
00713 
00714       for (tmp = removed; tmp; tmp = tmp->next)
00715         manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
00716       g_slist_free (removed);
00717     }
00718   else
00719     {
00720       DBusGProxyNameOwnerInfo *info;
00721       GSList *link;
00722 
00723       /* Name owner changed or deleted */ 
00724 
00725       names = g_hash_table_lookup (manager->owner_names, prev_owner);
00726 
00727       info = NULL;
00728       if (names != NULL)
00729         {
00730           link = g_slist_find_custom (names, name, find_name_in_info);
00731 
00732           if (link != NULL)
00733             {
00734               info = link->data;
00735           
00736               names = g_slist_delete_link (names, link);
00737 
00738               if (names == NULL)
00739                 g_hash_table_remove (manager->owner_names, prev_owner);
00740             }
00741         }
00742 
00743       if (new_owner[0] == '\0')
00744         {
00745           DBusGProxyUnassociateData data;
00746           GSList *tmp;
00747 
00748           data.name = name;
00749           data.destroyed = NULL;
00750 
00751           /* A service went away, we need to unassociate proxies */
00752           g_hash_table_foreach (manager->proxy_lists,
00753                                 unassociate_proxies, &data);
00754 
00755           UNLOCK_MANAGER (manager);
00756 
00757           /* the destroyed list's data pointers are weak pointers, so that we
00758            * don't end up calling destroy on proxies which have already been
00759            * freed up as a result of other ones being destroyed */
00760           for (tmp = data.destroyed; tmp; tmp = tmp->next)
00761             if (tmp->data != NULL)
00762               {
00763                 g_object_remove_weak_pointer (G_OBJECT (tmp->data),
00764                     &(tmp->data));
00765                 dbus_g_proxy_destroy (tmp->data);
00766               }
00767           g_slist_free (data.destroyed);
00768 
00769           LOCK_MANAGER (manager);
00770 
00771           if (info)
00772             {
00773               g_free (info->name);
00774               g_free (info);
00775             }
00776         }
00777       else if (info)
00778         {
00779           insert_nameinfo (manager, new_owner, info);
00780         }
00781     }
00782 }
00783 
00784 static void
00785 got_name_owner_cb (DBusGProxy       *bus_proxy,
00786                    DBusGProxyCall   *call,
00787                    void             *user_data)
00788 {
00789   DBusGProxy *proxy = user_data;
00790   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00791   GError *error;
00792   char *owner;
00793 
00794   error = NULL;
00795   owner = NULL;
00796 
00797   LOCK_MANAGER (priv->manager);
00798 
00799   if (!dbus_g_proxy_end_call (bus_proxy, call, &error,
00800                               G_TYPE_STRING, &owner,
00801                               G_TYPE_INVALID))
00802     {
00803       if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
00804         {
00805           priv->manager->unassociated_proxies = g_slist_prepend (priv->manager->unassociated_proxies, proxy);
00806         }
00807       else if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION)
00808         g_warning ("Couldn't get name owner (%s): %s",
00809                    dbus_g_error_get_name (error),
00810                    error->message);
00811       else
00812         g_warning ("Couldn't get name owner (code %d): %s",
00813                    error->code, error->message);
00814       g_clear_error (&error);
00815       goto out;
00816     }
00817   else
00818     {
00819       dbus_g_proxy_manager_monitor_name_owner (priv->manager, owner, priv->name);
00820       priv->associated = TRUE;
00821     }
00822 
00823  out:
00824   priv->name_call = NULL;
00825   UNLOCK_MANAGER (priv->manager);
00826   g_free (owner);
00827 }
00828 
00829 static char *
00830 get_name_owner (DBusConnection     *connection,
00831                 const char         *name,
00832                 GError            **error)
00833 {
00834   DBusError derror;
00835   DBusMessage *request, *reply;
00836   char *base_name;
00837   
00838   dbus_error_init (&derror);
00839 
00840   base_name = NULL;
00841   reply = NULL;
00842 
00843   request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
00844                                           DBUS_PATH_DBUS,
00845                                           DBUS_INTERFACE_DBUS,
00846                                           "GetNameOwner");
00847   if (request == NULL)
00848     g_error ("Out of memory");
00849   
00850   if (!dbus_message_append_args (request, 
00851                                  DBUS_TYPE_STRING, &name, 
00852                                  DBUS_TYPE_INVALID))
00853     g_error ("Out of memory");
00854 
00855   reply =
00856     dbus_connection_send_with_reply_and_block (connection,
00857                                                request,
00858                                                2000, &derror);
00859   if (reply == NULL)
00860     goto error;
00861 
00862   if (dbus_set_error_from_message (&derror, reply))
00863     goto error;
00864 
00865   if (!dbus_message_get_args (reply, &derror, 
00866                               DBUS_TYPE_STRING, &base_name, 
00867                               DBUS_TYPE_INVALID))
00868     goto error;
00869 
00870   base_name = g_strdup (base_name);
00871   goto out;
00872 
00873  error:
00874   g_assert (dbus_error_is_set (&derror));
00875   dbus_set_g_error (error, &derror);
00876   dbus_error_free (&derror);
00877 
00878  out:
00879   if (request)
00880     dbus_message_unref (request);
00881   if (reply)
00882     dbus_message_unref (reply);
00883 
00884   return base_name;
00885 }
00886 
00887 
00888 static void
00889 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
00890                                DBusGProxy        *proxy)
00891 {
00892   DBusGProxyList *list;
00893   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00894 
00895   LOCK_MANAGER (manager);
00896 
00897   if (manager->proxy_lists == NULL)
00898     {
00899       g_assert (manager->owner_names == NULL);
00900 
00901       list = NULL;
00902       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
00903                                                     tristring_equal,
00904                                                     NULL,
00905                                                     (GFreeFunc) g_proxy_list_free);
00906       manager->owner_names = g_hash_table_new_full (g_str_hash,
00907                                                     g_str_equal,
00908                                                     g_free,
00909                                                     NULL);
00910       /* FIXME - for now we listen for all NameOwnerChanged; once
00911        * Anders' detail patch lands we should add individual rules
00912        */
00913       dbus_bus_add_match (manager->connection,
00914                           "type='signal',sender='" DBUS_SERVICE_DBUS
00915                           "',path='" DBUS_PATH_DBUS
00916                           "',interface='" DBUS_INTERFACE_DBUS
00917                           "',member='NameOwnerChanged'",
00918                           NULL);
00919     }
00920   else
00921     {
00922       char *tri;
00923 
00924       tri = tristring_from_proxy (proxy);
00925       
00926       list = g_hash_table_lookup (manager->proxy_lists, tri);
00927 
00928       g_free (tri);
00929     }
00930       
00931   if (list == NULL)
00932     {
00933       list = g_proxy_list_new (proxy);
00934       
00935       g_hash_table_replace (manager->proxy_lists,
00936                             list->name, list);
00937     }
00938 
00939   if (list->proxies == NULL && priv->name)
00940     {
00941       /* We have to add the match rule to the server,
00942        * but only if the server is a message bus,
00943        * not if it's a peer.
00944        */
00945        char *rule;
00946        
00947        rule = g_proxy_get_match_rule (proxy);
00948        
00949        /* We don't check for errors; it's not like anyone would handle them, and
00950         * we don't want a round trip here.
00951         */
00952        dbus_bus_add_match (manager->connection,
00953                            rule, NULL);
00954        
00955        g_free (rule);
00956     }
00957 
00958   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00959   
00960   list->proxies = g_slist_prepend (list->proxies, proxy);
00961 
00962   if (!priv->for_owner)
00963     {
00964       const char *owner;
00965       DBusGProxyNameOwnerInfo *info;
00966 
00967       if (!dbus_g_proxy_manager_lookup_name_owner (manager, priv->name, &info, &owner))
00968         {
00969           priv->name_call = manager_begin_bus_call (manager, "GetNameOwner",
00970                                                      got_name_owner_cb,
00971                                                      proxy, NULL,
00972                                                      G_TYPE_STRING,
00973                                                      priv->name, 
00974                                                      G_TYPE_INVALID);
00975           
00976           priv->associated = FALSE;
00977         }
00978       else
00979         {
00980           info->refcount++;
00981           priv->associated = TRUE;
00982         }
00983     }
00984   
00985   UNLOCK_MANAGER (manager);
00986 }
00987 
00988 static void
00989 dbus_g_proxy_manager_unregister (DBusGProxyManager *manager,
00990                                 DBusGProxy        *proxy)
00991 {
00992   DBusGProxyList *list;
00993   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00994   char *tri;
00995   
00996   LOCK_MANAGER (manager);
00997 
00998 #ifndef G_DISABLE_CHECKS
00999   if (manager->proxy_lists == NULL)
01000     {
01001       g_warning ("Trying to unregister a proxy but there aren't any registered");
01002       return;
01003     }
01004 #endif
01005 
01006   tri = tristring_from_proxy (proxy);
01007   
01008   list = g_hash_table_lookup (manager->proxy_lists, tri);
01009 
01010 #ifndef G_DISABLE_CHECKS
01011   if (list == NULL)
01012     {
01013       g_warning ("Trying to unregister a proxy but it isn't registered");
01014       return;
01015     }
01016 #endif
01017 
01018   g_assert (g_slist_find (list->proxies, proxy) != NULL);
01019   
01020   list->proxies = g_slist_remove (list->proxies, proxy);
01021 
01022   g_assert (g_slist_find (list->proxies, proxy) == NULL);
01023 
01024   if (!priv->for_owner)
01025     {
01026       if (!priv->associated)
01027         {
01028           GSList *link;
01029 
01030           if (priv->name_call != 0)
01031             {
01032               dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
01033               priv->name_call = 0;
01034             }
01035           else
01036             {
01037               link = g_slist_find (manager->unassociated_proxies, proxy);
01038               g_assert (link != NULL);
01039 
01040               manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, link);
01041             }
01042         }
01043       else
01044         {
01045           g_assert (priv->name_call == 0);
01046           
01047           dbus_g_proxy_manager_unmonitor_name_owner (manager, priv->name);
01048         }
01049     }
01050 
01051   if (list->proxies == NULL)
01052     {
01053       char *rule;
01054       g_hash_table_remove (manager->proxy_lists,
01055                            tri);
01056       list = NULL;
01057 
01058       rule = g_proxy_get_match_rule (proxy);
01059       dbus_bus_remove_match (manager->connection,
01060                              rule, NULL);
01061       g_free (rule);
01062     }
01063   
01064   if (g_hash_table_size (manager->proxy_lists) == 0)
01065     {
01066       g_hash_table_destroy (manager->proxy_lists);
01067       manager->proxy_lists = NULL;
01068 
01069       /* remove the match added in dbus_g_proxy_manager_register */
01070       dbus_bus_remove_match (manager->connection,
01071                           "type='signal',sender='" DBUS_SERVICE_DBUS
01072                           "',path='" DBUS_PATH_DBUS
01073                           "',interface='" DBUS_INTERFACE_DBUS
01074                           "',member='NameOwnerChanged'",
01075                           NULL);
01076     }
01077 
01078   g_free (tri);
01079       
01080   UNLOCK_MANAGER (manager);
01081 }
01082 
01083 static void
01084 list_proxies_foreach (gpointer key,
01085                       gpointer value,
01086                       gpointer user_data)
01087 {
01088   DBusGProxyList *list;
01089   GSList **ret;
01090   GSList *tmp;
01091   
01092   list = value;
01093   ret = user_data;
01094 
01095   tmp = list->proxies;
01096   while (tmp != NULL)
01097     {
01098       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
01099 
01100       g_object_ref (proxy);
01101       *ret = g_slist_prepend (*ret, proxy);
01102       
01103       tmp = tmp->next;
01104     }
01105 }
01106 
01107 static GSList*
01108 dbus_g_proxy_manager_list_all (DBusGProxyManager *manager)
01109 {
01110   GSList *ret;
01111 
01112   ret = NULL;
01113 
01114   if (manager->proxy_lists)
01115     {
01116       g_hash_table_foreach (manager->proxy_lists,
01117                             list_proxies_foreach,
01118                             &ret);
01119     }
01120 
01121   return ret;
01122 }
01123 
01124 static DBusHandlerResult
01125 dbus_g_proxy_manager_filter (DBusConnection    *connection,
01126                              DBusMessage       *message,
01127                              void              *user_data)
01128 {
01129   DBusGProxyManager *manager;
01130   
01131   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
01132     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01133 
01134   manager = user_data;
01135 
01136   dbus_g_proxy_manager_ref (manager);
01137   
01138   LOCK_MANAGER (manager);
01139   
01140   if (dbus_message_is_signal (message,
01141                               DBUS_INTERFACE_LOCAL,
01142                               "Disconnected"))
01143     {
01144       /* Destroy all the proxies, quite possibly resulting in unreferencing
01145        * the proxy manager and the connection as well.
01146        */
01147       GSList *all;
01148       GSList *tmp;
01149 
01150       all = dbus_g_proxy_manager_list_all (manager);
01151 
01152       tmp = all;
01153       while (tmp != NULL)
01154         {
01155           DBusGProxy *proxy;
01156 
01157           proxy = DBUS_G_PROXY (tmp->data);
01158 
01159           UNLOCK_MANAGER (manager);
01160           dbus_g_proxy_destroy (proxy);
01161           g_object_unref (G_OBJECT (proxy));
01162           LOCK_MANAGER (manager);
01163           
01164           tmp = tmp->next;
01165         }
01166 
01167       g_slist_free (all);
01168 
01169 #ifndef G_DISABLE_CHECKS
01170       if (manager->proxy_lists != NULL)
01171         g_warning ("Disconnection emitted \"destroy\" on all DBusGProxy, but somehow new proxies were created in response to one of those destroy signals. This will cause a memory leak.");
01172 #endif
01173     }
01174   else
01175     {
01176       char *tri;
01177       GSList *full_list;
01178       GSList *owned_names;
01179       GSList *tmp;
01180       const char *sender;
01181 
01182       /* First we handle NameOwnerChanged internally */
01183       if (dbus_message_is_signal (message,
01184                                   DBUS_INTERFACE_DBUS,
01185                                   "NameOwnerChanged"))
01186         {
01187           const char *name;
01188           const char *prev_owner;
01189           const char *new_owner;
01190           DBusError derr;
01191 
01192           dbus_error_init (&derr);
01193           if (!dbus_message_get_args (message,
01194                                       &derr,
01195                                       DBUS_TYPE_STRING,
01196                                       &name,
01197                                       DBUS_TYPE_STRING,
01198                                       &prev_owner,
01199                                       DBUS_TYPE_STRING,
01200                                       &new_owner,
01201                                       DBUS_TYPE_INVALID))
01202             {
01203               /* Ignore this error */
01204               dbus_error_free (&derr);
01205             }
01206           else if (manager->owner_names != NULL)
01207             {
01208               dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
01209             }
01210         }
01211 
01212       sender = dbus_message_get_sender (message);
01213 
01214       /* dbus spec requires these, libdbus validates */
01215       g_assert (dbus_message_get_path (message) != NULL);
01216       g_assert (dbus_message_get_interface (message) != NULL);
01217       g_assert (dbus_message_get_member (message) != NULL);
01218       
01219       tri = tristring_from_message (message);
01220 
01221       if (manager->proxy_lists)
01222         {
01223           DBusGProxyList *owner_list;
01224           owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01225           if (owner_list)
01226             full_list = g_slist_copy (owner_list->proxies);
01227           else
01228             full_list = NULL;
01229         }
01230       else
01231         full_list = NULL;
01232 
01233       g_free (tri);
01234 
01235       if (manager->owner_names && sender)
01236         {
01237           owned_names = g_hash_table_lookup (manager->owner_names, sender);
01238           for (tmp = owned_names; tmp; tmp = tmp->next)
01239             {
01240               DBusGProxyList *owner_list;
01241               DBusGProxyNameOwnerInfo *nameinfo;
01242 
01243               nameinfo = tmp->data;
01244               g_assert (nameinfo->refcount > 0);
01245               tri = tristring_alloc_from_strings (0, nameinfo->name,
01246                                                   dbus_message_get_path (message),
01247                                                   dbus_message_get_interface (message));
01248 
01249               owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01250               if (owner_list != NULL)
01251                 full_list = g_slist_concat (full_list, g_slist_copy (owner_list->proxies));
01252               g_free (tri);
01253             }
01254         }
01255 
01256 #if 0
01257       g_print ("proxy got %s,%s,%s = list %p\n",
01258                tri,
01259                tri + strlen (tri) + 1,
01260                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
01261                list);
01262 #endif
01263       
01264       /* Emit the signal */
01265       
01266       g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
01267       
01268       for (tmp = full_list; tmp; tmp = tmp->next)
01269         {
01270           DBusGProxy *proxy;
01271           
01272           proxy = DBUS_G_PROXY (tmp->data);
01273           
01274           UNLOCK_MANAGER (manager);
01275           dbus_g_proxy_emit_remote_signal (proxy, message);
01276           g_object_unref (G_OBJECT (proxy));
01277           LOCK_MANAGER (manager);
01278         }
01279       g_slist_free (full_list);
01280     }
01281 
01282   UNLOCK_MANAGER (manager);
01283   dbus_g_proxy_manager_unref (manager);
01284   
01285   /* "Handling" signals doesn't make sense, they are for everyone
01286    * who cares
01287    */
01288   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01289 }
01290 
01291 
01292 
01293 /*      ---------- DBusGProxy --------------   */
01294 #define DBUS_G_PROXY_DESTROYED(proxy)  (DBUS_G_PROXY_GET_PRIVATE(proxy)->manager == NULL)
01295 
01296 static void
01297 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
01298                                       GValue       *return_value,
01299                                       guint         n_param_values,
01300                                       const GValue *param_values,
01301                                       gpointer      invocation_hint,
01302                                       gpointer      marshal_data);
01303 enum
01304 {
01305   PROP_0,
01306   PROP_NAME,
01307   PROP_PATH,
01308   PROP_INTERFACE,
01309   PROP_CONNECTION
01310 };
01311 
01312 enum
01313 {
01314   DESTROY,
01315   RECEIVED,
01316   LAST_SIGNAL
01317 };
01318 
01319 static void *parent_class;
01320 static guint signals[LAST_SIGNAL] = { 0 };
01321 
01322 static void
01323 dbus_g_proxy_init (DBusGProxy *proxy)
01324 {
01325   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01326   
01327   g_datalist_init (&priv->signal_signatures);
01328   priv->pending_calls = g_hash_table_new_full (NULL, NULL, NULL,
01329                                 (GDestroyNotify) dbus_pending_call_unref);
01330   priv->name_call = 0;
01331   priv->associated = FALSE;
01332 }
01333 
01334 static GObject *
01335 dbus_g_proxy_constructor (GType                  type,
01336                           guint                  n_construct_properties,
01337                           GObjectConstructParam *construct_properties)
01338 {
01339   DBusGProxy *proxy;
01340   DBusGProxyClass *klass;
01341   GObjectClass *parent_class;
01342   DBusGProxyPrivate *priv;
01343 
01344   klass = DBUS_G_PROXY_CLASS (g_type_class_peek (DBUS_TYPE_G_PROXY));
01345 
01346   parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
01347 
01348   proxy = DBUS_G_PROXY (parent_class->constructor (type, n_construct_properties,
01349                                                     construct_properties));
01350 
01351   priv = DBUS_G_PROXY_GET_PRIVATE (proxy);
01352 
01353   /* if these assertions fail, a deriving class has not set our required
01354    * parameters - our own public constructors do return_if_fail checks
01355    * on these parameters being provided. unfortunately we can't assert
01356    * for manager because it's allowed to be NULL when tha mangager is
01357    * setting up a bus proxy for its own calls */
01358   g_assert (priv->path != NULL);
01359   g_assert (priv->interface != NULL);
01360 
01361   if (priv->manager != NULL)
01362     {
01363       dbus_g_proxy_manager_register (priv->manager, proxy);
01364     }
01365 
01366   return G_OBJECT (proxy);
01367 }
01368 
01369 static void
01370 dbus_g_proxy_class_init (DBusGProxyClass *klass)
01371 {
01372   GObjectClass *object_class = G_OBJECT_CLASS (klass);
01373   
01374   parent_class = g_type_class_peek_parent (klass);
01375 
01376   g_type_class_add_private (klass, sizeof (DBusGProxyPrivate));
01377 
01378   object_class->set_property = dbus_g_proxy_set_property;
01379   object_class->get_property = dbus_g_proxy_get_property;
01380 
01381   g_object_class_install_property (object_class,
01382                                    PROP_NAME,
01383                                    g_param_spec_string ("name",
01384                                                         "name",
01385                                                         "name",
01386                                                         NULL,
01387                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01388 
01389   g_object_class_install_property (object_class,
01390                                    PROP_PATH,
01391                                    g_param_spec_string ("path",
01392                                                         "path",
01393                                                         "path",
01394                                                         NULL,
01395                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01396 
01397   g_object_class_install_property (object_class,
01398                                    PROP_INTERFACE,
01399                                    g_param_spec_string ("interface",
01400                                                         "interface",
01401                                                         "interface",
01402                                                         NULL,
01403                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01404   
01405   g_object_class_install_property (object_class,
01406                                    PROP_CONNECTION,
01407                                    g_param_spec_boxed ("connection",
01408                                                         "connection",
01409                                                         "connection",
01410                                                         DBUS_TYPE_G_CONNECTION,
01411                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01412   
01413   object_class->finalize = dbus_g_proxy_finalize;
01414   object_class->dispose = dbus_g_proxy_dispose;
01415   object_class->constructor = dbus_g_proxy_constructor;
01416   
01417   signals[DESTROY] =
01418     g_signal_new ("destroy",
01419                   G_OBJECT_CLASS_TYPE (object_class),
01420                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
01421                   0,
01422                   NULL, NULL,
01423                   g_cclosure_marshal_VOID__VOID,
01424                   G_TYPE_NONE, 0);
01425 
01426   signals[RECEIVED] =
01427     g_signal_new ("received",
01428                   G_OBJECT_CLASS_TYPE (object_class),
01429                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
01430                   0,
01431                   NULL, NULL,
01432                   marshal_dbus_message_to_g_marshaller,
01433                   G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
01434 }
01435 
01436 static gboolean
01437 cancel_pending_call (gpointer key, gpointer val, gpointer data)
01438 {
01439   DBusPendingCall *pending = val;
01440 
01441   dbus_pending_call_cancel (pending);
01442 
01443   return TRUE;
01444 }
01445 
01446 static void
01447 dbus_g_proxy_dispose (GObject *object)
01448 {
01449   DBusGProxy *proxy = DBUS_G_PROXY (object);
01450   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01451 
01452   if (priv->pending_calls == NULL) 
01453     {
01454       return;
01455     }
01456 
01457   /* Cancel outgoing pending calls */
01458   g_hash_table_foreach_remove (priv->pending_calls, cancel_pending_call, NULL);
01459   g_hash_table_destroy (priv->pending_calls);
01460   priv->pending_calls = NULL;
01461 
01462   if (priv->manager && proxy != priv->manager->bus_proxy)
01463     {
01464       dbus_g_proxy_manager_unregister (priv->manager, proxy);
01465       dbus_g_proxy_manager_unref (priv->manager);
01466     }
01467   priv->manager = NULL;
01468   
01469   g_datalist_clear (&priv->signal_signatures);
01470   
01471   g_signal_emit (object, signals[DESTROY], 0);
01472   
01473   G_OBJECT_CLASS (parent_class)->dispose (object);
01474 }
01475 
01476 static void
01477 dbus_g_proxy_finalize (GObject *object)
01478 {
01479   DBusGProxy *proxy = DBUS_G_PROXY (object);
01480   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01481   
01482   g_return_if_fail (DBUS_G_PROXY_DESTROYED (proxy));
01483   
01484   g_free (priv->name);
01485   g_free (priv->path);
01486   g_free (priv->interface);
01487   
01488   G_OBJECT_CLASS (parent_class)->finalize (object);
01489 }
01490 
01491 static void
01492 dbus_g_proxy_destroy (DBusGProxy *proxy)
01493 {
01494   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
01495    * from GtkObject?
01496    */
01497   g_object_run_dispose (G_OBJECT (proxy));
01498 }
01499 
01500 static void
01501 dbus_g_proxy_set_property (GObject *object,
01502                            guint prop_id,
01503                            const GValue *value,
01504                            GParamSpec *pspec)
01505 {
01506   DBusGProxy *proxy = DBUS_G_PROXY (object);
01507   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01508   DBusGConnection *connection;
01509 
01510   switch (prop_id)
01511     {
01512     case PROP_NAME:
01513       priv->name = g_strdup (g_value_get_string (value));
01514       if (priv->name)
01515         priv->for_owner = (priv->name[0] == ':');
01516       else
01517         priv->for_owner = TRUE;
01518       break;
01519     case PROP_PATH:
01520       priv->path = g_strdup (g_value_get_string (value));
01521       break;
01522     case PROP_INTERFACE:
01523       priv->interface = g_strdup (g_value_get_string (value));
01524       break;
01525     case PROP_CONNECTION:
01526       connection = g_value_get_boxed (value);
01527       if (connection != NULL)
01528         {
01529           priv->manager = dbus_g_proxy_manager_get (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
01530         }
01531       break;
01532     default:
01533       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01534       break;
01535     }
01536 }
01537 
01538 static void 
01539 dbus_g_proxy_get_property (GObject *object,
01540                            guint prop_id,
01541                            GValue *value,
01542                            GParamSpec *pspec)
01543 {
01544   DBusGProxy *proxy = DBUS_G_PROXY (object);
01545   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01546 
01547   switch (prop_id)
01548     {
01549     case PROP_NAME:
01550       g_value_set_string (value, priv->name);
01551       break;
01552     case PROP_PATH:
01553       g_value_set_string (value, priv->path);
01554       break;
01555     case PROP_INTERFACE:
01556       g_value_set_string (value, priv->interface);
01557       break;
01558     case PROP_CONNECTION:
01559       g_value_set_boxed (value, DBUS_G_CONNECTION_FROM_CONNECTION(priv->manager->connection));
01560       break;
01561     default:
01562       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01563       break;
01564     }
01565 }
01566 
01567 /* this is to avoid people using g_signal_connect() directly,
01568  * to avoid confusion with local signal names, and because
01569  * of the horribly broken current setup (signals are added
01570  * globally to all proxies)
01571  */
01572 static char*
01573 create_signal_name (const char *interface,
01574                     const char *signal)
01575 {
01576   GString *str;
01577   char *p;
01578 
01579   str = g_string_new (interface);
01580 
01581   g_string_append (str, "-");
01582   
01583   g_string_append (str, signal);
01584 
01585   /* GLib will silently barf on '.' in signal names */
01586   p = str->str;
01587   while (*p)
01588     {
01589       if (*p == '.')
01590         *p = '-';
01591       ++p;
01592     }
01593   
01594   return g_string_free (str, FALSE);
01595 }
01596 
01597 static void
01598 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
01599                                       GValue       *return_value,
01600                                       guint         n_param_values,
01601                                       const GValue *param_values,
01602                                       gpointer      invocation_hint,
01603                                       gpointer      marshal_data)
01604 {
01605   /* Incoming here we have three params, the instance (Proxy), the
01606    * DBusMessage, the signature. We want to convert that to an
01607    * expanded GValue array, then call an appropriate normal GLib
01608    * marshaller.
01609    */
01610 #define MAX_SIGNATURE_ARGS 20
01611   GValueArray *value_array;
01612   GSignalCMarshaller c_marshaller;
01613   DBusGProxy *proxy;
01614   DBusMessage *message;
01615   GArray *gsignature;
01616   const GType *types;
01617   DBusGProxyPrivate *priv;
01618 
01619   g_assert (n_param_values == 3);
01620 
01621   proxy = g_value_get_object (&param_values[0]);
01622   message = g_value_get_boxed (&param_values[1]);
01623   gsignature = g_value_get_pointer (&param_values[2]);
01624 
01625   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
01626   g_return_if_fail (message != NULL);
01627   g_return_if_fail (gsignature != NULL);
01628 
01629   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01630 
01631   c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
01632                                                   (GType*) gsignature->data);
01633 
01634   g_return_if_fail (c_marshaller != NULL);
01635   
01636   {
01637     DBusGValueMarshalCtx context;
01638     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
01639     context.proxy = proxy;
01640 
01641     types = (const GType*) gsignature->data;
01642     value_array = _dbus_gvalue_demarshal_message (&context, message,
01643                                                  gsignature->len, types, NULL);
01644   }
01645 
01646   if (value_array == NULL)
01647     return;
01648   
01649   g_value_array_prepend (value_array, NULL);
01650   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_FROM_INSTANCE (proxy));
01651   g_value_set_instance (g_value_array_get_nth (value_array, 0), proxy);
01652 
01653   (* c_marshaller) (closure, return_value, value_array->n_values,
01654                     value_array->values, invocation_hint, marshal_data);
01655   
01656   g_value_array_free (value_array);
01657 }
01658 
01659 static void
01660 dbus_g_proxy_emit_remote_signal (DBusGProxy  *proxy,
01661                                  DBusMessage *message)
01662 {
01663   const char *interface;
01664   const char *signal;
01665   char *name;
01666   GQuark q;
01667   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01668   GArray *msg_gsignature = NULL;
01669 
01670   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
01671 
01672   interface = dbus_message_get_interface (message);
01673   signal = dbus_message_get_member (message);
01674 
01675   g_assert (interface != NULL);
01676   g_assert (signal != NULL);
01677 
01678   name = create_signal_name (interface, signal);
01679 
01680   /* If the quark isn't preexisting, there's no way there
01681    * are any handlers connected. We don't want to create
01682    * extra quarks for every possible signal.
01683    */
01684   q = g_quark_try_string (name);
01685 
01686   if (q != 0)
01687     {
01688       GArray *gsignature;
01689       guint i;
01690       
01691       gsignature = g_datalist_id_get_data (&priv->signal_signatures, q);
01692       if (gsignature == NULL)
01693         goto out;
01694       
01695       msg_gsignature = _dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
01696                                                        TRUE);
01697       for (i = 0; i < gsignature->len; i++)
01698         {
01699           if (msg_gsignature->len == i
01700               || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
01701             goto mismatch;
01702         }
01703       if (msg_gsignature->len != i)
01704         goto mismatch;
01705       
01706       g_signal_emit (proxy,
01707                      signals[RECEIVED],
01708                      q,
01709                      message,
01710                      msg_gsignature);
01711     }
01712 
01713  out:
01714   g_free (name);
01715   if (msg_gsignature)
01716     g_array_free (msg_gsignature, TRUE);
01717   return;
01718  mismatch:
01719 #if 0
01720   /* Don't spew on remote errors */
01721   g_warning ("Unexpected message signature '%s' for signal '%s'\n",
01722              dbus_message_get_signature (message),
01723              name);
01724 #endif
01725   goto out;
01726 }
01727 
01728 typedef struct
01729 {
01730   DBusGProxy *proxy;
01731   guint call_id;
01732   DBusGProxyCallNotify func;
01733   void *data;
01734   GDestroyNotify free_data_func;
01735 } GPendingNotifyClosure;
01736 
01737 static void
01738 d_pending_call_notify (DBusPendingCall *dcall,
01739                        void            *data)
01740 {
01741   GPendingNotifyClosure *closure = data;
01742 
01743   (* closure->func) (closure->proxy, DBUS_G_PROXY_ID_TO_CALL (closure->call_id), closure->data);
01744 }
01745 
01746 static void
01747 d_pending_call_free (void *data)
01748 {
01749   GPendingNotifyClosure *closure = data;
01750   
01751   if (closure->free_data_func)
01752     (* closure->free_data_func) (closure->data);
01753 
01754   g_free (closure);
01755 }
01756   
01757 #define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
01758 do { \
01759   GType valtype; \
01760   int i = 0; \
01761   VALARRAY = g_value_array_new (6); \
01762   valtype = FIRST_ARG_TYPE; \
01763   while (valtype != G_TYPE_INVALID) \
01764     { \
01765       const char *collect_err; \
01766       GValue *val; \
01767       g_value_array_append (VALARRAY, NULL); \
01768       val = g_value_array_get_nth (VALARRAY, i); \
01769       g_value_init (val, valtype); \
01770       collect_err = NULL; \
01771       G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
01772       valtype = va_arg (ARGS, GType); \
01773       i++; \
01774     } \
01775 } while (0)
01776 
01777 DBusGProxyCall *
01778 manager_begin_bus_call (DBusGProxyManager    *manager,
01779                         const char           *method,
01780                         DBusGProxyCallNotify  notify,
01781                         gpointer              user_data,
01782                         GDestroyNotify        destroy,
01783                         GType                 first_arg_type,
01784                         ...)
01785 {
01786   DBusGProxyCall *call;
01787   DBusGProxyPrivate *priv;
01788   va_list args;
01789   GValueArray *arg_values;
01790   
01791   va_start (args, first_arg_type);
01792 
01793   if (!manager->bus_proxy)
01794     {
01795       manager->bus_proxy = g_object_new (DBUS_TYPE_G_PROXY,
01796                                          "name", DBUS_SERVICE_DBUS,
01797                                          "path", DBUS_PATH_DBUS,
01798                                          "interface", DBUS_INTERFACE_DBUS,
01799                                          NULL);
01800       priv = DBUS_G_PROXY_GET_PRIVATE(manager->bus_proxy);
01801       priv->manager = manager;
01802     }
01803 
01804   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
01805   
01806   call = DBUS_G_PROXY_ID_TO_CALL (dbus_g_proxy_begin_call_internal (manager->bus_proxy, method, notify, user_data, destroy, arg_values,-1));
01807 
01808   g_value_array_free (arg_values);
01809 
01810   va_end (args);
01811 
01812   return call;
01813 }
01814 
01836 GType
01837 dbus_g_proxy_get_type (void)
01838 {
01839   static GType object_type = 0;
01840 
01841   if (!object_type)
01842     {
01843       static const GTypeInfo object_info =
01844         {
01845           sizeof (DBusGProxyClass),
01846           (GBaseInitFunc) NULL,
01847           (GBaseFinalizeFunc) NULL,
01848           (GClassInitFunc) dbus_g_proxy_class_init,
01849           NULL,           /* class_finalize */
01850           NULL,           /* class_data */
01851           sizeof (DBusGProxy),
01852           0,              /* n_preallocs */
01853           (GInstanceInitFunc) dbus_g_proxy_init,
01854         };
01855       
01856       object_type = g_type_register_static (G_TYPE_OBJECT,
01857                                             "DBusGProxy",
01858                                             &object_info, 0);
01859     }
01860   
01861   return object_type;
01862 }
01863 
01864 static DBusGProxy*
01865 dbus_g_proxy_new (DBusGConnection *connection,
01866                   const char      *name,
01867                   const char      *path_name,
01868                   const char      *interface_name)
01869 {
01870   DBusGProxy *proxy;
01871 
01872   g_assert (connection != NULL);
01873   
01874   proxy = g_object_new (DBUS_TYPE_G_PROXY, 
01875                         "name", name, 
01876                         "path", path_name, 
01877                         "interface", interface_name, 
01878                         "connection", connection, NULL);
01879 
01880   return proxy;
01881 }
01882 
01911 DBusGProxy*
01912 dbus_g_proxy_new_for_name (DBusGConnection *connection,
01913                            const char      *name,
01914                            const char      *path_name,
01915                            const char      *interface_name)
01916 {
01917   g_return_val_if_fail (connection != NULL, NULL);
01918   g_return_val_if_fail (name != NULL, NULL);
01919   g_return_val_if_fail (path_name != NULL, NULL);
01920   g_return_val_if_fail (interface_name != NULL, NULL);
01921 
01922   return dbus_g_proxy_new (connection, name,
01923                            path_name, interface_name);
01924 }
01925 
01951 DBusGProxy*
01952 dbus_g_proxy_new_for_name_owner (DBusGConnection          *connection,
01953                                  const char               *name,
01954                                  const char               *path_name,
01955                                  const char               *interface_name,
01956                                  GError                  **error)
01957 {
01958   DBusGProxy *proxy;
01959   char *unique_name;
01960 
01961   g_return_val_if_fail (connection != NULL, NULL);
01962   g_return_val_if_fail (name != NULL, NULL);
01963   g_return_val_if_fail (path_name != NULL, NULL);
01964   g_return_val_if_fail (interface_name != NULL, NULL);
01965 
01966   if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
01967     return NULL;
01968 
01969   proxy = dbus_g_proxy_new (connection, unique_name,
01970                             path_name, interface_name);
01971   g_free (unique_name);
01972   return proxy;
01973 }
01974 
01986 DBusGProxy*
01987 dbus_g_proxy_new_from_proxy (DBusGProxy        *proxy,
01988                              const char        *interface,
01989                              const char        *path)
01990 {
01991   DBusGProxyPrivate *priv;
01992 
01993   g_return_val_if_fail (proxy != NULL, NULL);
01994 
01995   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01996   
01997   if (interface == NULL)
01998     interface = priv->interface;
01999   if (path == NULL)
02000     path = priv->path;
02001 
02002   return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection),
02003                            priv->name,
02004                            path, interface);
02005 }
02006 
02021 DBusGProxy*
02022 dbus_g_proxy_new_for_peer (DBusGConnection          *connection,
02023                            const char               *path_name,
02024                            const char               *interface_name)
02025 {
02026   DBusGProxy *proxy;
02027   
02028   g_return_val_if_fail (connection != NULL, NULL);
02029   g_return_val_if_fail (path_name != NULL, NULL);
02030   g_return_val_if_fail (interface_name != NULL, NULL);
02031 
02032   proxy = dbus_g_proxy_new (connection, NULL,
02033                             path_name, interface_name);
02034 
02035   return proxy;
02036 }
02037 
02051 const char*
02052 dbus_g_proxy_get_bus_name (DBusGProxy        *proxy)
02053 {
02054   DBusGProxyPrivate *priv;
02055 
02056   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02057   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02058 
02059   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02060 
02061   return priv->name;
02062 }
02063 
02072 const char*
02073 dbus_g_proxy_get_interface (DBusGProxy        *proxy)
02074 {
02075   DBusGProxyPrivate *priv;
02076   
02077   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02078   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02079 
02080   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02081 
02082   return priv->interface;
02083 }
02084 
02092 void
02093 dbus_g_proxy_set_interface (DBusGProxy        *proxy,
02094                             const char        *interface_name)
02095 {
02096   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02097   /* FIXME - need to unregister when we switch interface for now
02098    * later should support idea of unset interface
02099    */
02100   dbus_g_proxy_manager_unregister (priv->manager, proxy);
02101   g_free (priv->interface);
02102   priv->interface = g_strdup (interface_name);
02103   dbus_g_proxy_manager_register (priv->manager, proxy);
02104 }
02105 
02113 const char*
02114 dbus_g_proxy_get_path (DBusGProxy        *proxy)
02115 {
02116   DBusGProxyPrivate *priv;
02117   
02118   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02119   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02120 
02121   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02122 
02123   return priv->path;
02124 }
02125 
02126 static DBusMessage *
02127 dbus_g_proxy_marshal_args_to_message (DBusGProxy  *proxy,
02128                                       const char  *method,
02129                                       GValueArray *args)
02130 {
02131   DBusMessage *message;
02132   DBusMessageIter msgiter;
02133   guint i;
02134   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02135 
02136   message = dbus_message_new_method_call (priv->name,
02137                                           priv->path,
02138                                           priv->interface,
02139                                           method);
02140   if (message == NULL)
02141     goto oom;
02142 
02143   dbus_message_iter_init_append (message, &msgiter);
02144   for (i = 0; i < args->n_values; i++)
02145     {
02146       GValue *gvalue;
02147 
02148       gvalue = g_value_array_get_nth (args, i);
02149 
02150       if (!_dbus_gvalue_marshal (&msgiter, gvalue))
02151         g_assert_not_reached ();
02152     }
02153   return message;
02154  oom:
02155   return NULL;
02156 }
02157 
02158 static guint
02159 dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
02160                                   const char          *method,
02161                                   DBusGProxyCallNotify notify,
02162                                   gpointer             user_data,
02163                                   GDestroyNotify       destroy,
02164                                   GValueArray         *args,
02165                                   int timeout)
02166 {
02167   DBusMessage *message;
02168   DBusPendingCall *pending;
02169   GPendingNotifyClosure *closure;
02170   guint call_id;
02171   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02172 
02173   pending = NULL;
02174 
02175   message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
02176   if (!message)
02177     goto oom;
02178 
02179   if (!dbus_connection_send_with_reply (priv->manager->connection,
02180                                         message,
02181                                         &pending,
02182                                         timeout))
02183     goto oom;
02184   dbus_message_unref (message);
02185   if (pending == NULL)
02186     {
02187       g_debug ("Disconnected");
02188       return 0;
02189     }
02190 
02191   call_id = ++priv->call_id_counter;
02192 
02193   if (notify != NULL)
02194     {
02195       closure = g_new (GPendingNotifyClosure, 1);
02196       closure->proxy = proxy; /* No need to ref as the lifecycle is tied to proxy */
02197       closure->call_id = call_id;
02198       closure->func = notify;
02199       closure->data = user_data;
02200       closure->free_data_func = destroy;
02201       dbus_pending_call_set_notify (pending, d_pending_call_notify,
02202                                     closure,
02203                                     d_pending_call_free);
02204     }
02205 
02206   g_hash_table_insert (priv->pending_calls, GUINT_TO_POINTER (call_id), pending);
02207 
02208   return call_id;
02209  oom:
02210   g_error ("Out of memory");
02211   return 0;
02212 }
02213 
02214 static gboolean
02215 dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
02216                                 guint              call_id,
02217                                 GError           **error,
02218                                 GType              first_arg_type,
02219                                 va_list            args)
02220 {
02221   DBusMessage *reply;
02222   DBusMessageIter msgiter;
02223   DBusError derror;
02224   va_list args_unwind;
02225   guint over;
02226   int n_retvals_processed;
02227   gboolean ret;
02228   GType valtype;
02229   DBusPendingCall *pending;
02230   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02231 
02232   reply = NULL;
02233   ret = FALSE;
02234   n_retvals_processed = 0;
02235   over = 0;
02236 
02237   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
02238   
02239   dbus_pending_call_block (pending);
02240   reply = dbus_pending_call_steal_reply (pending);
02241 
02242   g_assert (reply != NULL);
02243 
02244   dbus_error_init (&derror);
02245 
02246   switch (dbus_message_get_type (reply))
02247     {
02248     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
02249       dbus_message_iter_init (reply, &msgiter);
02250       valtype = first_arg_type;
02251       while (valtype != G_TYPE_INVALID)
02252         {
02253           int arg_type;
02254           gpointer return_storage;
02255           GValue gvalue = { 0, };
02256           DBusGValueMarshalCtx context;
02257 
02258           context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
02259           context.proxy = proxy;
02260 
02261           arg_type = dbus_message_iter_get_arg_type (&msgiter);
02262           if (arg_type == DBUS_TYPE_INVALID)
02263             {
02264               g_set_error (error, DBUS_GERROR,
02265                            DBUS_GERROR_INVALID_ARGS,
02266                            _("Too few arguments in reply"));
02267               goto out;
02268             }
02269 
02270           return_storage = va_arg (args, gpointer);
02271           if (return_storage == NULL)
02272             goto next;
02273 
02274           /* We handle variants specially; the caller is expected
02275            * to have already allocated storage for them.
02276            */
02277           if (arg_type == DBUS_TYPE_VARIANT
02278               && g_type_is_a (valtype, G_TYPE_VALUE))
02279             {
02280               if (!_dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
02281                 {
02282                   g_set_error (error,
02283                                DBUS_GERROR,
02284                                DBUS_GERROR_INVALID_ARGS,
02285                                _("Couldn't convert argument, expected \"%s\""),
02286                                g_type_name (valtype));
02287                   goto out;
02288                 }
02289             }
02290           else
02291             {
02292               g_value_init (&gvalue, valtype);
02293 
02294               if (!_dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error))
02295                 goto out;
02296 
02297               /* Anything that can be demarshaled must be storable */
02298               if (!_dbus_gvalue_store (&gvalue, (gpointer*) return_storage))
02299                 g_assert_not_reached ();
02300               /* Ownership of the value passes to the client, don't unset */
02301             }
02302           
02303         next:
02304           n_retvals_processed++;
02305           dbus_message_iter_next (&msgiter);
02306           valtype = va_arg (args, GType);
02307         }
02308       
02309       while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
02310         {
02311           over++;
02312           dbus_message_iter_next (&msgiter);
02313         }
02314 
02315       if (over > 0)
02316         {
02317           g_set_error (error, DBUS_GERROR,
02318                        DBUS_GERROR_INVALID_ARGS,
02319                        _("Too many arguments in reply; expected %d, got %d"),
02320                        n_retvals_processed, over);
02321           goto out;
02322         }
02323       break;
02324     case DBUS_MESSAGE_TYPE_ERROR:
02325       dbus_set_error_from_message (&derror, reply);
02326       dbus_set_g_error (error, &derror);
02327       dbus_error_free (&derror);
02328       goto out;
02329       break;
02330     default:
02331       dbus_set_error (&derror, DBUS_ERROR_FAILED,
02332                       "Reply was neither a method return nor an exception");
02333       dbus_set_g_error (error, &derror);
02334       dbus_error_free (&derror);
02335       goto out;
02336       break;
02337     }
02338 
02339   ret = TRUE;
02340  out:
02341   va_end (args);
02342 
02343   if (ret == FALSE)
02344     {
02345       int i;
02346       for (i = 0; i < n_retvals_processed; i++)
02347         {
02348           gpointer retval;
02349 
02350           retval = va_arg (args_unwind, gpointer);
02351 
02352           g_free (retval);
02353         }
02354     }
02355   va_end (args_unwind);
02356 
02357   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
02358 
02359   if (reply)
02360     dbus_message_unref (reply);
02361   return ret;
02362 }
02363 
02386 DBusGProxyCall *
02387 dbus_g_proxy_begin_call (DBusGProxy          *proxy,
02388                          const char          *method,
02389                          DBusGProxyCallNotify notify,
02390                          gpointer             user_data,
02391                          GDestroyNotify       destroy,
02392                          GType                first_arg_type,
02393                          ...)
02394 {
02395   guint call_id;
02396   va_list args;
02397   GValueArray *arg_values;
02398   
02399   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02400   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02401 
02402   va_start (args, first_arg_type);
02403 
02404   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
02405   
02406   call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values,-1);
02407 
02408   g_value_array_free (arg_values);
02409 
02410   va_end (args);
02411 
02412   return DBUS_G_PROXY_ID_TO_CALL (call_id);
02413 }
02414 
02438 DBusGProxyCall *
02439 dbus_g_proxy_begin_call_with_timeout (DBusGProxy          *proxy,
02440                          const char          *method,
02441                          DBusGProxyCallNotify notify,
02442                          gpointer             user_data,
02443                          GDestroyNotify       destroy,
02444                          int timeout,
02445                          GType                first_arg_type,
02446                          ...)
02447 {
02448   guint call_id;
02449   va_list args;
02450   GValueArray *arg_values;
02451 
02452   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02453   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02454 
02455   va_start (args, first_arg_type);
02456 
02457   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
02458 
02459   call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values,timeout);
02460 
02461   g_value_array_free (arg_values);
02462 
02463   va_end (args);
02464 
02465   return DBUS_G_PROXY_ID_TO_CALL (call_id);
02466 }
02467 
02490 gboolean
02491 dbus_g_proxy_end_call (DBusGProxy          *proxy,
02492                        DBusGProxyCall      *call,
02493                        GError             **error,
02494                        GType                first_arg_type,
02495                        ...)
02496 {
02497   gboolean ret;
02498   va_list args;
02499 
02500   va_start (args, first_arg_type);
02501 
02502   ret = dbus_g_proxy_end_call_internal (proxy, GPOINTER_TO_UINT (call), error, first_arg_type, args);
02503 
02504   va_end (args);
02505   
02506   return ret;
02507 }
02508 
02525 gboolean
02526 dbus_g_proxy_call (DBusGProxy        *proxy,
02527                    const char        *method,
02528                    GError           **error,
02529                    GType              first_arg_type,
02530                    ...)
02531 {
02532   gboolean ret;
02533   guint call_id;
02534   va_list args;
02535   GValueArray *in_args;
02536 
02537   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02538   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02539 
02540   va_start (args, first_arg_type);
02541 
02542   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02543 
02544   call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args,-1);
02545 
02546   g_value_array_free (in_args);
02547 
02548   if (call_id > 0)
02549     {
02550       first_arg_type = va_arg (args, GType);
02551       ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
02552     }
02553   else
02554     {
02555       g_set_error (error, DBUS_GERROR,
02556                    DBUS_GERROR_FAILED,
02557                    _("Disconnection or out-of-memory"));
02558       ret = FALSE;
02559     }
02560 
02561   va_end (args);
02562 
02563   return ret;
02564 }
02565 
02583 gboolean
02584 dbus_g_proxy_call_with_timeout (DBusGProxy        *proxy,
02585                    const char        *method,
02586                    int timeout,
02587                    GError           **error,
02588                    GType              first_arg_type,
02589                    ...)
02590 {
02591   gboolean ret;
02592   guint call_id;
02593   va_list args;
02594   GValueArray *in_args;
02595 
02596   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02597   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02598 
02599   va_start (args, first_arg_type);
02600 
02601   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02602 
02603   call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args,timeout);
02604 
02605   g_value_array_free (in_args);
02606 
02607   first_arg_type = va_arg (args, GType);
02608   ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
02609 
02610   va_end (args);
02611 
02612   return ret;
02613 }
02614 
02627 void
02628 dbus_g_proxy_call_no_reply (DBusGProxy               *proxy,
02629                             const char               *method,
02630                             GType                     first_arg_type,
02631                             ...)
02632 {
02633   DBusMessage *message;
02634   va_list args;
02635   GValueArray *in_args;
02636   DBusGProxyPrivate *priv;
02637   
02638   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02639   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02640 
02641   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02642 
02643   va_start (args, first_arg_type);
02644   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02645 
02646   message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
02647 
02648   g_value_array_free (in_args);
02649   va_end (args);
02650 
02651   if (!message)
02652     goto oom;
02653 
02654   dbus_message_set_no_reply (message, TRUE);
02655 
02656   if (!dbus_connection_send (priv->manager->connection,
02657                              message,
02658                              NULL))
02659     goto oom;
02660   dbus_message_unref (message);
02661   return;
02662   
02663  oom:
02664   g_error ("Out of memory");
02665 }
02666 
02677 void
02678 dbus_g_proxy_cancel_call (DBusGProxy        *proxy,
02679                           DBusGProxyCall    *call)
02680 {
02681   guint call_id;
02682   DBusPendingCall *pending;
02683   DBusGProxyPrivate *priv;
02684   
02685   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02686   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02687 
02688   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02689 
02690   call_id = DBUS_G_PROXY_CALL_TO_ID (call);
02691 
02692   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
02693   g_return_if_fail (pending != NULL);
02694 
02695   dbus_pending_call_cancel (pending);
02696 
02697   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
02698 }
02699 
02720 void
02721 dbus_g_proxy_send (DBusGProxy          *proxy,
02722                    DBusMessage         *message,
02723                    dbus_uint32_t       *client_serial)
02724 {
02725   DBusGProxyPrivate *priv;
02726   
02727   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02728   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02729   
02730   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02731   
02732   if (priv->name)
02733     {
02734       if (!dbus_message_set_destination (message, priv->name))
02735         g_error ("Out of memory");
02736     }
02737   if (priv->path)
02738     {
02739       if (!dbus_message_set_path (message, priv->path))
02740         g_error ("Out of memory");
02741     }
02742   if (priv->interface)
02743     {
02744       if (!dbus_message_set_interface (message, priv->interface))
02745         g_error ("Out of memory");
02746     }
02747   
02748   if (!dbus_connection_send (priv->manager->connection, message, client_serial))
02749     g_error ("Out of memory\n");
02750 }
02751 
02752 static void
02753 array_free_all (gpointer array)
02754 {
02755   g_array_free (array, TRUE);
02756 }
02757 
02768 void
02769 dbus_g_proxy_add_signal  (DBusGProxy        *proxy,
02770                           const char        *signal_name,
02771                           GType              first_type,
02772                           ...)
02773 {
02774   GQuark q;
02775   char *name;
02776   GArray *gtypesig;
02777   GType gtype;
02778   va_list args;
02779   DBusGProxyPrivate *priv;
02780 
02781   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02782   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02783   g_return_if_fail (signal_name != NULL);
02784   
02785   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02786 
02787   name = create_signal_name (priv->interface, signal_name);
02788   
02789   q = g_quark_from_string (name);
02790   
02791   g_return_if_fail (g_datalist_id_get_data (&priv->signal_signatures, q) == NULL);
02792 
02793   gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
02794 
02795   va_start (args, first_type);
02796   gtype = first_type;
02797   while (gtype != G_TYPE_INVALID)
02798     {
02799       g_array_append_val (gtypesig, gtype);
02800       gtype = va_arg (args, GType);
02801     }
02802   va_end (args);
02803 
02804 #ifndef G_DISABLE_CHECKS
02805   if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
02806     g_warning ("No marshaller for signature of signal '%s'", signal_name);
02807 #endif
02808 
02809   
02810   g_datalist_id_set_data_full (&priv->signal_signatures,
02811                                q, gtypesig,
02812                                array_free_all);
02813 
02814   g_free (name);
02815 }
02816 
02829 void
02830 dbus_g_proxy_connect_signal (DBusGProxy             *proxy,
02831                              const char             *signal_name,
02832                              GCallback               handler,
02833                              void                   *data,
02834                              GClosureNotify          free_data_func)
02835 {
02836   char *name;
02837   GClosure *closure;
02838   GQuark q;
02839   DBusGProxyPrivate *priv;
02840 
02841   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02842   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02843   g_return_if_fail (signal_name != NULL);
02844   g_return_if_fail (handler != NULL);
02845   
02846   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02847   name = create_signal_name (priv->interface, signal_name);
02848 
02849   q = g_quark_try_string (name);
02850 
02851 #ifndef G_DISABLE_CHECKS
02852   if (q == 0 || g_datalist_id_get_data (&priv->signal_signatures, q) == NULL)
02853     {
02854       g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
02855       g_free (name);
02856       return;
02857     }
02858 #endif
02859   
02860   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
02861   
02862   g_signal_connect_closure_by_id (G_OBJECT (proxy),
02863                                   signals[RECEIVED],
02864                                   q,
02865                                   closure, FALSE);
02866   
02867   g_free (name);
02868 }
02869 
02880 void
02881 dbus_g_proxy_disconnect_signal (DBusGProxy             *proxy,
02882                                 const char             *signal_name,
02883                                 GCallback               handler,
02884                                 void                   *data)
02885 {
02886   char *name;
02887   GQuark q;
02888   DBusGProxyPrivate *priv;
02889   
02890   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02891   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02892   g_return_if_fail (signal_name != NULL);
02893   g_return_if_fail (handler != NULL);
02894 
02895   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02896   name = create_signal_name (priv->interface, signal_name);
02897 
02898   q = g_quark_try_string (name);
02899   
02900   if (q != 0)
02901     {
02902       g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
02903                                             G_SIGNAL_MATCH_DETAIL |
02904                                             G_SIGNAL_MATCH_FUNC   |
02905                                             G_SIGNAL_MATCH_DATA,
02906                                             signals[RECEIVED],
02907                                             q,
02908                                             NULL,
02909                                             G_CALLBACK (handler), data);
02910     }
02911   else
02912     {
02913       g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
02914                  name);
02915     }
02916 
02917   g_free (name);
02918 }
02919 
02922 #ifdef DBUS_BUILD_TESTS
02923 
02929 gboolean
02930 _dbus_g_proxy_test (void)
02931 {
02932   
02933   
02934   return TRUE;
02935 }
02936 
02937 #endif /* DBUS_BUILD_TESTS */

Generated on Mon Mar 17 16:28:49 2008 for D-BUSGLibBindings by  doxygen 1.5.1