Main Page | Modules | Namespace List | Class Hierarchy | Data Structures | Directories | File List | Namespace Members | Data Fields | Related Pages

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

Generated on Tue Sep 13 01:28:06 2005 for D-BUS by  doxygen 1.4.4