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

Generated on Tue Jul 7 15:13:58 2009 for D-BUS by  doxygen 1.4.6