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;  
00077   int default_timeout; 
00078 };
00079 
00080 static void dbus_g_proxy_init               (DBusGProxy      *proxy);
00081 static void dbus_g_proxy_class_init         (DBusGProxyClass *klass);
00082 static GObject *dbus_g_proxy_constructor    (GType                  type,
00083                                              guint                  n_construct_properties,
00084                                              GObjectConstructParam *construct_properties);
00085 static void     dbus_g_proxy_set_property       (GObject               *object,
00086                                                  guint                  prop_id,
00087                                                  const GValue          *value,
00088                                                  GParamSpec            *pspec);
00089 static void     dbus_g_proxy_get_property       (GObject               *object,
00090                                                  guint                  prop_id,
00091                                                  GValue                *value,
00092                                                  GParamSpec            *pspec);
00093 
00094 static void dbus_g_proxy_finalize           (GObject         *object);
00095 static void dbus_g_proxy_dispose            (GObject         *object);
00096 static void dbus_g_proxy_destroy            (DBusGProxy      *proxy);
00097 static void dbus_g_proxy_emit_remote_signal (DBusGProxy      *proxy,
00098                                              DBusMessage     *message);
00099 
00100 static DBusGProxyCall *manager_begin_bus_call (DBusGProxyManager    *manager,
00101                                                const char          *method,
00102                                                DBusGProxyCallNotify notify,
00103                                                gpointer             data,
00104                                                GDestroyNotify       destroy,
00105                                                GType                first_arg_type,
00106                                                ...);
00107 static guint dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
00108                                                const char          *method,
00109                                                DBusGProxyCallNotify notify,
00110                                                gpointer             data,
00111                                                GDestroyNotify       destroy,
00112                                                GValueArray         *args,
00113                                                int timeout );
00114 static gboolean dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
00115                                                 guint              call_id,
00116                                                 GError           **error,
00117                                                 GType              first_arg_type,
00118                                                 va_list            args);
00119 
00124 typedef struct
00125 {
00126   GSList *proxies; 
00128   char name[4]; 
00133 } DBusGProxyList;
00134 
00140 struct _DBusGProxyManager
00141 {
00142   GStaticMutex lock; 
00143   int refcount;      
00144   DBusConnection *connection; 
00146   DBusGProxy *bus_proxy; 
00148   GHashTable *proxy_lists; 
00151   GHashTable *owner_names; 
00155   GSList *unassociated_proxies;     
00159 };
00160 
00161 static DBusGProxyManager *dbus_g_proxy_manager_ref    (DBusGProxyManager *manager);
00162 static DBusHandlerResult  dbus_g_proxy_manager_filter (DBusConnection    *connection,
00163                                                        DBusMessage       *message,
00164                                                        void              *user_data);
00165 
00166 
00168 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
00169 
00170 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
00171 
00172 static int g_proxy_manager_slot = -1;
00173 
00174 /* Lock controlling get/set manager as data on each connection */
00175 static GStaticMutex connection_g_proxy_lock = G_STATIC_MUTEX_INIT;
00176 
00177 static DBusGProxyManager*
00178 dbus_g_proxy_manager_get (DBusConnection *connection)
00179 {
00180   DBusGProxyManager *manager;
00181 
00182   dbus_connection_allocate_data_slot (&g_proxy_manager_slot);
00183   if (g_proxy_manager_slot < 0)
00184     g_error ("out of memory");
00185   
00186   g_static_mutex_lock (&connection_g_proxy_lock);
00187   
00188   manager = dbus_connection_get_data (connection, g_proxy_manager_slot);
00189   if (manager != NULL)
00190     {
00191       dbus_connection_free_data_slot (&g_proxy_manager_slot);
00192       dbus_g_proxy_manager_ref (manager);
00193       g_static_mutex_unlock (&connection_g_proxy_lock);
00194       return manager;
00195     }
00196   
00197   manager = g_new0 (DBusGProxyManager, 1);
00198 
00199   manager->refcount = 1;
00200   manager->connection = connection;
00201 
00202   g_static_mutex_init (&manager->lock);
00203 
00204   /* Proxy managers keep the connection alive, which means that
00205    * DBusGProxy indirectly does. To free a connection you have to free
00206    * all the proxies referring to it.
00207    */
00208   dbus_connection_ref (manager->connection);
00209 
00210   dbus_connection_set_data (connection, g_proxy_manager_slot,
00211                             manager, NULL);
00212 
00213   dbus_connection_add_filter (connection, dbus_g_proxy_manager_filter,
00214                               manager, NULL);
00215   
00216   g_static_mutex_unlock (&connection_g_proxy_lock);
00217   
00218   return manager;
00219 }
00220 
00221 static DBusGProxyManager * 
00222 dbus_g_proxy_manager_ref (DBusGProxyManager *manager)
00223 {
00224   g_assert (manager != NULL);
00225   g_assert (manager->refcount > 0);
00226 
00227   LOCK_MANAGER (manager);
00228   
00229   manager->refcount += 1;
00230 
00231   UNLOCK_MANAGER (manager);
00232 
00233   return manager;
00234 }
00235 
00236 static void
00237 dbus_g_proxy_manager_unref (DBusGProxyManager *manager)
00238 {
00239   g_assert (manager != NULL);
00240   g_assert (manager->refcount > 0);
00241 
00242   LOCK_MANAGER (manager);
00243   manager->refcount -= 1;
00244   if (manager->refcount == 0)
00245     {
00246       UNLOCK_MANAGER (manager);
00247 
00248       if (manager->bus_proxy)
00249         g_object_unref (manager->bus_proxy);
00250 
00251       if (manager->proxy_lists)
00252         {
00253           /* can't have any proxies left since they hold
00254            * a reference to the proxy manager.
00255            */
00256           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
00257           
00258           g_hash_table_destroy (manager->proxy_lists);
00259           manager->proxy_lists = NULL;
00260 
00261         }
00262 
00263       if (manager->owner_names)
00264         {
00265           /* Since we destroyed all proxies, none can be tracking
00266            * name owners
00267            */
00268           g_assert (g_hash_table_size (manager->owner_names) == 0);
00269 
00270           g_hash_table_destroy (manager->owner_names);
00271           manager->owner_names = NULL;
00272         }
00273 
00274       g_assert (manager->unassociated_proxies == NULL);
00275       
00276       g_static_mutex_free (&manager->lock);
00277 
00278       g_static_mutex_lock (&connection_g_proxy_lock);
00279 
00280       dbus_connection_remove_filter (manager->connection, dbus_g_proxy_manager_filter,
00281                                      manager);
00282       
00283       dbus_connection_set_data (manager->connection,
00284                                 g_proxy_manager_slot,
00285                                 NULL, NULL);
00286 
00287       g_static_mutex_unlock (&connection_g_proxy_lock);
00288       
00289       dbus_connection_unref (manager->connection);
00290       g_free (manager);
00291 
00292       dbus_connection_free_data_slot (&g_proxy_manager_slot);
00293     }
00294   else
00295     {
00296       UNLOCK_MANAGER (manager);
00297     }
00298 }
00299 
00300 static guint
00301 tristring_hash (gconstpointer key)
00302 {
00303   const char *p = key;
00304   guint h = *p;
00305 
00306   if (h)
00307     {
00308       for (p += 1; *p != '\0'; p++)
00309         h = (h << 5) - h + *p;
00310     }
00311 
00312   /* skip nul and do the next substring */
00313   for (p += 1; *p != '\0'; p++)
00314     h = (h << 5) - h + *p;
00315 
00316   /* skip nul again and another substring */
00317   for (p += 1; *p != '\0'; p++)
00318     h = (h << 5) - h + *p;
00319   
00320   return h;
00321 }
00322 
00323 static gboolean
00324 strequal_len (const char *a,
00325               const char *b,
00326               size_t     *lenp)
00327 {
00328   size_t a_len;
00329   size_t b_len;
00330 
00331   a_len = strlen (a);
00332   b_len = strlen (b);
00333 
00334   if (a_len != b_len)
00335     return FALSE;
00336 
00337   if (memcmp (a, b, a_len) != 0)
00338     return FALSE;
00339   
00340   *lenp = a_len;
00341 
00342   return TRUE;
00343 }
00344 
00345 static gboolean
00346 tristring_equal (gconstpointer  a,
00347                  gconstpointer  b)
00348 {
00349   const char *ap = a;
00350   const char *bp = b;
00351   size_t len;
00352 
00353   if (!strequal_len (ap, bp, &len))
00354     return FALSE;
00355 
00356   ap += len + 1;
00357   bp += len + 1;
00358 
00359   if (!strequal_len (ap, bp, &len))
00360     return FALSE;
00361 
00362   ap += len + 1;
00363   bp += len + 1;
00364 
00365   if (strcmp (ap, bp) != 0)
00366     return FALSE;
00367   
00368   return TRUE;
00369 }
00370 
00371 static char*
00372 tristring_alloc_from_strings (size_t      padding_before,
00373                               const char *name,
00374                               const char *path,
00375                               const char *interface)
00376 {
00377   size_t name_len, iface_len, path_len, len;
00378   char *tri;
00379   
00380   if (name)
00381     name_len = strlen (name);
00382   else
00383     name_len = 0;
00384 
00385   path_len = strlen (path);
00386   
00387   iface_len = strlen (interface);
00388 
00389   tri = g_malloc (padding_before + name_len + path_len + iface_len + 3);
00390 
00391   len = padding_before;
00392   
00393   if (name)
00394     memcpy (&tri[len], name, name_len);
00395 
00396   len += name_len;
00397   tri[len] = '\0';
00398   len += 1;
00399 
00400   g_assert (len == (padding_before + name_len + 1));
00401   
00402   memcpy (&tri[len], path, path_len);
00403   len += path_len;
00404   tri[len] = '\0';
00405   len += 1;
00406 
00407   g_assert (len == (padding_before + name_len + path_len + 2));
00408   
00409   memcpy (&tri[len], interface, iface_len);
00410   len += iface_len;
00411   tri[len] = '\0';
00412   len += 1;
00413 
00414   g_assert (len == (padding_before + name_len + path_len + iface_len + 3));
00415 
00416   return tri;
00417 }
00418 
00419 static char*
00420 tristring_from_proxy (DBusGProxy *proxy)
00421 {
00422   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00423 
00424   return tristring_alloc_from_strings (0,
00425                                        priv->name,
00426                                        priv->path,
00427                                        priv->interface);
00428 }
00429 
00430 static char*
00431 tristring_from_message (DBusMessage *message)
00432 {
00433   const char *path;
00434   const char *interface;
00435 
00436   path = dbus_message_get_path (message);
00437   interface = dbus_message_get_interface (message);
00438 
00439   g_assert (path);
00440   g_assert (interface);
00441   
00442   return tristring_alloc_from_strings (0,
00443                                        dbus_message_get_sender (message),
00444                                        path, interface);
00445 }
00446 
00447 static DBusGProxyList*
00448 g_proxy_list_new (DBusGProxy *first_proxy)
00449 {
00450   DBusGProxyList *list;
00451   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(first_proxy);
00452   
00453   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
00454                                                priv->name,
00455                                                priv->path,
00456                                                priv->interface);
00457   list->proxies = NULL;
00458 
00459   return list;
00460 }
00461 
00462 static void
00463 g_proxy_list_free (DBusGProxyList *list)
00464 {
00465   /* we don't hold a reference to the proxies in the list,
00466    * as they ref the GProxyManager
00467    */
00468   g_slist_free (list->proxies);  
00469 
00470   g_free (list);
00471 }
00472 
00473 static char*
00474 g_proxy_get_match_rule (DBusGProxy *proxy)
00475 {
00476   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00477   /* FIXME Escaping is required here */
00478   
00479   if (priv->name)
00480     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
00481                             priv->name, priv->path, priv->interface);
00482   else
00483     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
00484                             priv->path, priv->interface);
00485 }
00486 
00487 typedef struct
00488 {
00489   char *name;
00490   guint refcount;
00491 } DBusGProxyNameOwnerInfo;
00492 
00493 static gint
00494 find_name_in_info (gconstpointer a, gconstpointer b)
00495 {
00496   const DBusGProxyNameOwnerInfo *info = a;
00497   const char *name = b;
00498 
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 a service appeared and then vanished very quickly,
00662                * it's conceivable we have an inflight request for
00663                * GetNameOwner here.  Cancel it.
00664                * https://bugs.freedesktop.org/show_bug.cgi?id=18573
00665                */
00666               if (priv->name_call)
00667                 dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
00668 
00669               priv->name_call = NULL;
00670 
00671               priv->associated = FALSE;
00672               manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
00673             }
00674           else
00675             {
00676               data->destroyed = g_slist_prepend (data->destroyed, proxy);
00677               /* make contents of list into weak pointers in case the objects
00678                * unref each other when disposing */
00679               g_object_add_weak_pointer (G_OBJECT (proxy),
00680                   &(data->destroyed->data));
00681             }
00682         }
00683     }
00684 }
00685 
00686 static void
00687 dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager  *manager,
00688                                          const char         *name,
00689                                          const char         *prev_owner,
00690                                          const char         *new_owner)
00691 {
00692   GSList *names;
00693           
00694   if (prev_owner[0] == '\0')
00695     {
00696       GSList *tmp;
00697       GSList *removed;
00698 
00699       /* We have a new service, look at unassociated proxies */
00700 
00701       removed = NULL;
00702 
00703       for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
00704         {
00705           DBusGProxy *proxy = tmp->data;
00706           DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00707 
00708           if (!strcmp (priv->name, name))
00709             {
00710               removed = g_slist_prepend (removed, tmp);
00711               
00712               dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
00713               priv->associated = TRUE;
00714             }
00715         }
00716 
00717       for (tmp = removed; tmp; tmp = tmp->next)
00718         manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
00719       g_slist_free (removed);
00720     }
00721   else
00722     {
00723       DBusGProxyNameOwnerInfo *info;
00724       GSList *link;
00725 
00726       /* Name owner changed or deleted */ 
00727 
00728       names = g_hash_table_lookup (manager->owner_names, prev_owner);
00729 
00730       info = NULL;
00731       if (names != NULL)
00732         {
00733           link = g_slist_find_custom (names, name, find_name_in_info);
00734 
00735           if (link != NULL)
00736             {
00737               info = link->data;
00738           
00739               names = g_slist_delete_link (names, link);
00740 
00741               if (names == NULL)
00742                 g_hash_table_remove (manager->owner_names, prev_owner);
00743             }
00744         }
00745 
00746       if (new_owner[0] == '\0')
00747         {
00748           DBusGProxyUnassociateData data;
00749           GSList *tmp;
00750 
00751           data.name = name;
00752           data.destroyed = NULL;
00753 
00754           /* A service went away, we need to unassociate proxies */
00755           g_hash_table_foreach (manager->proxy_lists,
00756                                 unassociate_proxies, &data);
00757 
00758           UNLOCK_MANAGER (manager);
00759 
00760           /* the destroyed list's data pointers are weak pointers, so that we
00761            * don't end up calling destroy on proxies which have already been
00762            * freed up as a result of other ones being destroyed */
00763           for (tmp = data.destroyed; tmp; tmp = tmp->next)
00764             if (tmp->data != NULL)
00765               {
00766                 g_object_remove_weak_pointer (G_OBJECT (tmp->data),
00767                     &(tmp->data));
00768                 dbus_g_proxy_destroy (tmp->data);
00769               }
00770           g_slist_free (data.destroyed);
00771 
00772           LOCK_MANAGER (manager);
00773 
00774           if (info)
00775             {
00776               g_free (info->name);
00777               g_free (info);
00778             }
00779         }
00780       else if (info)
00781         {
00782           insert_nameinfo (manager, new_owner, info);
00783         }
00784     }
00785 }
00786 
00787 static void
00788 got_name_owner_cb (DBusGProxy       *bus_proxy,
00789                    DBusGProxyCall   *call,
00790                    void             *user_data)
00791 {
00792   DBusGProxy *proxy = user_data;
00793   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00794   GError *error;
00795   char *owner;
00796 
00797   error = NULL;
00798   owner = NULL;
00799 
00800   LOCK_MANAGER (priv->manager);
00801 
00802   if (!dbus_g_proxy_end_call (bus_proxy, call, &error,
00803                               G_TYPE_STRING, &owner,
00804                               G_TYPE_INVALID))
00805     {
00806       if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
00807         {
00808           priv->manager->unassociated_proxies = g_slist_prepend (priv->manager->unassociated_proxies, proxy);
00809         }
00810       else if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION)
00811         g_warning ("Couldn't get name owner (%s): %s",
00812                    dbus_g_error_get_name (error),
00813                    error->message);
00814       else
00815         g_warning ("Couldn't get name owner (code %d): %s",
00816                    error->code, error->message);
00817       g_clear_error (&error);
00818       goto out;
00819     }
00820   else
00821     {
00822       dbus_g_proxy_manager_monitor_name_owner (priv->manager, owner, priv->name);
00823       priv->associated = TRUE;
00824     }
00825 
00826  out:
00827   priv->name_call = NULL;
00828   UNLOCK_MANAGER (priv->manager);
00829   g_free (owner);
00830 }
00831 
00832 static char *
00833 get_name_owner (DBusConnection     *connection,
00834                 const char         *name,
00835                 GError            **error)
00836 {
00837   DBusError derror;
00838   DBusMessage *request, *reply;
00839   char *base_name;
00840   
00841   dbus_error_init (&derror);
00842 
00843   base_name = NULL;
00844   reply = NULL;
00845 
00846   request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
00847                                           DBUS_PATH_DBUS,
00848                                           DBUS_INTERFACE_DBUS,
00849                                           "GetNameOwner");
00850   if (request == NULL)
00851     g_error ("Out of memory");
00852   
00853   if (!dbus_message_append_args (request, 
00854                                  DBUS_TYPE_STRING, &name, 
00855                                  DBUS_TYPE_INVALID))
00856     g_error ("Out of memory");
00857 
00858   reply =
00859     dbus_connection_send_with_reply_and_block (connection,
00860                                                request,
00861                                                2000, &derror);
00862   if (reply == NULL)
00863     goto error;
00864 
00865   if (dbus_set_error_from_message (&derror, reply))
00866     goto error;
00867 
00868   if (!dbus_message_get_args (reply, &derror, 
00869                               DBUS_TYPE_STRING, &base_name, 
00870                               DBUS_TYPE_INVALID))
00871     goto error;
00872 
00873   base_name = g_strdup (base_name);
00874   goto out;
00875 
00876  error:
00877   g_assert (dbus_error_is_set (&derror));
00878   dbus_set_g_error (error, &derror);
00879   dbus_error_free (&derror);
00880 
00881  out:
00882   if (request)
00883     dbus_message_unref (request);
00884   if (reply)
00885     dbus_message_unref (reply);
00886 
00887   return base_name;
00888 }
00889 
00890 
00891 static void
00892 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
00893                                DBusGProxy        *proxy)
00894 {
00895   DBusGProxyList *list;
00896   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00897 
00898   LOCK_MANAGER (manager);
00899 
00900   if (manager->proxy_lists == NULL)
00901     {
00902       g_assert (manager->owner_names == NULL);
00903 
00904       list = NULL;
00905       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
00906                                                     tristring_equal,
00907                                                     NULL,
00908                                                     (GFreeFunc) g_proxy_list_free);
00909       manager->owner_names = g_hash_table_new_full (g_str_hash,
00910                                                     g_str_equal,
00911                                                     g_free,
00912                                                     NULL);
00913       /* FIXME - for now we listen for all NameOwnerChanged; once
00914        * Anders' detail patch lands we should add individual rules
00915        * 
00916        * NOTE: if you change this, be sure to change the matching
00917        * call to dbus_bus_remove_match in dbus_g_proxy_manager_unregister.
00918        */
00919       dbus_bus_add_match (manager->connection,
00920                           "type='signal',sender='" DBUS_SERVICE_DBUS
00921                           "',path='" DBUS_PATH_DBUS
00922                           "',interface='" DBUS_INTERFACE_DBUS
00923                           "',member='NameOwnerChanged'",
00924                           NULL);
00925     }
00926   else
00927     {
00928       char *tri;
00929 
00930       tri = tristring_from_proxy (proxy);
00931       
00932       list = g_hash_table_lookup (manager->proxy_lists, tri);
00933 
00934       g_free (tri);
00935     }
00936       
00937   if (list == NULL)
00938     {
00939       list = g_proxy_list_new (proxy);
00940       
00941       g_hash_table_replace (manager->proxy_lists,
00942                             list->name, list);
00943     }
00944 
00945   if (list->proxies == NULL && priv->name)
00946     {
00947       /* We have to add the match rule to the server,
00948        * but only if the server is a message bus,
00949        * not if it's a peer.
00950        */
00951        char *rule;
00952        
00953        rule = g_proxy_get_match_rule (proxy);
00954        
00955        /* We don't check for errors; it's not like anyone would handle them, and
00956         * we don't want a round trip here.
00957         */
00958        dbus_bus_add_match (manager->connection,
00959                            rule, NULL);
00960        
00961        g_free (rule);
00962     }
00963 
00964   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00965   
00966   list->proxies = g_slist_prepend (list->proxies, proxy);
00967 
00968   if (!priv->for_owner)
00969     {
00970       const char *owner;
00971       DBusGProxyNameOwnerInfo *info;
00972 
00973       if (!dbus_g_proxy_manager_lookup_name_owner (manager, priv->name, &info, &owner))
00974         {
00975           priv->name_call = manager_begin_bus_call (manager, "GetNameOwner",
00976                                                      got_name_owner_cb,
00977                                                      proxy, NULL,
00978                                                      G_TYPE_STRING,
00979                                                      priv->name, 
00980                                                      G_TYPE_INVALID);
00981           
00982           priv->associated = FALSE;
00983         }
00984       else
00985         {
00986           info->refcount++;
00987           priv->associated = TRUE;
00988         }
00989     }
00990   
00991   UNLOCK_MANAGER (manager);
00992 }
00993 
00994 static void
00995 dbus_g_proxy_manager_unregister (DBusGProxyManager *manager,
00996                                 DBusGProxy        *proxy)
00997 {
00998   DBusGProxyList *list;
00999   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01000   char *tri;
01001   
01002   LOCK_MANAGER (manager);
01003 
01004 #ifndef G_DISABLE_CHECKS
01005   if (manager->proxy_lists == NULL)
01006     {
01007       g_warning ("Trying to unregister a proxy but there aren't any registered");
01008       return;
01009     }
01010 #endif
01011 
01012   tri = tristring_from_proxy (proxy);
01013   
01014   list = g_hash_table_lookup (manager->proxy_lists, tri);
01015 
01016 #ifndef G_DISABLE_CHECKS
01017   if (list == NULL)
01018     {
01019       g_warning ("Trying to unregister a proxy but it isn't registered");
01020       return;
01021     }
01022 #endif
01023 
01024   g_assert (g_slist_find (list->proxies, proxy) != NULL);
01025   
01026   list->proxies = g_slist_remove (list->proxies, proxy);
01027 
01028   g_assert (g_slist_find (list->proxies, proxy) == NULL);
01029 
01030   if (!priv->for_owner)
01031     {
01032       if (!priv->associated)
01033         {
01034           GSList *link;
01035 
01036           if (priv->name_call != 0)
01037             {
01038               dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
01039               priv->name_call = 0;
01040             }
01041           else
01042             {
01043               link = g_slist_find (manager->unassociated_proxies, proxy);
01044               g_assert (link != NULL);
01045 
01046               manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, link);
01047             }
01048         }
01049       else
01050         {
01051           g_assert (priv->name_call == 0);
01052           
01053           dbus_g_proxy_manager_unmonitor_name_owner (manager, priv->name);
01054         }
01055     }
01056 
01057   if (list->proxies == NULL)
01058     {
01059       char *rule;
01060       g_hash_table_remove (manager->proxy_lists,
01061                            tri);
01062       list = NULL;
01063 
01064       rule = g_proxy_get_match_rule (proxy);
01065       dbus_bus_remove_match (manager->connection,
01066                              rule, NULL);
01067       g_free (rule);
01068     }
01069   
01070   if (g_hash_table_size (manager->proxy_lists) == 0)
01071     {
01072       g_hash_table_destroy (manager->proxy_lists);
01073       manager->proxy_lists = NULL;
01074 
01075       /*
01076        * NOTE: if you change this, be sure to change the matching
01077        * call to dbus_bus_add_match in dbus_g_proxy_manager_register.
01078        */
01079       dbus_bus_remove_match (manager->connection,
01080                              "type='signal',sender='" DBUS_SERVICE_DBUS
01081                              "',path='" DBUS_PATH_DBUS
01082                              "',interface='" DBUS_INTERFACE_DBUS
01083                              "',member='NameOwnerChanged'",
01084                              NULL);
01085     }
01086 
01087   g_free (tri);
01088       
01089   UNLOCK_MANAGER (manager);
01090 }
01091 
01092 static void
01093 list_proxies_foreach (gpointer key,
01094                       gpointer value,
01095                       gpointer user_data)
01096 {
01097   DBusGProxyList *list;
01098   GSList **ret;
01099   GSList *tmp;
01100   
01101   list = value;
01102   ret = user_data;
01103 
01104   tmp = list->proxies;
01105   while (tmp != NULL)
01106     {
01107       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
01108 
01109       g_object_ref (proxy);
01110       *ret = g_slist_prepend (*ret, proxy);
01111       
01112       tmp = tmp->next;
01113     }
01114 }
01115 
01116 static GSList*
01117 dbus_g_proxy_manager_list_all (DBusGProxyManager *manager)
01118 {
01119   GSList *ret;
01120 
01121   ret = NULL;
01122 
01123   if (manager->proxy_lists)
01124     {
01125       g_hash_table_foreach (manager->proxy_lists,
01126                             list_proxies_foreach,
01127                             &ret);
01128     }
01129 
01130   return ret;
01131 }
01132 
01133 static DBusHandlerResult
01134 dbus_g_proxy_manager_filter (DBusConnection    *connection,
01135                              DBusMessage       *message,
01136                              void              *user_data)
01137 {
01138   DBusGProxyManager *manager;
01139   
01140   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
01141     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01142 
01143   manager = user_data;
01144 
01145   dbus_g_proxy_manager_ref (manager);
01146   
01147   LOCK_MANAGER (manager);
01148   
01149   if (dbus_message_is_signal (message,
01150                               DBUS_INTERFACE_LOCAL,
01151                               "Disconnected"))
01152     {
01153       /* Destroy all the proxies, quite possibly resulting in unreferencing
01154        * the proxy manager and the connection as well.
01155        */
01156       GSList *all;
01157       GSList *tmp;
01158 
01159       all = dbus_g_proxy_manager_list_all (manager);
01160 
01161       tmp = all;
01162       while (tmp != NULL)
01163         {
01164           DBusGProxy *proxy;
01165 
01166           proxy = DBUS_G_PROXY (tmp->data);
01167 
01168           UNLOCK_MANAGER (manager);
01169           dbus_g_proxy_destroy (proxy);
01170           g_object_unref (G_OBJECT (proxy));
01171           LOCK_MANAGER (manager);
01172           
01173           tmp = tmp->next;
01174         }
01175 
01176       g_slist_free (all);
01177 
01178 #ifndef G_DISABLE_CHECKS
01179       if (manager->proxy_lists != NULL)
01180         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.");
01181 #endif
01182     }
01183   else
01184     {
01185       char *tri;
01186       GSList *full_list;
01187       GSList *owned_names;
01188       GSList *tmp;
01189       const char *sender;
01190 
01191       /* First we handle NameOwnerChanged internally */
01192       if (dbus_message_is_signal (message,
01193                                   DBUS_INTERFACE_DBUS,
01194                                   "NameOwnerChanged"))
01195         {
01196           const char *name;
01197           const char *prev_owner;
01198           const char *new_owner;
01199           DBusError derr;
01200 
01201           dbus_error_init (&derr);
01202           if (!dbus_message_get_args (message,
01203                                       &derr,
01204                                       DBUS_TYPE_STRING,
01205                                       &name,
01206                                       DBUS_TYPE_STRING,
01207                                       &prev_owner,
01208                                       DBUS_TYPE_STRING,
01209                                       &new_owner,
01210                                       DBUS_TYPE_INVALID))
01211             {
01212               /* Ignore this error */
01213               dbus_error_free (&derr);
01214             }
01215           else if (manager->owner_names != NULL)
01216             {
01217               dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
01218             }
01219         }
01220 
01221       sender = dbus_message_get_sender (message);
01222 
01223       /* dbus spec requires these, libdbus validates */
01224       g_assert (dbus_message_get_path (message) != NULL);
01225       g_assert (dbus_message_get_interface (message) != NULL);
01226       g_assert (dbus_message_get_member (message) != NULL);
01227       
01228       tri = tristring_from_message (message);
01229 
01230       if (manager->proxy_lists)
01231         {
01232           DBusGProxyList *owner_list;
01233           owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01234           if (owner_list)
01235             full_list = g_slist_copy (owner_list->proxies);
01236           else
01237             full_list = NULL;
01238         }
01239       else
01240         full_list = NULL;
01241 
01242       g_free (tri);
01243 
01244       if (manager->owner_names && sender)
01245         {
01246           owned_names = g_hash_table_lookup (manager->owner_names, sender);
01247           for (tmp = owned_names; tmp; tmp = tmp->next)
01248             {
01249               DBusGProxyList *owner_list;
01250               DBusGProxyNameOwnerInfo *nameinfo;
01251 
01252               nameinfo = tmp->data;
01253               g_assert (nameinfo->refcount > 0);
01254               tri = tristring_alloc_from_strings (0, nameinfo->name,
01255                                                   dbus_message_get_path (message),
01256                                                   dbus_message_get_interface (message));
01257 
01258               owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01259               if (owner_list != NULL) 
01260                 {
01261                   GSList *elt;
01262 
01263                   /* Ignore duplicates when adding to full_list */
01264                   for (elt = owner_list->proxies; elt; elt = g_slist_next (elt)) 
01265                     {
01266                       if (!g_slist_find (full_list, elt->data))
01267                         full_list = g_slist_append (full_list, elt->data);
01268                     }
01269                 }
01270               g_free (tri);
01271             }
01272         }
01273 
01274 #if 0
01275       g_print ("proxy got %s,%s,%s = list %p\n",
01276                tri,
01277                tri + strlen (tri) + 1,
01278                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
01279                list);
01280 #endif
01281       
01282       /* Emit the signal */
01283       
01284       g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
01285       
01286       for (tmp = full_list; tmp; tmp = tmp->next)
01287         {
01288           DBusGProxy *proxy;
01289           
01290           proxy = DBUS_G_PROXY (tmp->data);
01291           
01292           UNLOCK_MANAGER (manager);
01293           dbus_g_proxy_emit_remote_signal (proxy, message);
01294           g_object_unref (G_OBJECT (proxy));
01295           LOCK_MANAGER (manager);
01296         }
01297       g_slist_free (full_list);
01298     }
01299 
01300   UNLOCK_MANAGER (manager);
01301   dbus_g_proxy_manager_unref (manager);
01302   
01303   /* "Handling" signals doesn't make sense, they are for everyone
01304    * who cares
01305    */
01306   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01307 }
01308 
01309 
01310 
01311 /*      ---------- DBusGProxy --------------   */
01312 #define DBUS_G_PROXY_DESTROYED(proxy)  (DBUS_G_PROXY_GET_PRIVATE(proxy)->manager == NULL)
01313 
01314 static void
01315 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
01316                                       GValue       *return_value,
01317                                       guint         n_param_values,
01318                                       const GValue *param_values,
01319                                       gpointer      invocation_hint,
01320                                       gpointer      marshal_data);
01321 enum
01322 {
01323   PROP_0,
01324   PROP_NAME,
01325   PROP_PATH,
01326   PROP_INTERFACE,
01327   PROP_CONNECTION
01328 };
01329 
01330 enum
01331 {
01332   DESTROY,
01333   RECEIVED,
01334   LAST_SIGNAL
01335 };
01336 
01337 static void *parent_class;
01338 static guint signals[LAST_SIGNAL] = { 0 };
01339 
01340 static void
01341 dbus_g_proxy_init (DBusGProxy *proxy)
01342 {
01343   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01344   
01345   g_datalist_init (&priv->signal_signatures);
01346   priv->pending_calls = g_hash_table_new_full (NULL, NULL, NULL,
01347                                 (GDestroyNotify) dbus_pending_call_unref);
01348   priv->name_call = 0;
01349   priv->associated = FALSE;
01350   priv->default_timeout = -1;
01351 }
01352 
01353 static GObject *
01354 dbus_g_proxy_constructor (GType                  type,
01355                           guint                  n_construct_properties,
01356                           GObjectConstructParam *construct_properties)
01357 {
01358   DBusGProxy *proxy;
01359   DBusGProxyClass *klass;
01360   GObjectClass *parent_class;
01361   DBusGProxyPrivate *priv;
01362 
01363   klass = DBUS_G_PROXY_CLASS (g_type_class_peek (DBUS_TYPE_G_PROXY));
01364 
01365   parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
01366 
01367   proxy = DBUS_G_PROXY (parent_class->constructor (type, n_construct_properties,
01368                                                     construct_properties));
01369 
01370   priv = DBUS_G_PROXY_GET_PRIVATE (proxy);
01371 
01372   /* if these assertions fail, a deriving class has not set our required
01373    * parameters - our own public constructors do return_if_fail checks
01374    * on these parameters being provided. unfortunately we can't assert
01375    * for manager because it's allowed to be NULL when tha mangager is
01376    * setting up a bus proxy for its own calls */
01377   g_assert (priv->path != NULL);
01378   g_assert (priv->interface != NULL);
01379 
01380   if (priv->manager != NULL)
01381     {
01382       dbus_g_proxy_manager_register (priv->manager, proxy);
01383     }
01384 
01385   return G_OBJECT (proxy);
01386 }
01387 
01388 static void
01389 dbus_g_proxy_class_init (DBusGProxyClass *klass)
01390 {
01391   GObjectClass *object_class = G_OBJECT_CLASS (klass);
01392   
01393   parent_class = g_type_class_peek_parent (klass);
01394 
01395   g_type_class_add_private (klass, sizeof (DBusGProxyPrivate));
01396 
01397   object_class->set_property = dbus_g_proxy_set_property;
01398   object_class->get_property = dbus_g_proxy_get_property;
01399 
01400   g_object_class_install_property (object_class,
01401                                    PROP_NAME,
01402                                    g_param_spec_string ("name",
01403                                                         "name",
01404                                                         "name",
01405                                                         NULL,
01406                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01407 
01408   g_object_class_install_property (object_class,
01409                                    PROP_PATH,
01410                                    g_param_spec_string ("path",
01411                                                         "path",
01412                                                         "path",
01413                                                         NULL,
01414                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01415 
01416   g_object_class_install_property (object_class,
01417                                    PROP_INTERFACE,
01418                                    g_param_spec_string ("interface",
01419                                                         "interface",
01420                                                         "interface",
01421                                                         NULL,
01422                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01423   
01424   g_object_class_install_property (object_class,
01425                                    PROP_CONNECTION,
01426                                    g_param_spec_boxed ("connection",
01427                                                         "connection",
01428                                                         "connection",
01429                                                         DBUS_TYPE_G_CONNECTION,
01430                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01431   
01432   object_class->finalize = dbus_g_proxy_finalize;
01433   object_class->dispose = dbus_g_proxy_dispose;
01434   object_class->constructor = dbus_g_proxy_constructor;
01435   
01436   signals[DESTROY] =
01437     g_signal_new ("destroy",
01438                   G_OBJECT_CLASS_TYPE (object_class),
01439                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
01440                   0,
01441                   NULL, NULL,
01442                   g_cclosure_marshal_VOID__VOID,
01443                   G_TYPE_NONE, 0);
01444 
01445   signals[RECEIVED] =
01446     g_signal_new ("received",
01447                   G_OBJECT_CLASS_TYPE (object_class),
01448                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
01449                   0,
01450                   NULL, NULL,
01451                   marshal_dbus_message_to_g_marshaller,
01452                   G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
01453 }
01454 
01455 static gboolean
01456 cancel_pending_call (gpointer key, gpointer val, gpointer data)
01457 {
01458   DBusPendingCall *pending = val;
01459 
01460   dbus_pending_call_cancel (pending);
01461 
01462   return TRUE;
01463 }
01464 
01465 static void
01466 dbus_g_proxy_dispose (GObject *object)
01467 {
01468   DBusGProxy *proxy = DBUS_G_PROXY (object);
01469   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01470 
01471   if (priv->pending_calls == NULL) 
01472     {
01473       return;
01474     }
01475 
01476   /* Cancel outgoing pending calls */
01477   g_hash_table_foreach_remove (priv->pending_calls, cancel_pending_call, NULL);
01478   g_hash_table_destroy (priv->pending_calls);
01479   priv->pending_calls = NULL;
01480 
01481   if (priv->manager && proxy != priv->manager->bus_proxy)
01482     {
01483       dbus_g_proxy_manager_unregister (priv->manager, proxy);
01484       dbus_g_proxy_manager_unref (priv->manager);
01485     }
01486   priv->manager = NULL;
01487   
01488   g_datalist_clear (&priv->signal_signatures);
01489   
01490   g_signal_emit (object, signals[DESTROY], 0);
01491   
01492   G_OBJECT_CLASS (parent_class)->dispose (object);
01493 }
01494 
01495 static void
01496 dbus_g_proxy_finalize (GObject *object)
01497 {
01498   DBusGProxy *proxy = DBUS_G_PROXY (object);
01499   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01500   
01501   g_return_if_fail (DBUS_G_PROXY_DESTROYED (proxy));
01502   
01503   g_free (priv->name);
01504   g_free (priv->path);
01505   g_free (priv->interface);
01506   
01507   G_OBJECT_CLASS (parent_class)->finalize (object);
01508 }
01509 
01510 static void
01511 dbus_g_proxy_destroy (DBusGProxy *proxy)
01512 {
01513   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
01514    * from GtkObject?
01515    */
01516   g_object_run_dispose (G_OBJECT (proxy));
01517 }
01518 
01519 static void
01520 dbus_g_proxy_set_property (GObject *object,
01521                            guint prop_id,
01522                            const GValue *value,
01523                            GParamSpec *pspec)
01524 {
01525   DBusGProxy *proxy = DBUS_G_PROXY (object);
01526   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01527   DBusGConnection *connection;
01528 
01529   switch (prop_id)
01530     {
01531     case PROP_NAME:
01532       priv->name = g_strdup (g_value_get_string (value));
01533       if (priv->name)
01534         priv->for_owner = (priv->name[0] == ':');
01535       else
01536         priv->for_owner = TRUE;
01537       break;
01538     case PROP_PATH:
01539       priv->path = g_strdup (g_value_get_string (value));
01540       break;
01541     case PROP_INTERFACE:
01542       priv->interface = g_strdup (g_value_get_string (value));
01543       break;
01544     case PROP_CONNECTION:
01545       connection = g_value_get_boxed (value);
01546       if (connection != NULL)
01547         {
01548           priv->manager = dbus_g_proxy_manager_get (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
01549         }
01550       break;
01551     default:
01552       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01553       break;
01554     }
01555 }
01556 
01557 static void 
01558 dbus_g_proxy_get_property (GObject *object,
01559                            guint prop_id,
01560                            GValue *value,
01561                            GParamSpec *pspec)
01562 {
01563   DBusGProxy *proxy = DBUS_G_PROXY (object);
01564   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01565 
01566   switch (prop_id)
01567     {
01568     case PROP_NAME:
01569       g_value_set_string (value, priv->name);
01570       break;
01571     case PROP_PATH:
01572       g_value_set_string (value, priv->path);
01573       break;
01574     case PROP_INTERFACE:
01575       g_value_set_string (value, priv->interface);
01576       break;
01577     case PROP_CONNECTION:
01578       g_value_set_boxed (value, DBUS_G_CONNECTION_FROM_CONNECTION(priv->manager->connection));
01579       break;
01580     default:
01581       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01582       break;
01583     }
01584 }
01585 
01586 /* this is to avoid people using g_signal_connect() directly,
01587  * to avoid confusion with local signal names, and because
01588  * of the horribly broken current setup (signals are added
01589  * globally to all proxies)
01590  */
01591 static char*
01592 create_signal_name (const char *interface,
01593                     const char *signal)
01594 {
01595   GString *str;
01596   char *p;
01597 
01598   str = g_string_new (interface);
01599 
01600   g_string_append (str, "-");
01601   
01602   g_string_append (str, signal);
01603 
01604   /* GLib will silently barf on '.' in signal names */
01605   p = str->str;
01606   while (*p)
01607     {
01608       if (*p == '.')
01609         *p = '-';
01610       ++p;
01611     }
01612   
01613   return g_string_free (str, FALSE);
01614 }
01615 
01616 static void
01617 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
01618                                       GValue       *return_value,
01619                                       guint         n_param_values,
01620                                       const GValue *param_values,
01621                                       gpointer      invocation_hint,
01622                                       gpointer      marshal_data)
01623 {
01624   /* Incoming here we have three params, the instance (Proxy), the
01625    * DBusMessage, the signature. We want to convert that to an
01626    * expanded GValue array, then call an appropriate normal GLib
01627    * marshaller.
01628    */
01629 #define MAX_SIGNATURE_ARGS 20
01630   GValueArray *value_array;
01631   GSignalCMarshaller c_marshaller;
01632   DBusGProxy *proxy;
01633   DBusMessage *message;
01634   GArray *gsignature;
01635   const GType *types;
01636   DBusGProxyPrivate *priv;
01637 
01638   g_assert (n_param_values == 3);
01639 
01640   proxy = g_value_get_object (&param_values[0]);
01641   message = g_value_get_boxed (&param_values[1]);
01642   gsignature = g_value_get_pointer (&param_values[2]);
01643 
01644   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
01645   g_return_if_fail (message != NULL);
01646   g_return_if_fail (gsignature != NULL);
01647 
01648   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01649 
01650   c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
01651                                                   (GType*) gsignature->data);
01652 
01653   g_return_if_fail (c_marshaller != NULL);
01654   
01655   {
01656     DBusGValueMarshalCtx context;
01657     context.recursion_depth = 0;
01658     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
01659     context.proxy = proxy;
01660 
01661     types = (const GType*) gsignature->data;
01662     value_array = _dbus_gvalue_demarshal_message (&context, message,
01663                                                  gsignature->len, types, NULL);
01664   }
01665 
01666   if (value_array == NULL)
01667     return;
01668   
01669   g_value_array_prepend (value_array, NULL);
01670   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_FROM_INSTANCE (proxy));
01671   g_value_set_instance (g_value_array_get_nth (value_array, 0), proxy);
01672 
01673   (* c_marshaller) (closure, return_value, value_array->n_values,
01674                     value_array->values, invocation_hint, marshal_data);
01675   
01676   g_value_array_free (value_array);
01677 }
01678 
01679 static void
01680 dbus_g_proxy_emit_remote_signal (DBusGProxy  *proxy,
01681                                  DBusMessage *message)
01682 {
01683   const char *interface;
01684   const char *signal;
01685   char *name;
01686   GQuark q;
01687   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01688   GArray *msg_gsignature = NULL;
01689 
01690   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
01691 
01692   interface = dbus_message_get_interface (message);
01693   signal = dbus_message_get_member (message);
01694 
01695   g_assert (interface != NULL);
01696   g_assert (signal != NULL);
01697 
01698   name = create_signal_name (interface, signal);
01699 
01700   /* If the quark isn't preexisting, there's no way there
01701    * are any handlers connected. We don't want to create
01702    * extra quarks for every possible signal.
01703    */
01704   q = g_quark_try_string (name);
01705 
01706   if (q != 0)
01707     {
01708       GArray *gsignature;
01709       guint i;
01710       
01711       gsignature = g_datalist_id_get_data (&priv->signal_signatures, q);
01712       if (gsignature == NULL)
01713         goto out;
01714       
01715       msg_gsignature = _dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
01716                                                        TRUE);
01717       for (i = 0; i < gsignature->len; i++)
01718         {
01719           if (msg_gsignature->len == i
01720               || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
01721             goto mismatch;
01722         }
01723       if (msg_gsignature->len != i)
01724         goto mismatch;
01725       
01726       g_signal_emit (proxy,
01727                      signals[RECEIVED],
01728                      q,
01729                      message,
01730                      msg_gsignature);
01731     }
01732 
01733  out:
01734   g_free (name);
01735   if (msg_gsignature)
01736     g_array_free (msg_gsignature, TRUE);
01737   return;
01738  mismatch:
01739 #if 0
01740   /* Don't spew on remote errors */
01741   g_warning ("Unexpected message signature '%s' for signal '%s'\n",
01742              dbus_message_get_signature (message),
01743              name);
01744 #endif
01745   goto out;
01746 }
01747 
01748 typedef struct
01749 {
01750   DBusGProxy *proxy;
01751   guint call_id;
01752   DBusGProxyCallNotify func;
01753   void *data;
01754   GDestroyNotify free_data_func;
01755 } GPendingNotifyClosure;
01756 
01757 static void
01758 d_pending_call_notify (DBusPendingCall *dcall,
01759                        void            *data)
01760 {
01761   GPendingNotifyClosure *closure = data;
01762 
01763   (* closure->func) (closure->proxy, DBUS_G_PROXY_ID_TO_CALL (closure->call_id), closure->data);
01764 }
01765 
01766 static void
01767 d_pending_call_free (void *data)
01768 {
01769   GPendingNotifyClosure *closure = data;
01770   
01771   if (closure->free_data_func)
01772     (* closure->free_data_func) (closure->data);
01773 
01774   g_free (closure);
01775 }
01776   
01777 #define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
01778 do { \
01779   GType valtype; \
01780   int i = 0; \
01781   VALARRAY = g_value_array_new (6); \
01782   valtype = FIRST_ARG_TYPE; \
01783   while (valtype != G_TYPE_INVALID) \
01784     { \
01785       const char *collect_err; \
01786       GValue *val; \
01787       g_value_array_append (VALARRAY, NULL); \
01788       val = g_value_array_get_nth (VALARRAY, i); \
01789       g_value_init (val, valtype); \
01790       collect_err = NULL; \
01791       G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
01792       valtype = va_arg (ARGS, GType); \
01793       i++; \
01794     } \
01795 } while (0)
01796 
01797 DBusGProxyCall *
01798 manager_begin_bus_call (DBusGProxyManager    *manager,
01799                         const char           *method,
01800                         DBusGProxyCallNotify  notify,
01801                         gpointer              user_data,
01802                         GDestroyNotify        destroy,
01803                         GType                 first_arg_type,
01804                         ...)
01805 {
01806   DBusGProxyCall *call;
01807   DBusGProxyPrivate *priv;
01808   va_list args;
01809   GValueArray *arg_values;
01810   
01811   va_start (args, first_arg_type);
01812 
01813   if (!manager->bus_proxy)
01814     {
01815       manager->bus_proxy = g_object_new (DBUS_TYPE_G_PROXY,
01816                                          "name", DBUS_SERVICE_DBUS,
01817                                          "path", DBUS_PATH_DBUS,
01818                                          "interface", DBUS_INTERFACE_DBUS,
01819                                          NULL);
01820       priv = DBUS_G_PROXY_GET_PRIVATE(manager->bus_proxy);
01821       priv->manager = manager;
01822     }
01823 
01824   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
01825   
01826   call = DBUS_G_PROXY_ID_TO_CALL (dbus_g_proxy_begin_call_internal (manager->bus_proxy, method, notify, user_data, destroy, arg_values,-1));
01827 
01828   g_value_array_free (arg_values);
01829 
01830   va_end (args);
01831 
01832   return call;
01833 }
01834 
01856 GType
01857 dbus_g_proxy_get_type (void)
01858 {
01859   static GType object_type = 0;
01860 
01861   if (!object_type)
01862     {
01863       static const GTypeInfo object_info =
01864         {
01865           sizeof (DBusGProxyClass),
01866           (GBaseInitFunc) NULL,
01867           (GBaseFinalizeFunc) NULL,
01868           (GClassInitFunc) dbus_g_proxy_class_init,
01869           NULL,           /* class_finalize */
01870           NULL,           /* class_data */
01871           sizeof (DBusGProxy),
01872           0,              /* n_preallocs */
01873           (GInstanceInitFunc) dbus_g_proxy_init,
01874         };
01875       
01876       object_type = g_type_register_static (G_TYPE_OBJECT,
01877                                             "DBusGProxy",
01878                                             &object_info, 0);
01879     }
01880   
01881   return object_type;
01882 }
01883 
01884 static DBusGProxy*
01885 dbus_g_proxy_new (DBusGConnection *connection,
01886                   const char      *name,
01887                   const char      *path_name,
01888                   const char      *interface_name)
01889 {
01890   DBusGProxy *proxy;
01891 
01892   g_assert (connection != NULL);
01893   
01894   proxy = g_object_new (DBUS_TYPE_G_PROXY, 
01895                         "name", name, 
01896                         "path", path_name, 
01897                         "interface", interface_name, 
01898                         "connection", connection, NULL);
01899 
01900   return proxy;
01901 }
01902 
01931 DBusGProxy*
01932 dbus_g_proxy_new_for_name (DBusGConnection *connection,
01933                            const char      *name,
01934                            const char      *path_name,
01935                            const char      *interface_name)
01936 {
01937   g_return_val_if_fail (connection != NULL, NULL);
01938   g_return_val_if_fail (name != NULL, NULL);
01939   g_return_val_if_fail (path_name != NULL, NULL);
01940   g_return_val_if_fail (interface_name != NULL, NULL);
01941 
01942   return dbus_g_proxy_new (connection, name,
01943                            path_name, interface_name);
01944 }
01945 
01971 DBusGProxy*
01972 dbus_g_proxy_new_for_name_owner (DBusGConnection          *connection,
01973                                  const char               *name,
01974                                  const char               *path_name,
01975                                  const char               *interface_name,
01976                                  GError                  **error)
01977 {
01978   DBusGProxy *proxy;
01979   char *unique_name;
01980 
01981   g_return_val_if_fail (connection != NULL, NULL);
01982   g_return_val_if_fail (name != NULL, NULL);
01983   g_return_val_if_fail (path_name != NULL, NULL);
01984   g_return_val_if_fail (interface_name != NULL, NULL);
01985 
01986   if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
01987     return NULL;
01988 
01989   proxy = dbus_g_proxy_new (connection, unique_name,
01990                             path_name, interface_name);
01991   g_free (unique_name);
01992   return proxy;
01993 }
01994 
02006 DBusGProxy*
02007 dbus_g_proxy_new_from_proxy (DBusGProxy        *proxy,
02008                              const char        *interface,
02009                              const char        *path)
02010 {
02011   DBusGProxyPrivate *priv;
02012 
02013   g_return_val_if_fail (proxy != NULL, NULL);
02014 
02015   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02016   
02017   if (interface == NULL)
02018     interface = priv->interface;
02019   if (path == NULL)
02020     path = priv->path;
02021 
02022   return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection),
02023                            priv->name,
02024                            path, interface);
02025 }
02026 
02041 DBusGProxy*
02042 dbus_g_proxy_new_for_peer (DBusGConnection          *connection,
02043                            const char               *path_name,
02044                            const char               *interface_name)
02045 {
02046   DBusGProxy *proxy;
02047   
02048   g_return_val_if_fail (connection != NULL, NULL);
02049   g_return_val_if_fail (path_name != NULL, NULL);
02050   g_return_val_if_fail (interface_name != NULL, NULL);
02051 
02052   proxy = dbus_g_proxy_new (connection, NULL,
02053                             path_name, interface_name);
02054 
02055   return proxy;
02056 }
02057 
02071 const char*
02072 dbus_g_proxy_get_bus_name (DBusGProxy        *proxy)
02073 {
02074   DBusGProxyPrivate *priv;
02075 
02076   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02077   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02078 
02079   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02080 
02081   return priv->name;
02082 }
02083 
02092 const char*
02093 dbus_g_proxy_get_interface (DBusGProxy        *proxy)
02094 {
02095   DBusGProxyPrivate *priv;
02096   
02097   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02098   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02099 
02100   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02101 
02102   return priv->interface;
02103 }
02104 
02112 void
02113 dbus_g_proxy_set_interface (DBusGProxy        *proxy,
02114                             const char        *interface_name)
02115 {
02116   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02117   /* FIXME - need to unregister when we switch interface for now
02118    * later should support idea of unset interface
02119    */
02120   dbus_g_proxy_manager_unregister (priv->manager, proxy);
02121   g_free (priv->interface);
02122   priv->interface = g_strdup (interface_name);
02123   dbus_g_proxy_manager_register (priv->manager, proxy);
02124 }
02125 
02133 const char*
02134 dbus_g_proxy_get_path (DBusGProxy        *proxy)
02135 {
02136   DBusGProxyPrivate *priv;
02137   
02138   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02139   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02140 
02141   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02142 
02143   return priv->path;
02144 }
02145 
02146 static DBusMessage *
02147 dbus_g_proxy_marshal_args_to_message (DBusGProxy  *proxy,
02148                                       const char  *method,
02149                                       GValueArray *args)
02150 {
02151   DBusMessage *message;
02152   DBusMessageIter msgiter;
02153   guint i;
02154   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02155 
02156   message = dbus_message_new_method_call (priv->name,
02157                                           priv->path,
02158                                           priv->interface,
02159                                           method);
02160   if (message == NULL)
02161     goto oom;
02162 
02163   dbus_message_iter_init_append (message, &msgiter);
02164   for (i = 0; i < args->n_values; i++)
02165     {
02166       GValue *gvalue;
02167 
02168       gvalue = g_value_array_get_nth (args, i);
02169 
02170       if (!_dbus_gvalue_marshal (&msgiter, gvalue))
02171         g_assert_not_reached ();
02172     }
02173   return message;
02174  oom:
02175   return NULL;
02176 }
02177 
02178 static guint
02179 dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
02180                                   const char          *method,
02181                                   DBusGProxyCallNotify notify,
02182                                   gpointer             user_data,
02183                                   GDestroyNotify       destroy,
02184                                   GValueArray         *args,
02185                                   int timeout)
02186 {
02187   DBusMessage *message;
02188   DBusPendingCall *pending;
02189   GPendingNotifyClosure *closure;
02190   guint call_id;
02191   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02192 
02193   pending = NULL;
02194 
02195   message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
02196   if (!message)
02197     goto oom;
02198 
02199   if (!dbus_connection_send_with_reply (priv->manager->connection,
02200                                         message,
02201                                         &pending,
02202                                         timeout))
02203     goto oom;
02204   dbus_message_unref (message);
02205   
02206   /* If we got a NULL pending, that means the connection was disconnected,
02207    * and we need to abort this call.  
02208    * https://bugs.freedesktop.org/show_bug.cgi?id=12675
02209    */
02210   if (pending == NULL)
02211     return 0;
02212 
02213   call_id = ++priv->call_id_counter;
02214 
02215   if (notify != NULL)
02216     {
02217       closure = g_new (GPendingNotifyClosure, 1);
02218       closure->proxy = proxy; /* No need to ref as the lifecycle is tied to proxy */
02219       closure->call_id = call_id;
02220       closure->func = notify;
02221       closure->data = user_data;
02222       closure->free_data_func = destroy;
02223       dbus_pending_call_set_notify (pending, d_pending_call_notify,
02224                                     closure,
02225                                     d_pending_call_free);
02226     }
02227 
02228   g_hash_table_insert (priv->pending_calls, GUINT_TO_POINTER (call_id), pending);
02229 
02230   return call_id;
02231  oom:
02232   g_error ("Out of memory");
02233   return 0;
02234 }
02235 
02236 static gboolean
02237 dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
02238                                 guint              call_id,
02239                                 GError           **error,
02240                                 GType              first_arg_type,
02241                                 va_list            args)
02242 {
02243   DBusMessage *reply;
02244   DBusMessageIter msgiter;
02245   DBusError derror;
02246   va_list args_unwind;
02247   guint over;
02248   int n_retvals_processed;
02249   gboolean ret;
02250   GType valtype;
02251   DBusPendingCall *pending;
02252   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02253 
02254   reply = NULL;
02255   ret = FALSE;
02256   n_retvals_processed = 0;
02257   over = 0;
02258 
02259   /* Keep around a copy of output arguments so we can free on error. */
02260   G_VA_COPY(args_unwind, args);
02261 
02262   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
02263   
02264   dbus_pending_call_block (pending);
02265   reply = dbus_pending_call_steal_reply (pending);
02266 
02267   g_assert (reply != NULL);
02268 
02269   dbus_error_init (&derror);
02270 
02271   switch (dbus_message_get_type (reply))
02272     {
02273     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
02274       dbus_message_iter_init (reply, &msgiter);
02275       valtype = first_arg_type;
02276       while (valtype != G_TYPE_INVALID)
02277         {
02278           int arg_type;
02279           gpointer return_storage;
02280           GValue gvalue = { 0, };
02281           DBusGValueMarshalCtx context;
02282 
02283           context.recursion_depth = 0;
02284           context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
02285           context.proxy = proxy;
02286 
02287           arg_type = dbus_message_iter_get_arg_type (&msgiter);
02288           if (arg_type == DBUS_TYPE_INVALID)
02289             {
02290               g_set_error (error, DBUS_GERROR,
02291                            DBUS_GERROR_INVALID_ARGS,
02292                            _("Too few arguments in reply"));
02293               goto out;
02294             }
02295 
02296           return_storage = va_arg (args, gpointer);
02297           if (return_storage == NULL)
02298             goto next;
02299 
02300           /* We handle variants specially; the caller is expected
02301            * to have already allocated storage for them.
02302            */
02303           if (arg_type == DBUS_TYPE_VARIANT
02304               && g_type_is_a (valtype, G_TYPE_VALUE))
02305             {
02306               if (!_dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
02307                 {
02308                   g_set_error (error,
02309                                DBUS_GERROR,
02310                                DBUS_GERROR_INVALID_ARGS,
02311                                _("Couldn't convert argument, expected \"%s\""),
02312                                g_type_name (valtype));
02313                   goto out;
02314                 }
02315             }
02316           else
02317             {
02318               g_value_init (&gvalue, valtype);
02319 
02320               if (!_dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error))
02321                 goto out;
02322 
02323               /* Anything that can be demarshaled must be storable */
02324               if (!_dbus_gvalue_store (&gvalue, return_storage))
02325                 g_assert_not_reached ();
02326               /* Ownership of the value passes to the client, don't unset */
02327             }
02328           
02329         next:
02330           n_retvals_processed++;
02331           dbus_message_iter_next (&msgiter);
02332           valtype = va_arg (args, GType);
02333         }
02334       
02335       while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
02336         {
02337           over++;
02338           dbus_message_iter_next (&msgiter);
02339         }
02340 
02341       if (over > 0)
02342         {
02343           g_set_error (error, DBUS_GERROR,
02344                        DBUS_GERROR_INVALID_ARGS,
02345                        _("Too many arguments in reply; expected %d, got %d"),
02346                        n_retvals_processed, over);
02347           goto out;
02348         }
02349       break;
02350     case DBUS_MESSAGE_TYPE_ERROR:
02351       dbus_set_error_from_message (&derror, reply);
02352       dbus_set_g_error (error, &derror);
02353       dbus_error_free (&derror);
02354       goto out;
02355       break;
02356     default:
02357       dbus_set_error (&derror, DBUS_ERROR_FAILED,
02358                       "Reply was neither a method return nor an exception");
02359       dbus_set_g_error (error, &derror);
02360       dbus_error_free (&derror);
02361       goto out;
02362       break;
02363     }
02364 
02365   ret = TRUE;
02366  out:
02367   if (ret == FALSE)
02368     {
02369       int i;
02370 
02371       valtype = first_arg_type;
02372       for (i = 0; i < n_retvals_processed; i++)
02373         {
02374           GValue value = {0,};
02375           gpointer retval;
02376 
02377           g_value_init (&value, valtype);
02378 
02379           retval = va_arg (args_unwind, gpointer);
02380           if (retval == NULL)
02381             {
02382               i--;
02383               continue;
02384             }
02385             
02386           _dbus_gvalue_take (&value, retval);
02387           g_value_unset (&value);
02388 
02389           valtype = va_arg (args_unwind, GType);
02390         }
02391     }
02392   va_end (args_unwind);
02393   va_end (args);
02394 
02395   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
02396 
02397   if (reply)
02398     dbus_message_unref (reply);
02399   return ret;
02400 }
02401 
02424 DBusGProxyCall *
02425 dbus_g_proxy_begin_call (DBusGProxy          *proxy,
02426                          const char          *method,
02427                          DBusGProxyCallNotify notify,
02428                          gpointer             user_data,
02429                          GDestroyNotify       destroy,
02430                          GType                first_arg_type,
02431                          ...)
02432 {
02433   guint call_id;
02434   va_list args;
02435   GValueArray *arg_values;
02436   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02437   
02438   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02439   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02440 
02441   va_start (args, first_arg_type);
02442 
02443   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
02444   
02445   call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values, priv->default_timeout);
02446 
02447   g_value_array_free (arg_values);
02448 
02449   va_end (args);
02450 
02451   return DBUS_G_PROXY_ID_TO_CALL (call_id);
02452 }
02453 
02477 DBusGProxyCall *
02478 dbus_g_proxy_begin_call_with_timeout (DBusGProxy          *proxy,
02479                          const char          *method,
02480                          DBusGProxyCallNotify notify,
02481                          gpointer             user_data,
02482                          GDestroyNotify       destroy,
02483                          int timeout,
02484                          GType                first_arg_type,
02485                          ...)
02486 {
02487   guint call_id;
02488   va_list args;
02489   GValueArray *arg_values;
02490 
02491   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02492   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02493 
02494   va_start (args, first_arg_type);
02495 
02496   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
02497 
02498   call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values,timeout);
02499 
02500   g_value_array_free (arg_values);
02501 
02502   va_end (args);
02503 
02504   return DBUS_G_PROXY_ID_TO_CALL (call_id);
02505 }
02506 
02529 gboolean
02530 dbus_g_proxy_end_call (DBusGProxy          *proxy,
02531                        DBusGProxyCall      *call,
02532                        GError             **error,
02533                        GType                first_arg_type,
02534                        ...)
02535 {
02536   gboolean ret;
02537   va_list args;
02538 
02539   va_start (args, first_arg_type);
02540 
02541   ret = dbus_g_proxy_end_call_internal (proxy, GPOINTER_TO_UINT (call), error, first_arg_type, args);
02542 
02543   va_end (args);
02544   
02545   return ret;
02546 }
02547 
02564 gboolean
02565 dbus_g_proxy_call (DBusGProxy        *proxy,
02566                    const char        *method,
02567                    GError           **error,
02568                    GType              first_arg_type,
02569                    ...)
02570 {
02571   gboolean ret;
02572   guint call_id;
02573   va_list args;
02574   GValueArray *in_args;
02575   DBusGProxyPrivate *priv;
02576 
02577   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02578   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02579 
02580   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02581 
02582   va_start (args, first_arg_type);
02583 
02584   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02585 
02586   call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args, priv->default_timeout);
02587 
02588   g_value_array_free (in_args);
02589 
02590   if (call_id > 0)
02591     {
02592       first_arg_type = va_arg (args, GType);
02593       ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
02594     }
02595   else
02596     {
02597       g_set_error (error, DBUS_GERROR,
02598                    DBUS_GERROR_FAILED,
02599                    _("Disconnection or out-of-memory"));
02600       ret = FALSE;
02601     }
02602 
02603   va_end (args);
02604 
02605   return ret;
02606 }
02607 
02625 gboolean
02626 dbus_g_proxy_call_with_timeout (DBusGProxy        *proxy,
02627                    const char        *method,
02628                    int timeout,
02629                    GError           **error,
02630                    GType              first_arg_type,
02631                    ...)
02632 {
02633   gboolean ret;
02634   guint call_id;
02635   va_list args;
02636   GValueArray *in_args;
02637 
02638   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02639   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02640 
02641   va_start (args, first_arg_type);
02642 
02643   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02644 
02645   call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args,timeout);
02646 
02647   g_value_array_free (in_args);
02648 
02649   first_arg_type = va_arg (args, GType);
02650   ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
02651 
02652   va_end (args);
02653 
02654   return ret;
02655 }
02656 
02669 void
02670 dbus_g_proxy_call_no_reply (DBusGProxy               *proxy,
02671                             const char               *method,
02672                             GType                     first_arg_type,
02673                             ...)
02674 {
02675   DBusMessage *message;
02676   va_list args;
02677   GValueArray *in_args;
02678   DBusGProxyPrivate *priv;
02679   
02680   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02681   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02682 
02683   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02684 
02685   va_start (args, first_arg_type);
02686   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02687 
02688   message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
02689 
02690   g_value_array_free (in_args);
02691   va_end (args);
02692 
02693   if (!message)
02694     goto oom;
02695 
02696   dbus_message_set_no_reply (message, TRUE);
02697 
02698   if (!dbus_connection_send (priv->manager->connection,
02699                              message,
02700                              NULL))
02701     goto oom;
02702   dbus_message_unref (message);
02703   return;
02704   
02705  oom:
02706   g_error ("Out of memory");
02707 }
02708 
02719 void
02720 dbus_g_proxy_cancel_call (DBusGProxy        *proxy,
02721                           DBusGProxyCall    *call)
02722 {
02723   guint call_id;
02724   DBusPendingCall *pending;
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   call_id = DBUS_G_PROXY_CALL_TO_ID (call);
02733 
02734   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
02735   g_return_if_fail (pending != NULL);
02736 
02737   dbus_pending_call_cancel (pending);
02738 
02739   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
02740 }
02741 
02762 void
02763 dbus_g_proxy_send (DBusGProxy          *proxy,
02764                    DBusMessage         *message,
02765                    dbus_uint32_t       *client_serial)
02766 {
02767   DBusGProxyPrivate *priv;
02768   
02769   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02770   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02771   
02772   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02773   
02774   if (priv->name)
02775     {
02776       if (!dbus_message_set_destination (message, priv->name))
02777         g_error ("Out of memory");
02778     }
02779   if (priv->path)
02780     {
02781       if (!dbus_message_set_path (message, priv->path))
02782         g_error ("Out of memory");
02783     }
02784   if (priv->interface)
02785     {
02786       if (!dbus_message_set_interface (message, priv->interface))
02787         g_error ("Out of memory");
02788     }
02789   
02790   if (!dbus_connection_send (priv->manager->connection, message, client_serial))
02791     g_error ("Out of memory\n");
02792 }
02793 
02794 static void
02795 array_free_all (gpointer array)
02796 {
02797   g_array_free (array, TRUE);
02798 }
02799 
02810 void
02811 dbus_g_proxy_add_signal  (DBusGProxy        *proxy,
02812                           const char        *signal_name,
02813                           GType              first_type,
02814                           ...)
02815 {
02816   GQuark q;
02817   char *name;
02818   GArray *gtypesig;
02819   GType gtype;
02820   va_list args;
02821   DBusGProxyPrivate *priv;
02822 
02823   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02824   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02825   g_return_if_fail (signal_name != NULL);
02826   
02827   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02828 
02829   name = create_signal_name (priv->interface, signal_name);
02830   
02831   q = g_quark_from_string (name);
02832   
02833   g_return_if_fail (g_datalist_id_get_data (&priv->signal_signatures, q) == NULL);
02834 
02835   gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
02836 
02837   va_start (args, first_type);
02838   gtype = first_type;
02839   while (gtype != G_TYPE_INVALID)
02840     {
02841       g_array_append_val (gtypesig, gtype);
02842       gtype = va_arg (args, GType);
02843     }
02844   va_end (args);
02845 
02846 #ifndef G_DISABLE_CHECKS
02847   if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
02848     g_warning ("No marshaller for signature of signal '%s'", signal_name);
02849 #endif
02850 
02851   
02852   g_datalist_id_set_data_full (&priv->signal_signatures,
02853                                q, gtypesig,
02854                                array_free_all);
02855 
02856   g_free (name);
02857 }
02858 
02871 void
02872 dbus_g_proxy_connect_signal (DBusGProxy             *proxy,
02873                              const char             *signal_name,
02874                              GCallback               handler,
02875                              void                   *data,
02876                              GClosureNotify          free_data_func)
02877 {
02878   char *name;
02879   GClosure *closure;
02880   GQuark q;
02881   DBusGProxyPrivate *priv;
02882 
02883   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02884   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02885   g_return_if_fail (signal_name != NULL);
02886   g_return_if_fail (handler != NULL);
02887   
02888   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02889   name = create_signal_name (priv->interface, signal_name);
02890 
02891   q = g_quark_try_string (name);
02892 
02893 #ifndef G_DISABLE_CHECKS
02894   if (q == 0 || g_datalist_id_get_data (&priv->signal_signatures, q) == NULL)
02895     {
02896       g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
02897       g_free (name);
02898       return;
02899     }
02900 #endif
02901   
02902   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
02903   
02904   g_signal_connect_closure_by_id (G_OBJECT (proxy),
02905                                   signals[RECEIVED],
02906                                   q,
02907                                   closure, FALSE);
02908   
02909   g_free (name);
02910 }
02911 
02922 void
02923 dbus_g_proxy_disconnect_signal (DBusGProxy             *proxy,
02924                                 const char             *signal_name,
02925                                 GCallback               handler,
02926                                 void                   *data)
02927 {
02928   char *name;
02929   GQuark q;
02930   DBusGProxyPrivate *priv;
02931   
02932   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02933   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02934   g_return_if_fail (signal_name != NULL);
02935   g_return_if_fail (handler != NULL);
02936 
02937   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02938   name = create_signal_name (priv->interface, signal_name);
02939 
02940   q = g_quark_try_string (name);
02941   
02942   if (q != 0)
02943     {
02944       g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
02945                                             G_SIGNAL_MATCH_DETAIL |
02946                                             G_SIGNAL_MATCH_FUNC   |
02947                                             G_SIGNAL_MATCH_DATA,
02948                                             signals[RECEIVED],
02949                                             q,
02950                                             NULL,
02951                                             G_CALLBACK (handler), data);
02952     }
02953   else
02954     {
02955       g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
02956                  name);
02957     }
02958 
02959   g_free (name);
02960 }
02961 
02979 void
02980 dbus_g_proxy_set_default_timeout (DBusGProxy        *proxy,
02981                                   int                timeout)
02982 {
02983   DBusGProxyPrivate *priv;
02984 
02985   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02986   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02987 
02988   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02989   priv->default_timeout = timeout;
02990 }
02991 
02992 
02995 #ifdef DBUS_BUILD_TESTS
02996 
03002 gboolean
03003 _dbus_g_proxy_test (void)
03004 {
03005   
03006   
03007   return TRUE;
03008 }
03009 
03010 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Feb 24 16:47:59 2009 for D-BUSGLibBindings by  doxygen 1.5.1