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

Generated on Wed Feb 27 10:13:37 2008 for D-BUS by  doxygen 1.4.6