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   return strcmp (info->name, name);
00498 }
00499 
00500 typedef struct
00501 {
00502   const char *name;
00503   const char *owner;
00504   DBusGProxyNameOwnerInfo *info;
00505 } DBusGProxyNameOwnerForeachData;
00506 
00507 static void
00508 name_owner_foreach (gpointer key, gpointer val, gpointer data)
00509 {
00510   const char *owner;
00511   DBusGProxyNameOwnerForeachData *foreach_data;
00512   GSList *names;
00513   GSList *link;
00514 
00515   owner = key;
00516   names = val;
00517   foreach_data = data;
00518 
00519   if (foreach_data->owner != NULL)
00520     return;
00521 
00522   g_assert (foreach_data->info == NULL);
00523 
00524   link = g_slist_find_custom (names, foreach_data->name, find_name_in_info);
00525   if (link)
00526     {
00527       foreach_data->owner = owner;
00528       foreach_data->info = link->data;
00529     }
00530 }
00531 
00532 static gboolean
00533 dbus_g_proxy_manager_lookup_name_owner (DBusGProxyManager        *manager,
00534                                         const char               *name,
00535                                         DBusGProxyNameOwnerInfo **info,
00536                                         const char              **owner)
00537 {
00538   DBusGProxyNameOwnerForeachData foreach_data;
00539 
00540   foreach_data.name = name;
00541   foreach_data.owner = NULL;
00542   foreach_data.info = NULL;
00543   
00544   g_hash_table_foreach (manager->owner_names, name_owner_foreach, &foreach_data);
00545 
00546   *info = foreach_data.info;
00547   *owner = foreach_data.owner;
00548   return *info != NULL;
00549 }
00550 
00551 static void
00552 insert_nameinfo (DBusGProxyManager       *manager,
00553                  const char              *owner,
00554                  DBusGProxyNameOwnerInfo *info)
00555 {
00556   GSList *names;
00557   gboolean insert;
00558 
00559   names = g_hash_table_lookup (manager->owner_names, owner);
00560 
00561   /* Only need to g_hash_table_insert the first time */
00562   insert = (names == NULL);
00563 
00564   names = g_slist_append (names, info); 
00565 
00566   if (insert)
00567     g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
00568 }
00569 
00570 static void
00571 dbus_g_proxy_manager_monitor_name_owner (DBusGProxyManager  *manager,
00572                                          const char         *owner,
00573                                          const char         *name)
00574 {
00575   GSList *names;
00576   GSList *link;
00577   DBusGProxyNameOwnerInfo *nameinfo;
00578 
00579   names = g_hash_table_lookup (manager->owner_names, owner);
00580   link = g_slist_find_custom (names, name, find_name_in_info);
00581   
00582   if (!link)
00583     {
00584       nameinfo = g_new0 (DBusGProxyNameOwnerInfo, 1);
00585       nameinfo->name = g_strdup (name);
00586       nameinfo->refcount = 1;
00587 
00588       insert_nameinfo (manager, owner, nameinfo);
00589     }
00590   else
00591     {
00592       nameinfo = link->data;
00593       nameinfo->refcount++;
00594     }
00595 }
00596 
00597 static void
00598 dbus_g_proxy_manager_unmonitor_name_owner (DBusGProxyManager  *manager,
00599                                            const char         *name)
00600 {
00601   DBusGProxyNameOwnerInfo *info;
00602   const char *owner;
00603   gboolean ret;
00604 
00605   ret = dbus_g_proxy_manager_lookup_name_owner (manager, name, &info, &owner);
00606   g_assert (ret);
00607   g_assert (info != NULL);
00608   g_assert (owner != NULL);
00609 
00610   info->refcount--;
00611   if (info->refcount == 0)
00612     {
00613       GSList *names;
00614       GSList *link;
00615 
00616       names = g_hash_table_lookup (manager->owner_names, owner);
00617       link = g_slist_find_custom (names, name, find_name_in_info);
00618       names = g_slist_delete_link (names, link);
00619       if (names != NULL)
00620         g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
00621       else
00622         g_hash_table_remove (manager->owner_names, owner);
00623 
00624       g_free (info->name);
00625       g_free (info);
00626     }
00627 }
00628 
00629 typedef struct
00630 {
00631   const char *name;
00632   GSList *destroyed;
00633 } DBusGProxyUnassociateData;
00634 
00635 static void
00636 unassociate_proxies (gpointer key, gpointer val, gpointer user_data)
00637 {
00638   DBusGProxyList *list;
00639   const char *name;
00640   GSList *tmp;
00641   DBusGProxyUnassociateData *data;
00642 
00643   list = val;
00644   data = user_data;
00645   name = data->name;
00646   
00647   for (tmp = list->proxies; tmp; tmp = tmp->next)
00648     {
00649       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
00650       DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00651       DBusGProxyManager *manager;
00652 
00653       manager = priv->manager;
00654 
00655       if (!strcmp (priv->name, name))
00656         {
00657           if (!priv->for_owner)
00658             {
00659               g_assert (priv->associated);
00660               g_assert (priv->name_call == NULL);
00661 
00662               priv->associated = FALSE;
00663               manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
00664             }
00665           else
00666             {
00667               data->destroyed = g_slist_prepend (data->destroyed, proxy);
00668               /* make contents of list into weak pointers in case the objects
00669                * unref each other when disposing */
00670               g_object_add_weak_pointer (G_OBJECT (proxy),
00671                   &(data->destroyed->data));
00672             }
00673         }
00674     }
00675 }
00676 
00677 static void
00678 dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager  *manager,
00679                                          const char         *name,
00680                                          const char         *prev_owner,
00681                                          const char         *new_owner)
00682 {
00683   GSList *names;
00684           
00685   if (prev_owner[0] == '\0')
00686     {
00687       GSList *tmp;
00688       GSList *removed;
00689 
00690       /* We have a new service, look at unassociated proxies */
00691 
00692       removed = NULL;
00693 
00694       for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
00695         {
00696           DBusGProxy *proxy = tmp->data;
00697           DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00698 
00699           if (!strcmp (priv->name, name))
00700             {
00701               removed = g_slist_prepend (removed, tmp);
00702               
00703               dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
00704               priv->associated = TRUE;
00705             }
00706         }
00707 
00708       for (tmp = removed; tmp; tmp = tmp->next)
00709         manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
00710       g_slist_free (removed);
00711     }
00712   else
00713     {
00714       DBusGProxyNameOwnerInfo *info;
00715       GSList *link;
00716 
00717       /* Name owner changed or deleted */ 
00718 
00719       names = g_hash_table_lookup (manager->owner_names, prev_owner);
00720 
00721       info = NULL;
00722       if (names != NULL)
00723         {
00724           link = g_slist_find_custom (names, name, find_name_in_info);
00725 
00726           if (link != NULL)
00727             {
00728               info = link->data;
00729           
00730               names = g_slist_delete_link (names, link);
00731 
00732               if (names == NULL)
00733                 g_hash_table_remove (manager->owner_names, prev_owner);
00734             }
00735         }
00736 
00737       if (new_owner[0] == '\0')
00738         {
00739           DBusGProxyUnassociateData data;
00740           GSList *tmp;
00741 
00742           data.name = name;
00743           data.destroyed = NULL;
00744 
00745           /* A service went away, we need to unassociate proxies */
00746           g_hash_table_foreach (manager->proxy_lists,
00747                                 unassociate_proxies, &data);
00748 
00749           UNLOCK_MANAGER (manager);
00750 
00751           /* the destroyed list's data pointers are weak pointers, so that we
00752            * don't end up calling destroy on proxies which have already been
00753            * freed up as a result of other ones being destroyed */
00754           for (tmp = data.destroyed; tmp; tmp = tmp->next)
00755             if (tmp->data != NULL)
00756               {
00757                 g_object_remove_weak_pointer (G_OBJECT (tmp->data),
00758                     &(tmp->data));
00759                 dbus_g_proxy_destroy (tmp->data);
00760               }
00761           g_slist_free (data.destroyed);
00762 
00763           LOCK_MANAGER (manager);
00764 
00765           if (info)
00766             {
00767               g_free (info->name);
00768               g_free (info);
00769             }
00770         }
00771       else if (info)
00772         {
00773           insert_nameinfo (manager, new_owner, info);
00774         }
00775     }
00776 }
00777 
00778 static void
00779 got_name_owner_cb (DBusGProxy       *bus_proxy,
00780                    DBusGProxyCall   *call,
00781                    void             *user_data)
00782 {
00783   DBusGProxy *proxy = user_data;
00784   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00785   GError *error;
00786   char *owner;
00787 
00788   error = NULL;
00789   owner = NULL;
00790 
00791   LOCK_MANAGER (priv->manager);
00792 
00793   if (!dbus_g_proxy_end_call (bus_proxy, call, &error,
00794                               G_TYPE_STRING, &owner,
00795                               G_TYPE_INVALID))
00796     {
00797       if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
00798         {
00799           priv->manager->unassociated_proxies = g_slist_prepend (priv->manager->unassociated_proxies, proxy);
00800         }
00801       else if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION)
00802         g_warning ("Couldn't get name owner (%s): %s",
00803                    dbus_g_error_get_name (error),
00804                    error->message);
00805       else
00806         g_warning ("Couldn't get name owner (code %d): %s",
00807                    error->code, error->message);
00808       g_clear_error (&error);
00809       goto out;
00810     }
00811   else
00812     {
00813       dbus_g_proxy_manager_monitor_name_owner (priv->manager, owner, priv->name);
00814       priv->associated = TRUE;
00815     }
00816 
00817  out:
00818   priv->name_call = NULL;
00819   UNLOCK_MANAGER (priv->manager);
00820   g_free (owner);
00821 }
00822 
00823 static char *
00824 get_name_owner (DBusConnection     *connection,
00825                 const char         *name,
00826                 GError            **error)
00827 {
00828   DBusError derror;
00829   DBusMessage *request, *reply;
00830   char *base_name;
00831   
00832   dbus_error_init (&derror);
00833 
00834   base_name = NULL;
00835   reply = NULL;
00836 
00837   request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
00838                                           DBUS_PATH_DBUS,
00839                                           DBUS_INTERFACE_DBUS,
00840                                           "GetNameOwner");
00841   if (request == NULL)
00842     g_error ("Out of memory");
00843   
00844   if (!dbus_message_append_args (request, 
00845                                  DBUS_TYPE_STRING, &name, 
00846                                  DBUS_TYPE_INVALID))
00847     g_error ("Out of memory");
00848 
00849   reply =
00850     dbus_connection_send_with_reply_and_block (connection,
00851                                                request,
00852                                                2000, &derror);
00853   if (reply == NULL)
00854     goto error;
00855 
00856   if (dbus_set_error_from_message (&derror, reply))
00857     goto error;
00858 
00859   if (!dbus_message_get_args (reply, &derror, 
00860                               DBUS_TYPE_STRING, &base_name, 
00861                               DBUS_TYPE_INVALID))
00862     goto error;
00863 
00864   base_name = g_strdup (base_name);
00865   goto out;
00866 
00867  error:
00868   g_assert (dbus_error_is_set (&derror));
00869   dbus_set_g_error (error, &derror);
00870   dbus_error_free (&derror);
00871 
00872  out:
00873   if (request)
00874     dbus_message_unref (request);
00875   if (reply)
00876     dbus_message_unref (reply);
00877 
00878   return base_name;
00879 }
00880 
00881 
00882 static void
00883 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
00884                                DBusGProxy        *proxy)
00885 {
00886   DBusGProxyList *list;
00887   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00888 
00889   LOCK_MANAGER (manager);
00890 
00891   if (manager->proxy_lists == NULL)
00892     {
00893       g_assert (manager->owner_names == NULL);
00894 
00895       list = NULL;
00896       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
00897                                                     tristring_equal,
00898                                                     NULL,
00899                                                     (GFreeFunc) g_proxy_list_free);
00900       manager->owner_names = g_hash_table_new_full (g_str_hash,
00901                                                     g_str_equal,
00902                                                     g_free,
00903                                                     NULL);
00904       /* FIXME - for now we listen for all NameOwnerChanged; once
00905        * Anders' detail patch lands we should add individual rules
00906        */
00907       dbus_bus_add_match (manager->connection,
00908                           "type='signal',sender='" DBUS_SERVICE_DBUS
00909                           "',path='" DBUS_PATH_DBUS
00910                           "',interface='" DBUS_INTERFACE_DBUS
00911                           "',member='NameOwnerChanged'",
00912                           NULL);
00913     }
00914   else
00915     {
00916       char *tri;
00917 
00918       tri = tristring_from_proxy (proxy);
00919       
00920       list = g_hash_table_lookup (manager->proxy_lists, tri);
00921 
00922       g_free (tri);
00923     }
00924       
00925   if (list == NULL)
00926     {
00927       list = g_proxy_list_new (proxy);
00928       
00929       g_hash_table_replace (manager->proxy_lists,
00930                             list->name, list);
00931     }
00932 
00933   if (list->proxies == NULL && priv->name)
00934     {
00935       /* We have to add the match rule to the server,
00936        * but only if the server is a message bus,
00937        * not if it's a peer.
00938        */
00939        char *rule;
00940        
00941        rule = g_proxy_get_match_rule (proxy);
00942        
00943        /* We don't check for errors; it's not like anyone would handle them, and
00944         * we don't want a round trip here.
00945         */
00946        dbus_bus_add_match (manager->connection,
00947                            rule, NULL);
00948        
00949        g_free (rule);
00950     }
00951 
00952   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00953   
00954   list->proxies = g_slist_prepend (list->proxies, proxy);
00955 
00956   if (!priv->for_owner)
00957     {
00958       const char *owner;
00959       DBusGProxyNameOwnerInfo *info;
00960 
00961       if (!dbus_g_proxy_manager_lookup_name_owner (manager, priv->name, &info, &owner))
00962         {
00963           priv->name_call = manager_begin_bus_call (manager, "GetNameOwner",
00964                                                      got_name_owner_cb,
00965                                                      proxy, NULL,
00966                                                      G_TYPE_STRING,
00967                                                      priv->name, 
00968                                                      G_TYPE_INVALID);
00969           
00970           priv->associated = FALSE;
00971         }
00972       else
00973         {
00974           info->refcount++;
00975           priv->associated = TRUE;
00976         }
00977     }
00978   
00979   UNLOCK_MANAGER (manager);
00980 }
00981 
00982 static void
00983 dbus_g_proxy_manager_unregister (DBusGProxyManager *manager,
00984                                 DBusGProxy        *proxy)
00985 {
00986   DBusGProxyList *list;
00987   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00988   char *tri;
00989   
00990   LOCK_MANAGER (manager);
00991 
00992 #ifndef G_DISABLE_CHECKS
00993   if (manager->proxy_lists == NULL)
00994     {
00995       g_warning ("Trying to unregister a proxy but there aren't any registered");
00996       return;
00997     }
00998 #endif
00999 
01000   tri = tristring_from_proxy (proxy);
01001   
01002   list = g_hash_table_lookup (manager->proxy_lists, tri);
01003 
01004 #ifndef G_DISABLE_CHECKS
01005   if (list == NULL)
01006     {
01007       g_warning ("Trying to unregister a proxy but it isn't registered");
01008       return;
01009     }
01010 #endif
01011 
01012   g_assert (g_slist_find (list->proxies, proxy) != NULL);
01013   
01014   list->proxies = g_slist_remove (list->proxies, proxy);
01015 
01016   g_assert (g_slist_find (list->proxies, proxy) == NULL);
01017 
01018   if (!priv->for_owner)
01019     {
01020       if (!priv->associated)
01021         {
01022           GSList *link;
01023 
01024           if (priv->name_call != 0)
01025             {
01026               dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
01027               priv->name_call = 0;
01028             }
01029           else
01030             {
01031               link = g_slist_find (manager->unassociated_proxies, proxy);
01032               g_assert (link != NULL);
01033 
01034               manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, link);
01035             }
01036         }
01037       else
01038         {
01039           g_assert (priv->name_call == 0);
01040           
01041           dbus_g_proxy_manager_unmonitor_name_owner (manager, priv->name);
01042         }
01043     }
01044 
01045   if (list->proxies == NULL)
01046     {
01047       char *rule;
01048       g_hash_table_remove (manager->proxy_lists,
01049                            tri);
01050       list = NULL;
01051 
01052       rule = g_proxy_get_match_rule (proxy);
01053       dbus_bus_remove_match (manager->connection,
01054                              rule, NULL);
01055       g_free (rule);
01056     }
01057   
01058   if (g_hash_table_size (manager->proxy_lists) == 0)
01059     {
01060       g_hash_table_destroy (manager->proxy_lists);
01061       manager->proxy_lists = NULL;
01062     }
01063 
01064   g_free (tri);
01065       
01066   UNLOCK_MANAGER (manager);
01067 }
01068 
01069 static void
01070 list_proxies_foreach (gpointer key,
01071                       gpointer value,
01072                       gpointer user_data)
01073 {
01074   DBusGProxyList *list;
01075   GSList **ret;
01076   GSList *tmp;
01077   
01078   list = value;
01079   ret = user_data;
01080 
01081   tmp = list->proxies;
01082   while (tmp != NULL)
01083     {
01084       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
01085 
01086       g_object_ref (proxy);
01087       *ret = g_slist_prepend (*ret, proxy);
01088       
01089       tmp = tmp->next;
01090     }
01091 }
01092 
01093 static GSList*
01094 dbus_g_proxy_manager_list_all (DBusGProxyManager *manager)
01095 {
01096   GSList *ret;
01097 
01098   ret = NULL;
01099 
01100   if (manager->proxy_lists)
01101     {
01102       g_hash_table_foreach (manager->proxy_lists,
01103                             list_proxies_foreach,
01104                             &ret);
01105     }
01106 
01107   return ret;
01108 }
01109 
01110 static DBusHandlerResult
01111 dbus_g_proxy_manager_filter (DBusConnection    *connection,
01112                              DBusMessage       *message,
01113                              void              *user_data)
01114 {
01115   DBusGProxyManager *manager;
01116   
01117   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
01118     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01119 
01120   manager = user_data;
01121 
01122   dbus_g_proxy_manager_ref (manager);
01123   
01124   LOCK_MANAGER (manager);
01125   
01126   if (dbus_message_is_signal (message,
01127                               DBUS_INTERFACE_LOCAL,
01128                               "Disconnected"))
01129     {
01130       /* Destroy all the proxies, quite possibly resulting in unreferencing
01131        * the proxy manager and the connection as well.
01132        */
01133       GSList *all;
01134       GSList *tmp;
01135 
01136       all = dbus_g_proxy_manager_list_all (manager);
01137 
01138       tmp = all;
01139       while (tmp != NULL)
01140         {
01141           DBusGProxy *proxy;
01142 
01143           proxy = DBUS_G_PROXY (tmp->data);
01144 
01145           UNLOCK_MANAGER (manager);
01146           dbus_g_proxy_destroy (proxy);
01147           g_object_unref (G_OBJECT (proxy));
01148           LOCK_MANAGER (manager);
01149           
01150           tmp = tmp->next;
01151         }
01152 
01153       g_slist_free (all);
01154 
01155 #ifndef G_DISABLE_CHECKS
01156       if (manager->proxy_lists != NULL)
01157         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.");
01158 #endif
01159     }
01160   else
01161     {
01162       char *tri;
01163       GSList *full_list;
01164       GSList *owned_names;
01165       GSList *tmp;
01166       const char *sender;
01167 
01168       /* First we handle NameOwnerChanged internally */
01169       if (dbus_message_is_signal (message,
01170                                   DBUS_INTERFACE_DBUS,
01171                                   "NameOwnerChanged"))
01172         {
01173           const char *name;
01174           const char *prev_owner;
01175           const char *new_owner;
01176           DBusError derr;
01177 
01178           dbus_error_init (&derr);
01179           if (!dbus_message_get_args (message,
01180                                       &derr,
01181                                       DBUS_TYPE_STRING,
01182                                       &name,
01183                                       DBUS_TYPE_STRING,
01184                                       &prev_owner,
01185                                       DBUS_TYPE_STRING,
01186                                       &new_owner,
01187                                       DBUS_TYPE_INVALID))
01188             {
01189               /* Ignore this error */
01190               dbus_error_free (&derr);
01191             }
01192           else if (manager->owner_names != NULL)
01193             {
01194               dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
01195             }
01196         }
01197 
01198       sender = dbus_message_get_sender (message);
01199 
01200       /* dbus spec requires these, libdbus validates */
01201       g_assert (dbus_message_get_path (message) != NULL);
01202       g_assert (dbus_message_get_interface (message) != NULL);
01203       g_assert (dbus_message_get_member (message) != NULL);
01204       
01205       tri = tristring_from_message (message);
01206 
01207       if (manager->proxy_lists)
01208         {
01209           DBusGProxyList *owner_list;
01210           owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01211           if (owner_list)
01212             full_list = g_slist_copy (owner_list->proxies);
01213           else
01214             full_list = NULL;
01215         }
01216       else
01217         full_list = NULL;
01218 
01219       g_free (tri);
01220 
01221       if (manager->owner_names && sender)
01222         {
01223           owned_names = g_hash_table_lookup (manager->owner_names, sender);
01224           for (tmp = owned_names; tmp; tmp = tmp->next)
01225             {
01226               DBusGProxyList *owner_list;
01227               DBusGProxyNameOwnerInfo *nameinfo;
01228 
01229               nameinfo = tmp->data;
01230               g_assert (nameinfo->refcount > 0);
01231               tri = tristring_alloc_from_strings (0, nameinfo->name,
01232                                                   dbus_message_get_path (message),
01233                                                   dbus_message_get_interface (message));
01234 
01235               owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01236               if (owner_list != NULL)
01237                 full_list = g_slist_concat (full_list, g_slist_copy (owner_list->proxies));
01238               g_free (tri);
01239             }
01240         }
01241 
01242 #if 0
01243       g_print ("proxy got %s,%s,%s = list %p\n",
01244                tri,
01245                tri + strlen (tri) + 1,
01246                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
01247                list);
01248 #endif
01249       
01250       /* Emit the signal */
01251       
01252       g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
01253       
01254       for (tmp = full_list; tmp; tmp = tmp->next)
01255         {
01256           DBusGProxy *proxy;
01257           
01258           proxy = DBUS_G_PROXY (tmp->data);
01259           
01260           UNLOCK_MANAGER (manager);
01261           dbus_g_proxy_emit_remote_signal (proxy, message);
01262           g_object_unref (G_OBJECT (proxy));
01263           LOCK_MANAGER (manager);
01264         }
01265       g_slist_free (full_list);
01266     }
01267 
01268   UNLOCK_MANAGER (manager);
01269   dbus_g_proxy_manager_unref (manager);
01270   
01271   /* "Handling" signals doesn't make sense, they are for everyone
01272    * who cares
01273    */
01274   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01275 }
01276 
01277 
01278 
01279 /*      ---------- DBusGProxy --------------   */
01280 #define DBUS_G_PROXY_DESTROYED(proxy)  (DBUS_G_PROXY_GET_PRIVATE(proxy)->manager == NULL)
01281 
01282 static void
01283 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
01284                                       GValue       *return_value,
01285                                       guint         n_param_values,
01286                                       const GValue *param_values,
01287                                       gpointer      invocation_hint,
01288                                       gpointer      marshal_data);
01289 enum
01290 {
01291   PROP_0,
01292   PROP_NAME,
01293   PROP_PATH,
01294   PROP_INTERFACE,
01295   PROP_CONNECTION
01296 };
01297 
01298 enum
01299 {
01300   DESTROY,
01301   RECEIVED,
01302   LAST_SIGNAL
01303 };
01304 
01305 static void *parent_class;
01306 static guint signals[LAST_SIGNAL] = { 0 };
01307 
01308 static void
01309 dbus_g_proxy_init (DBusGProxy *proxy)
01310 {
01311   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01312   
01313   g_datalist_init (&priv->signal_signatures);
01314   priv->pending_calls = g_hash_table_new_full (NULL, NULL, NULL,
01315                                 (GDestroyNotify) dbus_pending_call_unref);
01316   priv->name_call = 0;
01317   priv->associated = FALSE;
01318 }
01319 
01320 static GObject *
01321 dbus_g_proxy_constructor (GType                  type,
01322                           guint                  n_construct_properties,
01323                           GObjectConstructParam *construct_properties)
01324 {
01325   DBusGProxy *proxy;
01326   DBusGProxyClass *klass;
01327   GObjectClass *parent_class;
01328   DBusGProxyPrivate *priv;
01329 
01330   klass = DBUS_G_PROXY_CLASS (g_type_class_peek (DBUS_TYPE_G_PROXY));
01331 
01332   parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
01333 
01334   proxy = DBUS_G_PROXY (parent_class->constructor (type, n_construct_properties,
01335                                                     construct_properties));
01336 
01337   priv = DBUS_G_PROXY_GET_PRIVATE (proxy);
01338 
01339   /* if these assertions fail, a deriving class has not set our required
01340    * parameters - our own public constructors do return_if_fail checks
01341    * on these parameters being provided. unfortunately we can't assert
01342    * for manager because it's allowed to be NULL when tha mangager is
01343    * setting up a bus proxy for its own calls */
01344   g_assert (priv->path != NULL);
01345   g_assert (priv->interface != NULL);
01346 
01347   if (priv->manager != NULL)
01348     {
01349       dbus_g_proxy_manager_register (priv->manager, proxy);
01350     }
01351 
01352   return G_OBJECT (proxy);
01353 }
01354 
01355 static void
01356 dbus_g_proxy_class_init (DBusGProxyClass *klass)
01357 {
01358   GObjectClass *object_class = G_OBJECT_CLASS (klass);
01359   
01360   parent_class = g_type_class_peek_parent (klass);
01361 
01362   g_type_class_add_private (klass, sizeof (DBusGProxyPrivate));
01363 
01364   object_class->set_property = dbus_g_proxy_set_property;
01365   object_class->get_property = dbus_g_proxy_get_property;
01366 
01367   g_object_class_install_property (object_class,
01368                                    PROP_NAME,
01369                                    g_param_spec_string ("name",
01370                                                         "name",
01371                                                         "name",
01372                                                         NULL,
01373                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01374 
01375   g_object_class_install_property (object_class,
01376                                    PROP_PATH,
01377                                    g_param_spec_string ("path",
01378                                                         "path",
01379                                                         "path",
01380                                                         NULL,
01381                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01382 
01383   g_object_class_install_property (object_class,
01384                                    PROP_INTERFACE,
01385                                    g_param_spec_string ("interface",
01386                                                         "interface",
01387                                                         "interface",
01388                                                         NULL,
01389                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01390   
01391   g_object_class_install_property (object_class,
01392                                    PROP_CONNECTION,
01393                                    g_param_spec_boxed ("connection",
01394                                                         "connection",
01395                                                         "connection",
01396                                                         DBUS_TYPE_G_CONNECTION,
01397                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01398   
01399   object_class->finalize = dbus_g_proxy_finalize;
01400   object_class->dispose = dbus_g_proxy_dispose;
01401   object_class->constructor = dbus_g_proxy_constructor;
01402   
01403   signals[DESTROY] =
01404     g_signal_new ("destroy",
01405                   G_OBJECT_CLASS_TYPE (object_class),
01406                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
01407                   0,
01408                   NULL, NULL,
01409                   g_cclosure_marshal_VOID__VOID,
01410                   G_TYPE_NONE, 0);
01411 
01412   signals[RECEIVED] =
01413     g_signal_new ("received",
01414                   G_OBJECT_CLASS_TYPE (object_class),
01415                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
01416                   0,
01417                   NULL, NULL,
01418                   marshal_dbus_message_to_g_marshaller,
01419                   G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
01420 }
01421 
01422 static void
01423 cancel_pending_call (gpointer key, gpointer val, gpointer data)
01424 {
01425   DBusGProxyCall *call = key;
01426   DBusGProxy *proxy = data;
01427 
01428   dbus_g_proxy_cancel_call (proxy, call);
01429 }
01430 
01431 static void
01432 dbus_g_proxy_dispose (GObject *object)
01433 {
01434   DBusGProxy *proxy = DBUS_G_PROXY (object);
01435   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01436 
01437   if (priv->pending_calls == NULL) 
01438     {
01439       return;
01440     }
01441 
01442   /* Cancel outgoing pending calls */
01443   g_hash_table_foreach (priv->pending_calls, cancel_pending_call, proxy);
01444   g_hash_table_destroy (priv->pending_calls);
01445   priv->pending_calls = NULL;
01446 
01447   if (priv->manager && proxy != priv->manager->bus_proxy)
01448     {
01449       dbus_g_proxy_manager_unregister (priv->manager, proxy);
01450       dbus_g_proxy_manager_unref (priv->manager);
01451     }
01452   priv->manager = NULL;
01453   
01454   g_datalist_clear (&priv->signal_signatures);
01455   
01456   g_signal_emit (object, signals[DESTROY], 0);
01457   
01458   G_OBJECT_CLASS (parent_class)->dispose (object);
01459 }
01460 
01461 static void
01462 dbus_g_proxy_finalize (GObject *object)
01463 {
01464   DBusGProxy *proxy = DBUS_G_PROXY (object);
01465   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01466   
01467   g_return_if_fail (DBUS_G_PROXY_DESTROYED (proxy));
01468   
01469   g_free (priv->name);
01470   g_free (priv->path);
01471   g_free (priv->interface);
01472   
01473   G_OBJECT_CLASS (parent_class)->finalize (object);
01474 }
01475 
01476 static void
01477 dbus_g_proxy_destroy (DBusGProxy *proxy)
01478 {
01479   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
01480    * from GtkObject?
01481    */
01482   g_object_run_dispose (G_OBJECT (proxy));
01483 }
01484 
01485 static void
01486 dbus_g_proxy_set_property (GObject *object,
01487                            guint prop_id,
01488                            const GValue *value,
01489                            GParamSpec *pspec)
01490 {
01491   DBusGProxy *proxy = DBUS_G_PROXY (object);
01492   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01493   DBusGConnection *connection;
01494 
01495   switch (prop_id)
01496     {
01497     case PROP_NAME:
01498       priv->name = g_strdup (g_value_get_string (value));
01499       if (priv->name)
01500         priv->for_owner = (priv->name[0] == ':');
01501       else
01502         priv->for_owner = TRUE;
01503       break;
01504     case PROP_PATH:
01505       priv->path = g_strdup (g_value_get_string (value));
01506       break;
01507     case PROP_INTERFACE:
01508       priv->interface = g_strdup (g_value_get_string (value));
01509       break;
01510     case PROP_CONNECTION:
01511       connection = g_value_get_boxed (value);
01512       if (connection != NULL)
01513         {
01514           priv->manager = dbus_g_proxy_manager_get (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
01515         }
01516       break;
01517     default:
01518       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01519       break;
01520     }
01521 }
01522 
01523 static void 
01524 dbus_g_proxy_get_property (GObject *object,
01525                            guint prop_id,
01526                            GValue *value,
01527                            GParamSpec *pspec)
01528 {
01529   DBusGProxy *proxy = DBUS_G_PROXY (object);
01530   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01531 
01532   switch (prop_id)
01533     {
01534     case PROP_NAME:
01535       g_value_set_string (value, priv->name);
01536       break;
01537     case PROP_PATH:
01538       g_value_set_string (value, priv->path);
01539       break;
01540     case PROP_INTERFACE:
01541       g_value_set_string (value, priv->interface);
01542       break;
01543     case PROP_CONNECTION:
01544       g_value_set_boxed (value, DBUS_G_CONNECTION_FROM_CONNECTION(priv->manager->connection));
01545       break;
01546     default:
01547       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01548       break;
01549     }
01550 }
01551 
01552 /* this is to avoid people using g_signal_connect() directly,
01553  * to avoid confusion with local signal names, and because
01554  * of the horribly broken current setup (signals are added
01555  * globally to all proxies)
01556  */
01557 static char*
01558 create_signal_name (const char *interface,
01559                     const char *signal)
01560 {
01561   GString *str;
01562   char *p;
01563 
01564   str = g_string_new (interface);
01565 
01566   g_string_append (str, "-");
01567   
01568   g_string_append (str, signal);
01569 
01570   /* GLib will silently barf on '.' in signal names */
01571   p = str->str;
01572   while (*p)
01573     {
01574       if (*p == '.')
01575         *p = '-';
01576       ++p;
01577     }
01578   
01579   return g_string_free (str, FALSE);
01580 }
01581 
01582 static void
01583 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
01584                                       GValue       *return_value,
01585                                       guint         n_param_values,
01586                                       const GValue *param_values,
01587                                       gpointer      invocation_hint,
01588                                       gpointer      marshal_data)
01589 {
01590   /* Incoming here we have three params, the instance (Proxy), the
01591    * DBusMessage, the signature. We want to convert that to an
01592    * expanded GValue array, then call an appropriate normal GLib
01593    * marshaller.
01594    */
01595 #define MAX_SIGNATURE_ARGS 20
01596   GValueArray *value_array;
01597   GSignalCMarshaller c_marshaller;
01598   DBusGProxy *proxy;
01599   DBusMessage *message;
01600   GArray *gsignature;
01601   const GType *types;
01602   DBusGProxyPrivate *priv;
01603 
01604   g_assert (n_param_values == 3);
01605 
01606   proxy = g_value_get_object (&param_values[0]);
01607   message = g_value_get_boxed (&param_values[1]);
01608   gsignature = g_value_get_pointer (&param_values[2]);
01609 
01610   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
01611   g_return_if_fail (message != NULL);
01612   g_return_if_fail (gsignature != NULL);
01613 
01614   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01615 
01616   c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
01617                                                   (GType*) gsignature->data);
01618 
01619   g_return_if_fail (c_marshaller != NULL);
01620   
01621   {
01622     DBusGValueMarshalCtx context;
01623     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
01624     context.proxy = proxy;
01625 
01626     types = (const GType*) gsignature->data;
01627     value_array = _dbus_gvalue_demarshal_message (&context, message,
01628                                                  gsignature->len, types, NULL);
01629   }
01630 
01631   if (value_array == NULL)
01632     return;
01633   
01634   g_value_array_prepend (value_array, NULL);
01635   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_FROM_INSTANCE (proxy));
01636   g_value_set_instance (g_value_array_get_nth (value_array, 0), proxy);
01637 
01638   (* c_marshaller) (closure, return_value, value_array->n_values,
01639                     value_array->values, invocation_hint, marshal_data);
01640   
01641   g_value_array_free (value_array);
01642 }
01643 
01644 static void
01645 dbus_g_proxy_emit_remote_signal (DBusGProxy  *proxy,
01646                                  DBusMessage *message)
01647 {
01648   const char *interface;
01649   const char *signal;
01650   char *name;
01651   GQuark q;
01652   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01653   GArray *msg_gsignature = NULL;
01654 
01655   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
01656 
01657   interface = dbus_message_get_interface (message);
01658   signal = dbus_message_get_member (message);
01659 
01660   g_assert (interface != NULL);
01661   g_assert (signal != NULL);
01662 
01663   name = create_signal_name (interface, signal);
01664 
01665   /* If the quark isn't preexisting, there's no way there
01666    * are any handlers connected. We don't want to create
01667    * extra quarks for every possible signal.
01668    */
01669   q = g_quark_try_string (name);
01670 
01671   if (q != 0)
01672     {
01673       GArray *gsignature;
01674       guint i;
01675       
01676       gsignature = g_datalist_id_get_data (&priv->signal_signatures, q);
01677       if (gsignature == NULL)
01678         goto out;
01679       
01680       msg_gsignature = _dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
01681                                                        TRUE);
01682       for (i = 0; i < gsignature->len; i++)
01683         {
01684           if (msg_gsignature->len == i
01685               || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
01686             goto mismatch;
01687         }
01688       if (msg_gsignature->len != i)
01689         goto mismatch;
01690       
01691       g_signal_emit (proxy,
01692                      signals[RECEIVED],
01693                      q,
01694                      message,
01695                      msg_gsignature);
01696     }
01697 
01698  out:
01699   g_free (name);
01700   if (msg_gsignature)
01701     g_array_free (msg_gsignature, TRUE);
01702   return;
01703  mismatch:
01704 #if 0
01705   /* Don't spew on remote errors */
01706   g_warning ("Unexpected message signature '%s' for signal '%s'\n",
01707              dbus_message_get_signature (message),
01708              name);
01709 #endif
01710   goto out;
01711 }
01712 
01713 typedef struct
01714 {
01715   DBusGProxy *proxy;
01716   guint call_id;
01717   DBusGProxyCallNotify func;
01718   void *data;
01719   GDestroyNotify free_data_func;
01720 } GPendingNotifyClosure;
01721 
01722 static void
01723 d_pending_call_notify (DBusPendingCall *dcall,
01724                        void            *data)
01725 {
01726   GPendingNotifyClosure *closure = data;
01727 
01728   (* closure->func) (closure->proxy, DBUS_G_PROXY_ID_TO_CALL (closure->call_id), closure->data);
01729 }
01730 
01731 static void
01732 d_pending_call_free (void *data)
01733 {
01734   GPendingNotifyClosure *closure = data;
01735   
01736   if (closure->free_data_func)
01737     (* closure->free_data_func) (closure->data);
01738 
01739   g_free (closure);
01740 }
01741   
01742 #define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
01743 do { \
01744   GType valtype; \
01745   int i = 0; \
01746   VALARRAY = g_value_array_new (6); \
01747   valtype = FIRST_ARG_TYPE; \
01748   while (valtype != G_TYPE_INVALID) \
01749     { \
01750       const char *collect_err; \
01751       GValue *val; \
01752       g_value_array_append (VALARRAY, NULL); \
01753       val = g_value_array_get_nth (VALARRAY, i); \
01754       g_value_init (val, valtype); \
01755       collect_err = NULL; \
01756       G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
01757       valtype = va_arg (ARGS, GType); \
01758       i++; \
01759     } \
01760 } while (0)
01761 
01762 DBusGProxyCall *
01763 manager_begin_bus_call (DBusGProxyManager    *manager,
01764                         const char           *method,
01765                         DBusGProxyCallNotify  notify,
01766                         gpointer              user_data,
01767                         GDestroyNotify        destroy,
01768                         GType                 first_arg_type,
01769                         ...)
01770 {
01771   DBusGProxyCall *call;
01772   DBusGProxyPrivate *priv;
01773   va_list args;
01774   GValueArray *arg_values;
01775   
01776   va_start (args, first_arg_type);
01777 
01778   if (!manager->bus_proxy)
01779     {
01780       manager->bus_proxy = g_object_new (DBUS_TYPE_G_PROXY,
01781                                          "name", DBUS_SERVICE_DBUS,
01782                                          "path", DBUS_PATH_DBUS,
01783                                          "interface", DBUS_INTERFACE_DBUS,
01784                                          NULL);
01785       priv = DBUS_G_PROXY_GET_PRIVATE(manager->bus_proxy);
01786       priv->manager = manager;
01787     }
01788 
01789   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
01790   
01791   call = DBUS_G_PROXY_ID_TO_CALL (dbus_g_proxy_begin_call_internal (manager->bus_proxy, method, notify, user_data, destroy, arg_values,-1));
01792 
01793   g_value_array_free (arg_values);
01794 
01795   va_end (args);
01796 
01797   return call;
01798 }
01799 
01821 GType
01822 dbus_g_proxy_get_type (void)
01823 {
01824   static GType object_type = 0;
01825 
01826   if (!object_type)
01827     {
01828       static const GTypeInfo object_info =
01829         {
01830           sizeof (DBusGProxyClass),
01831           (GBaseInitFunc) NULL,
01832           (GBaseFinalizeFunc) NULL,
01833           (GClassInitFunc) dbus_g_proxy_class_init,
01834           NULL,           /* class_finalize */
01835           NULL,           /* class_data */
01836           sizeof (DBusGProxy),
01837           0,              /* n_preallocs */
01838           (GInstanceInitFunc) dbus_g_proxy_init,
01839         };
01840       
01841       object_type = g_type_register_static (G_TYPE_OBJECT,
01842                                             "DBusGProxy",
01843                                             &object_info, 0);
01844     }
01845   
01846   return object_type;
01847 }
01848 
01849 static DBusGProxy*
01850 dbus_g_proxy_new (DBusGConnection *connection,
01851                   const char      *name,
01852                   const char      *path_name,
01853                   const char      *interface_name)
01854 {
01855   DBusGProxy *proxy;
01856 
01857   g_assert (connection != NULL);
01858   
01859   proxy = g_object_new (DBUS_TYPE_G_PROXY, 
01860                         "name", name, 
01861                         "path", path_name, 
01862                         "interface", interface_name, 
01863                         "connection", connection, NULL);
01864 
01865   return proxy;
01866 }
01867 
01896 DBusGProxy*
01897 dbus_g_proxy_new_for_name (DBusGConnection *connection,
01898                            const char      *name,
01899                            const char      *path_name,
01900                            const char      *interface_name)
01901 {
01902   g_return_val_if_fail (connection != NULL, NULL);
01903   g_return_val_if_fail (name != NULL, NULL);
01904   g_return_val_if_fail (path_name != NULL, NULL);
01905   g_return_val_if_fail (interface_name != NULL, NULL);
01906 
01907   return dbus_g_proxy_new (connection, name,
01908                            path_name, interface_name);
01909 }
01910 
01936 DBusGProxy*
01937 dbus_g_proxy_new_for_name_owner (DBusGConnection          *connection,
01938                                  const char               *name,
01939                                  const char               *path_name,
01940                                  const char               *interface_name,
01941                                  GError                  **error)
01942 {
01943   DBusGProxy *proxy;
01944   char *unique_name;
01945 
01946   g_return_val_if_fail (connection != NULL, NULL);
01947   g_return_val_if_fail (name != NULL, NULL);
01948   g_return_val_if_fail (path_name != NULL, NULL);
01949   g_return_val_if_fail (interface_name != NULL, NULL);
01950 
01951   if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
01952     return NULL;
01953 
01954   proxy = dbus_g_proxy_new (connection, unique_name,
01955                             path_name, interface_name);
01956   g_free (unique_name);
01957   return proxy;
01958 }
01959 
01971 DBusGProxy*
01972 dbus_g_proxy_new_from_proxy (DBusGProxy        *proxy,
01973                              const char        *interface,
01974                              const char        *path)
01975 {
01976   DBusGProxyPrivate *priv;
01977 
01978   g_return_val_if_fail (proxy != NULL, NULL);
01979 
01980   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01981   
01982   if (interface == NULL)
01983     interface = priv->interface;
01984   if (path == NULL)
01985     path = priv->path;
01986 
01987   return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection),
01988                            priv->name,
01989                            path, interface);
01990 }
01991 
02006 DBusGProxy*
02007 dbus_g_proxy_new_for_peer (DBusGConnection          *connection,
02008                            const char               *path_name,
02009                            const char               *interface_name)
02010 {
02011   DBusGProxy *proxy;
02012   
02013   g_return_val_if_fail (connection != NULL, NULL);
02014   g_return_val_if_fail (path_name != NULL, NULL);
02015   g_return_val_if_fail (interface_name != NULL, NULL);
02016 
02017   proxy = dbus_g_proxy_new (connection, NULL,
02018                             path_name, interface_name);
02019 
02020   return proxy;
02021 }
02022 
02036 const char*
02037 dbus_g_proxy_get_bus_name (DBusGProxy        *proxy)
02038 {
02039   DBusGProxyPrivate *priv;
02040 
02041   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02042   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02043 
02044   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02045 
02046   return priv->name;
02047 }
02048 
02057 const char*
02058 dbus_g_proxy_get_interface (DBusGProxy        *proxy)
02059 {
02060   DBusGProxyPrivate *priv;
02061   
02062   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02063   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02064 
02065   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02066 
02067   return priv->interface;
02068 }
02069 
02077 void
02078 dbus_g_proxy_set_interface (DBusGProxy        *proxy,
02079                             const char        *interface_name)
02080 {
02081   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02082   /* FIXME - need to unregister when we switch interface for now
02083    * later should support idea of unset interface
02084    */
02085   dbus_g_proxy_manager_unregister (priv->manager, proxy);
02086   g_free (priv->interface);
02087   priv->interface = g_strdup (interface_name);
02088   dbus_g_proxy_manager_register (priv->manager, proxy);
02089 }
02090 
02098 const char*
02099 dbus_g_proxy_get_path (DBusGProxy        *proxy)
02100 {
02101   DBusGProxyPrivate *priv;
02102   
02103   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02104   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02105 
02106   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02107 
02108   return priv->path;
02109 }
02110 
02111 static DBusMessage *
02112 dbus_g_proxy_marshal_args_to_message (DBusGProxy  *proxy,
02113                                       const char  *method,
02114                                       GValueArray *args)
02115 {
02116   DBusMessage *message;
02117   DBusMessageIter msgiter;
02118   guint i;
02119   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02120 
02121   message = dbus_message_new_method_call (priv->name,
02122                                           priv->path,
02123                                           priv->interface,
02124                                           method);
02125   if (message == NULL)
02126     goto oom;
02127 
02128   dbus_message_iter_init_append (message, &msgiter);
02129   for (i = 0; i < args->n_values; i++)
02130     {
02131       GValue *gvalue;
02132 
02133       gvalue = g_value_array_get_nth (args, i);
02134 
02135       if (!_dbus_gvalue_marshal (&msgiter, gvalue))
02136         g_assert_not_reached ();
02137     }
02138   return message;
02139  oom:
02140   return NULL;
02141 }
02142 
02143 static guint
02144 dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
02145                                   const char          *method,
02146                                   DBusGProxyCallNotify notify,
02147                                   gpointer             user_data,
02148                                   GDestroyNotify       destroy,
02149                                   GValueArray         *args,
02150                                   int timeout)
02151 {
02152   DBusMessage *message;
02153   DBusPendingCall *pending;
02154   GPendingNotifyClosure *closure;
02155   guint call_id;
02156   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02157 
02158   pending = NULL;
02159 
02160   message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
02161   if (!message)
02162     goto oom;
02163 
02164   if (!dbus_connection_send_with_reply (priv->manager->connection,
02165                                         message,
02166                                         &pending,
02167                                         timeout))
02168     goto oom;
02169   dbus_message_unref (message);
02170   g_assert (pending != NULL);
02171 
02172   call_id = ++priv->call_id_counter;
02173 
02174   if (notify != NULL)
02175     {
02176       closure = g_new (GPendingNotifyClosure, 1);
02177       closure->proxy = proxy; /* No need to ref as the lifecycle is tied to proxy */
02178       closure->call_id = call_id;
02179       closure->func = notify;
02180       closure->data = user_data;
02181       closure->free_data_func = destroy;
02182       dbus_pending_call_set_notify (pending, d_pending_call_notify,
02183                                     closure,
02184                                     d_pending_call_free);
02185     }
02186 
02187   g_hash_table_insert (priv->pending_calls, GUINT_TO_POINTER (call_id), pending);
02188 
02189   return call_id;
02190  oom:
02191   g_error ("Out of memory");
02192   return 0;
02193 }
02194 
02195 static gboolean
02196 dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
02197                                 guint              call_id,
02198                                 GError           **error,
02199                                 GType              first_arg_type,
02200                                 va_list            args)
02201 {
02202   DBusMessage *reply;
02203   DBusMessageIter msgiter;
02204   DBusError derror;
02205   va_list args_unwind;
02206   guint over;
02207   int n_retvals_processed;
02208   gboolean ret;
02209   GType valtype;
02210   DBusPendingCall *pending;
02211   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02212 
02213   reply = NULL;
02214   ret = FALSE;
02215   n_retvals_processed = 0;
02216   over = 0;
02217 
02218   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
02219   
02220   dbus_pending_call_block (pending);
02221   reply = dbus_pending_call_steal_reply (pending);
02222 
02223   g_assert (reply != NULL);
02224 
02225   dbus_error_init (&derror);
02226 
02227   switch (dbus_message_get_type (reply))
02228     {
02229     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
02230       dbus_message_iter_init (reply, &msgiter);
02231       valtype = first_arg_type;
02232       while (valtype != G_TYPE_INVALID)
02233         {
02234           int arg_type;
02235           gpointer return_storage;
02236           GValue gvalue = { 0, };
02237           DBusGValueMarshalCtx context;
02238 
02239           context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
02240           context.proxy = proxy;
02241 
02242           arg_type = dbus_message_iter_get_arg_type (&msgiter);
02243           if (arg_type == DBUS_TYPE_INVALID)
02244             {
02245               g_set_error (error, DBUS_GERROR,
02246                            DBUS_GERROR_INVALID_ARGS,
02247                            _("Too few arguments in reply"));
02248               goto out;
02249             }
02250 
02251           return_storage = va_arg (args, gpointer);
02252           if (return_storage == NULL)
02253             goto next;
02254 
02255           /* We handle variants specially; the caller is expected
02256            * to have already allocated storage for them.
02257            */
02258           if (arg_type == DBUS_TYPE_VARIANT
02259               && g_type_is_a (valtype, G_TYPE_VALUE))
02260             {
02261               if (!_dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
02262                 {
02263                   g_set_error (error,
02264                                DBUS_GERROR,
02265                                DBUS_GERROR_INVALID_ARGS,
02266                                _("Couldn't convert argument, expected \"%s\""),
02267                                g_type_name (valtype));
02268                   goto out;
02269                 }
02270             }
02271           else
02272             {
02273               g_value_init (&gvalue, valtype);
02274 
02275               if (!_dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error))
02276                 goto out;
02277 
02278               /* Anything that can be demarshaled must be storable */
02279               if (!_dbus_gvalue_store (&gvalue, (gpointer*) return_storage))
02280                 g_assert_not_reached ();
02281               /* Ownership of the value passes to the client, don't unset */
02282             }
02283           
02284         next:
02285           n_retvals_processed++;
02286           dbus_message_iter_next (&msgiter);
02287           valtype = va_arg (args, GType);
02288         }
02289       
02290       while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
02291         {
02292           over++;
02293           dbus_message_iter_next (&msgiter);
02294         }
02295 
02296       if (over > 0)
02297         {
02298           g_set_error (error, DBUS_GERROR,
02299                        DBUS_GERROR_INVALID_ARGS,
02300                        _("Too many arguments in reply; expected %d, got %d"),
02301                        n_retvals_processed, over);
02302           goto out;
02303         }
02304       break;
02305     case DBUS_MESSAGE_TYPE_ERROR:
02306       dbus_set_error_from_message (&derror, reply);
02307       dbus_set_g_error (error, &derror);
02308       dbus_error_free (&derror);
02309       goto out;
02310       break;
02311     default:
02312       dbus_set_error (&derror, DBUS_ERROR_FAILED,
02313                       "Reply was neither a method return nor an exception");
02314       dbus_set_g_error (error, &derror);
02315       dbus_error_free (&derror);
02316       goto out;
02317       break;
02318     }
02319 
02320   ret = TRUE;
02321  out:
02322   va_end (args);
02323 
02324   if (ret == FALSE)
02325     {
02326       int i;
02327       for (i = 0; i < n_retvals_processed; i++)
02328         {
02329           gpointer retval;
02330 
02331           retval = va_arg (args_unwind, gpointer);
02332 
02333           g_free (retval);
02334         }
02335     }
02336   va_end (args_unwind);
02337 
02338   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
02339 
02340   if (reply)
02341     dbus_message_unref (reply);
02342   return ret;
02343 }
02344 
02367 DBusGProxyCall *
02368 dbus_g_proxy_begin_call (DBusGProxy          *proxy,
02369                          const char          *method,
02370                          DBusGProxyCallNotify notify,
02371                          gpointer             user_data,
02372                          GDestroyNotify       destroy,
02373                          GType                first_arg_type,
02374                          ...)
02375 {
02376   guint call_id;
02377   va_list args;
02378   GValueArray *arg_values;
02379   
02380   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02381   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02382 
02383   va_start (args, first_arg_type);
02384 
02385   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
02386   
02387   call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values,-1);
02388 
02389   g_value_array_free (arg_values);
02390 
02391   va_end (args);
02392 
02393   return DBUS_G_PROXY_ID_TO_CALL (call_id);
02394 }
02395 
02419 DBusGProxyCall *
02420 dbus_g_proxy_begin_call_with_timeout (DBusGProxy          *proxy,
02421                          const char          *method,
02422                          DBusGProxyCallNotify notify,
02423                          gpointer             user_data,
02424                          GDestroyNotify       destroy,
02425                          int timeout,
02426                          GType                first_arg_type,
02427                          ...)
02428 {
02429   guint call_id;
02430   va_list args;
02431   GValueArray *arg_values;
02432 
02433   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02434   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02435 
02436   va_start (args, first_arg_type);
02437 
02438   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
02439 
02440   call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values,timeout);
02441 
02442   g_value_array_free (arg_values);
02443 
02444   va_end (args);
02445 
02446   return DBUS_G_PROXY_ID_TO_CALL (call_id);
02447 }
02448 
02471 gboolean
02472 dbus_g_proxy_end_call (DBusGProxy          *proxy,
02473                        DBusGProxyCall      *call,
02474                        GError             **error,
02475                        GType                first_arg_type,
02476                        ...)
02477 {
02478   gboolean ret;
02479   va_list args;
02480 
02481   va_start (args, first_arg_type);
02482 
02483   ret = dbus_g_proxy_end_call_internal (proxy, GPOINTER_TO_UINT (call), error, first_arg_type, args);
02484 
02485   va_end (args);
02486   
02487   return ret;
02488 }
02489 
02506 gboolean
02507 dbus_g_proxy_call (DBusGProxy        *proxy,
02508                    const char        *method,
02509                    GError           **error,
02510                    GType              first_arg_type,
02511                    ...)
02512 {
02513   gboolean ret;
02514   guint call_id;
02515   va_list args;
02516   GValueArray *in_args;
02517 
02518   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02519   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02520 
02521   va_start (args, first_arg_type);
02522 
02523   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02524 
02525   call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args,-1);
02526 
02527   g_value_array_free (in_args);
02528 
02529   first_arg_type = va_arg (args, GType);
02530   ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
02531 
02532   va_end (args);
02533 
02534   return ret;
02535 }
02536 
02554 gboolean
02555 dbus_g_proxy_call_with_timeout (DBusGProxy        *proxy,
02556                    const char        *method,
02557                    int timeout,
02558                    GError           **error,
02559                    GType              first_arg_type,
02560                    ...)
02561 {
02562   gboolean ret;
02563   guint call_id;
02564   va_list args;
02565   GValueArray *in_args;
02566 
02567   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02568   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02569 
02570   va_start (args, first_arg_type);
02571 
02572   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02573 
02574   call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args,timeout);
02575 
02576   g_value_array_free (in_args);
02577 
02578   first_arg_type = va_arg (args, GType);
02579   ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
02580 
02581   va_end (args);
02582 
02583   return ret;
02584 }
02585 
02598 void
02599 dbus_g_proxy_call_no_reply (DBusGProxy               *proxy,
02600                             const char               *method,
02601                             GType                     first_arg_type,
02602                             ...)
02603 {
02604   DBusMessage *message;
02605   va_list args;
02606   GValueArray *in_args;
02607   DBusGProxyPrivate *priv;
02608   
02609   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02610   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02611 
02612   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02613 
02614   va_start (args, first_arg_type);
02615   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02616 
02617   message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
02618 
02619   g_value_array_free (in_args);
02620   va_end (args);
02621 
02622   if (!message)
02623     goto oom;
02624 
02625   dbus_message_set_no_reply (message, TRUE);
02626 
02627   if (!dbus_connection_send (priv->manager->connection,
02628                              message,
02629                              NULL))
02630     goto oom;
02631   dbus_message_unref (message);
02632   return;
02633   
02634  oom:
02635   g_error ("Out of memory");
02636 }
02637 
02648 void
02649 dbus_g_proxy_cancel_call (DBusGProxy        *proxy,
02650                           DBusGProxyCall    *call)
02651 {
02652   guint call_id;
02653   DBusPendingCall *pending;
02654   DBusGProxyPrivate *priv;
02655   
02656   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02657   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02658 
02659   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02660 
02661   call_id = DBUS_G_PROXY_CALL_TO_ID (call);
02662 
02663   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
02664   g_return_if_fail (pending != NULL);
02665 
02666   dbus_pending_call_cancel (pending);
02667 
02668   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
02669 }
02670 
02691 void
02692 dbus_g_proxy_send (DBusGProxy          *proxy,
02693                    DBusMessage         *message,
02694                    dbus_uint32_t       *client_serial)
02695 {
02696   DBusGProxyPrivate *priv;
02697   
02698   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02699   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02700   
02701   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02702   
02703   if (priv->name)
02704     {
02705       if (!dbus_message_set_destination (message, priv->name))
02706         g_error ("Out of memory");
02707     }
02708   if (priv->path)
02709     {
02710       if (!dbus_message_set_path (message, priv->path))
02711         g_error ("Out of memory");
02712     }
02713   if (priv->interface)
02714     {
02715       if (!dbus_message_set_interface (message, priv->interface))
02716         g_error ("Out of memory");
02717     }
02718   
02719   if (!dbus_connection_send (priv->manager->connection, message, client_serial))
02720     g_error ("Out of memory\n");
02721 }
02722 
02723 static void
02724 array_free_all (gpointer array)
02725 {
02726   g_array_free (array, TRUE);
02727 }
02728 
02739 void
02740 dbus_g_proxy_add_signal  (DBusGProxy        *proxy,
02741                           const char        *signal_name,
02742                           GType              first_type,
02743                           ...)
02744 {
02745   GQuark q;
02746   char *name;
02747   GArray *gtypesig;
02748   GType gtype;
02749   va_list args;
02750   DBusGProxyPrivate *priv;
02751 
02752   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02753   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02754   g_return_if_fail (signal_name != NULL);
02755   
02756   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02757 
02758   name = create_signal_name (priv->interface, signal_name);
02759   
02760   q = g_quark_from_string (name);
02761   
02762   g_return_if_fail (g_datalist_id_get_data (&priv->signal_signatures, q) == NULL);
02763 
02764   gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
02765 
02766   va_start (args, first_type);
02767   gtype = first_type;
02768   while (gtype != G_TYPE_INVALID)
02769     {
02770       g_array_append_val (gtypesig, gtype);
02771       gtype = va_arg (args, GType);
02772     }
02773   va_end (args);
02774 
02775 #ifndef G_DISABLE_CHECKS
02776   if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
02777     g_warning ("No marshaller for signature of signal '%s'", signal_name);
02778 #endif
02779 
02780   
02781   g_datalist_id_set_data_full (&priv->signal_signatures,
02782                                q, gtypesig,
02783                                array_free_all);
02784 
02785   g_free (name);
02786 }
02787 
02800 void
02801 dbus_g_proxy_connect_signal (DBusGProxy             *proxy,
02802                              const char             *signal_name,
02803                              GCallback               handler,
02804                              void                   *data,
02805                              GClosureNotify          free_data_func)
02806 {
02807   char *name;
02808   GClosure *closure;
02809   GQuark q;
02810   DBusGProxyPrivate *priv;
02811 
02812   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02813   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02814   g_return_if_fail (signal_name != NULL);
02815   g_return_if_fail (handler != NULL);
02816   
02817   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02818   name = create_signal_name (priv->interface, signal_name);
02819 
02820   q = g_quark_try_string (name);
02821 
02822 #ifndef G_DISABLE_CHECKS
02823   if (q == 0 || g_datalist_id_get_data (&priv->signal_signatures, q) == NULL)
02824     {
02825       g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
02826       g_free (name);
02827       return;
02828     }
02829 #endif
02830   
02831   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
02832   
02833   g_signal_connect_closure_by_id (G_OBJECT (proxy),
02834                                   signals[RECEIVED],
02835                                   q,
02836                                   closure, FALSE);
02837   
02838   g_free (name);
02839 }
02840 
02851 void
02852 dbus_g_proxy_disconnect_signal (DBusGProxy             *proxy,
02853                                 const char             *signal_name,
02854                                 GCallback               handler,
02855                                 void                   *data)
02856 {
02857   char *name;
02858   GQuark q;
02859   DBusGProxyPrivate *priv;
02860   
02861   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02862   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02863   g_return_if_fail (signal_name != NULL);
02864   g_return_if_fail (handler != NULL);
02865 
02866   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02867   name = create_signal_name (priv->interface, signal_name);
02868 
02869   q = g_quark_try_string (name);
02870   
02871   if (q != 0)
02872     {
02873       g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
02874                                             G_SIGNAL_MATCH_DETAIL |
02875                                             G_SIGNAL_MATCH_FUNC   |
02876                                             G_SIGNAL_MATCH_DATA,
02877                                             signals[RECEIVED],
02878                                             q,
02879                                             NULL,
02880                                             G_CALLBACK (handler), data);
02881     }
02882   else
02883     {
02884       g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
02885                  name);
02886     }
02887 
02888   g_free (name);
02889 }
02890 
02893 #ifdef DBUS_BUILD_TESTS
02894 
02900 gboolean
02901 _dbus_g_proxy_test (void)
02902 {
02903   
02904   
02905   return TRUE;
02906 }
02907 
02908 #endif /* DBUS_BUILD_TESTS */

Generated on Sat Dec 6 19:56:17 2008 for D-BUSGLibBindings by  doxygen 1.5.1