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 static gboolean dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
00112                                                 guint              call_id,
00113                                                 GError           **error,
00114                                                 GType              first_arg_type,
00115                                                 va_list            args);
00116 
00121 typedef struct
00122 {
00123   GSList *proxies; 
00125   char name[4]; 
00130 } DBusGProxyList;
00131 
00137 struct _DBusGProxyManager
00138 {
00139   GStaticMutex lock; 
00140   int refcount;      
00141   DBusConnection *connection; 
00143   DBusGProxy *bus_proxy; 
00145   GHashTable *proxy_lists; 
00148   GHashTable *owner_names; 
00152   GSList *unassociated_proxies;     
00156 };
00157 
00158 static DBusGProxyManager *dbus_g_proxy_manager_ref    (DBusGProxyManager *manager);
00159 static DBusHandlerResult  dbus_g_proxy_manager_filter (DBusConnection    *connection,
00160                                                        DBusMessage       *message,
00161                                                        void              *user_data);
00162 
00163 
00165 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
00166 
00167 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
00168 
00169 static int g_proxy_manager_slot = -1;
00170 
00171 /* Lock controlling get/set manager as data on each connection */
00172 static GStaticMutex connection_g_proxy_lock = G_STATIC_MUTEX_INIT;
00173 
00174 static DBusGProxyManager*
00175 dbus_g_proxy_manager_get (DBusConnection *connection)
00176 {
00177   DBusGProxyManager *manager;
00178 
00179   dbus_connection_allocate_data_slot (&g_proxy_manager_slot);
00180   if (g_proxy_manager_slot < 0)
00181     g_error ("out of memory");
00182   
00183   g_static_mutex_lock (&connection_g_proxy_lock);
00184   
00185   manager = dbus_connection_get_data (connection, g_proxy_manager_slot);
00186   if (manager != NULL)
00187     {
00188       dbus_connection_free_data_slot (&g_proxy_manager_slot);
00189       dbus_g_proxy_manager_ref (manager);
00190       g_static_mutex_unlock (&connection_g_proxy_lock);
00191       return manager;
00192     }
00193   
00194   manager = g_new0 (DBusGProxyManager, 1);
00195 
00196   manager->refcount = 1;
00197   manager->connection = connection;
00198 
00199   g_static_mutex_init (&manager->lock);
00200 
00201   /* Proxy managers keep the connection alive, which means that
00202    * DBusGProxy indirectly does. To free a connection you have to free
00203    * all the proxies referring to it.
00204    */
00205   dbus_connection_ref (manager->connection);
00206 
00207   dbus_connection_set_data (connection, g_proxy_manager_slot,
00208                             manager, NULL);
00209 
00210   dbus_connection_add_filter (connection, dbus_g_proxy_manager_filter,
00211                               manager, NULL);
00212   
00213   g_static_mutex_unlock (&connection_g_proxy_lock);
00214   
00215   return manager;
00216 }
00217 
00218 static DBusGProxyManager * 
00219 dbus_g_proxy_manager_ref (DBusGProxyManager *manager)
00220 {
00221   g_assert (manager != NULL);
00222   g_assert (manager->refcount > 0);
00223 
00224   LOCK_MANAGER (manager);
00225   
00226   manager->refcount += 1;
00227 
00228   UNLOCK_MANAGER (manager);
00229 
00230   return manager;
00231 }
00232 
00233 static void
00234 dbus_g_proxy_manager_unref (DBusGProxyManager *manager)
00235 {
00236   g_assert (manager != NULL);
00237   g_assert (manager->refcount > 0);
00238 
00239   LOCK_MANAGER (manager);
00240   manager->refcount -= 1;
00241   if (manager->refcount == 0)
00242     {
00243       UNLOCK_MANAGER (manager);
00244 
00245       if (manager->bus_proxy)
00246         g_object_unref (manager->bus_proxy);
00247 
00248       if (manager->proxy_lists)
00249         {
00250           /* can't have any proxies left since they hold
00251            * a reference to the proxy manager.
00252            */
00253           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
00254           
00255           g_hash_table_destroy (manager->proxy_lists);
00256           manager->proxy_lists = NULL;
00257 
00258         }
00259 
00260       if (manager->owner_names)
00261         {
00262           /* Since we destroyed all proxies, none can be tracking
00263            * name owners
00264            */
00265           g_assert (g_hash_table_size (manager->owner_names) == 0);
00266 
00267           g_hash_table_destroy (manager->owner_names);
00268           manager->owner_names = NULL;
00269         }
00270 
00271       g_assert (manager->unassociated_proxies == NULL);
00272       
00273       g_static_mutex_free (&manager->lock);
00274 
00275       g_static_mutex_lock (&connection_g_proxy_lock);
00276 
00277       dbus_connection_remove_filter (manager->connection, dbus_g_proxy_manager_filter,
00278                                      manager);
00279       
00280       dbus_connection_set_data (manager->connection,
00281                                 g_proxy_manager_slot,
00282                                 NULL, NULL);
00283 
00284       g_static_mutex_unlock (&connection_g_proxy_lock);
00285       
00286       dbus_connection_unref (manager->connection);
00287       g_free (manager);
00288 
00289       dbus_connection_free_data_slot (&g_proxy_manager_slot);
00290     }
00291   else
00292     {
00293       UNLOCK_MANAGER (manager);
00294     }
00295 }
00296 
00297 static guint
00298 tristring_hash (gconstpointer key)
00299 {
00300   const char *p = key;
00301   guint h = *p;
00302 
00303   if (h)
00304     {
00305       for (p += 1; *p != '\0'; p++)
00306         h = (h << 5) - h + *p;
00307     }
00308 
00309   /* skip nul and do the next substring */
00310   for (p += 1; *p != '\0'; p++)
00311     h = (h << 5) - h + *p;
00312 
00313   /* skip nul again and another substring */
00314   for (p += 1; *p != '\0'; p++)
00315     h = (h << 5) - h + *p;
00316   
00317   return h;
00318 }
00319 
00320 static gboolean
00321 strequal_len (const char *a,
00322               const char *b,
00323               size_t     *lenp)
00324 {
00325   size_t a_len;
00326   size_t b_len;
00327 
00328   a_len = strlen (a);
00329   b_len = strlen (b);
00330 
00331   if (a_len != b_len)
00332     return FALSE;
00333 
00334   if (memcmp (a, b, a_len) != 0)
00335     return FALSE;
00336   
00337   *lenp = a_len;
00338 
00339   return TRUE;
00340 }
00341 
00342 static gboolean
00343 tristring_equal (gconstpointer  a,
00344                  gconstpointer  b)
00345 {
00346   const char *ap = a;
00347   const char *bp = b;
00348   size_t len;
00349 
00350   if (!strequal_len (ap, bp, &len))
00351     return FALSE;
00352 
00353   ap += len + 1;
00354   bp += len + 1;
00355 
00356   if (!strequal_len (ap, bp, &len))
00357     return FALSE;
00358 
00359   ap += len + 1;
00360   bp += len + 1;
00361 
00362   if (strcmp (ap, bp) != 0)
00363     return FALSE;
00364   
00365   return TRUE;
00366 }
00367 
00368 static char*
00369 tristring_alloc_from_strings (size_t      padding_before,
00370                               const char *name,
00371                               const char *path,
00372                               const char *interface)
00373 {
00374   size_t name_len, iface_len, path_len, len;
00375   char *tri;
00376   
00377   if (name)
00378     name_len = strlen (name);
00379   else
00380     name_len = 0;
00381 
00382   path_len = strlen (path);
00383   
00384   iface_len = strlen (interface);
00385 
00386   tri = g_malloc (padding_before + name_len + path_len + iface_len + 3);
00387 
00388   len = padding_before;
00389   
00390   if (name)
00391     memcpy (&tri[len], name, name_len);
00392 
00393   len += name_len;
00394   tri[len] = '\0';
00395   len += 1;
00396 
00397   g_assert (len == (padding_before + name_len + 1));
00398   
00399   memcpy (&tri[len], path, path_len);
00400   len += path_len;
00401   tri[len] = '\0';
00402   len += 1;
00403 
00404   g_assert (len == (padding_before + name_len + path_len + 2));
00405   
00406   memcpy (&tri[len], interface, iface_len);
00407   len += iface_len;
00408   tri[len] = '\0';
00409   len += 1;
00410 
00411   g_assert (len == (padding_before + name_len + path_len + iface_len + 3));
00412 
00413   return tri;
00414 }
00415 
00416 static char*
00417 tristring_from_proxy (DBusGProxy *proxy)
00418 {
00419   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00420 
00421   return tristring_alloc_from_strings (0,
00422                                        priv->name,
00423                                        priv->path,
00424                                        priv->interface);
00425 }
00426 
00427 static char*
00428 tristring_from_message (DBusMessage *message)
00429 {
00430   const char *path;
00431   const char *interface;
00432 
00433   path = dbus_message_get_path (message);
00434   interface = dbus_message_get_interface (message);
00435 
00436   g_assert (path);
00437   g_assert (interface);
00438   
00439   return tristring_alloc_from_strings (0,
00440                                        dbus_message_get_sender (message),
00441                                        path, interface);
00442 }
00443 
00444 static DBusGProxyList*
00445 g_proxy_list_new (DBusGProxy *first_proxy)
00446 {
00447   DBusGProxyList *list;
00448   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(first_proxy);
00449   
00450   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
00451                                                priv->name,
00452                                                priv->path,
00453                                                priv->interface);
00454   list->proxies = NULL;
00455 
00456   return list;
00457 }
00458 
00459 static void
00460 g_proxy_list_free (DBusGProxyList *list)
00461 {
00462   /* we don't hold a reference to the proxies in the list,
00463    * as they ref the GProxyManager
00464    */
00465   g_slist_free (list->proxies);  
00466 
00467   g_free (list);
00468 }
00469 
00470 static char*
00471 g_proxy_get_match_rule (DBusGProxy *proxy)
00472 {
00473   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00474   /* FIXME Escaping is required here */
00475   
00476   if (priv->name)
00477     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
00478                             priv->name, priv->path, priv->interface);
00479   else
00480     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
00481                             priv->path, priv->interface);
00482 }
00483 
00484 typedef struct
00485 {
00486   char *name;
00487   guint refcount;
00488 } DBusGProxyNameOwnerInfo;
00489 
00490 static gint
00491 find_name_in_info (gconstpointer a, gconstpointer b)
00492 {
00493   const DBusGProxyNameOwnerInfo *info = a;
00494   const char *name = b;
00495 
00496   if (info == NULL || info->name == NULL)
00497     return 1;
00498   return strcmp (info->name, name);
00499 }
00500 
00501 typedef struct
00502 {
00503   const char *name;
00504   const char *owner;
00505   DBusGProxyNameOwnerInfo *info;
00506 } DBusGProxyNameOwnerForeachData;
00507 
00508 static void
00509 name_owner_foreach (gpointer key, gpointer val, gpointer data)
00510 {
00511   const char *owner;
00512   DBusGProxyNameOwnerForeachData *foreach_data;
00513   GSList *names;
00514   GSList *link;
00515 
00516   owner = key;
00517   names = val;
00518   foreach_data = data;
00519 
00520   if (foreach_data->owner != NULL)
00521     return;
00522 
00523   g_assert (foreach_data->info == NULL);
00524 
00525   link = g_slist_find_custom (names, foreach_data->name, find_name_in_info);
00526   if (link)
00527     {
00528       foreach_data->owner = owner;
00529       foreach_data->info = link->data;
00530     }
00531 }
00532 
00533 static gboolean
00534 dbus_g_proxy_manager_lookup_name_owner (DBusGProxyManager        *manager,
00535                                         const char               *name,
00536                                         DBusGProxyNameOwnerInfo **info,
00537                                         const char              **owner)
00538 {
00539   DBusGProxyNameOwnerForeachData foreach_data;
00540 
00541   foreach_data.name = name;
00542   foreach_data.owner = NULL;
00543   foreach_data.info = NULL;
00544   
00545   g_hash_table_foreach (manager->owner_names, name_owner_foreach, &foreach_data);
00546 
00547   *info = foreach_data.info;
00548   *owner = foreach_data.owner;
00549   return *info != NULL;
00550 }
00551 
00552 static void
00553 insert_nameinfo (DBusGProxyManager       *manager,
00554                  const char              *owner,
00555                  DBusGProxyNameOwnerInfo *info)
00556 {
00557   GSList *names;
00558   gboolean insert;
00559 
00560   names = g_hash_table_lookup (manager->owner_names, owner);
00561 
00562   /* Only need to g_hash_table_insert the first time */
00563   insert = (names == NULL);
00564 
00565   names = g_slist_append (names, info); 
00566 
00567   if (insert)
00568     g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
00569 }
00570 
00571 static void
00572 dbus_g_proxy_manager_monitor_name_owner (DBusGProxyManager  *manager,
00573                                          const char         *owner,
00574                                          const char         *name)
00575 {
00576   GSList *names;
00577   GSList *link;
00578   DBusGProxyNameOwnerInfo *nameinfo;
00579 
00580   names = g_hash_table_lookup (manager->owner_names, owner);
00581   link = g_slist_find_custom (names, name, find_name_in_info);
00582   
00583   if (!link)
00584     {
00585       nameinfo = g_new0 (DBusGProxyNameOwnerInfo, 1);
00586       nameinfo->name = g_strdup (name);
00587       nameinfo->refcount = 1;
00588 
00589       insert_nameinfo (manager, owner, nameinfo);
00590     }
00591   else
00592     {
00593       nameinfo = link->data;
00594       nameinfo->refcount++;
00595     }
00596 }
00597 
00598 static void
00599 dbus_g_proxy_manager_unmonitor_name_owner (DBusGProxyManager  *manager,
00600                                            const char         *name)
00601 {
00602   DBusGProxyNameOwnerInfo *info;
00603   const char *owner;
00604   gboolean ret;
00605 
00606   ret = dbus_g_proxy_manager_lookup_name_owner (manager, name, &info, &owner);
00607   g_assert (ret);
00608   g_assert (info != NULL);
00609   g_assert (owner != NULL);
00610 
00611   info->refcount--;
00612   if (info->refcount == 0)
00613     {
00614       GSList *names;
00615       GSList *link;
00616 
00617       names = g_hash_table_lookup (manager->owner_names, owner);
00618       link = g_slist_find_custom (names, name, find_name_in_info);
00619       names = g_slist_delete_link (names, link);
00620       if (names != NULL)
00621         g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
00622       else
00623         g_hash_table_remove (manager->owner_names, owner);
00624 
00625       g_free (info->name);
00626       g_free (info);
00627     }
00628 }
00629 
00630 typedef struct
00631 {
00632   const char *name;
00633   GSList *destroyed;
00634 } DBusGProxyUnassociateData;
00635 
00636 static void
00637 unassociate_proxies (gpointer key, gpointer val, gpointer user_data)
00638 {
00639   DBusGProxyList *list;
00640   const char *name;
00641   GSList *tmp;
00642   DBusGProxyUnassociateData *data;
00643 
00644   list = val;
00645   data = user_data;
00646   name = data->name;
00647   
00648   for (tmp = list->proxies; tmp; tmp = tmp->next)
00649     {
00650       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
00651       DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00652       DBusGProxyManager *manager;
00653 
00654       manager = priv->manager;
00655 
00656       if (!strcmp (priv->name, name))
00657         {
00658           if (!priv->for_owner)
00659             {
00660               if (priv->name_call != NULL)
00661                 {
00662                   dbus_g_proxy_cancel_call (manager->bus_proxy,
00663                                             priv->name_call);
00664                   priv->name_call = NULL;
00665                 }
00666 
00667               priv->associated = FALSE;
00668               manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
00669             }
00670           else
00671             {
00672               data->destroyed = g_slist_prepend (data->destroyed, proxy);
00673               /* make contents of list into weak pointers in case the objects
00674                * unref each other when disposing */
00675               g_object_add_weak_pointer (G_OBJECT (proxy),
00676                   &(data->destroyed->data));
00677             }
00678         }
00679     }
00680 }
00681 
00682 static void
00683 dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager  *manager,
00684                                          const char         *name,
00685                                          const char         *prev_owner,
00686                                          const char         *new_owner)
00687 {
00688   GSList *names;
00689           
00690   if (prev_owner[0] == '\0')
00691     {
00692       GSList *tmp;
00693       GSList *removed;
00694 
00695       /* We have a new service, look at unassociated proxies */
00696 
00697       removed = NULL;
00698 
00699       for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
00700         {
00701           DBusGProxy *proxy = tmp->data;
00702           DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00703 
00704           if (!strcmp (priv->name, name))
00705             {
00706               removed = g_slist_prepend (removed, tmp);
00707               
00708               dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
00709               priv->associated = TRUE;
00710             }
00711         }
00712 
00713       for (tmp = removed; tmp; tmp = tmp->next)
00714         manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
00715       g_slist_free (removed);
00716     }
00717   else
00718     {
00719       DBusGProxyNameOwnerInfo *info;
00720       GSList *link;
00721 
00722       /* Name owner changed or deleted */ 
00723 
00724       names = g_hash_table_lookup (manager->owner_names, prev_owner);
00725 
00726       info = NULL;
00727       if (names != NULL)
00728         {
00729           link = g_slist_find_custom (names, name, find_name_in_info);
00730 
00731           if (link != NULL)
00732             {
00733               info = link->data;
00734           
00735               names = g_slist_delete_link (names, link);
00736 
00737               if (names == NULL)
00738                 g_hash_table_remove (manager->owner_names, prev_owner);
00739             }
00740         }
00741 
00742       if (new_owner[0] == '\0')
00743         {
00744           DBusGProxyUnassociateData data;
00745           GSList *tmp;
00746 
00747           data.name = name;
00748           data.destroyed = NULL;
00749 
00750           /* A service went away, we need to unassociate proxies */
00751           g_hash_table_foreach (manager->proxy_lists,
00752                                 unassociate_proxies, &data);
00753 
00754           UNLOCK_MANAGER (manager);
00755 
00756           /* the destroyed list's data pointers are weak pointers, so that we
00757            * don't end up calling destroy on proxies which have already been
00758            * freed up as a result of other ones being destroyed */
00759           for (tmp = data.destroyed; tmp; tmp = tmp->next)
00760             if (tmp->data != NULL)
00761               {
00762                 g_object_remove_weak_pointer (G_OBJECT (tmp->data),
00763                     &(tmp->data));
00764                 dbus_g_proxy_destroy (tmp->data);
00765               }
00766           g_slist_free (data.destroyed);
00767 
00768           LOCK_MANAGER (manager);
00769 
00770           if (info)
00771             {
00772               g_free (info->name);
00773               g_free (info);
00774             }
00775         }
00776       else if (info)
00777         {
00778           insert_nameinfo (manager, new_owner, info);
00779         }
00780     }
00781 }
00782 
00783 static void
00784 got_name_owner_cb (DBusGProxy       *bus_proxy,
00785                    DBusGProxyCall   *call,
00786                    void             *user_data)
00787 {
00788   DBusGProxy *proxy = user_data;
00789   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00790   GError *error;
00791   char *owner;
00792 
00793   error = NULL;
00794   owner = NULL;
00795 
00796   LOCK_MANAGER (priv->manager);
00797 
00798   if (!dbus_g_proxy_end_call (bus_proxy, call, &error,
00799                               G_TYPE_STRING, &owner,
00800                               G_TYPE_INVALID))
00801     {
00802       if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
00803         {
00804           priv->manager->unassociated_proxies = g_slist_prepend (priv->manager->unassociated_proxies, proxy);
00805         }
00806       else
00807         g_warning ("Couldn't get name owner (%s): %s",
00808                    dbus_g_error_get_name (error),
00809                    error->message);
00810 
00811       g_clear_error (&error);
00812       goto out;
00813     }
00814   else
00815     {
00816       dbus_g_proxy_manager_monitor_name_owner (priv->manager, owner, priv->name);
00817       priv->associated = TRUE;
00818     }
00819 
00820  out:
00821   priv->name_call = NULL;
00822   UNLOCK_MANAGER (priv->manager);
00823   g_free (owner);
00824 }
00825 
00826 static char *
00827 get_name_owner (DBusConnection     *connection,
00828                 const char         *name,
00829                 GError            **error)
00830 {
00831   DBusError derror;
00832   DBusMessage *request, *reply;
00833   char *base_name;
00834   
00835   dbus_error_init (&derror);
00836 
00837   base_name = NULL;
00838   reply = NULL;
00839 
00840   request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
00841                                           DBUS_PATH_DBUS,
00842                                           DBUS_INTERFACE_DBUS,
00843                                           "GetNameOwner");
00844   if (request == NULL)
00845     g_error ("Out of memory");
00846   
00847   if (!dbus_message_append_args (request, 
00848                                  DBUS_TYPE_STRING, &name, 
00849                                  DBUS_TYPE_INVALID))
00850     g_error ("Out of memory");
00851 
00852   reply =
00853     dbus_connection_send_with_reply_and_block (connection,
00854                                                request,
00855                                                2000, &derror);
00856   if (reply == NULL)
00857     goto error;
00858 
00859   if (dbus_set_error_from_message (&derror, reply))
00860     goto error;
00861 
00862   if (!dbus_message_get_args (reply, &derror, 
00863                               DBUS_TYPE_STRING, &base_name, 
00864                               DBUS_TYPE_INVALID))
00865     goto error;
00866 
00867   base_name = g_strdup (base_name);
00868   goto out;
00869 
00870  error:
00871   g_assert (dbus_error_is_set (&derror));
00872   dbus_set_g_error (error, &derror);
00873   dbus_error_free (&derror);
00874 
00875  out:
00876   if (request)
00877     dbus_message_unref (request);
00878   if (reply)
00879     dbus_message_unref (reply);
00880 
00881   return base_name;
00882 }
00883 
00884 
00885 static void
00886 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
00887                                DBusGProxy        *proxy)
00888 {
00889   DBusGProxyList *list;
00890   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00891 
00892   LOCK_MANAGER (manager);
00893 
00894   if (manager->proxy_lists == NULL)
00895     {
00896       g_assert (manager->owner_names == NULL);
00897 
00898       list = NULL;
00899       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
00900                                                     tristring_equal,
00901                                                     NULL,
00902                                                     (GFreeFunc) g_proxy_list_free);
00903       manager->owner_names = g_hash_table_new_full (g_str_hash,
00904                                                     g_str_equal,
00905                                                     g_free,
00906                                                     NULL);
00907       /* FIXME - for now we listen for all NameOwnerChanged; once
00908        * Anders' detail patch lands we should add individual rules
00909        */
00910       dbus_bus_add_match (manager->connection,
00911                           "type='signal',sender='" DBUS_SERVICE_DBUS
00912                           "',path='" DBUS_PATH_DBUS
00913                           "',interface='" DBUS_INTERFACE_DBUS
00914                           "',member='NameOwnerChanged'",
00915                           NULL);
00916     }
00917   else
00918     {
00919       char *tri;
00920 
00921       tri = tristring_from_proxy (proxy);
00922       
00923       list = g_hash_table_lookup (manager->proxy_lists, tri);
00924 
00925       g_free (tri);
00926     }
00927       
00928   if (list == NULL)
00929     {
00930       list = g_proxy_list_new (proxy);
00931       
00932       g_hash_table_replace (manager->proxy_lists,
00933                             list->name, list);
00934     }
00935 
00936   if (list->proxies == NULL)
00937     {
00938       /* We have to add the match rule to the server,
00939        * but FIXME only if the server is a message bus,
00940        * not if it's a peer.
00941        */
00942       char *rule;
00943 
00944       rule = g_proxy_get_match_rule (proxy);
00945       
00946       /* We don't check for errors; it's not like anyone would handle them,
00947        * and we don't want a round trip here.
00948        */
00949       dbus_bus_add_match (manager->connection,
00950                           rule, NULL);
00951 
00952       g_free (rule);
00953     }
00954 
00955   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00956   
00957   list->proxies = g_slist_prepend (list->proxies, proxy);
00958 
00959   if (!priv->for_owner)
00960     {
00961       const char *owner;
00962       DBusGProxyNameOwnerInfo *info;
00963 
00964       if (!dbus_g_proxy_manager_lookup_name_owner (manager, priv->name, &info, &owner))
00965         {
00966           priv->name_call = manager_begin_bus_call (manager, "GetNameOwner",
00967                                                      got_name_owner_cb,
00968                                                      proxy, NULL,
00969                                                      G_TYPE_STRING,
00970                                                      priv->name, 
00971                                                      G_TYPE_INVALID);
00972           
00973           priv->associated = FALSE;
00974         }
00975       else
00976         {
00977           info->refcount++;
00978           priv->associated = TRUE;
00979         }
00980     }
00981   
00982   UNLOCK_MANAGER (manager);
00983 }
00984 
00985 static void
00986 dbus_g_proxy_manager_unregister (DBusGProxyManager *manager,
00987                                 DBusGProxy        *proxy)
00988 {
00989   DBusGProxyList *list;
00990   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
00991   char *tri;
00992   
00993   LOCK_MANAGER (manager);
00994 
00995 #ifndef G_DISABLE_CHECKS
00996   if (manager->proxy_lists == NULL)
00997     {
00998       g_warning ("Trying to unregister a proxy but there aren't any registered");
00999       return;
01000     }
01001 #endif
01002 
01003   tri = tristring_from_proxy (proxy);
01004   
01005   list = g_hash_table_lookup (manager->proxy_lists, tri);
01006 
01007 #ifndef G_DISABLE_CHECKS
01008   if (list == NULL)
01009     {
01010       g_warning ("Trying to unregister a proxy but it isn't registered");
01011       return;
01012     }
01013 #endif
01014 
01015   g_assert (g_slist_find (list->proxies, proxy) != NULL);
01016   
01017   list->proxies = g_slist_remove (list->proxies, proxy);
01018 
01019   g_assert (g_slist_find (list->proxies, proxy) == NULL);
01020 
01021   if (!priv->for_owner)
01022     {
01023       if (!priv->associated)
01024         {
01025           GSList *link;
01026 
01027           if (priv->name_call != 0)
01028             {
01029               dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
01030               priv->name_call = 0;
01031             }
01032           else
01033             {
01034               link = g_slist_find (manager->unassociated_proxies, proxy);
01035               g_assert (link != NULL);
01036 
01037               manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, link);
01038             }
01039         }
01040       else
01041         {
01042           g_assert (priv->name_call == 0);
01043           
01044           dbus_g_proxy_manager_unmonitor_name_owner (manager, priv->name);
01045         }
01046     }
01047 
01048   if (list->proxies == NULL)
01049     {
01050       char *rule;
01051       g_hash_table_remove (manager->proxy_lists,
01052                            tri);
01053       list = NULL;
01054 
01055       rule = g_proxy_get_match_rule (proxy);
01056       dbus_bus_remove_match (manager->connection,
01057                              rule, NULL);
01058       g_free (rule);
01059     }
01060   
01061   if (g_hash_table_size (manager->proxy_lists) == 0)
01062     {
01063       g_hash_table_destroy (manager->proxy_lists);
01064       manager->proxy_lists = NULL;
01065     }
01066 
01067   g_free (tri);
01068       
01069   UNLOCK_MANAGER (manager);
01070 }
01071 
01072 static void
01073 list_proxies_foreach (gpointer key,
01074                       gpointer value,
01075                       gpointer user_data)
01076 {
01077   DBusGProxyList *list;
01078   GSList **ret;
01079   GSList *tmp;
01080   
01081   list = value;
01082   ret = user_data;
01083 
01084   tmp = list->proxies;
01085   while (tmp != NULL)
01086     {
01087       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
01088 
01089       g_object_ref (proxy);
01090       *ret = g_slist_prepend (*ret, proxy);
01091       
01092       tmp = tmp->next;
01093     }
01094 }
01095 
01096 static GSList*
01097 dbus_g_proxy_manager_list_all (DBusGProxyManager *manager)
01098 {
01099   GSList *ret;
01100 
01101   ret = NULL;
01102 
01103   if (manager->proxy_lists)
01104     {
01105       g_hash_table_foreach (manager->proxy_lists,
01106                             list_proxies_foreach,
01107                             &ret);
01108     }
01109 
01110   return ret;
01111 }
01112 
01113 static DBusHandlerResult
01114 dbus_g_proxy_manager_filter (DBusConnection    *connection,
01115                              DBusMessage       *message,
01116                              void              *user_data)
01117 {
01118   DBusGProxyManager *manager;
01119   
01120   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
01121     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01122 
01123   manager = user_data;
01124 
01125   dbus_g_proxy_manager_ref (manager);
01126   
01127   LOCK_MANAGER (manager);
01128   
01129   if (dbus_message_is_signal (message,
01130                               DBUS_INTERFACE_LOCAL,
01131                               "Disconnected"))
01132     {
01133       /* Destroy all the proxies, quite possibly resulting in unreferencing
01134        * the proxy manager and the connection as well.
01135        */
01136       GSList *all;
01137       GSList *tmp;
01138 
01139       all = dbus_g_proxy_manager_list_all (manager);
01140 
01141       tmp = all;
01142       while (tmp != NULL)
01143         {
01144           DBusGProxy *proxy;
01145 
01146           proxy = DBUS_G_PROXY (tmp->data);
01147 
01148           UNLOCK_MANAGER (manager);
01149           dbus_g_proxy_destroy (proxy);
01150           g_object_unref (G_OBJECT (proxy));
01151           LOCK_MANAGER (manager);
01152           
01153           tmp = tmp->next;
01154         }
01155 
01156       g_slist_free (all);
01157 
01158 #ifndef G_DISABLE_CHECKS
01159       if (manager->proxy_lists != NULL)
01160         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.");
01161 #endif
01162     }
01163   else
01164     {
01165       char *tri;
01166       GSList *full_list;
01167       GSList *owned_names;
01168       GSList *tmp;
01169       const char *sender;
01170 
01171       /* First we handle NameOwnerChanged internally */
01172       if (dbus_message_is_signal (message,
01173                                   DBUS_INTERFACE_DBUS,
01174                                   "NameOwnerChanged"))
01175         {
01176           const char *name;
01177           const char *prev_owner;
01178           const char *new_owner;
01179           DBusError derr;
01180 
01181           dbus_error_init (&derr);
01182           if (!dbus_message_get_args (message,
01183                                       &derr,
01184                                       DBUS_TYPE_STRING,
01185                                       &name,
01186                                       DBUS_TYPE_STRING,
01187                                       &prev_owner,
01188                                       DBUS_TYPE_STRING,
01189                                       &new_owner,
01190                                       DBUS_TYPE_INVALID))
01191             {
01192               /* Ignore this error */
01193               dbus_error_free (&derr);
01194             }
01195           else if (manager->owner_names != NULL)
01196             {
01197               dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
01198             }
01199         }
01200 
01201       sender = dbus_message_get_sender (message);
01202 
01203       /* dbus spec requires these, libdbus validates */
01204       g_assert (sender != NULL);
01205       g_assert (dbus_message_get_path (message) != NULL);
01206       g_assert (dbus_message_get_interface (message) != NULL);
01207       g_assert (dbus_message_get_member (message) != NULL);
01208       
01209       tri = tristring_from_message (message);
01210 
01211       if (manager->proxy_lists)
01212         {
01213           DBusGProxyList *owner_list;
01214           owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01215           if (owner_list)
01216             full_list = g_slist_copy (owner_list->proxies);
01217           else
01218             full_list = NULL;
01219         }
01220       else
01221         full_list = NULL;
01222 
01223       g_free (tri);
01224 
01225       if (manager->owner_names)
01226         {
01227           owned_names = g_hash_table_lookup (manager->owner_names, sender);
01228           for (tmp = owned_names; tmp; tmp = tmp->next)
01229             {
01230               DBusGProxyList *owner_list;
01231               DBusGProxyNameOwnerInfo *nameinfo;
01232 
01233               nameinfo = tmp->data;
01234               g_assert (nameinfo->refcount > 0);
01235               tri = tristring_alloc_from_strings (0, nameinfo->name,
01236                                                   dbus_message_get_path (message),
01237                                                   dbus_message_get_interface (message));
01238 
01239               owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01240               if (owner_list != NULL)
01241                 full_list = g_slist_concat (full_list, g_slist_copy (owner_list->proxies));
01242               g_free (tri);
01243             }
01244         }
01245 
01246 #if 0
01247       g_print ("proxy got %s,%s,%s = list %p\n",
01248                tri,
01249                tri + strlen (tri) + 1,
01250                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
01251                list);
01252 #endif
01253       
01254       /* Emit the signal */
01255       
01256       g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
01257       
01258       for (tmp = full_list; tmp; tmp = tmp->next)
01259         {
01260           DBusGProxy *proxy;
01261           
01262           proxy = DBUS_G_PROXY (tmp->data);
01263           
01264           UNLOCK_MANAGER (manager);
01265           dbus_g_proxy_emit_remote_signal (proxy, message);
01266           g_object_unref (G_OBJECT (proxy));
01267           LOCK_MANAGER (manager);
01268         }
01269       g_slist_free (full_list);
01270     }
01271 
01272   UNLOCK_MANAGER (manager);
01273   dbus_g_proxy_manager_unref (manager);
01274   
01275   /* "Handling" signals doesn't make sense, they are for everyone
01276    * who cares
01277    */
01278   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01279 }
01280 
01281 
01282 
01283 /*      ---------- DBusGProxy --------------   */
01284 #define DBUS_G_PROXY_DESTROYED(proxy)  (DBUS_G_PROXY_GET_PRIVATE(proxy)->manager == NULL)
01285 
01286 static void
01287 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
01288                                       GValue       *return_value,
01289                                       guint         n_param_values,
01290                                       const GValue *param_values,
01291                                       gpointer      invocation_hint,
01292                                       gpointer      marshal_data);
01293 enum
01294 {
01295   PROP_0,
01296   PROP_NAME,
01297   PROP_PATH,
01298   PROP_INTERFACE,
01299   PROP_CONNECTION
01300 };
01301 
01302 enum
01303 {
01304   DESTROY,
01305   RECEIVED,
01306   LAST_SIGNAL
01307 };
01308 
01309 static void *parent_class;
01310 static guint signals[LAST_SIGNAL] = { 0 };
01311 
01312 static void
01313 dbus_g_proxy_init (DBusGProxy *proxy)
01314 {
01315   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01316   
01317   g_datalist_init (&priv->signal_signatures);
01318   priv->pending_calls = g_hash_table_new_full (NULL, NULL, NULL,
01319                                 (GDestroyNotify) dbus_pending_call_unref);
01320   priv->name_call = 0;
01321   priv->associated = FALSE;
01322 }
01323 
01324 static GObject *
01325 dbus_g_proxy_constructor (GType                  type,
01326                           guint                  n_construct_properties,
01327                           GObjectConstructParam *construct_properties)
01328 {
01329   DBusGProxy *proxy;
01330   DBusGProxyClass *klass;
01331   GObjectClass *parent_class;
01332   DBusGProxyPrivate *priv;
01333 
01334   klass = DBUS_G_PROXY_CLASS (g_type_class_peek (DBUS_TYPE_G_PROXY));
01335 
01336   parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
01337 
01338   proxy = DBUS_G_PROXY (parent_class->constructor (type, n_construct_properties,
01339                                                     construct_properties));
01340 
01341   priv = DBUS_G_PROXY_GET_PRIVATE (proxy);
01342 
01343   /* if these assertions fail, a deriving class has not set our required
01344    * parameters - our own public constructors do return_if_fail checks
01345    * on these parameters being provided. unfortunately we can't assert
01346    * for manager because it's allowed to be NULL when tha mangager is
01347    * setting up a bus proxy for its own calls */
01348   g_assert (priv->name != NULL);
01349   g_assert (priv->path != NULL);
01350   g_assert (priv->interface != NULL);
01351 
01352   if (priv->manager != NULL)
01353     {
01354       dbus_g_proxy_manager_register (priv->manager, proxy);
01355     }
01356 
01357   return G_OBJECT (proxy);
01358 }
01359 
01360 static void
01361 dbus_g_proxy_class_init (DBusGProxyClass *klass)
01362 {
01363   GObjectClass *object_class = G_OBJECT_CLASS (klass);
01364   
01365   parent_class = g_type_class_peek_parent (klass);
01366 
01367   g_type_class_add_private (klass, sizeof (DBusGProxyPrivate));
01368 
01369   object_class->set_property = dbus_g_proxy_set_property;
01370   object_class->get_property = dbus_g_proxy_get_property;
01371 
01372   g_object_class_install_property (object_class,
01373                                    PROP_NAME,
01374                                    g_param_spec_string ("name",
01375                                                         "name",
01376                                                         "name",
01377                                                         NULL,
01378                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01379 
01380   g_object_class_install_property (object_class,
01381                                    PROP_PATH,
01382                                    g_param_spec_string ("path",
01383                                                         "path",
01384                                                         "path",
01385                                                         NULL,
01386                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01387 
01388   g_object_class_install_property (object_class,
01389                                    PROP_INTERFACE,
01390                                    g_param_spec_string ("interface",
01391                                                         "interface",
01392                                                         "interface",
01393                                                         NULL,
01394                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01395   
01396   g_object_class_install_property (object_class,
01397                                    PROP_CONNECTION,
01398                                    g_param_spec_boxed ("connection",
01399                                                         "connection",
01400                                                         "connection",
01401                                                         DBUS_TYPE_G_CONNECTION,
01402                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01403   
01404   object_class->finalize = dbus_g_proxy_finalize;
01405   object_class->dispose = dbus_g_proxy_dispose;
01406   object_class->constructor = dbus_g_proxy_constructor;
01407   
01408   signals[DESTROY] =
01409     g_signal_new ("destroy",
01410                   G_OBJECT_CLASS_TYPE (object_class),
01411                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
01412                   0,
01413                   NULL, NULL,
01414                   g_cclosure_marshal_VOID__VOID,
01415                   G_TYPE_NONE, 0);
01416 
01417   signals[RECEIVED] =
01418     g_signal_new ("received",
01419                   G_OBJECT_CLASS_TYPE (object_class),
01420                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
01421                   0,
01422                   NULL, NULL,
01423                   marshal_dbus_message_to_g_marshaller,
01424                   G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
01425 }
01426 
01427 static void
01428 cancel_pending_call (gpointer key, gpointer val, gpointer data)
01429 {
01430   DBusGProxyCall *call = key;
01431   DBusGProxy *proxy = data;
01432 
01433   dbus_g_proxy_cancel_call (proxy, call);
01434 }
01435 
01436 static void
01437 dbus_g_proxy_dispose (GObject *object)
01438 {
01439   DBusGProxy *proxy = DBUS_G_PROXY (object);
01440   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01441 
01442   if (priv->pending_calls == NULL) 
01443     {
01444       return;
01445     }
01446 
01447   /* Cancel outgoing pending calls */
01448   g_hash_table_foreach (priv->pending_calls, cancel_pending_call, proxy);
01449   g_hash_table_destroy (priv->pending_calls);
01450   priv->pending_calls = NULL;
01451 
01452   if (priv->manager && proxy != priv->manager->bus_proxy)
01453     {
01454       dbus_g_proxy_manager_unregister (priv->manager, proxy);
01455       dbus_g_proxy_manager_unref (priv->manager);
01456     }
01457   priv->manager = NULL;
01458   
01459   g_datalist_clear (&priv->signal_signatures);
01460   
01461   g_signal_emit (object, signals[DESTROY], 0);
01462   
01463   G_OBJECT_CLASS (parent_class)->dispose (object);
01464 }
01465 
01466 static void
01467 dbus_g_proxy_finalize (GObject *object)
01468 {
01469   DBusGProxy *proxy = DBUS_G_PROXY (object);
01470   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01471   
01472   g_return_if_fail (DBUS_G_PROXY_DESTROYED (proxy));
01473   
01474   g_free (priv->name);
01475   g_free (priv->path);
01476   g_free (priv->interface);
01477   
01478   G_OBJECT_CLASS (parent_class)->finalize (object);
01479 }
01480 
01481 static void
01482 dbus_g_proxy_destroy (DBusGProxy *proxy)
01483 {
01484   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
01485    * from GtkObject?
01486    */
01487   g_object_run_dispose (G_OBJECT (proxy));
01488 }
01489 
01490 static void
01491 dbus_g_proxy_set_property (GObject *object,
01492                            guint prop_id,
01493                            const GValue *value,
01494                            GParamSpec *pspec)
01495 {
01496   DBusGProxy *proxy = DBUS_G_PROXY (object);
01497   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01498   DBusGConnection *connection;
01499 
01500   switch (prop_id)
01501     {
01502     case PROP_NAME:
01503       priv->name = g_strdup (g_value_get_string (value));
01504       priv->for_owner = (priv->name[0] == ':');
01505       break;
01506     case PROP_PATH:
01507       priv->path = g_strdup (g_value_get_string (value));
01508       break;
01509     case PROP_INTERFACE:
01510       priv->interface = g_strdup (g_value_get_string (value));
01511       break;
01512     case PROP_CONNECTION:
01513       connection = g_value_get_boxed (value);
01514       if (connection != NULL)
01515         {
01516           priv->manager = dbus_g_proxy_manager_get (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
01517         }
01518       break;
01519     default:
01520       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01521       break;
01522     }
01523 }
01524 
01525 static void 
01526 dbus_g_proxy_get_property (GObject *object,
01527                            guint prop_id,
01528                            GValue *value,
01529                            GParamSpec *pspec)
01530 {
01531   DBusGProxy *proxy = DBUS_G_PROXY (object);
01532   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01533 
01534   switch (prop_id)
01535     {
01536     case PROP_NAME:
01537       g_value_set_string (value, priv->name);
01538       break;
01539     case PROP_PATH:
01540       g_value_set_string (value, priv->path);
01541       break;
01542     case PROP_INTERFACE:
01543       g_value_set_string (value, priv->interface);
01544       break;
01545     case PROP_CONNECTION:
01546       g_value_set_boxed (value, DBUS_G_CONNECTION_FROM_CONNECTION(priv->manager->connection));
01547       break;
01548     default:
01549       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01550       break;
01551     }
01552 }
01553 
01554 /* this is to avoid people using g_signal_connect() directly,
01555  * to avoid confusion with local signal names, and because
01556  * of the horribly broken current setup (signals are added
01557  * globally to all proxies)
01558  */
01559 static char*
01560 create_signal_name (const char *interface,
01561                     const char *signal)
01562 {
01563   GString *str;
01564   char *p;
01565 
01566   str = g_string_new (interface);
01567 
01568   g_string_append (str, "-");
01569   
01570   g_string_append (str, signal);
01571 
01572   /* GLib will silently barf on '.' in signal names */
01573   p = str->str;
01574   while (*p)
01575     {
01576       if (*p == '.')
01577         *p = '-';
01578       ++p;
01579     }
01580   
01581   return g_string_free (str, FALSE);
01582 }
01583 
01584 static void
01585 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
01586                                       GValue       *return_value,
01587                                       guint         n_param_values,
01588                                       const GValue *param_values,
01589                                       gpointer      invocation_hint,
01590                                       gpointer      marshal_data)
01591 {
01592   /* Incoming here we have three params, the instance (Proxy), the
01593    * DBusMessage, the signature. We want to convert that to an
01594    * expanded GValue array, then call an appropriate normal GLib
01595    * marshaller.
01596    */
01597 #define MAX_SIGNATURE_ARGS 20
01598   GValueArray *value_array;
01599   GSignalCMarshaller c_marshaller;
01600   DBusGProxy *proxy;
01601   DBusMessage *message;
01602   GArray *gsignature;
01603   const GType *types;
01604   DBusGProxyPrivate *priv;
01605 
01606   g_assert (n_param_values == 3);
01607 
01608   proxy = g_value_get_object (&param_values[0]);
01609   message = g_value_get_boxed (&param_values[1]);
01610   gsignature = g_value_get_pointer (&param_values[2]);
01611 
01612   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
01613   g_return_if_fail (message != NULL);
01614   g_return_if_fail (gsignature != NULL);
01615 
01616   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01617 
01618   c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
01619                                                   (GType*) gsignature->data);
01620 
01621   g_return_if_fail (c_marshaller != NULL);
01622   
01623   {
01624     DBusGValueMarshalCtx context;
01625     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
01626     context.proxy = proxy;
01627 
01628     types = (const GType*) gsignature->data;
01629     value_array = _dbus_gvalue_demarshal_message (&context, message,
01630                                                  gsignature->len, types, NULL);
01631   }
01632 
01633   if (value_array == NULL)
01634     return;
01635   
01636   g_value_array_prepend (value_array, NULL);
01637   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_FROM_INSTANCE (proxy));
01638   g_value_set_instance (g_value_array_get_nth (value_array, 0), proxy);
01639 
01640   (* c_marshaller) (closure, return_value, value_array->n_values,
01641                     value_array->values, invocation_hint, marshal_data);
01642   
01643   g_value_array_free (value_array);
01644 }
01645 
01646 static void
01647 dbus_g_proxy_emit_remote_signal (DBusGProxy  *proxy,
01648                                  DBusMessage *message)
01649 {
01650   const char *interface;
01651   const char *signal;
01652   char *name;
01653   GQuark q;
01654   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01655   GArray *msg_gsignature = NULL;
01656 
01657   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
01658 
01659   interface = dbus_message_get_interface (message);
01660   signal = dbus_message_get_member (message);
01661 
01662   g_assert (interface != NULL);
01663   g_assert (signal != NULL);
01664 
01665   name = create_signal_name (interface, signal);
01666 
01667   /* If the quark isn't preexisting, there's no way there
01668    * are any handlers connected. We don't want to create
01669    * extra quarks for every possible signal.
01670    */
01671   q = g_quark_try_string (name);
01672 
01673   if (q != 0)
01674     {
01675       GArray *gsignature;
01676       guint i;
01677       
01678       gsignature = g_datalist_id_get_data (&priv->signal_signatures, q);
01679       if (gsignature == NULL)
01680         goto out;
01681       
01682       msg_gsignature = _dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
01683                                                        TRUE);
01684       for (i = 0; i < gsignature->len; i++)
01685         {
01686           if (msg_gsignature->len == i
01687               || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
01688             goto mismatch;
01689         }
01690       if (msg_gsignature->len != i)
01691         goto mismatch;
01692       
01693       g_signal_emit (proxy,
01694                      signals[RECEIVED],
01695                      q,
01696                      message,
01697                      msg_gsignature);
01698     }
01699 
01700  out:
01701   g_free (name);
01702   if (msg_gsignature)
01703     g_array_free (msg_gsignature, TRUE);
01704   return;
01705  mismatch:
01706 #if 0
01707   /* Don't spew on remote errors */
01708   g_warning ("Unexpected message signature '%s' for signal '%s'\n",
01709              dbus_message_get_signature (message),
01710              name);
01711 #endif
01712   goto out;
01713 }
01714 
01715 typedef struct
01716 {
01717   DBusGProxy *proxy;
01718   guint call_id;
01719   DBusGProxyCallNotify func;
01720   void *data;
01721   GDestroyNotify free_data_func;
01722 } GPendingNotifyClosure;
01723 
01724 static void
01725 d_pending_call_notify (DBusPendingCall *dcall,
01726                        void            *data)
01727 {
01728   GPendingNotifyClosure *closure = data;
01729 
01730   (* closure->func) (closure->proxy, DBUS_G_PROXY_ID_TO_CALL (closure->call_id), closure->data);
01731 }
01732 
01733 static void
01734 d_pending_call_free (void *data)
01735 {
01736   GPendingNotifyClosure *closure = data;
01737   
01738   if (closure->free_data_func)
01739     (* closure->free_data_func) (closure->data);
01740 
01741   g_free (closure);
01742 }
01743   
01744 #define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
01745 do { \
01746   GType valtype; \
01747   int i = 0; \
01748   VALARRAY = g_value_array_new (6); \
01749   valtype = FIRST_ARG_TYPE; \
01750   while (valtype != G_TYPE_INVALID) \
01751     { \
01752       const char *collect_err; \
01753       GValue *val; \
01754       g_value_array_append (VALARRAY, NULL); \
01755       val = g_value_array_get_nth (VALARRAY, i); \
01756       g_value_init (val, valtype); \
01757       collect_err = NULL; \
01758       G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
01759       valtype = va_arg (ARGS, GType); \
01760       i++; \
01761     } \
01762 } while (0)
01763 
01764 DBusGProxyCall *
01765 manager_begin_bus_call (DBusGProxyManager    *manager,
01766                         const char           *method,
01767                         DBusGProxyCallNotify  notify,
01768                         gpointer              user_data,
01769                         GDestroyNotify        destroy,
01770                         GType                 first_arg_type,
01771                         ...)
01772 {
01773   DBusGProxyCall *call;
01774   DBusGProxyPrivate *priv;
01775   va_list args;
01776   GValueArray *arg_values;
01777   
01778   va_start (args, first_arg_type);
01779 
01780   if (!manager->bus_proxy)
01781     {
01782       manager->bus_proxy = g_object_new (DBUS_TYPE_G_PROXY,
01783                                          "name", DBUS_SERVICE_DBUS,
01784                                          "path", DBUS_PATH_DBUS,
01785                                          "interface", DBUS_INTERFACE_DBUS,
01786                                          NULL);
01787       priv = DBUS_G_PROXY_GET_PRIVATE(manager->bus_proxy);
01788       priv->manager = manager;
01789     }
01790 
01791   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
01792   
01793   call = DBUS_G_PROXY_ID_TO_CALL (dbus_g_proxy_begin_call_internal (manager->bus_proxy, method, notify, user_data, destroy, arg_values));
01794 
01795   g_value_array_free (arg_values);
01796 
01797   va_end (args);
01798 
01799   return call;
01800 }
01801 
01823 GType
01824 dbus_g_proxy_get_type (void)
01825 {
01826   static GType object_type = 0;
01827 
01828   if (!object_type)
01829     {
01830       static const GTypeInfo object_info =
01831         {
01832           sizeof (DBusGProxyClass),
01833           (GBaseInitFunc) NULL,
01834           (GBaseFinalizeFunc) NULL,
01835           (GClassInitFunc) dbus_g_proxy_class_init,
01836           NULL,           /* class_finalize */
01837           NULL,           /* class_data */
01838           sizeof (DBusGProxy),
01839           0,              /* n_preallocs */
01840           (GInstanceInitFunc) dbus_g_proxy_init,
01841         };
01842       
01843       object_type = g_type_register_static (G_TYPE_OBJECT,
01844                                             "DBusGProxy",
01845                                             &object_info, 0);
01846     }
01847   
01848   return object_type;
01849 }
01850 
01851 static DBusGProxy*
01852 dbus_g_proxy_new (DBusGConnection *connection,
01853                   const char      *name,
01854                   const char      *path_name,
01855                   const char      *interface_name)
01856 {
01857   DBusGProxy *proxy;
01858 
01859   g_assert (connection != NULL);
01860   
01861   proxy = g_object_new (DBUS_TYPE_G_PROXY, 
01862                         "name", name, 
01863                         "path", path_name, 
01864                         "interface", interface_name, 
01865                         "connection", connection, NULL);
01866 
01867   return proxy;
01868 }
01869 
01898 DBusGProxy*
01899 dbus_g_proxy_new_for_name (DBusGConnection *connection,
01900                            const char      *name,
01901                            const char      *path_name,
01902                            const char      *interface_name)
01903 {
01904   g_return_val_if_fail (connection != NULL, NULL);
01905   g_return_val_if_fail (name != NULL, NULL);
01906   g_return_val_if_fail (path_name != NULL, NULL);
01907   g_return_val_if_fail (interface_name != NULL, NULL);
01908 
01909   return dbus_g_proxy_new (connection, name,
01910                            path_name, interface_name);
01911 }
01912 
01938 DBusGProxy*
01939 dbus_g_proxy_new_for_name_owner (DBusGConnection          *connection,
01940                                  const char               *name,
01941                                  const char               *path_name,
01942                                  const char               *interface_name,
01943                                  GError                  **error)
01944 {
01945   DBusGProxy *proxy;
01946   char *unique_name;
01947 
01948   g_return_val_if_fail (connection != NULL, NULL);
01949   g_return_val_if_fail (name != NULL, NULL);
01950   g_return_val_if_fail (path_name != NULL, NULL);
01951   g_return_val_if_fail (interface_name != NULL, NULL);
01952 
01953   if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
01954     return NULL;
01955 
01956   proxy = dbus_g_proxy_new (connection, unique_name,
01957                             path_name, interface_name);
01958   g_free (unique_name);
01959   return proxy;
01960 }
01961 
01973 DBusGProxy*
01974 dbus_g_proxy_new_from_proxy (DBusGProxy        *proxy,
01975                              const char        *interface,
01976                              const char        *path)
01977 {
01978   DBusGProxyPrivate *priv;
01979 
01980   g_return_val_if_fail (proxy != NULL, NULL);
01981 
01982   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
01983   
01984   if (interface == NULL)
01985     interface = priv->interface;
01986   if (path == NULL)
01987     path = priv->path;
01988 
01989   return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection),
01990                            priv->name,
01991                            path, interface);
01992 }
01993 
02008 DBusGProxy*
02009 dbus_g_proxy_new_for_peer (DBusGConnection          *connection,
02010                            const char               *path_name,
02011                            const char               *interface_name)
02012 {
02013   DBusGProxy *proxy;
02014   
02015   g_return_val_if_fail (connection != NULL, NULL);
02016   g_return_val_if_fail (path_name != NULL, NULL);
02017   g_return_val_if_fail (interface_name != NULL, NULL);
02018 
02019   proxy = dbus_g_proxy_new (connection, NULL,
02020                             path_name, interface_name);
02021 
02022   return proxy;
02023 }
02024 
02038 const char*
02039 dbus_g_proxy_get_bus_name (DBusGProxy        *proxy)
02040 {
02041   DBusGProxyPrivate *priv;
02042 
02043   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02044   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02045 
02046   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02047 
02048   return priv->name;
02049 }
02050 
02059 const char*
02060 dbus_g_proxy_get_interface (DBusGProxy        *proxy)
02061 {
02062   DBusGProxyPrivate *priv;
02063   
02064   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02065   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02066 
02067   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02068 
02069   return priv->interface;
02070 }
02071 
02079 void
02080 dbus_g_proxy_set_interface (DBusGProxy        *proxy,
02081                             const char        *interface_name)
02082 {
02083   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02084   /* FIXME - need to unregister when we switch interface for now
02085    * later should support idea of unset interface
02086    */
02087   dbus_g_proxy_manager_unregister (priv->manager, proxy);
02088   g_free (priv->interface);
02089   priv->interface = g_strdup (interface_name);
02090   dbus_g_proxy_manager_register (priv->manager, proxy);
02091 }
02092 
02100 const char*
02101 dbus_g_proxy_get_path (DBusGProxy        *proxy)
02102 {
02103   DBusGProxyPrivate *priv;
02104   
02105   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02106   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02107 
02108   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02109 
02110   return priv->path;
02111 }
02112 
02113 static DBusMessage *
02114 dbus_g_proxy_marshal_args_to_message (DBusGProxy  *proxy,
02115                                       const char  *method,
02116                                       GValueArray *args)
02117 {
02118   DBusMessage *message;
02119   DBusMessageIter msgiter;
02120   guint i;
02121   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02122 
02123   message = dbus_message_new_method_call (priv->name,
02124                                           priv->path,
02125                                           priv->interface,
02126                                           method);
02127   if (message == NULL)
02128     goto oom;
02129 
02130   dbus_message_iter_init_append (message, &msgiter);
02131   for (i = 0; i < args->n_values; i++)
02132     {
02133       GValue *gvalue;
02134 
02135       gvalue = g_value_array_get_nth (args, i);
02136 
02137       if (!_dbus_gvalue_marshal (&msgiter, gvalue))
02138         g_assert_not_reached ();
02139     }
02140   return message;
02141  oom:
02142   return NULL;
02143 }
02144 
02145 static guint
02146 dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
02147                                   const char          *method,
02148                                   DBusGProxyCallNotify notify,
02149                                   gpointer             user_data,
02150                                   GDestroyNotify       destroy,
02151                                   GValueArray         *args)
02152 {
02153   DBusMessage *message;
02154   DBusPendingCall *pending;
02155   GPendingNotifyClosure *closure;
02156   guint call_id;
02157   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02158 
02159   pending = NULL;
02160 
02161   message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
02162   if (!message)
02163     goto oom;
02164   
02165   if (!dbus_connection_send_with_reply (priv->manager->connection,
02166                                         message,
02167                                         &pending,
02168                                         -1))
02169     goto oom;
02170   dbus_message_unref (message);
02171   g_assert (pending != NULL);
02172 
02173   call_id = ++priv->call_id_counter;
02174 
02175   if (notify != NULL)
02176     {
02177       closure = g_new (GPendingNotifyClosure, 1);
02178       closure->proxy = proxy; /* No need to ref as the lifecycle is tied to proxy */
02179       closure->call_id = call_id;
02180       closure->func = notify;
02181       closure->data = user_data;
02182       closure->free_data_func = destroy;
02183       dbus_pending_call_set_notify (pending, d_pending_call_notify,
02184                                     closure,
02185                                     d_pending_call_free);
02186     }
02187 
02188   g_hash_table_insert (priv->pending_calls, GUINT_TO_POINTER (call_id), pending);
02189   
02190   return call_id;
02191  oom:
02192   g_error ("Out of memory");
02193   return 0;
02194 }
02195 
02196 static gboolean
02197 dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
02198                                 guint              call_id,
02199                                 GError           **error,
02200                                 GType              first_arg_type,
02201                                 va_list            args)
02202 {
02203   DBusMessage *reply;
02204   DBusMessageIter msgiter;
02205   DBusError derror;
02206   va_list args_unwind;
02207   guint over;
02208   int n_retvals_processed;
02209   gboolean ret;
02210   GType valtype;
02211   DBusPendingCall *pending;
02212   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02213 
02214   reply = NULL;
02215   ret = FALSE;
02216   n_retvals_processed = 0;
02217   over = 0;
02218 
02219   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
02220   
02221   dbus_pending_call_block (pending);
02222   reply = dbus_pending_call_steal_reply (pending);
02223 
02224   g_assert (reply != NULL);
02225 
02226   dbus_error_init (&derror);
02227 
02228   switch (dbus_message_get_type (reply))
02229     {
02230     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
02231 
02232       dbus_message_iter_init (reply, &msgiter);
02233       valtype = first_arg_type;
02234       while (valtype != G_TYPE_INVALID)
02235         {
02236           int arg_type;
02237           gpointer return_storage;
02238           GValue gvalue = { 0, };
02239           DBusGValueMarshalCtx context;
02240 
02241           context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
02242           context.proxy = proxy;
02243 
02244           arg_type = dbus_message_iter_get_arg_type (&msgiter);
02245           if (arg_type == DBUS_TYPE_INVALID)
02246             {
02247               g_set_error (error, DBUS_GERROR,
02248                            DBUS_GERROR_INVALID_ARGS,
02249                            _("Too few arguments in reply"));
02250               goto out;
02251             }
02252 
02253           return_storage = va_arg (args, gpointer);
02254           if (return_storage == NULL)
02255             goto next;
02256 
02257           /* We handle variants specially; the caller is expected
02258            * to have already allocated storage for them.
02259            */
02260           if (arg_type == DBUS_TYPE_VARIANT
02261               && g_type_is_a (valtype, G_TYPE_VALUE))
02262             {
02263               if (!_dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
02264                 {
02265                   g_set_error (error,
02266                                DBUS_GERROR,
02267                                DBUS_GERROR_INVALID_ARGS,
02268                                _("Couldn't convert argument, expected \"%s\""),
02269                                g_type_name (valtype));
02270                   goto out;
02271                 }
02272             }
02273           else
02274             {
02275               g_value_init (&gvalue, valtype);
02276 
02277               if (!_dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error))
02278                 goto out;
02279 
02280               /* Anything that can be demarshaled must be storable */
02281               if (!_dbus_gvalue_store (&gvalue, (gpointer*) return_storage))
02282                 g_assert_not_reached ();
02283               /* Ownership of the value passes to the client, don't unset */
02284             }
02285           
02286         next:
02287           n_retvals_processed++;
02288           dbus_message_iter_next (&msgiter);
02289           valtype = va_arg (args, GType);
02290         }
02291       
02292       while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
02293         {
02294           over++;
02295           dbus_message_iter_next (&msgiter);
02296         }
02297 
02298       if (over > 0)
02299         {
02300           g_set_error (error, DBUS_GERROR,
02301                        DBUS_GERROR_INVALID_ARGS,
02302                        _("Too many arguments in reply; expected %d, got %d"),
02303                        n_retvals_processed, over);
02304           goto out;
02305         }
02306       break;
02307     case DBUS_MESSAGE_TYPE_ERROR:
02308       dbus_set_error_from_message (&derror, reply);
02309       dbus_set_g_error (error, &derror);
02310       dbus_error_free (&derror);
02311       goto out;
02312       break;
02313     default:
02314       dbus_set_error (&derror, DBUS_ERROR_FAILED,
02315                       "Reply was neither a method return nor an exception");
02316       dbus_set_g_error (error, &derror);
02317       dbus_error_free (&derror);
02318       goto out;
02319       break;
02320     }
02321 
02322   ret = TRUE;
02323  out:
02324   va_end (args);
02325 
02326   if (ret == FALSE)
02327     {
02328       int i;
02329       for (i = 0; i < n_retvals_processed; i++)
02330         {
02331           gpointer retval;
02332 
02333           retval = va_arg (args_unwind, gpointer);
02334 
02335           g_free (retval);
02336         }
02337     }
02338   va_end (args_unwind);
02339 
02340   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
02341 
02342   if (reply)
02343     dbus_message_unref (reply);
02344   return ret;
02345 }
02346 
02369 DBusGProxyCall *
02370 dbus_g_proxy_begin_call (DBusGProxy          *proxy,
02371                          const char          *method,
02372                          DBusGProxyCallNotify notify,
02373                          gpointer             user_data,
02374                          GDestroyNotify       destroy,
02375                          GType                first_arg_type,
02376                          ...)
02377 {
02378   guint call_id;
02379   va_list args;
02380   GValueArray *arg_values;
02381   
02382   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
02383   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
02384 
02385   va_start (args, first_arg_type);
02386 
02387   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
02388   
02389   call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values);
02390 
02391   g_value_array_free (arg_values);
02392 
02393   va_end (args);
02394 
02395   return DBUS_G_PROXY_ID_TO_CALL (call_id);
02396 }
02397 
02420 gboolean
02421 dbus_g_proxy_end_call (DBusGProxy          *proxy,
02422                        DBusGProxyCall      *call,
02423                        GError             **error,
02424                        GType                first_arg_type,
02425                        ...)
02426 {
02427   gboolean ret;
02428   va_list args;
02429 
02430   va_start (args, first_arg_type);
02431 
02432   ret = dbus_g_proxy_end_call_internal (proxy, GPOINTER_TO_UINT (call), error, first_arg_type, args);
02433 
02434   va_end (args);
02435   
02436   return ret;
02437 }
02438 
02455 gboolean
02456 dbus_g_proxy_call (DBusGProxy        *proxy,
02457                    const char        *method,
02458                    GError           **error,
02459                    GType              first_arg_type,
02460                    ...)
02461 {
02462   gboolean ret;
02463   guint call_id;
02464   va_list args;
02465   GValueArray *in_args;
02466 
02467   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02468   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02469 
02470   va_start (args, first_arg_type);
02471 
02472   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02473 
02474   call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args);
02475 
02476   g_value_array_free (in_args);
02477 
02478   first_arg_type = va_arg (args, GType);
02479   ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
02480 
02481   va_end (args);
02482 
02483   return ret;
02484 }
02485 
02498 void
02499 dbus_g_proxy_call_no_reply (DBusGProxy               *proxy,
02500                             const char               *method,
02501                             GType                     first_arg_type,
02502                             ...)
02503 {
02504   DBusMessage *message;
02505   va_list args;
02506   GValueArray *in_args;
02507   DBusGProxyPrivate *priv;
02508   
02509   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02510   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02511 
02512   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02513 
02514   va_start (args, first_arg_type);
02515   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02516 
02517   message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
02518 
02519   g_value_array_free (in_args);
02520   va_end (args);
02521 
02522   if (!message)
02523     goto oom;
02524 
02525   dbus_message_set_no_reply (message, TRUE);
02526 
02527   if (!dbus_connection_send (priv->manager->connection,
02528                              message,
02529                              NULL))
02530     goto oom;
02531   dbus_message_unref (message);
02532   return;
02533   
02534  oom:
02535   g_error ("Out of memory");
02536 }
02537 
02548 void
02549 dbus_g_proxy_cancel_call (DBusGProxy        *proxy,
02550                           DBusGProxyCall    *call)
02551 {
02552   guint call_id;
02553   DBusPendingCall *pending;
02554   DBusGProxyPrivate *priv;
02555   
02556   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02557   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02558 
02559   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02560 
02561   call_id = DBUS_G_PROXY_CALL_TO_ID (call);
02562 
02563   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
02564   g_return_if_fail (pending != NULL);
02565 
02566   dbus_pending_call_cancel (pending);
02567 
02568   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
02569 }
02570 
02591 void
02592 dbus_g_proxy_send (DBusGProxy          *proxy,
02593                    DBusMessage         *message,
02594                    dbus_uint32_t       *client_serial)
02595 {
02596   DBusGProxyPrivate *priv;
02597   
02598   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02599   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02600   
02601   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02602   
02603   if (priv->name)
02604     {
02605       if (!dbus_message_set_destination (message, priv->name))
02606         g_error ("Out of memory");
02607     }
02608   if (priv->path)
02609     {
02610       if (!dbus_message_set_path (message, priv->path))
02611         g_error ("Out of memory");
02612     }
02613   if (priv->interface)
02614     {
02615       if (!dbus_message_set_interface (message, priv->interface))
02616         g_error ("Out of memory");
02617     }
02618   
02619   if (!dbus_connection_send (priv->manager->connection, message, client_serial))
02620     g_error ("Out of memory\n");
02621 }
02622 
02623 static void
02624 array_free_all (gpointer array)
02625 {
02626   g_array_free (array, TRUE);
02627 }
02628 
02639 void
02640 dbus_g_proxy_add_signal  (DBusGProxy        *proxy,
02641                           const char        *signal_name,
02642                           GType              first_type,
02643                           ...)
02644 {
02645   GQuark q;
02646   char *name;
02647   GArray *gtypesig;
02648   GType gtype;
02649   va_list args;
02650   DBusGProxyPrivate *priv;
02651 
02652   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02653   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02654   g_return_if_fail (signal_name != NULL);
02655   
02656   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02657 
02658   name = create_signal_name (priv->interface, signal_name);
02659   
02660   q = g_quark_from_string (name);
02661   
02662   g_return_if_fail (g_datalist_id_get_data (&priv->signal_signatures, q) == NULL);
02663 
02664   gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
02665 
02666   va_start (args, first_type);
02667   gtype = first_type;
02668   while (gtype != G_TYPE_INVALID)
02669     {
02670       g_array_append_val (gtypesig, gtype);
02671       gtype = va_arg (args, GType);
02672     }
02673   va_end (args);
02674 
02675 #ifndef G_DISABLE_CHECKS
02676   if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
02677     g_warning ("No marshaller for signature of signal '%s'", signal_name);
02678 #endif
02679 
02680   
02681   g_datalist_id_set_data_full (&priv->signal_signatures,
02682                                q, gtypesig,
02683                                array_free_all);
02684 
02685   g_free (name);
02686 }
02687 
02700 void
02701 dbus_g_proxy_connect_signal (DBusGProxy             *proxy,
02702                              const char             *signal_name,
02703                              GCallback               handler,
02704                              void                   *data,
02705                              GClosureNotify          free_data_func)
02706 {
02707   char *name;
02708   GClosure *closure;
02709   GQuark q;
02710   DBusGProxyPrivate *priv;
02711 
02712   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02713   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02714   g_return_if_fail (signal_name != NULL);
02715   g_return_if_fail (handler != NULL);
02716   
02717   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02718   name = create_signal_name (priv->interface, signal_name);
02719 
02720   q = g_quark_try_string (name);
02721 
02722 #ifndef G_DISABLE_CHECKS
02723   if (q == 0 || g_datalist_id_get_data (&priv->signal_signatures, q) == NULL)
02724     {
02725       g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
02726       g_free (name);
02727       return;
02728     }
02729 #endif
02730   
02731   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
02732   
02733   g_signal_connect_closure_by_id (G_OBJECT (proxy),
02734                                   signals[RECEIVED],
02735                                   q,
02736                                   closure, FALSE);
02737   
02738   g_free (name);
02739 }
02740 
02751 void
02752 dbus_g_proxy_disconnect_signal (DBusGProxy             *proxy,
02753                                 const char             *signal_name,
02754                                 GCallback               handler,
02755                                 void                   *data)
02756 {
02757   char *name;
02758   GQuark q;
02759   DBusGProxyPrivate *priv;
02760   
02761   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02762   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02763   g_return_if_fail (signal_name != NULL);
02764   g_return_if_fail (handler != NULL);
02765 
02766   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
02767   name = create_signal_name (priv->interface, signal_name);
02768 
02769   q = g_quark_try_string (name);
02770   
02771   if (q != 0)
02772     {
02773       g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
02774                                             G_SIGNAL_MATCH_DETAIL |
02775                                             G_SIGNAL_MATCH_FUNC   |
02776                                             G_SIGNAL_MATCH_DATA,
02777                                             signals[RECEIVED],
02778                                             q,
02779                                             NULL,
02780                                             G_CALLBACK (handler), data);
02781     }
02782   else
02783     {
02784       g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
02785                  name);
02786     }
02787 
02788   g_free (name);
02789 }
02790 
02793 #ifdef DBUS_BUILD_TESTS
02794 
02800 gboolean
02801 _dbus_g_proxy_test (void)
02802 {
02803   
02804   
02805   return TRUE;
02806 }
02807 
02808 #endif /* DBUS_BUILD_TESTS */

Generated on Wed Nov 22 01:34:45 2006 for D-BUSGLibBindings by  doxygen 1.4.6