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

Generated on Fri Sep 30 19:45:35 2005 for D-BUS by  doxygen 1.4.4